From d771ffb942ffdd0e3435bad0dee115126dd7f962 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:40 +0300 Subject: [PATCH 0001/4375] Dockerfile: add libc6-dev-i386 & gcc-multilib Fixes the following error on travis-ci: CC arch/x86/syscalls/syscall32.o In file included from /usr/include/signal.h:28:0, from /home/travis/build/0x7f454c46/criu/criu/arch/x86/include/asm/types.h:5, from arch/x86/syscalls/syscall32.c:1: /usr/include/features.h:374:25: fatal error: sys/cdefs.h: No such file or directory # include ^ Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.x86_64.hdr | 4 ++++ scripts/travis/travis-tests | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/build/Dockerfile.x86_64.hdr b/scripts/build/Dockerfile.x86_64.hdr index 331b71343..2f136098c 100644 --- a/scripts/build/Dockerfile.x86_64.hdr +++ b/scripts/build/Dockerfile.x86_64.hdr @@ -1 +1,5 @@ FROM ubuntu:trusty + +RUN apt-get update -qq && apt-get install -qq \ + gcc-multilib \ + libc6-dev-i386 diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index c8c519202..ac73981ad 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -3,7 +3,8 @@ set -x -e TRAVIS_PKGS="protobuf-c-compiler libprotobuf-c0-dev libaio-dev libprotobuf-dev protobuf-compiler python-ipaddr libcap-dev - libnl-3-dev gdb bash python-protobuf libnet-dev util-linux" + libnl-3-dev gcc-multilib libc6-dev-i386 gdb bash python-protobuf + libnet-dev util-linux" travis_prep () { [ -n "$SKIP_TRAVIS_PREP" ] && return From ec97356024f15984ef2cbc28ed9529c046588cad Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 5 Apr 2016 18:41:13 +0300 Subject: [PATCH 0002/4375] compel: piegen -- Add @arch option This will be needed to print out cflags and ldflags. Unused at moment. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/piegen/main.c | 45 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/criu/pie/piegen/main.c b/criu/pie/piegen/main.c index c34a8b944..e55ec845f 100644 --- a/criu/pie/piegen/main.c +++ b/criu/pie/piegen/main.c @@ -17,6 +17,10 @@ #include "config.h" #include "piegen.h" +static const char compel_cflags_pie[] = "-fpie -Wa,--noexecstack -fno-stack-protector"; +static const char compel_cflags_nopic[] = "-fno-pic -Wa,--noexecstack -fno-stack-protector"; +static const char compel_ldflags[] = "-r"; + piegen_opt_t opts = { .input_filename = NULL, .uapi_dir = "piegen/uapi", @@ -71,13 +75,39 @@ static int handle_elf(void *mem, size_t size) */ int main(int argc, char *argv[]) { + const char *current_cflags = NULL; struct stat st; - int opt, idx; + int opt, idx, i; void *mem; int fd; - static const char short_opts[] = "f:o:s:p:v:r:u:h"; + typedef struct { + const char *arch; + const char *cflags; + } compel_cflags_t; + + static const compel_cflags_t compel_cflags[] = { + { + .arch = "x86", + .cflags = compel_cflags_pie, + }, { + .arch = "ia32", + .cflags = compel_cflags_nopic, + }, { + .arch = "aarch64", + .cflags = compel_cflags_pie, + }, { + .arch = "arm", + .cflags = compel_cflags_pie, + }, { + .arch = "ppc64", + .cflags = compel_cflags_pie, + }, + }; + + static const char short_opts[] = "a:f:o:s:p:v:r:u:h"; static struct option long_opts[] = { + { "arch", required_argument, 0, 'a' }, { "file", required_argument, 0, 'f' }, { "output", required_argument, 0, 'o' }, { "stream", required_argument, 0, 's' }, @@ -98,6 +128,17 @@ int main(int argc, char *argv[]) if (opt == -1) break; switch (opt) { + case 'a': + for (i = 0; i < ARRAY_SIZE(compel_cflags); i++) { + if (!strcmp(optarg, compel_cflags[i].arch)) { + current_cflags = compel_cflags[i].cflags; + break; + } + } + + if (!current_cflags) + goto usage; + break; case 'f': opts.input_filename = optarg; break; From dbc2edb83a0713c1a002e7e95dd7f8ac02878001 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 5 Apr 2016 18:41:14 +0300 Subject: [PATCH 0003/4375] compel: piegen -- Introduce actions Here we introduce actions: - "piegen" to generate blobs, which is used by criu already; - "cflags" and "ldflags" to print out options needed for compiler and linker when building compel compatible objects. We rather moved old "main" function body into piegen helper function and implement the rest of actions since they are one-liners. Note the usage uses new "compel" brand, but it's safe because we don't export anything yet. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 2 +- criu/pie/piegen/main.c | 98 +++++++++++++++++++++++++++--------------- 2 files changed, 64 insertions(+), 36 deletions(-) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 141c0182b..7ea79d1c3 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -78,7 +78,7 @@ $(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/lib.a $(obj)/$(PIELDS) $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(obj)/$(PIELDS) criu/pie/piegen $(call msg-gen, $@) - $(Q) criu/pie/piegen/piegen -f $< -v $(call target-name,$@)_relocs -p $(call target-name,$@)_blob_offset__ -s $(call target-name,$@)_blob -o $@ $(piegen_stdout) + $(Q) criu/pie/piegen/piegen piegen -f $< -v $(call target-name,$@)_relocs -p $(call target-name,$@)_blob_offset__ -s $(call target-name,$@)_blob -o $@ $(piegen_stdout) else diff --git a/criu/pie/piegen/main.c b/criu/pie/piegen/main.c index e55ec845f..575c371f4 100644 --- a/criu/pie/piegen/main.c +++ b/criu/pie/piegen/main.c @@ -70,16 +70,52 @@ static int handle_elf(void *mem, size_t size) return -1; } -/* - * That;s the tool to generate patches object files. - */ +static int piegen(void) +{ + struct stat st; + void *mem; + int fd; + + fd = open(opts.input_filename, O_RDONLY); + if (fd < 0) { + pr_perror("Can't open file %s", opts.input_filename); + goto err; + } + + if (fstat(fd, &st)) { + pr_perror("Can't stat file %s", opts.input_filename); + goto err; + } + + fout = fopen(opts.output_filename, "w"); + if (fout == NULL) { + pr_perror("Can't open %s", opts.output_filename); + goto err; + } + + mem = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FILE, fd, 0); + if (mem == MAP_FAILED) { + pr_perror("Can't mmap file %s", opts.input_filename); + goto err; + } + + if (handle_elf(mem, st.st_size)) { + fclose(fout); + unlink(opts.output_filename); + goto err; + } + +err: + fclose(fout); + printf("%s generated successfully.\n", opts.output_filename); + return 0; +} + int main(int argc, char *argv[]) { const char *current_cflags = NULL; - struct stat st; int opt, idx, i; - void *mem; - int fd; + char *action; typedef struct { const char *arch; @@ -161,47 +197,39 @@ int main(int argc, char *argv[]) opts.nrgotpcrel_name = optarg; break; case 'h': - default: goto usage; + default: + break; } } - if (!opts.input_filename) + if (optind >= argc) goto usage; - fd = open(opts.input_filename, O_RDONLY); - if (fd < 0) { - pr_perror("Can't open file %s", opts.input_filename); - goto err; + action = argv[optind++]; + + if (!strcmp(action, "cflags")) { + if (!current_cflags) + goto usage; + printf("%s", current_cflags); + return 0; } - if (fstat(fd, &st)) { - pr_perror("Can't stat file %s", opts.input_filename); - goto err; + if (!strcmp(action, "ldflags")) { + printf("%s", compel_ldflags); + return 0; } - fout = fopen(opts.output_filename, "w"); - if (fout == NULL) { - pr_perror("Can't open %s", opts.output_filename); - goto err; + if (!strcmp(action, "piegen")) { + if (!opts.input_filename) + goto usage; + return piegen(); } - mem = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FILE, fd, 0); - if (mem == MAP_FAILED) { - pr_perror("Can't mmap file %s", opts.input_filename); - goto err; - } - - if (handle_elf(mem, st.st_size)) { - fclose(fout); - unlink(opts.output_filename); - goto err; - } - fclose(fout); - printf("%s generated successfully.\n", opts.output_filename); - return 0; usage: - fprintf(stderr, "Usage: %s -f filename\n", argv[0]); -err: + printf("Usage:\n"); + printf(" compel --arch=(x86|ia32|aarch64|arm|ppc64) cflags\n"); + printf(" compel --arch=(x86|ia32|aarch64|arm|ppc64) ldflags\n"); + printf(" compel -f filename piegen\n"); return 1; } From acfa85ba5ae3783346ae058be6e95f3253e0e93c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 5 Apr 2016 18:41:15 +0300 Subject: [PATCH 0004/4375] compel: Initial commit for standalone tool The compel component is a replacement for several aspects of CRIU functionality: binary blobs generation for PIE parasite/restore code, and a library for parasite code injection and execution (to be implemented). In the commit we rather shuffle compel into own directory and use it for 1) Fetching cflags when compiling PIE blobs 2) Use its "piegen" functionality to generate blobs themselves. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 11 +++++++--- Makefile.versions | 5 +++++ compel/Makefile | 20 +++++++++++++++++++ {criu/pie/piegen => compel/include}/piegen.h | 0 .../piegen => compel/include}/uapi/types.h | 0 {criu/pie/piegen => compel/src}/elf-ppc64.c | 0 {criu/pie/piegen => compel/src}/elf-x86-32.c | 0 {criu/pie/piegen => compel/src}/elf-x86-64.c | 0 {criu/pie/piegen => compel/src}/elf.c | 0 {criu/pie/piegen => compel/src}/main.c | 0 criu/Makefile | 17 +--------------- criu/pie/Makefile | 13 ++++++------ criu/pie/pie-relocs.c | 2 +- criu/pie/pie-relocs.h | 2 +- criu/pie/piegen/Makefile | 19 ------------------ 15 files changed, 42 insertions(+), 47 deletions(-) create mode 100644 compel/Makefile rename {criu/pie/piegen => compel/include}/piegen.h (100%) rename {criu/pie/piegen => compel/include}/uapi/types.h (100%) rename {criu/pie/piegen => compel/src}/elf-ppc64.c (100%) rename {criu/pie/piegen => compel/src}/elf-x86-32.c (100%) rename {criu/pie/piegen => compel/src}/elf-x86-64.c (100%) rename {criu/pie/piegen => compel/src}/elf.c (100%) rename {criu/pie/piegen => compel/src}/main.c (100%) delete mode 100644 criu/pie/piegen/Makefile diff --git a/Makefile b/Makefile index 79490d073..2113fb024 100644 --- a/Makefile +++ b/Makefile @@ -127,7 +127,7 @@ endif CFLAGS += $(WARNINGS) $(DEFINES) -iquote include/ # Default target -all: criu lib +all: compel criu lib .PHONY: all # @@ -201,6 +201,9 @@ $(eval $(call gen-built-in,images)) .PHONY: .FORCE +# Compel get used by CRIU, build it earlier +$(eval $(call gen-built-in,compel)) + # # Next the socket CR library # @@ -222,9 +225,9 @@ $(SOCCR_A): |soccr/built-in.o # # But note that we're already included # the nmk so we can reuse it there. -criu/%: images/built-in.o $(VERSION_HEADER) $(CONFIG_HEADER) .FORCE +criu/%: images/built-in.o compel/compel $(VERSION_HEADER) $(CONFIG_HEADER) .FORCE $(Q) $(MAKE) $(build)=criu $@ -criu: images/built-in.o $(SOCCR_A) $(VERSION_HEADER) $(CONFIG_HEADER) +criu: images/built-in.o compel/compel $(SOCCR_A) $(VERSION_HEADER) $(CONFIG_HEADER) $(Q) $(MAKE) $(build)=criu all .PHONY: criu @@ -248,6 +251,7 @@ clean: subclean $(Q) $(MAKE) $(build)=criu $@ $(Q) $(MAKE) $(build)=soccr $@ $(Q) $(MAKE) $(build)=lib $@ + $(Q) $(MAKE) $(build)=compel $@ .PHONY: clean # mrproper depends on clean in nmk @@ -256,6 +260,7 @@ mrproper: subclean $(Q) $(MAKE) $(build)=criu $@ $(Q) $(MAKE) $(build)=soccr $@ $(Q) $(MAKE) $(build)=lib $@ + $(Q) $(MAKE) $(build)=compel $@ $(Q) $(RM) $(CONFIG_HEADER) $(Q) $(RM) $(SOCCR_CONFIG) $(Q) $(RM) $(VERSION_HEADER) diff --git a/Makefile.versions b/Makefile.versions index 5139b5d4f..3ea7ca681 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -23,3 +23,8 @@ SOCCR_SO_VERSION_MAJOR := 1 SOCCR_SO_VERSION_MINOR := 0 export SOCCR_SO_VERSION_MAJOR SOCCR_SO_VERSION_MINOR + +COMPEL_SO_VERSION_MAJOR := 1 +COMPEL_SO_VERSION_MINOR := 0 + +export COMPEL_SO_VERSION_MAJOR COMPEL_SO_VERSION_MINOR diff --git a/compel/Makefile b/compel/Makefile new file mode 100644 index 000000000..5e4bd7b76 --- /dev/null +++ b/compel/Makefile @@ -0,0 +1,20 @@ +include $(SRC_DIR)/Makefile.versions + +ccflags-y += -iquote criu/include +ccflags-y += -iquote compel/include +ccflags-y += -DCOMPEL_VERSION=\"$(COMPEL_SO_VERSION_MAJOR).$(COMPEL_SO_VERSION_MINOR)\" + +host-ccflags-y += $(filter-out -pg $(CFLAGS-GCOV),$(ccflags-y)) +HOSTCFLAGS += $(filter-out -pg $(CFLAGS-GCOV),$(WARNINGS) $(DEFINES)) +HOSTLDFLAGS += $(filter-out -pg $(CFLAGS-GCOV),$(LDFLAGS)) + +hostprogs-y += compel +compel-objs += src/main.o + +ifneq ($(filter ia32 x86, $(ARCH)),) +compel-objs += src/elf-x86-32.o +compel-objs += src/elf-x86-64.o +endif +ifeq ($(SRCARCH),ppc64) +compel-objs += src/elf-ppc64.o +endif diff --git a/criu/pie/piegen/piegen.h b/compel/include/piegen.h similarity index 100% rename from criu/pie/piegen/piegen.h rename to compel/include/piegen.h diff --git a/criu/pie/piegen/uapi/types.h b/compel/include/uapi/types.h similarity index 100% rename from criu/pie/piegen/uapi/types.h rename to compel/include/uapi/types.h diff --git a/criu/pie/piegen/elf-ppc64.c b/compel/src/elf-ppc64.c similarity index 100% rename from criu/pie/piegen/elf-ppc64.c rename to compel/src/elf-ppc64.c diff --git a/criu/pie/piegen/elf-x86-32.c b/compel/src/elf-x86-32.c similarity index 100% rename from criu/pie/piegen/elf-x86-32.c rename to compel/src/elf-x86-32.c diff --git a/criu/pie/piegen/elf-x86-64.c b/compel/src/elf-x86-64.c similarity index 100% rename from criu/pie/piegen/elf-x86-64.c rename to compel/src/elf-x86-64.c diff --git a/criu/pie/piegen/elf.c b/compel/src/elf.c similarity index 100% rename from criu/pie/piegen/elf.c rename to compel/src/elf.c diff --git a/criu/pie/piegen/main.c b/compel/src/main.c similarity index 100% rename from criu/pie/piegen/main.c rename to compel/src/main.c diff --git a/criu/Makefile b/criu/Makefile index 421ef455c..6c0241f4b 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -45,18 +45,6 @@ ARCH-LIB := $(ARCH_DIR)/crtools.built-in.o $(ARCH-LIB): syscalls_lib $(Q) $(MAKE) $(build)=$(ARCH_DIR) all -# -# piegen tool needed for PIE code. -ifeq ($(piegen-y),y) -piegen-bin := criu/pie/piegen/piegen - -criu/pie/piegen/%: $(CONFIG_HEADER) - $(Q) CC=$(HOSTCC) LD=$(HOSTLD) CFLAGS="$(ccflags-y) $(HOSTCFLAGS) $(WARNINGS) $(DEFINES)" $(MAKE) $(build)=criu/pie/piegen $@ -$(piegen-bin): criu/pie/piegen/built-in.o - $(call msg-link, $@) - $(Q) $(HOSTCC) $(HOSTCFLAGS) $^ $(LDFLAGS) -o $@ -endif - # # PIE library code. criu/pie/lib.a: $(ARCH-LIB) @@ -64,7 +52,7 @@ criu/pie/lib.a: $(ARCH-LIB) # # PIE code blobs themseves. -pie: $(piegen-bin) criu/pie/lib.a +pie: criu/pie/lib.a $(Q) $(MAKE) $(build)=criu/pie all .PHONY: pie @@ -98,14 +86,12 @@ $(obj)/criu: $(PROGRAM-BUILTINS) subclean: $(Q) $(RM) $(obj)/*.{gcda,gcno,gcov} $(Q) $(RM) $(obj)/pie/*.{gcda,gcno,gcov} - $(Q) $(RM) $(obj)/pie/piegen/*.{gcda,gcno,gcov} $(Q) $(RM) -r $(obj)/gcov $(Q) $(MAKE) $(call build-as,Makefile.syscalls,$(ARCH_DIR)) clean $(Q) $(MAKE) $(build)=$(ARCH_DIR) clean $(Q) $(MAKE) $(call build-as,Makefile.library,$(PIE_DIR)) clean $(Q) $(MAKE) $(call build-as,Makefile.crtools,criu) clean $(Q) $(MAKE) $(build)=$(PIE_DIR) clean - $(Q) $(MAKE) $(build)=$(PIE_DIR)/piegen clean .PHONY: subclean cleanup-y += $(obj)/criu clean: subclean @@ -118,7 +104,6 @@ subproper: $(Q) $(MAKE) $(call build-as,Makefile.library,$(PIE_DIR)) mrproper $(Q) $(MAKE) $(call build-as,Makefile.crtools,criu) mrproper $(Q) $(MAKE) $(build)=$(PIE_DIR) mrproper - $(Q) $(MAKE) $(build)=$(PIE_DIR)/piegen mrproper .PHONY: subproper mrproper: subproper diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 7ea79d1c3..220ee6e0c 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -16,7 +16,7 @@ restorer-obj-e += ./$(ARCH_DIR)/syscalls.built-in.o # project. # CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) -CFLAGS += -iquote $(SRC_DIR)/criu/pie/piegen +CFLAGS += -iquote $(SRC_DIR)/compel/include CFLAGS += -iquote $(SRC_DIR)/criu/arch/$(ARCH)/include CFLAGS += -iquote $(SRC_DIR)/criu/include CFLAGS += -iquote $(SRC_DIR)/include @@ -25,10 +25,9 @@ CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 -ifneq ($(filter-out ia32,$(ARCH)),) - ccflags-y += -DCR_NOGLIBC -fpie -Wa,--noexecstack -fno-stack-protector -else - ccflags-y += -DCR_NOGLIBC -fno-pic -Wa,--noexecstack -fno-stack-protector +ccflags-y += -DCR_NOGLIBC +ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) + ccflags-y += $(shell $(SRC_DIR)/compel/compel --arch=$(ARCH) cflags) endif ifeq ($(SRCARCH),arm) @@ -76,9 +75,9 @@ $(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/lib.a $(obj)/$(PIELDS) $(call msg-gen, $@) $(Q) $(LD) -r -T $(obj)/$(PIELDS) -o $@ $< $(obj)/lib.a -$(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(obj)/$(PIELDS) criu/pie/piegen +$(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(obj)/$(PIELDS) compel/compel $(call msg-gen, $@) - $(Q) criu/pie/piegen/piegen piegen -f $< -v $(call target-name,$@)_relocs -p $(call target-name,$@)_blob_offset__ -s $(call target-name,$@)_blob -o $@ $(piegen_stdout) + $(Q) compel/compel piegen -f $< -v $(call target-name,$@)_relocs -p $(call target-name,$@)_blob_offset__ -s $(call target-name,$@)_blob -o $@ $(piegen_stdout) else diff --git a/criu/pie/pie-relocs.c b/criu/pie/pie-relocs.c index 0c2275a76..4e4924845 100644 --- a/criu/pie/pie-relocs.c +++ b/criu/pie/pie-relocs.c @@ -17,7 +17,7 @@ #include "log.h" #include "common/compiler.h" -#include "piegen/uapi/types.h" +#include "compel/include/uapi/types.h" #include "common/bug.h" __maybe_unused void elf_relocs_apply(void *mem, void *vbase, size_t size, elf_reloc_t *elf_relocs, size_t nr_relocs) diff --git a/criu/pie/pie-relocs.h b/criu/pie/pie-relocs.h index 8d9ae2873..269beadcd 100644 --- a/criu/pie/pie-relocs.h +++ b/criu/pie/pie-relocs.h @@ -1,7 +1,7 @@ #ifndef __PIE_RELOCS_H__ #define __PIE_RELOCS_H__ -#include "piegen/uapi/types.h" +#include "compel/include/uapi/types.h" #include "common/compiler.h" #include "config.h" diff --git a/criu/pie/piegen/Makefile b/criu/pie/piegen/Makefile deleted file mode 100644 index 0af489070..000000000 --- a/criu/pie/piegen/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -CFLAGS += -iquote pie/piegen - -obj-y += main.o -ifneq ($(filter ia32 x86, $(ARCH)),) -obj-y += elf-x86-32.o -obj-y += elf-x86-64.o -endif -ifeq ($(SRCARCH),ppc64) -obj-y += elf-ppc64.o -endif - -cleanup-y += $(obj)/piegen -cleanup-y += $(obj)/*.o - -ifneq ($(MAKECMDGOALS),clean) -ifneq ($(MAKECMDGOALS),mrproper) -incdeps := y -endif -endif From f2dd307be9b2d61a90463c856bbaeccfa9416231 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 6 Apr 2016 15:25:43 +0300 Subject: [PATCH 0005/4375] compel: Drop config.h from deps We don't need it actually. Signed-off-by: Cyrill Gorcunov Acked-by: Andrew Vagin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compel/src/main.c b/compel/src/main.c index 575c371f4..8ce5f75f3 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -14,7 +14,6 @@ #include #include "common/compiler.h" -#include "config.h" #include "piegen.h" static const char compel_cflags_pie[] = "-fpie -Wa,--noexecstack -fno-stack-protector"; From 4ffbb4d04e85c4151519dcbc673df697ca27ec7a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 7 Apr 2016 13:51:00 +0300 Subject: [PATCH 0006/4375] build: compel -- Drop double targeting It's a hostprog so one target is enough, otherwise we're gitting double deps generation. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2113fb024..c69548833 100644 --- a/Makefile +++ b/Makefile @@ -202,7 +202,8 @@ $(eval $(call gen-built-in,images)) .PHONY: .FORCE # Compel get used by CRIU, build it earlier -$(eval $(call gen-built-in,compel)) +compel/%: + $(Q) $(MAKE) $(build)=compel $@ # # Next the socket CR library From 0aa355e40a37119d1aa7ec689bcc2c359c33432b Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:39 +0300 Subject: [PATCH 0007/4375] .gitignore: add compel/compel Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 44e43c970..92b480513 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ cscope* tags TAGS Makefile.local +compel/compel images/*.c images/*.h images/google/protobuf/*.c From bbc2f1331f3752dee62028bb59eaa93c2e70ac7d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:41 +0300 Subject: [PATCH 0008/4375] x86/build: generate syscalls-{64,32}.built-in.o After uncommenting FIXME: It will add sc_exec_table_32 for compatible tasks to sys-exec-tbl.c Now it does: - add two different 32/64 syscall tables for cr-exec sys-exec-tbl-{64,32}. - add two different syscall headers syscall-{64,32}.h, that are included from more x86 generic syscall.h depending on -DCONFIG_X86_{32,64} option. - builds two different syscalls-{32,64}.built-in.o - for criu core files, that need SYS_memfd_create and other SYS_* __NR_* defines (currently kerndat.c and shmem.c), create simple syscall-codes.h that includes syscall-codes-64.h [Added after rebase on master] That way after apply, the compatible patch set will be simply able to bisect for regressions. Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .gitignore | 8 +- criu/Makefile | 5 + criu/arch/ppc64/Makefile.syscalls | 3 + criu/arch/scripts/arm/gen-sys-exec-tbl.pl | 4 + criu/arch/x86/Makefile.syscalls | 215 ++++++++++++++++------ criu/arch/x86/syscalls/syscall32.c | 2 +- criu/cr-exec.c | 3 - criu/pie/Makefile | 9 +- 8 files changed, 186 insertions(+), 63 deletions(-) diff --git a/.gitignore b/.gitignore index 92b480513..ae5f8e3c5 100644 --- a/.gitignore +++ b/.gitignore @@ -23,11 +23,11 @@ images/google/protobuf/*.c images/google/protobuf/*.h .gitid criu/criu -criu/arch/*/sys-exec-tbl.c -criu/arch/*/syscalls.S +criu/arch/*/sys-exec-tbl*.c +criu/arch/*/syscalls*.S criu/include/config.h -criu/include/syscall-codes.h -criu/include/syscall.h +criu/include/syscall-codes*.h +criu/include/syscall*.h soccr/config.h criu/include/version.h criu/pie/restorer-blob.h diff --git a/criu/Makefile b/criu/Makefile index 6c0241f4b..4f4d673b5 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -34,7 +34,12 @@ include $(SRC_DIR)/criu/Makefile.packages # # System calls library. +ifeq ($(ARCH),x86) +# Do not need 32-bit compatible syscall lib compiled in criu +SYSCALL-LIB := $(ARCH_DIR)/syscalls-64.built-in.o +else SYSCALL-LIB := $(ARCH_DIR)/syscalls.built-in.o +endif syscalls_lib: $(Q) $(MAKE) $(call build-as,Makefile.syscalls,$(ARCH_DIR)) all .PHONY: syscalls_lib diff --git a/criu/arch/ppc64/Makefile.syscalls b/criu/arch/ppc64/Makefile.syscalls index 979741a87..d11597821 100644 --- a/criu/arch/ppc64/Makefile.syscalls +++ b/criu/arch/ppc64/Makefile.syscalls @@ -49,6 +49,9 @@ SYS-EXEC-TBL := sys-exec-tbl.c $(obj)/$(SYS-EXEC-TBL): $(obj)/syscalls/$(SYS-DEF) $(obj)/$(SYS-CODES) $(obj)/$(SYS-PROTO) $(E) " GEN " $@ $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "static struct syscall_exec_desc sc_exec_table[] = {" >> $@ $(Q) cat $< | awk '/^__NR/{print "SYSCALL(", substr($$3, 5), ",", $$2, ")"}' >> $@ + $(Q) echo " { }, /* terminator */" >> $@ + $(Q) echo "};" >> $@ mrproper-y += $(obj)/$(SYS-EXEC-TBL) all-y += $(obj)/$(SYS-EXEC-TBL) diff --git a/criu/arch/scripts/arm/gen-sys-exec-tbl.pl b/criu/arch/scripts/arm/gen-sys-exec-tbl.pl index a3037b78c..2f90c13fe 100755 --- a/criu/arch/scripts/arm/gen-sys-exec-tbl.pl +++ b/criu/arch/scripts/arm/gen-sys-exec-tbl.pl @@ -13,6 +13,7 @@ open TBLOUT, ">", $tblout or die $!; open IN, "<", $in or die $!; print TBLOUT "/* Autogenerated, don't edit */\n"; +print TBLOUT "static struct syscall_exec_desc sc_exec_table[] = {\n"; for () { if ($_ =~ /\#/) { @@ -37,3 +38,6 @@ for () { print TBLOUT "SYSCALL($sys_name, $sys_num)\n"; } } + +print TBLOUT " { }, /* terminator */"; +print TBLOUT "};" diff --git a/criu/arch/x86/Makefile.syscalls b/criu/arch/x86/Makefile.syscalls index a2c509df6..79c58be3a 100644 --- a/criu/arch/x86/Makefile.syscalls +++ b/criu/arch/x86/Makefile.syscalls @@ -1,71 +1,178 @@ include $(__nmk_dir)msg.mk -builtin-name := syscalls.built-in.o CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) +CFLAGS := $(filter-out -DCONFIG_X86_64,$(CFLAGS)) -SYS-TYPES := ../../include/syscall-types.h -SYS-CODES := ../../include/syscall-codes.h -SYS-PROTO := ../../include/syscall.h +SYS-PROTO-GENERIC := $(obj)/../../include/syscall.h +SYS-EXEC-TBL-GENERIC := sys-exec-tbl.c +SYS-CODES-GENERIC = $(obj)/../../include/syscall-codes.h +SYS-CODES = $(obj)/../../include/syscall-codes-$(1).h +SYS-PROTO = $(obj)/../../include/syscall-$(1).h +SYS-DEF = $(obj)/syscalls/syscall_$(1).tbl +SYS-ASM = syscalls-$(1).S +SYS-ASM-COMMON = syscall-common-x86-$(1).S +SYS-EXEC-TBL = $(obj)/sys-exec-tbl-$(1).c + +target := +target_32 := syscalls-32 +target_64 := syscalls-64 + +SYS-BITS := 32 + +# native x86_64 ifeq ($(ARCH),x86) - SYS-DEF := syscall_64.tbl - SYS-ASM-COMMON := syscall-common-x86-64.S - asflags-y += -fpie -Wstrict-prototypes -Wa,--noexecstack -else - SYS-DEF := syscall_32.tbl - SYS-ASM-COMMON := syscall-common-x86-32.S - asflags-y += -fno-pic -Wstrict-prototypes -Wa,--noexecstack - obj-y += syscalls/syscall32.o - -$(obj)/syscalls/syscall32.o: $(obj)/$(SYS-CODES) $(obj)/$(SYS-PROTO) + SYS-BITS += 64 endif +# targets +define gen-targets +target += $(target_$(1)) +endef + +$(eval $(call map,gen-targets,$(SYS-BITS))) + +# AFLAGS, LDFLAGS +asflags-y += -Wstrict-prototypes -Wa,--noexecstack asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer -asflags-y += -iquote $(obj) -iquote $(obj)/include -iquote $(SRC_DIR)/criu/include +asflags-y += -iquote $(obj) -iquote $(obj)/include +asflags-y += -iquote $(SRC_DIR)/criu/include -SYS-ASM := syscalls.S -obj-y += $(SYS-ASM:.S=).o +AFLAGS_$(target_32) += -fno-pic -m32 +AFLAGS_$(target_64) += -fpie +LDFLAGS_$(target_32) += -m elf_i386 -$(obj)/$(SYS-CODES): $(obj)/syscalls/$(SYS-DEF) - $(call msg-gen, $@) - $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) echo "#ifndef __ASM_CR_SYSCALL_CODES_H__" >> $@ - $(Q) echo "#define __ASM_CR_SYSCALL_CODES_H__" >> $@ - $(Q) cat $< | awk '/^__NR/{SYSN=$$1; sub("^__NR", "SYS", SYSN);'\ - 'print "\n#ifndef ", $$1, "\n#define", $$1, $$2, "\n#endif";'\ - 'print "#ifndef ", SYSN, "\n#define ", SYSN, $$1, "\n#endif"}' >> $@ - $(Q) echo "#endif /* __ASM_CR_SYSCALL_CODES_H__ */" >> $@ -mrproper-y += $(obj)/$(SYS-CODES) +$(target_32)-obj-y += syscalls/syscall32.o +$(obj)/syscalls/syscall32.d: $(obj)/../../include/syscall-codes-32.h \ + $(obj)/../../include/syscall-32.h -$(obj)/$(SYS-PROTO): $(obj)/syscalls/$(SYS-DEF) - $(call msg-gen, $@) - $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) echo "#ifndef __ASM_CR_SYSCALL_PROTO_H__" >> $@ - $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H__" >> $@ - $(Q) echo "#ifndef CR_NOGLIBC" >> $@ - $(Q) echo "# error This file should only be used in the parasite code" >> $@ - $(Q) echo "#endif" >> $@ - $(Q) echo "#include \"syscall-codes.h\"" >> $@ - $(Q) echo "#include \"syscall-types.h\"" >> $@ -ifneq ($(ARCH),x86) - $(Q) echo "#include \"asm/syscall32.h\"" >> $@ +CFLAGS_syscall32.o += -fno-pic -m32 -DCR_NOGLIBC -DCONFIG_X86_32 +CFLAGS_syscall32.d += -fno-pic -m32 -DCR_NOGLIBC -DCONFIG_X86_32 +cleanup-y += $(obj)/syscalls/syscall32.o + +# Here are rules for 32/64-bit platforms. For compat mode we need both +# 32 and 64 bit syscalls, so generate the rules with SYS-BIT being +# $1 parameter in all gen-rule-* + +# awk variable should be escaped twice +AV := $$$$ + +define gen-rule-sys-codes +$(SYS-CODES): $(SYS-DEF) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_CODES_H_$(1)__" >> $$@ + $(Q) echo "#define __ASM_CR_SYSCALL_CODES_H_$(1)__" >> $$@ + $(Q) cat $$< | awk '/^__NR/{SYSN=$(AV)1; \ + sub("^__NR", "SYS", SYSN); \ + print "\n#ifndef ", $(AV)1; \ + print "#define", $(AV)1, $(AV)2; \ + print "#endif"; \ + print "\n#ifndef ", SYSN; \ + print "#define ", SYSN, $(AV)1; \ + print "#endif";}' >> $$@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_CODES_H_$(1)__ */" >> $$@ +mrproper-y += $(SYS-CODES) +endef + +define gen-rule-sys-proto +$(SYS-PROTO): $(SYS-DEF) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_PROTO_H_$(1)__" >> $$@ + $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H_$(1)__" >> $$@ + $(Q) echo "#ifndef CR_NOGLIBC" >> $$@ + $(Q) echo "# error This file should only be used in the parasite code" \ + >> $$@ + $(Q) echo "#endif" >> $$@ + $(Q) echo '#include "syscall-codes-$(1).h"' >> $$@ + $(Q) echo '#include "syscall-types.h"' >> $$@ +ifeq ($(1),32) + $(Q) echo '#include "asm/syscall32.h"' >> $$@ endif - $(Q) cat $< | awk '/^__NR/{print "extern long", $$3, substr($$0, index($$0,$$4)), ";"}' >> $@ - $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H__ */" >> $@ -mrproper-y += $(obj)/$(SYS-PROTO) + $(Q) cat $$< | awk '/^__NR/{print "extern long", $(AV)3, \ + substr($(AV)0, index($(AV)0,$(AV)4)), ";"}' >> $$@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H_$(1)__ */" >> $$@ +mrproper-y += $(SYS-PROTO) +endef -$(obj)/$(SYS-ASM): $(obj)/syscalls/$(SYS-DEF) $(obj)/syscalls/$(SYS-ASM-COMMON) $(obj)/$(SYS-CODES) $(obj)/$(SYS-PROTO) - $(call msg-gen, $@) - $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) echo "#include \"syscall-codes.h\"" >> $@ - $(Q) echo "#include \"syscalls/$(SYS-ASM-COMMON)\"" >> $@ - $(Q) cat $< | awk '/^__NR/{print "SYSCALL(", $$3, ",", $$2, ")"}' >> $@ +define gen-rule-sys-asm +$(obj)/$(SYS-ASM): $(SYS-DEF) $(obj)/syscalls/$(SYS-ASM-COMMON) \ + $(SYS-CODES) $(SYS-PROTO) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) echo '#include "syscall-codes-$(1).h"' >> $$@ + $(Q) echo '#include "syscalls/$(SYS-ASM-COMMON)"' >> $$@ + $(Q) cat $$< | awk '/^__NR/{print "SYSCALL(", $(AV)3, ",", $(AV)2, ")"}'\ + >> $$@ mrproper-y += $(obj)/$(SYS-ASM) +$(target_$(1))-obj-y += $(SYS-ASM:.S=).o +endef -SYS-EXEC-TBL := sys-exec-tbl.c -$(obj)/$(SYS-EXEC-TBL): $(obj)/syscalls/$(SYS-DEF) $(obj)/$(SYS-CODES) $(obj)/$(SYS-PROTO) +# for 32-bit $(SYS-ASM) +AFLAGS_syscalls-32.o += -fno-pic -m32 + +define gen-rule-sys-exec-tbl +$(SYS-EXEC-TBL): $(SYS-DEF) $(SYS-CODES) $(SYS-PROTO) $(SYS-PROTO-GENERIC) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) cat $$< | awk '/^__NR/{print \ + "SYSCALL(", substr($(AV)3, 5), ",", $(AV)2, ")"}' >> $$@ +mrproper-y += $(SYS-EXEC-TBL) +all-y += $(SYS-EXEC-TBL) +endef + +# Some parts of criu need SYS_memfd_create and other ifndef/define syscalls +# Use 64-bit, native syscalls as-is, add __NR32_*/SYS32_* defines +# to generic file +$(SYS-CODES-GENERIC): $(obj)/syscalls/syscall_32.tbl $(call msg-gen, $@) - $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) cat $< | awk '/^__NR/{print "SYSCALL(", substr($$3, 5), ",", $$2, ")"}' >> $@ -mrproper-y += $(obj)/$(SYS-EXEC-TBL) -all-y += $(obj)/$(SYS-EXEC-TBL) + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_CODES_H__" >> $@ + $(Q) echo "#define __ASM_CR_SYSCALL_CODES_H__" >> $@ + $(Q) echo '#include "syscall-codes-64.h"' >> $@ + $(Q) cat $< | awk '/^__NR/{NR32=$$1; \ + sub("^__NR", "__NR32", NR32); \ + print "\n#ifndef ", NR32; \ + print "#define ", NR32, $$2; \ + print "#endif";}' >> $@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_CODES_H__ */" >> $@ +mrproper-y += $(SYS-CODES-GENERIC) +all-y += $(SYS-CODES-GENERIC) + +$(SYS-PROTO-GENERIC): $(strip $(call map,SYS-PROTO,$(SYS-BITS))) + $(call msg-gen, $@) + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_PROTO_H__" >> $@ + $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H__" >> $@ + $(Q) echo "" >> $@ + $(Q) echo "#ifdef CONFIG_X86_32" >> $@ + $(Q) echo '#include "syscall-32.h"' >> $@ + $(Q) echo "#else" >> $@ + $(Q) echo '#include "syscall-64.h"' >> $@ + $(Q) echo "#endif /* CONFIG_X86_32 */" >> $@ + $(Q) echo "" >> $@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H__ */" >> $@ +mrproper-y += $(SYS-PROTO-GENERIC) + +$(obj)/$(SYS-EXEC-TBL-GENERIC): + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "static struct syscall_exec_desc sc_exec_table[] = {" >> $@ +ifeq ($(ARCH),x86) + $(Q) echo '#include "sys-exec-tbl-64.c"' >> $@ + $(Q) echo " { }, /* terminator */" >> $@ + $(Q) echo "};" >> $@ + $(Q) echo "" >> $@ +# FIXME: uncomment to support 32-bit task +# $(Q) echo "static struct syscall_exec_desc sc_exec_table_32[] = {" >> $@ +endif +# $(Q) echo '#include "sys-exec-tbl-32.c"' >> $@ +# $(Q) echo " { }, /* terminator */" >> $@ +# $(Q) echo "};" >> $@ +mrproper-y += $(obj)/$(SYS-EXEC-TBL-GENERIC) +all-y += $(obj)/$(SYS-EXEC-TBL-GENERIC) + +$(eval $(call map,gen-rule-sys-codes,$(SYS-BITS))) +$(eval $(call map,gen-rule-sys-proto,$(SYS-BITS))) +$(eval $(call map,gen-rule-sys-asm,$(SYS-BITS))) +$(eval $(call map,gen-rule-sys-exec-tbl,$(SYS-BITS))) diff --git a/criu/arch/x86/syscalls/syscall32.c b/criu/arch/x86/syscalls/syscall32.c index b68ef0957..88af59330 100644 --- a/criu/arch/x86/syscalls/syscall32.c +++ b/criu/arch/x86/syscalls/syscall32.c @@ -1,5 +1,5 @@ #include "asm/types.h" -#include "syscall.h" +#include "syscall-32.h" #define SYS_SOCKET 1 /* sys_socket(2) */ #define SYS_BIND 2 /* sys_bind(2) */ diff --git a/criu/cr-exec.c b/criu/cr-exec.c index 75dfd0f95..aa8b0f634 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -17,12 +17,9 @@ struct syscall_exec_desc { unsigned nr; }; -static struct syscall_exec_desc sc_exec_table[] = { #define SYSCALL(__name, __nr) { .name = #__name, .nr = __nr, }, #include "sys-exec-tbl.c" #undef SYSCALL - { }, /* terminator */ -}; static struct syscall_exec_desc *find_syscall(char *name) { diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 220ee6e0c..4edcf4852 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -3,11 +3,18 @@ target += restorer parasite-obj-y += parasite.o parasite-obj-y += ./$(ARCH_DIR)/parasite-head.o -parasite-obj-e += ./$(ARCH_DIR)/syscalls.built-in.o restorer-obj-y += restorer.o restorer-obj-y += ./$(ARCH_DIR)/restorer.o + +ifeq ($(ARCH),x86) +# FIXME: depend on 32/64 pie type +parasite-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o +restorer-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o +else +parasite-obj-e += ./$(ARCH_DIR)/syscalls.built-in.o restorer-obj-e += ./$(ARCH_DIR)/syscalls.built-in.o +endif # # We can't provide proper mount implementation From bc5cca1a2900b90bb6fd6bc468afc82036978148 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:42 +0300 Subject: [PATCH 0009/4375] cr-exec: add non-generated sys-exec-tbl for x86 Impact: search sys-exec-tbl-32.c for compatible tasks. Rename task_in_compat_mode to arch_task_compatible and use it in find_syscall for 64-bit to check compatible task's syscall nr. It still will not execute syscall in 32-tasks, as we still do not have 32-bit pie (arch_can_dump_task will return false for these tasks). NOTE: be sure to `make mrproper` on criu directory before applying this patch, as before `criu/arch/x86/sys-exec-tbl.c` was autogenerated, it will make conflict if you try to apply this patch on dirty directory. Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .gitignore | 2 ++ criu/arch/x86/Makefile.syscalls | 18 ------------ criu/arch/x86/crtools.c | 4 +-- criu/arch/x86/sys-exec-tbl.c | 50 +++++++++++++++++++++++++++++++++ criu/cr-exec.c | 7 +++-- 5 files changed, 59 insertions(+), 22 deletions(-) create mode 100644 criu/arch/x86/sys-exec-tbl.c diff --git a/.gitignore b/.gitignore index ae5f8e3c5..b9a758281 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,8 @@ images/google/protobuf/*.h .gitid criu/criu criu/arch/*/sys-exec-tbl*.c +# x86 syscalls-table is not generated +!criu/arch/x86/sys-exec-tbl.c criu/arch/*/syscalls*.S criu/include/config.h criu/include/syscall-codes*.h diff --git a/criu/arch/x86/Makefile.syscalls b/criu/arch/x86/Makefile.syscalls index 79c58be3a..0506c1f2b 100644 --- a/criu/arch/x86/Makefile.syscalls +++ b/criu/arch/x86/Makefile.syscalls @@ -4,7 +4,6 @@ CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) CFLAGS := $(filter-out -DCONFIG_X86_64,$(CFLAGS)) SYS-PROTO-GENERIC := $(obj)/../../include/syscall.h -SYS-EXEC-TBL-GENERIC := sys-exec-tbl.c SYS-CODES-GENERIC = $(obj)/../../include/syscall-codes.h SYS-CODES = $(obj)/../../include/syscall-codes-$(1).h @@ -155,23 +154,6 @@ $(SYS-PROTO-GENERIC): $(strip $(call map,SYS-PROTO,$(SYS-BITS))) $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H__ */" >> $@ mrproper-y += $(SYS-PROTO-GENERIC) -$(obj)/$(SYS-EXEC-TBL-GENERIC): - $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) echo "static struct syscall_exec_desc sc_exec_table[] = {" >> $@ -ifeq ($(ARCH),x86) - $(Q) echo '#include "sys-exec-tbl-64.c"' >> $@ - $(Q) echo " { }, /* terminator */" >> $@ - $(Q) echo "};" >> $@ - $(Q) echo "" >> $@ -# FIXME: uncomment to support 32-bit task -# $(Q) echo "static struct syscall_exec_desc sc_exec_table_32[] = {" >> $@ -endif -# $(Q) echo '#include "sys-exec-tbl-32.c"' >> $@ -# $(Q) echo " { }, /* terminator */" >> $@ -# $(Q) echo "};" >> $@ -mrproper-y += $(obj)/$(SYS-EXEC-TBL-GENERIC) -all-y += $(obj)/$(SYS-EXEC-TBL-GENERIC) - $(eval $(call map,gen-rule-sys-codes,$(SYS-BITS))) $(eval $(call map,gen-rule-sys-proto,$(SYS-BITS))) $(eval $(call map,gen-rule-sys-asm,$(SYS-BITS))) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 6910fd110..c744aceb6 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -53,7 +53,7 @@ void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t * regs->flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_DF | X86_EFLAGS_IF); } -static int task_in_compat_mode(pid_t pid) +int arch_task_compatible(pid_t pid) { unsigned long cs, ds; @@ -79,7 +79,7 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) { pid_t pid = ctl->rpid; - if (task_in_compat_mode(pid)) { + if (arch_task_compatible(pid)) { pr_err("Can't dump task %d running in 32-bit mode\n", pid); return false; } diff --git a/criu/arch/x86/sys-exec-tbl.c b/criu/arch/x86/sys-exec-tbl.c new file mode 100644 index 000000000..b7f95b98e --- /dev/null +++ b/criu/arch/x86/sys-exec-tbl.c @@ -0,0 +1,50 @@ + +#ifdef CONFIG_X86_64 +static struct syscall_exec_desc sc_exec_table_64[] = { +#include "sys-exec-tbl-64.c" + { }, /* terminator */ +}; +#endif + +static struct syscall_exec_desc sc_exec_table_32[] = { +#include "sys-exec-tbl-32.c" + { }, /* terminator */ +}; + +struct syscall_exec_desc; + +static inline struct syscall_exec_desc * +find_syscall_table(char *name, struct syscall_exec_desc *tbl) +{ + int i; + + for (i = 0; tbl[i].name != NULL; i++) + if (!strcmp(tbl[i].name, name)) + return &tbl[i]; + return NULL; +} + +int __attribute__((weak)) arch_task_compatible(pid_t pid) { return false; } +#define ARCH_HAS_FIND_SYSCALL +/* overwrite default to search in two tables above */ +#ifdef CONFIG_X86_64 +struct syscall_exec_desc * find_syscall(char *name, int pid) +{ + int err = arch_task_compatible(pid); + + switch(err) { + case 0: + return find_syscall_table(name, sc_exec_table_64); + case 1: + return find_syscall_table(name, sc_exec_table_32); + default: /* Error */ + return NULL; + } +} +#else +struct syscall_exec_desc * +find_syscall(char *name, __attribute__((unused)) int pid) +{ + return find_syscall_table(name, sc_exec_table_32); +} +#endif diff --git a/criu/cr-exec.c b/criu/cr-exec.c index aa8b0f634..618a73c1e 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -21,7 +21,9 @@ struct syscall_exec_desc { #include "sys-exec-tbl.c" #undef SYSCALL -static struct syscall_exec_desc *find_syscall(char *name) +#ifndef ARCH_HAS_FIND_SYSCALL +struct syscall_exec_desc * +find_syscall(char *name, int __attribute__((unused)) pid) { int i; @@ -31,6 +33,7 @@ static struct syscall_exec_desc *find_syscall(char *name) return NULL; } +#endif #define MAX_ARGS 6 @@ -132,7 +135,7 @@ int cr_exec(int pid, char **opt) goto out; } - si = find_syscall(sys_name); + si = find_syscall(sys_name, pid); if (!si) { pr_err("Unknown syscall [%s]\n", sys_name); goto out; From 6b0fe1aff99f436e3954f7f320762ab26daa2c9f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:43 +0300 Subject: [PATCH 0010/4375] x86/pie: split parasite-head.S on {-32,-64} parts Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .../{parasite-head.S => parasite-head-32.S} | 22 +++---------------- criu/arch/x86/parasite-head-64.S | 22 +++++++++++++++++++ criu/pie/Makefile | 3 ++- 3 files changed, 27 insertions(+), 20 deletions(-) rename criu/arch/x86/{parasite-head.S => parasite-head-32.S} (53%) create mode 100644 criu/arch/x86/parasite-head-64.S diff --git a/criu/arch/x86/parasite-head.S b/criu/arch/x86/parasite-head-32.S similarity index 53% rename from criu/arch/x86/parasite-head.S rename to criu/arch/x86/parasite-head-32.S index e92e60d7f..900edebcb 100644 --- a/criu/arch/x86/parasite-head.S +++ b/criu/arch/x86/parasite-head-32.S @@ -3,23 +3,9 @@ .section .head.text, "ax" -#ifdef CONFIG_X86_64 - -ENTRY(__export_parasite_head_start) - subq $16, %rsp - andq $~15, %rsp - pushq $0 - movq %rsp, %rbp - movl __export_parasite_cmd(%rip), %edi - leaq __export_parasite_args(%rip), %rsi - call parasite_service - int $0x03 - .align 8 -__export_parasite_cmd: - .long 0 -END(__export_parasite_head_start) - -#else /* CONFIG_X86_64 */ +#ifndef CONFIG_X86_32 +# error 32-bit parasite should compile with CONFIG_X86_32 +#endif ENTRY(__export_parasite_head_start) subl $16, %esp @@ -36,5 +22,3 @@ ENTRY(__export_parasite_head_start) GLOBAL(__export_parasite_cmd) .long 0 END(__export_parasite_head_start) - -#endif /* CONFIG_X86_64 */ diff --git a/criu/arch/x86/parasite-head-64.S b/criu/arch/x86/parasite-head-64.S new file mode 100644 index 000000000..4cc4d920a --- /dev/null +++ b/criu/arch/x86/parasite-head-64.S @@ -0,0 +1,22 @@ +#include "asm/linkage.h" +#include "parasite.h" + + .section .head.text, "ax" + +#ifndef CONFIG_X86_64 +# error 64-bit parasite should compile with CONFIG_X86_64 +#endif + +ENTRY(__export_parasite_head_start) + subq $16, %rsp + andq $~15, %rsp + pushq $0 + movq %rsp, %rbp + movl __export_parasite_cmd(%rip), %edi + leaq __export_parasite_args(%rip), %rsi + call parasite_service + int $0x03 + .align 8 +__export_parasite_cmd: + .long 0 +END(__export_parasite_head_start) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 4edcf4852..c0eb2db8a 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -2,16 +2,17 @@ target += parasite target += restorer parasite-obj-y += parasite.o -parasite-obj-y += ./$(ARCH_DIR)/parasite-head.o restorer-obj-y += restorer.o restorer-obj-y += ./$(ARCH_DIR)/restorer.o ifeq ($(ARCH),x86) # FIXME: depend on 32/64 pie type +parasite-obj-y += ./$(ARCH_DIR)/parasite-head-64.o parasite-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o restorer-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o else +parasite-obj-y += ./$(ARCH_DIR)/parasite-head.o parasite-obj-e += ./$(ARCH_DIR)/syscalls.built-in.o restorer-obj-e += ./$(ARCH_DIR)/syscalls.built-in.o endif From af04c83c7cfc1e9d38bc65a0ec882fe236a23fe4 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:44 +0300 Subject: [PATCH 0011/4375] criu/pie: generate native.lib.a First pie library to use for compiling native pie. Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/Makefile | 6 +++--- criu/pie/Makefile | 4 ++-- criu/pie/Makefile.library | 26 ++++++++++++++------------ 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/criu/Makefile b/criu/Makefile index 4f4d673b5..c2ee5757f 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -52,12 +52,12 @@ $(ARCH-LIB): syscalls_lib # # PIE library code. -criu/pie/lib.a: $(ARCH-LIB) +criu/pie/native.lib.a: $(ARCH-LIB) $(Q) $(MAKE) $(call build-as,Makefile.library,criu/pie) all # # PIE code blobs themseves. -pie: criu/pie/lib.a +pie: criu/pie/native.lib.a $(Q) $(MAKE) $(build)=criu/pie all .PHONY: pie @@ -66,7 +66,7 @@ criu/pie/%: pie # # CRIU executable -PROGRAM-BUILTINS += criu/pie/lib.a +PROGRAM-BUILTINS += criu/pie/native.lib.a PROGRAM-BUILTINS += images/built-in.o PROGRAM-BUILTINS += $(obj)/built-in.o PROGRAM-BUILTINS += $(ARCH-LIB) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index c0eb2db8a..b7db1a374 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -79,9 +79,9 @@ ifeq ($(strip $(V)),) piegen_stdout := >/dev/null endif -$(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/lib.a $(obj)/$(PIELDS) +$(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/native.lib.a $(obj)/$(PIELDS) $(call msg-gen, $@) - $(Q) $(LD) -r -T $(obj)/$(PIELDS) -o $@ $< $(obj)/lib.a + $(Q) $(LD) -r -T $(obj)/$(PIELDS) -o $@ $< $(obj)/native.lib.a $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(obj)/$(PIELDS) compel/compel $(call msg-gen, $@) diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index dce650a51..1958393b4 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -1,26 +1,28 @@ -lib-y += log-simple.o -lib-y += util-fd.o -lib-y += util.o -lib-y += string.o +target := native + +$(target)-lib-y += log-simple.o +$(target)-lib-y += util-fd.o +$(target)-lib-y += util.o +$(target)-lib-y += string.o ifeq ($(VDSO),y) - lib-y += util-vdso.o - lib-y += parasite-vdso.o - lib-y += ./$(ARCH_DIR)/vdso-pie.o + $(target)-lib-y += util-vdso.o + $(target)-lib-y += parasite-vdso.o + $(target)-lib-y += ./$(ARCH_DIR)/vdso-pie.o ifeq ($(SRCARCH),aarch64) - lib-y += ./$(ARCH_DIR)/intraprocedure.o + $(target)-lib-y += ./$(ARCH_DIR)/intraprocedure.o endif ifeq ($(SRCARCH),ppc64) - lib-y += ./$(ARCH_DIR)/vdso-trampoline.o + $(target)-lib-y += ./$(ARCH_DIR)/vdso-trampoline.o endif endif ifeq ($(SRCARCH),ppc64) - lib-y += ./$(ARCH_DIR)/memcpy_power7.o - lib-y += ./$(ARCH_DIR)/memcmp_64.o - lib-y += ./$(ARCH_DIR)/misc.o + $(target)-lib-y += ./$(ARCH_DIR)/memcpy_power7.o + $(target)-lib-y += ./$(ARCH_DIR)/memcmp_64.o + $(target)-lib-y += ./$(ARCH_DIR)/misc.o endif ifeq ($(SRCARCH),x86) From 789f9208d4d1d4c972f55a1bae5e3aefee73edee Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:46 +0300 Subject: [PATCH 0012/4375] pie.lib: generate compatible pie object files Now compatible objects will be in $(obj)/compat/$(basename)-compat.o I can't use just $(obj)/compat/$(basename).o as basename for file will be the same as for native object, which wouldn't work by the reason of CFLAGS_$(F) in nmk-ccflags. So, I need different names for compatible/native objects. Because I don't want to make a mess in parent directories, I put this symlinks to compat/ dirs. This is how I came to that decision (even if I do not like it). Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/compat/vdso-pie-compat.c | 1 + criu/pie/Makefile.library | 45 ++++++++++++++++++-------- criu/pie/compat/log-simple-compat.c | 1 + criu/pie/compat/parasite-vdso-compat.c | 1 + criu/pie/compat/util-compat.c | 1 + criu/pie/compat/util-fd-compat.c | 1 + criu/pie/compat/util-vdso-compat.c | 1 + 7 files changed, 38 insertions(+), 13 deletions(-) create mode 120000 criu/arch/x86/compat/vdso-pie-compat.c create mode 120000 criu/pie/compat/log-simple-compat.c create mode 120000 criu/pie/compat/parasite-vdso-compat.c create mode 120000 criu/pie/compat/util-compat.c create mode 120000 criu/pie/compat/util-fd-compat.c create mode 120000 criu/pie/compat/util-vdso-compat.c diff --git a/criu/arch/x86/compat/vdso-pie-compat.c b/criu/arch/x86/compat/vdso-pie-compat.c new file mode 120000 index 000000000..98b1f39da --- /dev/null +++ b/criu/arch/x86/compat/vdso-pie-compat.c @@ -0,0 +1 @@ +../vdso-pie.c \ No newline at end of file diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 1958393b4..e2ad1b8fb 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -1,34 +1,53 @@ -target := native +target := native -$(target)-lib-y += log-simple.o -$(target)-lib-y += util-fd.o -$(target)-lib-y += util.o -$(target)-lib-y += string.o +CFLAGS := $(filter-out -DCONFIG_X86_64,$(CFLAGS)) +CFLAGS += -Wa,--noexecstack -fno-stack-protector -DCR_NOGLIBC + +CFLAGS_native += -fpie + +ifeq ($(ARCH),x86) + target += compat + CFLAGS_native += -DCONFIG_X86_64 + CFLAGS_compat += -fno-pic -m32 -DCONFIG_X86_32 +endif + +OBJS += log-simple.o util-fd.o util.o string.o ifeq ($(VDSO),y) - $(target)-lib-y += util-vdso.o - $(target)-lib-y += parasite-vdso.o - $(target)-lib-y += ./$(ARCH_DIR)/vdso-pie.o + OBJS += util-vdso.o parasite-vdso.o ./$(ARCH_DIR)/vdso-pie.o ifeq ($(SRCARCH),aarch64) - $(target)-lib-y += ./$(ARCH_DIR)/intraprocedure.o + OBJS += ./$(ARCH_DIR)/intraprocedure.o endif ifeq ($(SRCARCH),ppc64) - $(target)-lib-y += ./$(ARCH_DIR)/vdso-trampoline.o + OBJS += ./$(ARCH_DIR)/vdso-trampoline.o endif endif ifeq ($(SRCARCH),ppc64) - $(target)-lib-y += ./$(ARCH_DIR)/memcpy_power7.o - $(target)-lib-y += ./$(ARCH_DIR)/memcmp_64.o - $(target)-lib-y += ./$(ARCH_DIR)/misc.o + OBJS += ./$(ARCH_DIR)/memcpy_power7.o \ + ./$(ARCH_DIR)/memcmp_64.o ./$(ARCH_DIR)/misc.o endif ifeq ($(SRCARCH),x86) lib-y += ./$(ARCH_DIR)/memcpy.o endif +define gen-native-objs +native-lib-y += $(1) +CFLAGS_$(1) := $(CFLAGS_native) +endef + +compat-obj = $(basename $(notdir $(1)))-compat.o +define gen-compat-objs +compat-lib-y += $(dir ./$(call objectify,$(1)))compat/$(compat-obj) +CFLAGS_$(compat-obj) := $(CFLAGS_compat) +endef + +$(eval $(call map,gen-native-objs,$(OBJS))) +$(eval $(call map,gen-compat-objs,$(OBJS))) + # # We can't provide proper mount implementation # in parasite code -- it requires run-time rellocation diff --git a/criu/pie/compat/log-simple-compat.c b/criu/pie/compat/log-simple-compat.c new file mode 120000 index 000000000..fd4c4bae2 --- /dev/null +++ b/criu/pie/compat/log-simple-compat.c @@ -0,0 +1 @@ +../log-simple.c \ No newline at end of file diff --git a/criu/pie/compat/parasite-vdso-compat.c b/criu/pie/compat/parasite-vdso-compat.c new file mode 120000 index 000000000..95158832f --- /dev/null +++ b/criu/pie/compat/parasite-vdso-compat.c @@ -0,0 +1 @@ +../parasite-vdso.c \ No newline at end of file diff --git a/criu/pie/compat/util-compat.c b/criu/pie/compat/util-compat.c new file mode 120000 index 000000000..39606ede1 --- /dev/null +++ b/criu/pie/compat/util-compat.c @@ -0,0 +1 @@ +../util.c \ No newline at end of file diff --git a/criu/pie/compat/util-fd-compat.c b/criu/pie/compat/util-fd-compat.c new file mode 120000 index 000000000..358f069dc --- /dev/null +++ b/criu/pie/compat/util-fd-compat.c @@ -0,0 +1 @@ +../util-fd.c \ No newline at end of file diff --git a/criu/pie/compat/util-vdso-compat.c b/criu/pie/compat/util-vdso-compat.c new file mode 120000 index 000000000..4caac4510 --- /dev/null +++ b/criu/pie/compat/util-vdso-compat.c @@ -0,0 +1 @@ +../util-vdso.c \ No newline at end of file From 65566abd3c220b00f977e75d1da1d7a3e37949e1 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:47 +0300 Subject: [PATCH 0013/4375] pie/vdso: add i386 trampoline Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/vdso-pie.c | 41 +++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/criu/arch/x86/vdso-pie.c b/criu/arch/x86/vdso-pie.c index 3aac72e96..cef7f37c4 100644 --- a/criu/arch/x86/vdso-pie.c +++ b/criu/arch/x86/vdso-pie.c @@ -20,16 +20,34 @@ typedef struct { u16 jmp_rax; u32 guards; } __packed jmp_t; +#define IMMEDIATE(j) (j.imm64) + +jmp_t jmp = { + .movabs = 0xb848, + .jmp_rax = 0xe0ff, + .guards = 0xcccccccc, +}; + +#else /* CONFIG_X86_64 */ +typedef struct { + u8 movl; + u32 imm32; + u16 jmp_eax; + u32 guards; +} __packed jmp_t; +#define IMMEDIATE(j) (j.imm32) + +jmp_t jmp = { + .movl = 0xb8, + .jmp_eax = 0xe0ff, + .guards = 0xcccccccc, +}; +#endif /* CONFIG_X86_64 */ int vdso_redirect_calls(unsigned long base_to, unsigned long base_from, struct vdso_symtable *to, struct vdso_symtable *from) { - jmp_t jmp = { - .movabs = 0xb848, - .jmp_rax = 0xe0ff, - .guards = 0xcccccccc, - }; unsigned int i; for (i = 0; i < ARRAY_SIZE(to->symbols); i++) { @@ -40,20 +58,9 @@ int vdso_redirect_calls(unsigned long base_to, unsigned long base_from, base_from, from->symbols[i].offset, base_to, to->symbols[i].offset, i); - jmp.imm64 = base_to + to->symbols[i].offset; + IMMEDIATE(jmp) = base_to + to->symbols[i].offset; memcpy((void *)(base_from + from->symbols[i].offset), &jmp, sizeof(jmp)); } return 0; } - -#else /* CONFIG_X86_64 */ - -int vdso_redirect_calls(unsigned long base_to, unsigned long base_from, - struct vdso_symtable *to, - struct vdso_symtable *from) -{ - return 0; -} - -#endif /* CONFIG_X86_64 */ From 29a434c4cf8907023f4a8d3ac245025b77b9dc37 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:48 +0300 Subject: [PATCH 0014/4375] parasite: refactor macros for compat/native usage In code they yet use native parasite type, but in definition this parameter is not used (will be used at the next patch). Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 4 ++-- criu/include/parasite.h | 5 ++++- criu/include/restorer.h | 3 +-- criu/parasite-syscall.c | 13 +++++++------ criu/pie/Makefile | 6 +++++- criu/pie/pie-relocs.h | 18 ++++++++---------- 6 files changed, 27 insertions(+), 22 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 70147e31a..a5ec851ea 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2326,7 +2326,7 @@ static int prepare_restorer_blob(void) * in turn will lead to set-exe-file prctl to fail with EBUSY. */ - restorer_len = pie_size(restorer_blob); + restorer_len = pie_size(restorer); restorer = mmap(NULL, restorer_len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, 0, 0); @@ -2350,7 +2350,7 @@ static int remap_restorer_blob(void *addr) return -1; } - ELF_RELOCS_APPLY_RESTORER(addr, addr); + ELF_RELOCS_APPLY(restorer, addr, addr); return 0; } diff --git a/criu/include/parasite.h b/criu/include/parasite.h index fe8a116c2..f31b9f818 100644 --- a/criu/include/parasite.h +++ b/criu/include/parasite.h @@ -276,7 +276,10 @@ struct parasite_dump_cgroup_args { }; /* the parasite prefix is added by gen_offsets.sh */ -#define parasite_sym(pblob, name) ((void *)(pblob) + parasite_blob_offset__##name) +#define __pblob_offset(ptype, symbol) \ + parasite ## _blob_offset__ ## symbol +#define parasite_sym(pblob, ptype, symbol) \ + ((void *)(pblob) + __pblob_offset(ptype, symbol)) #endif /* !__ASSEMBLY__ */ diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 60246eff1..39a5f2f04 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -226,7 +226,6 @@ enum { /* the restorer_blob_offset__ prefix is added by gen_offsets.sh */ #define __blob_offset(name) restorer_blob_offset__ ## name -#define _blob_offset(name) __blob_offset(name) -#define restorer_sym(rblob, name) (void*)(rblob + _blob_offset(name)) +#define restorer_sym(rblob, name) (void*)(rblob + __blob_offset(name)) #endif /* __CR_RESTORER_H__ */ diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index a51d39687..6623f4352 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -1344,6 +1344,7 @@ static int parasite_start_daemon(struct parasite_ctl *ctl, struct pstree_item *i return 0; } +/* FIXME: parasite native/compat */ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, struct vm_area_list *vma_area_list) { @@ -1377,7 +1378,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ctl->args_size = round_up(parasite_args_size, PAGE_SIZE); parasite_args_size = PARASITE_ARG_SIZE_MIN; /* reset for next task */ - map_exchange_size = pie_size(parasite_blob) + ctl->args_size; + map_exchange_size = pie_size(parasite) + ctl->args_size; map_exchange_size += RESTORE_STACK_SIGFRAME + PARASITE_STACK_SIZE; if (item->nr_threads > 1) map_exchange_size += PARASITE_STACK_SIZE; @@ -1391,14 +1392,14 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map); memcpy(ctl->local_map, parasite_blob, sizeof(parasite_blob)); - ELF_RELOCS_APPLY_PARASITE(ctl->local_map, ctl->remote_map); + ELF_RELOCS_APPLY(parasite, ctl->local_map, ctl->remote_map); /* Setup the rest of a control block */ - ctl->parasite_ip = (unsigned long)parasite_sym(ctl->remote_map, __export_parasite_head_start); - ctl->addr_cmd = parasite_sym(ctl->local_map, __export_parasite_cmd); - ctl->addr_args = parasite_sym(ctl->local_map, __export_parasite_args); + ctl->parasite_ip = (unsigned long)parasite_sym(ctl->remote_map, native, __export_parasite_head_start); + ctl->addr_cmd = parasite_sym(ctl->local_map, native, __export_parasite_cmd); + ctl->addr_args = parasite_sym(ctl->local_map, native, __export_parasite_args); - p = pie_size(parasite_blob) + ctl->args_size; + p = pie_size(parasite) + ctl->args_size; ctl->rsigframe = ctl->remote_map + p; ctl->sigframe = ctl->local_map + p; diff --git a/criu/pie/Makefile b/criu/pie/Makefile index b7db1a374..0b6774062 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -85,7 +85,11 @@ $(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/native.lib.a $(obj)/$(PIELDS $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(obj)/$(PIELDS) compel/compel $(call msg-gen, $@) - $(Q) compel/compel piegen -f $< -v $(call target-name,$@)_relocs -p $(call target-name,$@)_blob_offset__ -s $(call target-name,$@)_blob -o $@ $(piegen_stdout) + $(Q) compel/compel piegen -f $< \ + -v $(call target-name,$@)_relocs \ + -p $(call target-name,$@)_blob_offset__ \ + -s $(call target-name,$@)_blob \ + -o $@ $(piegen_stdout) else diff --git a/criu/pie/pie-relocs.h b/criu/pie/pie-relocs.h index 269beadcd..7f863c669 100644 --- a/criu/pie/pie-relocs.h +++ b/criu/pie/pie-relocs.h @@ -10,19 +10,17 @@ extern __maybe_unused void elf_relocs_apply(void *mem, void *vbase, size_t size, elf_reloc_t *elf_relocs, size_t nr_relocs); -#define pie_size(__blob_name) (round_up(sizeof(__blob_name) + nr_gotpcrel * sizeof(long), page_size())) -#define ELF_RELOCS_APPLY_PARASITE(__mem, __vbase) \ - elf_relocs_apply(__mem, __vbase, sizeof(parasite_blob), \ - parasite_relocs, ARRAY_SIZE(parasite_relocs)) -#define ELF_RELOCS_APPLY_RESTORER(__mem, __vbase) \ - elf_relocs_apply(__mem, __vbase, sizeof(restorer_blob), \ - restorer_relocs, ARRAY_SIZE(restorer_relocs)) +/* FIXME: native/compat pie's pie_size(), ELF_RELOCS_APPLY() */ +#define pie_size(__pie_name) (round_up(sizeof(__pie_name##_blob) + \ + __pie_name ## _nr_gotpcrel * sizeof(long), page_size())) +#define ELF_RELOCS_APPLY(__pie_name, __mem, __vbase) \ + elf_relocs_apply(__mem, __vbase, sizeof(__pie_name##_blob), \ + __pie_name##_relocs, ARRAY_SIZE(__pie_name##_relocs)) #else -#define pie_size(__blob_name) (round_up(sizeof(__blob_name), page_size())) -#define ELF_RELOCS_APPLY_PARASITE(__mem, __vbase) -#define ELF_RELOCS_APPLY_RESTORER(__mem, __vbase) +#define pie_size(__pie_name) (round_up(sizeof(__pie_name##_blob), page_size())) +#define ELF_RELOCS_APPLY(__pie_name, __mem, __vbase) #endif From d94b9f3065057b8e3eb49a519499764dcacd3409 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:49 +0300 Subject: [PATCH 0015/4375] pie: generate native and compat parasites Only parasite should be mode-depended, not restorer, as restorer will just switch to compatible mode with arch_prctl at the end and jump to 32-bit executable with sigreturn. So for parasite there are two targets: "native" and "compat", and one for restorer with the same name "restorer". It will result in parasite-native.o, parasite-compat.o and restorer.o objects. Pie build still may work with piegen or without it (gen-offset.sh). There are many FIXME in this patch, all them are in C code, that should be fixed to use compatible parsite when needed. Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .gitignore | 4 +- criu/include/parasite.h | 2 +- criu/parasite-syscall.c | 8 +- criu/pie/Makefile | 176 ++++++++++++++++++++---------- criu/pie/compat/parasite-compat.c | 1 + criu/pie/parasite-blob.h | 6 + 6 files changed, 134 insertions(+), 63 deletions(-) create mode 120000 criu/pie/compat/parasite-compat.c create mode 100644 criu/pie/parasite-blob.h diff --git a/.gitignore b/.gitignore index b9a758281..91ca0437f 100644 --- a/.gitignore +++ b/.gitignore @@ -33,9 +33,9 @@ criu/include/syscall*.h soccr/config.h criu/include/version.h criu/pie/restorer-blob.h -criu/pie/parasite-blob.h +criu/pie/parasite-*-blob.h criu/pie/piegen/piegen -criu/pie/pie.lds.S +criu/pie/pie.lds*.S criu/protobuf-desc-gen.h scripts/build/qemu-user-static/* lib/.crit-setup.files diff --git a/criu/include/parasite.h b/criu/include/parasite.h index f31b9f818..965b1dcf3 100644 --- a/criu/include/parasite.h +++ b/criu/include/parasite.h @@ -277,7 +277,7 @@ struct parasite_dump_cgroup_args { /* the parasite prefix is added by gen_offsets.sh */ #define __pblob_offset(ptype, symbol) \ - parasite ## _blob_offset__ ## symbol + parasite_ ## ptype ## _blob_offset__ ## symbol #define parasite_sym(pblob, ptype, symbol) \ ((void *)(pblob) + __pblob_offset(ptype, symbol)) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 6623f4352..9a9df360d 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -1378,7 +1378,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ctl->args_size = round_up(parasite_args_size, PAGE_SIZE); parasite_args_size = PARASITE_ARG_SIZE_MIN; /* reset for next task */ - map_exchange_size = pie_size(parasite) + ctl->args_size; + map_exchange_size = pie_size(parasite_native) + ctl->args_size; map_exchange_size += RESTORE_STACK_SIGFRAME + PARASITE_STACK_SIZE; if (item->nr_threads > 1) map_exchange_size += PARASITE_STACK_SIZE; @@ -1390,16 +1390,16 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, goto err_restore; pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map); - memcpy(ctl->local_map, parasite_blob, sizeof(parasite_blob)); + memcpy(ctl->local_map, parasite_native_blob, sizeof(parasite_native_blob)); - ELF_RELOCS_APPLY(parasite, ctl->local_map, ctl->remote_map); + ELF_RELOCS_APPLY(parasite_native, ctl->local_map, ctl->remote_map); /* Setup the rest of a control block */ ctl->parasite_ip = (unsigned long)parasite_sym(ctl->remote_map, native, __export_parasite_head_start); ctl->addr_cmd = parasite_sym(ctl->local_map, native, __export_parasite_cmd); ctl->addr_args = parasite_sym(ctl->local_map, native, __export_parasite_args); - p = pie_size(parasite) + ctl->args_size; + p = pie_size(parasite_native) + ctl->args_size; ctl->rsigframe = ctl->remote_map + p; ctl->sigframe = ctl->local_map + p; diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 0b6774062..7539f79ac 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -1,22 +1,38 @@ -target += parasite -target += restorer +# native/compat target names are _only_ for parasite +# restorer is always native (64-bit) +parasite_target := native -parasite-obj-y += parasite.o +ifeq ($(ARCH),x86) + parasite_target += compat +endif + +native-obj-y += parasite.o +compat-obj-y += compat/parasite-compat.o restorer-obj-y += restorer.o restorer-obj-y += ./$(ARCH_DIR)/restorer.o ifeq ($(ARCH),x86) -# FIXME: depend on 32/64 pie type -parasite-obj-y += ./$(ARCH_DIR)/parasite-head-64.o -parasite-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o -restorer-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o + restorer-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o + + native-obj-y += ./$(ARCH_DIR)/parasite-head-64.o + native-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o + compat-obj-y += ./$(ARCH_DIR)/parasite-head-32.o + compat-obj-e += ./$(ARCH_DIR)/syscalls-32.built-in.o + + AFLAGS_parasite-head-64.o += -fpie -DCONFIG_X86_64 + AFLAGS_parasite-head-64.d += -fpie -DCONFIG_X86_64 + + AFLAGS_parasite-head-32.o += -fno-pic -m32 -DCONFIG_X86_32 + AFLAGS_parasite-head-32.d += -fno-pic -m32 -DCONFIG_X86_32 else -parasite-obj-y += ./$(ARCH_DIR)/parasite-head.o -parasite-obj-e += ./$(ARCH_DIR)/syscalls.built-in.o -restorer-obj-e += ./$(ARCH_DIR)/syscalls.built-in.o + native-obj-y += ./$(ARCH_DIR)/parasite-head.o + native-obj-e += ./$(ARCH_DIR)/syscalls.built-in.o + restorer-obj-e += ./$(ARCH_DIR)/syscalls.built-in.o endif +target += $(parasite_target) restorer + # # We can't provide proper mount implementation # in parasite code -- it requires run-time rellocation @@ -24,6 +40,7 @@ endif # project. # CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) +CFLAGS := $(filter-out -DCONFIG_X86_64,$(CFLAGS)) CFLAGS += -iquote $(SRC_DIR)/compel/include CFLAGS += -iquote $(SRC_DIR)/criu/arch/$(ARCH)/include CFLAGS += -iquote $(SRC_DIR)/criu/include @@ -34,10 +51,28 @@ CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 ccflags-y += -DCR_NOGLIBC -ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) - ccflags-y += $(shell $(SRC_DIR)/compel/compel --arch=$(ARCH) cflags) +NATIVE_CFLAGS := $(shell $(SRC_DIR)/compel/compel --arch=$(ARCH) cflags) + +ifeq ($(ARCH),x86) + NATIVE_CFLAGS += -DCONFIG_X86_64 + COMPAT_CFLAGS += -fno-pic -m32 -DCONFIG_X86_32 + COMPAT_LDFLAGS += -m elf_i386 endif +CFLAGS_restorer.o += $(NATIVE_CFLAGS) +# $1 - object name +define obj-export-native-flags + CFLAGS_$(notdir $(1)) := $(NATIVE_CFLAGS) +endef +# $1 - object name +define obj-export-compat-flags + CFLAGS_$(notdir $(1)) := $(COMPAT_CFLAGS) + LDFLAGS_$(notdir $(1)) := $(COMPAT_LDFLAGS) +endef + +$(eval $(call map,obj-export-native-flags,$(native-obj-y) native)) +$(eval $(call map,obj-export-compat-flags,$(compat-obj-y) compat)) + ifeq ($(SRCARCH),arm) ccflags-y += -marm endif @@ -45,67 +80,97 @@ endif asflags-y += -D__ASSEMBLY__ GEN-OFFSETS := $(obj)/../../scripts/gen-offsets.sh -BLOBS := $(obj)/parasite-blob.h $(obj)/restorer-blob.h -PIELDS := pie.lds.S +BLOBS += $(obj)/restorer-blob.h + +define gen-pields-blobs-var +PIELDS += $(obj)/pie.lds-$(1).S +BLOBS += $(obj)/parasite-$(1)-blob.h +endef +$(eval $(call map,gen-pields-blobs-var,$(parasite_target))) .SECONDARY: ifeq ($(piegen-y),y) -target-name = $(patsubst criu/pie/%-blob.h,%,$(1)) - -ifeq ($(SRCARCH),ppc64) -$(obj)/$(PIELDS): $(obj)/pie-reloc.lds.S.in - $(call msg-gen, $@) - $(Q) echo "OUTPUT_ARCH($(LDARCH))" > $(obj)/$(PIELDS) - $(Q) cat $< >> $(obj)/$(PIELDS) +PIELDS_INCLUDE := $(obj)/pie-reloc.lds.S.in else -ifeq ($(ARCH),x86) -$(obj)/$(PIELDS): $(obj)/pie-reloc.lds.S.in - $(call msg-gen, $@) - $(Q) echo "OUTPUT_ARCH(i386:x86-64)" > $(obj)/$(PIELDS) - $(Q) echo "TARGET(elf64-x86-64)" >> $(obj)/$(PIELDS) - $(Q) cat $< >> $(obj)/$(PIELDS) -else # i386 ia32 -$(obj)/$(PIELDS): $(obj)/pie-reloc.lds.S.in - $(call msg-gen, $@) - $(Q) echo "OUTPUT_ARCH(i386)" > $(obj)/$(PIELDS) - $(Q) echo "TARGET(elf32-i386)" >> $(obj)/$(PIELDS) - $(Q) cat $< >> $(obj)/$(PIELDS) -endif +PIELDS_INCLUDE := $(obj)/pie.lds.S.in endif +ifeq ($(ARCH),x86) +$(obj)/pie.lds-native.S: $(PIELDS_INCLUDE) + $(call msg-gen, $@) + $(Q) echo "OUTPUT_ARCH(i386:x86-64)" > $@ + $(Q) echo "TARGET(elf64-x86-64)" >> $@ + $(Q) cat $< >> $@ + +$(obj)/pie.lds-compat.S: $(PIELDS_INCLUDE) + $(call msg-gen, $@) + $(Q) echo "OUTPUT_ARCH(i386)" > $@ + $(Q) echo "TARGET(elf32-i386)" >> $@ + $(Q) cat $< >> $@ +else # !x86 +ifeq ($(filter-out i386 ia32,$(ARCH)),) +$(PIELDS): $(PIELDS_INCLUDE) + $(call msg-gen, $@) + $(Q) echo "OUTPUT_ARCH(i386)" > $@ + $(Q) echo "TARGET(elf32-i386)" >> $@ + $(Q) cat $< >> $@ +else # arm, aarch64, ppc64 +$(PIELDS): $(PIELDS_INCLUDE) + $(call msg-gen, $@) + $(Q) echo "OUTPUT_ARCH($(LDARCH))" > $@ + $(Q) cat $< >> $@ +endif # non i386 +endif # non x86 ARCH + +# for C files, we need "parasite-native" to be "parasite_native" +target-name = $(patsubst criu/pie/%_blob.h,%,$(subst -,_,$(1))) + +ifeq ($(piegen-y),y) ifeq ($(strip $(V)),) piegen_stdout := >/dev/null endif -$(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/native.lib.a $(obj)/$(PIELDS) +$(obj)/restorer.built-in.bin.o: $(obj)/restorer.built-in.o \ + $(obj)/native.lib.a $(obj)/pie.lds-native.S $(call msg-gen, $@) - $(Q) $(LD) -r -T $(obj)/$(PIELDS) -o $@ $< $(obj)/native.lib.a + $(Q) $(LD) -r -T $(obj)/pie.lds-native.S -o $@ $< $(obj)/native.lib.a -$(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(obj)/$(PIELDS) compel/compel +# $1 - binary mode: native/compat +define gen-rule-built-in.bin.o +$(obj)/parasite-$(1).built-in.bin.o: $(obj)/$(1).built-in.o \ + $(obj)/$(1).lib.a $(obj)/pie.lds-$(1).S + $$(call msg-gen, $$@) + $(Q) $(LD) -r -T $(obj)/pie.lds-$(1).S -o $$@ $$< $(obj)/$(1).lib.a +endef +$(eval $(call map,gen-rule-built-in.bin.o,$(parasite_target))) + +$(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel $(call msg-gen, $@) - $(Q) compel/compel piegen -f $< \ + $(Q) $(SRC_DIR)/compel/compel piegen -f $< \ -v $(call target-name,$@)_relocs \ -p $(call target-name,$@)_blob_offset__ \ -s $(call target-name,$@)_blob \ + -r $(call target-name,$@)_nr_gotpcrel \ + -u $(SRC_DIR)/compel/include/uapi \ -o $@ $(piegen_stdout) -else +else # !piegen-y -$(obj)/$(PIELDS): $(obj)/$(PIELDS).in +define gen-rule-built-in.bin.o +$(obj)/parasite-$(1).built-in.bin.o: $(obj)/$(1).built-in.o \ + $(obj)/pie.lds-$(1).S + $$(call msg-gen, $$@) + $(Q) $(LD) -r -T $(obj)/pie.lds-$(1).S -o $$@ $$< +endef + +$(eval $(call map,gen-rule-built-in.bin.o,$(parasite_target))) + +$(obj)/restorer.built-in.bin.o: $(obj)/restorer.built-in.o \ + $(obj)/pie.lds-native.S $(call msg-gen, $@) - $(Q) $(SH) -c "echo 'OUTPUT_ARCH($(LDARCH))' > $(obj)/$(PIELDS)" - $(Q) $(SH) -c "cat $(obj)/$(PIELDS).in >> $(obj)/$(PIELDS)" - -# ld on arm doesn't like -pie and -r options together -ifeq ($(filter arm aarch64,$(ARCH)),) - LD_R := -r -endif - -$(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/$(PIELDS) $(obj)/lib.a - $(call msg-gen, $@) - $(Q) $(LD) $(LD_R) -T $(obj)/$(PIELDS) -o $@ $< $(obj)/lib.a + $(Q) $(LD) -r -T $(obj)/pie.lds-native.S -o $@ $< $(obj)/%.built-in.bin: $(obj)/%.built-in.bin.o $(call msg-gen, $@) @@ -113,17 +178,16 @@ $(obj)/%.built-in.bin: $(obj)/%.built-in.bin.o $(obj)/%-blob.h: $(obj)/%.built-in.bin $(GEN-OFFSETS) $(call msg-gen, $@) - $(Q) $(SH) $(GEN-OFFSETS) $(@:-blob.h=) $(notdir $(@:-blob.h=)) $(CROSS_COMPILE) > $@ + $(Q) $(SH) $(GEN-OFFSETS) $(@:-blob.h=) $(call target-name,$@) $(CROSS_COMPILE) > $@ -endif -$(BLOBS): $(obj)/$(PIELDS) +endif # !piegen-y + all-y += $(BLOBS) - # blobs and pields are in cleanup, rather than in mrproper because # we want them to be re-generated after `make clean && make` cleanup-y += $(BLOBS) -cleanup-y += $(obj)/$(PIELDS) +cleanup-y += $(PIELDS) cleanup-y += $(obj)/*.bin cleanup-y += $(obj)/*.built-in.bin.o cleanup-y += $(obj)/*.built-in.bin diff --git a/criu/pie/compat/parasite-compat.c b/criu/pie/compat/parasite-compat.c new file mode 120000 index 000000000..bc5cbac9d --- /dev/null +++ b/criu/pie/compat/parasite-compat.c @@ -0,0 +1 @@ +../parasite.c \ No newline at end of file diff --git a/criu/pie/parasite-blob.h b/criu/pie/parasite-blob.h new file mode 100644 index 000000000..278ca6d85 --- /dev/null +++ b/criu/pie/parasite-blob.h @@ -0,0 +1,6 @@ +#include "parasite-native-blob.h" + +#ifdef CONFIG_X86_64 +/* FIXME: parasite_compat_blob defined but not used */ +/* # include "parasite-compat-blob.h"*/ +#endif From 6068d10cee4a7976876d7a8a9d24fd40ffdbb1b9 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 18 Apr 2016 21:02:00 +0300 Subject: [PATCH 0016/4375] core/x86: add compatible 32 register set Introduced user_regs_struct32. Other changes mainly are reforming existing code to use the new register sets union. For protobuf images - reuse user_x86_regs_entry for both compatible and native tasks with enum in the beggining that describes register set type. That's better and simpler, than introducing a new 32-bit register set for compatible tasks. I tried to do this firstly with oneof keyword: https://github.com/0x7f454c46/criu/commit/499c93ae0e2b8ffb8c562f309bb046d77d6b07c0 But protobuf supports oneof keyword only from recent version 2.6.0, so I tried to rework it into enum + 2 register sets: https://github.com/0x7f454c46/criu/commit/aab4489bd4e0b1360b6e05614c2fce3ff2a52eb7 But that did not work either because restorer pie takes gpregs as thread_restore_args parameter and UserRegsEntry shouldn't contain pointers, but structure objects. This may be fixed by redefining UserRegsEntry not as typedef for UserX86RegsEntry, but containing needed objects, than treat it right for restorer - but that's more complicated that reusing user_x86_regs_entry. Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 213 ++++++++++++++++------- criu/arch/x86/include/asm/dump.h | 3 + criu/arch/x86/include/asm/infect-types.h | 104 +++++++---- criu/parasite-syscall.c | 2 + images/core-x86.proto | 7 + 5 files changed, 239 insertions(+), 90 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index c744aceb6..0b85aab2c 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -26,6 +26,7 @@ /* * Injected syscall instruction */ +/* FIXME: 32-bit syscalls */ const char code_syscall[] = { 0x0f, 0x05, /* syscall */ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc /* int 3, ... */ @@ -40,17 +41,21 @@ static inline __always_unused void __check_code_syscall(void) BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); } +/* + * regs must be inited when calling this function from original context + */ void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) { - regs->ip = new_ip; + set_user_reg(regs, ip, new_ip); if (stack) - regs->sp = (unsigned long) stack; + set_user_reg(regs, sp, (unsigned long) stack); /* Avoid end of syscall processing */ - regs->orig_ax = -1; + set_user_reg(regs, orig_ax, -1); /* Make sure flags are in known state */ - regs->flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_DF | X86_EFLAGS_IF); + set_user_reg(regs, flags, get_user_reg(regs, flags) & + ~(X86_EFLAGS_TF | X86_EFLAGS_DF | X86_EFLAGS_IF)); } int arch_task_compatible(pid_t pid) @@ -58,14 +63,18 @@ int arch_task_compatible(pid_t pid) unsigned long cs, ds; errno = 0; - cs = ptrace(PTRACE_PEEKUSER, pid, offsetof(user_regs_struct_t, cs), 0); + /* + * Offset of register must be from 64-bit set even for + * compatible tasks. Fix this to support native i386 tasks + */ + cs = ptrace(PTRACE_PEEKUSER, pid, offsetof(user_regs_struct64, cs), 0); if (errno != 0) { pr_perror("Can't get CS register for %d", pid); return -1; } errno = 0; - ds = ptrace(PTRACE_PEEKUSER, pid, offsetof(user_regs_struct_t, ds), 0); + ds = ptrace(PTRACE_PEEKUSER, pid, offsetof(user_regs_struct64, ds), 0); if (errno != 0) { pr_perror("Can't get DS register for %d", pid); return -1; @@ -79,6 +88,7 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) { pid_t pid = ctl->rpid; + /* FIXME: remove it */ if (arch_task_compatible(pid)) { pr_err("Can't dump task %d running in 32-bit mode\n", pid); return false; @@ -98,23 +108,40 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, user_regs_struct_t regs = ctl->orig.regs; int err; - regs.ax = (unsigned long)nr; - regs.di = arg1; - regs.si = arg2; - regs.dx = arg3; - regs.r10 = arg4; - regs.r8 = arg5; - regs.r9 = arg6; + if (regs.is_native) { + user_regs_struct64 *r = ®s.native; + + r->ax = (uint64_t)nr; + r->di = arg1; + r->si = arg2; + r->dx = arg3; + r->r10 = arg4; + r->r8 = arg5; + r->r9 = arg6; + } else { + user_regs_struct32 *r = ®s.compat; + + r->ax = (uint32_t)nr; + r->bx = arg1; + r->cx = arg2; + r->dx = arg3; + r->si = arg4; + r->di = arg5; + r->bp = arg6; + } err = __parasite_execute_syscall(ctl, ®s, code_syscall); - *ret = regs.ax; + *ret = get_user_reg(®s, ax); return err; } static int save_task_regs(CoreEntry *core, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs); +#define get_signed_user_reg(pregs, name) \ + (((pregs)->is_native) ? (int64_t)((pregs)->native.name) : \ + (int32_t)((pregs)->compat.name)) int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) { user_fpregs_struct_t xsave = { }, *xs = NULL; @@ -125,18 +152,18 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) pr_info("Dumping GP/FPU registers for %d\n", pid); /* Did we come from a system call? */ - if ((int)regs.orig_ax >= 0) { + if (get_signed_user_reg(®s, orig_ax) >= 0) { /* Restart the system call */ - switch ((long)(int)regs.ax) { + switch (get_signed_user_reg(®s, ax)) { case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: - regs.ax = regs.orig_ax; - regs.ip -= 2; + set_user_reg(®s, ax, get_user_reg(®s, orig_ax)); + set_user_reg(®s, ip, get_user_reg(®s, ip) - 2); break; case -ERESTART_RESTARTBLOCK: pr_warn("Will restore %d with interrupted system call\n", pid); - regs.ax = -EINTR; + set_user_reg(®s, ax, -EINTR); break; } } @@ -180,61 +207,83 @@ static int save_task_regs(CoreEntry *core, { UserX86RegsEntry *gpregs = core->thread_info->gpregs; -#define assign_reg(dst, src, e) do { dst->e = (__typeof__(dst->e))(src)->e; } while (0) -#define assign_array(dst, src, e) memcpy(dst->e, &(src)->e, sizeof((src)->e)) +#define assign_reg(dst, src, e) do { dst->e = (__typeof__(dst->e))src.e; } while (0) +#define assign_array(dst, src, e) memcpy(dst->e, &src.e, sizeof(src.e)) - assign_reg(gpregs, regs, r15); - assign_reg(gpregs, regs, r14); - assign_reg(gpregs, regs, r13); - assign_reg(gpregs, regs, r12); - assign_reg(gpregs, regs, bp); - assign_reg(gpregs, regs, bx); - assign_reg(gpregs, regs, r11); - assign_reg(gpregs, regs, r10); - assign_reg(gpregs, regs, r9); - assign_reg(gpregs, regs, r8); - assign_reg(gpregs, regs, ax); - assign_reg(gpregs, regs, cx); - assign_reg(gpregs, regs, dx); - assign_reg(gpregs, regs, si); - assign_reg(gpregs, regs, di); - assign_reg(gpregs, regs, orig_ax); - assign_reg(gpregs, regs, ip); - assign_reg(gpregs, regs, cs); - assign_reg(gpregs, regs, flags); - assign_reg(gpregs, regs, sp); - assign_reg(gpregs, regs, ss); - assign_reg(gpregs, regs, fs_base); - assign_reg(gpregs, regs, gs_base); - assign_reg(gpregs, regs, ds); - assign_reg(gpregs, regs, es); - assign_reg(gpregs, regs, fs); - assign_reg(gpregs, regs, gs); + if (regs.is_native) { + assign_reg(gpregs, regs->native, r15); + assign_reg(gpregs, regs->native, r14); + assign_reg(gpregs, regs->native, r13); + assign_reg(gpregs, regs->native, r12); + assign_reg(gpregs, regs->native, bp); + assign_reg(gpregs, regs->native, bx); + assign_reg(gpregs, regs->native, r11); + assign_reg(gpregs, regs->native, r10); + assign_reg(gpregs, regs->native, r9); + assign_reg(gpregs, regs->native, r8); + assign_reg(gpregs, regs->native, ax); + assign_reg(gpregs, regs->native, cx); + assign_reg(gpregs, regs->native, dx); + assign_reg(gpregs, regs->native, si); + assign_reg(gpregs, regs->native, di); + assign_reg(gpregs, regs->native, orig_ax); + assign_reg(gpregs, regs->native, ip); + assign_reg(gpregs, regs->native, cs); + assign_reg(gpregs, regs->native, flags); + assign_reg(gpregs, regs->native, sp); + assign_reg(gpregs, regs->native, ss); + assign_reg(gpregs, regs->native, fs_base); + assign_reg(gpregs, regs->native, gs_base); + assign_reg(gpregs, regs->native, ds); + assign_reg(gpregs, regs->native, es); + assign_reg(gpregs, regs->native, fs); + assign_reg(gpregs, regs->native, gs); + gpregs->mode = USER_X86_REGS_MODE__NATIVE; + } else { + assign_reg(gpregs, regs->compat, bx); + assign_reg(gpregs, regs->compat, cx); + assign_reg(gpregs, regs->compat, dx); + assign_reg(gpregs, regs->compat, si); + assign_reg(gpregs, regs->compat, di); + assign_reg(gpregs, regs->compat, bp); + assign_reg(gpregs, regs->compat, ax); + assign_reg(gpregs, regs->compat, ds); + assign_reg(gpregs, regs->compat, es); + assign_reg(gpregs, regs->compat, fs); + assign_reg(gpregs, regs->compat, gs); + assign_reg(gpregs, regs->compat, orig_ax); + assign_reg(gpregs, regs->compat, ip); + assign_reg(gpregs, regs->compat, cs); + assign_reg(gpregs, regs->compat, flags); + assign_reg(gpregs, regs->compat, sp); + assign_reg(gpregs, regs->compat, ss); + gpregs->mode = USER_X86_REGS_MODE__COMPAT; + } if (!fpregs) return 0; - assign_reg(core->thread_info->fpregs, &fpregs->i387, cwd); - assign_reg(core->thread_info->fpregs, &fpregs->i387, swd); - assign_reg(core->thread_info->fpregs, &fpregs->i387, twd); - assign_reg(core->thread_info->fpregs, &fpregs->i387, fop); - assign_reg(core->thread_info->fpregs, &fpregs->i387, rip); - assign_reg(core->thread_info->fpregs, &fpregs->i387, rdp); - assign_reg(core->thread_info->fpregs, &fpregs->i387, mxcsr); - assign_reg(core->thread_info->fpregs, &fpregs->i387, mxcsr_mask); + assign_reg(core->thread_info->fpregs, fpregs->i387, cwd); + assign_reg(core->thread_info->fpregs, fpregs->i387, swd); + assign_reg(core->thread_info->fpregs, fpregs->i387, twd); + assign_reg(core->thread_info->fpregs, fpregs->i387, fop); + assign_reg(core->thread_info->fpregs, fpregs->i387, rip); + assign_reg(core->thread_info->fpregs, fpregs->i387, rdp); + assign_reg(core->thread_info->fpregs, fpregs->i387, mxcsr); + assign_reg(core->thread_info->fpregs, fpregs->i387, mxcsr_mask); /* Make sure we have enough space */ BUG_ON(core->thread_info->fpregs->n_st_space != ARRAY_SIZE(fpregs->i387.st_space)); BUG_ON(core->thread_info->fpregs->n_xmm_space != ARRAY_SIZE(fpregs->i387.xmm_space)); - assign_array(core->thread_info->fpregs, &fpregs->i387, st_space); - assign_array(core->thread_info->fpregs, &fpregs->i387, xmm_space); + assign_array(core->thread_info->fpregs, fpregs->i387, st_space); + assign_array(core->thread_info->fpregs, fpregs->i387, xmm_space); if (cpu_has_feature(X86_FEATURE_OSXSAVE)) { BUG_ON(core->thread_info->fpregs->xsave->n_ymmh_space != ARRAY_SIZE(fpregs->ymmh.ymmh_space)); - assign_reg(core->thread_info->fpregs->xsave, &fpregs->xsave_hdr, xstate_bv); - assign_array(core->thread_info->fpregs->xsave, &fpregs->ymmh, ymmh_space); + assign_reg(core->thread_info->fpregs->xsave, fpregs->xsave_hdr, xstate_bv); + assign_array(core->thread_info->fpregs->xsave, fpregs->ymmh, ymmh_space); } #undef assign_reg @@ -243,6 +292,44 @@ static int save_task_regs(CoreEntry *core, return 0; } +int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs) +{ + struct iovec iov; + int ret; + + iov.iov_base = ®s->native; + iov.iov_len = sizeof(user_regs_struct64); + + ret = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov); + if (iov.iov_len == sizeof(regs->native)) { + regs->is_native = true; + return ret; + } + if (iov.iov_len == sizeof(regs->compat)) { + regs->is_native = false; + return ret; + } + + pr_err("PTRACE_GETREGSET read %zu bytes for pid %d, but native/compat regs sizes are %zu/%zu bytes", + iov.iov_len, pid, + sizeof(regs->native), sizeof(regs->compat)); + return -1; +} + +int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs) +{ + struct iovec iov; + + if (regs->is_native) { + iov.iov_base = ®s->native; + iov.iov_len = sizeof(user_regs_struct64); + } else { + iov.iov_base = ®s->compat; + iov.iov_len = sizeof(user_regs_struct32); + } + return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov); +} + int arch_alloc_thread_info(CoreEntry *core) { size_t sz; @@ -477,6 +564,12 @@ void *mmap_seized(struct parasite_ctl *ctl, int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) { + /* FIXME: rt_sigcontext for compatible tasks */ + if (r->gpregs_case != USER_X86_REGS_CASE_T__NATIVE) { + pr_err("Can't prepare rt_sigframe for compatible task restore\n"); + return -1; + } + #define CPREG1(d) f->uc.uc_mcontext.d = r->d #define CPREG2(d, s) f->uc.uc_mcontext.d = r->s diff --git a/criu/arch/x86/include/asm/dump.h b/criu/arch/x86/include/asm/dump.h index 1505fd298..02ec20042 100644 --- a/criu/arch/x86/include/asm/dump.h +++ b/criu/arch/x86/include/asm/dump.h @@ -5,6 +5,9 @@ extern int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core); extern int arch_alloc_thread_info(CoreEntry *core); extern void arch_free_thread_info(CoreEntry *core); +#define ARCH_HAS_GET_REGS +extern int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs); +extern int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs); #define core_put_tls(core, tls) diff --git a/criu/arch/x86/include/asm/infect-types.h b/criu/arch/x86/include/asm/infect-types.h index 24727ed1f..d56902acf 100644 --- a/criu/arch/x86/include/asm/infect-types.h +++ b/criu/arch/x86/include/asm/infect-types.h @@ -11,34 +11,78 @@ #define SIGMAX_OLD 31 typedef struct { - unsigned long r15; - unsigned long r14; - unsigned long r13; - unsigned long r12; - unsigned long bp; - unsigned long bx; - unsigned long r11; - unsigned long r10; - unsigned long r9; - unsigned long r8; - unsigned long ax; - unsigned long cx; - unsigned long dx; - unsigned long si; - unsigned long di; - unsigned long orig_ax; - unsigned long ip; - unsigned long cs; - unsigned long flags; - unsigned long sp; - unsigned long ss; - unsigned long fs_base; - unsigned long gs_base; - unsigned long ds; - unsigned long es; - unsigned long fs; - unsigned long gs; + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t bp; + uint64_t bx; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t ax; + uint64_t cx; + uint64_t dx; + uint64_t si; + uint64_t di; + uint64_t orig_ax; + uint64_t ip; + uint64_t cs; + uint64_t flags; + uint64_t sp; + uint64_t ss; + uint64_t fs_base; + uint64_t gs_base; + uint64_t ds; + uint64_t es; + uint64_t fs; + uint64_t gs; +} user_regs_struct64; + +typedef struct { + uint32_t bx; + uint32_t cx; + uint32_t dx; + uint32_t si; + uint32_t di; + uint32_t bp; + uint32_t ax; + uint32_t ds; + uint32_t es; + uint32_t fs; + uint32_t gs; + uint32_t orig_ax; + uint32_t ip; + uint32_t cs; + uint32_t flags; + uint32_t sp; + uint32_t ss; +} user_regs_struct32; + +#ifdef CONFIG_X86_64 +typedef struct { + union { + user_regs_struct64 native; + user_regs_struct32 compat; + }; + bool is_native; } user_regs_struct_t; +#define get_user_reg(pregs, name) (((pregs)->is_native) ? \ + ((pregs)->native.name) : \ + ((pregs)->compat.name)) +#define set_user_reg(pregs, name, val) (((pregs)->is_native) ? \ + ((pregs)->native.name = val) : \ + ((pregs)->compat.name = val)) +#else +typedef struct { + union { + user_regs_struct32 native; + }; +} user_regs_struct_t; +#define get_user_reg(pregs, name) ((pregs)->native.name) +#define set_user_reg(pregs, name, val) ((pregs)->native.name = val) +#endif #if 0 typedef struct { @@ -74,9 +118,9 @@ static inline unsigned long task_size(void) { return TASK_SIZE; } typedef uint64_t auxv_t; typedef uint32_t tls_t; -#define REG_RES(regs) ((regs).ax) -#define REG_IP(regs) ((regs).ip) -#define REG_SYSCALL_NR(regs) ((regs).orig_ax) +#define REG_RES(regs) get_user_reg(®s, ax) +#define REG_IP(regs) get_user_reg(®s, ip) +#define REG_SYSCALL_NR(regs) get_user_reg(®s, orig_ax) #define AT_VECTOR_SIZE 44 diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 9a9df360d..9190d1801 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -69,6 +69,7 @@ unsigned long get_exec_start(struct vm_area_list *vmas) return 0; } +#ifndef ARCH_HAS_GET_REGS static inline int ptrace_get_regs(int pid, user_regs_struct_t *regs) { struct iovec iov; @@ -86,6 +87,7 @@ static inline int ptrace_set_regs(int pid, user_regs_struct_t *regs) iov.iov_len = sizeof(user_regs_struct_t); return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov); } +#endif static int get_thread_ctx(int pid, struct thread_ctx *ctx) { diff --git a/images/core-x86.proto b/images/core-x86.proto index a3fa1759e..6c084e5ca 100644 --- a/images/core-x86.proto +++ b/images/core-x86.proto @@ -2,6 +2,12 @@ syntax = "proto2"; import "opts.proto"; +enum user_x86_regs_case_t { + NATIVE = 1; + COMPAT = 2; +} + +/* Reusing entry for both 64 and 32 bits register sets */ message user_x86_regs_entry { required uint64 r15 = 1; required uint64 r14 = 2; @@ -30,6 +36,7 @@ message user_x86_regs_entry { required uint64 es = 25; required uint64 fs = 26; required uint64 gs = 27; + optional user_x86_regs_case_t gpregs_case = 28 [default = NATIVE]; } message user_x86_xsave_entry { From 2aa583b45bc35ad23afe2be69c96e78e722df5b8 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:51 +0300 Subject: [PATCH 0017/4375] x86/crtools: rework arch_task_compatible Detect task's personality by the size of register set, returned by ptrace call with PTRACE_GETREGSET (more reliable). The same approach uses strace from 4.8 version: https://sourceforge.net/projects/strace/files/strace/4.8/ Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 0b85aab2c..85f2f54ed 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -58,9 +58,24 @@ void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t * ~(X86_EFLAGS_TF | X86_EFLAGS_DF | X86_EFLAGS_IF)); } +int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs); int arch_task_compatible(pid_t pid) { - unsigned long cs, ds; + user_regs_struct_t r; + int ret = ptrace_get_regs(pid, &r); + + if (ret) + return -1; + + return !r.is_native; +} + +#define USER32_CS 0x23 +#define USER_CS 0x33 + +static bool ldt_task_selectors(pid_t pid) +{ + unsigned long cs; errno = 0; /* @@ -73,15 +88,7 @@ int arch_task_compatible(pid_t pid) return -1; } - errno = 0; - ds = ptrace(PTRACE_PEEKUSER, pid, offsetof(user_regs_struct64, ds), 0); - if (errno != 0) { - pr_perror("Can't get DS register for %d", pid); - return -1; - } - - /* It's x86-32 or x32 */ - return cs != 0x33 || ds == 0x2b; + return cs != USER_CS && cs != USER32_CS; } bool arch_can_dump_task(struct parasite_ctl *ctl) @@ -94,6 +101,11 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) return false; } + if (ldt_task_selectors(pid)) { + pr_err("Can't dump task %d with LDT descriptors\n", pid); + return false; + } + return true; } From 024bae0af586ab6f42297e302f6ced095aa8b51c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:52 +0300 Subject: [PATCH 0018/4375] x86: add user_regs_native macro (optional) This will document that {get,set}_user_reg should be used only on initialized register set. Otherwise, after some code changes we may find ourself in situation when setting not inited user regs will set them for compatible register set: (is_native == false). Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/include/asm/infect-types.h | 2 ++ criu/arch/arm/include/asm/infect-types.h | 2 ++ criu/arch/ppc64/include/asm/infect-types.h | 2 ++ criu/arch/x86/crtools.c | 14 ++++---- criu/arch/x86/include/asm/infect-types.h | 38 +++++++++++++++----- 5 files changed, 42 insertions(+), 16 deletions(-) diff --git a/criu/arch/aarch64/include/asm/infect-types.h b/criu/arch/aarch64/include/asm/infect-types.h index 76fcfebf5..714881c57 100644 --- a/criu/arch/aarch64/include/asm/infect-types.h +++ b/criu/arch/aarch64/include/asm/infect-types.h @@ -23,6 +23,8 @@ typedef struct user_fpsimd_state user_fpregs_struct_t; #define REG_IP(r) ((uint64_t)(r).pc) #define REG_SYSCALL_NR(r) ((uint64_t)(r).regs[8]) +#define user_regs_native(pregs) true + /* * Range for task size calculated from the following Linux kernel files: * arch/arm64/include/asm/memory.h diff --git a/criu/arch/arm/include/asm/infect-types.h b/criu/arch/arm/include/asm/infect-types.h index 3552ec931..9c2092e5d 100644 --- a/criu/arch/arm/include/asm/infect-types.h +++ b/criu/arch/arm/include/asm/infect-types.h @@ -57,6 +57,8 @@ struct user_vfp_exc { #define REG_IP(regs) ((regs).ARM_pc) #define REG_SYSCALL_NR(regs) ((regs).ARM_r7) +#define user_regs_native(pregs) true + /* * Range for task size calculated from the following Linux kernel files: * arch/arm/include/asm/memory.h diff --git a/criu/arch/ppc64/include/asm/infect-types.h b/criu/arch/ppc64/include/asm/infect-types.h index 1969ca2b5..f243def73 100644 --- a/criu/arch/ppc64/include/asm/infect-types.h +++ b/criu/arch/ppc64/include/asm/infect-types.h @@ -76,6 +76,8 @@ typedef struct { #define REG_IP(regs) ((uint64_t)(regs).nip) #define REG_SYSCALL_NR(regs) ((uint64_t)(regs).gpr[0]) +#define user_regs_native(pregs) true + /* * Copied from the following kernel header files : * include/linux/auxvec.h diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 85f2f54ed..f48aa82de 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -67,7 +67,7 @@ int arch_task_compatible(pid_t pid) if (ret) return -1; - return !r.is_native; + return !user_regs_native(&r); } #define USER32_CS 0x23 @@ -120,7 +120,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, user_regs_struct_t regs = ctl->orig.regs; int err; - if (regs.is_native) { + if (user_regs_native(®s)) { user_regs_struct64 *r = ®s.native; r->ax = (uint64_t)nr; @@ -152,7 +152,7 @@ static int save_task_regs(CoreEntry *core, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs); #define get_signed_user_reg(pregs, name) \ - (((pregs)->is_native) ? (int64_t)((pregs)->native.name) : \ + ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \ (int32_t)((pregs)->compat.name)) int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) { @@ -222,7 +222,7 @@ static int save_task_regs(CoreEntry *core, #define assign_reg(dst, src, e) do { dst->e = (__typeof__(dst->e))src.e; } while (0) #define assign_array(dst, src, e) memcpy(dst->e, &src.e, sizeof(src.e)) - if (regs.is_native) { + if (user_regs_native(regs)) { assign_reg(gpregs, regs->native, r15); assign_reg(gpregs, regs->native, r14); assign_reg(gpregs, regs->native, r13); @@ -314,11 +314,11 @@ int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs) ret = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov); if (iov.iov_len == sizeof(regs->native)) { - regs->is_native = true; + regs->__is_native = NATIVE_MAGIC; return ret; } if (iov.iov_len == sizeof(regs->compat)) { - regs->is_native = false; + regs->__is_native = COMPAT_MAGIC; return ret; } @@ -332,7 +332,7 @@ int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs) { struct iovec iov; - if (regs->is_native) { + if (user_regs_native(regs)) { iov.iov_base = ®s->native; iov.iov_len = sizeof(user_regs_struct64); } else { diff --git a/criu/arch/x86/include/asm/infect-types.h b/criu/arch/x86/include/asm/infect-types.h index d56902acf..08344f747 100644 --- a/criu/arch/x86/include/asm/infect-types.h +++ b/criu/arch/x86/include/asm/infect-types.h @@ -4,6 +4,8 @@ #include #include #include +#include "log.h" +#include "common/bug.h" #include "common/page.h" #include "syscall-types.h" @@ -61,27 +63,45 @@ typedef struct { } user_regs_struct32; #ifdef CONFIG_X86_64 +/* + * To be sure that we rely on inited reg->__is_native, this member + * is (short int) instead of initial (bool). The right way to + * check if regs are native or compat is to use user_regs_native() macro. + * This should cost nothing, as *usually* sizeof(bool) == sizeof(short) + */ typedef struct { union { user_regs_struct64 native; user_regs_struct32 compat; }; - bool is_native; + short __is_native; /* use user_regs_native macro to check it */ } user_regs_struct_t; -#define get_user_reg(pregs, name) (((pregs)->is_native) ? \ - ((pregs)->native.name) : \ - ((pregs)->compat.name)) -#define set_user_reg(pregs, name, val) (((pregs)->is_native) ? \ - ((pregs)->native.name = val) : \ - ((pregs)->compat.name = val)) + +#define NATIVE_MAGIC 0x0A +#define COMPAT_MAGIC 0x0C +static inline bool user_regs_native(user_regs_struct_t *pregs) +{ + return pregs->__is_native == NATIVE_MAGIC; +} + +#define get_user_reg(pregs, name) \ + ((user_regs_native(pregs)) ? \ + ((pregs)->native.name) : \ + ((pregs)->compat.name)) + +#define set_user_reg(pregs, name, val) \ + ((user_regs_native(pregs)) ? \ + ((pregs)->native.name = (val)) : \ + ((pregs)->compat.name = (val))) #else typedef struct { union { user_regs_struct32 native; }; } user_regs_struct_t; -#define get_user_reg(pregs, name) ((pregs)->native.name) -#define set_user_reg(pregs, name, val) ((pregs)->native.name = val) +#define user_regs_native(pregs) true +#define get_user_reg(pregs, name) ((pregs)->native.name) +#define set_user_reg(pregs, name, val) ((pregs)->native.name = val) #endif #if 0 From 8c2faeb5a71c06fef2eda79a5ae5d9f7dd7871a9 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:53 +0300 Subject: [PATCH 0019/4375] parasite-syscall: choose between native/compat blobs Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/parasite-syscall.c | 44 ++++++++++++++++++++++++++++++---------- criu/pie/parasite-blob.h | 3 +-- criu/pie/pie-relocs.h | 1 - 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 9190d1801..ba47079e1 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -1346,13 +1346,27 @@ static int parasite_start_daemon(struct parasite_ctl *ctl, struct pstree_item *i return 0; } -/* FIXME: parasite native/compat */ +#define init_parasite_ctl(ctl, blob_type) \ + do { \ + memcpy(ctl->local_map, parasite_##blob_type##_blob, \ + sizeof(parasite_##blob_type##_blob)); \ + ELF_RELOCS_APPLY(parasite_##blob_type, \ + ctl->local_map, ctl->remote_map); \ + /* Setup the rest of a control block */ \ + ctl->parasite_ip = (unsigned long)parasite_sym(ctl->remote_map, \ + blob_type, __export_parasite_head_start); \ + ctl->addr_cmd = parasite_sym(ctl->local_map, blob_type, \ + __export_parasite_cmd); \ + ctl->addr_args = parasite_sym(ctl->local_map, blob_type, \ + __export_parasite_args); \ + } while (0) + struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, struct vm_area_list *vma_area_list) { int ret; struct parasite_ctl *ctl; - unsigned long p, map_exchange_size; + unsigned long p, map_exchange_size, parasite_size; BUG_ON(item->threads[0].real != pid); @@ -1378,9 +1392,18 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, * without using ptrace at all. */ + if (user_regs_native(&ctl->orig.regs)) + parasite_size = pie_size(parasite_native); +#ifdef CONFIG_X86_64 /* compat blob isn't defined for other archs */ + else + parasite_size = pie_size(parasite_compat); +#endif + ctl->args_size = round_up(parasite_args_size, PAGE_SIZE); parasite_args_size = PARASITE_ARG_SIZE_MIN; /* reset for next task */ - map_exchange_size = pie_size(parasite_native) + ctl->args_size; + parasite_size += ctl->args_size; + + map_exchange_size = parasite_size; map_exchange_size += RESTORE_STACK_SIGFRAME + PARASITE_STACK_SIZE; if (item->nr_threads > 1) map_exchange_size += PARASITE_STACK_SIZE; @@ -1392,16 +1415,15 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, goto err_restore; pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map); - memcpy(ctl->local_map, parasite_native_blob, sizeof(parasite_native_blob)); - ELF_RELOCS_APPLY(parasite_native, ctl->local_map, ctl->remote_map); + if (user_regs_native(&ctl->orig.regs)) + init_parasite_ctl(ctl, native); +#ifdef CONFIG_X86_64 /* compat blob isn't defined for other archs */ + else + init_parasite_ctl(ctl, compat); +#endif - /* Setup the rest of a control block */ - ctl->parasite_ip = (unsigned long)parasite_sym(ctl->remote_map, native, __export_parasite_head_start); - ctl->addr_cmd = parasite_sym(ctl->local_map, native, __export_parasite_cmd); - ctl->addr_args = parasite_sym(ctl->local_map, native, __export_parasite_args); - - p = pie_size(parasite_native) + ctl->args_size; + p = parasite_size; ctl->rsigframe = ctl->remote_map + p; ctl->sigframe = ctl->local_map + p; diff --git a/criu/pie/parasite-blob.h b/criu/pie/parasite-blob.h index 278ca6d85..796d36ed2 100644 --- a/criu/pie/parasite-blob.h +++ b/criu/pie/parasite-blob.h @@ -1,6 +1,5 @@ #include "parasite-native-blob.h" #ifdef CONFIG_X86_64 -/* FIXME: parasite_compat_blob defined but not used */ -/* # include "parasite-compat-blob.h"*/ +# include "parasite-compat-blob.h" #endif diff --git a/criu/pie/pie-relocs.h b/criu/pie/pie-relocs.h index 7f863c669..f768739d8 100644 --- a/criu/pie/pie-relocs.h +++ b/criu/pie/pie-relocs.h @@ -10,7 +10,6 @@ extern __maybe_unused void elf_relocs_apply(void *mem, void *vbase, size_t size, elf_reloc_t *elf_relocs, size_t nr_relocs); -/* FIXME: native/compat pie's pie_size(), ELF_RELOCS_APPLY() */ #define pie_size(__pie_name) (round_up(sizeof(__pie_name##_blob) + \ __pie_name ## _nr_gotpcrel * sizeof(long), page_size())) #define ELF_RELOCS_APPLY(__pie_name, __mem, __vbase) \ From 7f48302509df5f787fef1e4ea3d50c361467d2a8 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:54 +0300 Subject: [PATCH 0020/4375] x86/crtools: add injected int 0x80 instruction code Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index f48aa82de..bed2f4e8d 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -26,17 +26,24 @@ /* * Injected syscall instruction */ -/* FIXME: 32-bit syscalls */ const char code_syscall[] = { 0x0f, 0x05, /* syscall */ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc /* int 3, ... */ }; +const char code_int_80[] = { + 0xcd, 0x80, /* int $0x80 */ + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc /* int 3, ... */ +}; + static const int code_syscall_aligned = round_up(sizeof(code_syscall), sizeof(long)); +static const int +code_int_80_aligned = round_up(sizeof(code_syscall), sizeof(long)); static inline __always_unused void __check_code_syscall(void) { + BUILD_BUG_ON(code_int_80_aligned != BUILTIN_SYSCALL_SIZE); BUILD_BUG_ON(code_syscall_aligned != BUILTIN_SYSCALL_SIZE); BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); } @@ -130,6 +137,8 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, r->r10 = arg4; r->r8 = arg5; r->r9 = arg6; + + err = __parasite_execute_syscall(ctl, ®s, code_syscall); } else { user_regs_struct32 *r = ®s.compat; @@ -140,9 +149,9 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, r->si = arg4; r->di = arg5; r->bp = arg6; - } - err = __parasite_execute_syscall(ctl, ®s, code_syscall); + err = __parasite_execute_syscall(ctl, ®s, code_int_80); + } *ret = get_user_reg(®s, ax); return err; From 2ac20e79088cf90a35099084a81221a4be6ff936 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 12 Apr 2016 19:10:55 +0300 Subject: [PATCH 0021/4375] restorer: drop sigframe include It's included through "asm/restorer.h". Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/restorer.h | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 39a5f2f04..1dddafe24 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -17,7 +17,6 @@ #include "posix-timer.h" #include "timerfd.h" #include "shmem.h" -#include "sigframe.h" #include "parasite-vdso.h" #include From ddcb61de1309161533fafbcc1a1a0b2c3b7321da Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 19 Apr 2016 11:07:08 +0300 Subject: [PATCH 0022/4375] compel: Don't reclose files already closed In case of error don't re-close files already closed. https://github.com/xemul/criu/issues/148 Reported-by: Andrew Vagin Signed-off-by: Cyrill Gorcunov Reviewed-by: Andrey Vagin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index 8ce5f75f3..8f3a44b72 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -73,12 +73,12 @@ static int piegen(void) { struct stat st; void *mem; - int fd; + int fd, ret = -1; fd = open(opts.input_filename, O_RDONLY); if (fd < 0) { pr_perror("Can't open file %s", opts.input_filename); - goto err; + return -1; } if (fstat(fd, &st)) { @@ -99,15 +99,21 @@ static int piegen(void) } if (handle_elf(mem, st.st_size)) { - fclose(fout); + close(fd), fd = -1; unlink(opts.output_filename); goto err; } + ret = 0; + err: - fclose(fout); - printf("%s generated successfully.\n", opts.output_filename); - return 0; + if (fd >= 0) + close(fd); + if (fout) + fclose(fout); + if (!ret) + printf("%s generated successfully.\n", opts.output_filename); + return ret; } int main(int argc, char *argv[]) From db889906654dbc720968fdb1d47e5adccdc998d3 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 19 Apr 2016 11:07:09 +0300 Subject: [PATCH 0023/4375] compel: Add missing 32s support https://github.com/xemul/criu/issues/148#issuecomment-211635122 Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/elf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/compel/src/elf.c b/compel/src/elf.c index a959616e4..37c8a36ee 100644 --- a/compel/src/elf.c +++ b/compel/src/elf.c @@ -415,6 +415,7 @@ int handle_elf(void *mem, size_t size) #ifdef ELF_X86_64 case R_X86_64_32: /* Symbol + Addend (4 bytes) */ + case R_X86_64_32S: /* Symbol + Addend (4 bytes) */ pr_debug("\t\t\t\tR_X86_64_32 at 0x%-4lx val 0x%x\n", place, value32); pr_out(" { .offset = 0x%-8x, .type = PIEGEN_TYPE_INT, " ".addend = %-8d, .value = 0x%-16x, }, /* R_X86_64_32 */\n", From 189d782a166dc64e3c80742a1d58cfcbfb3ab473 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 27 Apr 2016 14:15:00 +0300 Subject: [PATCH 0024/4375] arm/pie/build: do not produce relocatable parasite object With `-r` option relocation to parasite_service was not made on ARM: 0x76dbc018: bl 0x76dbc018 0xebfffffe (You may saw it with objdump also). This leaded to hang at "Putting tsock" message: (01.368297) ---------------------------------------- (01.368321) (01.368339) Collecting fds (pid: 13503) (01.368360) ---------------------------------------- (01.368535) Found 3 file descriptors (01.368564) ---------------------------------------- (01.368648) Dump private signals of 13503 (01.368708) Dump shared signals of 13503 (01.368761) Parasite syscall_ip at 0x10000 (01.369605) Set up parasite blob using memfd (01.369641) Putting parasite blob into 0x76cc5000->0x76e1f000 (01.369755) Dumping GP/FPU registers for 13503 (01.369818) Putting tsock into pid 13503 Link against native.lib.a which also fixes build for aarm64. Reported-by: alex vk Reported-by: long.wanglong Cc: Cyrill Gorcunov Cc: Christopher Covington Reviewed-by: Christopher Covington Signed-off-by: Dmitry Safonov Reviewed-by: Christopher Covington Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 7539f79ac..975e075ef 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -158,19 +158,24 @@ $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel else # !piegen-y +# ld on arm doesn't like -pie and -r options together +ifeq ($(filter arm aarch64,$(ARCH)),) + LD_R := -r +endif + define gen-rule-built-in.bin.o $(obj)/parasite-$(1).built-in.bin.o: $(obj)/$(1).built-in.o \ - $(obj)/pie.lds-$(1).S + $(obj)/pie.lds-$(1).S $(obj)/native.lib.a $$(call msg-gen, $$@) - $(Q) $(LD) -r -T $(obj)/pie.lds-$(1).S -o $$@ $$< + $(Q) $(LD) $(LD_R) -T $(obj)/pie.lds-$(1).S -o $$@ $$< $(obj)/native.lib.a endef $(eval $(call map,gen-rule-built-in.bin.o,$(parasite_target))) $(obj)/restorer.built-in.bin.o: $(obj)/restorer.built-in.o \ - $(obj)/pie.lds-native.S + $(obj)/pie.lds-native.S $(obj)/native.lib.a $(call msg-gen, $@) - $(Q) $(LD) -r -T $(obj)/pie.lds-native.S -o $@ $< + $(Q) $(LD) $(LD_R) -T $(obj)/pie.lds-native.S -o $@ $< $(obj)/native.lib.a $(obj)/%.built-in.bin: $(obj)/%.built-in.bin.o $(call msg-gen, $@) From 4bccd6a6bc0e0787b120a124324162ea85612493 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 22 Apr 2016 21:44:00 +0300 Subject: [PATCH 0025/4375] .gitignore: update to recent changes Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .gitignore | 3 ++- Documentation/.gitignore | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 91ca0437f..4abbcaf7c 100644 --- a/.gitignore +++ b/.gitignore @@ -34,8 +34,9 @@ soccr/config.h criu/include/version.h criu/pie/restorer-blob.h criu/pie/parasite-*-blob.h -criu/pie/piegen/piegen criu/pie/pie.lds*.S criu/protobuf-desc-gen.h +lib/build/ +lib/c/criu.pc scripts/build/qemu-user-static/* lib/.crit-setup.files diff --git a/Documentation/.gitignore b/Documentation/.gitignore index ad3e4f05e..b4f39316b 100644 --- a/Documentation/.gitignore +++ b/Documentation/.gitignore @@ -3,3 +3,4 @@ *.[1-8] *.pdf *.ps +footer.txt From 427f68f0a3033d608e44cadb6e21799ce456293c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 29 Apr 2016 22:47:00 +0300 Subject: [PATCH 0026/4375] compel: shuffle skeleton a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I propose to change compel directory structure: - if we want support more arch's than x86/ppc66, it seems worth to add arch/ folder - move all sources from src/ folder up - to have headers and build additional object with CFLAGS for a symlink seems for me less hacky way than mess around with .c files cross-linking - I made handle-elf.h header for arch helpers code. I may named that just "elf.h", but that may confuse, as there are system header - I would like to drop those ELF_PPC64/ELF_X86_32/ELF_X86_64 defines and use CONFIG_X86_64 and whatnot After this patch compel directory become: compel/ ├── arch │ ├── ppc64 │ │ └── include │ │ └── handle-elf.h │ └── x86 │ └── include │ └── handle-elf.h ├── handle-elf-32.c -> handle-elf.c ├── handle-elf.c ├── include │ ├── piegen.h │ └── uapi │ ├── elf32-types.h │ ├── elf64-types.h │ └── types.h ├── main.c └── Makefile Note: temporary I make value32 and addend32 for compilation on arm/aarch64 Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 22 +++++++++++++------ compel/arch/ppc64/include/handle-elf.h | 9 ++++++++ compel/arch/x86/include/handle-elf.h | 18 +++++++++++++++ compel/handle-elf-32.c | 1 + compel/{src/elf.c => handle-elf.c} | 3 ++- .../uapi/elf32-types.h} | 6 ++--- .../uapi/elf64-types.h} | 6 ++--- compel/{src => }/main.c | 0 compel/src/elf-x86-64.c | 16 -------------- 9 files changed, 51 insertions(+), 30 deletions(-) create mode 100644 compel/arch/ppc64/include/handle-elf.h create mode 100644 compel/arch/x86/include/handle-elf.h create mode 120000 compel/handle-elf-32.c rename compel/{src/elf.c => handle-elf.c} (99%) rename compel/{src/elf-x86-32.c => include/uapi/elf32-types.h} (71%) rename compel/{src/elf-ppc64.c => include/uapi/elf64-types.h} (71%) rename compel/{src => }/main.c (100%) delete mode 100644 compel/src/elf-x86-64.c diff --git a/compel/Makefile b/compel/Makefile index 5e4bd7b76..d08e470df 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -2,6 +2,7 @@ include $(SRC_DIR)/Makefile.versions ccflags-y += -iquote criu/include ccflags-y += -iquote compel/include +ccflags-y += -iquote compel/arch/$(ARCH)/include ccflags-y += -DCOMPEL_VERSION=\"$(COMPEL_SO_VERSION_MAJOR).$(COMPEL_SO_VERSION_MINOR)\" host-ccflags-y += $(filter-out -pg $(CFLAGS-GCOV),$(ccflags-y)) @@ -9,12 +10,19 @@ HOSTCFLAGS += $(filter-out -pg $(CFLAGS-GCOV),$(WARNINGS) $(DEFINES)) HOSTLDFLAGS += $(filter-out -pg $(CFLAGS-GCOV),$(LDFLAGS)) hostprogs-y += compel -compel-objs += src/main.o +compel-objs += main.o +compel-objs += handle-elf.o -ifneq ($(filter ia32 x86, $(ARCH)),) -compel-objs += src/elf-x86-32.o -compel-objs += src/elf-x86-64.o -endif -ifeq ($(SRCARCH),ppc64) -compel-objs += src/elf-ppc64.o +# Add $(DEFINES) to CFLAGS of compel-objs. +# We can't do ccflags-y += $(DEFINES) +# as we need to build handle-elf-32.o +# with -DCONFIG_X86_32 +define ccflags-defines + HOSTCFLAGS_$(1) += $(DEFINES) +endef +$(eval $(call map,ccflags-defines,$(compel-objs))) + +ifeq ($(ARCH),x86) + compel-objs += handle-elf-32.o + HOSTCFLAGS_handle-elf-32.o += -DCONFIG_X86_32 endif diff --git a/compel/arch/ppc64/include/handle-elf.h b/compel/arch/ppc64/include/handle-elf.h new file mode 100644 index 000000000..203e91b65 --- /dev/null +++ b/compel/arch/ppc64/include/handle-elf.h @@ -0,0 +1,9 @@ +#ifndef __COMPEL_HANDLE_ELF_H__ +#define __COMPEL_HANDLE_ELF_H__ + +#include "uapi/elf32-types.h" + +#define ELF_PPC64 +#define handle_elf handle_elf_ppc64 + +#endif /* __COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/arch/x86/include/handle-elf.h b/compel/arch/x86/include/handle-elf.h new file mode 100644 index 000000000..75e3c3974 --- /dev/null +++ b/compel/arch/x86/include/handle-elf.h @@ -0,0 +1,18 @@ +#ifndef __COMPEL_HANDLE_ELF_H__ +#define __COMPEL_HANDLE_ELF_H__ + +#ifdef CONFIG_X86_32 + +#include "uapi/elf32-types.h" +#define ELF_X86_32 +#define handle_elf handle_elf_x86_32 + +#else /* CONFIG_X86_64 */ + +#include "uapi/elf64-types.h" +#define ELF_X86_64 +#define handle_elf handle_elf_x86_64 + +#endif + +#endif /* __COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/handle-elf-32.c b/compel/handle-elf-32.c new file mode 120000 index 000000000..fe4611886 --- /dev/null +++ b/compel/handle-elf-32.c @@ -0,0 +1 @@ +handle-elf.c \ No newline at end of file diff --git a/compel/src/elf.c b/compel/handle-elf.c similarity index 99% rename from compel/src/elf.c rename to compel/handle-elf.c index 37c8a36ee..089c9284d 100644 --- a/compel/src/elf.c +++ b/compel/handle-elf.c @@ -16,6 +16,7 @@ #include "common/compiler.h" #include "piegen.h" +#include "handle-elf.h" static bool __ptr_oob(const void *ptr, const void *start, const size_t size) { @@ -219,7 +220,7 @@ int handle_elf(void *mem, size_t size) for (k = 0; k < sh->sh_size / sh->sh_entsize; k++) { s64 __maybe_unused addend64, __maybe_unused value64; - s32 addend32, value32; + s32 __maybe_unused addend32, __maybe_unused value32; unsigned long place; const char *name; void *where; diff --git a/compel/src/elf-x86-32.c b/compel/include/uapi/elf32-types.h similarity index 71% rename from compel/src/elf-x86-32.c rename to compel/include/uapi/elf32-types.h index 413113ef3..0a3b08a32 100644 --- a/compel/src/elf-x86-32.c +++ b/compel/include/uapi/elf32-types.h @@ -1,5 +1,5 @@ -#define ELF_X86_32 -#define handle_elf handle_elf_x86_32 +#ifndef __COMPEL_ELF32_TYPES_H__ +#define __COMPEL_ELF32_TYPES_H__ #define Ehdr_t Elf32_Ehdr #define Shdr_t Elf32_Shdr @@ -13,4 +13,4 @@ #define ELF_R_SYM ELF32_R_SYM #define ELF_R_TYPE ELF32_R_TYPE -#include "elf.c" +#endif /* __COMPEL_ELF32_TYPES_H__ */ diff --git a/compel/src/elf-ppc64.c b/compel/include/uapi/elf64-types.h similarity index 71% rename from compel/src/elf-ppc64.c rename to compel/include/uapi/elf64-types.h index 472725f9f..31fcbdb06 100644 --- a/compel/src/elf-ppc64.c +++ b/compel/include/uapi/elf64-types.h @@ -1,5 +1,5 @@ -#define ELF_PPC64 -#define handle_elf handle_elf_ppc64 +#ifndef __COMPEL_ELF64_TYPES_H__ +#define __COMPEL_ELF64_TYPES_H__ #define Ehdr_t Elf64_Ehdr #define Shdr_t Elf64_Shdr @@ -13,4 +13,4 @@ #define ELF_R_SYM ELF64_R_SYM #define ELF_R_TYPE ELF64_R_TYPE -#include "elf.c" +#endif /* __COMPEL_ELF64_TYPES_H__ */ diff --git a/compel/src/main.c b/compel/main.c similarity index 100% rename from compel/src/main.c rename to compel/main.c diff --git a/compel/src/elf-x86-64.c b/compel/src/elf-x86-64.c deleted file mode 100644 index 8ba26672b..000000000 --- a/compel/src/elf-x86-64.c +++ /dev/null @@ -1,16 +0,0 @@ -#define ELF_X86_64 -#define handle_elf handle_elf_x86_64 - -#define Ehdr_t Elf64_Ehdr -#define Shdr_t Elf64_Shdr -#define Sym_t Elf64_Sym -#define Rel_t Elf64_Rel -#define Rela_t Elf64_Rela - -#define ELF_ST_TYPE ELF64_ST_TYPE -#define ELF_ST_BIND ELF64_ST_BIND - -#define ELF_R_SYM ELF64_R_SYM -#define ELF_R_TYPE ELF64_R_TYPE - -#include "elf.c" From 392469b697501e51916891ed4c7ad26a50dc801a Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 29 Apr 2016 22:47:00 +0300 Subject: [PATCH 0027/4375] compel: add per-arch handle-elf.c Split handle_elf() function from main.c to per-arch. Rename it to handle_binary not to cross-reference. Rename generic handle_elf to __handle_elf as with define not to litter namespace. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 3 +- compel/arch/aarch64/handle-elf.c | 20 +++++++++++ compel/arch/aarch64/include/handle-elf.h | 10 ++++++ compel/arch/arm/handle-elf.c | 13 ++++++++ compel/arch/arm/include/handle-elf.h | 10 ++++++ compel/arch/ppc64/handle-elf.c | 20 +++++++++++ compel/arch/ppc64/include/handle-elf.h | 4 ++- compel/arch/x86/handle-elf.c | 15 +++++++++ compel/arch/x86/include/handle-elf.h | 7 ++-- compel/handle-elf.c | 4 +-- compel/include/piegen.h | 30 ++++++++++++----- compel/main.c | 42 +----------------------- 12 files changed, 121 insertions(+), 57 deletions(-) create mode 100644 compel/arch/aarch64/handle-elf.c create mode 100644 compel/arch/aarch64/include/handle-elf.h create mode 100644 compel/arch/arm/handle-elf.c create mode 100644 compel/arch/arm/include/handle-elf.h create mode 100644 compel/arch/ppc64/handle-elf.c create mode 100644 compel/arch/x86/handle-elf.c diff --git a/compel/Makefile b/compel/Makefile index d08e470df..f8da14489 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -12,13 +12,14 @@ HOSTLDFLAGS += $(filter-out -pg $(CFLAGS-GCOV),$(LDFLAGS)) hostprogs-y += compel compel-objs += main.o compel-objs += handle-elf.o +compel-objs += arch/$(ARCH)/handle-elf.o # Add $(DEFINES) to CFLAGS of compel-objs. # We can't do ccflags-y += $(DEFINES) # as we need to build handle-elf-32.o # with -DCONFIG_X86_32 define ccflags-defines - HOSTCFLAGS_$(1) += $(DEFINES) + HOSTCFLAGS_$(notdir $(1)) += $(DEFINES) endef $(eval $(call map,ccflags-defines,$(compel-objs))) diff --git a/compel/arch/aarch64/handle-elf.c b/compel/arch/aarch64/handle-elf.c new file mode 100644 index 000000000..82c282b5f --- /dev/null +++ b/compel/arch/aarch64/handle-elf.c @@ -0,0 +1,20 @@ +#include + +#include "piegen.h" +#include "handle-elf.h" + +int handle_binary(void *mem, size_t size) +{ + const unsigned char *elf_ident = +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + elf_ident_64_le; +#else + elf_ident_64_be; +#endif + + if (memcmp(mem, elf_ident, sizeof(elf_ident_64_le)) == 0) + return handle_elf_aarch64(mem, size); + + pr_err("Unsupported Elf format detected\n"); + return -1; +} diff --git a/compel/arch/aarch64/include/handle-elf.h b/compel/arch/aarch64/include/handle-elf.h new file mode 100644 index 000000000..e9c5036f2 --- /dev/null +++ b/compel/arch/aarch64/include/handle-elf.h @@ -0,0 +1,10 @@ +#ifndef __COMPEL_HANDLE_ELF_H__ +#define __COMPEL_HANDLE_ELF_H__ + +#include "uapi/elf64-types.h" + +#define __handle_elf handle_elf_aarch64 + +extern int handle_elf_aarch64(void *mem, size_t size); + +#endif /* __COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/arch/arm/handle-elf.c b/compel/arch/arm/handle-elf.c new file mode 100644 index 000000000..580ed0e4f --- /dev/null +++ b/compel/arch/arm/handle-elf.c @@ -0,0 +1,13 @@ +#include + +#include "piegen.h" +#include "handle-elf.h" + +int handle_binary(void *mem, size_t size) +{ + if (memcmp(mem, elf_ident_32, sizeof(elf_ident_32)) == 0) + return handle_elf_arm(mem, size); + + pr_err("Unsupported Elf format detected\n"); + return -1; +} diff --git a/compel/arch/arm/include/handle-elf.h b/compel/arch/arm/include/handle-elf.h new file mode 100644 index 000000000..b44ed9f6a --- /dev/null +++ b/compel/arch/arm/include/handle-elf.h @@ -0,0 +1,10 @@ +#ifndef __COMPEL_HANDLE_ELF_H__ +#define __COMPEL_HANDLE_ELF_H__ + +#include "uapi/elf32-types.h" + +#define __handle_elf handle_elf_arm + +extern int handle_elf_arm(void *mem, size_t size); + +#endif /* __COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/arch/ppc64/handle-elf.c b/compel/arch/ppc64/handle-elf.c new file mode 100644 index 000000000..9433ef135 --- /dev/null +++ b/compel/arch/ppc64/handle-elf.c @@ -0,0 +1,20 @@ +#include + +#include "piegen.h" +#include "handle-elf.h" + +int handle_binary(void *mem, size_t size) +{ + const unsigned char *elf_ident = +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + elf_ident_64_le; +#else + elf_ident_64_be; +#endif + + if (memcmp(mem, elf_ident, sizeof(elf_ident_64_le)) == 0) + return handle_elf_ppc64(mem, size); + + pr_err("Unsupported Elf format detected\n"); + return -1; +} diff --git a/compel/arch/ppc64/include/handle-elf.h b/compel/arch/ppc64/include/handle-elf.h index 203e91b65..c6f23123d 100644 --- a/compel/arch/ppc64/include/handle-elf.h +++ b/compel/arch/ppc64/include/handle-elf.h @@ -4,6 +4,8 @@ #include "uapi/elf32-types.h" #define ELF_PPC64 -#define handle_elf handle_elf_ppc64 +#define __handle_elf handle_elf_ppc64 + +extern int handle_elf_ppc64(void *mem, size_t size); #endif /* __COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/arch/x86/handle-elf.c b/compel/arch/x86/handle-elf.c new file mode 100644 index 000000000..5a142c9ef --- /dev/null +++ b/compel/arch/x86/handle-elf.c @@ -0,0 +1,15 @@ +#include + +#include "piegen.h" +#include "handle-elf.h" + +int handle_binary(void *mem, size_t size) +{ + if (memcmp(mem, elf_ident_32, sizeof(elf_ident_32)) == 0) + return handle_elf_x86_32(mem, size); + else if (memcmp(mem, elf_ident_64_le, sizeof(elf_ident_64_le)) == 0) + return handle_elf_x86_64(mem, size); + + pr_err("Unsupported Elf format detected\n"); + return -1; +} diff --git a/compel/arch/x86/include/handle-elf.h b/compel/arch/x86/include/handle-elf.h index 75e3c3974..e02098dbe 100644 --- a/compel/arch/x86/include/handle-elf.h +++ b/compel/arch/x86/include/handle-elf.h @@ -5,14 +5,17 @@ #include "uapi/elf32-types.h" #define ELF_X86_32 -#define handle_elf handle_elf_x86_32 +#define __handle_elf handle_elf_x86_32 #else /* CONFIG_X86_64 */ #include "uapi/elf64-types.h" #define ELF_X86_64 -#define handle_elf handle_elf_x86_64 +#define __handle_elf handle_elf_x86_64 #endif +extern int handle_elf_x86_32(void *mem, size_t size); +extern int handle_elf_x86_64(void *mem, size_t size); + #endif /* __COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/handle-elf.c b/compel/handle-elf.c index 089c9284d..e61293087 100644 --- a/compel/handle-elf.c +++ b/compel/handle-elf.c @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -14,7 +13,6 @@ #include "asm-generic/int.h" -#include "common/compiler.h" #include "piegen.h" #include "handle-elf.h" @@ -63,7 +61,7 @@ static int do_relative_toc(long value, uint16_t *location, } #endif -int handle_elf(void *mem, size_t size) +int __handle_elf(void *mem, size_t size) { const char *symstrings = NULL; Shdr_t *symtab_hdr = NULL; diff --git a/compel/include/piegen.h b/compel/include/piegen.h index 0c695c6a7..da6ff219b 100644 --- a/compel/include/piegen.h +++ b/compel/include/piegen.h @@ -4,6 +4,9 @@ #include #include +#include +#include "compiler.h" + typedef struct { char *input_filename; char *output_filename; @@ -17,15 +20,6 @@ typedef struct { extern piegen_opt_t opts; extern FILE *fout; -#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64) -extern int handle_elf_x86_32(void *mem, size_t size); -extern int handle_elf_x86_64(void *mem, size_t size); -#endif - -#if defined(CONFIG_PPC64) -extern int handle_elf_ppc64(void *mem, size_t size); -#endif - #define pr_out(fmt, ...) fprintf(fout, fmt, ##__VA_ARGS__) #define pr_debug(fmt, ...) printf("%s: "fmt, opts.stream_name, ##__VA_ARGS__) @@ -33,4 +27,22 @@ extern int handle_elf_ppc64(void *mem, size_t size); #define pr_err(fmt, ...) fprintf(stderr, "%s: Error (%s:%d): "fmt, opts.stream_name, __FILE__, __LINE__, ##__VA_ARGS__) #define pr_perror(fmt, ...) fprintf(stderr, "%s: Error (%s:%d): "fmt ": %m\n", opts.stream_name, __FILE__, __LINE__, ##__VA_ARGS__) +extern int handle_binary(void *mem, size_t size); + +static const unsigned char __maybe_unused +elf_ident_32[EI_NIDENT] = { + 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const unsigned char __maybe_unused +elf_ident_64_le[EI_NIDENT] = { + 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const unsigned char __maybe_unused +elf_ident_64_be[EI_NIDENT] = { + 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x02, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + #endif /* __ELFTIL_H__ */ diff --git a/compel/main.c b/compel/main.c index 8f3a44b72..5fe30c316 100644 --- a/compel/main.c +++ b/compel/main.c @@ -7,13 +7,11 @@ #include #include -#include #include #include #include -#include "common/compiler.h" #include "piegen.h" static const char compel_cflags_pie[] = "-fpie -Wa,--noexecstack -fno-stack-protector"; @@ -31,44 +29,6 @@ piegen_opt_t opts = { FILE *fout; -static int handle_elf(void *mem, size_t size) -{ -#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64) - unsigned char elf_ident_x86_32[EI_NIDENT] = { - 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - - unsigned char elf_ident_x86_64[EI_NIDENT] = { - 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - - if (memcmp(mem, elf_ident_x86_32, sizeof(elf_ident_x86_32)) == 0) - return handle_elf_x86_32(mem, size); - else if (memcmp(mem, elf_ident_x86_64, sizeof(elf_ident_x86_64)) == 0) - return handle_elf_x86_64(mem, size); -#endif - -#if defined(CONFIG_PPC64) - const unsigned char elf_ident[EI_NIDENT] = { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -#else - 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x02, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -#endif - }; - - if (memcmp(mem, elf_ident, sizeof(elf_ident)) == 0) - return handle_elf_ppc64(mem, size); -#endif /* CONFIG_PPC64 */ - - pr_err("Unsupported Elf format detected\n"); - return -1; -} - static int piegen(void) { struct stat st; @@ -98,7 +58,7 @@ static int piegen(void) goto err; } - if (handle_elf(mem, st.st_size)) { + if (handle_binary(mem, st.st_size)) { close(fd), fd = -1; unlink(opts.output_filename); goto err; From 9efd30b6a17b299f0dfd4fadfcda900f3f75bbe0 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 29 Apr 2016 22:47:00 +0300 Subject: [PATCH 0028/4375] compel: define arch_is_machine_supported Check if ELF header complements ELF magic in per-arch way. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/include/handle-elf.h | 1 + compel/arch/arm/include/handle-elf.h | 1 + compel/arch/ppc64/include/handle-elf.h | 1 + compel/arch/x86/include/handle-elf.h | 2 ++ compel/handle-elf.c | 20 ++++++++++---------- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/compel/arch/aarch64/include/handle-elf.h b/compel/arch/aarch64/include/handle-elf.h index e9c5036f2..7d7bfb7b3 100644 --- a/compel/arch/aarch64/include/handle-elf.h +++ b/compel/arch/aarch64/include/handle-elf.h @@ -4,6 +4,7 @@ #include "uapi/elf64-types.h" #define __handle_elf handle_elf_aarch64 +#define arch_is_machine_supported(e_machine) (e_machine == EM_AARCH64) extern int handle_elf_aarch64(void *mem, size_t size); diff --git a/compel/arch/arm/include/handle-elf.h b/compel/arch/arm/include/handle-elf.h index b44ed9f6a..a465f4273 100644 --- a/compel/arch/arm/include/handle-elf.h +++ b/compel/arch/arm/include/handle-elf.h @@ -4,6 +4,7 @@ #include "uapi/elf32-types.h" #define __handle_elf handle_elf_arm +#define arch_is_machine_supported(e_machine) (e_machine == EM_ARM) extern int handle_elf_arm(void *mem, size_t size); diff --git a/compel/arch/ppc64/include/handle-elf.h b/compel/arch/ppc64/include/handle-elf.h index c6f23123d..ec0cad159 100644 --- a/compel/arch/ppc64/include/handle-elf.h +++ b/compel/arch/ppc64/include/handle-elf.h @@ -5,6 +5,7 @@ #define ELF_PPC64 #define __handle_elf handle_elf_ppc64 +#define arch_is_machine_supported(e_machine) (e_machine == EM_PPC64) extern int handle_elf_ppc64(void *mem, size_t size); diff --git a/compel/arch/x86/include/handle-elf.h b/compel/arch/x86/include/handle-elf.h index e02098dbe..eea94d463 100644 --- a/compel/arch/x86/include/handle-elf.h +++ b/compel/arch/x86/include/handle-elf.h @@ -6,12 +6,14 @@ #include "uapi/elf32-types.h" #define ELF_X86_32 #define __handle_elf handle_elf_x86_32 +#define arch_is_machine_supported(e_machine) (e_machine == EM_386) #else /* CONFIG_X86_64 */ #include "uapi/elf64-types.h" #define ELF_X86_64 #define __handle_elf handle_elf_x86_64 +#define arch_is_machine_supported(e_machine) (e_machine == EM_X86_64) #endif diff --git a/compel/handle-elf.c b/compel/handle-elf.c index e61293087..7ba5bd6fe 100644 --- a/compel/handle-elf.c +++ b/compel/handle-elf.c @@ -61,6 +61,15 @@ static int do_relative_toc(long value, uint16_t *location, } #endif +static bool is_header_supported(Ehdr_t *hdr) +{ + if (!arch_is_machine_supported(hdr->e_machine)) + return false; + if (hdr->e_type != ET_REL || hdr->e_version != EV_CURRENT) + return false; + return true; +} + int __handle_elf(void *mem, size_t size) { const char *symstrings = NULL; @@ -83,19 +92,10 @@ int __handle_elf(void *mem, size_t size) pr_debug("\ttype 0x%x machine 0x%x version 0x%x\n", (unsigned)hdr->e_type, (unsigned)hdr->e_machine, (unsigned)hdr->e_version); -#ifdef ELF_X86_64 - if (hdr->e_type != ET_REL || hdr->e_machine != EM_X86_64 || hdr->e_version != EV_CURRENT) { + if (!is_header_supported(hdr)) { pr_err("Unsupported header detected\n"); goto err; } -#endif - -#ifdef ELF_X86_32 - if (hdr->e_type != ET_REL || hdr->e_machine != EM_386 || hdr->e_version != EV_CURRENT) { - pr_err("Unsupported header detected\n"); - goto err; - } -#endif sec_hdrs = malloc(sizeof(*sec_hdrs) * hdr->e_shnum); if (!sec_hdrs) { From ce5cd6931294803f0cfb063e0464408299bdf9bb Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 4 May 2016 17:35:12 +0300 Subject: [PATCH 0029/4375] compel: fix build for ppc64 (typo) Sorry for this typo, I should be more attentive. Fixes: commit ea523b183326 ("compel: shuffle skeleton a bit"). Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/ppc64/include/handle-elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/arch/ppc64/include/handle-elf.h b/compel/arch/ppc64/include/handle-elf.h index ec0cad159..b324debdf 100644 --- a/compel/arch/ppc64/include/handle-elf.h +++ b/compel/arch/ppc64/include/handle-elf.h @@ -1,7 +1,7 @@ #ifndef __COMPEL_HANDLE_ELF_H__ #define __COMPEL_HANDLE_ELF_H__ -#include "uapi/elf32-types.h" +#include "uapi/elf64-types.h" #define ELF_PPC64 #define __handle_elf handle_elf_ppc64 From eb329f0949e8b7cda1bc634074bd89f42f5e0583 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 4 May 2016 17:35:13 +0300 Subject: [PATCH 0030/4375] compel: do not pass DEFINES two times to HOSTCFLAGS I think, it's more pretty to pass -DCONFIG_X86_* instead of all $DEFINES. That simplifies the statement and makes it more readable. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index f8da14489..23b064c45 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -6,7 +6,7 @@ ccflags-y += -iquote compel/arch/$(ARCH)/include ccflags-y += -DCOMPEL_VERSION=\"$(COMPEL_SO_VERSION_MAJOR).$(COMPEL_SO_VERSION_MINOR)\" host-ccflags-y += $(filter-out -pg $(CFLAGS-GCOV),$(ccflags-y)) -HOSTCFLAGS += $(filter-out -pg $(CFLAGS-GCOV),$(WARNINGS) $(DEFINES)) +HOSTCFLAGS += $(filter-out -pg $(CFLAGS-GCOV),$(WARNINGS) $(filter-out -DCONFIG_X86_64,$(DEFINES))) HOSTLDFLAGS += $(filter-out -pg $(CFLAGS-GCOV),$(LDFLAGS)) hostprogs-y += compel @@ -14,16 +14,13 @@ compel-objs += main.o compel-objs += handle-elf.o compel-objs += arch/$(ARCH)/handle-elf.o -# Add $(DEFINES) to CFLAGS of compel-objs. -# We can't do ccflags-y += $(DEFINES) -# as we need to build handle-elf-32.o -# with -DCONFIG_X86_32 +ifeq ($(ARCH),x86) +# Add -DCONFIG_X86_64 or -DCONFIG_X86_32 to HOSTCFLAGS define ccflags-defines - HOSTCFLAGS_$(notdir $(1)) += $(DEFINES) + HOSTCFLAGS_$(notdir $(1)) += -DCONFIG_X86_64 endef $(eval $(call map,ccflags-defines,$(compel-objs))) -ifeq ($(ARCH),x86) - compel-objs += handle-elf-32.o - HOSTCFLAGS_handle-elf-32.o += -DCONFIG_X86_32 -endif +compel-objs += handle-elf-32.o +HOSTCFLAGS_handle-elf-32.o += -DCONFIG_X86_32 +endif # ARCH == x86 From 72503fb903331323c0bd8bcac0d462c14fa4cfe4 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 6 May 2016 14:10:27 +0300 Subject: [PATCH 0031/4375] build: Fix compel target on @all There is no longer phony compel target but compel/compel instead. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c69548833..3bb68fc54 100644 --- a/Makefile +++ b/Makefile @@ -127,7 +127,7 @@ endif CFLAGS += $(WARNINGS) $(DEFINES) -iquote include/ # Default target -all: compel criu lib +all: compel/compel criu lib .PHONY: all # From eb6bc4019dcb9cf38814bf36478a1d132f5936bd Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 6 May 2016 14:10:28 +0300 Subject: [PATCH 0032/4375] build: Don't call for compel execution on clean targets Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 975e075ef..2d5828b5b 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -51,7 +51,9 @@ CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 ccflags-y += -DCR_NOGLIBC +ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) NATIVE_CFLAGS := $(shell $(SRC_DIR)/compel/compel --arch=$(ARCH) cflags) +endif ifeq ($(ARCH),x86) NATIVE_CFLAGS += -DCONFIG_X86_64 From c200d80372abcaf30f1fcb72b59332d7f6eeab8f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 6 May 2016 19:14:56 +0300 Subject: [PATCH 0033/4375] compel: separate get_strings_section from __handle_elf I copied __ptr_oob* checks from util-vdso.c. That will allow to check not only structure begin pointers, but structure end also. Before this patch code checked if strings section's header pointer is OOB, but it did it after dereferencing this pointer, which is meaningless. Now it checks: - OOB of sections table, - strings section's header should be inside sections table, - check strings section with it's length for OOB. In the very next patches I will add tests for this functions and other compel-related changes. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/handle-elf.c | 73 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/compel/handle-elf.c b/compel/handle-elf.c index 7ba5bd6fe..09b6f7eff 100644 --- a/compel/handle-elf.c +++ b/compel/handle-elf.c @@ -16,16 +16,36 @@ #include "piegen.h" #include "handle-elf.h" -static bool __ptr_oob(const void *ptr, const void *start, const size_t size) +/* TODO: merge with util-vdso.c part in criu header */ +/* Check if pointer is out-of-bound */ +static bool +__ptr_oob(const uintptr_t ptr, const uintptr_t start, const size_t size) { - const void *end = (const void *)((const unsigned long)start + size); - return ptr > end || ptr < start; + uintptr_t end = start + size; + + return ptr >= end || ptr < start; +} + +/* Check if pointed structure's end is out-of-bound */ +static bool __ptr_struct_end_oob(const uintptr_t ptr, const size_t struct_size, + const uintptr_t start, const size_t size) +{ + /* the last byte of the structure should be inside [begin, end) */ + return __ptr_oob(ptr + struct_size - 1, start, size); +} + +/* Check if pointed structure is out-of-bound */ +static bool __ptr_struct_oob(const uintptr_t ptr, const size_t struct_size, + const uintptr_t start, const size_t size) +{ + return __ptr_oob(ptr, start, size) || + __ptr_struct_end_oob(ptr, struct_size, start, size); } static bool test_pointer(const void *ptr, const void *start, const size_t size, const char *name, const char *file, const int line) { - if (__ptr_oob(ptr, start, size)) { + if (__ptr_oob((const uintptr_t)ptr, (const uintptr_t)start, size)) { pr_err("Corrupted pointer %p (%s) at %s:%d\n", ptr, name, file, line); return true; @@ -70,6 +90,43 @@ static bool is_header_supported(Ehdr_t *hdr) return true; } +static const char *get_strings_section(Ehdr_t *hdr, uintptr_t mem, size_t size) +{ + size_t sec_table_size = hdr->e_shentsize * hdr->e_shnum; + uintptr_t sec_table = mem + hdr->e_shoff; + Shdr_t *secstrings_hdr; + uintptr_t addr; + + if (__ptr_struct_oob(sec_table, sec_table_size, mem, size)) { + pr_err("Section table [%#zx, %#zx) is out of [%#zx, %#zx)\n", + sec_table, sec_table + sec_table_size, mem, mem + size); + return NULL; + } + + /* + * strings section header's offset in section headers table is + * (size of section header * index of string section header) + */ + addr = sec_table + hdr->e_shentsize * hdr->e_shstrndx; + if (__ptr_struct_oob(addr, sizeof(Shdr_t), + sec_table, sec_table + sec_table_size)) { + pr_err("String section header @%#zx is out of [%#zx, %#zx)\n", + addr, sec_table, sec_table + sec_table_size); + return NULL; + } + secstrings_hdr = (void*)addr; + + addr = mem + secstrings_hdr->sh_offset; + if (__ptr_struct_oob(addr, secstrings_hdr->sh_size, mem, size)) { + pr_err("String section @%#zx size %#lx is out of [%#zx, %#zx)\n", + addr, (unsigned long)secstrings_hdr->sh_size, + mem, mem + size); + return NULL; + } + + return (void*)addr; +} + int __handle_elf(void *mem, size_t size) { const char *symstrings = NULL; @@ -77,7 +134,6 @@ int __handle_elf(void *mem, size_t size) Sym_t *symbols = NULL; Ehdr_t *hdr = mem; - Shdr_t *secstrings_hdr = NULL; Shdr_t *strtab_hdr = NULL; Shdr_t **sec_hdrs = NULL; const char *secstrings; @@ -103,10 +159,9 @@ int __handle_elf(void *mem, size_t size) goto err; } - secstrings_hdr = mem + hdr->e_shoff + hdr->e_shentsize * hdr->e_shstrndx; - secstrings = mem + secstrings_hdr->sh_offset; - ptr_func_exit(secstrings_hdr); - ptr_func_exit(secstrings); + secstrings = get_strings_section(hdr, (uintptr_t)mem, size); + if (!secstrings) + goto err; pr_debug("Sections\n"); pr_debug("------------\n"); From efc30c08560074cd6a5f05d59108ed34518460d4 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 6 May 2016 19:14:57 +0300 Subject: [PATCH 0034/4375] compel: make output streams options That will help to omit pr_* output on the screen on tests, where one can redefine `opts`. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/piegen.h | 32 +++++++++++++++++++++++++++----- compel/main.c | 14 ++++++++------ 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/compel/include/piegen.h b/compel/include/piegen.h index da6ff219b..736152a2c 100644 --- a/compel/include/piegen.h +++ b/compel/include/piegen.h @@ -15,17 +15,39 @@ typedef struct { char *prefix_name; char *var_name; char *nrgotpcrel_name; + FILE *fout; + FILE *ferr; + FILE *fdebug; } piegen_opt_t; extern piegen_opt_t opts; -extern FILE *fout; -#define pr_out(fmt, ...) fprintf(fout, fmt, ##__VA_ARGS__) +#define pr_out(fmt, ...) \ +do { \ + if (opts.fout) \ + fprintf(opts.fout, fmt, ##__VA_ARGS__); \ +} while (0) -#define pr_debug(fmt, ...) printf("%s: "fmt, opts.stream_name, ##__VA_ARGS__) +#define pr_debug(fmt, ...) \ +do { \ + if (opts.fdebug) \ + fprintf(opts.fdebug, "%s: "fmt, \ + opts.stream_name, ##__VA_ARGS__); \ +} while (0) -#define pr_err(fmt, ...) fprintf(stderr, "%s: Error (%s:%d): "fmt, opts.stream_name, __FILE__, __LINE__, ##__VA_ARGS__) -#define pr_perror(fmt, ...) fprintf(stderr, "%s: Error (%s:%d): "fmt ": %m\n", opts.stream_name, __FILE__, __LINE__, ##__VA_ARGS__) +#define pr_err(fmt, ...) \ +do { \ + if (opts.ferr) \ + fprintf(opts.ferr, "%s: Error (%s:%d): "fmt, \ + opts.stream_name, __FILE__, __LINE__, ##__VA_ARGS__); \ +} while (0) + +#define pr_perror(fmt, ...) \ +do { \ + if (opts.ferr) \ + fprintf(opts.ferr, "%s: Error (%s:%d): "fmt ": %m\n", \ + opts.stream_name, __FILE__, __LINE__, ##__VA_ARGS__); \ +} while (0) extern int handle_binary(void *mem, size_t size); diff --git a/compel/main.c b/compel/main.c index 5fe30c316..6f117cded 100644 --- a/compel/main.c +++ b/compel/main.c @@ -25,10 +25,9 @@ piegen_opt_t opts = { .prefix_name = "__", .var_name = "elf_relocs", .nrgotpcrel_name = "nr_gotpcrel", + .fout = NULL, }; -FILE *fout; - static int piegen(void) { struct stat st; @@ -46,8 +45,8 @@ static int piegen(void) goto err; } - fout = fopen(opts.output_filename, "w"); - if (fout == NULL) { + opts.fout = fopen(opts.output_filename, "w"); + if (opts.fout == NULL) { pr_perror("Can't open %s", opts.output_filename); goto err; } @@ -69,8 +68,8 @@ static int piegen(void) err: if (fd >= 0) close(fd); - if (fout) - fclose(fout); + if (opts.fout) + fclose(opts.fout); if (!ret) printf("%s generated successfully.\n", opts.output_filename); return ret; @@ -82,6 +81,9 @@ int main(int argc, char *argv[]) int opt, idx, i; char *action; + opts.fdebug = stdout; + opts.ferr = stderr; + typedef struct { const char *arch; const char *cflags; From 89978b5b1d39868397b82fb016bafa1b086b147b Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 6 May 2016 19:14:58 +0300 Subject: [PATCH 0035/4375] compel: add error constants For tests, we need to know if elf file parsing was interrupted in a proper place (and thus meaningful error numbers). Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/handle-elf.c | 3 ++- compel/arch/arm/handle-elf.c | 3 ++- compel/arch/ppc64/handle-elf.c | 3 ++- compel/arch/x86/handle-elf.c | 3 ++- compel/handle-elf.c | 10 ++++++++-- compel/include/uapi/piegen-err.h | 10 ++++++++++ 6 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 compel/include/uapi/piegen-err.h diff --git a/compel/arch/aarch64/handle-elf.c b/compel/arch/aarch64/handle-elf.c index 82c282b5f..bbd4bf1b0 100644 --- a/compel/arch/aarch64/handle-elf.c +++ b/compel/arch/aarch64/handle-elf.c @@ -1,6 +1,7 @@ #include #include "piegen.h" +#include "uapi/piegen-err.h" #include "handle-elf.h" int handle_binary(void *mem, size_t size) @@ -16,5 +17,5 @@ int handle_binary(void *mem, size_t size) return handle_elf_aarch64(mem, size); pr_err("Unsupported Elf format detected\n"); - return -1; + return -E_NOT_ELF; } diff --git a/compel/arch/arm/handle-elf.c b/compel/arch/arm/handle-elf.c index 580ed0e4f..2692439c7 100644 --- a/compel/arch/arm/handle-elf.c +++ b/compel/arch/arm/handle-elf.c @@ -1,6 +1,7 @@ #include #include "piegen.h" +#include "uapi/piegen-err.h" #include "handle-elf.h" int handle_binary(void *mem, size_t size) @@ -9,5 +10,5 @@ int handle_binary(void *mem, size_t size) return handle_elf_arm(mem, size); pr_err("Unsupported Elf format detected\n"); - return -1; + return -E_NOT_ELF; } diff --git a/compel/arch/ppc64/handle-elf.c b/compel/arch/ppc64/handle-elf.c index 9433ef135..049e3fba0 100644 --- a/compel/arch/ppc64/handle-elf.c +++ b/compel/arch/ppc64/handle-elf.c @@ -1,6 +1,7 @@ #include #include "piegen.h" +#include "uapi/piegen-err.h" #include "handle-elf.h" int handle_binary(void *mem, size_t size) @@ -16,5 +17,5 @@ int handle_binary(void *mem, size_t size) return handle_elf_ppc64(mem, size); pr_err("Unsupported Elf format detected\n"); - return -1; + return -E_NOT_ELF; } diff --git a/compel/arch/x86/handle-elf.c b/compel/arch/x86/handle-elf.c index 5a142c9ef..9edb94262 100644 --- a/compel/arch/x86/handle-elf.c +++ b/compel/arch/x86/handle-elf.c @@ -1,6 +1,7 @@ #include #include "piegen.h" +#include "uapi/piegen-err.h" #include "handle-elf.h" int handle_binary(void *mem, size_t size) @@ -11,5 +12,5 @@ int handle_binary(void *mem, size_t size) return handle_elf_x86_64(mem, size); pr_err("Unsupported Elf format detected\n"); - return -1; + return -E_NOT_ELF; } diff --git a/compel/handle-elf.c b/compel/handle-elf.c index 09b6f7eff..cc1ecc734 100644 --- a/compel/handle-elf.c +++ b/compel/handle-elf.c @@ -13,6 +13,7 @@ #include "asm-generic/int.h" +#include "uapi/piegen-err.h" #include "piegen.h" #include "handle-elf.h" @@ -142,6 +143,7 @@ int __handle_elf(void *mem, size_t size) #ifdef ELF_PPC64 s64 toc_offset = 0; #endif + int ret = -E_UNKNOWN; pr_debug("Header\n"); pr_debug("------------\n"); @@ -150,18 +152,22 @@ int __handle_elf(void *mem, size_t size) if (!is_header_supported(hdr)) { pr_err("Unsupported header detected\n"); + ret = -E_NOT_ELF; goto err; } sec_hdrs = malloc(sizeof(*sec_hdrs) * hdr->e_shnum); if (!sec_hdrs) { pr_err("No memory for section headers\n"); + ret = -E_NOMEM; goto err; } secstrings = get_strings_section(hdr, (uintptr_t)mem, size); - if (!secstrings) + if (!secstrings) { + ret = -E_NO_STR_SEC; goto err; + } pr_debug("Sections\n"); pr_debug("------------\n"); @@ -563,5 +569,5 @@ int __handle_elf(void *mem, size_t size) return 0; err: free(sec_hdrs); - return -1; + return ret; } diff --git a/compel/include/uapi/piegen-err.h b/compel/include/uapi/piegen-err.h new file mode 100644 index 000000000..f8a2349a1 --- /dev/null +++ b/compel/include/uapi/piegen-err.h @@ -0,0 +1,10 @@ +#ifndef __PIEGEN_ERR_H__ +#define __PIEGEN_ERR_H__ + +/* Error numbers for piegen. Success is 0, so errors should differ. */ +#define E_UNKNOWN 1 +#define E_NOMEM 2 +#define E_NOT_ELF 3 +#define E_NO_STR_SEC 4 + +#endif /* __PIEGEN_ERR_H__ */ From 6fe6a283e18226e94ac908c333cbd54f4f26db13 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 11 May 2016 15:49:00 +0300 Subject: [PATCH 0036/4375] compel: add tests for compel Yet they only test for ELF header, but soon I'll add more of them. It's build with $ make test/compel/handle_binary and test output is in TAP format: $ ./test/compel/handle_binary ok 1 - check zero ELF header ok 2 - check non-supported ELF header ok 3 - check non-relocatable ELF header ok 4 - check zero ELF header ok 5 - check non-supported ELF header ok 6 - check non-relocatable ELF header (here two runs for x86_64 and x86_32 ELF binaries) I'm planning to integrate it with Travis, so we will be sure that compel is properly working (as this tests doesn't need any ns and may be run on qemu-static). Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 4 ++ compel/Makefile | 16 ++++-- test/compel/Makefile | 18 +++++++ .../aarch64/include/arch_test_handle_binary.h | 21 ++++++++ .../arm/include/arch_test_handle_binary.h | 18 +++++++ .../ppc64/include/arch_test_handle_binary.h | 21 ++++++++ .../x86/include/arch_test_handle_binary.h | 45 ++++++++++++++++ test/compel/handle_binary.c | 39 ++++++++++++++ test/compel/handle_binary_32.c | 1 + test/compel/main.c | 54 +++++++++++++++++++ 10 files changed, 234 insertions(+), 3 deletions(-) create mode 100644 test/compel/Makefile create mode 100644 test/compel/arch/aarch64/include/arch_test_handle_binary.h create mode 100644 test/compel/arch/arm/include/arch_test_handle_binary.h create mode 100644 test/compel/arch/ppc64/include/arch_test_handle_binary.h create mode 100644 test/compel/arch/x86/include/arch_test_handle_binary.h create mode 100644 test/compel/handle_binary.c create mode 120000 test/compel/handle_binary_32.c create mode 100644 test/compel/main.c diff --git a/Makefile b/Makefile index 3bb68fc54..9e2483ab2 100644 --- a/Makefile +++ b/Makefile @@ -205,6 +205,9 @@ $(eval $(call gen-built-in,images)) compel/%: $(Q) $(MAKE) $(build)=compel $@ +test/compel/%: + $(Q) $(MAKE) $(build)=compel $@ + # # Next the socket CR library # @@ -244,6 +247,7 @@ lib: criu subclean: $(Q) $(MAKE) -C Documentation clean + $(Q) $(MAKE) $(build)=test/compel clean $(Q) $(RM) .gitid .PHONY: subclean diff --git a/compel/Makefile b/compel/Makefile index 23b064c45..db90c7e14 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -6,8 +6,10 @@ ccflags-y += -iquote compel/arch/$(ARCH)/include ccflags-y += -DCOMPEL_VERSION=\"$(COMPEL_SO_VERSION_MAJOR).$(COMPEL_SO_VERSION_MINOR)\" host-ccflags-y += $(filter-out -pg $(CFLAGS-GCOV),$(ccflags-y)) -HOSTCFLAGS += $(filter-out -pg $(CFLAGS-GCOV),$(WARNINGS) $(filter-out -DCONFIG_X86_64,$(DEFINES))) +HOSTCFLAGS += $(filter-out -pg $(CFLAGS-GCOV),$(WARNINGS) $(DEFINES)) HOSTLDFLAGS += $(filter-out -pg $(CFLAGS-GCOV),$(LDFLAGS)) +HOSTCFLAGS := $(filter-out -DCONFIG_X86_64,$(HOSTCFLAGS)) +export host-ccflags-y HOSTCFLAGS HOSTLDFLAGS hostprogs-y += compel compel-objs += main.o @@ -17,10 +19,18 @@ compel-objs += arch/$(ARCH)/handle-elf.o ifeq ($(ARCH),x86) # Add -DCONFIG_X86_64 or -DCONFIG_X86_32 to HOSTCFLAGS define ccflags-defines - HOSTCFLAGS_$(notdir $(1)) += -DCONFIG_X86_64 + export HOSTCFLAGS_$(notdir $(1)) += -DCONFIG_X86_64 endef $(eval $(call map,ccflags-defines,$(compel-objs))) compel-objs += handle-elf-32.o -HOSTCFLAGS_handle-elf-32.o += -DCONFIG_X86_32 +export HOSTCFLAGS_handle-elf-32.o += -DCONFIG_X86_32 endif # ARCH == x86 + +export compel-objs +test/compel/%: + $(Q) $(MAKE) $(build)=test/compel $@ + +test: test/compel/test_handle_binary + +.PHONY: test diff --git a/test/compel/Makefile b/test/compel/Makefile new file mode 100644 index 000000000..a23097f62 --- /dev/null +++ b/test/compel/Makefile @@ -0,0 +1,18 @@ +# Relative path to original objects +define compel_obj_path + $(addprefix ../../compel/,$(1)) +endef + +host-ccflags-y += -iquote test/compel/arch/$(ARCH)/include +test_objs := $(filter-out main.o,$(compel-objs)) + +hostprogs-y += handle_binary +handle_binary-objs += $(call compel_obj_path,$(test_objs)) +handle_binary-objs += main.o +handle_binary-objs += handle_binary.o + +ifeq ($(ARCH),x86) + handle_binary-objs += handle_binary_32.o + HOSTCFLAGS_handle_binary.o += -DCONFIG_X86_64 + HOSTCFLAGS_handle_binary_32.o += -DCONFIG_X86_32 +endif diff --git a/test/compel/arch/aarch64/include/arch_test_handle_binary.h b/test/compel/arch/aarch64/include/arch_test_handle_binary.h new file mode 100644 index 000000000..9ed25c9f5 --- /dev/null +++ b/test/compel/arch/aarch64/include/arch_test_handle_binary.h @@ -0,0 +1,21 @@ +#ifndef __ARCH_TEST_HANDLE_BINARY__ +#define __ARCH_TEST_HANDLE_BINARY__ + +#include "uapi/elf64-types.h" +#define __run_tests arch_run_tests + +static __maybe_unused void arch_test_set_elf_hdr_ident(void *mem) +{ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + memcpy(mem, elf_ident_64_le, sizeof(elf_ident_64_le)); +#else + memcpy(mem, elf_ident_64_be, sizeof(elf_ident_64_be)); +#endif +} + +static __maybe_unused void arch_test_set_elf_hdr_machine(Ehdr_t *hdr) +{ + hdr->e_machine = EM_AARCH64; +} + +#endif /* __ARCH_TEST_HANDLE_BINARY__ */ diff --git a/test/compel/arch/arm/include/arch_test_handle_binary.h b/test/compel/arch/arm/include/arch_test_handle_binary.h new file mode 100644 index 000000000..4b14b2bf6 --- /dev/null +++ b/test/compel/arch/arm/include/arch_test_handle_binary.h @@ -0,0 +1,18 @@ +#ifndef __ARCH_TEST_HANDLE_BINARY__ +#define __ARCH_TEST_HANDLE_BINARY__ + +#include "uapi/elf32-types.h" +#define __run_tests arch_run_tests + +static __maybe_unused void arch_test_set_elf_hdr_ident(void *mem) +{ + memcpy(mem, elf_ident_32, sizeof(elf_ident_32)); +} + +static __maybe_unused void arch_test_set_elf_hdr_machine(Ehdr_t *hdr) +{ + hdr->e_machine = EM_ARM; +} + + +#endif /* __ARCH_TEST_HANDLE_BINARY__ */ diff --git a/test/compel/arch/ppc64/include/arch_test_handle_binary.h b/test/compel/arch/ppc64/include/arch_test_handle_binary.h new file mode 100644 index 000000000..7bf80b25d --- /dev/null +++ b/test/compel/arch/ppc64/include/arch_test_handle_binary.h @@ -0,0 +1,21 @@ +#ifndef __ARCH_TEST_HANDLE_BINARY__ +#define __ARCH_TEST_HANDLE_BINARY__ + +#include "uapi/elf64-types.h" +#define __run_tests arch_run_tests + +static __maybe_unused void arch_test_set_elf_hdr_ident(void *mem) +{ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + memcpy(mem, elf_ident_64_le, sizeof(elf_ident_64_le)); +#else + memcpy(mem, elf_ident_64_be, sizeof(elf_ident_64_be)); +#endif +} + +static __maybe_unused void arch_test_set_elf_hdr_machine(Ehdr_t *hdr) +{ + hdr->e_machine = EM_PPC64; +} + +#endif /* __ARCH_TEST_HANDLE_BINARY__ */ diff --git a/test/compel/arch/x86/include/arch_test_handle_binary.h b/test/compel/arch/x86/include/arch_test_handle_binary.h new file mode 100644 index 000000000..cbc240e58 --- /dev/null +++ b/test/compel/arch/x86/include/arch_test_handle_binary.h @@ -0,0 +1,45 @@ +#ifndef __ARCH_TEST_HANDLE_BINARY__ +#define __ARCH_TEST_HANDLE_BINARY__ + +#include + +#ifdef CONFIG_X86_64 +#include "uapi/elf64-types.h" +#define __run_tests run_tests_64 + +static __maybe_unused void arch_test_set_elf_hdr_ident(void *mem) +{ + memcpy(mem, elf_ident_64_le, sizeof(elf_ident_64_le)); +} + +static __maybe_unused void arch_test_set_elf_hdr_machine(Ehdr_t *hdr) +{ + hdr->e_machine = EM_X86_64; +} + +#else /* !CONFIG_X86_64 */ + +#include "uapi/elf32-types.h" +#define __run_tests run_tests_32 + +static __maybe_unused void arch_test_set_elf_hdr_ident(void *mem) +{ + memcpy(mem, elf_ident_32, sizeof(elf_ident_32)); +} + +static __maybe_unused void arch_test_set_elf_hdr_machine(Ehdr_t *hdr) +{ + hdr->e_machine = EM_386; +} + +#endif /* CONFIG_X86_32 */ + +extern void run_tests_64(void *mem); +extern void run_tests_32(void *mem); + +static __maybe_unused void arch_run_tests(void *mem) +{ + run_tests_64(mem); + run_tests_32(mem); +} +#endif /* __ARCH_TEST_HANDLE_BINARY__ */ diff --git a/test/compel/handle_binary.c b/test/compel/handle_binary.c new file mode 100644 index 000000000..a1d0bc0a0 --- /dev/null +++ b/test/compel/handle_binary.c @@ -0,0 +1,39 @@ +#include + +#include "uapi/piegen-err.h" +#include "piegen.h" + +#include "arch_test_handle_binary.h" + +extern int launch_test(void *mem, int expected_ret, const char *test_name); + +static void set_elf_hdr_relocatable(Ehdr_t *hdr) +{ + hdr->e_type = ET_REL; + hdr->e_version = EV_CURRENT; +} + +static int test_prepare_elf_header(void *elf) +{ + memset(elf, 0, sizeof(Ehdr_t)); + if (launch_test(elf, -E_NOT_ELF, "check zero ELF header")) + return -1; + + arch_test_set_elf_hdr_ident(elf); + if (launch_test(elf, -E_NOT_ELF, "check non-supported ELF header")) + return -1; + + arch_test_set_elf_hdr_machine(elf); + if (launch_test(elf, -E_NOT_ELF, "check non-relocatable ELF header")) + return -1; + + set_elf_hdr_relocatable(elf); + + return 0; +} + +void __run_tests(void *mem) +{ + if (test_prepare_elf_header(mem)) + return; +} diff --git a/test/compel/handle_binary_32.c b/test/compel/handle_binary_32.c new file mode 120000 index 000000000..5364be3e4 --- /dev/null +++ b/test/compel/handle_binary_32.c @@ -0,0 +1 @@ +handle_binary.c \ No newline at end of file diff --git a/test/compel/main.c b/test/compel/main.c new file mode 100644 index 000000000..e272dfb76 --- /dev/null +++ b/test/compel/main.c @@ -0,0 +1,54 @@ +/* + * Test for handle_binary(). + * In this test ELF binary file is constructed from + * header up to sections and relocations. + * On each stage it tests non-valid ELF binaries to be parsed. + * For passing test, handle_binary should return errors for all + * non-valid binaries and handle all relocations. + * + * Test author: Dmitry Safonov + */ + +#include +#include +#include + +#include "piegen.h" +#include "arch_test_handle_binary.h" + +/* size of buffer with formed ELF file */ +#define ELF_BUF_SIZE 4096 + +extern int handle_binary(void *mem, size_t size); +extern void run_tests(void *mem); + +piegen_opt_t opts = { + .fout = NULL, + .ferr = NULL, + .fdebug = NULL, +}; + +int launch_test(void *mem, int expected_ret, const char *test_name) +{ + static unsigned test_nr = 1; + int ret = handle_binary(mem, ELF_BUF_SIZE); + + if (ret != expected_ret) + printf("not ok %u - %s, expected %d but ret is %d\n", + test_nr, test_name, expected_ret, ret); + else + printf("ok %u - %s\n", test_nr, test_name); + test_nr++; + fflush(stdout); + + return ret != expected_ret; +} + +int main(int argc, char **argv) +{ + void *elf_buf = malloc(ELF_BUF_SIZE); + + arch_run_tests(elf_buf); + free(elf_buf); + return 0; +} From 72cc02d14af437f990be207375bd93f581ad8be9 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 25 May 2016 15:52:57 +0300 Subject: [PATCH 0037/4375] compel: fix sign-extension in get_strings_section Well, I hope, I will not make integer promotion mistakes anymore: > 6.3.1.1 > If an int can represent all values of the original type, the value > is converted to an int; otherwise, it is converted to an unsigned int. > These are called the integer promotions.48) All other types are > unchanged by the integer promotions. >>> CID 161317: (SIGN_EXTENSION) >>> Suspicious implicit sign extension: "hdr->e_shentsize" with type "unsigned short" (16 bits, unsigned) is promoted in "hdr->e_shentsize * hdr->e_shnum" to type "int" (32 bits, signed), then sign-extended to type "unsigned long" (64 bits, unsigned). If "hdr->e_shentsize * hdr->e_shnum" is greater than 0x7FFFFFFF, the upper bits of the result will all be 1. 96 size_t sec_table_size = hdr->e_shentsize * hdr->e_shnum; >>> CID 161317: (SIGN_EXTENSION) >>> Suspicious implicit sign extension: "hdr->e_shentsize" with type "unsigned short" (16 bits, unsigned) is promoted in "hdr->e_shentsize * hdr->e_shstrndx" to type "int" (32 bits, signed), then sign-extended to type "unsigned long" (64 bits, unsigned). If "hdr->e_shentsize * hdr->e_shstrndx" is greater than 0x7FFFFFFF, the upper bits of the result will all be 1. 111 addr = sec_table + hdr->e_shentsize * hdr->e_shstrndx; Fixes: #157 Fixes: commit 36664a3cabec ("compel: separate get_strings_section from __handle_elf"). Reported-by: Coverity Reported-by: Andrew Vagin Cc: Andrew Vagin Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/handle-elf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/handle-elf.c b/compel/handle-elf.c index cc1ecc734..d3a8fe815 100644 --- a/compel/handle-elf.c +++ b/compel/handle-elf.c @@ -93,7 +93,7 @@ static bool is_header_supported(Ehdr_t *hdr) static const char *get_strings_section(Ehdr_t *hdr, uintptr_t mem, size_t size) { - size_t sec_table_size = hdr->e_shentsize * hdr->e_shnum; + size_t sec_table_size = ((size_t) hdr->e_shentsize) * hdr->e_shnum; uintptr_t sec_table = mem + hdr->e_shoff; Shdr_t *secstrings_hdr; uintptr_t addr; @@ -108,7 +108,7 @@ static const char *get_strings_section(Ehdr_t *hdr, uintptr_t mem, size_t size) * strings section header's offset in section headers table is * (size of section header * index of string section header) */ - addr = sec_table + hdr->e_shentsize * hdr->e_shstrndx; + addr = sec_table + ((size_t) hdr->e_shentsize) * hdr->e_shstrndx; if (__ptr_struct_oob(addr, sizeof(Shdr_t), sec_table, sec_table + sec_table_size)) { pr_err("String section header @%#zx is out of [%#zx, %#zx)\n", From e162c0cda01c65b88092c5a0e679e14b405cb393 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 25 May 2016 15:52:58 +0300 Subject: [PATCH 0038/4375] test/compel: add test to .gitignore Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/test/.gitignore b/test/.gitignore index a529b5d83..7d3d4232b 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -12,3 +12,4 @@ /zdtm-tst-list /stats-restore /zdtm_mount_cgroups.lock +/compel/handle_binary From 80a5f519f3a763b1eda3e16353edb44ae80cbb0f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 25 May 2016 15:52:59 +0300 Subject: [PATCH 0039/4375] test/compel: add va_args printing to launch_test() Also changed tests messages, before (on x86): ok 1 - check zero ELF header ok 2 - check non-supported ELF header ok 3 - check non-relocatable ELF header ok 4 - check zero ELF header ok 5 - check non-supported ELF header ok 6 - check non-relocatable ELF header After: ok 1 - zero ELF header (64-bit ELF) ok 2 - unsupported ELF header (64-bit ELF) ok 3 - non-relocatable ELF header (64-bit ELF) ok 4 - zero ELF header (32-bit ELF) ok 5 - unsupported ELF header (32-bit ELF) ok 6 - non-relocatable ELF header (32-bit ELF) Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .../aarch64/include/arch_test_handle_binary.h | 2 +- .../arm/include/arch_test_handle_binary.h | 2 +- .../ppc64/include/arch_test_handle_binary.h | 2 +- .../x86/include/arch_test_handle_binary.h | 8 +++---- test/compel/handle_binary.c | 14 ++++++------- test/compel/main.c | 21 +++++++++++++------ 6 files changed, 29 insertions(+), 20 deletions(-) diff --git a/test/compel/arch/aarch64/include/arch_test_handle_binary.h b/test/compel/arch/aarch64/include/arch_test_handle_binary.h index 9ed25c9f5..cbefd6843 100644 --- a/test/compel/arch/aarch64/include/arch_test_handle_binary.h +++ b/test/compel/arch/aarch64/include/arch_test_handle_binary.h @@ -2,7 +2,7 @@ #define __ARCH_TEST_HANDLE_BINARY__ #include "uapi/elf64-types.h" -#define __run_tests arch_run_tests +#define arch_run_tests(mem) __run_tests(mem, "") static __maybe_unused void arch_test_set_elf_hdr_ident(void *mem) { diff --git a/test/compel/arch/arm/include/arch_test_handle_binary.h b/test/compel/arch/arm/include/arch_test_handle_binary.h index 4b14b2bf6..d80382911 100644 --- a/test/compel/arch/arm/include/arch_test_handle_binary.h +++ b/test/compel/arch/arm/include/arch_test_handle_binary.h @@ -2,7 +2,7 @@ #define __ARCH_TEST_HANDLE_BINARY__ #include "uapi/elf32-types.h" -#define __run_tests arch_run_tests +#define arch_run_tests(mem) __run_tests(mem, "") static __maybe_unused void arch_test_set_elf_hdr_ident(void *mem) { diff --git a/test/compel/arch/ppc64/include/arch_test_handle_binary.h b/test/compel/arch/ppc64/include/arch_test_handle_binary.h index 7bf80b25d..0c70c91db 100644 --- a/test/compel/arch/ppc64/include/arch_test_handle_binary.h +++ b/test/compel/arch/ppc64/include/arch_test_handle_binary.h @@ -2,7 +2,7 @@ #define __ARCH_TEST_HANDLE_BINARY__ #include "uapi/elf64-types.h" -#define __run_tests arch_run_tests +#define arch_run_tests(mem) __run_tests(mem, "") static __maybe_unused void arch_test_set_elf_hdr_ident(void *mem) { diff --git a/test/compel/arch/x86/include/arch_test_handle_binary.h b/test/compel/arch/x86/include/arch_test_handle_binary.h index cbc240e58..082c00dfb 100644 --- a/test/compel/arch/x86/include/arch_test_handle_binary.h +++ b/test/compel/arch/x86/include/arch_test_handle_binary.h @@ -34,12 +34,12 @@ static __maybe_unused void arch_test_set_elf_hdr_machine(Ehdr_t *hdr) #endif /* CONFIG_X86_32 */ -extern void run_tests_64(void *mem); -extern void run_tests_32(void *mem); +extern void run_tests_64(void *mem, const char *msg); +extern void run_tests_32(void *mem, const char *msg); static __maybe_unused void arch_run_tests(void *mem) { - run_tests_64(mem); - run_tests_32(mem); + run_tests_64(mem, "(64-bit ELF)"); + run_tests_32(mem, "(32-bit ELF)"); } #endif /* __ARCH_TEST_HANDLE_BINARY__ */ diff --git a/test/compel/handle_binary.c b/test/compel/handle_binary.c index a1d0bc0a0..09100427f 100644 --- a/test/compel/handle_binary.c +++ b/test/compel/handle_binary.c @@ -5,7 +5,7 @@ #include "arch_test_handle_binary.h" -extern int launch_test(void *mem, int expected_ret, const char *test_name); +extern int launch_test(void *mem, int expected_ret, const char *test_fmt, ...); static void set_elf_hdr_relocatable(Ehdr_t *hdr) { @@ -13,18 +13,18 @@ static void set_elf_hdr_relocatable(Ehdr_t *hdr) hdr->e_version = EV_CURRENT; } -static int test_prepare_elf_header(void *elf) +static int test_prepare_elf_header(void *elf, const char *msg) { memset(elf, 0, sizeof(Ehdr_t)); - if (launch_test(elf, -E_NOT_ELF, "check zero ELF header")) + if (launch_test(elf, -E_NOT_ELF, "zero ELF header %s", msg)) return -1; arch_test_set_elf_hdr_ident(elf); - if (launch_test(elf, -E_NOT_ELF, "check non-supported ELF header")) + if (launch_test(elf, -E_NOT_ELF, "unsupported ELF header %s", msg)) return -1; arch_test_set_elf_hdr_machine(elf); - if (launch_test(elf, -E_NOT_ELF, "check non-relocatable ELF header")) + if (launch_test(elf, -E_NOT_ELF, "non-relocatable ELF header %s", msg)) return -1; set_elf_hdr_relocatable(elf); @@ -32,8 +32,8 @@ static int test_prepare_elf_header(void *elf) return 0; } -void __run_tests(void *mem) +void __run_tests(void *mem, const char *msg) { - if (test_prepare_elf_header(mem)) + if (test_prepare_elf_header(mem, msg)) return; } diff --git a/test/compel/main.c b/test/compel/main.c index e272dfb76..869d5f7a2 100644 --- a/test/compel/main.c +++ b/test/compel/main.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "piegen.h" #include "arch_test_handle_binary.h" @@ -22,22 +23,30 @@ extern int handle_binary(void *mem, size_t size); extern void run_tests(void *mem); +/* To shut down error printing on tests for failures */ piegen_opt_t opts = { .fout = NULL, .ferr = NULL, .fdebug = NULL, }; -int launch_test(void *mem, int expected_ret, const char *test_name) +int launch_test(void *mem, int expected_ret, const char *test_fmt, ...) { static unsigned test_nr = 1; int ret = handle_binary(mem, ELF_BUF_SIZE); + va_list params; - if (ret != expected_ret) - printf("not ok %u - %s, expected %d but ret is %d\n", - test_nr, test_name, expected_ret, ret); - else - printf("ok %u - %s\n", test_nr, test_name); + va_start(params, test_fmt); + if (ret != expected_ret) { + printf("not ok %u - ", test_nr); + vprintf(test_fmt, params); + printf(", expected %d but ret is %d\n", expected_ret, ret); + } else { + printf("ok %u - ", test_nr); + vprintf(test_fmt, params); + putchar('\n'); + } + va_end(params); test_nr++; fflush(stdout); From 6f58ca5acec4493a1fbc5c3920f0e9c071e7c6cc Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 25 May 2016 20:12:00 +0300 Subject: [PATCH 0040/4375] Makefile: add .FORCE target Sorry for introducing that, but we need to force-rebuild implicit rules on the level of main Makefile. All the sub-makefiles should decide if the force-rebuilding target really needs a rebuild, because they know it's dependencies. Pattern-specific rules are implicit, so something like: .PHONY: compel/% criu/% #... will not work. .FORCE target seems the simplest way to solve this "going to submake on rebuild" problem. But maybe there is more elegant proposal? FWIW, before this patch: [criu]$ make compel/compel make[1]: Entering directory '~/tools/criu' HOSTDEP compel/handle-elf-32.d ... HOSTLINK compel/compel make[1]: Leaving directory '~/tools/criu' [criu]$ touch compel/main.c [criu]$ make compel/compel make: 'compel/compel' is up to date. [criu]$ touch compel/Makefile [criu]$ make compel/compel make: 'compel/compel' is up to date. After the patch: [criu]$ touch compel/main.c [criu]$ make compel/compel make[1]: Entering directory '~/tools/criu' HOSTDEP compel/main.d HOSTCC compel/main.o HOSTLINK compel/compel make[1]: Leaving directory '~/tools/criu' [criu]$ touch compel/Makefile [criu]$ make compel/compel make[1]: Entering directory '~/tools/criu' HOSTDEP compel/handle-elf-32.d ... HOSTLINK compel/compel make[1]: Leaving directory '~/tools/criu' Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9e2483ab2..a6e08d124 100644 --- a/Makefile +++ b/Makefile @@ -202,10 +202,10 @@ $(eval $(call gen-built-in,images)) .PHONY: .FORCE # Compel get used by CRIU, build it earlier -compel/%: +compel/%: .FORCE $(Q) $(MAKE) $(build)=compel $@ -test/compel/%: +test/compel/%: .FORCE $(Q) $(MAKE) $(build)=compel $@ # From 3c966037d86d4efbdff3baf5875a87e5b0680a4b Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 30 May 2016 16:14:00 +0300 Subject: [PATCH 0041/4375] compel/tests: add sections table & string section tests Now it has 4 new tests: ok 4 - section table start oob (64-bit ELF) ok 5 - too many sections in table (64-bit ELF) ok 6 - strings section's header oob of section table (64-bit ELF) ok 7 - strings section oob (64-bit ELF) I.e, if we forget to test string section's header oob with the next diff: >--- a/compel/handle-elf.c >+++ b/compel/handle-elf.c >@@ -122,7 +122,7 @@ static const char *get_strings_section(Ehdr_t *hdr, uintptr_t mem, > pr_err("String section @%#zx size %#lx is out of [%#zx, %#zx)\n", > addr, (unsigned long)secstrings_hdr->sh_size, > mem, mem + size); >- return NULL; >+ return (void*)addr; > } > > return (void*)addr; It will yell with: ok 1 - zero ELF header (64-bit ELF) ... not ok 6 - strings section's header oob of section table (64-bit ELF), expected -4 but ret is -1 ... not ok 12 - strings section's header oob of section table (32-bit ELF), expected -4 but ret is -1 Should be more useful when I add relocations tests after all. (but this seems for me useful too). Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/elf32-types.h | 4 +++ compel/include/uapi/elf64-types.h | 4 +++ test/compel/handle_binary.c | 53 +++++++++++++++++++++++++++++++ test/compel/main.c | 6 ++-- 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/compel/include/uapi/elf32-types.h b/compel/include/uapi/elf32-types.h index 0a3b08a32..51bf4a24a 100644 --- a/compel/include/uapi/elf32-types.h +++ b/compel/include/uapi/elf32-types.h @@ -7,6 +7,10 @@ #define Rel_t Elf32_Rel #define Rela_t Elf32_Rela +#define Off_t Elf32_Off +#define Word_t Elf32_Word +#define Half_t Elf32_Half + #define ELF_ST_TYPE ELF32_ST_TYPE #define ELF_ST_BIND ELF32_ST_BIND diff --git a/compel/include/uapi/elf64-types.h b/compel/include/uapi/elf64-types.h index 31fcbdb06..d4d6f6f16 100644 --- a/compel/include/uapi/elf64-types.h +++ b/compel/include/uapi/elf64-types.h @@ -7,6 +7,10 @@ #define Rel_t Elf64_Rel #define Rela_t Elf64_Rela +#define Off_t Elf64_Off +#define Word_t Elf64_Word +#define Half_t Elf64_Half + #define ELF_ST_TYPE ELF64_ST_TYPE #define ELF_ST_BIND ELF64_ST_BIND diff --git a/test/compel/handle_binary.c b/test/compel/handle_binary.c index 09100427f..a213ed0d3 100644 --- a/test/compel/handle_binary.c +++ b/test/compel/handle_binary.c @@ -6,6 +6,9 @@ #include "arch_test_handle_binary.h" extern int launch_test(void *mem, int expected_ret, const char *test_fmt, ...); +extern const size_t test_elf_buf_size; + +static const unsigned int sections_nr = 1; static void set_elf_hdr_relocatable(Ehdr_t *hdr) { @@ -13,6 +16,53 @@ static void set_elf_hdr_relocatable(Ehdr_t *hdr) hdr->e_version = EV_CURRENT; } +static int test_add_strings_section(void *elf, const char *msg) +{ + Ehdr_t *hdr = elf; + Shdr_t *sec_strings_hdr; + uintptr_t sections_table = (uintptr_t)elf + hdr->e_shoff; + size_t sections_table_size = sections_nr*sizeof(hdr->e_shentsize); + + hdr->e_shnum = sections_nr; + hdr->e_shstrndx = sections_nr; /* off-by-one */ + if (launch_test(elf, -E_NO_STR_SEC, + "strings section's header oob of section table %s", msg)) + return -1; + + hdr->e_shstrndx = 0; + sec_strings_hdr = (void *)sections_table; + + sec_strings_hdr->sh_offset = (Off_t)-1; + if (launch_test(elf, -E_NO_STR_SEC, "strings section oob %s", msg)) + return -1; + + /* Put strings just right after sections table. */ + sec_strings_hdr->sh_offset = sections_table - (uintptr_t)elf + + sections_table_size; + return 0; +} + +static int test_prepare_section_table(void *elf, const char *msg) +{ + Ehdr_t *hdr = elf; + + hdr->e_shoff = (Off_t)test_elf_buf_size; + if (launch_test(elf, -E_NO_STR_SEC, "section table start oob %s", msg)) + return -1; + + /* Lets put sections table right after ELF header. */ + hdr->e_shoff = (Off_t) sizeof(Ehdr_t); + hdr->e_shentsize = (Half_t) sizeof(Shdr_t); + + hdr->e_shnum = (Half_t)-1; + if (launch_test(elf, -E_NO_STR_SEC, "too many sections in table %s", msg)) + return -1; + + if (test_add_strings_section(elf, msg)) + return -1; + return 0; +} + static int test_prepare_elf_header(void *elf, const char *msg) { memset(elf, 0, sizeof(Ehdr_t)); @@ -29,6 +79,9 @@ static int test_prepare_elf_header(void *elf, const char *msg) set_elf_hdr_relocatable(elf); + if (test_prepare_section_table(elf, msg)) + return -1; + return 0; } diff --git a/test/compel/main.c b/test/compel/main.c index 869d5f7a2..67c4c8430 100644 --- a/test/compel/main.c +++ b/test/compel/main.c @@ -18,7 +18,7 @@ #include "arch_test_handle_binary.h" /* size of buffer with formed ELF file */ -#define ELF_BUF_SIZE 4096 +const size_t test_elf_buf_size = 4096; extern int handle_binary(void *mem, size_t size); extern void run_tests(void *mem); @@ -33,7 +33,7 @@ piegen_opt_t opts = { int launch_test(void *mem, int expected_ret, const char *test_fmt, ...) { static unsigned test_nr = 1; - int ret = handle_binary(mem, ELF_BUF_SIZE); + int ret = handle_binary(mem, test_elf_buf_size); va_list params; va_start(params, test_fmt); @@ -55,7 +55,7 @@ int launch_test(void *mem, int expected_ret, const char *test_fmt, ...) int main(int argc, char **argv) { - void *elf_buf = malloc(ELF_BUF_SIZE); + void *elf_buf = malloc(test_elf_buf_size); arch_run_tests(elf_buf); free(elf_buf); From 5e0b4d0060548c74167263eb2a03023436714244 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 30 May 2016 15:48:47 +0300 Subject: [PATCH 0042/4375] compel/test: add ASSERT macro Now it looks prettier. Also deleted unnecessary parameters from test's functions. No functional changes. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/compel/handle_binary.c | 44 +++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/test/compel/handle_binary.c b/test/compel/handle_binary.c index a213ed0d3..b06c814ba 100644 --- a/test/compel/handle_binary.c +++ b/test/compel/handle_binary.c @@ -8,6 +8,12 @@ extern int launch_test(void *mem, int expected_ret, const char *test_fmt, ...); extern const size_t test_elf_buf_size; +static uintptr_t elf_addr; +static const char *test_bitness; +#define ASSERT(expected, fmt, ...) \ + launch_test((void *)elf_addr, expected, \ + fmt " %s", ##__VA_ARGS__, test_bitness) + static const unsigned int sections_nr = 1; static void set_elf_hdr_relocatable(Ehdr_t *hdr) @@ -16,38 +22,35 @@ static void set_elf_hdr_relocatable(Ehdr_t *hdr) hdr->e_version = EV_CURRENT; } -static int test_add_strings_section(void *elf, const char *msg) +static int test_add_strings_section(Ehdr_t *hdr) { - Ehdr_t *hdr = elf; Shdr_t *sec_strings_hdr; - uintptr_t sections_table = (uintptr_t)elf + hdr->e_shoff; + uintptr_t sections_table = elf_addr + hdr->e_shoff; size_t sections_table_size = sections_nr*sizeof(hdr->e_shentsize); hdr->e_shnum = sections_nr; hdr->e_shstrndx = sections_nr; /* off-by-one */ - if (launch_test(elf, -E_NO_STR_SEC, - "strings section's header oob of section table %s", msg)) + if (ASSERT(-E_NO_STR_SEC, + "strings section's header oob of section table")) return -1; hdr->e_shstrndx = 0; sec_strings_hdr = (void *)sections_table; sec_strings_hdr->sh_offset = (Off_t)-1; - if (launch_test(elf, -E_NO_STR_SEC, "strings section oob %s", msg)) + if (ASSERT(-E_NO_STR_SEC, "strings section oob")) return -1; /* Put strings just right after sections table. */ - sec_strings_hdr->sh_offset = sections_table - (uintptr_t)elf + + sec_strings_hdr->sh_offset = sections_table - elf_addr + sections_table_size; return 0; } -static int test_prepare_section_table(void *elf, const char *msg) +static int test_prepare_section_table(Ehdr_t *hdr) { - Ehdr_t *hdr = elf; - hdr->e_shoff = (Off_t)test_elf_buf_size; - if (launch_test(elf, -E_NO_STR_SEC, "section table start oob %s", msg)) + if (ASSERT(-E_NO_STR_SEC, "section table start oob")) return -1; /* Lets put sections table right after ELF header. */ @@ -55,31 +58,31 @@ static int test_prepare_section_table(void *elf, const char *msg) hdr->e_shentsize = (Half_t) sizeof(Shdr_t); hdr->e_shnum = (Half_t)-1; - if (launch_test(elf, -E_NO_STR_SEC, "too many sections in table %s", msg)) + if (ASSERT(-E_NO_STR_SEC, "too many sections in table")) return -1; - if (test_add_strings_section(elf, msg)) + if (test_add_strings_section(hdr)) return -1; return 0; } -static int test_prepare_elf_header(void *elf, const char *msg) +static int test_prepare_elf_header(void *elf) { memset(elf, 0, sizeof(Ehdr_t)); - if (launch_test(elf, -E_NOT_ELF, "zero ELF header %s", msg)) + if (ASSERT(-E_NOT_ELF, "zero ELF header")) return -1; arch_test_set_elf_hdr_ident(elf); - if (launch_test(elf, -E_NOT_ELF, "unsupported ELF header %s", msg)) + if (ASSERT(-E_NOT_ELF, "unsupported ELF header")) return -1; arch_test_set_elf_hdr_machine(elf); - if (launch_test(elf, -E_NOT_ELF, "non-relocatable ELF header %s", msg)) + if (ASSERT(-E_NOT_ELF, "non-relocatable ELF header")) return -1; set_elf_hdr_relocatable(elf); - if (test_prepare_section_table(elf, msg)) + if (test_prepare_section_table(elf)) return -1; return 0; @@ -87,6 +90,9 @@ static int test_prepare_elf_header(void *elf, const char *msg) void __run_tests(void *mem, const char *msg) { - if (test_prepare_elf_header(mem, msg)) + elf_addr = (uintptr_t)mem; + test_bitness = msg; + + if (test_prepare_elf_header(mem)) return; } From d6cea8104761b237c90b29c85f3dbdd269e2a89f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 30 May 2016 15:48:48 +0300 Subject: [PATCH 0043/4375] compel/tests: test binary should return error To check test's result in travis. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .../arch/x86/include/arch_test_handle_binary.h | 14 +++++++++----- test/compel/handle_binary.c | 5 +++-- test/compel/main.c | 5 +++-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/test/compel/arch/x86/include/arch_test_handle_binary.h b/test/compel/arch/x86/include/arch_test_handle_binary.h index 082c00dfb..ae16ac57e 100644 --- a/test/compel/arch/x86/include/arch_test_handle_binary.h +++ b/test/compel/arch/x86/include/arch_test_handle_binary.h @@ -34,12 +34,16 @@ static __maybe_unused void arch_test_set_elf_hdr_machine(Ehdr_t *hdr) #endif /* CONFIG_X86_32 */ -extern void run_tests_64(void *mem, const char *msg); -extern void run_tests_32(void *mem, const char *msg); +extern int run_tests_64(void *mem, const char *msg); +extern int run_tests_32(void *mem, const char *msg); -static __maybe_unused void arch_run_tests(void *mem) +static __maybe_unused int arch_run_tests(void *mem) { - run_tests_64(mem, "(64-bit ELF)"); - run_tests_32(mem, "(32-bit ELF)"); + int ret; + + ret = run_tests_64(mem, "(64-bit ELF)"); + ret += run_tests_32(mem, "(32-bit ELF)"); + + return ret; } #endif /* __ARCH_TEST_HANDLE_BINARY__ */ diff --git a/test/compel/handle_binary.c b/test/compel/handle_binary.c index b06c814ba..4ef42ae11 100644 --- a/test/compel/handle_binary.c +++ b/test/compel/handle_binary.c @@ -88,11 +88,12 @@ static int test_prepare_elf_header(void *elf) return 0; } -void __run_tests(void *mem, const char *msg) +int __run_tests(void *mem, const char *msg) { elf_addr = (uintptr_t)mem; test_bitness = msg; if (test_prepare_elf_header(mem)) - return; + return 1; + return 0; } diff --git a/test/compel/main.c b/test/compel/main.c index 67c4c8430..846095ea1 100644 --- a/test/compel/main.c +++ b/test/compel/main.c @@ -56,8 +56,9 @@ int launch_test(void *mem, int expected_ret, const char *test_fmt, ...) int main(int argc, char **argv) { void *elf_buf = malloc(test_elf_buf_size); + int ret; - arch_run_tests(elf_buf); + ret = arch_run_tests(elf_buf); free(elf_buf); - return 0; + return ret; } From 968925817709a24c0873e0e1b747d03d581381ea Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 30 May 2016 15:48:49 +0300 Subject: [PATCH 0044/4375] compel/Makefile: use force to rebuild test's submake Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compel/Makefile b/compel/Makefile index db90c7e14..5166e9318 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -27,8 +27,10 @@ compel-objs += handle-elf-32.o export HOSTCFLAGS_handle-elf-32.o += -DCONFIG_X86_32 endif # ARCH == x86 +.PHONY: .FORCE + export compel-objs -test/compel/%: +test/compel/%: .FORCE $(Q) $(MAKE) $(build)=test/compel $@ test: test/compel/test_handle_binary From 9d27b2cc36b92dd5c9cab1092f66dd525dce2981 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 30 May 2016 15:48:50 +0300 Subject: [PATCH 0045/4375] compel/tests: fix tests on !x86 archs Add missing string.h include for memcpy(), add extern __run_tests from handle_binary.o. Fixes: commit 67526eb51ecf ("compel: add tests for compel"). Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/compel/arch/aarch64/include/arch_test_handle_binary.h | 3 +++ test/compel/arch/arm/include/arch_test_handle_binary.h | 3 +++ test/compel/arch/ppc64/include/arch_test_handle_binary.h | 3 +++ 3 files changed, 9 insertions(+) diff --git a/test/compel/arch/aarch64/include/arch_test_handle_binary.h b/test/compel/arch/aarch64/include/arch_test_handle_binary.h index cbefd6843..dbaa1d6e3 100644 --- a/test/compel/arch/aarch64/include/arch_test_handle_binary.h +++ b/test/compel/arch/aarch64/include/arch_test_handle_binary.h @@ -1,8 +1,11 @@ #ifndef __ARCH_TEST_HANDLE_BINARY__ #define __ARCH_TEST_HANDLE_BINARY__ +#include + #include "uapi/elf64-types.h" #define arch_run_tests(mem) __run_tests(mem, "") +extern int __run_tests(void *mem, const char *msg); static __maybe_unused void arch_test_set_elf_hdr_ident(void *mem) { diff --git a/test/compel/arch/arm/include/arch_test_handle_binary.h b/test/compel/arch/arm/include/arch_test_handle_binary.h index d80382911..234bd384a 100644 --- a/test/compel/arch/arm/include/arch_test_handle_binary.h +++ b/test/compel/arch/arm/include/arch_test_handle_binary.h @@ -1,8 +1,11 @@ #ifndef __ARCH_TEST_HANDLE_BINARY__ #define __ARCH_TEST_HANDLE_BINARY__ +#include + #include "uapi/elf32-types.h" #define arch_run_tests(mem) __run_tests(mem, "") +extern int __run_tests(void *mem, const char *msg); static __maybe_unused void arch_test_set_elf_hdr_ident(void *mem) { diff --git a/test/compel/arch/ppc64/include/arch_test_handle_binary.h b/test/compel/arch/ppc64/include/arch_test_handle_binary.h index 0c70c91db..5f826fee2 100644 --- a/test/compel/arch/ppc64/include/arch_test_handle_binary.h +++ b/test/compel/arch/ppc64/include/arch_test_handle_binary.h @@ -1,8 +1,11 @@ #ifndef __ARCH_TEST_HANDLE_BINARY__ #define __ARCH_TEST_HANDLE_BINARY__ +#include + #include "uapi/elf64-types.h" #define arch_run_tests(mem) __run_tests(mem, "") +extern int __run_tests(void *mem, const char *msg); static __maybe_unused void arch_test_set_elf_hdr_ident(void *mem) { From 1fff6d8a0cc398715668c9fc0d19dcc6adf0b3ba Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 30 May 2016 15:48:51 +0300 Subject: [PATCH 0046/4375] travis-ci: run compel tests on build stage It took a little time on travis (I didn't measure, just starred at build and it added not visible delay for build). But it will help to verify that compel works on all supported arches. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.tmpl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/build/Dockerfile.tmpl b/scripts/build/Dockerfile.tmpl index 6069af25f..72a21ea82 100644 --- a/scripts/build/Dockerfile.tmpl +++ b/scripts/build/Dockerfile.tmpl @@ -27,3 +27,4 @@ RUN make -j $(nproc) CC=$CC V=1 RUN make mrproper RUN bash -c 'CLEAN="$(git clean -ndx --exclude=scripts/build --exclude=.config)"; echo "${CLEAN}"; test -z "${CLEAN}"; exit $?' RUN make -j $(nproc) CC=$CC -C test/zdtm +RUN make test/compel/handle_binary && ./test/compel/handle_binary From 69302058dd6ca78d07cffc88b7380054b48e5c82 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 20 Jun 2016 11:08:00 +0300 Subject: [PATCH 0047/4375] compel: print nr of unsupported relocation Impact: just a bit more info for debugging. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/handle-elf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compel/handle-elf.c b/compel/handle-elf.c index d3a8fe815..be001720f 100644 --- a/compel/handle-elf.c +++ b/compel/handle-elf.c @@ -527,7 +527,8 @@ int __handle_elf(void *mem, size_t size) #endif default: - pr_err("Unsupported relocation\n"); + pr_err("Unsupported relocation of type %lu\n", + (unsigned long)ELF_R_TYPE(r->rel.r_info)); goto err; } } From d58750c946559c97284cc0746ae597f91f723410 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:23:54 +0300 Subject: [PATCH 0048/4375] x86/dump: save gpregs_case Missed has_gpregs_case and on restore it's always native task. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index bed2f4e8d..245b87444 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -280,6 +280,7 @@ static int save_task_regs(CoreEntry *core, assign_reg(gpregs, regs->compat, ss); gpregs->mode = USER_X86_REGS_MODE__COMPAT; } + gpregs->has_gpregs_case = true; if (!fpregs) return 0; From 5aba43bdb7682d8e192fb597d9d7b687589b101c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:23:58 +0300 Subject: [PATCH 0049/4375] x86: add 32-bit sigframe for rt_sigreturn I tried to split this patch as much as it goes, but still it's quite huge. Mostly it has many compatible structures declarations. Lesser it contains adaptation to new native/compat sigframe duality. The only logic that changed by this patch is the order of creating sigframe in construct_sigframe. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 104 +++++++++++++------- criu/arch/x86/include/asm/restorer.h | 33 +++++++ criu/arch/x86/include/asm/sigframe.h | 136 +++++++++++++++++++++++++-- criu/arch/x86/include/asm/types.h | 16 ++++ criu/arch/x86/sigframe.c | 19 +++- criu/sigframe.c | 11 ++- 6 files changed, 272 insertions(+), 47 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 245b87444..3972aa32d 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -496,7 +496,9 @@ static void show_rt_xsave_frame(struct xsave_struct *x) int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) { - fpu_state_t *fpu_state = &sigframe->fpu_state; + fpu_state_t *fpu_state = core_is_compat(core) ? + &sigframe->compat.fpu_state : + &sigframe->native.fpu_state; struct xsave_struct *x = &fpu_state->xsave; /* @@ -584,51 +586,83 @@ void *mmap_seized(struct parasite_ctl *ctl, return (void *)map; } -int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) +#ifdef CONFIG_X86_64 +#define CPREG32(d) f->compat.uc.uc_mcontext.d = r->d +#else +#define CPREG32(d) f->uc.uc_mcontext.d = r->d +#endif +static void restore_compat_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) { - /* FIXME: rt_sigcontext for compatible tasks */ - if (r->gpregs_case != USER_X86_REGS_CASE_T__NATIVE) { - pr_err("Can't prepare rt_sigframe for compatible task restore\n"); - return -1; - } + CPREG32(gs); + CPREG32(fs); + CPREG32(es); + CPREG32(ds); -#define CPREG1(d) f->uc.uc_mcontext.d = r->d -#define CPREG2(d, s) f->uc.uc_mcontext.d = r->s + CPREG32(di); CPREG32(si); CPREG32(bp); CPREG32(sp); CPREG32(bx); + CPREG32(dx); CPREG32(cx); CPREG32(ip); CPREG32(ax); + CPREG32(cs); + CPREG32(ss); + CPREG32(flags); #ifdef CONFIG_X86_64 - CPREG1(r8); - CPREG1(r9); - CPREG1(r10); - CPREG1(r11); - CPREG1(r12); - CPREG1(r13); - CPREG1(r14); - CPREG1(r15); + f->is_native = false; #endif +} +#undef CPREG32 - CPREG2(rdi, di); - CPREG2(rsi, si); - CPREG2(rbp, bp); - CPREG2(rbx, bx); - CPREG2(rdx, dx); - CPREG2(rax, ax); - CPREG2(rcx, cx); - CPREG2(rsp, sp); - CPREG2(rip, ip); - CPREG2(eflags, flags); +#ifdef CONFIG_X86_64 +#define CPREG64(d, s) f->native.uc.uc_mcontext.d = r->s +static void restore_native_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) +{ + CPREG64(rdi, di); + CPREG64(rsi, si); + CPREG64(rbp, bp); + CPREG64(rsp, sp); + CPREG64(rbx, bx); + CPREG64(rdx, dx); + CPREG64(rcx, cx); + CPREG64(rip, ip); + CPREG64(rax, ax); - CPREG1(cs); - CPREG1(ss); + CPREG64(r8, r8); + CPREG64(r9, r9); + CPREG64(r10, r10); + CPREG64(r11, r11); + CPREG64(r12, r12); + CPREG64(r13, r13); + CPREG64(r14, r14); + CPREG64(r15, r15); -#ifdef CONFIG_X86_32 - CPREG1(gs); - CPREG1(fs); - CPREG1(es); - CPREG1(ds); -#endif + CPREG64(cs, cs); + CPREG64(eflags, flags); + + f->is_native = true; +} +#undef CPREG64 + +int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) +{ + switch (r->gpregs_case) { + case USER_X86_REGS_CASE_T__NATIVE: + restore_native_gpregs(f, r); + break; + case USER_X86_REGS_CASE_T__COMPAT: + restore_compat_gpregs(f, r); + break; + default: + pr_err("Can't prepare rt_sigframe: regs_case corrupt\n"); + return -1; + } return 0; } +#else /* !CONFIG_X86_64 */ +int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) +{ + restore_compat_gpregs(f, r); + return 0; +} +#endif /* Copied from the gdb header gdb/nat/x86-dregs.h */ diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index ac8745144..e2ae30399 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -74,6 +74,39 @@ : "memory") #endif /* CONFIG_X86_64 */ +static inline void +__setup_sas_compat(struct ucontext_ia32* uc, ThreadSasEntry *sas) +{ + uc->uc_stack.ss_sp = (compat_uptr_t)(sas)->ss_sp; + uc->uc_stack.ss_flags = (int)(sas)->ss_flags; + uc->uc_stack.ss_size = (compat_size_t)(sas)->ss_size; +} + +static inline void +__setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas) +{ +#ifdef CONFIG_X86_64 + if (sigframe->is_native) { + struct rt_ucontext *uc = &sigframe->native.uc; + + uc->uc_stack.ss_sp = (void *)decode_pointer((sas)->ss_sp); + uc->uc_stack.ss_flags = (int)(sas)->ss_flags; + uc->uc_stack.ss_size = (size_t)(sas)->ss_size; + } else { + __setup_sas_compat(&sigframe->compat.uc, sas); + } +#else + __setup_sas_compat(&sigframe->uc, sas); +#endif +} + +static inline void _setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas) +{ + if (sas) + __setup_sas(sigframe, sas); +} +#define setup_sas _setup_sas + int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r); int restore_nonsigframe_gpregs(UserX86RegsEntry *r); diff --git a/criu/arch/x86/include/asm/sigframe.h b/criu/arch/x86/include/asm/sigframe.h index 2bee1ad00..2dc1a6933 100644 --- a/criu/arch/x86/include/asm/sigframe.h +++ b/criu/arch/x86/include/asm/sigframe.h @@ -39,24 +39,141 @@ struct rt_sigcontext { unsigned long reserved1[8]; }; +struct rt_sigcontext_32 { + uint32_t gs; + uint32_t fs; + uint32_t es; + uint32_t ds; + uint32_t di; + uint32_t si; + uint32_t bp; + uint32_t sp; + uint32_t bx; + uint32_t dx; + uint32_t cx; + uint32_t ax; + uint32_t trapno; + uint32_t err; + uint32_t ip; + uint32_t cs; + uint32_t flags; + uint32_t sp_at_signal; + uint32_t ss; + + uint32_t fpstate; + uint32_t oldmask; + uint32_t cr2; +}; + #include "sigframe-common.h" -struct rt_sigframe { +/* + * XXX: move declarations to generic sigframe.h or sigframe-compat.h + * when (if) other architectures will support compatible C/R + */ + +typedef u32 compat_uptr_t; +typedef u32 compat_size_t; +typedef u32 compat_sigset_word; + +#define _COMPAT_NSIG 64 +#define _COMPAT_NSIG_BPW 32 +#define _COMPAT_NSIG_WORDS (_COMPAT_NSIG / _COMPAT_NSIG_BPW) + +typedef struct { + compat_sigset_word sig[_COMPAT_NSIG_WORDS]; +} compat_sigset_t; + +typedef struct compat_siginfo { + int si_signo; + int si_errno; + int si_code; + int _pad[128/sizeof(int) - 3]; +} compat_siginfo_t; + +static inline void __always_unused __check_compat_sigset_t(void) +{ + BUILD_BUG_ON(sizeof(compat_sigset_t) != sizeof(k_rtsigset_t)); +} + +#ifdef CONFIG_X86_32 +#define rt_sigframe_ia32 rt_sigframe +#endif + +typedef struct compat_sigaltstack { + compat_uptr_t ss_sp; + int ss_flags; + compat_size_t ss_size; +} compat_stack_t; + +struct ucontext_ia32 { + unsigned int uc_flags; + unsigned int uc_link; + compat_stack_t uc_stack; + struct rt_sigcontext_32 uc_mcontext; + k_rtsigset_t uc_sigmask; /* mask last for extensibility */ +}; + +struct rt_sigframe_ia32 { + uint32_t pretcode; + int32_t sig; + uint32_t pinfo; + uint32_t puc; +#ifdef CONFIG_X86_64 + compat_siginfo_t info; +#else + struct rt_siginfo info; +#endif + struct ucontext_ia32 uc; + char retcode[8]; + + /* fp state follows here */ + fpu_state_t fpu_state; +}; + +#ifdef CONFIG_X86_64 +struct rt_sigframe_64 { char *pretcode; struct rt_ucontext uc; struct rt_siginfo info; + /* fp state follows here */ fpu_state_t fpu_state; }; -#define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->uc) -#define RT_SIGFRAME_REGIP(rt_sigframe) (rt_sigframe)->uc.uc_mcontext.rip -#define RT_SIGFRAME_FPU(rt_sigframe) (&(rt_sigframe)->fpu_state) +struct rt_sigframe { + union { + struct rt_sigframe_ia32 compat; + struct rt_sigframe_64 native; + }; + bool is_native; +}; + +#define RT_SIGFRAME_UC_SIGMASK(rt_sigframe) \ + ((rt_sigframe->is_native) ? \ + (&rt_sigframe->native.uc.uc_sigmask) : \ + (&rt_sigframe->compat.uc.uc_sigmask)) + +#define RT_SIGFRAME_REGIP(rt_sigframe) \ + ((rt_sigframe->is_native) ? \ + (rt_sigframe)->native.uc.uc_mcontext.rip : \ + (rt_sigframe)->compat.uc.uc_mcontext.ip) + +#define RT_SIGFRAME_FPU(rt_sigframe) \ + ((rt_sigframe->is_native) ? \ + (&(rt_sigframe)->native.fpu_state) : \ + (&(rt_sigframe)->compat.fpu_state)) + #define RT_SIGFRAME_HAS_FPU(rt_sigframe) (RT_SIGFRAME_FPU(rt_sigframe)->has_fpu) -#define RT_SIGFRAME_OFFSET(rt_sigframe) 8 +/* + * Sigframe offset is different for native/compat tasks. + * Offsets calculations one may see at kernel: + * - compatible is in sys32_rt_sigreturn at arch/x86/ia32/ia32_signal.c + * - native is in sys_rt_sigreturn at arch/x86/kernel/signal.c + */ +#define RT_SIGFRAME_OFFSET(rt_sigframe) ((rt_sigframe->is_native) ? 8 : 4 ) -#ifdef CONFIG_X86_64 #define ARCH_RT_SIGRETURN(new_sp) \ asm volatile( \ "movq %0, %%rax \n" \ @@ -67,6 +184,13 @@ struct rt_sigframe { : "r"(new_sp) \ : "rax","rsp","memory") #else /* CONFIG_X86_64 */ +#define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->uc) +#define RT_SIGFRAME_OFFSET(rt_sigframe) 4 +#define RT_SIGFRAME_REGIP(rt_sigframe) \ + (unsigned long)(rt_sigframe)->uc.uc_mcontext.ip +#define RT_SIGFRAME_FPU(rt_sigframe) (&(rt_sigframe)->fpu_state) +#define RT_SIGFRAME_HAS_FPU(rt_sigframe) (RT_SIGFRAME_FPU(rt_sigframe)->has_fpu) + #define ARCH_RT_SIGRETURN(new_sp) \ asm volatile( \ "movl %0, %%eax \n" \ diff --git a/criu/arch/x86/include/asm/types.h b/criu/arch/x86/include/asm/types.h index 1160c1bf7..743dc69fd 100644 --- a/criu/arch/x86/include/asm/types.h +++ b/criu/arch/x86/include/asm/types.h @@ -10,6 +10,22 @@ #include "images/core.pb-c.h" +#ifdef CONFIG_X86_64 +static inline int core_is_compat(CoreEntry *c) +{ + switch (c->thread_info->gpregs->mode) { + case USER_X86_REGS_MODE__NATIVE: + return 0; + case USER_X86_REGS_MODE__COMPAT: + return 1; + default: + return -1; + } +} +#else /* CONFIG_X86_64 */ +static inline int core_is_compat(CoreEntry *c) { return 0; } +#endif /* CONFIG_X86_64 */ + typedef void rt_signalfn_t(int, siginfo_t *, void *); typedef rt_signalfn_t *rt_sighandler_t; diff --git a/criu/arch/x86/sigframe.c b/criu/arch/x86/sigframe.c index 7da4a89d5..7faed892a 100644 --- a/criu/arch/x86/sigframe.c +++ b/criu/arch/x86/sigframe.c @@ -7,15 +7,24 @@ #include "log.h" int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, - struct rt_sigframe *rsigframe) + struct rt_sigframe *rsigframe) { - fpu_state_t *fpu_state = RT_SIGFRAME_FPU(rsigframe); + /* + * Use local sigframe to check native/compat type, + * but set address for rsigframe. + */ + fpu_state_t *fpu_state = (sigframe->is_native) ? + &rsigframe->native.fpu_state : + &rsigframe->compat.fpu_state; unsigned long addr = (unsigned long)(void *)&fpu_state->xsave; - if ((addr % 64ul) == 0ul) { - sigframe->uc.uc_mcontext.fpstate = &fpu_state->xsave; + if (sigframe->is_native && (addr % 64ul) == 0ul) { + sigframe->native.uc.uc_mcontext.fpstate = &fpu_state->xsave; + } else if (!sigframe->is_native && (addr % 32ul) == 0ul) { + sigframe->compat.uc.uc_mcontext.fpstate = (uint32_t)addr; } else { - pr_err("Unaligned address passed: %lx\n", addr); + pr_err("Unaligned address passed: %lx (native %d)\n", + addr, sigframe->is_native); return -1; } diff --git a/criu/sigframe.c b/criu/sigframe.c index 67363d372..b2dd85add 100644 --- a/criu/sigframe.c +++ b/criu/sigframe.c @@ -3,6 +3,7 @@ #include "restore.h" #include "images/core.pb-c.h" +#ifndef setup_sas static inline void setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas) { if (sas) { @@ -14,20 +15,28 @@ static inline void setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas) #undef UC } } +#endif +#ifndef RT_SIGFRAME_UC_SIGMASK #define RT_SIGFRAME_UC_SIGMASK(sigframe) \ (k_rtsigset_t*)&RT_SIGFRAME_UC(sigframe)->uc_sigmask +#endif int construct_sigframe(struct rt_sigframe *sigframe, struct rt_sigframe *rsigframe, k_rtsigset_t *blkset, CoreEntry *core) { - k_rtsigset_t *blk_sigset = RT_SIGFRAME_UC_SIGMASK(sigframe); + k_rtsigset_t *blk_sigset; + /* + * Copy basic register set in the first place: this will set + * rt_sigframe type: native/compat. + */ if (restore_gpregs(sigframe, CORE_THREAD_ARCH_INFO(core)->gpregs)) return -1; + blk_sigset = RT_SIGFRAME_UC_SIGMASK(sigframe); if (blkset) memcpy(blk_sigset, blkset, sizeof(k_rtsigset_t)); else From b6aca38d14cb129748f3127228f4b66b89c767f0 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:23:59 +0300 Subject: [PATCH 0050/4375] x86/restorer: add sigreturn to compat mode Do pure 32-bit sigreturn. Change code selector, do 0x80 rt_sigreturn. We should have here remapped 32-bit vDSO, all should be fine. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/include/asm/sigframe.h | 2 +- criu/arch/arm/include/asm/sigframe.h | 2 +- criu/arch/ppc64/include/asm/sigframe.h | 2 +- criu/arch/x86/include/asm/sigframe.h | 28 ++++++++++++++++++++++-- criu/pie/parasite.c | 2 +- criu/pie/restorer.c | 9 ++++---- 6 files changed, 35 insertions(+), 10 deletions(-) diff --git a/criu/arch/aarch64/include/asm/sigframe.h b/criu/arch/aarch64/include/asm/sigframe.h index d428c2904..3e8d63fb8 100644 --- a/criu/arch/aarch64/include/asm/sigframe.h +++ b/criu/arch/aarch64/include/asm/sigframe.h @@ -32,7 +32,7 @@ struct rt_sigframe { uint64_t lr; }; -#define ARCH_RT_SIGRETURN(new_sp) \ +#define ARCH_RT_SIGRETURN(new_sp, rt_sigframe) \ asm volatile( \ "mov sp, %0 \n" \ "mov x8, #"__stringify(__NR_rt_sigreturn)" \n" \ diff --git a/criu/arch/arm/include/asm/sigframe.h b/criu/arch/arm/include/asm/sigframe.h index eea502f0b..c9433e07b 100644 --- a/criu/arch/arm/include/asm/sigframe.h +++ b/criu/arch/arm/include/asm/sigframe.h @@ -64,7 +64,7 @@ struct rt_sigframe { }; -#define ARCH_RT_SIGRETURN(new_sp) \ +#define ARCH_RT_SIGRETURN(new_sp, rt_sigframe) \ asm volatile( \ "mov sp, %0 \n" \ "mov r7, #"__stringify(__NR_rt_sigreturn)" \n" \ diff --git a/criu/arch/ppc64/include/asm/sigframe.h b/criu/arch/ppc64/include/asm/sigframe.h index 9575df629..498bf8a8c 100644 --- a/criu/arch/ppc64/include/asm/sigframe.h +++ b/criu/arch/ppc64/include/asm/sigframe.h @@ -43,7 +43,7 @@ struct rt_sigframe { char abigap[USER_REDZONE_SIZE]; } __attribute__((aligned(16))); -#define ARCH_RT_SIGRETURN(new_sp) \ +#define ARCH_RT_SIGRETURN(new_sp, rt_sigframe) \ asm volatile( \ "mr 1, %0 \n" \ "li 0, "__stringify(__NR_rt_sigreturn)" \n" \ diff --git a/criu/arch/x86/include/asm/sigframe.h b/criu/arch/x86/include/asm/sigframe.h index 2dc1a6933..b03aaf6cb 100644 --- a/criu/arch/x86/include/asm/sigframe.h +++ b/criu/arch/x86/include/asm/sigframe.h @@ -174,7 +174,9 @@ struct rt_sigframe { */ #define RT_SIGFRAME_OFFSET(rt_sigframe) ((rt_sigframe->is_native) ? 8 : 4 ) -#define ARCH_RT_SIGRETURN(new_sp) \ +#define USER32_CS 0x23 + +#define ARCH_RT_SIGRETURN_NATIVE(new_sp) \ asm volatile( \ "movq %0, %%rax \n" \ "movq %%rax, %%rsp \n" \ @@ -183,6 +185,28 @@ struct rt_sigframe { : \ : "r"(new_sp) \ : "rax","rsp","memory") +#define ARCH_RT_SIGRETURN_COMPAT(new_sp) \ + asm volatile( \ + "pushq $"__stringify(USER32_CS)" \n" \ + "pushq $1f \n" \ + "lretq \n" \ + "1: \n" \ + ".code32 \n" \ + "movl %%edi, %%esp \n" \ + "movl $"__stringify(__NR32_rt_sigreturn)",%%eax \n" \ + "int $0x80 \n" \ + ".code64 \n" \ + : \ + : "rdi"(new_sp) \ + : "eax","esp","memory") + +#define ARCH_RT_SIGRETURN(new_sp, rt_sigframe) \ +do { \ + if ((rt_sigframe)->is_native) \ + ARCH_RT_SIGRETURN_NATIVE(new_sp); \ + else \ + ARCH_RT_SIGRETURN_COMPAT(new_sp); \ +} while (0) #else /* CONFIG_X86_64 */ #define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->uc) #define RT_SIGFRAME_OFFSET(rt_sigframe) 4 @@ -191,7 +215,7 @@ struct rt_sigframe { #define RT_SIGFRAME_FPU(rt_sigframe) (&(rt_sigframe)->fpu_state) #define RT_SIGFRAME_HAS_FPU(rt_sigframe) (RT_SIGFRAME_FPU(rt_sigframe)->has_fpu) -#define ARCH_RT_SIGRETURN(new_sp) \ +#define ARCH_RT_SIGRETURN(new_sp, rt_sigframe) \ asm volatile( \ "movl %0, %%eax \n" \ "movl %%eax, %%esp \n" \ diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index ec979bc65..45e5e79e9 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -659,7 +659,7 @@ static int __parasite_daemon_wait_msg(struct ctl_msg *m) static noinline void fini_sigreturn(unsigned long new_sp) { - ARCH_RT_SIGRETURN(new_sp); + ARCH_RT_SIGRETURN(new_sp, sigframe); } static void parasite_cleanup(void) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 1db154bac..7c4da5761 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -424,9 +424,10 @@ static int restore_thread_common(struct thread_restore_args *args) return 0; } -static void noinline rst_sigreturn(unsigned long new_sp) +static void noinline rst_sigreturn(unsigned long new_sp, + struct rt_sigframe *sigframe) { - ARCH_RT_SIGRETURN(new_sp); + ARCH_RT_SIGRETURN(new_sp, sigframe); } /* @@ -485,7 +486,7 @@ long __export_restore_thread(struct thread_restore_args *args) futex_dec_and_wake(&thread_inprogress); new_sp = (long)rt_sigframe + RT_SIGFRAME_OFFSET(rt_sigframe); - rst_sigreturn(new_sp); + rst_sigreturn(new_sp, rt_sigframe); core_restore_end: pr_err("Restorer abnormal termination for %ld\n", sys_getpid()); @@ -1449,7 +1450,7 @@ long __export_restore_task(struct task_restore_args *args) * pure assembly since we don't need any additional * code insns from gcc. */ - rst_sigreturn(new_sp); + rst_sigreturn(new_sp, rt_sigframe); core_restore_end: futex_abort_and_wake(&task_entries_local->nr_in_progress); From f6126361a2064bf766431a098bbee7babf823ed7 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:00 +0300 Subject: [PATCH 0051/4375] parasite-head-32: fix cmd & args load Seems like, offset was broken. And it had typo: leal -> movl (according to 64-bit parasite header), as cmd parameter is int (not pointer to int) in parasite_service: int __used __parasite_entry parasite_service(unsigned int cmd, void *args) Fixed - loads good now. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/parasite-head-32.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/arch/x86/parasite-head-32.S b/criu/arch/x86/parasite-head-32.S index 900edebcb..50c032a90 100644 --- a/criu/arch/x86/parasite-head-32.S +++ b/criu/arch/x86/parasite-head-32.S @@ -14,8 +14,8 @@ ENTRY(__export_parasite_head_start) movl %esp, %ebp call 1f 1: popl %ecx -2: leal (__export_parasite_cmd-2b)(%ecx), %eax - leal (__export_parasite_args-2b)(%ecx), %edx + movl (__export_parasite_cmd-1b)(%ecx), %eax + leal (__export_parasite_args-1b)(%ecx), %edx call parasite_service int $0x03 .align 8 From 094afe856b4bc95d562f535e79f8ca8b7fbdff3d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:01 +0300 Subject: [PATCH 0052/4375] syscalls: add __NR(syscall, compat) wrapper Generic code uses raw syscall numbers for: - syscall_seized, to execute through parasite control needed syscall; - parasite_stop_on_syscall, to trap couple of tasks on needed syscall. As syscall numbers may differ (and differ for x86) between native and compatible mode, we need proper syscall wrapper here. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .../aarch64/include/asm/parasite-syscall.h | 1 + criu/arch/arm/include/asm/parasite-syscall.h | 1 + .../arch/ppc64/include/asm/parasite-syscall.h | 2 + criu/arch/x86/crtools.c | 5 ++- criu/arch/x86/include/asm/parasite-syscall.h | 10 +++++ criu/arch/x86/include/asm/syscall32.h | 8 ---- criu/cr-restore.c | 3 +- criu/include/parasite-syscall.h | 3 +- criu/parasite-syscall.c | 41 ++++++++++++++----- 9 files changed, 53 insertions(+), 21 deletions(-) diff --git a/criu/arch/aarch64/include/asm/parasite-syscall.h b/criu/arch/aarch64/include/asm/parasite-syscall.h index f992bca84..7a5591ad5 100644 --- a/criu/arch/aarch64/include/asm/parasite-syscall.h +++ b/criu/arch/aarch64/include/asm/parasite-syscall.h @@ -5,6 +5,7 @@ struct parasite_ctl; #define ARCH_SI_TRAP TRAP_BRKPT +#define __NR(syscall, compat) __NR_##syscall void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); diff --git a/criu/arch/arm/include/asm/parasite-syscall.h b/criu/arch/arm/include/asm/parasite-syscall.h index f992bca84..7a5591ad5 100644 --- a/criu/arch/arm/include/asm/parasite-syscall.h +++ b/criu/arch/arm/include/asm/parasite-syscall.h @@ -5,6 +5,7 @@ struct parasite_ctl; #define ARCH_SI_TRAP TRAP_BRKPT +#define __NR(syscall, compat) __NR_##syscall void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); diff --git a/criu/arch/ppc64/include/asm/parasite-syscall.h b/criu/arch/ppc64/include/asm/parasite-syscall.h index 1ac6b3b59..7a5591ad5 100644 --- a/criu/arch/ppc64/include/asm/parasite-syscall.h +++ b/criu/arch/ppc64/include/asm/parasite-syscall.h @@ -5,6 +5,8 @@ struct parasite_ctl; #define ARCH_SI_TRAP TRAP_BRKPT +#define __NR(syscall, compat) __NR_##syscall + void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); void *mmap_seized(struct parasite_ctl *ctl, diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 3972aa32d..49cfbed23 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -6,6 +6,7 @@ #include "types.h" #include "asm/processor-flags.h" +#include "asm/parasite-syscall.h" #include "asm/restorer.h" #include "asm/fpu.h" @@ -18,6 +19,7 @@ #include "util.h" #include "cpu.h" #include "errno.h" +#include "syscall-codes.h" #include "protobuf.h" #include "images/core.pb-c.h" @@ -570,8 +572,9 @@ void *mmap_seized(struct parasite_ctl *ctl, { unsigned long map; int err; + bool compat_task = !user_regs_native(&ctl->orig.regs); - err = syscall_seized(ctl, __NR_mmap, &map, + err = syscall_seized(ctl, __NR(mmap, compat_task), &map, (unsigned long)addr, length, prot, flags, fd, offset); if (err < 0) return NULL; diff --git a/criu/arch/x86/include/asm/parasite-syscall.h b/criu/arch/x86/include/asm/parasite-syscall.h index e2c7a5abb..cbc0442dd 100644 --- a/criu/arch/x86/include/asm/parasite-syscall.h +++ b/criu/arch/x86/include/asm/parasite-syscall.h @@ -7,6 +7,16 @@ struct parasite_ctl; #define ARCH_SI_TRAP SI_KERNEL +#define __NR(syscall, compat) ((compat) ? __NR32_##syscall : __NR_##syscall) + +/* + * For x86_32 __NR_mmap inside the kernel represents old_mmap system + * call, but since we didn't use it yet lets go further and simply + * define own alias for __NR_mmap2 which would allow us to unify code + * between 32 and 64 bits version. + */ +#define __NR32_mmap __NR32_mmap2 + void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); diff --git a/criu/arch/x86/include/asm/syscall32.h b/criu/arch/x86/include/asm/syscall32.h index b0d5cb71d..a6e298217 100644 --- a/criu/arch/x86/include/asm/syscall32.h +++ b/criu/arch/x86/include/asm/syscall32.h @@ -14,12 +14,4 @@ extern long sys_getsockopt(int sockfd, int level, int optname, const void *optva extern long sys_shmat(int shmid, void *shmaddr, int shmflag); extern long sys_pread(unsigned int fd, char *ubuf, u32 count, u64 pos); -/* - * For x86_32 __NR_mmap inside the kernel represents old_mmap system - * call, but since we didn't use it yet lets go further and simply - * define own alias for __NR_mmap2 which would allow us to unify code - * between 32 and 64 bits version. - */ -#define __NR_mmap __NR_mmap2 - #endif /* __CR_SYSCALL32_H__ */ diff --git a/criu/cr-restore.c b/criu/cr-restore.c index a5ec851ea..706907e16 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -79,6 +79,7 @@ #include "parasite-syscall.h" #include "files-reg.h" +#include "syscall-codes.h" #include "protobuf.h" #include "images/sa.pb-c.h" @@ -1864,7 +1865,7 @@ static int restore_root_task(struct pstree_item *init) if (ret == 0) ret = parasite_stop_on_syscall(task_entries->nr_threads, - __NR_rt_sigreturn, flag); + __NR(rt_sigreturn, 0), __NR(rt_sigreturn, 1), flag); if (clear_breakpoints()) pr_err("Unable to flush breakpoints\n"); diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 6004a8520..16675e895 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -132,7 +132,8 @@ enum trace_flags { }; extern int parasite_stop_daemon(struct parasite_ctl *ctl); -extern int parasite_stop_on_syscall(int tasks, int sys_nr, enum trace_flags trace); +extern int parasite_stop_on_syscall(int tasks, int sys_nr, + int sys_nr_compat, enum trace_flags trace); extern int parasite_unmap(struct parasite_ctl *ctl, unsigned long addr); extern int ptrace_stop_pie(pid_t pid, void *addr, enum trace_flags *tf); diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index ba47079e1..3fa908ab4 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -927,7 +927,8 @@ static int parasite_fini_seized(struct parasite_ctl *ctl) if (ret < 0) return ret; - if (parasite_stop_on_syscall(1, __NR_rt_sigreturn, flag)) + if (parasite_stop_on_syscall(1, __NR(rt_sigreturn, 0), + __NR(rt_sigreturn, 1), flag)) return -1; if (ptrace_flush_breakpoints(pid)) @@ -962,13 +963,31 @@ static bool task_is_trapped(int status, pid_t pid) return false; } +static inline int is_required_syscall(user_regs_struct_t regs, pid_t pid, + const int sys_nr, const int sys_nr_compat) +{ + const char *mode = user_regs_native(®s) ? "native" : "compat"; + int req_sysnr = user_regs_native(®s) ? sys_nr : sys_nr_compat; + + pr_debug("%d (%s) is going to execute the syscall %lu, required is %d\n", + pid, mode, REG_SYSCALL_NR(regs), req_sysnr); + if (user_regs_native(®s) && (REG_SYSCALL_NR(regs) == sys_nr)) + return true; + if (!user_regs_native(®s) && (REG_SYSCALL_NR(regs) == sys_nr_compat)) + return true; + + return false; +} /* * Trap tasks on the exit from the specified syscall * * tasks - number of processes, which should be trapped * sys_nr - the required syscall number + * sys_nr_compat - the required compatible syscall number */ -int parasite_stop_on_syscall(int tasks, const int sys_nr, enum trace_flags trace) +int parasite_stop_on_syscall(int tasks, + const int sys_nr, const int sys_nr_compat, + enum trace_flags trace) { user_regs_struct_t regs; int status, ret; @@ -1004,8 +1023,7 @@ int parasite_stop_on_syscall(int tasks, const int sys_nr, enum trace_flags trace return -1; } - pr_debug("%d is going to execute the syscall %lu\n", pid, REG_SYSCALL_NR(regs)); - if (REG_SYSCALL_NR(regs) == sys_nr) { + if (is_required_syscall(regs, pid, sys_nr, sys_nr_compat)) { /* * The process is going to execute the required syscall, * the next stop will be on the exit from this syscall @@ -1083,7 +1101,7 @@ int parasite_cure_remote(struct parasite_ctl *ctl) } else { unsigned long ret; - syscall_seized(ctl, __NR_munmap, &ret, + syscall_seized(ctl, __NR(munmap, !seized_native(ctl)), &ret, (unsigned long)ctl->remote_map, ctl->map_length, 0, 0, 0, 0); if (ret) { @@ -1137,7 +1155,8 @@ int parasite_unmap(struct parasite_ctl *ctl, unsigned long addr) if (ret) goto err; - ret = parasite_stop_on_syscall(1, __NR_munmap, TRACE_ENTER); + ret = parasite_stop_on_syscall(1, __NR(munmap, 0), + __NR(munmap, 1), TRACE_ENTER); if (restore_thread_ctx(pid, &ctl->orig)) ret = -1; @@ -1217,6 +1236,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) pid_t pid = ctl->rpid; unsigned long sret = -ENOSYS; int ret, fd, lfd; + bool __maybe_unused compat_task = !user_regs_native(&ctl->orig.regs); if (fault_injected(FI_NO_MEMFD)) return 1; @@ -1228,13 +1248,14 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) return -1; } - ret = syscall_seized(ctl, __NR_memfd_create, &sret, + ret = syscall_seized(ctl, __NR(memfd_create, compat_task), &sret, (unsigned long)where, 0, 0, 0, 0, 0); if (ptrace_poke_area(pid, orig_code, where, sizeof(orig_code))) { fd = (int)(long)sret; if (fd >= 0) - syscall_seized(ctl, __NR_close, &sret, fd, 0, 0, 0, 0, 0); + syscall_seized(ctl, __NR(close, compat_task), &sret, + fd, 0, 0, 0, 0, 0); pr_err("Can't restore memfd args (pid: %d)\n", pid); return -1; } @@ -1274,7 +1295,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) goto err_curef; } - syscall_seized(ctl, __NR_close, &sret, fd, 0, 0, 0, 0, 0); + syscall_seized(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); close(lfd); pr_info("Set up parasite blob using memfd\n"); @@ -1283,7 +1304,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) err_curef: close(lfd); err_cure: - syscall_seized(ctl, __NR_close, &sret, fd, 0, 0, 0, 0, 0); + syscall_seized(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); return -1; } From 6b9780ca769d1f6dd5b0467940e41c1a9480bf1d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:02 +0300 Subject: [PATCH 0053/4375] x86/crtools: log dumping task's mode Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 49cfbed23..a15399670 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -172,7 +172,8 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) struct iovec iov; int ret = -1; - pr_info("Dumping GP/FPU registers for %d\n", pid); + pr_info("Dumping general registers for %d in %s mode\n", pid, + user_regs_native(®s) ? "native" : "compat"); /* Did we come from a system call? */ if (get_signed_user_reg(®s, orig_ax) >= 0) { @@ -203,6 +204,8 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) * thus decode it accrodingly. */ + pr_info("Dumping GP/FPU registers for %d\n", pid); + if (cpu_has_feature(X86_FEATURE_OSXSAVE)) { iov.iov_base = &xsave; iov.iov_len = sizeof(xsave); From 2c0d72fd10c545f3406313b3b02947bb238e2c6c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:03 +0300 Subject: [PATCH 0054/4375] kdat: add compat_sigreturn feature Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/include/asm/restorer.h | 1 + criu/arch/arm/include/asm/restorer.h | 2 +- criu/arch/ppc64/include/asm/restorer.h | 1 + criu/arch/x86/crtools.c | 36 ++++++++++++++++++++++-- criu/arch/x86/include/asm/restorer.h | 8 ++++++ criu/include/kerndat.h | 1 + criu/kerndat.c | 16 +++++++++++ 7 files changed, 62 insertions(+), 3 deletions(-) diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h index aea7951f3..8c5d8550e 100644 --- a/criu/arch/aarch64/include/asm/restorer.h +++ b/criu/arch/aarch64/include/asm/restorer.h @@ -52,6 +52,7 @@ : "sp", "x0", "memory") +#define kdat_compat_sigreturn_test() 0 int restore_gpregs(struct rt_sigframe *f, UserAarch64RegsEntry *r); int restore_nonsigframe_gpregs(UserAarch64RegsEntry *r); diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h index 4d0f64488..e8eec8329 100644 --- a/criu/arch/arm/include/asm/restorer.h +++ b/criu/arch/arm/include/asm/restorer.h @@ -53,7 +53,7 @@ : "memory") - +#define kdat_compat_sigreturn_test() 0 int restore_gpregs(struct rt_sigframe *f, UserArmRegsEntry *r); int restore_nonsigframe_gpregs(UserArmRegsEntry *r); diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h index 8f9d41966..ff44d7d61 100644 --- a/criu/arch/ppc64/include/asm/restorer.h +++ b/criu/arch/ppc64/include/asm/restorer.h @@ -47,6 +47,7 @@ "r"(&thread_args[i]) /* %6 */ \ : "memory","0","3","4","5","6","7","14","15") +#define kdat_compat_sigreturn_test() 0 int restore_gpregs(struct rt_sigframe *f, UserPpc64RegsEntry *r); int restore_nonsigframe_gpregs(UserPpc64RegsEntry *r); diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index a15399670..8c866fbd6 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "types.h" #include "asm/processor-flags.h" @@ -20,6 +22,7 @@ #include "cpu.h" #include "errno.h" #include "syscall-codes.h" +#include "kerndat.h" #include "protobuf.h" #include "images/core.pb-c.h" @@ -67,6 +70,31 @@ void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t * ~(X86_EFLAGS_TF | X86_EFLAGS_DF | X86_EFLAGS_IF)); } +#ifdef CONFIG_X86_64 +/* Remaps 64-bit vDSO on the same addr, where it already is */ +int kdat_compat_sigreturn_test(void) +{ + unsigned long auxval; + int ret; + + errno = 0; + auxval = getauxval(AT_SYSINFO_EHDR); + if (!auxval || errno == ENOENT) { + pr_err("Failed to get auxval, err: %lu\n", auxval); + return 0; + } + /* + * Mapping vDSO on very low unaligned address (1). + * We will get ENOMEM or EPERM if ARCH_MAP_VDSO_* exist, + * and ENOSYS if patches aren't in kernel. + */ + ret = syscall(SYS_arch_prctl, ARCH_MAP_VDSO_32, 1); + if (ret == -1 && errno == ENOSYS) + return 0; + return 1; +} +#endif /* CONFIG_X86_64 */ + int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs); int arch_task_compatible(pid_t pid) { @@ -103,9 +131,13 @@ static bool ldt_task_selectors(pid_t pid) bool arch_can_dump_task(struct parasite_ctl *ctl) { pid_t pid = ctl->rpid; + int ret; - /* FIXME: remove it */ - if (arch_task_compatible(pid)) { + ret = arch_task_compatible(pid); + if (ret < 0) + return false; + + if (ret && !kdat.has_compat_sigreturn) { pr_err("Can't dump task %d running in 32-bit mode\n", pid); return false; } diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index e2ae30399..7fd93bd5d 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -54,6 +54,12 @@ : \ : "r"(ret) \ : "memory") + +#ifndef ARCH_MAP_VDSO_32 +# define ARCH_MAP_VDSO_32 0x2002 +#endif + +extern int kdat_compat_sigreturn_test(void); #else /* CONFIG_X86_64 */ #define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \ thread_args, clone_restore_fn) \ @@ -72,6 +78,8 @@ : \ : "r"(ret) \ : "memory") + +#define kdat_compat_sigreturn_test() 0 #endif /* CONFIG_X86_64 */ static inline void diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 6bedccb08..68a597801 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -34,6 +34,7 @@ struct kerndat_s { unsigned long task_size; bool ipv6; bool has_loginuid; + bool has_compat_sigreturn; enum pagemap_func pmap; unsigned int has_xtlocks; unsigned long mmap_min_addr; diff --git a/criu/kerndat.c b/criu/kerndat.c index 933ca6cd0..fc946ba62 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -557,6 +557,16 @@ err: return exit_code; } +static int kerndat_compat_restore(void) +{ + int ret = kdat_compat_sigreturn_test(); + + if (ret < 0) /* failure */ + return ret; + kdat.has_compat_sigreturn = !!ret; + return 0; +} + int kerndat_init(void) { int ret; @@ -582,6 +592,8 @@ int kerndat_init(void) ret = kerndat_iptables_has_xtlocks(); if (!ret) ret = kerndat_tcp_repair(); + if (!ret) + ret = kerndat_compat_restore(); kerndat_lsm(); kerndat_mmap_min_addr(); @@ -614,6 +626,8 @@ int kerndat_init_rst(void) ret = kerndat_iptables_has_xtlocks(); if (!ret) ret = kerndat_tcp_repair(); + if (!ret) + ret = kerndat_compat_restore(); kerndat_lsm(); kerndat_mmap_min_addr(); @@ -626,6 +640,8 @@ int kerndat_init_cr_exec(void) int ret; ret = get_task_size(); + if (!ret) + ret = kerndat_compat_restore(); return ret; } From 8e329bde93971e4584bbefaf366039a0de66b586 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:05 +0300 Subject: [PATCH 0055/4375] parasite-syscall: deserialize compat parasite's answers Compatible parasite will use standard types, which are sized as _args_compat structures in "parasite-compat.h". Sometimes I miss high-level overloading in C. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 33 +++++-- criu/include/parasite-syscall.h | 3 +- criu/parasite-syscall.c | 161 ++++++++++++++++++++++---------- 3 files changed, 137 insertions(+), 60 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 650930554..3da66d33e 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -667,7 +667,7 @@ static int dump_task_ids(struct pstree_item *item, const struct cr_imgset *cr_im return pb_write_one(img_from_set(cr_imgset, CR_FD_IDS), item->ids, PB_IDS); } -int dump_thread_core(int pid, CoreEntry *core, const struct parasite_dump_thread *ti) +int dump_thread_core(int pid, CoreEntry *core, bool native, const void *dump_thread) { int ret; ThreadCoreEntry *tc = core->thread_core; @@ -678,13 +678,30 @@ int dump_thread_core(int pid, CoreEntry *core, const struct parasite_dump_thread if (!ret) ret = dump_sched_info(pid, tc); if (!ret) { - core_put_tls(core, ti->tls); - CORE_THREAD_ARCH_INFO(core)->clear_tid_addr = encode_pointer(ti->tid_addr); - BUG_ON(!tc->sas); - copy_sas(tc->sas, &ti->sas); - if (ti->pdeath_sig) { - tc->has_pdeath_sig = true; - tc->pdeath_sig = ti->pdeath_sig; + if (native) { + const struct parasite_dump_thread *ti = dump_thread; + + core_put_tls(core, ti->tls); + CORE_THREAD_ARCH_INFO(core)->clear_tid_addr = + encode_pointer(ti->tid_addr); + BUG_ON(!tc->sas); + copy_sas(tc->sas, &ti->sas); + if (ti->pdeath_sig) { + tc->has_pdeath_sig = true; + tc->pdeath_sig = ti->pdeath_sig; + } + } else { + const struct parasite_dump_thread_compat *ti = dump_thread; + + core_put_tls(core, (tls_t)ti->tls); + CORE_THREAD_ARCH_INFO(core)->clear_tid_addr = + encode_pointer((void*)(uintptr_t)ti->tid_addr); + BUG_ON(!tc->sas); + copy_sas_compat(tc->sas, &ti->sas); + if (ti->pdeath_sig) { + tc->has_pdeath_sig = true; + tc->pdeath_sig = ti->pdeath_sig; + } } } diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 16675e895..b28fe0473 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -85,7 +85,8 @@ extern int parasite_dump_creds(struct parasite_ctl *ctl, struct _CredsEntry *ce) extern int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, struct _CoreEntry *core); extern int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, struct pid *tid, struct _CoreEntry *core); -extern int dump_thread_core(int pid, CoreEntry *core, const struct parasite_dump_thread *dt); +extern int dump_thread_core(int pid, CoreEntry *core, bool native, + const void *dump_thread); extern int parasite_drain_fds_seized(struct parasite_ctl *ctl, struct parasite_drain_fd *dfds, int nr_fds, int off, diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 3fa908ab4..3a36aee48 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -120,6 +120,10 @@ static int restore_thread_ctx(int pid, struct thread_ctx *ctx) return ret; } +static inline bool seized_native(struct parasite_ctl *ctl) +{ + return user_regs_native(&ctl->orig.regs); +} static int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack, user_regs_struct_t *regs, struct thread_ctx *octx) { @@ -589,13 +593,19 @@ static int alloc_groups_copy_creds(CredsEntry *ce, struct parasite_dump_creds *c int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEntry *core) { ThreadCoreEntry *tc = core->thread_core; - struct parasite_dump_thread *args; + struct parasite_dump_thread *args = NULL; + struct parasite_dump_thread_compat *args_c = NULL; struct parasite_dump_creds *pc; int ret; - args = parasite_args(ctl, struct parasite_dump_thread); + if (seized_native(ctl)) { + args = parasite_args(ctl, struct parasite_dump_thread); + pc = args->creds; + } else { + args_c = parasite_args(ctl, struct parasite_dump_thread_compat); + pc = args_c->creds; + } - pc = args->creds; pc->cap_last_cap = kdat.last_cap; ret = parasite_execute_daemon(PARASITE_CMD_DUMP_THREAD, ctl); @@ -608,13 +618,17 @@ int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEn return -1; } - return dump_thread_core(pid, core, args); + if (seized_native(ctl)) + return dump_thread_core(pid, core, true, args); + else + return dump_thread_core(pid, core, false, args_c); } int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, struct pid *tid, CoreEntry *core) { - struct parasite_dump_thread *args; + struct parasite_dump_thread *args = NULL; + struct parasite_dump_thread_compat *args_c = NULL; pid_t pid = tid->real; ThreadCoreEntry *tc = core->thread_core; CredsEntry *creds = tc->creds; @@ -624,9 +638,14 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, BUG_ON(id == 0); /* Leader is dumped in dump_task_core_all */ - args = parasite_args(ctl, struct parasite_dump_thread); + if (seized_native(ctl)) { + args = parasite_args(ctl, struct parasite_dump_thread); + pc = args->creds; + } else { + args_c = parasite_args(ctl, struct parasite_dump_thread_compat); + pc = args_c->creds; + } - pc = args->creds; pc->cap_last_cap = kdat.last_cap; ret = get_thread_ctx(pid, &octx); @@ -654,18 +673,37 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, return -1; } - tid->ns[0].virt = args->tid; - return dump_thread_core(pid, core, args); + if (seized_native(ctl)) { + tid->ns[0].virt = args->tid; + return dump_thread_core(pid, core, true, args); + } else { + tid->ns[0].virt = args_c->tid; + return dump_thread_core(pid, core, false, args_c); + } } +#define ASSIGN_SAS(se, args) \ +do { \ + ASSIGN_TYPED(se.sigaction, encode_pointer( \ + (void*)(uintptr_t)args->sas[i].rt_sa_handler)); \ + ASSIGN_TYPED(se.flags, args->sas[i].rt_sa_flags); \ + ASSIGN_TYPED(se.restorer, encode_pointer( \ + (void*)(uintptr_t)args->sas[i].rt_sa_restorer));\ + BUILD_BUG_ON(sizeof(se.mask) != sizeof(args->sas[0].rt_sa_mask.sig)); \ + memcpy(&se.mask, args->sas[i].rt_sa_mask.sig, sizeof(se.mask)); \ +} while(0) int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_imgset) { - struct parasite_dump_sa_args *args; + struct parasite_dump_sa_args *args = NULL; + struct parasite_dump_sa_args_compat *args_c = NULL; int ret, sig; struct cr_img *img; SaEntry se = SA_ENTRY__INIT; - args = parasite_args(ctl, struct parasite_dump_sa_args); + if (seized_native(ctl)) + args = parasite_args(ctl, struct parasite_dump_sa_args); + else + args_c = parasite_args(ctl, struct parasite_dump_sa_args_compat); ret = parasite_execute_daemon(PARASITE_CMD_DUMP_SIGACTS, ctl); if (ret < 0) @@ -679,11 +717,10 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_ if (sig == SIGSTOP || sig == SIGKILL) continue; - ASSIGN_TYPED(se.sigaction, encode_pointer(args->sas[i].rt_sa_handler)); - ASSIGN_TYPED(se.flags, args->sas[i].rt_sa_flags); - ASSIGN_TYPED(se.restorer, encode_pointer(args->sas[i].rt_sa_restorer)); - BUILD_BUG_ON(sizeof(se.mask) != sizeof(args->sas[0].rt_sa_mask.sig)); - memcpy(&se.mask, args->sas[i].rt_sa_mask.sig, sizeof(se.mask)); + if (seized_native(ctl)) + ASSIGN_SAS(se, args); + else + ASSIGN_SAS(se, args_c); if (pb_write_one(img, &se, PB_SIGACT) < 0) return -1; @@ -692,49 +729,44 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_ return 0; } -static void encode_itimer(struct itimerval *v, ItimerEntry *ie) -{ - ie->isec = v->it_interval.tv_sec; - ie->iusec = v->it_interval.tv_usec; - ie->vsec = v->it_value.tv_sec; - ie->vusec = v->it_value.tv_usec; -} +#define encode_itimer(v, ie) \ +do { \ + ie->isec = v->it_interval.tv_sec; \ + ie->iusec = v->it_interval.tv_usec; \ + ie->vsec = v->it_value.tv_sec; \ + ie->vusec = v->it_value.tv_usec; \ +} while(0) \ +#define ASSIGN_ITIMER(args) \ +do { \ + encode_itimer((&args->real), (core->tc->timers->real)); \ + encode_itimer((&args->virt), (core->tc->timers->virt)); \ + encode_itimer((&args->prof), (core->tc->timers->prof)); \ +} while(0) int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct pstree_item *item) { CoreEntry *core = item->core[0]; - struct parasite_dump_itimers_args *args; + struct parasite_dump_itimers_args *args = NULL; + struct parasite_dump_itimers_args_compat *args_c = NULL; int ret; - args = parasite_args(ctl, struct parasite_dump_itimers_args); + if (seized_native(ctl)) + args = parasite_args(ctl, struct parasite_dump_itimers_args); + else + args_c = parasite_args(ctl, struct parasite_dump_itimers_args_compat); ret = parasite_execute_daemon(PARASITE_CMD_DUMP_ITIMERS, ctl); if (ret < 0) return ret; - encode_itimer(&args->real, core->tc->timers->real); - encode_itimer(&args->virt, core->tc->timers->virt); - encode_itimer(&args->prof, core->tc->timers->prof); + if (seized_native(ctl)) + ASSIGN_ITIMER(args); + else + ASSIGN_ITIMER(args_c); return 0; } -static void encode_posix_timer(struct posix_timer *v, struct proc_posix_timer *vp, PosixTimerEntry *pte) -{ - pte->it_id = vp->spt.it_id; - pte->clock_id = vp->spt.clock_id; - pte->si_signo = vp->spt.si_signo; - pte->it_sigev_notify = vp->spt.it_sigev_notify; - pte->sival_ptr = encode_pointer(vp->spt.sival_ptr); - - pte->overrun = v->overrun; - - pte->isec = v->val.it_interval.tv_sec; - pte->insec = v->val.it_interval.tv_nsec; - pte->vsec = v->val.it_value.tv_sec; - pte->vnsec = v->val.it_value.tv_nsec; -} - static int core_alloc_posix_timers(TaskTimersEntry *tte, int n, PosixTimerEntry **pte) { @@ -754,13 +786,30 @@ static int core_alloc_posix_timers(TaskTimersEntry *tte, int n, return 0; } +#define encode_posix_timer(v, vp, pte) \ +do { \ + (pte)->it_id = (vp)->spt.it_id; \ + (pte)->clock_id = (vp)->spt.clock_id; \ + (pte)->si_signo = (vp)->spt.si_signo; \ + (pte)->it_sigev_notify = (vp)->spt.it_sigev_notify; \ + (pte)->sival_ptr = encode_pointer((vp)->spt.sival_ptr); \ + \ + (pte)->overrun = (v)->overrun; \ + \ + (pte)->isec = (v)->val.it_interval.tv_sec; \ + (pte)->insec = (v)->val.it_interval.tv_nsec; \ + (pte)->vsec = (v)->val.it_value.tv_sec; \ + (pte)->vnsec = (v)->val.it_value.tv_nsec; \ +} while(0) + int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, struct parasite_ctl *ctl, struct pstree_item *item) { CoreEntry *core = item->core[0]; TaskTimersEntry *tte = core->tc->timers; PosixTimerEntry *pte; - struct parasite_dump_posix_timers_args * args; + struct parasite_dump_posix_timers_args *args = NULL; + struct parasite_dump_posix_timers_args_compat *args_c = NULL; struct proc_posix_timer *temp; int i; int ret = 0; @@ -768,12 +817,22 @@ int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, if (core_alloc_posix_timers(tte, proc_args->timer_n, &pte)) return -1; - args = parasite_args_s(ctl, posix_timers_dump_size(proc_args->timer_n)); - args->timer_n = proc_args->timer_n; + if(seized_native(ctl)) { + args = parasite_args_s(ctl, + posix_timers_dump_size(proc_args->timer_n)); + args->timer_n = proc_args->timer_n; + } else { + args_c = parasite_args_s(ctl, + posix_timers_compat_dump_size(proc_args->timer_n)); + args_c->timer_n = proc_args->timer_n; + } i = 0; list_for_each_entry(temp, &proc_args->timers, list) { - args->timer[i].it_id = temp->spt.it_id; + if(seized_native(ctl)) + args->timer[i].it_id = temp->spt.it_id; + else + args_c->timer[i].it_id = temp->spt.it_id; i++; } @@ -1236,7 +1295,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) pid_t pid = ctl->rpid; unsigned long sret = -ENOSYS; int ret, fd, lfd; - bool __maybe_unused compat_task = !user_regs_native(&ctl->orig.regs); + bool __maybe_unused compat_task = !seized_native(ctl); if (fault_injected(FI_NO_MEMFD)) return 1; @@ -1413,7 +1472,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, * without using ptrace at all. */ - if (user_regs_native(&ctl->orig.regs)) + if (seized_native(ctl)) parasite_size = pie_size(parasite_native); #ifdef CONFIG_X86_64 /* compat blob isn't defined for other archs */ else @@ -1437,7 +1496,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map); - if (user_regs_native(&ctl->orig.regs)) + if (seized_native(ctl)) init_parasite_ctl(ctl, native); #ifdef CONFIG_X86_64 /* compat blob isn't defined for other archs */ else From aefed47f8f27db7a7a4089e60753f9708e818ee8 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:06 +0300 Subject: [PATCH 0056/4375] page-pipe: add compatible iovec struct iovec may have different size for dumpee. But that reason, pages dump will fail (with added debug to pie): (00.011440) page-pipe: Page pipe: (00.011441) page-pipe: * 1 pipes 8/523 iovs: (00.011442) page-pipe: buf 16 pages, 8 iovs: (00.011444) page-pipe: 0x8048000 3 (00.011446) page-pipe: 0xf7512000 1 (00.011447) page-pipe: 0xf76ca000 4 (00.011449) page-pipe: 0xf76cf000 1 (00.011450) page-pipe: 0xf76dc000 2 (00.011452) page-pipe: 0xf76e1000 1 (00.011454) page-pipe: 0xf7702000 2 (00.011455) page-pipe: 0xffdad000 2 (00.011470) page-pipe: * 0 holes: (00.011471) PPB: 16 pages 8 segs 16 pipe 0 off (00.011476) Sent msg to daemon 8 0 0 pie: __fetched msg: 8 0 0 (00.011479) Wait for ack 8 on daemon socket pie: sys_vmsplice for 16 pages 8 segs 0 off pie: buf 16 pages, 8 iovs: pie: 0x8048000 0 pie: 0x3000 0 pie: 0xf7512000 0 pie: 0x1000 0 pie: 0xf76ca000 0 pie: 0x4000 0 pie: 0xf76cf000 0 pie: 0x1000 0 pie: Error (pie/parasite.c:93): Can't splice pages to pipe (0/16) pie: __sent ack msg: 8 8 -1 Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/parasite-syscall.h | 1 + criu/mem.c | 2 ++ criu/page-pipe.c | 51 +++++++++++++++++++++++++++++---- criu/parasite-syscall.c | 2 +- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index b28fe0473..95296c558 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -119,6 +119,7 @@ extern int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, extern int __parasite_execute_syscall(struct parasite_ctl *ctl, user_regs_struct_t *regs, const char *code_syscall); extern bool arch_can_dump_task(struct parasite_ctl *ctl); +extern bool seized_native(struct parasite_ctl *ctl); /* * The PTRACE_SYSCALL will trap task twice -- on diff --git a/criu/mem.c b/criu/mem.c index 48e522744..629e61f53 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -304,6 +304,8 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, * use, i.e. on non-lazy non-predump. */ cpp_flags |= PP_CHUNK_MODE; + if (!seized_native(ctl)) + cpp_flags |= PP_COMPAT; pp = create_page_pipe(vma_area_list->priv_size, pargs_iovs(args), cpp_flags); if (!pp) diff --git a/criu/page-pipe.c b/criu/page-pipe.c index cf1e97f2b..09ff268dc 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -81,6 +81,18 @@ static int ppb_resize_pipe(struct page_pipe_buf *ppb, unsigned long new_size) return 0; } +/* XXX: move to arch-depended file, when non-x86 add support for compat mode */ +struct iovec_compat { + u32 iov_base; + u32 iov_len; +}; + +static inline void iov_init_compat(struct iovec_compat *iov, unsigned long addr) +{ + iov->iov_base = (u32)addr; + iov->iov_len = PAGE_SIZE; +} + static int page_pipe_grow(struct page_pipe *pp) { struct page_pipe_buf *ppb; @@ -208,7 +220,13 @@ static inline int try_add_page_to(struct page_pipe *pp, struct page_pipe_buf *pp pr_debug("Add iov to page pipe (%u iovs, %u/%u total)\n", ppb->nr_segs, pp->free_iov, pp->nr_iovs); - iov_init(&ppb->iov[ppb->nr_segs++], addr); + if (pp->flags & PP_COMPAT) { + struct iovec_compat *iovs = (void *)ppb->iov; + + iov_init_compat(&iovs[ppb->nr_segs++], addr); + } else { + iov_init(&ppb->iov[ppb->nr_segs++], addr); + } pp->free_iov++; BUG_ON(pp->free_iov > pp->nr_iovs); out: @@ -256,7 +274,13 @@ int page_pipe_add_hole(struct page_pipe *pp, unsigned long addr) iov_grow_page(&pp->holes[pp->free_hole - 1], addr)) goto out; - iov_init(&pp->holes[pp->free_hole++], addr); + if (pp->flags & PP_COMPAT) { + struct iovec_compat *iovs = (void *)pp->holes; + + iov_init_compat(&iovs[pp->free_hole++], addr); + } else { + iov_init(&pp->holes[pp->free_hole++], addr); + } out: return 0; } @@ -266,6 +290,7 @@ void debug_show_page_pipe(struct page_pipe *pp) struct page_pipe_buf *ppb; int i; struct iovec *iov; + struct iovec_compat *iov_c; if (pr_quelled(LOG_DEBUG)) return; @@ -277,14 +302,28 @@ void debug_show_page_pipe(struct page_pipe *pp) pr_debug("\tbuf %u pages, %u iovs:\n", ppb->pages_in, ppb->nr_segs); for (i = 0; i < ppb->nr_segs; i++) { - iov = &ppb->iov[i]; - pr_debug("\t\t%p %lu\n", iov->iov_base, iov->iov_len / PAGE_SIZE); + if (pp->flags & PP_COMPAT) { + iov_c = (void *)ppb->iov; + pr_debug("\t\t%x %lu\n", iov_c[i].iov_base, + iov_c[i].iov_len / PAGE_SIZE); + } else { + iov = &ppb->iov[i]; + pr_debug("\t\t%p %lu\n", iov->iov_base, + iov->iov_len / PAGE_SIZE); + } } } pr_debug("* %u holes:\n", pp->free_hole); for (i = 0; i < pp->free_hole; i++) { - iov = &pp->holes[i]; - pr_debug("\t%p %lu\n", iov->iov_base, iov->iov_len / PAGE_SIZE); + if (pp->flags & PP_COMPAT) { + iov_c = (void *)pp->holes; + pr_debug("\t%x %lu\n", iov_c[i].iov_base, + iov_c[i].iov_len / PAGE_SIZE); + } else { + iov = &pp->holes[i]; + pr_debug("\t%p %lu\n", iov->iov_base, + iov->iov_len / PAGE_SIZE); + } } } diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 3a36aee48..5483aae8c 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -120,7 +120,7 @@ static int restore_thread_ctx(int pid, struct thread_ctx *ctx) return ret; } -static inline bool seized_native(struct parasite_ctl *ctl) +bool seized_native(struct parasite_ctl *ctl) { return user_regs_native(&ctl->orig.regs); } From 3c09c15daf0d1176dba9649e9980a73016b0e78d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:07 +0300 Subject: [PATCH 0057/4375] page-xfer: dump compatible iovec Change page_xfer_dump_pages the way it could handle compatible iovs. Separated hole dumping in page_xfer_dump_hole and introduced iterator function get_iov which will return native iovec, converting compatible iovec if needed. Fixes: (00.009060) Fetched ack: 7 7 0 (00.009061) Transfering pages: (00.009062) buf 16/16 (00.009063) p 0x100008048000 [32841] (00.009101) Error (page-xfer.c:504): Only 65536 of 17592320561152 bytes have been spliced (00.009253) page-pipe: Killing page pipe (00.009263) ---------------------------------------- Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/page-pipe.h | 6 ++++++ criu/page-pipe.c | 6 ------ criu/page-xfer.c | 19 +++++++++++++++---- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h index c7642d9b8..38c38968f 100644 --- a/criu/include/page-pipe.h +++ b/criu/include/page-pipe.h @@ -119,6 +119,12 @@ struct page_pipe { #define PP_COMPAT 0x2 /* Use compatible iovs (struct compat_iovec) */ #define PP_OWN_IOVS 0x4 /* create_page_pipe allocated IOVs memory */ +/* XXX: move to arch-depended file, when non-x86 add support for compat mode */ +struct iovec_compat { + u32 iov_base; + u32 iov_len; +}; + struct page_pipe *create_page_pipe(unsigned int nr_segs, struct iovec *iovs, unsigned flags); extern void destroy_page_pipe(struct page_pipe *p); extern int page_pipe_add_page(struct page_pipe *p, unsigned long addr); diff --git a/criu/page-pipe.c b/criu/page-pipe.c index 09ff268dc..a015d02e5 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -81,12 +81,6 @@ static int ppb_resize_pipe(struct page_pipe_buf *ppb, unsigned long new_size) return 0; } -/* XXX: move to arch-depended file, when non-x86 add support for compat mode */ -struct iovec_compat { - u32 iov_base; - u32 iov_len; -}; - static inline void iov_init_compat(struct iovec_compat *iov, unsigned long addr) { iov->iov_base = (u32)addr; diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 8fa8e7214..8ec0998a4 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -341,9 +341,19 @@ static int page_xfer_dump_hole(struct page_xfer *xfer, return 0; } -static struct iovec get_iov(struct iovec *iovs, unsigned int n) +static struct iovec get_iov(struct iovec *iovs, unsigned int n, bool compat) { - return iovs[n]; + if (likely(!compat)) { + return iovs[n]; + } else { + struct iovec ret; + struct iovec_compat *tmp = (struct iovec_compat*)(void *)iovs; + + tmp += n; + ret.iov_base = (void *)(uintptr_t)tmp->iov_base; + ret.iov_len = tmp->iov_len; + return ret; + } } static int dump_holes(struct page_xfer *xfer, struct page_pipe *pp, @@ -352,7 +362,8 @@ static int dump_holes(struct page_xfer *xfer, struct page_pipe *pp, int ret; for (; *cur_hole < pp->free_hole ; (*cur_hole)++) { - struct iovec hole = get_iov(pp->holes, *cur_hole); + struct iovec hole = get_iov(pp->holes, *cur_hole, + pp->flags & PP_COMPAT); if (limit && hole.iov_base >= limit) break; @@ -380,7 +391,7 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, pr_debug("\tbuf %d/%d\n", ppb->pages_in, ppb->nr_segs); for (i = 0; i < ppb->nr_segs; i++) { - struct iovec iov = get_iov(ppb->iov, i); + struct iovec iov = get_iov(ppb->iov, i, pp->flags & PP_COMPAT); ret = dump_holes(xfer, pp, &cur_hole, iov.iov_base, off); if (ret) From 5877e70e7e4b4b05be89c34dc5f53e8ff5009ef0 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:08 +0300 Subject: [PATCH 0058/4375] x86: change k_rtsigset_t sig type As it has equall size for compat/native tasks. Fixes for compatible tasks: pie: Daemon waits for command (00.009247) Fetched ack: 7 7 0 pie: __fetched msg: 9 0 0 pie: Error (pie/parasite.c:106): sys_sigaction failed (-22) pie: __sent ack msg: 9 9 -22 pie: Error (pie/parasite.c:725): Close the control socket for writing Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/include/asm/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/arch/x86/include/asm/types.h b/criu/arch/x86/include/asm/types.h index 743dc69fd..623dd84c6 100644 --- a/criu/arch/x86/include/asm/types.h +++ b/criu/arch/x86/include/asm/types.h @@ -38,7 +38,7 @@ typedef rt_restorefn_t *rt_sigrestore_t; #define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) typedef struct { - unsigned long sig[_KNSIG_WORDS]; + u64 sig[_KNSIG_WORDS]; } k_rtsigset_t; #define SA_RESTORER 0x04000000 From c7c63a3e8b1f6530e641a26df92949c9a325523e Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:10 +0300 Subject: [PATCH 0059/4375] vdso: try_fill_symtable always for compat tasks Their vDSO's pfn differ from native tasks. TODO: compute on dump compatible vDSO's pfn. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/vdso.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/criu/vdso.c b/criu/vdso.c index f8fbe14dd..1d70f8a61 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -100,7 +100,14 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, */ args->start = vma->e->start; args->len = vma_area_len(vma); - args->try_fill_symtable = (fd < 0) ? true : false; + /* + * XXX: For compatible tasks, vDSO pfn is different from + * our native vdso_pfn. Check vma explicitly. + */ + if (!seized_native(ctl)) + args->try_fill_symtable = true; + else + args->try_fill_symtable = (fd < 0) ? true : false; args->is_vdso = false; if (parasite_execute_daemon(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) { From 64d39a20df30518a5fd4040606f7db3ee31ae172 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:11 +0300 Subject: [PATCH 0060/4375] restorer: unmapping native blob in compat task We need to do it in pure ia32 asm. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/include/asm/types.h | 3 ++- criu/arch/arm/include/asm/types.h | 2 ++ criu/arch/ppc64/include/asm/types.h | 3 ++- criu/cr-restore.c | 8 +++++++- criu/pie/restorer.c | 25 +++++++++++++++++++++++-- 5 files changed, 36 insertions(+), 5 deletions(-) diff --git a/criu/arch/aarch64/include/asm/types.h b/criu/arch/aarch64/include/asm/types.h index 1903130b9..976fca200 100644 --- a/criu/arch/aarch64/include/asm/types.h +++ b/criu/arch/aarch64/include/asm/types.h @@ -10,7 +10,6 @@ #include "bitops.h" #include "asm/int.h" - typedef void rt_signalfn_t(int, siginfo_t *, void *); typedef rt_signalfn_t *rt_sighandler_t; @@ -35,6 +34,8 @@ typedef struct { k_rtsigset_t rt_sa_mask; } rt_sigaction_t; +#define core_is_compat(core) false + typedef UserAarch64RegsEntry UserRegsEntry; #define CORE_ENTRY__MARCH CORE_ENTRY__MARCH__AARCH64 diff --git a/criu/arch/arm/include/asm/types.h b/criu/arch/arm/include/asm/types.h index c7a2631a1..a4a752dad 100644 --- a/criu/arch/arm/include/asm/types.h +++ b/criu/arch/arm/include/asm/types.h @@ -33,6 +33,8 @@ typedef struct { k_rtsigset_t rt_sa_mask; } rt_sigaction_t; +#define core_is_compat(core) false + typedef UserArmRegsEntry UserRegsEntry; #define CORE_ENTRY__MARCH CORE_ENTRY__MARCH__ARM diff --git a/criu/arch/ppc64/include/asm/types.h b/criu/arch/ppc64/include/asm/types.h index d6ca9e5d3..73ab4d270 100644 --- a/criu/arch/ppc64/include/asm/types.h +++ b/criu/arch/ppc64/include/asm/types.h @@ -37,11 +37,12 @@ typedef struct { k_rtsigset_t rt_sa_mask; /* mask last for extensibility */ } rt_sigaction_t; +#define core_is_compat(core) false + typedef UserPpc64RegsEntry UserRegsEntry; #define CORE_ENTRY__MARCH CORE_ENTRY__MARCH__PPC64 - #define CORE_THREAD_ARCH_INFO(core) core->ti_ppc64 static inline void *decode_pointer(uint64_t v) { return (void*)v; } diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 706907e16..74dbf8d84 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -105,6 +105,7 @@ #ifndef arch_export_unmap #define arch_export_unmap __export_unmap +#define arch_export_unmap_compat __export_unmap_compat #endif struct pstree_item *current; @@ -2867,7 +2868,12 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns */ task_args->clone_restore_fn = restorer_sym(mem, arch_export_restore_thread); restore_task_exec_start = restorer_sym(mem, arch_export_restore_task); - rsti(current)->munmap_restorer = restorer_sym(mem, arch_export_unmap); + if (core_is_compat(core)) + rsti(current)->munmap_restorer = + restorer_sym(mem, arch_export_unmap_compat); + else + rsti(current)->munmap_restorer = + restorer_sym(mem, arch_export_unmap); task_args->bootstrap_start = mem; mem += restorer_len; diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 7c4da5761..5026146fc 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -885,8 +885,6 @@ static void restore_posix_timers(struct task_restore_args *args) sys_timer_settime((kernel_timer_t)rt->spt.it_id, 0, &rt->val, NULL); } } -static void *bootstrap_start; -static unsigned int bootstrap_len; /* * sys_munmap must not return here. The control process must @@ -898,11 +896,34 @@ static unsigned long vdso_rt_size; #define vdso_rt_size (0) #endif +static void *bootstrap_start; +static unsigned int bootstrap_len; + void __export_unmap(void) { sys_munmap(bootstrap_start, bootstrap_len - vdso_rt_size); } +#ifdef CONFIG_X86_64 +asm ( + " .pushsection .text\n" + " .global __export_unmap_compat\n" + "__export_unmap_compat:\n" + " .code32\n" + " mov bootstrap_start, %ebx\n" + " mov bootstrap_len, %ecx\n" + " movl $"__stringify(__NR32_munmap)", %eax\n" + " int $0x80\n" + " .code64\n" + " .popsection\n" +); +extern char __export_unmap_compat; +#else +void __export_unmap_compat(void) +{ +} +#endif + /* * This function unmaps all VMAs, which don't belong to * the restored process or the restorer. From 2457ce6f6d31211975e93bc1181717b93e4ff355 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:12 +0300 Subject: [PATCH 0061/4375] restore: add arch_prctl mapping compatible vDSO Map here instead of park before unmap. TODO: need to check that mapped size is smaller than x86_64 vDSO. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 1 + criu/include/parasite-vdso.h | 2 ++ criu/include/restorer.h | 2 ++ criu/pie/parasite-vdso.c | 20 ++++++++++++++++++++ criu/pie/restorer.c | 14 ++++++++++++-- 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 74dbf8d84..9ef3570c2 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2957,6 +2957,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns if (core->tc->has_seccomp_mode) task_args->seccomp_mode = core->tc->seccomp_mode; + task_args->compatible_mode = core_is_compat(core); /* * Arguments for task restoration. */ diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index 530cc01cb..d50319048 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -80,12 +80,14 @@ static inline bool is_vdso_mark(void *addr) } extern int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned long park_size); +int vdso_map_compat(unsigned long map_at); extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, size_t index, VmaEntry *vmas, size_t nr_vmas); #else /* CONFIG_VDSO */ #define vdso_do_park(sym_rt, park_at, park_size) (0) +#define vdso_map_compat(map_at) (0) #endif /* CONFIG_VDSO */ diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 1dddafe24..0fc47e283 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -174,6 +174,8 @@ struct task_restore_args { int seccomp_mode; + bool compatible_mode; + #ifdef CONFIG_VDSO unsigned long vdso_rt_size; struct vdso_symtable vdso_sym_rt; /* runtime vdso symbols */ diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index a6183fcc4..69797995d 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -68,6 +68,26 @@ int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned l return ret; } +#ifdef CONFIG_X86_64 +#ifndef ARCH_MAP_VDSO_32 +# define ARCH_MAP_VDSO_32 0x2002 +#endif +int vdso_map_compat(unsigned long map_at) +{ + int ret; + + pr_debug("Mapping compatible vDSO at %lx\n", map_at); + + ret = sys_arch_prctl(ARCH_MAP_VDSO_32, map_at); + return ret; +} +#else +int vdso_map_compat(unsigned long map_at) +{ + return 0; +} +#endif + int vdso_proxify(char *who, struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, size_t index, VmaEntry *vmas, size_t nr_vmas) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 5026146fc..48269ce25 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1087,13 +1087,23 @@ long __export_restore_task(struct task_restore_args *args) pr_info("Switched to the restorer %d\n", my_pid); - if (vdso_do_park(&args->vdso_sym_rt, args->vdso_rt_parked_at, vdso_rt_size)) - goto core_restore_end; + if (!args->compatible_mode) { + /* Compatible vDSO will be mapped, not moved */ + if (vdso_do_park(&args->vdso_sym_rt, + args->vdso_rt_parked_at, vdso_rt_size)) + goto core_restore_end; + } if (unmap_old_vmas((void *)args->premmapped_addr, args->premmapped_len, bootstrap_start, bootstrap_len, args->task_size)) goto core_restore_end; + if (args->compatible_mode) { + /* Map compatible vdso */ + if (vdso_map_compat(args->vdso_rt_parked_at)) + goto core_restore_end; + } + /* Shift private vma-s to the left */ for (i = 0; i < args->vmas_n; i++) { vma_entry = args->vmas + i; From f52ea57df3431e22cf2a31142e9c530818b9c9a4 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:13 +0300 Subject: [PATCH 0062/4375] pie/restorer: add vdso_fill_symtable_compat for 32-bit vdso While restorering compatible application on x86-64, we need to parse 32-bit vDSO. By that reason I need _three_ compiled object versions for util-vdso: - for native parasite it's util-vdso.o - for compatible parasite it's compat/util-vdso.o - for restorer it's util-vdso.o and util-vdso-elf32.o Note, that I can't link compat/util-vdso.o to restorer, as it's i386 ELF which ld can't link to x86_64 ELF file. TODO: maybe I'll need to refactor and introduce generic CONFIG_COMPAT instead of those defined(CONFIG_X86_32). Fixes: pie: 27504: vdso: Mapping compatible vDSO at 0x25000 pie: 27504: Remap 0x7f3de3efa000->0x8048000 len 0x1000 ... pie: 27504: vdso: Parsing at 0xf7776000 0xf7778000 pie: 27504: Error (pie/util-vdso.c:87): vdso: Elf header magic mismatch pie: 27504: Error (pie/restorer.c:1540): Restorer fail 27504 (00.029188) Error (cr-restore.c:988): 27504 exited, status=1 (00.033072) Error (cr-restore.c:1870): Restoring FAILED. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/parasite-vdso.h | 2 +- criu/include/util-vdso.h | 4 ++++ criu/pie/Makefile.library | 3 +++ criu/pie/parasite-vdso.c | 22 +++++++++++++++++++--- criu/pie/restorer.c | 3 ++- criu/pie/util-vdso-elf32.c | 1 + 6 files changed, 30 insertions(+), 5 deletions(-) create mode 120000 criu/pie/util-vdso-elf32.c diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index d50319048..4f25f57d3 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -83,7 +83,7 @@ extern int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, uns int vdso_map_compat(unsigned long map_at); extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, size_t index, - VmaEntry *vmas, size_t nr_vmas); + VmaEntry *vmas, size_t nr_vmas, bool compat_vdso); #else /* CONFIG_VDSO */ #define vdso_do_park(sym_rt, park_at, park_size) (0) diff --git a/criu/include/util-vdso.h b/criu/include/util-vdso.h index 43f7549c8..63bc70d79 100644 --- a/criu/include/util-vdso.h +++ b/criu/include/util-vdso.h @@ -88,6 +88,10 @@ static inline unsigned long vvar_vma_size(struct vdso_symtable *t) return t->vvar_end - t->vvar_start; } +#if defined(CONFIG_X86_32) +# define vdso_fill_symtable vdso_fill_symtable_compat +#endif + extern int vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t); #endif /* __CR_UTIL_VDSO_H__ */ diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index e2ad1b8fb..136799ab8 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -9,6 +9,9 @@ ifeq ($(ARCH),x86) target += compat CFLAGS_native += -DCONFIG_X86_64 CFLAGS_compat += -fno-pic -m32 -DCONFIG_X86_32 + + native-lib-y += util-vdso-elf32.o + CFLAGS_util-vdso-elf32.o += -DCONFIG_X86_32 endif OBJS += log-simple.o util-fd.o util.o string.o diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 69797995d..a45098a19 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -81,16 +81,32 @@ int vdso_map_compat(unsigned long map_at) ret = sys_arch_prctl(ARCH_MAP_VDSO_32, map_at); return ret; } + +extern int vdso_fill_symtable_compat(uintptr_t mem, size_t size, + struct vdso_symtable *t); +int __vdso_fill_symtable(uintptr_t mem, size_t size, + struct vdso_symtable *t, bool compat_vdso) +{ + if (compat_vdso) + return vdso_fill_symtable_compat(mem, size, t); + else + return vdso_fill_symtable(mem, size, t); +} #else int vdso_map_compat(unsigned long map_at) { return 0; } +int __vdso_fill_symtable(uintptr_t mem, size_t size, + struct vdso_symtable *t, bool __always_unused compat_vdso) +{ + return vdso_fill_symtable(mem, size, t); +} #endif int vdso_proxify(char *who, struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, size_t index, - VmaEntry *vmas, size_t nr_vmas) + VmaEntry *vmas, size_t nr_vmas, bool compat_vdso) { VmaEntry *vma_vdso = NULL, *vma_vvar = NULL; struct vdso_symtable s = VDSO_SYMTABLE_INIT; @@ -125,8 +141,8 @@ int vdso_proxify(char *who, struct vdso_symtable *sym_rt, /* * Find symbols in vDSO zone read from image. */ - if (vdso_fill_symtable((uintptr_t)vma_vdso->start, - vma_entry_len(vma_vdso), &s)) + if (__vdso_fill_symtable((uintptr_t)vma_vdso->start, + vma_entry_len(vma_vdso), &s, compat_vdso)) return -1; /* diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 48269ce25..1ac49cab2 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1169,7 +1169,8 @@ long __export_restore_task(struct task_restore_args *args) vma_entry_is(&args->vmas[i], VMA_AREA_VVAR)) { if (vdso_proxify("dumpee", &args->vdso_sym_rt, args->vdso_rt_parked_at, - i, args->vmas, args->vmas_n)) + i, args->vmas, args->vmas_n, + args->compatible_mode)) goto core_restore_end; break; } diff --git a/criu/pie/util-vdso-elf32.c b/criu/pie/util-vdso-elf32.c new file mode 120000 index 000000000..97928c055 --- /dev/null +++ b/criu/pie/util-vdso-elf32.c @@ -0,0 +1 @@ +util-vdso.c \ No newline at end of file From 928fe9be0e3fdaef96ba0ef8653daf565c93a840 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:14 +0300 Subject: [PATCH 0063/4375] restorer: refill symtable for rt-vdso Otherwise, we still have parsed x86_64 vdso symtable. After this: pie: 17917: vdso: Mapping compatible vDSO at 0x25000 pie: 17917: vdso: Parsing at 0x25000 0x29000 pie: 17917: Error (pie/util-vdso-elf32.c:87): vdso: Elf header magic m> pie: 17917: ismatch pie: 17917: vdso: Parsing at 0x26000 0x29000 pie: 17917: Error (pie/util-vdso-elf32.c:87): vdso: Elf header magic m> pie: 17917: ismatch pie: 17917: vdso: Parsing at 0x27000 0x29000 pie: 17917: vdso: PT_LOAD p_vaddr: 0x0 pie: 17917: vdso: DT_HASH: 0xb4 pie: 17917: vdso: DT_STRTAB: 0x1c0 pie: 17917: vdso: DT_SYMTAB: 0x130 pie: 17917: vdso: DT_STRSZ: 0x95 pie: 17917: vdso: DT_SYMENT: 0x10 pie: 17917: vdso: nbucket 0x3 nchain 0x9 bucket 0x270bc chain 0x270c8 Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/parasite-vdso.h | 5 +++-- criu/pie/parasite-vdso.c | 29 +++++++++++++++++++++++++---- criu/pie/restorer.c | 3 ++- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index 4f25f57d3..025396319 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -80,14 +80,15 @@ static inline bool is_vdso_mark(void *addr) } extern int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned long park_size); -int vdso_map_compat(unsigned long map_at); +extern int vdso_map_compat(unsigned long map_at, unsigned long park_size, + struct vdso_symtable *sym_rt); extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, size_t index, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso); #else /* CONFIG_VDSO */ #define vdso_do_park(sym_rt, park_at, park_size) (0) -#define vdso_map_compat(map_at) (0) +#define vdso_map_compat(map_at, park_size, sym_rt) (0) #endif /* CONFIG_VDSO */ diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index a45098a19..512186c7a 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -72,18 +72,37 @@ int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned l #ifndef ARCH_MAP_VDSO_32 # define ARCH_MAP_VDSO_32 0x2002 #endif -int vdso_map_compat(unsigned long map_at) +extern int vdso_fill_symtable_compat(uintptr_t mem, size_t size, + struct vdso_symtable *t); + +int vdso_map_compat(unsigned long map_at, unsigned long park_size, + struct vdso_symtable *sym_rt) { + unsigned long search_vdso; int ret; pr_debug("Mapping compatible vDSO at %lx\n", map_at); ret = sys_arch_prctl(ARCH_MAP_VDSO_32, map_at); + if (ret) + return ret; + + /* + * We could map VVAR firstly, or VDSO. + * Try to find VDSO pages in this couple of parking pages. + */ + for (search_vdso = map_at; search_vdso < map_at + park_size; + search_vdso += PAGE_SIZE) + { + ret = vdso_fill_symtable_compat(search_vdso, + map_at + park_size - search_vdso, sym_rt); + if (!ret) + return 0; + } + pr_err("Failed to parse a arch_prctl-mapped vDSO %d\n", ret); return ret; } -extern int vdso_fill_symtable_compat(uintptr_t mem, size_t size, - struct vdso_symtable *t); int __vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t, bool compat_vdso) { @@ -93,7 +112,9 @@ int __vdso_fill_symtable(uintptr_t mem, size_t size, return vdso_fill_symtable(mem, size, t); } #else -int vdso_map_compat(unsigned long map_at) +int vdso_map_compat(unsigned long __always_unused map_at, + unsigned long __always_unused park_size, + struct vdso_symtable __always_unused *sym_rt) { return 0; } diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 1ac49cab2..ebac5b9a4 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1100,7 +1100,8 @@ long __export_restore_task(struct task_restore_args *args) if (args->compatible_mode) { /* Map compatible vdso */ - if (vdso_map_compat(args->vdso_rt_parked_at)) + if (vdso_map_compat(args->vdso_rt_parked_at, + vdso_rt_size, &args->vdso_sym_rt)) goto core_restore_end; } From 75281003bde0b925559bf5be8de9c2b231a80245 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:16 +0300 Subject: [PATCH 0064/4375] x86: add helpers to call 32-bit code from 64-bit I need it to call sigaction from 32-bit code as kernel will set sigframe ABI according to sigaction call ABI. Also I will call {get,set}_thread_area to restore TLS entries. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/call32.S | 68 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 criu/arch/x86/call32.S diff --git a/criu/arch/x86/call32.S b/criu/arch/x86/call32.S new file mode 100644 index 000000000..f2e118f26 --- /dev/null +++ b/criu/arch/x86/call32.S @@ -0,0 +1,68 @@ +/* + * call32.S - assembly helpers for mixed-bitness code + * From kernel selftests originally: tools/testing/selftests/x86/thunks.S + * Copyright (c) 2015 Andrew Lutomirski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * These are little helpers that make it easier to switch bitness on + * the fly. + */ + + .text + + .global call32_from_64 + .type call32_from_64, @function +call32_from_64: + // rdi: stack to use + // esi: function to call + + // Save registers + pushq %rbx + pushq %rbp + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + pushfq + + // Switch stacks + mov %rsp,(%rdi) + mov %rdi,%rsp + + // Switch to compatibility mode + pushq $0x23 /* USER32_CS */ + pushq $1f + lretq + +1: + .code32 + // Call the function + call *%esi + // Switch back to long mode + jmp $0x33,$1f + .code64 + +1: + // Restore the stack + mov (%rsp),%rsp + + // Restore registers + popfq + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx + + ret + +.size call32_from_64, .-call32_from_64 From b1cc99844f6015b71cc116da719394d84a47fbcd Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:17 +0300 Subject: [PATCH 0065/4375] x86/call32: reserve space for saving 64-bit sp on 32-bit stack I prefer this to be done in callee, than in caller for simplicity. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/call32.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/arch/x86/call32.S b/criu/arch/x86/call32.S index f2e118f26..bc724d6c5 100644 --- a/criu/arch/x86/call32.S +++ b/criu/arch/x86/call32.S @@ -34,6 +34,7 @@ call32_from_64: pushfq // Switch stacks + sub $8, %rdi mov %rsp,(%rdi) mov %rdi,%rsp @@ -53,6 +54,7 @@ call32_from_64: 1: // Restore the stack mov (%rsp),%rsp + add $8, %rdi // Restore registers popfq From 2bcfa2c1fcaf38f3e39ffd62d1e1072061a111d1 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:18 +0300 Subject: [PATCH 0066/4375] x86: dump TLS entries from GDT Dump TLS with the help of SYS_get_thread_area. Primary for 32-bit applications, but this also may be used by mixed 64/32 bit code. I do not enable dumping for 64 bit unless we'll meet such code, but include 3 user_desc entries of TLS as not present in 64-bit images. That's arguable and I may include user_descs only for compat tasks. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 17 +++++++- criu/arch/x86/include/asm/dump.h | 25 +++++++++++- criu/arch/x86/include/asm/infect-types.h | 14 ++++++- criu/arch/x86/include/asm/parasite.h | 51 +++++++++++++++++++++++- criu/arch/x86/include/asm/restorer.h | 5 ++- images/core-x86.proto | 15 +++++++ 6 files changed, 122 insertions(+), 5 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 8c866fbd6..18eb499e6 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -389,6 +389,18 @@ int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs) return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov); } +static void alloc_tls(ThreadInfoX86 *ti, void **mempool) +{ + int i; + + ti->tls = xptr_pull_s(mempool, GDT_ENTRY_TLS_NUM*sizeof(UserDescT*)); + ti->n_tls = GDT_ENTRY_TLS_NUM; + for (i = 0; i < GDT_ENTRY_TLS_NUM; i++) { + ti->tls[i] = xptr_pull(mempool, UserDescT); + user_desc_t__init(ti->tls[i]); + } +} + int arch_alloc_thread_info(CoreEntry *core) { size_t sz; @@ -399,7 +411,9 @@ int arch_alloc_thread_info(CoreEntry *core) with_fpu = cpu_has_feature(X86_FEATURE_FPU); - sz = sizeof(ThreadInfoX86) + sizeof(UserX86RegsEntry); + sz = sizeof(ThreadInfoX86) + sizeof(UserX86RegsEntry) + + GDT_ENTRY_TLS_NUM*sizeof(UserDescT) + + GDT_ENTRY_TLS_NUM*sizeof(UserDescT*); if (with_fpu) { sz += sizeof(UserX86FpregsEntry); with_xsave = cpu_has_feature(X86_FEATURE_OSXSAVE); @@ -415,6 +429,7 @@ int arch_alloc_thread_info(CoreEntry *core) thread_info_x86__init(ti); ti->gpregs = xptr_pull(&m, UserX86RegsEntry); user_x86_regs_entry__init(ti->gpregs); + alloc_tls(ti, &m); if (with_fpu) { UserX86FpregsEntry *fpregs; diff --git a/criu/arch/x86/include/asm/dump.h b/criu/arch/x86/include/asm/dump.h index 02ec20042..9c3555236 100644 --- a/criu/arch/x86/include/asm/dump.h +++ b/criu/arch/x86/include/asm/dump.h @@ -9,6 +9,29 @@ extern void arch_free_thread_info(CoreEntry *core); extern int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs); extern int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs); -#define core_put_tls(core, tls) +static inline void core_put_tls(CoreEntry *core, tls_t tls) +{ + ThreadInfoX86 *ti = core->thread_info; + int i; + + for (i = 0; i < GDT_ENTRY_TLS_NUM; i++) + { + user_desc_t *from = &tls.desc[i]; + UserDescT *to = ti->tls[i]; + +#define COPY_TLS(field) to->field = from->field + COPY_TLS(entry_number); + COPY_TLS(base_addr); + COPY_TLS(limit); + COPY_TLS(seg_32bit); + to->contents_h = from->contents & 0x2; + to->contents_l = from->contents & 0x1; + COPY_TLS(read_exec_only); + COPY_TLS(limit_in_pages); + COPY_TLS(seg_not_present); + COPY_TLS(useable); +#undef COPY_TLS + } +} #endif diff --git a/criu/arch/x86/include/asm/infect-types.h b/criu/arch/x86/include/asm/infect-types.h index 08344f747..65fc3d997 100644 --- a/criu/arch/x86/include/asm/infect-types.h +++ b/criu/arch/x86/include/asm/infect-types.h @@ -136,7 +136,19 @@ typedef struct xsave_struct user_fpregs_struct_t; static inline unsigned long task_size(void) { return TASK_SIZE; } typedef uint64_t auxv_t; -typedef uint32_t tls_t; + +/* + * Linux preserves three TLS segments in GDT. + * Offsets in GDT differ between 32-bit and 64-bit machines. + * For 64-bit x86 those GDT offsets are the same + * for native and compat tasks. + */ +#define GDT_ENTRY_TLS_MIN 12 +#define GDT_ENTRY_TLS_MAX 14 +#define GDT_ENTRY_TLS_NUM 3 +typedef struct { + user_desc_t desc[GDT_ENTRY_TLS_NUM]; +} tls_t; #define REG_RES(regs) get_user_reg(®s, ax) #define REG_IP(regs) get_user_reg(®s, ip) diff --git a/criu/arch/x86/include/asm/parasite.h b/criu/arch/x86/include/asm/parasite.h index 669ae63e2..d238327db 100644 --- a/criu/arch/x86/include/asm/parasite.h +++ b/criu/arch/x86/include/asm/parasite.h @@ -5,6 +5,55 @@ # define __parasite_entry __attribute__((regparm(3))) #endif -static inline void arch_get_tls(tls_t *ptls) { (void)ptls; } +#ifdef CONFIG_X86_32 +static void arch_get_user_desc(user_desc_t *desc) +{ + if (sys_get_thread_area(desc)) + pr_err("Failed to dump TLS descriptor #%d\n", + desc->entry_number); +} +#else /* !X86_32 */ +static void arch_get_user_desc(user_desc_t *desc) +{ + /* + * For 64-bit applications, TLS (fs_base for Glibc) is + * in MSR, which are dumped with the help of arch_prctl(). + * + * But SET_FS_BASE will update GDT if base pointer fits in 4 bytes. + * Otherwise it will set only MSR, which allows for mixed 64/32-bit + * code to use: 2 MSRs as TLS base _and_ 3 GDT entries. + * Having in sum 5 TLS pointers, 3 of which are four bytes and + * other two bigger than four bytes: + * struct thread_struct { + * struct desc_struct tls_array[3]; + * ... + * #ifdef CONFIG_X86_64 + * unsigned long fsbase; + * unsigned long gsbase; + * #endif + * ... + * }; + * + * For this mixed code we may want to call get_thread_area + * 32-bit syscall. But as additional three calls to kernel + * will slow dumping, I omit it here. + */ + desc->seg_not_present = 1; +} +#endif /* !X86_32 */ + +static void arch_get_tls(tls_t *ptls) +{ + int i; + + for (i = 0; i < GDT_ENTRY_TLS_NUM; i++) + { + user_desc_t *d = &ptls->desc[i]; + + memset(d, 0, sizeof(user_desc_t)); + d->entry_number = GDT_ENTRY_TLS_MIN + i; + arch_get_user_desc(d); + } +} #endif diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index 7fd93bd5d..3a21eff9d 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -118,7 +118,10 @@ static inline void _setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas) int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r); int restore_nonsigframe_gpregs(UserX86RegsEntry *r); -static inline void restore_tls(tls_t *ptls) { (void)ptls; } +static inline void restore_tls(tls_t *ptls) +{ + (void)ptls; +} int ptrace_set_breakpoint(pid_t pid, void *addr); int ptrace_flush_breakpoints(pid_t pid); diff --git a/images/core-x86.proto b/images/core-x86.proto index 6c084e5ca..663276c90 100644 --- a/images/core-x86.proto +++ b/images/core-x86.proto @@ -65,8 +65,23 @@ message user_x86_fpregs_entry { optional user_x86_xsave_entry xsave = 13; } +message user_desc_t { + required uint32 entry_number = 1; + /* this is for GDT, not for MSRs - 32-bit base */ + required uint32 base_addr = 2; + required uint32 limit = 3; + required bool seg_32bit = 4; + required bool contents_h = 5; + required bool contents_l = 6; + required bool read_exec_only = 7 [default = true]; + required bool limit_in_pages = 8; + required bool seg_not_present = 9 [default = true]; + required bool useable = 10; +} + message thread_info_x86 { required uint64 clear_tid_addr = 1[(criu).hex = true]; required user_x86_regs_entry gpregs = 2[(criu).hex = true]; required user_x86_fpregs_entry fpregs = 3; + repeated user_desc_t tls = 4; } From ae119678ea7dc78fdac1a8ab6225651f81fb5c8e Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:19 +0300 Subject: [PATCH 0067/4375] x86: restore TLS Put dumped TLS descriptors back to GDT. Do it only if it was present. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/include/asm/restore.h | 23 ++++++++++- criu/arch/x86/include/asm/restorer.h | 5 +-- criu/arch/x86/restorer.c | 62 ++++++++++++++++++++++++++++ criu/pie/Makefile | 1 + 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/criu/arch/x86/include/asm/restore.h b/criu/arch/x86/include/asm/restore.h index c00553dff..c5aa7cdeb 100644 --- a/criu/arch/x86/include/asm/restore.h +++ b/criu/arch/x86/include/asm/restore.h @@ -28,7 +28,28 @@ ; #endif /* CONFIG_X86_64 */ -#define core_get_tls(pcore, ptls) +static inline void core_get_tls(CoreEntry *pcore, tls_t *ptls) +{ + ThreadInfoX86 *ti = pcore->thread_info; + int i; + + for (i = 0; i < GDT_ENTRY_TLS_NUM; i++) { + user_desc_t *to = &ptls->desc[i]; + UserDescT *from = ti->tls[i]; + +#define COPY_TLS(field) to->field = from->field + COPY_TLS(entry_number); + COPY_TLS(base_addr); + COPY_TLS(limit); + COPY_TLS(seg_32bit); + to->contents = ((u32)from->contents_h << 1) | from->contents_l; + COPY_TLS(read_exec_only); + COPY_TLS(limit_in_pages); + COPY_TLS(seg_not_present); + COPY_TLS(useable); +#undef COPY_TLS + } +} int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core); diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index 3a21eff9d..4c99b6eaf 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -118,10 +118,7 @@ static inline void _setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas) int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r); int restore_nonsigframe_gpregs(UserX86RegsEntry *r); -static inline void restore_tls(tls_t *ptls) -{ - (void)ptls; -} +void restore_tls(tls_t *ptls); int ptrace_set_breakpoint(pid_t pid, void *addr); int ptrace_flush_breakpoints(pid_t pid); diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index 4446194d6..9ead12977 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -5,6 +5,7 @@ #include "restorer.h" #include "asm/restorer.h" #include "asm/fpu.h" +#include "asm/string.h" #include "syscall.h" #include "log.h" @@ -32,3 +33,64 @@ int restore_nonsigframe_gpregs(UserX86RegsEntry *r) #endif return 0; } + +extern unsigned long call32_from_64(void *stack, void *func); + +asm ( " .pushsection .text \n" + " .global restore_set_thread_area \n" + " .code32 \n" + "restore_set_thread_area: \n" + " movl $"__stringify(__NR32_set_thread_area)",%eax\n" + " int $0x80 \n" + " ret \n" + " .popsection \n" + " .code64"); +extern char restore_set_thread_area; + +static void *stack32; + +static int prepare_stack32(void) +{ + + if (stack32) + return 0; + + stack32 = (void*)sys_mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (stack32 == MAP_FAILED) { + stack32 = NULL; + pr_err("Failed to allocate stack for 32-bit TLS restore\n"); + return -1; + } + + return 0; +} + +void restore_tls(tls_t *ptls) +{ + int i; + + for (i = 0; i < GDT_ENTRY_TLS_NUM; i++) { + user_desc_t *desc = &ptls->desc[i]; + int ret; + + if (desc->seg_not_present) + continue; + + if (prepare_stack32() < 0) + return; + + builtin_memcpy(stack32, desc, sizeof(user_desc_t)); + + /* user_desc parameter for set_thread_area syscall */ + asm volatile ("\t movl %%ebx,%%ebx\n" : :"b"(stack32)); + call32_from_64(stack32 + PAGE_SIZE, &restore_set_thread_area); + asm volatile ("\t movl %%eax,%0\n" : "=r"(ret)); + if (ret) + pr_err("Failed to restore TLS descriptor %d in GDT ret %d\n", + desc->entry_number, ret); + } + + if (stack32) + sys_munmap(stack32, PAGE_SIZE); +} diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 2d5828b5b..5d92b31b5 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -14,6 +14,7 @@ restorer-obj-y += ./$(ARCH_DIR)/restorer.o ifeq ($(ARCH),x86) restorer-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o + restorer-obj-y += ./$(ARCH_DIR)/call32.o native-obj-y += ./$(ARCH_DIR)/parasite-head-64.o native-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o From 19e4ab4f5a14e36ad53f767ae5e4bd41ccffa521 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:20 +0300 Subject: [PATCH 0068/4375] zdtm: add compatible tests building `make test COMPAT_TEST=y` will build all executable tests as i386 ELFs. For building tests, need the following libraries from multilib: libaio.i686 libaio-devel.i686 libcap-devel.i686 libcap.i686 Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/zdtm/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/zdtm/Makefile b/test/zdtm/Makefile index 8abf2144d..2566a925e 100644 --- a/test/zdtm/Makefile +++ b/test/zdtm/Makefile @@ -1,5 +1,13 @@ SUBDIRS = lib static transition +ifeq ($(COMPAT_TEST),y) +ifeq ($(ARCH),x86) + export USERCFLAGS += -m32 + export CFLAGS += -m32 + export LDFLAGS += -m32 +endif +endif + default: all .PHONY: default lib static transition From 3f1ac58c334208e868c519171393f785066a67cb Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:21 +0300 Subject: [PATCH 0069/4375] restore/x86: call int80 for compat sigaction restore The kernel patch "x86/signal: add SA_{X32,IA32}_ABI sa_flags" makes signal's ABI the same as sigaction's syscall ABI instead of per-thread's TIF_IA32 flag. So for delivering signals with compatible ABI, we need to call sigaction through raw int80 exception. This patch restores signals with int80: cr-restore part and PIE restorer's part lay in sigaction_compat.c, which compiled for criu binary and for restorer PIE. The PIE's part is needed strictly for setting SIGCHLD handler, other signal handlers are set in cr-restore (as it was before). Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/include/asm/restorer.h | 5 + criu/arch/arm/include/asm/restorer.h | 5 + criu/arch/ppc64/include/asm/restorer.h | 5 + criu/arch/x86/Makefile | 2 + criu/arch/x86/include/asm/restorer.h | 16 +++ criu/arch/x86/include/asm/types.h | 7 ++ criu/arch/x86/restorer.c | 10 +- criu/arch/x86/sigaction_compat.c | 68 +++++++++++ criu/arch/x86/sigaction_compat_pie.c | 1 + criu/cr-restore.c | 144 +++++++++++++++++++---- criu/parasite-syscall.c | 7 +- criu/pie/Makefile | 2 + criu/pie/restorer.c | 15 ++- images/sa.proto | 1 + 14 files changed, 258 insertions(+), 30 deletions(-) create mode 100644 criu/arch/x86/sigaction_compat.c create mode 120000 criu/arch/x86/sigaction_compat_pie.c diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h index 8c5d8550e..e23ab11fb 100644 --- a/criu/arch/aarch64/include/asm/restorer.h +++ b/criu/arch/aarch64/include/asm/restorer.h @@ -72,4 +72,9 @@ static inline int ptrace_flush_breakpoints(pid_t pid) return 0; } +static inline void *alloc_compat_syscall_stack(void) { return NULL; } +static inline void free_compat_syscall_stack(void *stack32) { } +static inline int +arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; } + #endif diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h index e8eec8329..07bf4aeb2 100644 --- a/criu/arch/arm/include/asm/restorer.h +++ b/criu/arch/arm/include/asm/restorer.h @@ -82,4 +82,9 @@ static inline int ptrace_flush_breakpoints(pid_t pid) return 0; } +static inline void *alloc_compat_syscall_stack(void) { return NULL; } +static inline void free_compat_syscall_stack(void *stack32) { } +static inline int +arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; } + #endif diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h index ff44d7d61..afd00c519 100644 --- a/criu/arch/ppc64/include/asm/restorer.h +++ b/criu/arch/ppc64/include/asm/restorer.h @@ -70,4 +70,9 @@ static inline int ptrace_flush_breakpoints(pid_t pid) */ unsigned long sys_shmat(int shmid, const void *shmaddr, int shmflg); +static inline void *alloc_compat_syscall_stack(void) { return NULL; } +static inline void free_compat_syscall_stack(void *stack32) { } +static inline int +arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; } + #endif /*__CR_ASM_RESTORER_H__*/ diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index 21f6fdd2d..aa03af353 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -6,3 +6,5 @@ ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include obj-y += cpu.o obj-y += crtools.o obj-y += sigframe.o +obj-y += sigaction_compat.o +obj-y += call32.o diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index 4c99b6eaf..7907aef5c 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -7,6 +7,22 @@ #include "sigframe.h" +#ifdef CONFIG_COMPAT +extern void *alloc_compat_syscall_stack(void); +extern void free_compat_syscall_stack(void *mem); +extern unsigned long call32_from_64(void *stack, void *func); +extern void restore_tls(tls_t *ptls); + +extern int arch_compat_rt_sigaction(void *stack32, int sig, + rt_sigaction_t_compat *act); +#else +static inline void *alloc_compat_syscall_stack(void) { return NULL; } +static inline void free_compat_syscall_stack(void *stack32) { } +static inline void restore_tls(tls_t *ptls) { } +static inline int +arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; } +#endif + #ifdef CONFIG_X86_64 #define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \ thread_args, clone_restore_fn) \ diff --git a/criu/arch/x86/include/asm/types.h b/criu/arch/x86/include/asm/types.h index 623dd84c6..be5cd77b6 100644 --- a/criu/arch/x86/include/asm/types.h +++ b/criu/arch/x86/include/asm/types.h @@ -50,6 +50,13 @@ typedef struct { k_rtsigset_t rt_sa_mask; } rt_sigaction_t; +typedef struct { + u32 rt_sa_handler; + u32 rt_sa_flags; + u32 rt_sa_restorer; + k_rtsigset_t rt_sa_mask; +} rt_sigaction_t_compat; + typedef struct { unsigned int entry_number; unsigned int base_addr; diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index 9ead12977..5a0007706 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -34,8 +34,6 @@ int restore_nonsigframe_gpregs(UserX86RegsEntry *r) return 0; } -extern unsigned long call32_from_64(void *stack, void *func); - asm ( " .pushsection .text \n" " .global restore_set_thread_area \n" " .code32 \n" @@ -55,10 +53,8 @@ static int prepare_stack32(void) if (stack32) return 0; - stack32 = (void*)sys_mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, - MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (stack32 == MAP_FAILED) { - stack32 = NULL; + stack32 = alloc_compat_syscall_stack(); + if (!stack32) { pr_err("Failed to allocate stack for 32-bit TLS restore\n"); return -1; } @@ -92,5 +88,5 @@ void restore_tls(tls_t *ptls) } if (stack32) - sys_munmap(stack32, PAGE_SIZE); + free_compat_syscall_stack(stack32); } diff --git a/criu/arch/x86/sigaction_compat.c b/criu/arch/x86/sigaction_compat.c new file mode 100644 index 000000000..ef6d13c91 --- /dev/null +++ b/criu/arch/x86/sigaction_compat.c @@ -0,0 +1,68 @@ +#include "asm/restorer.h" +#include "asm/fpu.h" +#include "asm/string.h" + +#include + +#ifdef CR_NOGLIBC +# include "syscall.h" +#else +# define sys_mmap mmap +# define sys_munmap munmap +# ifndef __NR32_rt_sigaction +# define __NR32_rt_sigaction 174 +# endif +#endif +#include "log.h" +#include "cpu.h" + +void *alloc_compat_syscall_stack(void) +{ + void *mem = (void*)sys_mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + + if (mem == MAP_FAILED) + return 0; + return mem; +} + +void free_compat_syscall_stack(void *mem) +{ + sys_munmap(mem, PAGE_SIZE); +} + +asm ( " .pushsection .text \n" + " .global restore_rt_sigaction \n" + " .code32 \n" + "restore_rt_sigaction: \n" + " mov %edx, %esi \n" + " mov $0, %edx \n" + " movl $"__stringify(__NR32_rt_sigaction)",%eax \n" + " int $0x80 \n" + " ret \n" + " .popsection \n" + " .code64"); +extern char restore_rt_sigaction; + +/* + * Call raw rt_sigaction syscall through int80 - so the ABI kernel choses + * to deliver this signal would be i386. + */ +int arch_compat_rt_sigaction(void *stack32, int sig, rt_sigaction_t_compat *act) +{ + int ret; + + /* + * To be sure, that sigaction pointer lies under 4G, + * coping it on the bottom of the stack. + */ + builtin_memcpy(stack32, act, sizeof(rt_sigaction_t_compat)); + + asm volatile ("\t movl %%ebx,%%ebx\n" : :"b"(sig)); /* signum */ + asm volatile ("\t movl %%ecx,%%ecx\n" : :"c"(stack32)); /* act */ + asm volatile ("\t movl %%edx,%%edx\n" : :"d"(sizeof(act->rt_sa_mask))); + call32_from_64(stack32 + PAGE_SIZE, &restore_rt_sigaction); + asm volatile ("\t movl %%eax,%0\n" : "=r"(ret)); + return ret; +} + diff --git a/criu/arch/x86/sigaction_compat_pie.c b/criu/arch/x86/sigaction_compat_pie.c new file mode 120000 index 000000000..009ac3a87 --- /dev/null +++ b/criu/arch/x86/sigaction_compat_pie.c @@ -0,0 +1 @@ +sigaction_compat.c \ No newline at end of file diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 9ef3570c2..bd61d3882 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -277,7 +277,15 @@ err: } static rt_sigaction_t sigchld_act; +/* + * If parent's sigaction has blocked SIGKILL (which is non-sence), + * this parent action is non-valid and shouldn't be inherited. + * Used to mark parent_act* no more valid. + */ static rt_sigaction_t parent_act[SIGMAX]; +#ifdef CONFIG_COMPAT +static rt_sigaction_t_compat parent_act_compat[SIGMAX]; +#endif static bool sa_inherited(int sig, rt_sigaction_t *sa) { @@ -289,6 +297,10 @@ static bool sa_inherited(int sig, rt_sigaction_t *sa) pa = &parent_act[sig]; + /* Omitting non-valid sigaction */ + if (pa->rt_sa_mask.sig[0] & (1 << SIGKILL)) + return false; + for (i = 0; i < _KNSIG_WORDS; i++) if (pa->rt_sa_mask.sig[i] != sa->rt_sa_mask.sig[i]) return false; @@ -298,26 +310,10 @@ static bool sa_inherited(int sig, rt_sigaction_t *sa) pa->rt_sa_restorer == sa->rt_sa_restorer; } -/* Returns number of restored signals, -1 or negative errno on fail */ -static int restore_one_sigaction(int sig, struct cr_img *img, int pid) +static int restore_native_sigaction(int sig, SaEntry *e) { rt_sigaction_t act; - SaEntry *e; - int ret = 0; - - BUG_ON(sig == SIGKILL || sig == SIGSTOP); - - ret = pb_read_one_eof(img, &e, PB_SIGACT); - if (ret == 0) { - if (sig != SIGMAX_OLD + 1) { /* backward compatibility */ - pr_err("Unexpected EOF %d\n", sig); - return -1; - } - pr_warn("This format of sigacts-%d.img is deprecated\n", pid); - return -1; - } - if (ret < 0) - return ret; + int ret; ASSIGN_TYPED(act.rt_sa_handler, decode_pointer(e->sigaction)); ASSIGN_TYPED(act.rt_sa_flags, e->flags); @@ -325,8 +321,6 @@ static int restore_one_sigaction(int sig, struct cr_img *img, int pid) BUILD_BUG_ON(sizeof(e->mask) != sizeof(act.rt_sa_mask.sig)); memcpy(act.rt_sa_mask.sig, &e->mask, sizeof(act.rt_sa_mask.sig)); - sa_entry__free_unpacked(e, NULL); - if (sig == SIGCHLD) { sigchld_act = act; return 0; @@ -346,10 +340,116 @@ static int restore_one_sigaction(int sig, struct cr_img *img, int pid) } parent_act[sig - 1] = act; + /* Mark SIGKILL blocked which makes compat sigaction non-valid */ +#ifdef CONFIG_COMPAT + parent_act_compat[sig - 1].rt_sa_mask.sig[0] |= 1 << SIGKILL; +#endif return 1; } +static void *stack32; + +#ifdef CONFIG_COMPAT +static bool sa_compat_inherited(int sig, rt_sigaction_t_compat *sa) +{ + rt_sigaction_t_compat *pa; + int i; + + if (current == root_item) + return false; + + pa = &parent_act_compat[sig]; + + /* Omitting non-valid sigaction */ + if (pa->rt_sa_mask.sig[0] & (1 << SIGKILL)) + return false; + + for (i = 0; i < _KNSIG_WORDS; i++) + if (pa->rt_sa_mask.sig[i] != sa->rt_sa_mask.sig[i]) + return false; + + return pa->rt_sa_handler == sa->rt_sa_handler && + pa->rt_sa_flags == sa->rt_sa_flags && + pa->rt_sa_restorer == sa->rt_sa_restorer; +} + +static int restore_compat_sigaction(int sig, SaEntry *e) +{ + rt_sigaction_t_compat act; + int ret; + + ASSIGN_TYPED(act.rt_sa_handler, (u32)e->sigaction); + ASSIGN_TYPED(act.rt_sa_flags, e->flags); + ASSIGN_TYPED(act.rt_sa_restorer, (u32)e->restorer); + BUILD_BUG_ON(sizeof(e->mask) != sizeof(act.rt_sa_mask.sig)); + memcpy(act.rt_sa_mask.sig, &e->mask, sizeof(act.rt_sa_mask.sig)); + + if (sig == SIGCHLD) { + memcpy(&sigchld_act, &act, sizeof(rt_sigaction_t_compat)); + return 0; + } + + if (sa_compat_inherited(sig - 1, &act)) + return 1; + + if (!stack32) { + stack32 = alloc_compat_syscall_stack(); + if (!stack32) + return -1; + } + + ret = arch_compat_rt_sigaction(stack32, sig, &act); + if (ret < 0) { + pr_err("Can't restore compat sigaction: %d\n", ret); + return ret; + } + + parent_act_compat[sig - 1] = act; + /* Mark SIGKILL blocked which makes native sigaction non-valid */ + parent_act[sig - 1].rt_sa_mask.sig[0] |= 1 << SIGKILL; + + return 1; +} +#else +static int restore_compat_sigaction(int sig, SaEntry *e) +{ + return -1; +} +#endif + +/* Returns number of restored signals, -1 or negative errno on fail */ +static int restore_one_sigaction(int sig, struct cr_img *img, int pid) +{ + bool sigaction_is_compat; + SaEntry *e; + int ret = 0; + + BUG_ON(sig == SIGKILL || sig == SIGSTOP); + + ret = pb_read_one_eof(img, &e, PB_SIGACT); + if (ret == 0) { + if (sig != SIGMAX_OLD + 1) { /* backward compatibility */ + pr_err("Unexpected EOF %d\n", sig); + return -1; + } + pr_warn("This format of sigacts-%d.img is deprecated\n", pid); + return -1; + } + if (ret < 0) + return ret; + + sigaction_is_compat = e->has_compat_sigaction && e->compat_sigaction; + if (sigaction_is_compat) + ret = restore_compat_sigaction(sig, e); + else + ret = restore_native_sigaction(sig, e); + + sa_entry__free_unpacked(e, NULL); + + return ret; +} + static int prepare_sigactions(void) { int pid = vpid(current); @@ -381,6 +481,10 @@ static int prepare_sigactions(void) SIGMAX - 3 /* KILL, STOP and CHLD */); close_image(img); + if (stack32) { + free_compat_syscall_stack(stack32); + stack32 = NULL; + } return ret; } diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 5483aae8c..1e64a08b2 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -699,8 +699,9 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_ int ret, sig; struct cr_img *img; SaEntry se = SA_ENTRY__INIT; + bool native_task = seized_native(ctl); - if (seized_native(ctl)) + if (native_task) args = parasite_args(ctl, struct parasite_dump_sa_args); else args_c = parasite_args(ctl, struct parasite_dump_sa_args_compat); @@ -717,10 +718,12 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_ if (sig == SIGSTOP || sig == SIGKILL) continue; - if (seized_native(ctl)) + if (native_task) ASSIGN_SAS(se, args); else ASSIGN_SAS(se, args_c); + se.has_compat_sigaction = true; + se.compat_sigaction = !native_task; if (pb_write_one(img, &se, PB_SIGACT) < 0) return -1; diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 5d92b31b5..cc8b69f20 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -15,6 +15,7 @@ restorer-obj-y += ./$(ARCH_DIR)/restorer.o ifeq ($(ARCH),x86) restorer-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o restorer-obj-y += ./$(ARCH_DIR)/call32.o + restorer-obj-y += ./$(ARCH_DIR)/sigaction_compat_pie.o native-obj-y += ./$(ARCH_DIR)/parasite-head-64.o native-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o @@ -73,6 +74,7 @@ define obj-export-compat-flags LDFLAGS_$(notdir $(1)) := $(COMPAT_LDFLAGS) endef +$(eval $(call map,obj-export-native-flags,$(restorer-obj-y))) $(eval $(call map,obj-export-native-flags,$(native-obj-y) native)) $(eval $(call map,obj-export-compat-flags,$(compat-obj-y) compat)) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index ebac5b9a4..bb129787c 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1410,7 +1410,20 @@ long __export_restore_task(struct task_restore_args *args) goto core_restore_end; } - sys_sigaction(SIGCHLD, &args->sigchld_act, NULL, sizeof(k_rtsigset_t)); + if (!args->compatible_mode) { + sys_sigaction(SIGCHLD, &args->sigchld_act, + NULL, sizeof(k_rtsigset_t)); + } else { + void *stack = alloc_compat_syscall_stack(); + + if (!stack) { + pr_err("Failed to allocate 32-bit stack for sigaction\n"); + goto core_restore_end; + } + arch_compat_rt_sigaction(stack, SIGCHLD, + (void*)&args->sigchld_act); + free_compat_syscall_stack(stack); + } ret = restore_signals(args->siginfo, args->siginfo_n, true); if (ret) diff --git a/images/sa.proto b/images/sa.proto index d4c590a13..3bce0c4ff 100644 --- a/images/sa.proto +++ b/images/sa.proto @@ -7,4 +7,5 @@ message sa_entry { required uint64 flags = 2 [(criu).hex = true]; required uint64 restorer = 3 [(criu).hex = true]; required uint64 mask = 4 [(criu).hex = true]; + optional bool compat_sigaction = 5; } From a8ae7b4eea9d1388e1fedc1c4c35aa9221317855 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:24:22 +0300 Subject: [PATCH 0070/4375] signal/x86-32: use packed for compat rt_sigaction Otherwise compiler nicely align it for us on 24 bytes. Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/include/asm/types.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/criu/arch/x86/include/asm/types.h b/criu/arch/x86/include/asm/types.h index be5cd77b6..fa2cb77f9 100644 --- a/criu/arch/x86/include/asm/types.h +++ b/criu/arch/x86/include/asm/types.h @@ -50,7 +50,12 @@ typedef struct { k_rtsigset_t rt_sa_mask; } rt_sigaction_t; -typedef struct { +/* + * Note: there is unaligned access on x86_64 and it's fine. + * However, when porting this code -- keep in mind about possible issues + * with unaligned rt_sa_mask. + */ +typedef struct __attribute__((packed)) { u32 rt_sa_handler; u32 rt_sa_flags; u32 rt_sa_restorer; From acfd9a3ebe8ca2d781d944dba6c7971124647450 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 22:25:49 +0300 Subject: [PATCH 0071/4375] vdso: suppress not ELF vDSO error When mapping compatible vDSO in restorer blob (with vdso_map_compat), we don't know if the kernel will map firstly vvar pages or vdso pages. So we attempt search by checking ELF header magic on those pages. Which leads to following "errors", which this patch hides: pie: 1: Error (pie/util-vdso-elf32.c:87): vdso: Elf header magic misma> pie: 1: Error (pie/util-vdso-elf32.c:87): vdso: Elf header magic misma> pie: 7: Error (pie/util-vdso-elf32.c:87): vdso: Elf header magic misma> pie: 7: Error (pie/util-vdso-elf32.c:87): vdso: Elf header magic misma> pie: 6: Error (pie/util-vdso-elf32.c:87): vdso: Elf header magic misma> pie: 6: Error (pie/util-vdso-elf32.c:87): vdso: Elf header magic misma> pie: 4: Error (pie/util-vdso-elf32.c:87): vdso: Elf header magic misma> pie: 5: Error (pie/util-vdso-elf32.c:87): vdso: Elf header magic misma> pie: 4: Error (pie/util-vdso-elf32.c:87): vdso: Elf header magic misma> pie: 5: Error (pie/util-vdso-elf32.c:87): vdso: Elf header magic misma> (for two vvar pages and 5 processes being restored). Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/util-vdso.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/criu/pie/util-vdso.c b/criu/pie/util-vdso.c index 567d38460..b55739a9e 100644 --- a/criu/pie/util-vdso.c +++ b/criu/pie/util-vdso.c @@ -88,11 +88,8 @@ static int has_elf_identity(Ehdr_t *ehdr) BUILD_BUG_ON(sizeof(elf_ident) != sizeof(ehdr->e_ident)); - if (memcmp(ehdr->e_ident, elf_ident, sizeof(elf_ident))) { - pr_err("Elf header magic mismatch\n"); + if (memcmp(ehdr->e_ident, elf_ident, sizeof(elf_ident))) return false; - } - return true; } From c36515ad418f97fccf56df3d0a5b86e291811aef Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 7 Jul 2016 00:15:24 +0300 Subject: [PATCH 0072/4375] criu: arch, x86 -- A few style tuneup in mixed call code - use entry/end from linkage - use macros for segments - use C style comments Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Tested-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/Makefile | 4 ++++ criu/arch/x86/call32.S | 37 ++++++++++++++++---------------- criu/arch/x86/parasite-head-64.S | 2 +- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index aa03af353..c8ac6e303 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -3,6 +3,10 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include +asflags-y += -Wstrict-prototypes -Wa,--noexecstack +asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer +asflags-y += -iquote $(obj)/include + obj-y += cpu.o obj-y += crtools.o obj-y += sigframe.o diff --git a/criu/arch/x86/call32.S b/criu/arch/x86/call32.S index bc724d6c5..48d28e2f1 100644 --- a/criu/arch/x86/call32.S +++ b/criu/arch/x86/call32.S @@ -16,15 +16,19 @@ * the fly. */ +#include "common/asm/linkage.h" + +#define __USER32_CS 0x23 +#define __USER_CS 0x33 + .text - .global call32_from_64 - .type call32_from_64, @function -call32_from_64: - // rdi: stack to use - // esi: function to call - - // Save registers +/* + * @rdi: Stack to use + * @esi: Pointer to function for calling + */ +ENTRY(call32_from_64) + /* Callee-saving registers due to ABI */ pushq %rbx pushq %rbp pushq %r12 @@ -33,30 +37,29 @@ call32_from_64: pushq %r15 pushfq - // Switch stacks + /* Switch stacks */ sub $8, %rdi mov %rsp,(%rdi) mov %rdi,%rsp - // Switch to compatibility mode - pushq $0x23 /* USER32_CS */ + /* Switch into compatibility mode */ + pushq $__USER32_CS pushq $1f lretq 1: .code32 - // Call the function + /* Run function and switch back */ call *%esi - // Switch back to long mode - jmp $0x33,$1f + jmp $__USER_CS,$1f .code64 1: - // Restore the stack + /* Restore the stack */ mov (%rsp),%rsp add $8, %rdi - // Restore registers + /* Restore registers */ popfq popq %r15 popq %r14 @@ -64,7 +67,5 @@ call32_from_64: popq %r12 popq %rbp popq %rbx - ret - -.size call32_from_64, .-call32_from_64 +END(call32_from_64) diff --git a/criu/arch/x86/parasite-head-64.S b/criu/arch/x86/parasite-head-64.S index 4cc4d920a..bb6f95232 100644 --- a/criu/arch/x86/parasite-head-64.S +++ b/criu/arch/x86/parasite-head-64.S @@ -1,4 +1,4 @@ -#include "asm/linkage.h" +#include "common/asm/linkage.h" #include "parasite.h" .section .head.text, "ax" From cd073d3e885c7826257ff69633aad84e064562ad Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Thu, 7 Jul 2016 08:59:00 +0300 Subject: [PATCH 0073/4375] parasite: pass parameter regs as pointer CID 163751 (#1 of 1): Big parameter passed by value (PASS_BY_VALUE) pass_by_value: Passing parameter regs of type user_regs_struct_t (size 224 bytes) by value. Signed-off-by: Andrew Vagin Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov --- criu/parasite-syscall.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 1e64a08b2..64f8ed84d 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -1025,17 +1025,17 @@ static bool task_is_trapped(int status, pid_t pid) return false; } -static inline int is_required_syscall(user_regs_struct_t regs, pid_t pid, +static inline int is_required_syscall(user_regs_struct_t *regs, pid_t pid, const int sys_nr, const int sys_nr_compat) { - const char *mode = user_regs_native(®s) ? "native" : "compat"; - int req_sysnr = user_regs_native(®s) ? sys_nr : sys_nr_compat; + const char *mode = user_regs_native(regs) ? "native" : "compat"; + int req_sysnr = user_regs_native(regs) ? sys_nr : sys_nr_compat; pr_debug("%d (%s) is going to execute the syscall %lu, required is %d\n", - pid, mode, REG_SYSCALL_NR(regs), req_sysnr); - if (user_regs_native(®s) && (REG_SYSCALL_NR(regs) == sys_nr)) + pid, mode, REG_SYSCALL_NR(*regs), req_sysnr); + if (user_regs_native(regs) && (REG_SYSCALL_NR(*regs) == sys_nr)) return true; - if (!user_regs_native(®s) && (REG_SYSCALL_NR(regs) == sys_nr_compat)) + if (!user_regs_native(regs) && (REG_SYSCALL_NR(*regs) == sys_nr_compat)) return true; return false; @@ -1085,7 +1085,7 @@ int parasite_stop_on_syscall(int tasks, return -1; } - if (is_required_syscall(regs, pid, sys_nr, sys_nr_compat)) { + if (is_required_syscall(®s, pid, sys_nr, sys_nr_compat)) { /* * The process is going to execute the required syscall, * the next stop will be on the exit from this syscall From 8f6800db8322db92927679f2f5eb7f7c7fe0aa59 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 7 Jul 2016 14:51:53 +0300 Subject: [PATCH 0074/4375] x86/ptrace: describe failures from errno ptrace_get_regs correctly returns error code in case of failure, but for debugging reasons let's add error printing in case of PTRACE_GETREGSET failed right after the call to ptrace(). Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 18eb499e6..b1c70cde3 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -360,6 +360,11 @@ int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs) iov.iov_len = sizeof(user_regs_struct64); ret = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov); + if (ret == -1) { + pr_perror("PTRACE_GETREGSET failed"); + return -1; + } + if (iov.iov_len == sizeof(regs->native)) { regs->__is_native = NATIVE_MAGIC; return ret; From 5141d3238abd22bc98bd2b3117ebbed16614c60f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 7 Jul 2016 16:36:16 +0300 Subject: [PATCH 0075/4375] cr-exec: check syscall's number right before injecting it So, I made a mistake in find_syscall: it can't use arch_task_compatible to find out in which mode the application is (native/compat). The reason is that arch_task_compatible uses PTRACE_GETREGSET. And at the moment of find_syscall we haven't yet seized the task. In this patch I move syscall's number check right before injecting a syscall, where we have parasite_ctl with all needed information about task's mode. This makes error-path for wrong syscall number longer and subtler (includes curing now), but I think it's a corner-case, so as it makes error-less path to execute_syscall shorter and without additional ptrace syscalls, it's better. Reported-by: Andrew Vagin Cc: Andrew Vagin Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/sys-exec-tbl.c | 19 ++++++------------- criu/cr-exec.c | 14 +++++++------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/criu/arch/x86/sys-exec-tbl.c b/criu/arch/x86/sys-exec-tbl.c index b7f95b98e..ca45ef0d3 100644 --- a/criu/arch/x86/sys-exec-tbl.c +++ b/criu/arch/x86/sys-exec-tbl.c @@ -24,26 +24,19 @@ find_syscall_table(char *name, struct syscall_exec_desc *tbl) return NULL; } -int __attribute__((weak)) arch_task_compatible(pid_t pid) { return false; } #define ARCH_HAS_FIND_SYSCALL /* overwrite default to search in two tables above */ #ifdef CONFIG_X86_64 -struct syscall_exec_desc * find_syscall(char *name, int pid) +struct syscall_exec_desc * find_syscall(char *name, struct parasite_ctl *ctl) { - int err = arch_task_compatible(pid); - - switch(err) { - case 0: - return find_syscall_table(name, sc_exec_table_64); - case 1: - return find_syscall_table(name, sc_exec_table_32); - default: /* Error */ - return NULL; - } + if (seized_native(ctl)) + return find_syscall_table(name, sc_exec_table_64); + else + return find_syscall_table(name, sc_exec_table_32); } #else struct syscall_exec_desc * -find_syscall(char *name, __attribute__((unused)) int pid) +find_syscall(char *name, __always_unused struct parasite_ctl *ctl) { return find_syscall_table(name, sc_exec_table_32); } diff --git a/criu/cr-exec.c b/criu/cr-exec.c index 618a73c1e..356e206d5 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -23,7 +23,7 @@ struct syscall_exec_desc { #ifndef ARCH_HAS_FIND_SYSCALL struct syscall_exec_desc * -find_syscall(char *name, int __attribute__((unused)) pid) +find_syscall(char *name, struct parasite_ctl __always_unused *ctl) { int i; @@ -135,12 +135,6 @@ int cr_exec(int pid, char **opt) goto out; } - si = find_syscall(sys_name, pid); - if (!si) { - pr_err("Unknown syscall [%s]\n", sys_name); - goto out; - } - if (seize_catch_task(pid)) goto out; @@ -178,6 +172,12 @@ int cr_exec(int pid, char **opt) goto out_unseize; } + si = find_syscall(sys_name, ctl); + if (!si) { + pr_err("Unknown syscall [%s]\n", sys_name); + goto out_cure; + } + ret = execute_syscall(ctl, si, opt + 1); if (ret < 0) { pr_err("Can't execute syscall remotely\n"); From 5c7e141b3444dc29e5dd4b2d3be210eb49cae61d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 7 Jul 2016 20:39:19 +0300 Subject: [PATCH 0076/4375] parasite-syscall: refactor dumping of posix timers Tried hard to save compile-time static type checking and make code more readable, hiding native/compat details in macros. I think, it's better now. Also BTW fixes: #188 (and compatible zdtm test) Signed-off-by: Dmitry Safonov Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/parasite-syscall.c | 78 +++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 64f8ed84d..227eca2dc 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -789,21 +789,42 @@ static int core_alloc_posix_timers(TaskTimersEntry *tte, int n, return 0; } -#define encode_posix_timer(v, vp, pte) \ +#define set_posix_timer_arg(args, ctl, m, val) \ do { \ - (pte)->it_id = (vp)->spt.it_id; \ - (pte)->clock_id = (vp)->spt.clock_id; \ - (pte)->si_signo = (vp)->spt.si_signo; \ - (pte)->it_sigev_notify = (vp)->spt.it_sigev_notify; \ - (pte)->sival_ptr = encode_pointer((vp)->spt.sival_ptr); \ - \ - (pte)->overrun = (v)->overrun; \ - \ - (pte)->isec = (v)->val.it_interval.tv_sec; \ - (pte)->insec = (v)->val.it_interval.tv_nsec; \ - (pte)->vsec = (v)->val.it_value.tv_sec; \ - (pte)->vnsec = (v)->val.it_value.tv_nsec; \ -} while(0) + if (seized_native(ctl)) \ + ASSIGN_TYPED( \ + ((struct parasite_dump_posix_timers_args*)args)->m, val); \ + else \ + ASSIGN_TYPED( \ + ((struct parasite_dump_posix_timers_args_compat*)args)->m, val);\ +} while (0) + +#define get_posix_timer_arg(out, m) \ +do { \ + if (seized_native(ctl)) \ + ASSIGN_TYPED( \ + out, ((struct parasite_dump_posix_timers_args*)args)->m); \ + else \ + ASSIGN_TYPED( \ + out, ((struct parasite_dump_posix_timers_args_compat*)args)->m);\ +} while (0) + +static void encode_posix_timer(void *args, struct parasite_ctl *ctl, + struct proc_posix_timer *vp, PosixTimerEntry *pte, int i) +{ + pte->it_id = vp->spt.it_id; + pte->clock_id = vp->spt.clock_id; + pte->si_signo = vp->spt.si_signo; + pte->it_sigev_notify = vp->spt.it_sigev_notify; + pte->sival_ptr = encode_pointer(vp->spt.sival_ptr); + + get_posix_timer_arg(pte->overrun, timer[i].overrun); + + get_posix_timer_arg(pte->isec, timer[i].val.it_interval.tv_sec); + get_posix_timer_arg(pte->insec, timer[i].val.it_interval.tv_nsec); + get_posix_timer_arg(pte->vsec, timer[i].val.it_value.tv_sec); + get_posix_timer_arg(pte->vnsec, timer[i].val.it_value.tv_nsec); +} int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, struct parasite_ctl *ctl, struct pstree_item *item) @@ -811,31 +832,26 @@ int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, CoreEntry *core = item->core[0]; TaskTimersEntry *tte = core->tc->timers; PosixTimerEntry *pte; - struct parasite_dump_posix_timers_args *args = NULL; - struct parasite_dump_posix_timers_args_compat *args_c = NULL; struct proc_posix_timer *temp; - int i; + void *args = NULL; + int args_size; int ret = 0; + int i; if (core_alloc_posix_timers(tte, proc_args->timer_n, &pte)) return -1; - if(seized_native(ctl)) { - args = parasite_args_s(ctl, - posix_timers_dump_size(proc_args->timer_n)); - args->timer_n = proc_args->timer_n; - } else { - args_c = parasite_args_s(ctl, - posix_timers_compat_dump_size(proc_args->timer_n)); - args_c->timer_n = proc_args->timer_n; - } + if (seized_native(ctl)) + args_size = posix_timers_dump_size(proc_args->timer_n); + else + args_size = posix_timers_compat_dump_size(proc_args->timer_n); + args = parasite_args_s(ctl, args_size); + + set_posix_timer_arg(args, ctl, timer_n, proc_args->timer_n); i = 0; list_for_each_entry(temp, &proc_args->timers, list) { - if(seized_native(ctl)) - args->timer[i].it_id = temp->spt.it_id; - else - args_c->timer[i].it_id = temp->spt.it_id; + set_posix_timer_arg(args, ctl, timer[i].it_id, temp->spt.it_id); i++; } @@ -846,7 +862,7 @@ int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, i = 0; list_for_each_entry(temp, &proc_args->timers, list) { posix_timer_entry__init(&pte[i]); - encode_posix_timer(&args->timer[i], temp, &pte[i]); + encode_posix_timer(args, ctl, temp, &pte[i], i); tte->posix[i] = &pte[i]; i++; } From abca195ef20c573539762f1960a479aabe6e0a44 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 7 Jul 2016 00:15:00 +0300 Subject: [PATCH 0077/4375] criu: arch, x86 -- Rename registers mode @gpregs_case is a bit vague name, lets define traditional @mode here. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 10 +++++----- images/core-x86.proto | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index b1c70cde3..0c14b8602 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -317,7 +317,7 @@ static int save_task_regs(CoreEntry *core, assign_reg(gpregs, regs->compat, ss); gpregs->mode = USER_X86_REGS_MODE__COMPAT; } - gpregs->has_gpregs_case = true; + gpregs->has_mode = true; if (!fpregs) return 0; @@ -701,15 +701,15 @@ static void restore_native_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) { - switch (r->gpregs_case) { - case USER_X86_REGS_CASE_T__NATIVE: + switch (r->mode) { + case USER_X86_REGS_MODE__NATIVE: restore_native_gpregs(f, r); break; - case USER_X86_REGS_CASE_T__COMPAT: + case USER_X86_REGS_MODE__COMPAT: restore_compat_gpregs(f, r); break; default: - pr_err("Can't prepare rt_sigframe: regs_case corrupt\n"); + pr_err("Can't prepare rt_sigframe: registers mode corrupted (%d)\n", r->mode); return -1; } return 0; diff --git a/images/core-x86.proto b/images/core-x86.proto index 663276c90..d4b791dbc 100644 --- a/images/core-x86.proto +++ b/images/core-x86.proto @@ -2,7 +2,7 @@ syntax = "proto2"; import "opts.proto"; -enum user_x86_regs_case_t { +enum user_x86_regs_mode { NATIVE = 1; COMPAT = 2; } @@ -36,7 +36,7 @@ message user_x86_regs_entry { required uint64 es = 25; required uint64 fs = 26; required uint64 gs = 27; - optional user_x86_regs_case_t gpregs_case = 28 [default = NATIVE]; + optional user_x86_regs_mode mode = 28 [default = NATIVE]; } message user_x86_xsave_entry { From bbf29e89b49a203a5a15f4e5421c7ff61b741753 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 18 Jul 2016 22:22:43 +0300 Subject: [PATCH 0078/4375] make: drop compel/compel dependency for all target Target criu depends on all, so this is redundant and makes noise: if you had typed `make` without arguments, it has built compel firstly, if you had typed `make criu`, it has built protobuf images firstly. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a6e08d124..6176f2349 100644 --- a/Makefile +++ b/Makefile @@ -127,7 +127,7 @@ endif CFLAGS += $(WARNINGS) $(DEFINES) -iquote include/ # Default target -all: compel/compel criu lib +all: criu lib .PHONY: all # From b6b2290f8726a7bff329480914a869d3d1e0d01f Mon Sep 17 00:00:00 2001 From: Laurent Dufour Date: Tue, 19 Jul 2016 19:30:00 +0300 Subject: [PATCH 0079/4375] parasite: simplify syscall check In is_required_syscall() req_sysnr is set according to the native mode so we can check the syscall number directly against it. No functional change expected. Cc: Dmitry Safonov Signed-off-by: Laurent Dufour Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/parasite-syscall.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 227eca2dc..50d06410f 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -1049,12 +1049,8 @@ static inline int is_required_syscall(user_regs_struct_t *regs, pid_t pid, pr_debug("%d (%s) is going to execute the syscall %lu, required is %d\n", pid, mode, REG_SYSCALL_NR(*regs), req_sysnr); - if (user_regs_native(regs) && (REG_SYSCALL_NR(*regs) == sys_nr)) - return true; - if (!user_regs_native(regs) && (REG_SYSCALL_NR(*regs) == sys_nr_compat)) - return true; - return false; + return (REG_SYSCALL_NR(*regs) == req_sysnr); } /* * Trap tasks on the exit from the specified syscall From 31d394bc55ad9663c1479e472f11da280108256d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 8 Aug 2016 15:57:15 +0300 Subject: [PATCH 0080/4375] feature-test: add CONFIG_COMPAT compile option I'll wrap all compatible code in this CONFIG_COMPAT define. As I'll wrap also compatible parasite generation in this, it's also makefile variable, rather than just C define. The test itself consists of including stubs-32.h, which is glibc6-i686 presence test and is compiled with -m32 option, which is test for gcc-multilib. Cc: Cyrill Gorcunov Cc: Andrew Vagin Signed-off-by: Dmitry Safonov Reviewed-by: Cyrill Gorcunov Acked-by: Andrew Vagin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile.config | 8 ++++++++ scripts/feature-tests.mak | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/Makefile.config b/Makefile.config index e0d49d2ff..42b2d94e6 100644 --- a/Makefile.config +++ b/Makefile.config @@ -19,6 +19,14 @@ CONFIG_FILE = $(SRC_DIR)/.config $(CONFIG_FILE): touch $(CONFIG_FILE) +ifeq ($(SRCARCH),x86) +# CONFIG_COMPAT is only for x86 now, no need for compile-test other archs +ifeq ($(call try-cc,$(FEATURE_TEST_X86_COMPAT),-m32),true) + export CONFIG_COMPAT := y + FEATURE_DEFINES += -DCONFIG_COMPAT +endif +endif + export DEFINES += $(FEATURE_DEFINES) export CFLAGS += $(FEATURE_DEFINES) diff --git a/scripts/feature-tests.mak b/scripts/feature-tests.mak index 09bbdc815..ad50eb4ad 100644 --- a/scripts/feature-tests.mak +++ b/scripts/feature-tests.mak @@ -88,3 +88,15 @@ int main(int argc, char *argv[], char *envp[]) } endef + +define FEATURE_TEST_X86_COMPAT + +/* Test for glibc-devel.i686 presence */ +#include + +int main(int argc, char **argv) +{ + return 0; +} + +endef From 74c0a70223a1056f2d6ab58333ca4f7a0573cb33 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 8 Aug 2016 15:57:16 +0300 Subject: [PATCH 0081/4375] criu: wrap compatible code with CONFIG_COMPAT As we will not support *native* 32-bit i386 build, I dropped some ifdefs, introducing instead of ifdef(CONFIG_X86_64) -- ifdef(CONFIG_COMPAT). CRIU should build now without ia32 Glibc and gcc-multilib support. Maybe I should add some warning that the build is made without compatible task support (or criu check should print that), will do as compat patches hit master. Fixes: #181 Cc: Cyrill Gorcunov Cc: Andrew Vagin Signed-off-by: Dmitry Safonov Acked-by: Andrew Vagin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/Makefile | 6 ++++-- criu/arch/x86/Makefile.syscalls | 8 +++----- criu/arch/x86/include/asm/restorer.h | 2 -- criu/arch/x86/restorer.c | 4 ++-- criu/arch/x86/sys-exec-tbl.c | 8 ++++---- criu/page-pipe.c | 8 ++++---- criu/parasite-syscall.c | 4 ++-- criu/pie/Makefile | 9 ++++++--- criu/pie/Makefile.library | 7 ++++--- criu/pie/parasite-blob.h | 2 +- 10 files changed, 30 insertions(+), 28 deletions(-) diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index c8ac6e303..bf5395fe9 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -10,5 +10,7 @@ asflags-y += -iquote $(obj)/include obj-y += cpu.o obj-y += crtools.o obj-y += sigframe.o -obj-y += sigaction_compat.o -obj-y += call32.o +ifeq ($(CONFIG_COMPAT),y) + obj-y += sigaction_compat.o + obj-y += call32.o +endif diff --git a/criu/arch/x86/Makefile.syscalls b/criu/arch/x86/Makefile.syscalls index 0506c1f2b..839f24c1b 100644 --- a/criu/arch/x86/Makefile.syscalls +++ b/criu/arch/x86/Makefile.syscalls @@ -17,11 +17,9 @@ target := target_32 := syscalls-32 target_64 := syscalls-64 -SYS-BITS := 32 - -# native x86_64 -ifeq ($(ARCH),x86) - SYS-BITS += 64 +SYS-BITS := 64 +ifeq ($(CONFIG_COMPAT),y) + SYS-BITS += 32 endif # targets diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index 7907aef5c..45b13315e 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -134,8 +134,6 @@ static inline void _setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas) int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r); int restore_nonsigframe_gpregs(UserX86RegsEntry *r); -void restore_tls(tls_t *ptls); - int ptrace_set_breakpoint(pid_t pid, void *addr); int ptrace_flush_breakpoints(pid_t pid); diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index 5a0007706..574e0da26 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -13,7 +13,6 @@ int restore_nonsigframe_gpregs(UserX86RegsEntry *r) { -#ifdef CONFIG_X86_64 long ret; unsigned long fsgs_base; @@ -30,10 +29,10 @@ int restore_nonsigframe_gpregs(UserX86RegsEntry *r) pr_info("SET_GS fail %ld\n", ret); return -1; } -#endif return 0; } +#ifdef CONFIG_COMPAT asm ( " .pushsection .text \n" " .global restore_set_thread_area \n" " .code32 \n" @@ -90,3 +89,4 @@ void restore_tls(tls_t *ptls) if (stack32) free_compat_syscall_stack(stack32); } +#endif diff --git a/criu/arch/x86/sys-exec-tbl.c b/criu/arch/x86/sys-exec-tbl.c index ca45ef0d3..f52578736 100644 --- a/criu/arch/x86/sys-exec-tbl.c +++ b/criu/arch/x86/sys-exec-tbl.c @@ -1,15 +1,15 @@ -#ifdef CONFIG_X86_64 static struct syscall_exec_desc sc_exec_table_64[] = { #include "sys-exec-tbl-64.c" { }, /* terminator */ }; -#endif +#ifdef CONFIG_COMPAT static struct syscall_exec_desc sc_exec_table_32[] = { #include "sys-exec-tbl-32.c" { }, /* terminator */ }; +#endif struct syscall_exec_desc; @@ -26,7 +26,7 @@ find_syscall_table(char *name, struct syscall_exec_desc *tbl) #define ARCH_HAS_FIND_SYSCALL /* overwrite default to search in two tables above */ -#ifdef CONFIG_X86_64 +#ifdef CONFIG_COMPAT struct syscall_exec_desc * find_syscall(char *name, struct parasite_ctl *ctl) { if (seized_native(ctl)) @@ -38,6 +38,6 @@ struct syscall_exec_desc * find_syscall(char *name, struct parasite_ctl *ctl) struct syscall_exec_desc * find_syscall(char *name, __always_unused struct parasite_ctl *ctl) { - return find_syscall_table(name, sc_exec_table_32); + return find_syscall_table(name, sc_exec_table_64); } #endif diff --git a/criu/page-pipe.c b/criu/page-pipe.c index a015d02e5..bdf72fb24 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -299,11 +299,11 @@ void debug_show_page_pipe(struct page_pipe *pp) if (pp->flags & PP_COMPAT) { iov_c = (void *)ppb->iov; pr_debug("\t\t%x %lu\n", iov_c[i].iov_base, - iov_c[i].iov_len / PAGE_SIZE); + (unsigned long) iov_c[i].iov_len / PAGE_SIZE); } else { iov = &ppb->iov[i]; pr_debug("\t\t%p %lu\n", iov->iov_base, - iov->iov_len / PAGE_SIZE); + (unsigned long) iov->iov_len / PAGE_SIZE); } } } @@ -313,11 +313,11 @@ void debug_show_page_pipe(struct page_pipe *pp) if (pp->flags & PP_COMPAT) { iov_c = (void *)pp->holes; pr_debug("\t%x %lu\n", iov_c[i].iov_base, - iov_c[i].iov_len / PAGE_SIZE); + (unsigned long) iov_c[i].iov_len / PAGE_SIZE); } else { iov = &pp->holes[i]; pr_debug("\t%p %lu\n", iov->iov_base, - iov->iov_len / PAGE_SIZE); + (unsigned long) iov->iov_len / PAGE_SIZE); } } } diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 50d06410f..65fb12a2b 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -1489,7 +1489,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, if (seized_native(ctl)) parasite_size = pie_size(parasite_native); -#ifdef CONFIG_X86_64 /* compat blob isn't defined for other archs */ +#ifdef CONFIG_COMPAT else parasite_size = pie_size(parasite_compat); #endif @@ -1513,7 +1513,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, if (seized_native(ctl)) init_parasite_ctl(ctl, native); -#ifdef CONFIG_X86_64 /* compat blob isn't defined for other archs */ +#ifdef CONFIG_COMPAT else init_parasite_ctl(ctl, compat); #endif diff --git a/criu/pie/Makefile b/criu/pie/Makefile index cc8b69f20..1c5baeff0 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -2,7 +2,7 @@ # restorer is always native (64-bit) parasite_target := native -ifeq ($(ARCH),x86) +ifeq ($(CONFIG_COMPAT),y) parasite_target += compat endif @@ -14,8 +14,11 @@ restorer-obj-y += ./$(ARCH_DIR)/restorer.o ifeq ($(ARCH),x86) restorer-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o - restorer-obj-y += ./$(ARCH_DIR)/call32.o - restorer-obj-y += ./$(ARCH_DIR)/sigaction_compat_pie.o + + ifeq ($(CONFIG_COMPAT),y) + restorer-obj-y += ./$(ARCH_DIR)/call32.o + restorer-obj-y += ./$(ARCH_DIR)/sigaction_compat_pie.o + endif native-obj-y += ./$(ARCH_DIR)/parasite-head-64.o native-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 136799ab8..debd27d00 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -6,11 +6,12 @@ CFLAGS += -Wa,--noexecstack -fno-stack-protector -DCR_NOGLIBC CFLAGS_native += -fpie ifeq ($(ARCH),x86) - target += compat + ifeq ($(CONFIG_COMPAT),y) + target += compat + native-lib-y += util-vdso-elf32.o + endif CFLAGS_native += -DCONFIG_X86_64 CFLAGS_compat += -fno-pic -m32 -DCONFIG_X86_32 - - native-lib-y += util-vdso-elf32.o CFLAGS_util-vdso-elf32.o += -DCONFIG_X86_32 endif diff --git a/criu/pie/parasite-blob.h b/criu/pie/parasite-blob.h index 796d36ed2..ddafd05f5 100644 --- a/criu/pie/parasite-blob.h +++ b/criu/pie/parasite-blob.h @@ -1,5 +1,5 @@ #include "parasite-native-blob.h" -#ifdef CONFIG_X86_64 +#ifdef CONFIG_COMPAT # include "parasite-compat-blob.h" #endif From ec58dcab745f3dbb17ae3f46c1559413b16e49c2 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 16 Sep 2016 21:37:10 +0300 Subject: [PATCH 0082/4375] parasite/x86: introduce&use builtin_memset Don't use compiler-provided memset in parasite. Fixes: commit 86434deba0b4 ("x86: dump TLS entries from GDT"). Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/include/asm/parasite.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/criu/arch/x86/include/asm/parasite.h b/criu/arch/x86/include/asm/parasite.h index d238327db..7f9c16033 100644 --- a/criu/arch/x86/include/asm/parasite.h +++ b/criu/arch/x86/include/asm/parasite.h @@ -1,6 +1,8 @@ #ifndef __ASM_PARASITE_H__ #define __ASM_PARASITE_H__ +#include "asm-generic/string.h" + #ifdef CONFIG_X86_32 # define __parasite_entry __attribute__((regparm(3))) #endif @@ -50,7 +52,7 @@ static void arch_get_tls(tls_t *ptls) { user_desc_t *d = &ptls->desc[i]; - memset(d, 0, sizeof(user_desc_t)); + builtin_memset(d, 0, sizeof(user_desc_t)); d->entry_number = GDT_ENTRY_TLS_MIN + i; arch_get_user_desc(d); } From 3c85c5350a2ed985619ac56d3cb4d43ef39b2a49 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 16 Sep 2016 21:37:11 +0300 Subject: [PATCH 0083/4375] make/x86: get cflags for ia32 from compel tool I think, we could transpher also `-m elf_i386' and `-m32' to compel output - but only in case if we will not support native x86_32 in compel (as they are wrong for native build). Or introduce something like compat_ia32 in compel option, not sure. Left in makefile for a while. Also it would be good to remove $(LD_R) in makefile and use compel output for ldflags, but that will be valid only when compel will support arm arch. Fixes (with the following patches): GEN criu/pie/parasite-compat-blob.h parasite_compat_blob: Error (compel/handle-elf-32.c:322): Unexpected undefined symbol: `__stack_chk_fail'. External symbol in PIE? Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 1c5baeff0..eff91cc70 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -58,11 +58,14 @@ CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 ccflags-y += -DCR_NOGLIBC ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) NATIVE_CFLAGS := $(shell $(SRC_DIR)/compel/compel --arch=$(ARCH) cflags) +ifeq ($(ARCH),x86) + COMPAT_CFLAGS := $(shell $(SRC_DIR)/compel/compel --arch=ia32 cflags) +endif endif ifeq ($(ARCH),x86) NATIVE_CFLAGS += -DCONFIG_X86_64 - COMPAT_CFLAGS += -fno-pic -m32 -DCONFIG_X86_32 + COMPAT_CFLAGS += -m32 -DCONFIG_X86_32 COMPAT_LDFLAGS += -m elf_i386 endif From 281572bd707dd067792a4850083f36404d4b7f4d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 16 Sep 2016 21:37:12 +0300 Subject: [PATCH 0084/4375] pie: provide callbacks for stack-protector The other way to solve this is to compile shared between CRIU and PIEs objects twice: without stack-protection and with environment choice. But I don't think it worth it. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/parasite.c | 18 ++++++++++++++++++ criu/pie/restorer.c | 11 +++++++++++ 2 files changed, 29 insertions(+) diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index 45e5e79e9..8694668a5 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -867,3 +867,21 @@ int __used __parasite_entry parasite_service(unsigned int cmd, void *args) return parasite_trap_cmd(cmd, args); } + +/* + * Mainally, -fstack-protector is disabled for parasite. + * But we share some object files, compiled for CRIU with parasite. + * Those files (like cpu.c) may be compiled with stack protector + * support. We can't use gcc-ld provided stackprotector callback, + * as Glibc is unmapped. Let's just try to cure application in + * case of stack smashing in parasite. + */ +void __stack_chk_fail(void) +{ + /* + * Smash didn't happen in printing part, as it's not shared + * with CRIU, therefore compiled with -fnostack-protector. + */ + pr_err("Stack smash detected in parasite\n"); + fini(); +} diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index bb129787c..ba37ff4ca 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1504,3 +1504,14 @@ core_restore_end: sys_exit_group(1); return -1; } + +/* + * For most of the restorer's objects -fstack-protector is disabled. + * But we share some of them with CRIU, which may have it enabled. + */ +void __stack_chk_fail(void) +{ + pr_err("Restorer stack smash detected %ld\n", sys_getpid()); + sys_exit_group(1); + BUG(); +} From 693f56fdd88747dbfd427ff110b58e8913e601c6 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 16 Sep 2016 21:37:13 +0300 Subject: [PATCH 0085/4375] parasite-vdso: vdso_map_compat under CONFIG_COMPAT It's used in restorer to map compatible vDSO blob. When !CONFIG_COMPAT it's not needed and even more: vdso_fill_symtable_compat is macro and is undefined in that case. It will never shoot, as compat_vdso is always false for that case, but get rid of it. I also need to leave CONFIG_X86_64 here, as arch_prctl() is not defined for x86_32. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/parasite-vdso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 512186c7a..03a3f0e0d 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -68,7 +68,7 @@ int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned l return ret; } -#ifdef CONFIG_X86_64 +#if defined(CONFIG_X86_64) && defined(CONFIG_COMPAT) #ifndef ARCH_MAP_VDSO_32 # define ARCH_MAP_VDSO_32 0x2002 #endif From 745b26a7a28c9f53b4a1ad1e5d065e89f9f45469 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 16 Sep 2016 21:37:14 +0300 Subject: [PATCH 0086/4375] compel: abort PIE generation on undefined/external symbols As we meet this before, I think, we should abort generation here. No point for making PIE with external symbols for us (at least, yet), so let's break build than find the problem at runtime. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/handle-elf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compel/handle-elf.c b/compel/handle-elf.c index be001720f..0d598468c 100644 --- a/compel/handle-elf.c +++ b/compel/handle-elf.c @@ -319,7 +319,8 @@ int __handle_elf(void *mem, size_t size) goto err; } #else - continue; + pr_err("Unexpected undefined symbol: `%s'. External symbol in PIE?\n", name); + goto err; #endif } From 2acc20056b35f2eb2530291f4a4b7a43701be1eb Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 21 Sep 2016 23:54:16 +0300 Subject: [PATCH 0087/4375] compel: build -- Add @sublevel Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile.versions | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.versions b/Makefile.versions index 3ea7ca681..59d74b485 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -26,5 +26,6 @@ export SOCCR_SO_VERSION_MAJOR SOCCR_SO_VERSION_MINOR COMPEL_SO_VERSION_MAJOR := 1 COMPEL_SO_VERSION_MINOR := 0 +COMPEL_SO_VERSION_SUBLEVEL := 0 -export COMPEL_SO_VERSION_MAJOR COMPEL_SO_VERSION_MINOR +export COMPEL_SO_VERSION_MAJOR COMPEL_SO_VERSION_MINOR COMPEL_SO_VERSION_SUBLEVEL From 596767d5f7540f3b93e4320062f37de6f76c2017 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 21 Sep 2016 23:54:17 +0300 Subject: [PATCH 0088/4375] compel: uapi -- Add standalone headers Will be used later. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/compel.h | 27 +++++++++++++++++++++++++++ compel/include/uapi/int.h | 15 +++++++++++++++ compel/include/uapi/types.h | 16 +--------------- 3 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 compel/include/uapi/compel.h create mode 100644 compel/include/uapi/int.h mode change 100644 => 120000 compel/include/uapi/types.h diff --git a/compel/include/uapi/compel.h b/compel/include/uapi/compel.h new file mode 100644 index 000000000..67b67c476 --- /dev/null +++ b/compel/include/uapi/compel.h @@ -0,0 +1,27 @@ +#ifndef UAPI_COMPEL_H__ +#define UAPI_COMPEL_H__ + +#include + +#define COMPEL_TYPE_INT (1u << 0) +#define COMPEL_TYPE_LONG (1u << 1) +#define COMPEL_TYPE_GOTPCREL (1u << 2) + +typedef struct { + unsigned int offset; + unsigned int type; + long addend; + long value; +} compel_reloc_t; + +/* + * FIXME: Backward compat layer for CRIU. Need to + * drop it later, before the release. + */ + +#define elf_reloc_t compel_reloc_t +#define PIEGEN_TYPE_INT COMPEL_TYPE_INT +#define PIEGEN_TYPE_LONG COMPEL_TYPE_LONG +#define PIEGEN_TYPE_GOTPCREL COMPEL_TYPE_GOTPCREL + +#endif /* UAPI_COMPEL_H__ */ diff --git a/compel/include/uapi/int.h b/compel/include/uapi/int.h new file mode 100644 index 000000000..ac3088d5a --- /dev/null +++ b/compel/include/uapi/int.h @@ -0,0 +1,15 @@ +#ifndef __CR_INT_H__ +#define __CR_INT_H__ + +#include + +typedef uint64_t u64; +typedef int64_t s64; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint8_t u8; +typedef int8_t s8; + +#endif /* __CR_INT_H__ */ diff --git a/compel/include/uapi/types.h b/compel/include/uapi/types.h deleted file mode 100644 index 34696e8c6..000000000 --- a/compel/include/uapi/types.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __PIEGEN_TYPES_H__ -#define __PIEGEN_TYPES_H__ - -#define PIEGEN_TYPE_INT (1u << 0) -#define PIEGEN_TYPE_LONG (1u << 1) -#define PIEGEN_TYPE_GOTPCREL (1u << 2) - -typedef struct { - unsigned int offset; - unsigned int type; - long addend; - long value; -} elf_reloc_t; - -#endif /* __PIEGEN_TYPES_H__ */ diff --git a/compel/include/uapi/types.h b/compel/include/uapi/types.h new file mode 120000 index 000000000..28c80ee9f --- /dev/null +++ b/compel/include/uapi/types.h @@ -0,0 +1 @@ +compel.h \ No newline at end of file From 3b0c8dbd4837e2a8b7bfb656b433b7fd6c7523b5 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 21 Sep 2016 23:54:18 +0300 Subject: [PATCH 0089/4375] compel: Reshuffle the directories structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Here we rather suffle source code into directories preparing ground for future work. Basically all this files movements should end up in the following compel/ tree structure compel/ ├── arch │ ├── aarch64 │ │ ├── plugins │ │ │ └── std │ │ └── src │ │ └── lib │ ├── arm ... │ ├── ppc64 ... │ └── x86 ... This is architectural part, where each arch consists of plugins/, and src/. src/ stands for code needed by compel cli + lib ├── include │ ├── compiler.h -> ../../criu/include/compiler.h │ ├── elf32-types.h │ ├── elf64-types.h │ ├── int.h -> ../../criu/include/asm-generic/int.h │ ├── piegen.h │ ├── shmem.h │ └── uapi │ ├── compel.h │ └── plugins.h Common includes + uapi ├── plugins │ ├── fds │ ├── shmem │ └── std Plugins source code └── src ├── lib │ ├── handle-elf-32.c -> handle-elf.c │ ├── handle-elf-32-host.c -> handle-elf-32.c │ ├── handle-elf.c │ └── handle-elf-host.c -> handle-elf.c compel library ├── main.c ├── main-host.c -> main.c compel cli └── shared └── fds.c shared code between plugins and compel cli Note: cross-compile won't work for a while. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 8 +- Makefile.compel | 35 ++++++ compel/Makefile | 49 +++------ compel/arch/aarch64/handle-elf.c | 21 ---- compel/arch/aarch64/include/handle-elf.h | 11 -- compel/arch/aarch64/src/lib/handle-elf.c | 34 ++++++ .../arch/aarch64/src/lib/include/handle-elf.h | 11 ++ compel/arch/arm/include/handle-elf.h | 11 -- compel/arch/arm/{ => src/lib}/handle-elf.c | 13 ++- compel/arch/arm/src/lib/include/handle-elf.h | 11 ++ compel/arch/ppc64/handle-elf.c | 21 ---- compel/arch/ppc64/include/handle-elf.h | 12 -- compel/arch/ppc64/src/lib/handle-elf.c | 34 ++++++ .../arch/ppc64/src/lib/include/handle-elf.h | 13 +++ compel/arch/x86/handle-elf.c | 16 --- compel/arch/x86/src/lib/handle-elf.c | 29 +++++ .../x86/{ => src/lib}/include/handle-elf.h | 18 +-- compel/include/elf32-types.h | 16 +++ compel/include/elf64-types.h | 16 +++ compel/include/piegen.h | 22 +--- compel/include/uapi/elf32-types.h | 20 ---- compel/include/uapi/elf64-types.h | 20 ---- compel/include/uapi/piegen-err.h | 10 -- compel/{ => src/lib}/handle-elf-32.c | 0 compel/{ => src/lib}/handle-elf.c | 103 ++++++++++-------- compel/{ => src}/main.c | 1 + 26 files changed, 300 insertions(+), 255 deletions(-) create mode 100644 Makefile.compel delete mode 100644 compel/arch/aarch64/handle-elf.c delete mode 100644 compel/arch/aarch64/include/handle-elf.h create mode 100644 compel/arch/aarch64/src/lib/handle-elf.c create mode 100644 compel/arch/aarch64/src/lib/include/handle-elf.h delete mode 100644 compel/arch/arm/include/handle-elf.h rename compel/arch/arm/{ => src/lib}/handle-elf.c (54%) create mode 100644 compel/arch/arm/src/lib/include/handle-elf.h delete mode 100644 compel/arch/ppc64/handle-elf.c delete mode 100644 compel/arch/ppc64/include/handle-elf.h create mode 100644 compel/arch/ppc64/src/lib/handle-elf.c create mode 100644 compel/arch/ppc64/src/lib/include/handle-elf.h delete mode 100644 compel/arch/x86/handle-elf.c create mode 100644 compel/arch/x86/src/lib/handle-elf.c rename compel/arch/x86/{ => src/lib}/include/handle-elf.h (59%) create mode 100644 compel/include/elf32-types.h create mode 100644 compel/include/elf64-types.h delete mode 100644 compel/include/uapi/elf32-types.h delete mode 100644 compel/include/uapi/elf64-types.h delete mode 100644 compel/include/uapi/piegen-err.h rename compel/{ => src/lib}/handle-elf-32.c (100%) rename compel/{ => src/lib}/handle-elf.c (88%) rename compel/{ => src}/main.c (99%) diff --git a/Makefile b/Makefile index 6176f2349..1c8702beb 100644 --- a/Makefile +++ b/Makefile @@ -201,12 +201,9 @@ $(eval $(call gen-built-in,images)) .PHONY: .FORCE +# # Compel get used by CRIU, build it earlier -compel/%: .FORCE - $(Q) $(MAKE) $(build)=compel $@ - -test/compel/%: .FORCE - $(Q) $(MAKE) $(build)=compel $@ +include Makefile.compel # # Next the socket CR library @@ -269,6 +266,7 @@ mrproper: subclean $(Q) $(RM) $(CONFIG_HEADER) $(Q) $(RM) $(SOCCR_CONFIG) $(Q) $(RM) $(VERSION_HEADER) + $(Q) $(RM) $(COMPEL_VERSION_HEADER) $(Q) $(RM) include/common/asm $(Q) $(RM) cscope.* $(Q) $(RM) tags TAGS diff --git a/Makefile.compel b/Makefile.compel new file mode 100644 index 000000000..dd60defbf --- /dev/null +++ b/Makefile.compel @@ -0,0 +1,35 @@ +COMPEL_VERSION_HEADER := compel/include/version.h + +$(COMPEL_VERSION_HEADER): $(SRC_DIR)/Makefile.versions + $(call msg-gen, $(COMPEL_VERSION_HEADER)) + $(E) " GEN " $@ + $(Q) echo "/* Autogenerated, do not edit */" > $(COMPEL_VERSION_HEADER) + $(Q) echo "#ifndef COMPEL_SO_VERSION_H__" >> $(COMPEL_VERSION_HEADER) + $(Q) echo "#define COMPEL_SO_VERSION_H__" >> $(COMPEL_VERSION_HEADER) + $(Q) echo "#define COMPEL_SO_VERSION \"$(COMPEL_SO_VERSION)\"" >> $(COMPEL_VERSION_HEADER) + $(Q) echo "#define COMPEL_SO_VERSION_MAJOR " $(COMPEL_SO_VERSION_MAJOR) >> $(COMPEL_VERSION_HEADER) + $(Q) echo "#define COMPEL_SO_VERSION_MINOR " $(COMPEL_SO_VERSION_MINOR) >> $(COMPEL_VERSION_HEADER) + $(Q) echo "#define COMPEL_SO_VERSION_SUBLEVEL " $(COMPEL_SO_VERSION_SUBLEVEL) >> $(COMPEL_VERSION_HEADER) + $(Q) echo "#endif /* COMPEL_SO_VERSION_H__ */" >> $(COMPEL_VERSION_HEADER) + +# +# Compel itself. +compel/%: $(COMPEL_VERSION_HEADER) $(CONFIG_HEADER) .FORCE + $(Q) $(MAKE) $(build)=compel $@ + +# +# Plugins +compel/plugins/%: $(COMPEL_VERSION_HEADER) $(CONFIG_HEADER) .FORCE + $(Q) $(MAKE) $(build)=compel/plugins $@ + +compel/compel: compel/built-in.o compel/lib.a $(COMPEL_VERSION_HEADER) + $(call msg-link, $@) + $(Q) $(CC) $(CFLAGS) $^ $(WRAPFLAGS) $(LDFLAGS) -rdynamic -o $@ + +# +# And compel library. +LIBCOMPEL_SO := libcompel.so +LIBCOMPEL_SO_CFLAGS += $(CFLAGS) -rdynamic -Wl,-soname,$(LIBCOMPEL_SO).$(COMPEL_SO_VERSION_MAJOR) +compel/$(LIBCOMPEL_SO): compel/lib.a + $(call msg-link, $@) + $(Q) $(CC) -shared $(LIBCOMPEL_SO_CFLAGS) -o $@ -Wl,--whole-archive $^ -Wl,--no-whole-archive $(LDFLAGS) diff --git a/compel/Makefile b/compel/Makefile index 5166e9318..52eb27ea7 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -1,38 +1,23 @@ include $(SRC_DIR)/Makefile.versions -ccflags-y += -iquote criu/include -ccflags-y += -iquote compel/include -ccflags-y += -iquote compel/arch/$(ARCH)/include -ccflags-y += -DCOMPEL_VERSION=\"$(COMPEL_SO_VERSION_MAJOR).$(COMPEL_SO_VERSION_MINOR)\" - -host-ccflags-y += $(filter-out -pg $(CFLAGS-GCOV),$(ccflags-y)) -HOSTCFLAGS += $(filter-out -pg $(CFLAGS-GCOV),$(WARNINGS) $(DEFINES)) -HOSTLDFLAGS += $(filter-out -pg $(CFLAGS-GCOV),$(LDFLAGS)) -HOSTCFLAGS := $(filter-out -DCONFIG_X86_64,$(HOSTCFLAGS)) -export host-ccflags-y HOSTCFLAGS HOSTLDFLAGS - -hostprogs-y += compel -compel-objs += main.o -compel-objs += handle-elf.o -compel-objs += arch/$(ARCH)/handle-elf.o - -ifeq ($(ARCH),x86) -# Add -DCONFIG_X86_64 or -DCONFIG_X86_32 to HOSTCFLAGS -define ccflags-defines - export HOSTCFLAGS_$(notdir $(1)) += -DCONFIG_X86_64 -endef -$(eval $(call map,ccflags-defines,$(compel-objs))) - -compel-objs += handle-elf-32.o -export HOSTCFLAGS_handle-elf-32.o += -DCONFIG_X86_32 -endif # ARCH == x86 - .PHONY: .FORCE -export compel-objs -test/compel/%: .FORCE - $(Q) $(MAKE) $(build)=test/compel $@ +COMPEL_SO_VERSION := $(COMPEL_SO_VERSION_MAJOR)$(if $(COMPEL_SO_VERSION_MINOR),.$(COMPEL_SO_VERSION_MINOR))$(if $(COMPEL_SO_VERSION_SUBLEVEL),.$(COMPEL_SO_VERSION_SUBLEVEL)) +COMPEL_SO_VERSION_CODE := $(shell expr $(COMPEL_SO_VERSION_MAJOR) \* 65536 \+ $(COMPEL_SO_VERSION_MINOR) \* 256 \+ $(COMPEL_SO_VERSION_SUBLEVEL)) +ccflags-y += -iquote compel/arch/$(ARCH)/src/lib/include +ccflags-y += -iquote compel/include +ccflags-y += -iquote compel/plugins/include +ccflags-y += -iquote $(SRC_DIR)/criu/include +ccflags-y += -fPIC -test: test/compel/test_handle_binary +lib-y += arch/$(ARCH)/src/lib/handle-elf.o +lib-y += src/lib/handle-elf.o +lib-y += src/lib/handle-elf-32.o -.PHONY: test +obj-y += src/main.o + +CFLAGS_handle-elf-32.o += -UCONFIG_X86_64 -DCONFIG_X86_32 +CFLAGS_handle-elf-32.d += -UCONFIG_X86_64 -DCONFIG_X86_32 + +cleanup-y += compel/compel +cleanup-y += compel/libcompel.so diff --git a/compel/arch/aarch64/handle-elf.c b/compel/arch/aarch64/handle-elf.c deleted file mode 100644 index bbd4bf1b0..000000000 --- a/compel/arch/aarch64/handle-elf.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -#include "piegen.h" -#include "uapi/piegen-err.h" -#include "handle-elf.h" - -int handle_binary(void *mem, size_t size) -{ - const unsigned char *elf_ident = -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - elf_ident_64_le; -#else - elf_ident_64_be; -#endif - - if (memcmp(mem, elf_ident, sizeof(elf_ident_64_le)) == 0) - return handle_elf_aarch64(mem, size); - - pr_err("Unsupported Elf format detected\n"); - return -E_NOT_ELF; -} diff --git a/compel/arch/aarch64/include/handle-elf.h b/compel/arch/aarch64/include/handle-elf.h deleted file mode 100644 index 7d7bfb7b3..000000000 --- a/compel/arch/aarch64/include/handle-elf.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __COMPEL_HANDLE_ELF_H__ -#define __COMPEL_HANDLE_ELF_H__ - -#include "uapi/elf64-types.h" - -#define __handle_elf handle_elf_aarch64 -#define arch_is_machine_supported(e_machine) (e_machine == EM_AARCH64) - -extern int handle_elf_aarch64(void *mem, size_t size); - -#endif /* __COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/arch/aarch64/src/lib/handle-elf.c b/compel/arch/aarch64/src/lib/handle-elf.c new file mode 100644 index 000000000..633a382cc --- /dev/null +++ b/compel/arch/aarch64/src/lib/handle-elf.c @@ -0,0 +1,34 @@ +#include + +#include "uapi/compel.h" + +#include "handle-elf.h" +#include "piegen.h" + +static const unsigned char __maybe_unused +elf_ident_64_le[EI_NIDENT] = { + 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char __maybe_unused +elf_ident_64_be[EI_NIDENT] = { + 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x02, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +int handle_binary(void *mem, size_t size) +{ + const unsigned char *elf_ident = +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + elf_ident_64_le; +#else + elf_ident_64_be; +#endif + + if (memcmp(mem, elf_ident, sizeof(elf_ident_64_le)) == 0) + return handle_elf_aarch64(mem, size); + + pr_err("Unsupported Elf format detected\n"); + return -EINVAL; +} diff --git a/compel/arch/aarch64/src/lib/include/handle-elf.h b/compel/arch/aarch64/src/lib/include/handle-elf.h new file mode 100644 index 000000000..0f64b34cb --- /dev/null +++ b/compel/arch/aarch64/src/lib/include/handle-elf.h @@ -0,0 +1,11 @@ +#ifndef COMPEL_HANDLE_ELF_H__ +#define COMPEL_HANDLE_ELF_H__ + +#include "elf64-types.h" + +#define __handle_elf handle_elf_aarch64 +#define arch_is_machine_supported(e_machine) (e_machine == EM_AARCH64) + +extern int handle_elf_aarch64(void *mem, size_t size); + +#endif /* COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/arch/arm/include/handle-elf.h b/compel/arch/arm/include/handle-elf.h deleted file mode 100644 index a465f4273..000000000 --- a/compel/arch/arm/include/handle-elf.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __COMPEL_HANDLE_ELF_H__ -#define __COMPEL_HANDLE_ELF_H__ - -#include "uapi/elf32-types.h" - -#define __handle_elf handle_elf_arm -#define arch_is_machine_supported(e_machine) (e_machine == EM_ARM) - -extern int handle_elf_arm(void *mem, size_t size); - -#endif /* __COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/arch/arm/handle-elf.c b/compel/arch/arm/src/lib/handle-elf.c similarity index 54% rename from compel/arch/arm/handle-elf.c rename to compel/arch/arm/src/lib/handle-elf.c index 2692439c7..e2df0f90d 100644 --- a/compel/arch/arm/handle-elf.c +++ b/compel/arch/arm/src/lib/handle-elf.c @@ -1,8 +1,15 @@ #include -#include "piegen.h" -#include "uapi/piegen-err.h" +#include "uapi/compel.h" + #include "handle-elf.h" +#include "piegen.h" + +static const unsigned char __maybe_unused +elf_ident_32[EI_NIDENT] = { + 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; int handle_binary(void *mem, size_t size) { @@ -10,5 +17,5 @@ int handle_binary(void *mem, size_t size) return handle_elf_arm(mem, size); pr_err("Unsupported Elf format detected\n"); - return -E_NOT_ELF; + return -EINVAL; } diff --git a/compel/arch/arm/src/lib/include/handle-elf.h b/compel/arch/arm/src/lib/include/handle-elf.h new file mode 100644 index 000000000..e5971f37b --- /dev/null +++ b/compel/arch/arm/src/lib/include/handle-elf.h @@ -0,0 +1,11 @@ +#ifndef COMPEL_HANDLE_ELF_H__ +#define COMPEL_HANDLE_ELF_H__ + +#include "elf32-types.h" + +#define __handle_elf handle_elf_arm +#define arch_is_machine_supported(e_machine) (e_machine == EM_ARM) + +extern int handle_elf_arm(void *mem, size_t size); + +#endif /* COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/arch/ppc64/handle-elf.c b/compel/arch/ppc64/handle-elf.c deleted file mode 100644 index 049e3fba0..000000000 --- a/compel/arch/ppc64/handle-elf.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -#include "piegen.h" -#include "uapi/piegen-err.h" -#include "handle-elf.h" - -int handle_binary(void *mem, size_t size) -{ - const unsigned char *elf_ident = -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - elf_ident_64_le; -#else - elf_ident_64_be; -#endif - - if (memcmp(mem, elf_ident, sizeof(elf_ident_64_le)) == 0) - return handle_elf_ppc64(mem, size); - - pr_err("Unsupported Elf format detected\n"); - return -E_NOT_ELF; -} diff --git a/compel/arch/ppc64/include/handle-elf.h b/compel/arch/ppc64/include/handle-elf.h deleted file mode 100644 index b324debdf..000000000 --- a/compel/arch/ppc64/include/handle-elf.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __COMPEL_HANDLE_ELF_H__ -#define __COMPEL_HANDLE_ELF_H__ - -#include "uapi/elf64-types.h" - -#define ELF_PPC64 -#define __handle_elf handle_elf_ppc64 -#define arch_is_machine_supported(e_machine) (e_machine == EM_PPC64) - -extern int handle_elf_ppc64(void *mem, size_t size); - -#endif /* __COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/arch/ppc64/src/lib/handle-elf.c b/compel/arch/ppc64/src/lib/handle-elf.c new file mode 100644 index 000000000..6491f2085 --- /dev/null +++ b/compel/arch/ppc64/src/lib/handle-elf.c @@ -0,0 +1,34 @@ +#include + +#include "uapi/compel.h" + +#include "handle-elf.h" +#include "piegen.h" + +static const unsigned char __maybe_unused +elf_ident_64_le[EI_NIDENT] = { + 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char __maybe_unused +elf_ident_64_be[EI_NIDENT] = { + 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x02, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +int handle_binary(void *mem, size_t size) +{ + const unsigned char *elf_ident = +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + elf_ident_64_le; +#else + elf_ident_64_be; +#endif + + if (memcmp(mem, elf_ident, sizeof(elf_ident_64_le)) == 0) + return handle_elf_ppc64(mem, size); + + pr_err("Unsupported Elf format detected\n"); + return -EINVAL; +} diff --git a/compel/arch/ppc64/src/lib/include/handle-elf.h b/compel/arch/ppc64/src/lib/include/handle-elf.h new file mode 100644 index 000000000..1a8217e6b --- /dev/null +++ b/compel/arch/ppc64/src/lib/include/handle-elf.h @@ -0,0 +1,13 @@ +#ifndef COMPEL_HANDLE_ELF_H__ +#define COMPEL_HANDLE_ELF_H__ + +#include "elf64-types.h" + +#define ELF_PPC64 + +#define __handle_elf handle_elf_ppc64 +#define arch_is_machine_supported(e_machine) (e_machine == EM_PPC64) + +extern int handle_elf_ppc64(void *mem, size_t size); + +#endif /* COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/arch/x86/handle-elf.c b/compel/arch/x86/handle-elf.c deleted file mode 100644 index 9edb94262..000000000 --- a/compel/arch/x86/handle-elf.c +++ /dev/null @@ -1,16 +0,0 @@ -#include - -#include "piegen.h" -#include "uapi/piegen-err.h" -#include "handle-elf.h" - -int handle_binary(void *mem, size_t size) -{ - if (memcmp(mem, elf_ident_32, sizeof(elf_ident_32)) == 0) - return handle_elf_x86_32(mem, size); - else if (memcmp(mem, elf_ident_64_le, sizeof(elf_ident_64_le)) == 0) - return handle_elf_x86_64(mem, size); - - pr_err("Unsupported Elf format detected\n"); - return -E_NOT_ELF; -} diff --git a/compel/arch/x86/src/lib/handle-elf.c b/compel/arch/x86/src/lib/handle-elf.c new file mode 100644 index 000000000..7cfbaa1dd --- /dev/null +++ b/compel/arch/x86/src/lib/handle-elf.c @@ -0,0 +1,29 @@ +#include + +#include "uapi/compel.h" + +#include "handle-elf.h" +#include "piegen.h" + +static const unsigned char __maybe_unused +elf_ident_64_le[EI_NIDENT] = { + 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char __maybe_unused +elf_ident_32[EI_NIDENT] = { + 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +int handle_binary(void *mem, size_t size) +{ + if (memcmp(mem, elf_ident_32, sizeof(elf_ident_32)) == 0) + return handle_elf_x86_32(mem, size); + else if (memcmp(mem, elf_ident_64_le, sizeof(elf_ident_64_le)) == 0) + return handle_elf_x86_64(mem, size); + + pr_err("Unsupported Elf format detected\n"); + return -EINVAL; +} diff --git a/compel/arch/x86/include/handle-elf.h b/compel/arch/x86/src/lib/include/handle-elf.h similarity index 59% rename from compel/arch/x86/include/handle-elf.h rename to compel/arch/x86/src/lib/include/handle-elf.h index eea94d463..bfc935a4e 100644 --- a/compel/arch/x86/include/handle-elf.h +++ b/compel/arch/x86/src/lib/include/handle-elf.h @@ -1,18 +1,22 @@ -#ifndef __COMPEL_HANDLE_ELF_H__ -#define __COMPEL_HANDLE_ELF_H__ +#ifndef COMPEL_HANDLE_ELF_H__ +#define COMPEL_HANDLE_ELF_H__ #ifdef CONFIG_X86_32 -#include "uapi/elf32-types.h" +#include "elf32-types.h" + #define ELF_X86_32 -#define __handle_elf handle_elf_x86_32 + +#define __handle_elf handle_elf_x86_32 #define arch_is_machine_supported(e_machine) (e_machine == EM_386) #else /* CONFIG_X86_64 */ -#include "uapi/elf64-types.h" +#include "elf64-types.h" + #define ELF_X86_64 -#define __handle_elf handle_elf_x86_64 + +#define __handle_elf handle_elf_x86_64 #define arch_is_machine_supported(e_machine) (e_machine == EM_X86_64) #endif @@ -20,4 +24,4 @@ extern int handle_elf_x86_32(void *mem, size_t size); extern int handle_elf_x86_64(void *mem, size_t size); -#endif /* __COMPEL_HANDLE_ELF_H__ */ +#endif /* COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/include/elf32-types.h b/compel/include/elf32-types.h new file mode 100644 index 000000000..b516ba17e --- /dev/null +++ b/compel/include/elf32-types.h @@ -0,0 +1,16 @@ +#ifndef COMPEL_ELF32_TYPES_H__ +#define COMPEL_ELF32_TYPES_H__ + +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Rel Elf32_Rel +#define Elf_Rela Elf32_Rela + +#define ELF_ST_TYPE ELF32_ST_TYPE +#define ELF_ST_BIND ELF32_ST_BIND + +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE + +#endif /* COMPEL_ELF32_TYPES_H__ */ diff --git a/compel/include/elf64-types.h b/compel/include/elf64-types.h new file mode 100644 index 000000000..c4d5f1c72 --- /dev/null +++ b/compel/include/elf64-types.h @@ -0,0 +1,16 @@ +#ifndef COMPEL_ELF64_TYPES_H__ +#define COMPEL_ELF64_TYPES_H__ + +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define Elf_Rel Elf64_Rel +#define Elf_Rela Elf64_Rela + +#define ELF_ST_TYPE ELF64_ST_TYPE +#define ELF_ST_BIND ELF64_ST_BIND + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE + +#endif /* COMPEL_ELF64_TYPES_H__ */ diff --git a/compel/include/piegen.h b/compel/include/piegen.h index 736152a2c..f1ed2e13d 100644 --- a/compel/include/piegen.h +++ b/compel/include/piegen.h @@ -1,5 +1,5 @@ -#ifndef __ELFTIL_H__ -#define __ELFTIL_H__ +#ifndef COMPEL_PIEGEN_H__ +#define COMPEL_PIEGEN_H__ #include #include @@ -51,20 +51,4 @@ do { \ extern int handle_binary(void *mem, size_t size); -static const unsigned char __maybe_unused -elf_ident_32[EI_NIDENT] = { - 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -static const unsigned char __maybe_unused -elf_ident_64_le[EI_NIDENT] = { - 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -static const unsigned char __maybe_unused -elf_ident_64_be[EI_NIDENT] = { - 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x02, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -#endif /* __ELFTIL_H__ */ +#endif /* COMPEL_PIEGEN_H__ */ diff --git a/compel/include/uapi/elf32-types.h b/compel/include/uapi/elf32-types.h deleted file mode 100644 index 51bf4a24a..000000000 --- a/compel/include/uapi/elf32-types.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __COMPEL_ELF32_TYPES_H__ -#define __COMPEL_ELF32_TYPES_H__ - -#define Ehdr_t Elf32_Ehdr -#define Shdr_t Elf32_Shdr -#define Sym_t Elf32_Sym -#define Rel_t Elf32_Rel -#define Rela_t Elf32_Rela - -#define Off_t Elf32_Off -#define Word_t Elf32_Word -#define Half_t Elf32_Half - -#define ELF_ST_TYPE ELF32_ST_TYPE -#define ELF_ST_BIND ELF32_ST_BIND - -#define ELF_R_SYM ELF32_R_SYM -#define ELF_R_TYPE ELF32_R_TYPE - -#endif /* __COMPEL_ELF32_TYPES_H__ */ diff --git a/compel/include/uapi/elf64-types.h b/compel/include/uapi/elf64-types.h deleted file mode 100644 index d4d6f6f16..000000000 --- a/compel/include/uapi/elf64-types.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __COMPEL_ELF64_TYPES_H__ -#define __COMPEL_ELF64_TYPES_H__ - -#define Ehdr_t Elf64_Ehdr -#define Shdr_t Elf64_Shdr -#define Sym_t Elf64_Sym -#define Rel_t Elf64_Rel -#define Rela_t Elf64_Rela - -#define Off_t Elf64_Off -#define Word_t Elf64_Word -#define Half_t Elf64_Half - -#define ELF_ST_TYPE ELF64_ST_TYPE -#define ELF_ST_BIND ELF64_ST_BIND - -#define ELF_R_SYM ELF64_R_SYM -#define ELF_R_TYPE ELF64_R_TYPE - -#endif /* __COMPEL_ELF64_TYPES_H__ */ diff --git a/compel/include/uapi/piegen-err.h b/compel/include/uapi/piegen-err.h deleted file mode 100644 index f8a2349a1..000000000 --- a/compel/include/uapi/piegen-err.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __PIEGEN_ERR_H__ -#define __PIEGEN_ERR_H__ - -/* Error numbers for piegen. Success is 0, so errors should differ. */ -#define E_UNKNOWN 1 -#define E_NOMEM 2 -#define E_NOT_ELF 3 -#define E_NO_STR_SEC 4 - -#endif /* __PIEGEN_ERR_H__ */ diff --git a/compel/handle-elf-32.c b/compel/src/lib/handle-elf-32.c similarity index 100% rename from compel/handle-elf-32.c rename to compel/src/lib/handle-elf-32.c diff --git a/compel/handle-elf.c b/compel/src/lib/handle-elf.c similarity index 88% rename from compel/handle-elf.c rename to compel/src/lib/handle-elf.c index 0d598468c..3aaa2a2fa 100644 --- a/compel/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -11,16 +11,15 @@ #include #include +#include "uapi/compel.h" + #include "asm-generic/int.h" -#include "uapi/piegen-err.h" -#include "piegen.h" #include "handle-elf.h" +#include "piegen.h" -/* TODO: merge with util-vdso.c part in criu header */ /* Check if pointer is out-of-bound */ -static bool -__ptr_oob(const uintptr_t ptr, const uintptr_t start, const size_t size) +static bool __ptr_oob(const uintptr_t ptr, const uintptr_t start, const size_t size) { uintptr_t end = start + size; @@ -29,7 +28,7 @@ __ptr_oob(const uintptr_t ptr, const uintptr_t start, const size_t size) /* Check if pointed structure's end is out-of-bound */ static bool __ptr_struct_end_oob(const uintptr_t ptr, const size_t struct_size, - const uintptr_t start, const size_t size) + const uintptr_t start, const size_t size) { /* the last byte of the structure should be inside [begin, end) */ return __ptr_oob(ptr + struct_size - 1, start, size); @@ -37,7 +36,7 @@ static bool __ptr_struct_end_oob(const uintptr_t ptr, const size_t struct_size, /* Check if pointed structure is out-of-bound */ static bool __ptr_struct_oob(const uintptr_t ptr, const size_t struct_size, - const uintptr_t start, const size_t size) + const uintptr_t start, const size_t size) { return __ptr_oob(ptr, start, size) || __ptr_struct_end_oob(ptr, struct_size, start, size); @@ -73,7 +72,8 @@ static int do_relative_toc(long value, uint16_t *location, } if ((~mask & 0xffff) & value) { - pr_err("bad TOC16 relocation (%ld) (0x%lx)\n", value, (~mask & 0xffff) & value); + pr_err("bad TOC16 relocation (%ld) (0x%lx)\n", + value, (~mask & 0xffff) & value); return -1; } @@ -82,7 +82,7 @@ static int do_relative_toc(long value, uint16_t *location, } #endif -static bool is_header_supported(Ehdr_t *hdr) +static bool is_header_supported(Elf_Ehdr *hdr) { if (!arch_is_machine_supported(hdr->e_machine)) return false; @@ -91,11 +91,11 @@ static bool is_header_supported(Ehdr_t *hdr) return true; } -static const char *get_strings_section(Ehdr_t *hdr, uintptr_t mem, size_t size) +static const char *get_strings_section(Elf_Ehdr *hdr, uintptr_t mem, size_t size) { size_t sec_table_size = ((size_t) hdr->e_shentsize) * hdr->e_shnum; uintptr_t sec_table = mem + hdr->e_shoff; - Shdr_t *secstrings_hdr; + Elf_Shdr *secstrings_hdr; uintptr_t addr; if (__ptr_struct_oob(sec_table, sec_table_size, mem, size)) { @@ -109,7 +109,7 @@ static const char *get_strings_section(Ehdr_t *hdr, uintptr_t mem, size_t size) * (size of section header * index of string section header) */ addr = sec_table + ((size_t) hdr->e_shentsize) * hdr->e_shstrndx; - if (__ptr_struct_oob(addr, sizeof(Shdr_t), + if (__ptr_struct_oob(addr, sizeof(Elf_Shdr), sec_table, sec_table + sec_table_size)) { pr_err("String section header @%#zx is out of [%#zx, %#zx)\n", addr, sec_table, sec_table + sec_table_size); @@ -128,51 +128,55 @@ static const char *get_strings_section(Ehdr_t *hdr, uintptr_t mem, size_t size) return (void*)addr; } +/* + * This name @__handle_elf get renamed into + * @handle_elf_ppc64 or say @handle_elf_x86_64 + * depending on the architecture it's compiled + * under. + */ int __handle_elf(void *mem, size_t size) { const char *symstrings = NULL; - Shdr_t *symtab_hdr = NULL; - Sym_t *symbols = NULL; - Ehdr_t *hdr = mem; + Elf_Shdr *symtab_hdr = NULL; + Elf_Sym *symbols = NULL; + Elf_Ehdr *hdr = mem; - Shdr_t *strtab_hdr = NULL; - Shdr_t **sec_hdrs = NULL; + Elf_Shdr *strtab_hdr = NULL; + Elf_Shdr **sec_hdrs = NULL; const char *secstrings; size_t i, k, nr_gotpcrel = 0; #ifdef ELF_PPC64 s64 toc_offset = 0; #endif - int ret = -E_UNKNOWN; + int ret = -EINVAL; pr_debug("Header\n"); pr_debug("------------\n"); pr_debug("\ttype 0x%x machine 0x%x version 0x%x\n", - (unsigned)hdr->e_type, (unsigned)hdr->e_machine, (unsigned)hdr->e_version); + (unsigned)hdr->e_type, (unsigned)hdr->e_machine, + (unsigned)hdr->e_version); if (!is_header_supported(hdr)) { pr_err("Unsupported header detected\n"); - ret = -E_NOT_ELF; goto err; } sec_hdrs = malloc(sizeof(*sec_hdrs) * hdr->e_shnum); if (!sec_hdrs) { pr_err("No memory for section headers\n"); - ret = -E_NOMEM; + ret = -ENOMEM; goto err; } secstrings = get_strings_section(hdr, (uintptr_t)mem, size); - if (!secstrings) { - ret = -E_NO_STR_SEC; + if (!secstrings) goto err; - } pr_debug("Sections\n"); pr_debug("------------\n"); for (i = 0; i < hdr->e_shnum; i++) { - Shdr_t *sh = mem + hdr->e_shoff + hdr->e_shentsize * i; + Elf_Shdr *sh = mem + hdr->e_shoff + hdr->e_shentsize * i; ptr_func_exit(sh); if (sh->sh_type == SHT_SYMTAB) @@ -221,9 +225,9 @@ int __handle_elf(void *mem, size_t size) pr_out("#include \"%s/types.h\"\n", opts.uapi_dir); for (i = 0; i < symtab_hdr->sh_size / symtab_hdr->sh_entsize; i++) { - Sym_t *sym = &symbols[i]; + Elf_Sym *sym = &symbols[i]; const char *name; - Shdr_t *sh_src; + Elf_Shdr *sh_src; ptr_func_exit(sym); name = &symstrings[sym->st_name]; @@ -245,7 +249,8 @@ int __handle_elf(void *mem, size_t size) #endif if (strncmp(name, "__export", 8)) continue; - if ((sym->st_shndx && sym->st_shndx < hdr->e_shnum) || sym->st_shndx == SHN_ABS) { + if ((sym->st_shndx && sym->st_shndx < hdr->e_shnum) || + sym->st_shndx == SHN_ABS) { if (sym->st_shndx == SHN_ABS) { sh_src = NULL; } else { @@ -254,7 +259,8 @@ int __handle_elf(void *mem, size_t size) } pr_out("#define %s%s 0x%lx\n", opts.prefix_name, name, - (unsigned long)(sym->st_value + (sh_src ? sh_src->sh_addr : 0))); + (unsigned long)(sym->st_value + + (sh_src ? sh_src->sh_addr : 0))); } } } @@ -264,8 +270,8 @@ int __handle_elf(void *mem, size_t size) pr_debug("Relocations\n"); pr_debug("------------\n"); for (i = 0; i < hdr->e_shnum; i++) { - Shdr_t *sh = sec_hdrs[i]; - Shdr_t *sh_rel; + Elf_Shdr *sh = sec_hdrs[i]; + Elf_Shdr *sh_rel; if (sh->sh_type != SHT_REL && sh->sh_type != SHT_RELA) continue; @@ -283,11 +289,11 @@ int __handle_elf(void *mem, size_t size) unsigned long place; const char *name; void *where; - Sym_t *sym; + Elf_Sym *sym; union { - Rel_t rel; - Rela_t rela; + Elf_Rel rel; + Elf_Rela rela; } *r = mem + sh->sh_offset + sh->sh_entsize * k; ptr_func_exit(r); @@ -341,7 +347,7 @@ int __handle_elf(void *mem, size_t size) value32 = (s32)sym->st_value; value64 = (s64)sym->st_value; } else { - Shdr_t *sh_src; + Elf_Shdr *sh_src; if ((unsigned)sym->st_shndx > (unsigned)hdr->e_shnum) { pr_err("Unexpected symbol section index %u/%u\n", @@ -356,7 +362,9 @@ int __handle_elf(void *mem, size_t size) } #ifdef ELF_PPC64 -/* Snippet from the OpenPOWER ABI for Linux Supplement: +/* + * Snippet from the OpenPOWER ABI for Linux Supplement: + * * The OpenPOWER ABI uses the three most-significant bits in the symbol * st_other field specifies the number of instructions between a function's * global entry point and local entry point. The global entry point is used @@ -364,6 +372,7 @@ int __handle_elf(void *mem, size_t size) * local entry point is used when r2 is known to already be valid for the * function. A value of zero in these bits asserts that the function does * not use r2. + * * The st_other values have the following meanings: * 0 and 1, the local and global entry points are the same. * 2, the local entry point is at 1 instruction past the global entry point. @@ -408,7 +417,7 @@ int __handle_elf(void *mem, size_t size) case R_PPC64_ADDR32: pr_debug("\t\t\tR_PPC64_ADDR32 at 0x%-4lx val 0x%x\n", place, (unsigned int)(value32 + addend32)); - pr_out(" { .offset = 0x%-8x, .type = PIEGEN_TYPE_INT, " + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_INT, " " .addend = %-8d, .value = 0x%-16x, " "}, /* R_PPC64_ADDR32 */\n", (unsigned int) place, addend32, value32); @@ -418,7 +427,7 @@ int __handle_elf(void *mem, size_t size) case R_PPC64_REL64: pr_debug("\t\t\tR_PPC64_ADDR64 at 0x%-4lx val 0x%lx\n", place, value64 + addend64); - pr_out("\t{ .offset = 0x%-8x, .type = PIEGEN_TYPE_LONG," + pr_out("\t{ .offset = 0x%-8x, .type = COMPEL_TYPE_LONG," " .addend = %-8ld, .value = 0x%-16lx, " "}, /* R_PPC64_ADDR64 */\n", (unsigned int) place, (long)addend64, (long)value64); @@ -478,13 +487,13 @@ int __handle_elf(void *mem, size_t size) case R_X86_64_32: /* Symbol + Addend (4 bytes) */ case R_X86_64_32S: /* Symbol + Addend (4 bytes) */ pr_debug("\t\t\t\tR_X86_64_32 at 0x%-4lx val 0x%x\n", place, value32); - pr_out(" { .offset = 0x%-8x, .type = PIEGEN_TYPE_INT, " + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_INT, " ".addend = %-8d, .value = 0x%-16x, }, /* R_X86_64_32 */\n", (unsigned int)place, addend32, value32); break; case R_X86_64_64: /* Symbol + Addend (8 bytes) */ pr_debug("\t\t\t\tR_X86_64_64 at 0x%-4lx val 0x%lx\n", place, (long)value64); - pr_out(" { .offset = 0x%-8x, .type = PIEGEN_TYPE_LONG, " + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_LONG, " ".addend = %-8ld, .value = 0x%-16lx, }, /* R_X86_64_64 */\n", (unsigned int)place, (long)addend64, (long)value64); break; @@ -504,7 +513,7 @@ int __handle_elf(void *mem, size_t size) break; case R_X86_64_GOTPCREL: /* SymbolOffsetInGot + GOT + Addend - Place (4 bytes) */ pr_debug("\t\t\t\tR_X86_64_GOTPCREL at 0x%-4lx val 0x%x\n", place, value32); - pr_out(" { .offset = 0x%-8x, .type = PIEGEN_TYPE_LONG | PIEGEN_TYPE_GOTPCREL, " + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_LONG | COMPEL_TYPE_GOTPCREL, " ".addend = %-8d, .value = 0x%-16x, }, /* R_X86_64_GOTPCREL */\n", (unsigned int)place, addend32, value32); nr_gotpcrel++; @@ -514,7 +523,7 @@ int __handle_elf(void *mem, size_t size) #ifdef ELF_X86_32 case R_386_32: /* Symbol + Addend */ pr_debug("\t\t\t\tR_386_32 at 0x%-4lx val 0x%x\n", place, value32 + addend32); - pr_out(" { .offset = 0x%-8x, .type = PIEGEN_TYPE_INT, " + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_INT, " ".addend = %-4d, .value = 0x%x, },\n", (unsigned int)place, addend32, value32); break; @@ -539,8 +548,8 @@ int __handle_elf(void *mem, size_t size) pr_out("static __maybe_unused const char %s[] = {\n\t", opts.stream_name); - for (i=0, k=0; i < hdr->e_shnum; i++) { - Shdr_t *sh = sec_hdrs[i]; + for (i = 0, k = 0; i < hdr->e_shnum; i++) { + Elf_Shdr *sh = sec_hdrs[i]; unsigned char *shdata; size_t j; @@ -548,19 +557,19 @@ int __handle_elf(void *mem, size_t size) continue; shdata = mem + sh->sh_offset; - pr_debug("Copying section '%s'\n" \ + pr_debug("Copying section '%s'\n" "\tstart:0x%lx (gap:0x%lx) size:0x%lx\n", &secstrings[sh->sh_name], (unsigned long) sh->sh_addr, (unsigned long)(sh->sh_addr - k), (unsigned long) sh->sh_size); /* write 0 in the gap between the 2 sections */ - for (;k < sh->sh_addr; k++) { + for (; k < sh->sh_addr; k++) { if (k && (k % 8) == 0) pr_out("\n\t"); pr_out("0x00,"); } - for (j=0; j < sh->sh_size; j++, k++) { + for (j = 0; j < sh->sh_size; j++, k++) { if (k && (k % 8) == 0) pr_out("\n\t"); pr_out("%#02x,", shdata[j]); diff --git a/compel/main.c b/compel/src/main.c similarity index 99% rename from compel/main.c rename to compel/src/main.c index 6f117cded..ee6ccd53a 100644 --- a/compel/main.c +++ b/compel/src/main.c @@ -12,6 +12,7 @@ #include #include +#include "version.h" #include "piegen.h" static const char compel_cflags_pie[] = "-fpie -Wa,--noexecstack -fno-stack-protector"; From a437c2d969b7c6ef4915d74cede5d328494b34c1 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 21 Sep 2016 23:54:19 +0300 Subject: [PATCH 0090/4375] compel: Add plugins header Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/plugins.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 compel/include/uapi/plugins.h diff --git a/compel/include/uapi/plugins.h b/compel/include/uapi/plugins.h new file mode 100644 index 000000000..e9ebfb67f --- /dev/null +++ b/compel/include/uapi/plugins.h @@ -0,0 +1,35 @@ +#ifndef UAPI_COMPEL_PLUGIN_H__ +#define UAPI_COMPEL_PLUGIN_H__ + +#define __init __attribute__((__used__)) __attribute__ ((__section__(".compel.init"))) +#define __exit __attribute__((__used__)) __attribute__ ((__section__(".compel.exit"))) + +#ifndef __ASSEMBLY__ + +typedef struct { + const char *name; + int (*init)(void); + void (*exit)(void); +} plugin_init_t; + +#define plugin_register(___desc) \ + static const plugin_init_t * const \ + ___ptr__##___desc __init = &___desc; + +#define PLUGIN_REGISTER(___id, ___name, ___init, ___exit) \ + static const plugin_init_t __plugin_desc_##___id = { \ + .name = ___name, \ + .init = ___init, \ + .exit = ___exit, \ + }; \ + plugin_register(__plugin_desc_##___id); + +#define PLUGIN_REGISTER_DUMMY(___id) \ + static const plugin_init_t __plugin_desc_##___id = { \ + .name = #___id, \ + }; \ + plugin_register(__plugin_desc_##___id); + +#endif /* __ASSEMBLY__ */ + +#endif /* UAPI_COMPEL_PLUGIN_H__ */ From 20d5bb140d233efd6ed84d39ea7d0fefdfeb32a0 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 21 Sep 2016 23:54:20 +0300 Subject: [PATCH 0091/4375] compel: plusings -- Add std plugin The plugin provides basic features as string copying, syscalls, printing. Not used on its own by now but will be shipping by default with other plugins. With great help from Dmitry Safonov. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .../plugins/include/asm/std/syscall-types.h | 53 ++++ compel/arch/x86/plugins/std/call32.S | 71 +++++ .../std/syscalls/syscall-common-x86-32.S | 36 +++ .../std/syscalls/syscall-common-x86-64.S | 21 ++ .../arch/x86/plugins/std/syscalls/syscall32.c | 85 ++++++ .../x86/plugins/std/syscalls/syscall_32.tbl | 95 +++++++ .../x86/plugins/std/syscalls/syscall_64.tbl | 106 +++++++ compel/arch/x86/scripts/pack.lds.S | 30 ++ compel/plugins/Makefile | 127 +++++++++ compel/plugins/include/uapi/plugin-std.h | 6 + compel/plugins/include/uapi/std/string.h | 28 ++ .../plugins/include/uapi/std/syscall-types.h | 55 ++++ compel/plugins/std/std.c | 89 ++++++ compel/plugins/std/string.c | 262 ++++++++++++++++++ 14 files changed, 1064 insertions(+) create mode 100644 compel/arch/x86/plugins/include/asm/std/syscall-types.h create mode 100644 compel/arch/x86/plugins/std/call32.S create mode 100644 compel/arch/x86/plugins/std/syscalls/syscall-common-x86-32.S create mode 100644 compel/arch/x86/plugins/std/syscalls/syscall-common-x86-64.S create mode 100644 compel/arch/x86/plugins/std/syscalls/syscall32.c create mode 100644 compel/arch/x86/plugins/std/syscalls/syscall_32.tbl create mode 100644 compel/arch/x86/plugins/std/syscalls/syscall_64.tbl create mode 100644 compel/arch/x86/scripts/pack.lds.S create mode 100644 compel/plugins/Makefile create mode 100644 compel/plugins/include/uapi/plugin-std.h create mode 100644 compel/plugins/include/uapi/std/string.h create mode 100644 compel/plugins/include/uapi/std/syscall-types.h create mode 100644 compel/plugins/std/std.c create mode 100644 compel/plugins/std/string.c diff --git a/compel/arch/x86/plugins/include/asm/std/syscall-types.h b/compel/arch/x86/plugins/include/asm/std/syscall-types.h new file mode 100644 index 000000000..744809d07 --- /dev/null +++ b/compel/arch/x86/plugins/include/asm/std/syscall-types.h @@ -0,0 +1,53 @@ +#ifndef COMPEL_ARCH_SYSCALL_TYPES_H__ +#define COMPEL_ARCH_SYSCALL_TYPES_H__ + +/* Types for sigaction, sigprocmask syscalls */ +typedef void rt_signalfn_t(int, siginfo_t *, void *); +typedef rt_signalfn_t *rt_sighandler_t; + +typedef void rt_restorefn_t(void); +typedef rt_restorefn_t *rt_sigrestore_t; + +#define _KNSIG 64 +# define _NSIG_BPW 64 + +#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) + +typedef struct { + u64 sig[_KNSIG_WORDS]; +} k_rtsigset_t; + +typedef struct { + rt_sighandler_t rt_sa_handler; + unsigned long rt_sa_flags; + rt_sigrestore_t rt_sa_restorer; + k_rtsigset_t rt_sa_mask; +} rt_sigaction_t; + +/* + * Note: there is unaligned access on x86_64 and it's fine. + * However, when porting this code -- keep in mind about possible issues + * with unaligned rt_sa_mask. + */ +typedef struct __attribute__((packed)) { + u32 rt_sa_handler; + u32 rt_sa_flags; + u32 rt_sa_restorer; + k_rtsigset_t rt_sa_mask; +} rt_sigaction_t_compat; + +/* Types for set_thread_area, get_thread_area syscalls */ +typedef struct { + unsigned int entry_number; + unsigned int base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; + unsigned int lm:1; +} user_desc_t; + +#endif /* COMPEL_ARCH_SYSCALL_TYPES_H__ */ diff --git a/compel/arch/x86/plugins/std/call32.S b/compel/arch/x86/plugins/std/call32.S new file mode 100644 index 000000000..935461dcd --- /dev/null +++ b/compel/arch/x86/plugins/std/call32.S @@ -0,0 +1,71 @@ +/* + * call32.S - assembly helpers for mixed-bitness code + * From kernel selftests originally: tools/testing/selftests/x86/thunks.S + * Copyright (c) 2015 Andrew Lutomirski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * These are little helpers that make it easier to switch bitness on + * the fly. + */ + +#include "asm/linkage.h" + +#define __USER32_CS 0x23 +#define __USER_CS 0x33 + + .text + +/* + * @rdi: Stack to use + * @esi: Pointer to function for calling + */ +ENTRY(call32_from_64) + /* Callee-saving registers due to ABI */ + pushq %rbx + pushq %rbp + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + pushfq + + /* Switch stacks */ + sub $8, %rdi + mov %rsp,(%rdi) + mov %rdi,%rsp + + /* Switch into compatibility mode */ + pushq $__USER32_CS + pushq $1f + lretq + +1: + .code32 + /* Run function and switch back */ + call *%esi + jmp $__USER_CS,$1f + .code64 + +1: + /* Restore the stack */ + mov (%rsp),%rsp + add $8, %rdi + + /* Restore registers */ + popfq + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx + ret +END(call32_from_64) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-32.S b/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-32.S new file mode 100644 index 000000000..ae6d594dc --- /dev/null +++ b/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-32.S @@ -0,0 +1,36 @@ +#include "asm/linkage.h" + +#define SYSCALL(name, opcode) \ + ENTRY(name); \ + movl $opcode, %eax; \ + jmp __syscall_common; \ + END(name) + +ENTRY(__syscall_common) + pushl %ebx + pushl %esi + pushl %edi + pushl %ebp + +#define __arg(n) (4 * (n) + 20)(%esp) + movl __arg(0),%ebx + movl __arg(1),%ecx + movl __arg(2),%edx + movl __arg(3),%esi + movl __arg(4),%edi + movl __arg(5),%ebp +#undef __arg + + int $0x80 + + popl %ebp + popl %edi + popl %esi + popl %ebx + ret +END(__syscall_common) + +ENTRY(__cr_restore_rt) + movl $__NR_rt_sigreturn, %eax + jmp __syscall_common +END(__cr_restore_rt) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-64.S b/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-64.S new file mode 100644 index 000000000..b93c31288 --- /dev/null +++ b/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-64.S @@ -0,0 +1,21 @@ +#include "asm/linkage.h" + +#define SYSCALL(name, opcode) \ + ENTRY(name); \ + movl $opcode, %eax; \ + jmp __syscall_common; \ + END(name) + + .text + .align 4 + +ENTRY(__syscall_common) + movq %rcx, %r10 + syscall + ret +END(__syscall_common) + +ENTRY(__cr_restore_rt) + movq $__NR_rt_sigreturn, %rax + syscall +END(__cr_restore_rt) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall32.c b/compel/arch/x86/plugins/std/syscalls/syscall32.c new file mode 100644 index 000000000..88af59330 --- /dev/null +++ b/compel/arch/x86/plugins/std/syscalls/syscall32.c @@ -0,0 +1,85 @@ +#include "asm/types.h" +#include "syscall-32.h" + +#define SYS_SOCKET 1 /* sys_socket(2) */ +#define SYS_BIND 2 /* sys_bind(2) */ +#define SYS_CONNECT 3 /* sys_connect(2) */ +#define SYS_SENDTO 11 /* sys_sendto(2) */ +#define SYS_RECVFROM 12 /* sys_recvfrom(2) */ +#define SYS_SHUTDOWN 13 /* sys_shutdown(2) */ +#define SYS_SETSOCKOPT 14 /* sys_setsockopt(2) */ +#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */ +#define SYS_SENDMSG 16 /* sys_sendmsg(2) */ +#define SYS_RECVMSG 17 /* sys_recvmsg(2) */ + +long sys_socket(int domain, int type, int protocol) +{ + u32 a[] = { (u32)domain, (u32)type, (u32)protocol }; + return sys_socketcall(SYS_SOCKET, (unsigned long *)a); +} + +long sys_connect(int sockfd, struct sockaddr *addr, int addrlen) +{ + u32 a[] = {(u32)sockfd, (u32)addr, (u32)addrlen}; + return sys_socketcall(SYS_CONNECT, (unsigned long *)a); +} + +long sys_sendto(int sockfd, void *buff, size_t len, unsigned int flags, struct sockaddr *addr, int addr_len) +{ + u32 a[] = {(u32)sockfd, (u32)buff, (u32)len, (u32)flags, (u32)addr, (u32)addr_len}; + return sys_socketcall(SYS_SENDTO, (unsigned long *)a); +} + +long sys_recvfrom(int sockfd, void *ubuf, size_t size, unsigned int flags, struct sockaddr *addr, int *addr_len) +{ + u32 a[] = {(u32)sockfd, (u32)ubuf, (u32)size, (u32)flags, (u32)addr, (u32)addr_len}; + return sys_socketcall(SYS_RECVFROM, (unsigned long *)a); +} + +long sys_sendmsg(int sockfd, const struct msghdr *msg, int flags) +{ + u32 a[] = {(u32)sockfd, (u32)msg, (u32)flags}; + return sys_socketcall(SYS_SENDMSG, (unsigned long *)a); +} + +long sys_recvmsg(int sockfd, struct msghdr *msg, int flags) +{ + u32 a[] = {(u32)sockfd, (u32)msg, (u32)flags}; + return sys_socketcall(SYS_RECVMSG, (unsigned long *)a); +} + +long sys_shutdown(int sockfd, int how) +{ + u32 a[] = {(u32)sockfd, (u32)how}; + return sys_socketcall(SYS_SHUTDOWN, (unsigned long *)a); +} + +long sys_bind(int sockfd, const struct sockaddr *addr, int addrlen) +{ + u32 a[] = {(u32)sockfd, (u32)addr, (u32)addrlen}; + return sys_socketcall(SYS_BIND, (unsigned long *)a); +} + +long sys_setsockopt(int sockfd, int level, int optname, const void *optval, unsigned int optlen) +{ + u32 a[] = {(u32)sockfd, (u32)level, (u32)optname, (u32)optval, (u32)optlen}; + return sys_socketcall(SYS_SETSOCKOPT, (unsigned long *)a); +} + +long sys_getsockopt(int sockfd, int level, int optname, const void *optval, unsigned int *optlen) +{ + u32 a[] = {(u32)sockfd, (u32)level, (u32)optname, (u32)optval, (u32)optlen}; + return sys_socketcall(SYS_GETSOCKOPT, (unsigned long *)a); +} + +#define SHMAT 21 + +long sys_shmat(int shmid, void *shmaddr, int shmflag) +{ + return sys_ipc(SHMAT, shmid, shmflag, 0, shmaddr, 0); +} + +long sys_pread(unsigned int fd, char *ubuf, u32 count, u64 pos) +{ + return sys_pread64(fd, ubuf, count, (u32)(pos & 0xffffffffu), (u32)(pos >> 32)); +} diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl new file mode 100644 index 000000000..4f7e42194 --- /dev/null +++ b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl @@ -0,0 +1,95 @@ +# +# System calls table, please make sure the table consist only the syscalls +# really used somewhere in project. +# +# code name arguments +# ------------------------------------------------------------------------------------------------------------------------------------------------------------- +__NR_restart_syscall 0 sys_restart_syscall (void) +__NR_exit 1 sys_exit (unsigned long error_code) +__NR_read 3 sys_read (int fd, void *buf, unsigned long count) +__NR_write 4 sys_write (int fd, const void *buf, unsigned long count) +__NR_open 5 sys_open (const char *filename, int flags, unsigned int mode) +__NR_close 6 sys_close (int fd) +__NR_unlink 10 sys_unlink (char *pathname) +__NR_lseek 19 sys_lseek (int fd, s32 offset, unsigned int origin) +__NR_getpid 20 sys_getpid (void) +__NR_mount 21 sys_mount (const char *dev_name, const char *dir_name, const char *type, unsigned long flags, const void *data) +__NR_ptrace 26 sys_ptrace (long request, pid_t pid, void *addr, void *data) +__NR_kill 37 sys_kill (long pid, int sig) +__NR_mkdir 39 sys_mkdir (const char *name, int mode) +__NR_rmdir 40 sys_rmdir (const char *name) +__NR_brk 45 sys_brk (void *addr) +__NR_umount2 52 sys_umount2 (char *name, int flags) +__NR_ioctl 54 sys_ioctl (unsigned int fd, unsigned int cmd, unsigned long arg) +__NR_fcntl 55 sys_fcntl (unsigned int fd, unsigned int cmd, unsigned long arg) +__NR_umask 60 sys_umask (int mask) +__NR_setrlimit 75 sys_setrlimit (unsigned int resource, struct krlimit *rlim) +__NR_gettimeofday 78 sys_gettimeofday (struct timeval *tv, struct timezone *tz) +__NR_munmap 91 sys_munmap (void *addr, unsigned long len) +__NR_setpriority 97 sys_setpriority (int which, int who, int nice) +__NR_socketcall 102 sys_socketcall (int call, unsigned long *args) +__NR_setitimer 104 sys_setitimer (int which, struct itimerval *in, struct itimerval *out) +__NR_getitimer 105 sys_getitimer (int which, struct itimerval *it) +__NR_wait4 114 sys_wait4 (pid_t pid, int *stat_addr, int options, struct rusage *ru) +__NR_ipc 117 sys_ipc (unsigned int call, int first, unsigned long second, unsigned long third, void *ptr, long fifth) +__NR_clone 120 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, void *child_tid) +__NR_mprotect 125 sys_mprotect (const void *addr, unsigned long len, unsigned long prot) +__NR_getpgid 132 sys_getpgid (pid_t pid) +__NR_personality 136 sys_personality (unsigned int personality) +__NR_flock 143 sys_flock (int fd, unsigned long cmd) +__NR_getsid 147 sys_getsid (void) +__NR_sched_setscheduler 156 sys_sched_setscheduler (int pid, int policy, struct sched_param *p) +__NR_nanosleep 162 sys_nanosleep (struct timespec *rqtp, struct timespec *rmtp) +__NR_mremap 163 sys_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) +__NR_prctl 172 sys_prctl (int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) +__NR_rt_sigreturn 173 sys_rt_sigreturn (void) +__NR_rt_sigaction 174 sys_sigaction (int signum, const rt_sigaction_t *act, rt_sigaction_t *oldact, size_t sigsetsize) +__NR_rt_sigprocmask 175 sys_sigprocmask (int how, k_rtsigset_t *set, k_rtsigset_t *oset, size_t sigsetsize) +__NR_rt_sigqueueinfo 178 sys_rt_sigqueueinfo (pid_t pid, int sig, siginfo_t *uinfo) +__NR_pread64 180 sys_pread64 (unsigned int fd, char *ubuf, u32 count, u32 poslo, u32 poshi) +__NR_capget 184 sys_capget (struct cap_header *h, struct cap_data *d) +__NR_capset 185 sys_capset (struct cap_header *h, struct cap_data *d) +__NR_sigaltstack 186 sys_sigaltstack (const void *uss_ptr, void *uoss_ptr) +__NR_mmap2 192 sys_mmap (void *addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) +__NR_getgroups32 205 sys_getgroups (int gsize, unsigned int *groups) +__NR_setgroups32 206 sys_setgroups (int gsize, unsigned int *groups) +__NR_setresuid32 208 sys_setresuid (int uid, int euid, int suid) +__NR_getresuid32 209 sys_getresuid (int *uid, int *euid, int *suid) +__NR_setresgid32 210 sys_setresgid (int gid, int egid, int sgid) +__NR_getresgid32 211 sys_getresgid (int *gid, int *egid, int *sgid) +__NR_setfsuid32 215 sys_setfsuid (int fsuid) +__NR_setfsgid32 216 sys_setfsgid (int fsgid) +__NR_mincore 218 sys_mincore (void *addr, unsigned long size, unsigned char *vec) +__NR_madvise 219 sys_madvise (unsigned long start, size_t len, int behavior) +__NR_gettid 224 sys_gettid (void) +__NR_futex 240 sys_futex (u32 *uaddr, int op, u32 val, struct timespec *utime, u32 *uaddr2, u32 val3) +__NR_set_thread_area 243 sys_set_thread_area (user_desc_t *info) +__NR_get_thread_area 244 sys_get_thread_area (user_desc_t *info) +__NR_io_setup 245 sys_io_setup (unsigned nr_reqs, aio_context_t *ctx32p) +__NR_io_getevents 247 sys_io_getevents (aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout) +__NR_io_submit 248 sys_io_submit (aio_context_t ctx_id, long nr, struct iocb **iocbpp) +__NR_exit_group 252 sys_exit_group (int error_code) +__NR_set_tid_address 258 sys_set_tid_address (int *tid_addr) +__NR_timer_create 259 sys_timer_create (clockid_t which_clock, struct sigevent *timer_event_spec, kernel_timer_t *created_timer_id) +__NR_timer_settime 260 sys_timer_settime (kernel_timer_t timer_id, int flags, struct itimerspec *new, struct itimerspec *old) +__NR_timer_gettime 261 sys_timer_gettime (int timer_id, struct itimerspec *setting) +__NR_timer_getoverrun 262 sys_timer_getoverrun (int timer_id) +__NR_timer_delete 263 sys_timer_delete (kernel_timer_t timer_id) +__NR_clock_gettime 265 sys_clock_gettime (int which_clock, struct timespec *tp) +__NR_waitid 284 sys_waitid (int which, pid_t pid, struct siginfo *infop, int options, struct rusage *ru) +__NR_openat 295 sys_openat (int dfd, const char *filename, int flags, int mode) +__NR_readlinkat 305 sys_readlinkat (int fd, const char *path, char *buf, int bufsize) +__NR_set_robust_list 311 sys_set_robust_list (struct robust_list_head *head, size_t len) +__NR_get_robust_list 312 sys_get_robust_list (int pid, struct robust_list_head **head_ptr, size_t *len_ptr) +__NR_vmsplice 316 sys_vmsplice (int fd, const struct iovec *iov, unsigned int nr_segs, unsigned int flags) +__NR_signalfd 321 sys_signalfd (int ufd, const k_rtsigset_t *sigmask, size_t sigsetsize) +__NR_timerfd_settime 325 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) +__NR_rt_tgsigqueueinfo 335 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *uinfo) +__NR_fanotify_init 338 sys_fanotify_init (unsigned int flags, unsigned int event_f_flags) +__NR_fanotify_mark 339 sys_fanotify_mark (int fanotify_fd, unsigned int flag, u32 mask, int dfd, const char *pathname) +__NR_open_by_handle_at 342 sys_open_by_handle_at (int mountdirfd, struct file_handle *handle, int flags) +__NR_setns 346 sys_setns (int fd, int nstype) +__NR_kcmp 349 sys_kcmp (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) +__NR_seccomp 354 sys_seccomp (unsigned int op, unsigned int flags, const char *uargs) +__NR_memfd_create 356 sys_memfd_create (const char *name, unsigned int flags) +__NR_userfaultfd 374 sys_userfaultfd (int flags) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl new file mode 100644 index 000000000..9a36b6826 --- /dev/null +++ b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl @@ -0,0 +1,106 @@ +# +# System calls table, please make sure the table consist only the syscalls +# really used somewhere in project. +# +# __NR_name code name arguments +# ------------------------------------------------------------------------------------------------------------------------------------------------------------- +__NR_read 0 sys_read (int fd, void *buf, unsigned long count) +__NR_write 1 sys_write (int fd, const void *buf, unsigned long count) +__NR_open 2 sys_open (const char *filename, unsigned long flags, unsigned long mode) +__NR_close 3 sys_close (int fd) +__NR_lseek 8 sys_lseek (int fd, unsigned long offset, unsigned long origin) +__NR_mmap 9 sys_mmap (void *addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long offset) +__NR_mprotect 10 sys_mprotect (const void *addr, unsigned long len, unsigned long prot) +__NR_munmap 11 sys_munmap (void *addr, unsigned long len) +__NR_brk 12 sys_brk (void *addr) +__NR_rt_sigaction 13 sys_sigaction (int signum, const rt_sigaction_t *act, rt_sigaction_t *oldact, size_t sigsetsize) +__NR_rt_sigprocmask 14 sys_sigprocmask (int how, k_rtsigset_t *set, k_rtsigset_t *old, size_t sigsetsize) +__NR_rt_sigreturn 15 sys_rt_sigreturn (void) +__NR_ioctl 16 sys_ioctl (unsigned int fd, unsigned int cmd, unsigned long arg) +__NR_pread64 17 sys_pread (unsigned int fd, char *buf, size_t count, loff_t pos) +__NR_mremap 25 sys_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) +__NR_mincore 27 sys_mincore (void *addr, unsigned long size, unsigned char *vec) +__NR_madvise 28 sys_madvise (unsigned long start, size_t len, int behavior) +__NR_shmat 30 sys_shmat (int shmid, void *shmaddr, int shmflag) +__NR_dup2 33 sys_dup2 (int oldfd, int newfd) +__NR_nanosleep 35 sys_nanosleep (struct timespec *req, struct timespec *rem) +__NR_getitimer 36 sys_getitimer (int which, const struct itimerval *val) +__NR_setitimer 38 sys_setitimer (int which, const struct itimerval *val, struct itimerval *old) +__NR_getpid 39 sys_getpid (void) +__NR_socket 41 sys_socket (int domain, int type, int protocol) +__NR_connect 42 sys_connect (int sockfd, struct sockaddr *addr, int addrlen) +__NR_sendto 44 sys_sendto (int sockfd, void *buff, size_t len, unsigned int flags, struct sockaddr *addr, int addr_len) +__NR_recvfrom 45 sys_recvfrom (int sockfd, void *ubuf, size_t size, unsigned int flags, struct sockaddr *addr, int *addr_len) +__NR_sendmsg 46 sys_sendmsg (int sockfd, const struct msghdr *msg, int flags) +__NR_recvmsg 47 sys_recvmsg (int sockfd, struct msghdr *msg, int flags) +__NR_shutdown 48 sys_shutdown (int sockfd, int how) +__NR_bind 49 sys_bind (int sockfd, const struct sockaddr *addr, int addrlen) +__NR_setsockopt 54 sys_setsockopt (int sockfd, int level, int optname, const void *optval, socklen_t optlen) +__NR_getsockopt 55 sys_getsockopt (int sockfd, int level, int optname, const void *optval, socklen_t *optlen) +__NR_clone 56 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, void *child_tid) +__NR_exit 60 sys_exit (unsigned long error_code) +__NR_wait4 61 sys_wait4 (int pid, int *status, int options, struct rusage *ru) +__NR_kill 62 sys_kill (long pid, int sig) +__NR_fcntl 72 sys_fcntl (int fd, int type, long arg) +__NR_flock 73 sys_flock (int fd, unsigned long cmd) +__NR_mkdir 83 sys_mkdir (const char *name, int mode) +__NR_rmdir 84 sys_rmdir (const char *name) +__NR_unlink 87 sys_unlink (char *pathname) +__NR_umask 95 sys_umask (int mask) +__NR_gettimeofday 96 sys_gettimeofday (struct timeval *tv, struct timezone *tz) +__NR_ptrace 101 sys_ptrace (long request, pid_t pid, void *addr, void *data) +__NR_getgroups 115 sys_getgroups (int gsize, unsigned int *groups) +__NR_setgroups 116 sys_setgroups (int gsize, unsigned int *groups) +__NR_setresuid 117 sys_setresuid (int uid, int euid, int suid) +__NR_getresuid 118 sys_getresuid (int *uid, int *euid, int *suid) +__NR_setresgid 119 sys_setresgid (int gid, int egid, int sgid) +__NR_getresgid 120 sys_getresgid (int *gid, int *egid, int *sgid) +__NR_getpgid 121 sys_getpgid (pid_t pid) +__NR_setfsuid 122 sys_setfsuid (int fsuid) +__NR_setfsgid 123 sys_setfsgid (int fsgid) +__NR_getsid 124 sys_getsid (void) +__NR_capget 125 sys_capget (struct cap_header *h, struct cap_data *d) +__NR_capset 126 sys_capset (struct cap_header *h, struct cap_data *d) +__NR_rt_sigqueueinfo 129 sys_rt_sigqueueinfo (pid_t pid, int sig, siginfo_t *info) +__NR_sigaltstack 131 sys_sigaltstack (const void *uss, void *uoss) +__NR_personality 135 sys_personality (unsigned int personality) +__NR_setpriority 141 sys_setpriority (int which, int who, int nice) +__NR_sched_setscheduler 144 sys_sched_setscheduler (int pid, int policy, struct sched_param *p) +__NR_prctl 157 sys_prctl (int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) +__NR_arch_prctl 158 sys_arch_prctl (int option, unsigned long addr) +__NR_setrlimit 160 sys_setrlimit (int resource, struct krlimit *rlim) +__NR_mount 165 sys_mount (char *dev_nmae, char *dir_name, char *type, unsigned long flags, void *data) +__NR_umount2 166 sys_umount2 (char *name, int flags) +__NR_gettid 186 sys_gettid (void) +__NR_futex 202 sys_futex (u32 *uaddr, int op, u32 val, struct timespec *utime, u32 *uaddr2, u32 val3) +__NR_set_thread_area 205 sys_set_thread_area (user_desc_t *info) +__NR_io_setup 206 sys_io_setup (unsigned nr_events, aio_context_t *ctx) +__NR_io_getevents 208 sys_io_getevents (aio_context_t ctx, long min_nr, long nr, struct io_event *evs, struct timespec *tmo) +__NR_io_submit 209 sys_io_submit (aio_context_t ctx, long nr, struct iocb **iocbpp) +__NR_get_thread_area 211 sys_get_thread_area (user_desc_t *info) +__NR_set_tid_address 218 sys_set_tid_address (int *tid_addr) +__NR_restart_syscall 219 sys_restart_syscall (void) +__NR_sys_timer_create 222 sys_timer_create (clockid_t which_clock, struct sigevent *timer_event_spec, kernel_timer_t *created_timer_id) +__NR_sys_timer_settime 223 sys_timer_settime (kernel_timer_t timer_id, int flags, const struct itimerspec *new_setting, struct itimerspec *old_setting) +__NR_sys_timer_gettime 224 sys_timer_gettime (int timer_id, const struct itimerspec *setting) +__NR_sys_timer_getoverrun 225 sys_timer_getoverrun (int timer_id) +__NR_sys_timer_delete 226 sys_timer_delete (kernel_timer_t timer_id) +__NR_clock_gettime 228 sys_clock_gettime (const clockid_t which_clock, const struct timespec *tp) +__NR_exit_group 231 sys_exit_group (int error_code) +__NR_openat 257 sys_openat (int dfd, const char *filename, int flags, int mode) +__NR_waitid 247 sys_waitid (int which, pid_t pid, struct siginfo *infop, int options, struct rusage *ru) +__NR_readlinkat 267 sys_readlinkat (int fd, const char *path, char *buf, int bufsize) +__NR_set_robust_list 273 sys_set_robust_list (struct robust_list_head *head, size_t len) +__NR_get_robust_list 274 sys_get_robust_list (int pid, struct robust_list_head **head_ptr, size_t *len_ptr) +__NR_seccomp 317 sys_seccomp (unsigned int op, unsigned int flags, const char *uargs) +__NR_vmsplice 278 sys_vmsplice (int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags) +__NR_timerfd_settime 286 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) +__NR_signalfd4 289 sys_signalfd (int fd, k_rtsigset_t *mask, size_t sizemask, int flags) +__NR_rt_tgsigqueueinfo 297 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *info) +__NR_fanotify_init 300 sys_fanotify_init (unsigned int flags, unsigned int event_f_flags) +__NR_fanotify_mark 301 sys_fanotify_mark (int fanotify_fd, unsigned int flags, u64 mask, int dfd, const char *pathname) +__NR_open_by_handle_at 304 sys_open_by_handle_at (int mountdirfd, struct file_handle *handle, int flags) +__NR_setns 308 sys_setns (int fd, int nstype) +__NR_kcmp 312 sys_kcmp (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) +__NR_memfd_create 319 sys_memfd_create (const char *name, unsigned int flags) +__NR_userfaultfd 323 sys_userfaultfd (int flags) diff --git a/compel/arch/x86/scripts/pack.lds.S b/compel/arch/x86/scripts/pack.lds.S new file mode 100644 index 000000000..3b94b3ecd --- /dev/null +++ b/compel/arch/x86/scripts/pack.lds.S @@ -0,0 +1,30 @@ +OUTPUT_ARCH(i386:x86-64) +SECTIONS +{ + . = ALIGN(64); + .text : { + *(.compel.prologue.text) + *(.text*) + } =0x0 + + . = ALIGN(64); + .compel.init : { + *(.compel.init) + } =0xff + + . = ALIGN(64); + .data : { + *(.data*) + *(.bss*) + *(.rodata*) + } =0x0 + + /DISCARD/ : { + *(.debug*) + *(.comment*) + *(.note*) + *(.group*) + *(.eh_frame*) + *(*) + } +} diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile new file mode 100644 index 000000000..f0b1de802 --- /dev/null +++ b/compel/plugins/Makefile @@ -0,0 +1,127 @@ +.PHONY: .FORCE + +ARCH_DIR := compel/arch/$(ARCH)/plugins + +ccflags-y += -iquote $(obj)/include/ +ccflags-y += -iquote $(obj)/include/uapi +ccflags-y += -iquote $(SRC_DIR)/criu/include +ccflags-y += -iquote $(SRC_DIR)/criu/arch/$(ARCH)/include +ccflags-y += -iquote $(SRC_DIR)/compel/include +ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR)/include + +asflags-y += -iquote $(SRC_DIR)/criu/arch/$(ARCH)/include +asflags-y += -iquote $(SRC_DIR)/compel/plugins/include/uapi +asflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR) + +# +# STD plugin +target += std +std-obj-y += std/std.o +std-obj-y += std/string.o +std-obj-y += arch/$(ARCH)/plugins/std/syscalls-64.o +std-obj-y += arch/$(ARCH)/plugins/std/calls32.o + +sys-proto-generic := $(obj)/include/uapi/std/syscall.h +sys-codes-generic := $(obj)/include/uapi/std/syscall-codes.h +sys-codes = $(obj)/include/uapi/std/syscall-codes-$(1).h +sys-proto = $(obj)/include/uapi/std/syscall-$(1).h +sys-def = $(ARCH_DIR)/std/syscalls/syscall_$(1).tbl +sys-asm = $(ARCH_DIR)/std/syscalls-$(1).S +sys-asm-common-name = std/syscalls/syscall-common-x86-$(1).S +sys-asm-common = $(ARCH_DIR)/$(sys-asm-common-name) + +sys-bits := 64 + +AV := $$$$ + +define gen-rule-sys-codes +$(sys-codes): $(sys-def) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) echo "#ifndef ASM_SYSCALL_CODES_H_$(1)__" >> $$@ + $(Q) echo "#define ASM_SYSCALL_CODES_H_$(1)__" >> $$@ + $(Q) cat $$< | awk '/^__NR/{SYSN=$(AV)1; \ + sub("^__NR", "SYS", SYSN); \ + print "\n#ifndef ", $(AV)1; \ + print "#define", $(AV)1, $(AV)2; \ + print "#endif"; \ + print "\n#ifndef ", SYSN; \ + print "#define ", SYSN, $(AV)1; \ + print "#endif";}' >> $$@ + $(Q) echo "#endif /* ASM_SYSCALL_CODES_H_$(1)__ */" >> $$@ +endef + +define gen-rule-sys-proto +$(sys-proto): $(sys-def) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) echo "#ifndef ASM_SYSCALL_PROTO_H_$(1)__" >> $$@ + $(Q) echo "#define ASM_SYSCALL_PROTO_H_$(1)__" >> $$@ + $(Q) echo '#include "std/syscall-codes-$(1).h"' >> $$@ + $(Q) echo '#include "syscall-types.h"' >> $$@ +ifeq ($(1),32) + $(Q) echo '#include "asm/syscall32.h"' >> $$@ +endif + $(Q) cat $$< | awk '/^__NR/{print "extern long", $(AV)3, \ + substr($(AV)0, index($(AV)0,$(AV)4)), ";"}' >> $$@ + $(Q) echo "#endif /* ASM_SYSCALL_PROTO_H_$(1)__ */" >> $$@ +endef + +define gen-rule-sys-asm +$(sys-asm): $(sys-def) $(sys-asm-common) $(sys-codes) $(sys-proto) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) echo '#include "std/syscall-codes-$(1).h"' >> $$@ + $(Q) echo '#include "$(sys-asm-common-name)"' >> $$@ + $(Q) cat $$< | awk '/^__NR/{print "SYSCALL(", $(AV)3, ",", $(AV)2, ")"}' >> $$@ +endef + +define gen-rule-sys-exec-tbl +$(sys-exec-tbl): $(sys-def) $(sys-codes) $(sys-proto) $(sys-proto-generic) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) cat $$< | awk '/^__NR/{print \ + "SYSCALL(", substr($(AV)3, 5), ",", $(AV)2, ")"}' >> $$@ +endef + +$(sys-codes-generic): $(ARCH_DIR)/std/syscalls/syscall_32.tbl + $(call msg-gen, $@) + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_CODES_H__" >> $@ + $(Q) echo "#define __ASM_CR_SYSCALL_CODES_H__" >> $@ + $(Q) echo '#include "std/syscall-codes-64.h"' >> $@ + $(Q) cat $< | awk '/^__NR/{NR32=$$1; \ + sub("^__NR", "__NR32", NR32); \ + print "\n#ifndef ", NR32; \ + print "#define ", NR32, $$2; \ + print "#endif";}' >> $@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_CODES_H__ */" >> $@ + +$(sys-proto-generic): $(strip $(call map,sys-proto,$(sys-bits))) + $(call msg-gen, $@) + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_PROTO_H__" >> $@ + $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H__" >> $@ + $(Q) echo "" >> $@ + $(Q) echo "#ifdef CONFIG_X86_32" >> $@ + $(Q) echo '#include "std/syscall-32.h"' >> $@ + $(Q) echo "#else" >> $@ + $(Q) echo '#include "std/syscall-64.h"' >> $@ + $(Q) echo "#endif /* CONFIG_X86_32 */" >> $@ + $(Q) echo "" >> $@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H__ */" >> $@ + +$(eval $(call map,gen-rule-sys-codes,$(sys-bits))) +$(eval $(call map,gen-rule-sys-proto,$(sys-bits))) +$(eval $(call map,gen-rule-sys-asm,$(sys-bits))) + +std-headers-deps += $(call sys-codes,$(sys-bits)) +std-headers-deps += $(call sys-proto,$(sys-bits)) +std-headers-deps += $(call sys-asm,$(sys-bits)) +std-headers-deps += $(sys-codes-generic) +std-headers-deps += $(sys-proto-generic) + +$(addprefix $(obj)/,$(std-obj-y:%.o=%.d)): | $(std-headers-deps) +$(addprefix $(obj)/,$(std-obj-y:%.o=%.i)): | $(std-headers-deps) +$(addprefix $(obj)/,$(std-obj-y:%.o=%.s)): | $(std-headers-deps) +$(addprefix $(obj)/,$(std-obj-y)): | $(std-headers-deps) diff --git a/compel/plugins/include/uapi/plugin-std.h b/compel/plugins/include/uapi/plugin-std.h new file mode 100644 index 000000000..292db8839 --- /dev/null +++ b/compel/plugins/include/uapi/plugin-std.h @@ -0,0 +1,6 @@ +#ifndef COMPEL_PLUGIN_STD_STD_H__ +#define COMPEL_PLUGIN_STD_STD_H__ + +#include "uapi/std/syscall.h" + +#endif /* COMPEL_PLUGIN_STD_STD_H__ */ diff --git a/compel/plugins/include/uapi/std/string.h b/compel/plugins/include/uapi/std/string.h new file mode 100644 index 000000000..8aec886bd --- /dev/null +++ b/compel/plugins/include/uapi/std/string.h @@ -0,0 +1,28 @@ +#ifndef COMPEL_PLUGIN_STD_STRING_H__ +#define COMPEL_PLUGIN_STD_STRING_H__ + +#include +#include +#include + +/* Standard file descriptors. */ +#define STDIN_FILENO 0 /* Standard input. */ +#define STDOUT_FILENO 1 /* Standard output. */ +#define STDERR_FILENO 2 /* Standard error output. */ + + +extern void __std_putc(int fd, char c); +extern void __std_puts(int fd, const char *s); +extern void __std_printk(int fd, const char *format, va_list args); +extern void __std_printf(int fd, const char *format, ...); + +#define std_printf(fmt, ...) __std_printf(STDOUT_FILENO, fmt, ##__VA_ARGS__) +#define std_puts(s) __std_puts(STDOUT_FILENO, s) +#define std_putchar(c) __std_putc(STDOUT_FILENO, c) + +extern unsigned long std_strtoul(const char *nptr, char **endptr, int base); +extern void *std_memcpy(void *to, const void *from, unsigned int n); +extern int std_memcmp(const void *cs, const void *ct, size_t count); +extern int std_strcmp(const char *cs, const char *ct); + +#endif /* COMPEL_PLUGIN_STD_STRING_H__ */ diff --git a/compel/plugins/include/uapi/std/syscall-types.h b/compel/plugins/include/uapi/std/syscall-types.h new file mode 100644 index 000000000..1b8188299 --- /dev/null +++ b/compel/plugins/include/uapi/std/syscall-types.h @@ -0,0 +1,55 @@ +/* + * Please add here type definitions if + * syscall prototypes need them. + */ + +#ifndef COMPEL_SYSCALL_TYPES_H__ +#define COMPEL_SYSCALL_TYPES_H__ + +#include +#include +#include +#include +#include +#include +#include + +struct cap_header { + u32 version; + int pid; +}; + +struct cap_data { + u32 eff; + u32 prm; + u32 inh; +}; + +struct robust_list_head; +struct file_handle; +struct itimerspec; +struct io_event; +struct sockaddr; +struct timespec; +struct siginfo; +struct msghdr; +struct rusage; +struct iocb; + +typedef unsigned long aio_context_t; + +#ifndef F_GETFD +# define F_GETFD 1 +#endif + +struct krlimit { + unsigned long rlim_cur; + unsigned long rlim_max; +}; + +/* Type of timers in the kernel. */ +typedef int kernel_timer_t; + +#include "asm/std/syscall-types.h" + +#endif /* COMPEL_SYSCALL_TYPES_H__ */ diff --git a/compel/plugins/std/std.c b/compel/plugins/std/std.c new file mode 100644 index 000000000..b3ea971f9 --- /dev/null +++ b/compel/plugins/std/std.c @@ -0,0 +1,89 @@ +#include + +#include "uapi/int.h" +#include "uapi/plugins.h" +#include "uapi/plugin-std.h" + +extern int main(void *arg_p, unsigned int arg_s); + +static struct prologue_init_args *init_args; +static int ctl_socket = -1; + +int std_ctl_sock(void) +{ + return ctl_socket; +} + +static int init_socket(struct prologue_init_args *args) +{ + int ret; + + ctl_socket = sys_socket(PF_UNIX, SOCK_SEQPACKET, 0); + if (ctl_socket < 0) + return ctl_socket; + + ret = sys_connect(ctl_socket, (struct sockaddr *)&args->ctl_sock_addr, args->ctl_sock_addr_len); + if (ret < 0) + return ret; + + return 0; +} + +static int fini_socket(void) +{ + char buf[32]; + int ret = 0; + + ret = sys_shutdown(ctl_socket, SHUT_WR); + if (ret) + goto err; + + ret = sys_recvfrom(ctl_socket, buf, sizeof(buf), MSG_WAITALL, 0, 0); + if (ret) + goto err; +err: + sys_close(ctl_socket); + ctl_socket = -1; + return ret; +} + +#define plugin_init_count(size) ((size) / (sizeof(plugin_init_t *))) + +int __export_std_compel_start(struct prologue_init_args *args, + const plugin_init_t * const *init_array, + size_t init_size) +{ + unsigned int i; + int ret = 0; + + init_args = args; + + ret = init_socket(args); + if (ret) + return ret; + + for (i = 0; i < plugin_init_count(init_size); i++) { + const plugin_init_t *d = init_array[i]; + + if (d && d->init) { + ret = d->init(); + if (ret) + break; + } + } + + if (!ret) + ret = main(args->arg_p, args->arg_s); + + for (; i > 0; i--) { + const plugin_init_t *d = init_array[i - 1]; + + if (d && d->exit) + d->exit(); + } + + fini_socket(); + return ret; +} + +PLUGIN_REGISTER_DUMMY(std) diff --git a/compel/plugins/std/string.c b/compel/plugins/std/string.c new file mode 100644 index 000000000..f4181f92a --- /dev/null +++ b/compel/plugins/std/string.c @@ -0,0 +1,262 @@ +#include +#include +#include + +#include "uapi/std/syscall.h" +#include "uapi/std/string.h" + +static const char conv_tab[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + +void __std_putc(int fd, char c) +{ + sys_write(fd, &c, 1); +} + +void __std_puts(int fd, const char *s) +{ + for (; *s; s++) + __std_putc(fd, *s); +} + +static size_t __std_vprint_long_hex(char *buf, size_t blen, unsigned long num, char **ps) +{ + char *s = &buf[blen - 2]; + + buf[blen - 1] = '\0'; + + if (num == 0) { + *s = '0', s--; + goto done; + } + + while (num > 0) { + *s = conv_tab[num % 16], s--; + num /= 16; + } + +done: + s++; + *ps = s; + return blen - (s - buf); +} + +static size_t __std_vprint_long(char *buf, size_t blen, long num, char **ps) +{ + char *s = &buf[blen - 2]; + int neg = 0; + + buf[blen - 1] = '\0'; + + if (num < 0) { + neg = 1; + num = -num; + } else if (num == 0) { + *s = '0'; + s--; + goto done; + } + + while (num > 0) { + *s = (num % 10) + '0'; + s--; + num /= 10; + } + + if (neg) { + *s = '-'; + s--; + } +done: + s++; + *ps = s; + return blen - (s - buf); +} + +void __std_printk(int fd, const char *format, va_list args) +{ + const char *s = format; + + for (; *s != '\0'; s++) { + char buf[32], *t; + int along = 0; + + if (*s != '%') { + __std_putc(fd, *s); + continue; + } + + s++; + if (*s == 'l') { + along = 1; + s++; + if (*s == 'l') + s++; + } + + switch (*s) { + case 's': + __std_puts(fd, va_arg(args, char *)); + break; + case 'd': + __std_vprint_long(buf, sizeof(buf), + along ? + va_arg(args, long) : + (long)va_arg(args, int), + &t); + __std_puts(fd, t); + break; + case 'x': + __std_vprint_long_hex(buf, sizeof(buf), + along ? + va_arg(args, long) : + (long)va_arg(args, int), + &t); + __std_puts(fd, t); + break; + } + } +} + +void __std_printf(int fd, const char *format, ...) +{ + va_list args; + + va_start(args, format); + __std_printk(fd, format, args); + va_end(args); +} + +static inline bool __isspace(unsigned char c) +{ + return c == ' ' || c == '\f' || + c == '\n' || c == '\r' || + c == '\t' || c == '\v'; +} + +static unsigned char __tolower(unsigned char c) +{ + return (c <= 'Z' && c >= 'A') ? c - 'A' + 'a' : c; +} + +static inline bool __isalpha(unsigned char c) +{ + return ((c <= 'Z' && c >= 'A') || + (c <= 'z' && c >= 'a')); +} + +static inline bool __isdigit(unsigned char c) +{ + return (c <= '9' && c >= '0'); +} + +static inline bool __isalnum(unsigned char c) +{ + return (__isalpha(c) || __isdigit(c)); +} + +static unsigned int __conv_val(unsigned char c) +{ + if (__isdigit(c)) + return c - '0'; + else if (__isalpha(c)) + return &conv_tab[__tolower(c)] - conv_tab; + return -1u; +} + +unsigned long std_strtoul(const char *nptr, char **endptr, int base) +{ + const char *s = nptr; + bool neg = false; + unsigned int v; + long num = 0; + + if (base < 0 || base == 1 || base > 36) + goto fin; + + while (__isspace(*s)) + s++; + if (!*s) + goto fin; + + if (*s == '-') + neg = true, s++; + + if (base == 0) { + if (s[0] == '0') { + unsigned char p = __tolower(s[1]); + switch (p) { + case 'b': + base = 2, s += 2; + break; + case 'x': + base = 16, s += 2; + break; + default: + base = 8, s += 1; + break; + } + } else + base = 10; + } else if (base == 16) { + if (s[0] == '0' && __tolower(s[1]) == 'x') + s += 2; + } + + for (; *s; s++) { + if (__isspace(*s)) + continue; + if (!__isalnum(*s)) + goto fin; + v = __conv_val(*s); + if (v == -1u || v > base) + goto fin; + num *= base; + num += v; + } + +fin: + if (endptr) + *endptr = (char *)s; + return neg ? (unsigned long)-num : (unsigned long)num; +} + +void *std_memcpy(void *to, const void *from, unsigned int n) +{ + int d0, d1, d2; + asm volatile("rep ; movsl \n" + "movl %4,%%ecx \n" + "andl $3,%%ecx \n" + "jz 1f \n" + "rep ; movsb \n" + "1:" + : "=&c" (d0), "=&D" (d1), "=&S" (d2) + : "0" (n / 4), "g" (n), "1" ((long)to), "2" ((long)from) + : "memory"); + return to; +} + +int std_memcmp(const void *cs, const void *ct, size_t count) +{ + const unsigned char *su1, *su2; + int res = 0; + + for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) + if ((res = *su1 - *su2) != 0) + break; + return res; +} + +int std_strcmp(const char *cs, const char *ct) +{ + unsigned char c1, c2; + + while (1) { + c1 = *cs++; + c2 = *ct++; + if (c1 != c2) + return c1 < c2 ? -1 : 1; + if (!c1) + break; + } + return 0; +} From 12ca38255c61da3de53407d3fe3320dc26cf258b Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 21 Sep 2016 23:54:21 +0300 Subject: [PATCH 0092/4375] compel: remove not needed from uapi Delete plugins/include/asm/std directory - let it be without plugin name. Make symlinks to reuse criu's files, except those, which will be deleted after libcompel from criu (like syscalls). Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/x86/plugins/include/asm/linkage.h | 1 + .../include/asm/{std => }/syscall-types.h | 0 compel/arch/x86/plugins/std/call32.S | 72 +------------------ compel/include/int.h | 1 + compel/include/uapi/int.h | 15 ---- compel/plugins/Makefile | 21 +++--- compel/plugins/include/uapi/plugin-std.h | 9 +++ .../plugins/include/uapi/std/syscall-types.h | 4 +- compel/plugins/std/std.c | 2 +- 9 files changed, 28 insertions(+), 97 deletions(-) create mode 120000 compel/arch/x86/plugins/include/asm/linkage.h rename compel/arch/x86/plugins/include/asm/{std => }/syscall-types.h (100%) mode change 100644 => 120000 compel/arch/x86/plugins/std/call32.S create mode 120000 compel/include/int.h delete mode 100644 compel/include/uapi/int.h diff --git a/compel/arch/x86/plugins/include/asm/linkage.h b/compel/arch/x86/plugins/include/asm/linkage.h new file mode 120000 index 000000000..b1b2fe3ee --- /dev/null +++ b/compel/arch/x86/plugins/include/asm/linkage.h @@ -0,0 +1 @@ +../../../../../../criu/arch/x86/include/asm/linkage.h \ No newline at end of file diff --git a/compel/arch/x86/plugins/include/asm/std/syscall-types.h b/compel/arch/x86/plugins/include/asm/syscall-types.h similarity index 100% rename from compel/arch/x86/plugins/include/asm/std/syscall-types.h rename to compel/arch/x86/plugins/include/asm/syscall-types.h diff --git a/compel/arch/x86/plugins/std/call32.S b/compel/arch/x86/plugins/std/call32.S deleted file mode 100644 index 935461dcd..000000000 --- a/compel/arch/x86/plugins/std/call32.S +++ /dev/null @@ -1,71 +0,0 @@ -/* - * call32.S - assembly helpers for mixed-bitness code - * From kernel selftests originally: tools/testing/selftests/x86/thunks.S - * Copyright (c) 2015 Andrew Lutomirski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * These are little helpers that make it easier to switch bitness on - * the fly. - */ - -#include "asm/linkage.h" - -#define __USER32_CS 0x23 -#define __USER_CS 0x33 - - .text - -/* - * @rdi: Stack to use - * @esi: Pointer to function for calling - */ -ENTRY(call32_from_64) - /* Callee-saving registers due to ABI */ - pushq %rbx - pushq %rbp - pushq %r12 - pushq %r13 - pushq %r14 - pushq %r15 - pushfq - - /* Switch stacks */ - sub $8, %rdi - mov %rsp,(%rdi) - mov %rdi,%rsp - - /* Switch into compatibility mode */ - pushq $__USER32_CS - pushq $1f - lretq - -1: - .code32 - /* Run function and switch back */ - call *%esi - jmp $__USER_CS,$1f - .code64 - -1: - /* Restore the stack */ - mov (%rsp),%rsp - add $8, %rdi - - /* Restore registers */ - popfq - popq %r15 - popq %r14 - popq %r13 - popq %r12 - popq %rbp - popq %rbx - ret -END(call32_from_64) diff --git a/compel/arch/x86/plugins/std/call32.S b/compel/arch/x86/plugins/std/call32.S new file mode 120000 index 000000000..b0fd67bc0 --- /dev/null +++ b/compel/arch/x86/plugins/std/call32.S @@ -0,0 +1 @@ +../../../../../criu/arch/x86/call32.S \ No newline at end of file diff --git a/compel/include/int.h b/compel/include/int.h new file mode 120000 index 000000000..5c118d596 --- /dev/null +++ b/compel/include/int.h @@ -0,0 +1 @@ +../../criu/include/asm-generic/int.h \ No newline at end of file diff --git a/compel/include/uapi/int.h b/compel/include/uapi/int.h deleted file mode 100644 index ac3088d5a..000000000 --- a/compel/include/uapi/int.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __CR_INT_H__ -#define __CR_INT_H__ - -#include - -typedef uint64_t u64; -typedef int64_t s64; -typedef uint32_t u32; -typedef int32_t s32; -typedef uint16_t u16; -typedef int16_t s16; -typedef uint8_t u8; -typedef int8_t s8; - -#endif /* __CR_INT_H__ */ diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index f0b1de802..626a9782f 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -2,24 +2,27 @@ ARCH_DIR := compel/arch/$(ARCH)/plugins -ccflags-y += -iquote $(obj)/include/ -ccflags-y += -iquote $(obj)/include/uapi -ccflags-y += -iquote $(SRC_DIR)/criu/include -ccflags-y += -iquote $(SRC_DIR)/criu/arch/$(ARCH)/include +# General compel includes ccflags-y += -iquote $(SRC_DIR)/compel/include -ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR)/include -asflags-y += -iquote $(SRC_DIR)/criu/arch/$(ARCH)/include -asflags-y += -iquote $(SRC_DIR)/compel/plugins/include/uapi +# General compel/plugins includes +ccflags-y += -iquote $(obj)/include +ccflags-y += -iquote $(obj)/include/uapi +asflags-y += -iquote $(obj)/include/uapi + +# Arch compel/plugins includes +ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR)/include +asflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR)/include asflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR) + # # STD plugin target += std std-obj-y += std/std.o std-obj-y += std/string.o -std-obj-y += arch/$(ARCH)/plugins/std/syscalls-64.o -std-obj-y += arch/$(ARCH)/plugins/std/calls32.o +std-obj-y += ./$(ARCH_DIR)/std/syscalls-64.o +std-obj-y += ./$(ARCH_DIR)/std/call32.o sys-proto-generic := $(obj)/include/uapi/std/syscall.h sys-codes-generic := $(obj)/include/uapi/std/syscall-codes.h diff --git a/compel/plugins/include/uapi/plugin-std.h b/compel/plugins/include/uapi/plugin-std.h index 292db8839..5eaa31f04 100644 --- a/compel/plugins/include/uapi/plugin-std.h +++ b/compel/plugins/include/uapi/plugin-std.h @@ -1,6 +1,15 @@ #ifndef COMPEL_PLUGIN_STD_STD_H__ #define COMPEL_PLUGIN_STD_STD_H__ +#include "uapi/plugins.h" #include "uapi/std/syscall.h" +struct prologue_init_args { + struct sockaddr *ctl_sock_addr; + socklen_t ctl_sock_addr_len; + + unsigned int arg_s; + void *arg_p; +}; + #endif /* COMPEL_PLUGIN_STD_STD_H__ */ diff --git a/compel/plugins/include/uapi/std/syscall-types.h b/compel/plugins/include/uapi/std/syscall-types.h index 1b8188299..564d027f2 100644 --- a/compel/plugins/include/uapi/std/syscall-types.h +++ b/compel/plugins/include/uapi/std/syscall-types.h @@ -14,6 +14,8 @@ #include #include +#include "int.h" + struct cap_header { u32 version; int pid; @@ -50,6 +52,6 @@ struct krlimit { /* Type of timers in the kernel. */ typedef int kernel_timer_t; -#include "asm/std/syscall-types.h" +#include "asm/syscall-types.h" #endif /* COMPEL_SYSCALL_TYPES_H__ */ diff --git a/compel/plugins/std/std.c b/compel/plugins/std/std.c index b3ea971f9..69bbb9bed 100644 --- a/compel/plugins/std/std.c +++ b/compel/plugins/std/std.c @@ -1,6 +1,6 @@ #include -#include "uapi/int.h" +#include "int.h" #include "uapi/plugins.h" #include "uapi/plugin-std.h" From 338f3aa7b7e3cc58df77df1c5e09b7b8a648bf76 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 21 Sep 2016 23:54:22 +0300 Subject: [PATCH 0093/4375] compel: make -- Add general assembly flags Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 626a9782f..d25829a90 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -15,6 +15,10 @@ ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR)/include asflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR)/include asflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR) +# General flags for assembly +asflags-y += -Wstrict-prototypes -Wa,--noexecstack +asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer + # # STD plugin From 23fcca8e877f7e9d96f14af8954048d2a21f63ac Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 21 Sep 2016 23:54:23 +0300 Subject: [PATCH 0094/4375] compel: Makefile.compel -- Remove second GEN msg Fixes: GEN compel/include/version.h GEN compel/include/version.h Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile.compel | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile.compel b/Makefile.compel index dd60defbf..b18cd8edc 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -2,7 +2,6 @@ COMPEL_VERSION_HEADER := compel/include/version.h $(COMPEL_VERSION_HEADER): $(SRC_DIR)/Makefile.versions $(call msg-gen, $(COMPEL_VERSION_HEADER)) - $(E) " GEN " $@ $(Q) echo "/* Autogenerated, do not edit */" > $(COMPEL_VERSION_HEADER) $(Q) echo "#ifndef COMPEL_SO_VERSION_H__" >> $(COMPEL_VERSION_HEADER) $(Q) echo "#define COMPEL_SO_VERSION_H__" >> $(COMPEL_VERSION_HEADER) From 7eee9d5c3da299e459b3d73970903e7b9cd4fd34 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 21 Sep 2016 23:54:24 +0300 Subject: [PATCH 0095/4375] compel: plugins -- Add prologue.h from compel, drop hand-made prologue_init_args Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .../arch/x86/plugins/include/asm/prologue.h | 36 +++++++++++++++++++ compel/plugins/include/uapi/plugin-std.h | 8 ----- compel/plugins/std/std.c | 2 ++ 3 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 compel/arch/x86/plugins/include/asm/prologue.h diff --git a/compel/arch/x86/plugins/include/asm/prologue.h b/compel/arch/x86/plugins/include/asm/prologue.h new file mode 100644 index 000000000..9d812eec9 --- /dev/null +++ b/compel/arch/x86/plugins/include/asm/prologue.h @@ -0,0 +1,36 @@ +#ifndef __ASM_PROLOGUE_H__ +#define __ASM_PROLOGUE_H__ + +#ifndef __ASSEMBLY__ + +#include +#include +#include + +#include + +#define sys_recv(sockfd, ubuf, size, flags) \ + sys_recvfrom(sockfd, ubuf, size, flags, NULL, NULL) + +typedef struct prologue_init_args { + struct sockaddr_un ctl_sock_addr; + unsigned int ctl_sock_addr_len; + + unsigned int arg_s; + void *arg_p; + + void *sigframe; +} prologue_init_args_t; + +#endif /* __ASSEMBLY__ */ + +/* + * Reserve enough space for sigframe. + * + * FIXME It is rather should be taken from sigframe header. + */ +#define PROLOGUE_SGFRAME_SIZE 4096 + +#define PROLOGUE_INIT_ARGS_SIZE 1024 + +#endif /* __ASM_PROLOGUE_H__ */ diff --git a/compel/plugins/include/uapi/plugin-std.h b/compel/plugins/include/uapi/plugin-std.h index 5eaa31f04..b77a7b449 100644 --- a/compel/plugins/include/uapi/plugin-std.h +++ b/compel/plugins/include/uapi/plugin-std.h @@ -4,12 +4,4 @@ #include "uapi/plugins.h" #include "uapi/std/syscall.h" -struct prologue_init_args { - struct sockaddr *ctl_sock_addr; - socklen_t ctl_sock_addr_len; - - unsigned int arg_s; - void *arg_p; -}; - #endif /* COMPEL_PLUGIN_STD_STD_H__ */ diff --git a/compel/plugins/std/std.c b/compel/plugins/std/std.c index 69bbb9bed..19090d7f7 100644 --- a/compel/plugins/std/std.c +++ b/compel/plugins/std/std.c @@ -4,6 +4,8 @@ #include "uapi/plugins.h" #include "uapi/plugin-std.h" +#include "asm/prologue.h" + extern int main(void *arg_p, unsigned int arg_s); static struct prologue_init_args *init_args; From 5cf76474f180e2c302a743a3bc9cc0acaaaf0f08 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 21 Sep 2016 23:54:25 +0300 Subject: [PATCH 0096/4375] compel: plugins,std -- Add prologue.S The prologue includes routines needed for parasite blob to work and is always included with the std plugin. Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/x86/plugins/include/asm/linkage.h | 1 - compel/arch/x86/plugins/std/prologue.S | 33 +++++++++++++++++++ .../std/syscalls/syscall-common-x86-32.S | 2 +- .../std/syscalls/syscall-common-x86-64.S | 2 +- compel/plugins/Makefile | 2 ++ 5 files changed, 37 insertions(+), 3 deletions(-) delete mode 120000 compel/arch/x86/plugins/include/asm/linkage.h create mode 100644 compel/arch/x86/plugins/std/prologue.S diff --git a/compel/arch/x86/plugins/include/asm/linkage.h b/compel/arch/x86/plugins/include/asm/linkage.h deleted file mode 120000 index b1b2fe3ee..000000000 --- a/compel/arch/x86/plugins/include/asm/linkage.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../criu/arch/x86/include/asm/linkage.h \ No newline at end of file diff --git a/compel/arch/x86/plugins/std/prologue.S b/compel/arch/x86/plugins/std/prologue.S new file mode 100644 index 000000000..79ad1f6f2 --- /dev/null +++ b/compel/arch/x86/plugins/std/prologue.S @@ -0,0 +1,33 @@ +#include "common/asm/linkage.h" +#include "asm/prologue.h" + +#include "uapi/std/syscall-codes.h" + + .section .compel.prologue.text, "ax" +ENTRY(__export_std_prologue_start) + push %rsp + + leaq __export_std_prologue_init_args(%rip), %rdi + movq __export_std_plugin_begin(%rip), %rsi + movq __export_std_plugin_size(%rip), %rdx + call __export_std_compel_start + +do_rt_sigreturn: + leaq __export_std_prologue_sigframe(%rip), %rax + addq $8, %rax + movq %rax, %rsp # we can't use sys_rt_sigreturn here + mov $__NR_rt_sigreturn, %eax # because we're adjusting stack + syscall + +GLOBAL(__export_std_prologue_init_args) + .space PROLOGUE_INIT_ARGS_SIZE, 0 + +GLOBAL(__export_std_plugin_begin) + .space 8, 0 +GLOBAL(__export_std_plugin_size) + .space 8, 0 + + .align 64 +GLOBAL(__export_std_prologue_sigframe) + .space PROLOGUE_SGFRAME_SIZE, 0 +END(__export_std_prologue_start) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-32.S b/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-32.S index ae6d594dc..c1a726123 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-32.S +++ b/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-32.S @@ -1,4 +1,4 @@ -#include "asm/linkage.h" +#include "common/asm/linkage.h" #define SYSCALL(name, opcode) \ ENTRY(name); \ diff --git a/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-64.S b/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-64.S index b93c31288..74465c302 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-64.S +++ b/compel/arch/x86/plugins/std/syscalls/syscall-common-x86-64.S @@ -1,4 +1,4 @@ -#include "asm/linkage.h" +#include "common/asm/linkage.h" #define SYSCALL(name, opcode) \ ENTRY(name); \ diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index d25829a90..3743f3a9c 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -8,6 +8,7 @@ ccflags-y += -iquote $(SRC_DIR)/compel/include # General compel/plugins includes ccflags-y += -iquote $(obj)/include ccflags-y += -iquote $(obj)/include/uapi +asflags-y += -iquote $(obj)/include asflags-y += -iquote $(obj)/include/uapi # Arch compel/plugins includes @@ -27,6 +28,7 @@ std-obj-y += std/std.o std-obj-y += std/string.o std-obj-y += ./$(ARCH_DIR)/std/syscalls-64.o std-obj-y += ./$(ARCH_DIR)/std/call32.o +std-obj-y += ./$(ARCH_DIR)/std/prologue.o sys-proto-generic := $(obj)/include/uapi/std/syscall.h sys-codes-generic := $(obj)/include/uapi/std/syscall-codes.h From a1d931c3547526c516de43bb3e0cbb0257a8d21a Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 21 Sep 2016 23:54:26 +0300 Subject: [PATCH 0097/4375] compel: plugins -- Add shmem plugin The shmem pluging allows creation of shared memory segment between parasite code and the caller. Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/shmem.h | 10 ++++++ compel/plugins/Makefile | 7 ++++ compel/plugins/include/std-priv.h | 6 ++++ compel/plugins/include/uapi/plugin-shmem.h | 17 ++++++++++ compel/plugins/shmem/shmem.c | 38 ++++++++++++++++++++++ 5 files changed, 78 insertions(+) create mode 100644 compel/include/shmem.h create mode 100644 compel/plugins/include/std-priv.h create mode 100644 compel/plugins/include/uapi/plugin-shmem.h create mode 100644 compel/plugins/shmem/shmem.c diff --git a/compel/include/shmem.h b/compel/include/shmem.h new file mode 100644 index 000000000..b6f994617 --- /dev/null +++ b/compel/include/shmem.h @@ -0,0 +1,10 @@ +#ifndef __COMPEL_PLUGIN_SHMEM_PRIV_H__ +#define __COMPEL_PLUGIN_SHMEM_PRIV_H__ + +struct shmem_plugin_msg { + unsigned long start; + unsigned long len; +}; + +#endif /* __COMPEL_PLUGIN_SHMEM_PRIV_H__ */ + diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 3743f3a9c..9480264bd 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -2,6 +2,9 @@ ARCH_DIR := compel/arch/$(ARCH)/plugins +# +# CFLAGS, ASFLAGS, LDFLAGS + # General compel includes ccflags-y += -iquote $(SRC_DIR)/compel/include @@ -20,6 +23,10 @@ asflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR) asflags-y += -Wstrict-prototypes -Wa,--noexecstack asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer +# +# Shmem plugin +target += shmem +shmem-obj-y += shmem/shmem.o # # STD plugin diff --git a/compel/plugins/include/std-priv.h b/compel/plugins/include/std-priv.h new file mode 100644 index 000000000..3fc3041c0 --- /dev/null +++ b/compel/plugins/include/std-priv.h @@ -0,0 +1,6 @@ +#ifndef __COMPEL_PLUGIN_STD_PRIV_H__ +#define __COMPEL_PLUGIN_STD_PRIV_H__ + +extern int std_ctl_sock(void); + +#endif /* __COMPEL_PLUGIN_STD_PRIV_H__ */ diff --git a/compel/plugins/include/uapi/plugin-shmem.h b/compel/plugins/include/uapi/plugin-shmem.h new file mode 100644 index 000000000..7e5850953 --- /dev/null +++ b/compel/plugins/include/uapi/plugin-shmem.h @@ -0,0 +1,17 @@ +#ifndef __COMPEL_PLUGIN_SHMEM_H__ +#define __COMPEL_PLUGIN_SHMEM_H__ + +/* + * Creates local shmem mapping and announces it + * to the peer. Peer can later "receive" one. The + * local area should be munmap()-ed at the end. + */ +extern void *shmem_create(unsigned long size); +/* + * "Receives" shmem from peer and maps it. The + * locally mapped area should be munmap()-ed at + * the end + */ +extern void *shmem_receive(unsigned long *size); + +#endif /* __COMPEL_PLUGIN_SHMEM_H__ */ diff --git a/compel/plugins/shmem/shmem.c b/compel/plugins/shmem/shmem.c new file mode 100644 index 000000000..9ded93fb3 --- /dev/null +++ b/compel/plugins/shmem/shmem.c @@ -0,0 +1,38 @@ +#include + +#include "uapi/plugins.h" +#include "uapi/plugin-shmem.h" +#include "uapi/std/syscall.h" +#include "shmem.h" +#include "std-priv.h" + +void *shmem_create(unsigned long size) +{ + int ret; + void *mem; + struct shmem_plugin_msg spi; + + mem = (void *)sys_mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANON, 0, 0); + if (mem == MAP_FAILED) + return NULL; + + spi.start = (unsigned long)mem; + spi.len = size; + + ret = sys_write(std_ctl_sock(), &spi, sizeof(spi)); + if (ret != sizeof(spi)) { + sys_munmap(mem, size); + return NULL; + } + + return mem; +} + +void *shmem_receive(unsigned long *size) +{ + /* master -> parasite not implemented yet */ + return NULL; +} + +PLUGIN_REGISTER_DUMMY(shmem) From 048c5073cfef07b81f32ea24fd6d8e3e6e663336 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 21 Sep 2016 23:54:27 +0300 Subject: [PATCH 0098/4375] compel: plugins,std -- Use sys_recvfrom instead of recv prologue.h defines sys_recv() macro - let's use it by now Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/std/std.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/plugins/std/std.c b/compel/plugins/std/std.c index 19090d7f7..6894a6921 100644 --- a/compel/plugins/std/std.c +++ b/compel/plugins/std/std.c @@ -40,7 +40,7 @@ static int fini_socket(void) if (ret) goto err; - ret = sys_recvfrom(ctl_socket, buf, sizeof(buf), MSG_WAITALL, 0, 0); + ret = sys_recv(ctl_socket, buf, sizeof(buf), MSG_WAITALL); if (ret) goto err; err: From 66929a661c8d98b89899a86b7c08a1200a4145f0 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 21 Sep 2016 23:54:28 +0300 Subject: [PATCH 0099/4375] compel: plugins -- Add fds plugin This is fd passing via unix sockets (scm creds) suitable for use by parasite code. Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/compiler.h | 1 + compel/plugins/Makefile | 5 + compel/plugins/fds/fds.c | 26 ++++++ compel/plugins/include/uapi/plugin-fds.h | 27 ++++++ compel/src/shared/fds.c | 113 +++++++++++++++++++++++ 5 files changed, 172 insertions(+) create mode 120000 compel/include/compiler.h create mode 100644 compel/plugins/fds/fds.c create mode 100644 compel/plugins/include/uapi/plugin-fds.h create mode 100644 compel/src/shared/fds.c diff --git a/compel/include/compiler.h b/compel/include/compiler.h new file mode 120000 index 000000000..ef56d20f6 --- /dev/null +++ b/compel/include/compiler.h @@ -0,0 +1 @@ +../../criu/include/compiler.h \ No newline at end of file diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 9480264bd..a30597ad8 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -23,6 +23,11 @@ asflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR) asflags-y += -Wstrict-prototypes -Wa,--noexecstack asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer +# +# Fds plugin +target += fds +fds-obj-y += fds/fds.o + # # Shmem plugin target += shmem diff --git a/compel/plugins/fds/fds.c b/compel/plugins/fds/fds.c new file mode 100644 index 000000000..fa739058f --- /dev/null +++ b/compel/plugins/fds/fds.c @@ -0,0 +1,26 @@ +#include "uapi/plugins.h" + +#include "uapi/std/syscall.h" +#include "uapi/std/string.h" +#include "uapi/plugin-fds.h" + +#include "std-priv.h" + +#include "compiler.h" + +#define __sys(foo) sys_##foo +#define __std(foo) std_##foo + +#include "../../src/shared/fds.c" + +int fds_send(int *fds, int nr_fds) +{ + return fds_send_via(std_ctl_sock(), fds, nr_fds); +} + +int fds_recv(int *fds, int nr_fds) +{ + return fds_recv_via(std_ctl_sock(), fds, nr_fds); +} + +PLUGIN_REGISTER_DUMMY(fds) diff --git a/compel/plugins/include/uapi/plugin-fds.h b/compel/plugins/include/uapi/plugin-fds.h new file mode 100644 index 000000000..96991eaa4 --- /dev/null +++ b/compel/plugins/include/uapi/plugin-fds.h @@ -0,0 +1,27 @@ +/* + * plugin-fds.h -- API for fds compel plugin + */ + +#ifndef __COMPEL_PLUGIN_FDS_H__ +#define __COMPEL_PLUGIN_FDS_H__ + +extern int fds_send(int *fds, int nr_fds); +extern int fds_recv(int *fds, int nr_fds); + +static inline int fds_send_one(int fd) +{ + return fds_send(&fd, 1); +} + +static inline int fds_recv_one(void) +{ + int fd, ret; + + ret = fds_recv(&fd, 1); + if (ret) + fd = -1; + + return fd; +} + +#endif /* __COMPEL_PLUGIN_FDS_H__ */ diff --git a/compel/src/shared/fds.c b/compel/src/shared/fds.c new file mode 100644 index 000000000..9bf49cbdd --- /dev/null +++ b/compel/src/shared/fds.c @@ -0,0 +1,113 @@ +#include +#include + +/* + * Because of kernel doing kmalloc for user data passed + * in SCM messages, and there is kernel's SCM_MAX_FD as a limit + * for descriptors passed at once we're trying to reduce + * the pressue on kernel memory manager and use predefined + * known to work well size of the message buffer. + */ +#define CR_SCM_MSG_SIZE (1024) +#define CR_SCM_MAX_FD (252) + +struct scm_fdset { + struct msghdr hdr; + struct iovec iov; + char msg_buf[CR_SCM_MSG_SIZE]; + char f; +}; + +static void scm_fdset_init_chunk(struct scm_fdset *fdset, int nr_fds) +{ + struct cmsghdr *cmsg; + + fdset->hdr.msg_controllen = CMSG_LEN(sizeof(int) * nr_fds); + + cmsg = CMSG_FIRSTHDR(&fdset->hdr); + cmsg->cmsg_len = fdset->hdr.msg_controllen; +} + +static int *scm_fdset_init(struct scm_fdset *fdset) +{ + struct cmsghdr *cmsg; + + BUILD_BUG_ON(sizeof(fdset->msg_buf) < (CMSG_SPACE(sizeof(int) * CR_SCM_MAX_FD))); + + fdset->iov.iov_base = &fdset->f; + fdset->iov.iov_len = 1; + + fdset->hdr.msg_iov = &fdset->iov; + fdset->hdr.msg_iovlen = 1; + fdset->hdr.msg_name = NULL; + fdset->hdr.msg_namelen = 0; + + fdset->hdr.msg_control = &fdset->msg_buf; + fdset->hdr.msg_controllen = CMSG_LEN(sizeof(int) * CR_SCM_MAX_FD); + + cmsg = CMSG_FIRSTHDR(&fdset->hdr); + cmsg->cmsg_len = fdset->hdr.msg_controllen; + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + return (int *)CMSG_DATA(cmsg); +} + +int fds_send_via(int sock, int *fds, int nr_fds) +{ + struct scm_fdset fdset; + int i, min_fd, ret; + int *cmsg_data; + + cmsg_data = scm_fdset_init(&fdset); + + for (i = 0; i < nr_fds; i += min_fd) { + min_fd = min(CR_SCM_MAX_FD, nr_fds - i); + scm_fdset_init_chunk(&fdset, min_fd); + __std(memcpy(cmsg_data, &fds[i], sizeof(int) * min_fd)); + ret = __sys(sendmsg(sock, &fdset.hdr, 0)); + if (ret <= 0) + return ret ? : -1; + } + + return 0; +} + +int fds_recv_via(int sock, int *fds, int nr_fds) +{ + struct scm_fdset fdset; + struct cmsghdr *cmsg; + int *cmsg_data; + int ret; + int i, min_fd; + + cmsg_data = scm_fdset_init(&fdset); + for (i = 0; i < nr_fds; i += min_fd) { + min_fd = min(CR_SCM_MAX_FD, nr_fds - i); + scm_fdset_init_chunk(&fdset, min_fd); + + ret = __sys(recvmsg(sock, &fdset.hdr, 0)); + if (ret <= 0) + return ret ? : -1; + + cmsg = CMSG_FIRSTHDR(&fdset.hdr); + if (!cmsg || cmsg->cmsg_type != SCM_RIGHTS) + return -1; + if (fdset.hdr.msg_flags & MSG_CTRUNC) + return -2; + + min_fd = (cmsg->cmsg_len - sizeof(struct cmsghdr)) / sizeof(int); + /* + * In case if kernel screwed the recepient, most probably + * the caller stack frame will be overwriten, just scream + * and exit. + */ + if (unlikely(min_fd > CR_SCM_MAX_FD)) + *(volatile unsigned long *)NULL = 0xdead0000 + __LINE__; + if (unlikely(min_fd <= 0)) + return -1; + __std(memcpy(&fds[i], cmsg_data, sizeof(int) * min_fd)); + } + + return 0; +} From 1f560c5f0cc93e2e4faa05b22542817fcb76cdf4 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 21 Sep 2016 23:54:29 +0300 Subject: [PATCH 0100/4375] compel: Get rid of old piegen code Use new compel.h header with appropriate types. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/compel.h | 10 ---------- compel/include/uapi/types.h | 1 - compel/src/lib/handle-elf.c | 4 ++-- criu/pie/pie-relocs.c | 10 +++++----- criu/pie/pie-relocs.h | 4 ++-- 5 files changed, 9 insertions(+), 20 deletions(-) delete mode 120000 compel/include/uapi/types.h diff --git a/compel/include/uapi/compel.h b/compel/include/uapi/compel.h index 67b67c476..10507ce3f 100644 --- a/compel/include/uapi/compel.h +++ b/compel/include/uapi/compel.h @@ -14,14 +14,4 @@ typedef struct { long value; } compel_reloc_t; -/* - * FIXME: Backward compat layer for CRIU. Need to - * drop it later, before the release. - */ - -#define elf_reloc_t compel_reloc_t -#define PIEGEN_TYPE_INT COMPEL_TYPE_INT -#define PIEGEN_TYPE_LONG COMPEL_TYPE_LONG -#define PIEGEN_TYPE_GOTPCREL COMPEL_TYPE_GOTPCREL - #endif /* UAPI_COMPEL_H__ */ diff --git a/compel/include/uapi/types.h b/compel/include/uapi/types.h deleted file mode 120000 index 28c80ee9f..000000000 --- a/compel/include/uapi/types.h +++ /dev/null @@ -1 +0,0 @@ -compel.h \ No newline at end of file diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index 3aaa2a2fa..32759fe0f 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -222,7 +222,7 @@ int __handle_elf(void *mem, size_t size) } pr_out("/* Autogenerated from %s */\n", opts.input_filename); - pr_out("#include \"%s/types.h\"\n", opts.uapi_dir); + pr_out("#include \"%s/compel.h\"\n", opts.uapi_dir); for (i = 0; i < symtab_hdr->sh_size / symtab_hdr->sh_entsize; i++) { Elf_Sym *sym = &symbols[i]; @@ -265,7 +265,7 @@ int __handle_elf(void *mem, size_t size) } } - pr_out("static __maybe_unused elf_reloc_t %s[] = {\n", opts.var_name); + pr_out("static __maybe_unused compel_reloc_t %s[] = {\n", opts.var_name); pr_debug("Relocations\n"); pr_debug("------------\n"); diff --git a/criu/pie/pie-relocs.c b/criu/pie/pie-relocs.c index 4e4924845..eac507b55 100644 --- a/criu/pie/pie-relocs.c +++ b/criu/pie/pie-relocs.c @@ -17,19 +17,19 @@ #include "log.h" #include "common/compiler.h" -#include "compel/include/uapi/types.h" +#include "compel/include/uapi/compel.h" #include "common/bug.h" -__maybe_unused void elf_relocs_apply(void *mem, void *vbase, size_t size, elf_reloc_t *elf_relocs, size_t nr_relocs) +__maybe_unused void elf_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *elf_relocs, size_t nr_relocs) { size_t i, j; for (i = 0, j = 0; i < nr_relocs; i++) { - if (elf_relocs[i].type & PIEGEN_TYPE_LONG) { + if (elf_relocs[i].type & COMPEL_TYPE_LONG) { long *where = mem + elf_relocs[i].offset; long *p = mem + size; - if (elf_relocs[i].type & PIEGEN_TYPE_GOTPCREL) { + if (elf_relocs[i].type & COMPEL_TYPE_GOTPCREL) { int *value = (int *)where; int rel; @@ -40,7 +40,7 @@ __maybe_unused void elf_relocs_apply(void *mem, void *vbase, size_t size, elf_re j++; } else *where = elf_relocs[i].value + elf_relocs[i].addend + (unsigned long)vbase; - } else if (elf_relocs[i].type & PIEGEN_TYPE_INT) { + } else if (elf_relocs[i].type & COMPEL_TYPE_INT) { int *where = (mem + elf_relocs[i].offset); *where = elf_relocs[i].value + elf_relocs[i].addend + (unsigned long)vbase; } else diff --git a/criu/pie/pie-relocs.h b/criu/pie/pie-relocs.h index f768739d8..1cabfe1d9 100644 --- a/criu/pie/pie-relocs.h +++ b/criu/pie/pie-relocs.h @@ -1,7 +1,7 @@ #ifndef __PIE_RELOCS_H__ #define __PIE_RELOCS_H__ -#include "compel/include/uapi/types.h" +#include "compel/include/uapi/compel.h" #include "common/compiler.h" #include "config.h" @@ -9,7 +9,7 @@ #ifdef CONFIG_PIEGEN extern __maybe_unused void elf_relocs_apply(void *mem, void *vbase, size_t size, - elf_reloc_t *elf_relocs, size_t nr_relocs); + compel_reloc_t *elf_relocs, size_t nr_relocs); #define pie_size(__pie_name) (round_up(sizeof(__pie_name##_blob) + \ __pie_name ## _nr_gotpcrel * sizeof(long), page_size())) #define ELF_RELOCS_APPLY(__pie_name, __mem, __vbase) \ From f20a1242698f7cb31836f292c5c27b92c4ee88f5 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 21 Sep 2016 23:54:30 +0300 Subject: [PATCH 0101/4375] compel: Build host program The default compel binary is the one compiled for target architecture. The compel-host one is compel compiled for current arch that is needed to build something for target arch. We could use default compel if target arch == current arch, but this makes things more complex. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 9 +++++++++ compel/arch/x86/src/lib/handle-elf-host.c | 1 + compel/src/lib/handle-elf-32-host.c | 1 + compel/src/lib/handle-elf-host.c | 1 + compel/src/main-host.c | 1 + 5 files changed, 13 insertions(+) create mode 120000 compel/arch/x86/src/lib/handle-elf-host.c create mode 120000 compel/src/lib/handle-elf-32-host.c create mode 120000 compel/src/lib/handle-elf-host.c create mode 120000 compel/src/main-host.c diff --git a/compel/Makefile b/compel/Makefile index 52eb27ea7..001ed385e 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -19,5 +19,14 @@ obj-y += src/main.o CFLAGS_handle-elf-32.o += -UCONFIG_X86_64 -DCONFIG_X86_32 CFLAGS_handle-elf-32.d += -UCONFIG_X86_64 -DCONFIG_X86_32 +host-ccflags-y += $(ccflags-y) + +hostprogs-y += compel-host +compel-host-objs := $(patsubst %.o,%-host.o,$(obj-y) $(lib-y)) + +HOSTCFLAGS_handle-elf-32-host.o += -UCONFIG_X86_64 -DCONFIG_X86_32 +HOSTCFLAGS_handle-elf-32-host.d += -UCONFIG_X86_64 -DCONFIG_X86_32 + cleanup-y += compel/compel +cleanup-y += compel/compel-host cleanup-y += compel/libcompel.so diff --git a/compel/arch/x86/src/lib/handle-elf-host.c b/compel/arch/x86/src/lib/handle-elf-host.c new file mode 120000 index 000000000..fe4611886 --- /dev/null +++ b/compel/arch/x86/src/lib/handle-elf-host.c @@ -0,0 +1 @@ +handle-elf.c \ No newline at end of file diff --git a/compel/src/lib/handle-elf-32-host.c b/compel/src/lib/handle-elf-32-host.c new file mode 120000 index 000000000..126cd5984 --- /dev/null +++ b/compel/src/lib/handle-elf-32-host.c @@ -0,0 +1 @@ +handle-elf-32.c \ No newline at end of file diff --git a/compel/src/lib/handle-elf-host.c b/compel/src/lib/handle-elf-host.c new file mode 120000 index 000000000..fe4611886 --- /dev/null +++ b/compel/src/lib/handle-elf-host.c @@ -0,0 +1 @@ +handle-elf.c \ No newline at end of file diff --git a/compel/src/main-host.c b/compel/src/main-host.c new file mode 120000 index 000000000..8a03e9439 --- /dev/null +++ b/compel/src/main-host.c @@ -0,0 +1 @@ +main.c \ No newline at end of file From c4030e283b5da5831d5bbbda6ddb2dbaed84b6a6 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 21 Sep 2016 23:54:31 +0300 Subject: [PATCH 0102/4375] compel: criu -- Use compel-host program compel-host is needed to build criu itself and run during piegen blob generation. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 4 ++-- criu/pie/Makefile | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 1c8702beb..6cbbdd220 100644 --- a/Makefile +++ b/Makefile @@ -226,9 +226,9 @@ $(SOCCR_A): |soccr/built-in.o # # But note that we're already included # the nmk so we can reuse it there. -criu/%: images/built-in.o compel/compel $(VERSION_HEADER) $(CONFIG_HEADER) .FORCE +criu/%: images/built-in.o compel/compel-host $(VERSION_HEADER) $(CONFIG_HEADER) .FORCE $(Q) $(MAKE) $(build)=criu $@ -criu: images/built-in.o compel/compel $(SOCCR_A) $(VERSION_HEADER) $(CONFIG_HEADER) +criu: images/built-in.o compel/compel-host $(SOCCR_A) $(VERSION_HEADER) $(CONFIG_HEADER) $(Q) $(MAKE) $(build)=criu all .PHONY: criu diff --git a/criu/pie/Makefile b/criu/pie/Makefile index eff91cc70..df3cd821f 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -57,9 +57,9 @@ CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 ccflags-y += -DCR_NOGLIBC ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) -NATIVE_CFLAGS := $(shell $(SRC_DIR)/compel/compel --arch=$(ARCH) cflags) +NATIVE_CFLAGS := $(shell $(SRC_DIR)/compel/compel-host --arch=$(ARCH) cflags) ifeq ($(ARCH),x86) - COMPAT_CFLAGS := $(shell $(SRC_DIR)/compel/compel --arch=ia32 cflags) + COMPAT_CFLAGS := $(shell $(SRC_DIR)/compel/compel-host --arch=ia32 cflags) endif endif @@ -157,9 +157,9 @@ $(obj)/parasite-$(1).built-in.bin.o: $(obj)/$(1).built-in.o \ endef $(eval $(call map,gen-rule-built-in.bin.o,$(parasite_target))) -$(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel +$(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host $(call msg-gen, $@) - $(Q) $(SRC_DIR)/compel/compel piegen -f $< \ + $(Q) $(SRC_DIR)/compel/compel-host piegen -f $< \ -v $(call target-name,$@)_relocs \ -p $(call target-name,$@)_blob_offset__ \ -s $(call target-name,$@)_blob \ From fbd6582c5a32ca19f37fbdaa5279089193712093 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 21 Sep 2016 23:54:32 +0300 Subject: [PATCH 0103/4375] compel: Add missing symlinks for host elf handling Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/handle-elf-host.c | 1 + compel/arch/arm/src/lib/handle-elf-host.c | 1 + compel/arch/ppc64/src/lib/handle-elf-host.c | 1 + 3 files changed, 3 insertions(+) create mode 120000 compel/arch/aarch64/src/lib/handle-elf-host.c create mode 120000 compel/arch/arm/src/lib/handle-elf-host.c create mode 120000 compel/arch/ppc64/src/lib/handle-elf-host.c diff --git a/compel/arch/aarch64/src/lib/handle-elf-host.c b/compel/arch/aarch64/src/lib/handle-elf-host.c new file mode 120000 index 000000000..fe4611886 --- /dev/null +++ b/compel/arch/aarch64/src/lib/handle-elf-host.c @@ -0,0 +1 @@ +handle-elf.c \ No newline at end of file diff --git a/compel/arch/arm/src/lib/handle-elf-host.c b/compel/arch/arm/src/lib/handle-elf-host.c new file mode 120000 index 000000000..fe4611886 --- /dev/null +++ b/compel/arch/arm/src/lib/handle-elf-host.c @@ -0,0 +1 @@ +handle-elf.c \ No newline at end of file diff --git a/compel/arch/ppc64/src/lib/handle-elf-host.c b/compel/arch/ppc64/src/lib/handle-elf-host.c new file mode 120000 index 000000000..fe4611886 --- /dev/null +++ b/compel/arch/ppc64/src/lib/handle-elf-host.c @@ -0,0 +1 @@ +handle-elf.c \ No newline at end of file From 11282c6084905e9921804a678ff2fe9c5c56ac65 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 21 Sep 2016 23:54:33 +0300 Subject: [PATCH 0104/4375] compel: test -- Disable compel tests for a while Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Dockerfile.tmpl b/scripts/build/Dockerfile.tmpl index 72a21ea82..6e35f87b6 100644 --- a/scripts/build/Dockerfile.tmpl +++ b/scripts/build/Dockerfile.tmpl @@ -27,4 +27,4 @@ RUN make -j $(nproc) CC=$CC V=1 RUN make mrproper RUN bash -c 'CLEAN="$(git clean -ndx --exclude=scripts/build --exclude=.config)"; echo "${CLEAN}"; test -z "${CLEAN}"; exit $?' RUN make -j $(nproc) CC=$CC -C test/zdtm -RUN make test/compel/handle_binary && ./test/compel/handle_binary +#RUN make test/compel/handle_binary && ./test/compel/handle_binary From e44320ec77e6ef7a2a121148ef6f717e18be73bc Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 21 Sep 2016 23:54:34 +0300 Subject: [PATCH 0105/4375] compel: handle-elf-32 needed for x86 only Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compel/Makefile b/compel/Makefile index 001ed385e..123e786ca 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -12,20 +12,27 @@ ccflags-y += -fPIC lib-y += arch/$(ARCH)/src/lib/handle-elf.o lib-y += src/lib/handle-elf.o + +ifeq ($(ARCH),x86) lib-y += src/lib/handle-elf-32.o +endif obj-y += src/main.o +ifeq ($(ARCH),x86) CFLAGS_handle-elf-32.o += -UCONFIG_X86_64 -DCONFIG_X86_32 CFLAGS_handle-elf-32.d += -UCONFIG_X86_64 -DCONFIG_X86_32 +endif host-ccflags-y += $(ccflags-y) hostprogs-y += compel-host compel-host-objs := $(patsubst %.o,%-host.o,$(obj-y) $(lib-y)) +ifeq ($(ARCH),x86) HOSTCFLAGS_handle-elf-32-host.o += -UCONFIG_X86_64 -DCONFIG_X86_32 HOSTCFLAGS_handle-elf-32-host.d += -UCONFIG_X86_64 -DCONFIG_X86_32 +endif cleanup-y += compel/compel cleanup-y += compel/compel-host From e2fb30d076a11b6277d566b8f8a889dea49c4043 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 23 Sep 2016 15:21:51 +0300 Subject: [PATCH 0106/4375] make, soccr: let CRIU depend on libsoccr As -lsoccr now is in $(LIBS) in Makefile.packages, it should be build before criu objects. Otherwise, we try to compile feature-tests with $(LIBS) and the succesful features fails with: :1:25: warning: extra tokens at end of #include directive /usr/bin/ld: cannot find -lsoccr collect2: error: ld returned 1 exit status Which lead to later problems: criu/sk-tcp.c:50:8: error: redefinition of 'struct tcp_repair_opt' struct tcp_repair_opt { ^ In file included from criu/sk-tcp.c:1:0: /usr/include/netinet/tcp.h:259:8: note: originally defined here struct tcp_repair_opt Because of fails in really-sucessful feture-tests. P.S. Maybe we should unbound feature-tests compilation from $(LIBS), specified in Makefile.packages - that looks right after all. Cc: Cyrill Gorcunov Cc: Pavel Emelyanov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 6cbbdd220..da664db4e 100644 --- a/Makefile +++ b/Makefile @@ -188,8 +188,7 @@ endif # # Configure variables. -CONFIG_HEADER_REL := criu/include/config.h -export CONFIG_HEADER := $(SRC_DIR)/$(CONFIG_HEADER_REL) +export CONFIG_HEADER := criu/include/config.h ifeq ($(filter clean mrproper,$(MAKECMDGOALS)),) include $(SRC_DIR)/Makefile.config endif @@ -211,7 +210,7 @@ include Makefile.compel SOCCR_A := soccr/libsoccr.a SOCCR_CONFIG := $(SRC_DIR)/soccr/config.h $(SOCCR_CONFIG): $(CONFIG_HEADER) - $(Q) test -f $@ || ln -s ../$(CONFIG_HEADER_REL) $@ + $(Q) test -f $@ || ln -s ../$(CONFIG_HEADER) $@ soccr/%: $(SOCCR_CONFIG) .FORCE $(Q) $(MAKE) $(build)=soccr $@ soccr/built-in.o: $(SOCCR_CONFIG) .FORCE @@ -226,9 +225,9 @@ $(SOCCR_A): |soccr/built-in.o # # But note that we're already included # the nmk so we can reuse it there. -criu/%: images/built-in.o compel/compel-host $(VERSION_HEADER) $(CONFIG_HEADER) .FORCE +criu/%: images/built-in.o compel/compel-host $(VERSION_HEADER) .FORCE $(Q) $(MAKE) $(build)=criu $@ -criu: images/built-in.o compel/compel-host $(SOCCR_A) $(VERSION_HEADER) $(CONFIG_HEADER) +criu: images/built-in.o compel/compel-host $(SOCCR_A) $(VERSION_HEADER) $(Q) $(MAKE) $(build)=criu all .PHONY: criu From 31b11262dad59ebdcb85e61c732e918e6eedf6aa Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 23 Sep 2016 17:20:32 +0300 Subject: [PATCH 0107/4375] make: define CONFIG_COMPAT on mrproper/clean As it's a make/build option, the set of files to compile depends on it. We don't do feature tests on mrproper/clean (no point in it). Let's define CONFIG_COMPAT for those targets, so compiled files will be properly cleaned. Reported-by: Adrian Reber Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index da664db4e..dcd4c7e69 100644 --- a/Makefile +++ b/Makefile @@ -191,6 +191,9 @@ endif export CONFIG_HEADER := criu/include/config.h ifeq ($(filter clean mrproper,$(MAKECMDGOALS)),) include $(SRC_DIR)/Makefile.config +else +# To clean all files, enable make/build options here +export CONFIG_COMPAT := y endif # From 642f990d15c5e826595380e875d4f291673d8dde Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 23 Sep 2016 16:14:00 +0300 Subject: [PATCH 0108/4375] compel: Split host and lib files Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compel/Makefile b/compel/Makefile index 123e786ca..bfb79237d 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -11,10 +11,13 @@ ccflags-y += -iquote $(SRC_DIR)/criu/include ccflags-y += -fPIC lib-y += arch/$(ARCH)/src/lib/handle-elf.o +host-lib-y += arch/$(ARCH)/src/lib/handle-elf.o lib-y += src/lib/handle-elf.o +host-lib-y += src/lib/handle-elf.o ifeq ($(ARCH),x86) lib-y += src/lib/handle-elf-32.o +host-lib-y += src/lib/handle-elf-32.o endif obj-y += src/main.o @@ -27,7 +30,7 @@ endif host-ccflags-y += $(ccflags-y) hostprogs-y += compel-host -compel-host-objs := $(patsubst %.o,%-host.o,$(obj-y) $(lib-y)) +compel-host-objs := $(patsubst %.o,%-host.o,$(obj-y) $(host-lib-y)) ifeq ($(ARCH),x86) HOSTCFLAGS_handle-elf-32-host.o += -UCONFIG_X86_64 -DCONFIG_X86_32 From 34c8ef4a14488fe6c8f29971c408605c11e17251 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 26 Sep 2016 22:36:33 +0300 Subject: [PATCH 0109/4375] compel: plugins, std -- Use compel_plugin entry point routine name Plain "main" makes compilers unhappy since it's known predefined name. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/std/std.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/plugins/std/std.c b/compel/plugins/std/std.c index 6894a6921..ada3f09d2 100644 --- a/compel/plugins/std/std.c +++ b/compel/plugins/std/std.c @@ -6,7 +6,7 @@ #include "asm/prologue.h" -extern int main(void *arg_p, unsigned int arg_s); +extern int compel_main(void *arg_p, unsigned int arg_s); static struct prologue_init_args *init_args; static int ctl_socket = -1; @@ -75,7 +75,7 @@ int __export_std_compel_start(struct prologue_init_args *args, } if (!ret) - ret = main(args->arg_p, args->arg_s); + ret = compel_main(args->arg_p, args->arg_s); for (; i > 0; i--) { const plugin_init_t *d = init_array[i - 1]; From a2e5b769e5a6263974a4e0150e1019f899635d97 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 26 Sep 2016 22:36:34 +0300 Subject: [PATCH 0110/4375] compel: Define separate targtes for plugins Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile.compel | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Makefile.compel b/Makefile.compel index b18cd8edc..e3edd558d 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -21,6 +21,19 @@ compel/%: $(COMPEL_VERSION_HEADER) $(CONFIG_HEADER) .FORCE compel/plugins/%: $(COMPEL_VERSION_HEADER) $(CONFIG_HEADER) .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ +# +# GNU make 4.x supports targets matching via wide +# match targeting, where GNU make 3.x series (used on +# Travis) is not, so we have to write them here explicitly. +compel/plugins/std.built-in.o: $(COMPEL_VERSION_HEADER) .FORCE + $(Q) $(MAKE) $(build)=compel/plugins $@ + +compel/plugins/shmem.built-in.o: $(COMPEL_VERSION_HEADER) .FORCE + $(Q) $(MAKE) $(build)=compel/plugins $@ + +compel/plugins/fds.built-in.o: $(COMPEL_VERSION_HEADER) .FORCE + $(Q) $(MAKE) $(build)=compel/plugins $@ + compel/compel: compel/built-in.o compel/lib.a $(COMPEL_VERSION_HEADER) $(call msg-link, $@) $(Q) $(CC) $(CFLAGS) $^ $(WRAPFLAGS) $(LDFLAGS) -rdynamic -o $@ From 0264fdcc3aa4d7fd1d91ce3b529e0d8d89108dae Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 26 Sep 2016 22:36:35 +0300 Subject: [PATCH 0111/4375] compel: plugins, std -- Add headers stubs - linkage.h points to CRIU's asm specific - prologue.h is just a link to x86, we will need to fix it when start using std with other plugins Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/plugins/include/asm/prologue.h | 1 + compel/arch/arm/plugins/include/asm/prologue.h | 1 + compel/arch/ppc64/plugins/include/asm/prologue.h | 1 + 3 files changed, 3 insertions(+) create mode 120000 compel/arch/aarch64/plugins/include/asm/prologue.h create mode 120000 compel/arch/arm/plugins/include/asm/prologue.h create mode 120000 compel/arch/ppc64/plugins/include/asm/prologue.h diff --git a/compel/arch/aarch64/plugins/include/asm/prologue.h b/compel/arch/aarch64/plugins/include/asm/prologue.h new file mode 120000 index 000000000..e0275e350 --- /dev/null +++ b/compel/arch/aarch64/plugins/include/asm/prologue.h @@ -0,0 +1 @@ +../../../../../arch/x86/plugins/include/asm/prologue.h \ No newline at end of file diff --git a/compel/arch/arm/plugins/include/asm/prologue.h b/compel/arch/arm/plugins/include/asm/prologue.h new file mode 120000 index 000000000..e0275e350 --- /dev/null +++ b/compel/arch/arm/plugins/include/asm/prologue.h @@ -0,0 +1 @@ +../../../../../arch/x86/plugins/include/asm/prologue.h \ No newline at end of file diff --git a/compel/arch/ppc64/plugins/include/asm/prologue.h b/compel/arch/ppc64/plugins/include/asm/prologue.h new file mode 120000 index 000000000..e0275e350 --- /dev/null +++ b/compel/arch/ppc64/plugins/include/asm/prologue.h @@ -0,0 +1 @@ +../../../../../arch/x86/plugins/include/asm/prologue.h \ No newline at end of file From e0697f780d541295a58e8a10e87875181c23df35 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 26 Sep 2016 22:36:36 +0300 Subject: [PATCH 0112/4375] compel: plugins,std -- Add syscall-types.h header Both std and criu will use it for syscalls sake. Note I've to disable x86 compat mode for a while: we have to provide native types there thus will back once everything else is complete. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile.config | 16 +++--- compel/Makefile | 10 ++++ .../plugins/include/asm/syscall-types.h | 28 ++++++++++ .../arm/plugins/include/asm/syscall-types.h | 28 ++++++++++ .../ppc64/plugins/include/asm/syscall-types.h | 28 ++++++++++ .../x86/plugins/include/asm/syscall-types.h | 21 +++++--- .../plugins/include/uapi/std/asm/.gitignore | 0 .../plugins/include/uapi/std/syscall-types.h | 2 +- criu/Makefile | 3 ++ criu/Makefile.crtools | 4 ++ criu/arch/aarch64/include/asm/types.h | 24 +-------- criu/arch/arm/include/asm/types.h | 24 +-------- criu/arch/ppc64/include/asm/types.h | 32 ++---------- criu/arch/x86/include/asm/types.h | 51 +------------------ 14 files changed, 132 insertions(+), 139 deletions(-) create mode 100644 compel/arch/aarch64/plugins/include/asm/syscall-types.h create mode 100644 compel/arch/arm/plugins/include/asm/syscall-types.h create mode 100644 compel/arch/ppc64/plugins/include/asm/syscall-types.h create mode 100644 compel/plugins/include/uapi/std/asm/.gitignore diff --git a/Makefile.config b/Makefile.config index 42b2d94e6..6ff42fe3f 100644 --- a/Makefile.config +++ b/Makefile.config @@ -19,13 +19,15 @@ CONFIG_FILE = $(SRC_DIR)/.config $(CONFIG_FILE): touch $(CONFIG_FILE) -ifeq ($(SRCARCH),x86) -# CONFIG_COMPAT is only for x86 now, no need for compile-test other archs -ifeq ($(call try-cc,$(FEATURE_TEST_X86_COMPAT),-m32),true) - export CONFIG_COMPAT := y - FEATURE_DEFINES += -DCONFIG_COMPAT -endif -endif +# +# FIXME Bring back once libcompel complete +#ifeq ($(SRCARCH),x86) +## CONFIG_COMPAT is only for x86 now, no need for compile-test other archs +#ifeq ($(call try-cc,$(FEATURE_TEST_X86_COMPAT),-m32),true) +# export CONFIG_COMPAT := y +# FEATURE_DEFINES += -DCONFIG_COMPAT +#endif +#endif export DEFINES += $(FEATURE_DEFINES) export CFLAGS += $(FEATURE_DEFINES) diff --git a/compel/Makefile b/compel/Makefile index bfb79237d..4d149a23e 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -40,3 +40,13 @@ endif cleanup-y += compel/compel cleanup-y += compel/compel-host cleanup-y += compel/libcompel.so + +# +# FIXME Fake target for syscalls headers generation, +# drop after syscalls generation. +$(obj)/plugins/include/uapi/std/asm/syscall-types.h: $(obj)/arch/$(ARCH)/plugins/include/asm/syscall-types.h + $(call msg-gen,$@) + $(Q) ln -s ../../../../../arch/$(ARCH)/plugins/include/asm/syscall-types.h $@ + +cleanup-y += $(obj)/plugins/include/uapi/std/asm/syscall-types.h +$(obj)/compel-host: $(obj)/plugins/include/uapi/std/asm/syscall-types.h diff --git a/compel/arch/aarch64/plugins/include/asm/syscall-types.h b/compel/arch/aarch64/plugins/include/asm/syscall-types.h new file mode 100644 index 000000000..ee0e2185d --- /dev/null +++ b/compel/arch/aarch64/plugins/include/asm/syscall-types.h @@ -0,0 +1,28 @@ +#ifndef COMPEL_ARCH_SYSCALL_TYPES_H__ +#define COMPEL_ARCH_SYSCALL_TYPES_H__ + +#define SA_RESTORER 0x04000000 + +typedef void rt_signalfn_t(int, siginfo_t *, void *); +typedef rt_signalfn_t *rt_sighandler_t; + +typedef void rt_restorefn_t(void); +typedef rt_restorefn_t *rt_sigrestore_t; + +#define _KNSIG 64 +#define _NSIG_BPW 64 + +#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) + +typedef struct { + unsigned long sig[_KNSIG_WORDS]; +} k_rtsigset_t; + +typedef struct { + rt_sighandler_t rt_sa_handler; + unsigned long rt_sa_flags; + rt_sigrestore_t rt_sa_restorer; + k_rtsigset_t rt_sa_mask; +} rt_sigaction_t; + +#endif /* COMPEL_ARCH_SYSCALL_TYPES_H__ */ diff --git a/compel/arch/arm/plugins/include/asm/syscall-types.h b/compel/arch/arm/plugins/include/asm/syscall-types.h new file mode 100644 index 000000000..cdb03ef4c --- /dev/null +++ b/compel/arch/arm/plugins/include/asm/syscall-types.h @@ -0,0 +1,28 @@ +#ifndef COMPEL_ARCH_SYSCALL_TYPES_H__ +#define COMPEL_ARCH_SYSCALL_TYPES_H__ + +#define SA_RESTORER 0x04000000 + +typedef void rt_signalfn_t(int, siginfo_t *, void *); +typedef rt_signalfn_t *rt_sighandler_t; + +typedef void rt_restorefn_t(void); +typedef rt_restorefn_t *rt_sigrestore_t; + +#define _KNSIG 64 +#define _NSIG_BPW 32 + +#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) + +typedef struct { + unsigned long sig[_KNSIG_WORDS]; +} k_rtsigset_t; + +typedef struct { + rt_sighandler_t rt_sa_handler; + unsigned long rt_sa_flags; + rt_sigrestore_t rt_sa_restorer; + k_rtsigset_t rt_sa_mask; +} rt_sigaction_t; + +#endif /* COMPEL_ARCH_SYSCALL_TYPES_H__ */ diff --git a/compel/arch/ppc64/plugins/include/asm/syscall-types.h b/compel/arch/ppc64/plugins/include/asm/syscall-types.h new file mode 100644 index 000000000..7754721e2 --- /dev/null +++ b/compel/arch/ppc64/plugins/include/asm/syscall-types.h @@ -0,0 +1,28 @@ +#ifndef COMPEL_ARCH_SYSCALL_TYPES_H__ +#define COMPEL_ARCH_SYSCALL_TYPES_H__ + +#define SA_RESTORER 0x04000000U + +typedef void rt_signalfn_t(int, siginfo_t *, void *); +typedef rt_signalfn_t *rt_sighandler_t; + +typedef void rt_restorefn_t(void); +typedef rt_restorefn_t *rt_sigrestore_t; + +#define _KNSIG 64 +#define _NSIG_BPW 64 + +#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) + +typedef struct { + unsigned long sig[_KNSIG_WORDS]; +} k_rtsigset_t; + +typedef struct { + rt_sighandler_t rt_sa_handler; + unsigned long rt_sa_flags; + rt_sigrestore_t rt_sa_restorer; + k_rtsigset_t rt_sa_mask; +} rt_sigaction_t; + +#endif /* COMPEL_ARCH_SYSCALL_TYPES_H__ */ diff --git a/compel/arch/x86/plugins/include/asm/syscall-types.h b/compel/arch/x86/plugins/include/asm/syscall-types.h index 744809d07..b22b6d795 100644 --- a/compel/arch/x86/plugins/include/asm/syscall-types.h +++ b/compel/arch/x86/plugins/include/asm/syscall-types.h @@ -8,13 +8,20 @@ typedef rt_signalfn_t *rt_sighandler_t; typedef void rt_restorefn_t(void); typedef rt_restorefn_t *rt_sigrestore_t; -#define _KNSIG 64 -# define _NSIG_BPW 64 +#define SA_RESTORER 0x04000000 -#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) +#define _KNSIG 64 + +#ifndef CONFIG_COMPAT +#define _NSIG_BPW 64 +#else +#define _NSIG_BPW 32 +#endif + +#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) typedef struct { - u64 sig[_KNSIG_WORDS]; + unsigned long sig[_KNSIG_WORDS]; } k_rtsigset_t; typedef struct { @@ -30,9 +37,9 @@ typedef struct { * with unaligned rt_sa_mask. */ typedef struct __attribute__((packed)) { - u32 rt_sa_handler; - u32 rt_sa_flags; - u32 rt_sa_restorer; + unsigned int rt_sa_handler; + unsigned int rt_sa_flags; + unsigned int rt_sa_restorer; k_rtsigset_t rt_sa_mask; } rt_sigaction_t_compat; diff --git a/compel/plugins/include/uapi/std/asm/.gitignore b/compel/plugins/include/uapi/std/asm/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/compel/plugins/include/uapi/std/syscall-types.h b/compel/plugins/include/uapi/std/syscall-types.h index 564d027f2..3296153b3 100644 --- a/compel/plugins/include/uapi/std/syscall-types.h +++ b/compel/plugins/include/uapi/std/syscall-types.h @@ -52,6 +52,6 @@ struct krlimit { /* Type of timers in the kernel. */ typedef int kernel_timer_t; -#include "asm/syscall-types.h" +#include "uapi/std/asm/syscall-types.h" #endif /* COMPEL_SYSCALL_TYPES_H__ */ diff --git a/criu/Makefile b/criu/Makefile index c2ee5757f..216306351 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -17,6 +17,9 @@ ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR) ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR)/include ccflags-y += -iquote $(SRC_DIR)/ ccflags-y += -I/usr/include/libnl3 +ccflags-y += -iquote compel/plugins/include +ccflags-y += -iquote compel/include +ccflags-y += -iquote compel/arch/$(ARCH)/plugins/std export ccflags-y diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index eafb8ae5b..cd96cdf17 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -1,4 +1,8 @@ ccflags-y += -iquote criu/$(ARCH) +ccflags-y += -iquote compel/plugins/include +ccflags-y += -iquote compel/include +ccflags-y += -iquote compel/arch/$(ARCH)/plugins/std + obj-y += action-scripts.o obj-y += external.o obj-y += aio.o diff --git a/criu/arch/aarch64/include/asm/types.h b/criu/arch/aarch64/include/asm/types.h index 976fca200..17353ac95 100644 --- a/criu/arch/aarch64/include/asm/types.h +++ b/criu/arch/aarch64/include/asm/types.h @@ -10,29 +10,7 @@ #include "bitops.h" #include "asm/int.h" -typedef void rt_signalfn_t(int, siginfo_t *, void *); -typedef rt_signalfn_t *rt_sighandler_t; - -typedef void rt_restorefn_t(void); -typedef rt_restorefn_t *rt_sigrestore_t; - -#define _KNSIG 64 -#define _NSIG_BPW 64 - -#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) - -typedef struct { - unsigned long sig[_KNSIG_WORDS]; -} k_rtsigset_t; - -#define SA_RESTORER 0x00000000 - -typedef struct { - rt_sighandler_t rt_sa_handler; - unsigned long rt_sa_flags; - rt_sigrestore_t rt_sa_restorer; - k_rtsigset_t rt_sa_mask; -} rt_sigaction_t; +#include "uapi/std/asm/syscall-types.h" #define core_is_compat(core) false diff --git a/criu/arch/arm/include/asm/types.h b/criu/arch/arm/include/asm/types.h index a4a752dad..e4dfd2cf1 100644 --- a/criu/arch/arm/include/asm/types.h +++ b/criu/arch/arm/include/asm/types.h @@ -9,29 +9,7 @@ #include "bitops.h" #include "asm/int.h" -typedef void rt_signalfn_t(int, siginfo_t *, void *); -typedef rt_signalfn_t *rt_sighandler_t; - -typedef void rt_restorefn_t(void); -typedef rt_restorefn_t *rt_sigrestore_t; - -#define _KNSIG 64 -#define _NSIG_BPW 32 - -#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) - -typedef struct { - unsigned long sig[_KNSIG_WORDS]; -} k_rtsigset_t; - -#define SA_RESTORER 0x04000000 - -typedef struct { - rt_sighandler_t rt_sa_handler; - unsigned long rt_sa_flags; - rt_sigrestore_t rt_sa_restorer; - k_rtsigset_t rt_sa_mask; -} rt_sigaction_t; +#include "uapi/std/asm/syscall-types.h" #define core_is_compat(core) false diff --git a/criu/arch/ppc64/include/asm/types.h b/criu/arch/ppc64/include/asm/types.h index 73ab4d270..25e2125b2 100644 --- a/criu/arch/ppc64/include/asm/types.h +++ b/criu/arch/ppc64/include/asm/types.h @@ -9,40 +9,14 @@ #include "bitops.h" #include "asm/int.h" -/* - * Copied from kernel header include/uapi/asm-generic/signal-defs.h - */ -typedef void rt_signalfn_t(int, siginfo_t *, void *); -typedef rt_signalfn_t *rt_sighandler_t; - -typedef void rt_restorefn_t(void); -typedef rt_restorefn_t *rt_sigrestore_t; - -/*Copied from the Linux kernel arch/powerpc/include/uapi/asm/signal.h */ -#define _KNSIG 64 -#define _NSIG_BPW 64 -#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) - -typedef struct { - uint64_t sig[_KNSIG_WORDS]; -} k_rtsigset_t; - -/* Copied from the Linux kernel arch/powerpc/include/uapi/asm/signal.h */ -#define SA_RESTORER 0x04000000U - -typedef struct { - rt_sighandler_t rt_sa_handler; - unsigned long rt_sa_flags; - rt_sigrestore_t rt_sa_restorer; - k_rtsigset_t rt_sa_mask; /* mask last for extensibility */ -} rt_sigaction_t; - -#define core_is_compat(core) false +#include "uapi/std/asm/syscall-types.h" typedef UserPpc64RegsEntry UserRegsEntry; #define CORE_ENTRY__MARCH CORE_ENTRY__MARCH__PPC64 +#define core_is_compat(core) false + #define CORE_THREAD_ARCH_INFO(core) core->ti_ppc64 static inline void *decode_pointer(uint64_t v) { return (void*)v; } diff --git a/criu/arch/x86/include/asm/types.h b/criu/arch/x86/include/asm/types.h index fa2cb77f9..84a29ec12 100644 --- a/criu/arch/x86/include/asm/types.h +++ b/criu/arch/x86/include/asm/types.h @@ -8,6 +8,8 @@ #include "bitops.h" #include "asm/int.h" +#include "uapi/std/asm/syscall-types.h" + #include "images/core.pb-c.h" #ifdef CONFIG_X86_64 @@ -26,55 +28,6 @@ static inline int core_is_compat(CoreEntry *c) static inline int core_is_compat(CoreEntry *c) { return 0; } #endif /* CONFIG_X86_64 */ -typedef void rt_signalfn_t(int, siginfo_t *, void *); -typedef rt_signalfn_t *rt_sighandler_t; - -typedef void rt_restorefn_t(void); -typedef rt_restorefn_t *rt_sigrestore_t; - -#define _KNSIG 64 -# define _NSIG_BPW 64 - -#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) - -typedef struct { - u64 sig[_KNSIG_WORDS]; -} k_rtsigset_t; - -#define SA_RESTORER 0x04000000 - -typedef struct { - rt_sighandler_t rt_sa_handler; - unsigned long rt_sa_flags; - rt_sigrestore_t rt_sa_restorer; - k_rtsigset_t rt_sa_mask; -} rt_sigaction_t; - -/* - * Note: there is unaligned access on x86_64 and it's fine. - * However, when porting this code -- keep in mind about possible issues - * with unaligned rt_sa_mask. - */ -typedef struct __attribute__((packed)) { - u32 rt_sa_handler; - u32 rt_sa_flags; - u32 rt_sa_restorer; - k_rtsigset_t rt_sa_mask; -} rt_sigaction_t_compat; - -typedef struct { - unsigned int entry_number; - unsigned int base_addr; - unsigned int limit; - unsigned int seg_32bit:1; - unsigned int contents:2; - unsigned int read_exec_only:1; - unsigned int limit_in_pages:1; - unsigned int seg_not_present:1; - unsigned int useable:1; - unsigned int lm:1; -} user_desc_t; - #define CORE_ENTRY__MARCH CORE_ENTRY__MARCH__X86_64 #define CORE_THREAD_ARCH_INFO(core) core->thread_info From 55bc551846d3deb10807577d23cbd22076930372 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 26 Sep 2016 22:36:37 +0300 Subject: [PATCH 0113/4375] compel: plugins,std -- Prepare stubs to use syscalls CRIU will reference to them, but for now they are just stubs. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/include/uapi/std/asm/syscall-types.h | 1 + compel/plugins/include/uapi/std/syscall-codes.h | 1 + compel/plugins/include/uapi/std/syscall.h | 1 + 3 files changed, 3 insertions(+) create mode 120000 compel/plugins/include/uapi/std/asm/syscall-types.h create mode 120000 compel/plugins/include/uapi/std/syscall-codes.h create mode 120000 compel/plugins/include/uapi/std/syscall.h diff --git a/compel/plugins/include/uapi/std/asm/syscall-types.h b/compel/plugins/include/uapi/std/asm/syscall-types.h new file mode 120000 index 000000000..de3054eef --- /dev/null +++ b/compel/plugins/include/uapi/std/asm/syscall-types.h @@ -0,0 +1 @@ +../../../../../arch/x86/plugins/include/asm/syscall-types.h \ No newline at end of file diff --git a/compel/plugins/include/uapi/std/syscall-codes.h b/compel/plugins/include/uapi/std/syscall-codes.h new file mode 120000 index 000000000..4296e5019 --- /dev/null +++ b/compel/plugins/include/uapi/std/syscall-codes.h @@ -0,0 +1 @@ +../../../../../criu/include/syscall-codes.h \ No newline at end of file diff --git a/compel/plugins/include/uapi/std/syscall.h b/compel/plugins/include/uapi/std/syscall.h new file mode 120000 index 000000000..697802a4d --- /dev/null +++ b/compel/plugins/include/uapi/std/syscall.h @@ -0,0 +1 @@ +../../../../../criu/include/syscall.h \ No newline at end of file From 35726a766798fec0ab2bb9d3ee7504fb3736738d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 26 Sep 2016 22:36:38 +0300 Subject: [PATCH 0114/4375] compel: criu -- Start using uapi/std syscalls stubs Real syscalls generation is inside criu for a while but will be moved out in the next patch. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/restorer.c | 2 +- criu/arch/aarch64/vdso-pie.c | 2 +- criu/arch/arm/restorer.c | 2 +- criu/arch/ppc64/restorer.c | 2 +- criu/arch/ppc64/vdso-pie.c | 2 +- criu/arch/x86/crtools.c | 2 +- criu/arch/x86/include/asm/restorer.h | 1 + criu/arch/x86/restorer.c | 2 +- criu/arch/x86/sigaction_compat.c | 2 +- criu/arch/x86/vdso-pie.c | 2 +- criu/cr-restore.c | 2 +- criu/fsnotify.c | 2 +- criu/kerndat.c | 2 +- criu/parasite-syscall.c | 2 +- criu/pie/log-simple.c | 2 +- criu/pie/parasite-vdso.c | 2 +- criu/pie/parasite.c | 2 +- criu/pie/restorer.c | 2 +- criu/pie/util-fd.c | 2 +- criu/pie/util.c | 2 +- criu/shmem.c | 2 +- include/common/lock.h | 2 +- 22 files changed, 22 insertions(+), 21 deletions(-) diff --git a/criu/arch/aarch64/restorer.c b/criu/arch/aarch64/restorer.c index c833a8836..72c9c4a97 100644 --- a/criu/arch/aarch64/restorer.c +++ b/criu/arch/aarch64/restorer.c @@ -3,7 +3,7 @@ #include "restorer.h" #include "asm/restorer.h" -#include "syscall.h" +#include "uapi/std/syscall.h" #include "log.h" #include "asm/fpu.h" #include "cpu.h" diff --git a/criu/arch/aarch64/vdso-pie.c b/criu/arch/aarch64/vdso-pie.c index 16a05506d..8612b2622 100644 --- a/criu/arch/aarch64/vdso-pie.c +++ b/criu/arch/aarch64/vdso-pie.c @@ -2,7 +2,7 @@ #include "asm/types.h" -#include "syscall.h" +#include "uapi/std/syscall.h" #include "parasite-vdso.h" #include "log.h" #include "common/bug.h" diff --git a/criu/arch/arm/restorer.c b/criu/arch/arm/restorer.c index 774a411de..8eb18a8ad 100644 --- a/criu/arch/arm/restorer.c +++ b/criu/arch/arm/restorer.c @@ -3,7 +3,7 @@ #include "restorer.h" #include "asm/restorer.h" -#include "syscall.h" +#include "uapi/std/syscall.h" #include "log.h" #include "asm/fpu.h" #include "cpu.h" diff --git a/criu/arch/ppc64/restorer.c b/criu/arch/ppc64/restorer.c index 5379e6018..3f0aff87a 100644 --- a/criu/arch/ppc64/restorer.c +++ b/criu/arch/ppc64/restorer.c @@ -4,7 +4,7 @@ #include "asm/restorer.h" #include "asm/fpu.h" -#include "syscall.h" +#include "uapi/std/syscall.h" #include "log.h" int restore_nonsigframe_gpregs(UserPpc64RegsEntry *r) diff --git a/criu/arch/ppc64/vdso-pie.c b/criu/arch/ppc64/vdso-pie.c index c7d8b9b7e..fbca7f51a 100644 --- a/criu/arch/ppc64/vdso-pie.c +++ b/criu/arch/ppc64/vdso-pie.c @@ -3,7 +3,7 @@ #include "asm/types.h" -#include "syscall.h" +#include "uapi/std/syscall.h" #include "parasite-vdso.h" #include "log.h" #include "common/bug.h" diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 0c14b8602..d2660e4b4 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -21,7 +21,7 @@ #include "util.h" #include "cpu.h" #include "errno.h" -#include "syscall-codes.h" +#include "uapi/std/syscall-codes.h" #include "kerndat.h" #include "protobuf.h" diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index 45b13315e..43a1b6989 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -4,6 +4,7 @@ #include "asm/types.h" #include "asm/fpu.h" #include "images/core.pb-c.h" +#include "uapi/std/syscall-codes.h" #include "sigframe.h" diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index 574e0da26..052d91a67 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -7,7 +7,7 @@ #include "asm/fpu.h" #include "asm/string.h" -#include "syscall.h" +#include "uapi/std/syscall.h" #include "log.h" #include "cpu.h" diff --git a/criu/arch/x86/sigaction_compat.c b/criu/arch/x86/sigaction_compat.c index ef6d13c91..214b2058b 100644 --- a/criu/arch/x86/sigaction_compat.c +++ b/criu/arch/x86/sigaction_compat.c @@ -5,7 +5,7 @@ #include #ifdef CR_NOGLIBC -# include "syscall.h" +# include "uapi/std/syscall.h" #else # define sys_mmap mmap # define sys_munmap munmap diff --git a/criu/arch/x86/vdso-pie.c b/criu/arch/x86/vdso-pie.c index cef7f37c4..07652d2fd 100644 --- a/criu/arch/x86/vdso-pie.c +++ b/criu/arch/x86/vdso-pie.c @@ -3,7 +3,7 @@ #include "string.h" #include "asm/types.h" -#include "syscall.h" +#include "uapi/std/syscall.h" #include "parasite-vdso.h" #include "log.h" #include "common/bug.h" diff --git a/criu/cr-restore.c b/criu/cr-restore.c index bd61d3882..dcc49d00c 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -79,7 +79,7 @@ #include "parasite-syscall.h" #include "files-reg.h" -#include "syscall-codes.h" +#include "uapi/std/syscall-codes.h" #include "protobuf.h" #include "images/sa.pb-c.h" diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 1d49d2bae..9a591a625 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -41,7 +41,7 @@ #include "namespaces.h" #include "pstree.h" #include "fault-injection.h" -#include "syscall-codes.h" +#include "uapi/std/syscall-codes.h" #include "protobuf.h" #include "images/fsnotify.pb-c.h" diff --git a/criu/kerndat.c b/criu/kerndat.c index fc946ba62..f3c654a39 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -26,8 +26,8 @@ #include "lsm.h" #include "proc_parse.h" #include "config.h" -#include "syscall-codes.h" #include "sk-inet.h" +#include "uapi/std/syscall-codes.h" struct kerndat_s kdat = { }; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 65fb12a2b..8fbfa34d5 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -30,7 +30,7 @@ #include "proc_parse.h" #include "aio.h" #include "fault-injection.h" -#include "syscall-codes.h" +#include "uapi/std/syscall-codes.h" #include "signal.h" #include "sigframe.h" diff --git a/criu/pie/log-simple.c b/criu/pie/log-simple.c index f1a92da61..3f8a73623 100644 --- a/criu/pie/log-simple.c +++ b/criu/pie/log-simple.c @@ -4,7 +4,7 @@ #include "types.h" #include "string.h" #include "common/bitsperlong.h" -#include "syscall.h" +#include "uapi/std/syscall.h" #include "log.h" struct simple_buf { diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 03a3f0e0d..7914de6f6 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -12,7 +12,7 @@ #include "int.h" #include "types.h" #include "page.h" -#include "syscall.h" +#include "uapi/std/syscall.h" #include "image.h" #include "parasite-vdso.h" #include "vma.h" diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index 8694668a5..c1d7cf991 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -9,7 +9,7 @@ #include "int.h" #include "types.h" -#include "syscall.h" +#include "uapi/std/syscall.h" #include "parasite.h" #include "config.h" #include "fcntl.h" diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index ba37ff4ca..b8cc640bb 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -21,7 +21,7 @@ #include "types.h" #include "common/compiler.h" #include "string.h" -#include "syscall.h" +#include "uapi/std/syscall.h" #include "signal.h" #include "config.h" #include "prctl.h" diff --git a/criu/pie/util-fd.c b/criu/pie/util-fd.c index e753f0b17..0e6291f9d 100644 --- a/criu/pie/util-fd.c +++ b/criu/pie/util-fd.c @@ -11,7 +11,7 @@ #include "string.h" #ifdef CR_NOGLIBC -# include "syscall.h" +# include "uapi/std/syscall.h" # define __sys(foo) sys_##foo # define __sys_err(ret) ret #else diff --git a/criu/pie/util.c b/criu/pie/util.c index f16982317..ed2949745 100644 --- a/criu/pie/util.c +++ b/criu/pie/util.c @@ -13,7 +13,7 @@ #include "util-pie.h" #ifdef CR_NOGLIBC -# include "syscall.h" +# include "uapi/std/syscall.h" # define __sys(foo) sys_##foo #else # define __sys(foo) foo diff --git a/criu/shmem.c b/criu/shmem.c index d2dee914d..997c20f36 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -16,7 +16,7 @@ #include "vma.h" #include "mem.h" #include "config.h" -#include "syscall-codes.h" +#include "uapi/std/syscall-codes.h" #include "bitops.h" #include "log.h" #include "types.h" diff --git a/include/common/lock.h b/include/common/lock.h index f68045cfe..bcd1145f0 100644 --- a/include/common/lock.h +++ b/include/common/lock.h @@ -15,7 +15,7 @@ #define LOCK_BUG() LOCK_BUG_ON(1) #ifdef CR_NOGLIBC -# include "syscall.h" +# include "uapi/std/syscall.h" #else # include # include From 19fadee9d909bef2a3418c86c06bed52eeb90445 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 26 Sep 2016 22:36:39 +0300 Subject: [PATCH 0115/4375] compel: plugins,std -- Implement syscalls in std plugin And use it in CRIU directly instead: - move syscalls into compel/arch/ARCH/plugins/std/syscalls - drop old symlinks - no build for 32bit on x86 as expected - use std.built-in.o inside criu directly (compel_main stub) - drop syscalls on x86 criu directory, I copied them already in first compel commist, so we can't move them now, but delete in place Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 6 +- compel/Makefile | 10 -- .../plugins/std/syscalls/Makefile.syscalls | 1 + .../plugins/std/syscalls/gen-sys-exec-tbl.pl | 1 + .../plugins/std/syscalls/gen-syscalls.pl | 1 + .../plugins/std/syscalls}/syscall-aux.S | 0 .../plugins/std/syscalls}/syscall-aux.h | 0 .../plugins/std}/syscalls/syscall-common.S | 0 .../aarch64/plugins/std/syscalls/syscall.def | 1 + .../plugins/std/syscalls/Makefile.syscalls | 59 +++++++ .../plugins/std/syscalls}/gen-sys-exec-tbl.pl | 0 .../arm/plugins/std/syscalls}/gen-syscalls.pl | 8 +- .../arm/plugins/std/syscalls}/syscall-aux.S | 0 .../arm/plugins/std/syscalls}/syscall-aux.h | 0 .../plugins/std}/syscalls/syscall-common.S | 0 .../arm/plugins/std}/syscalls/syscall.def | 0 .../plugins/std/syscalls/Makefile.syscalls | 57 +++++++ .../std}/syscalls/syscall-common-ppc64.S | 0 .../plugins/std}/syscalls/syscall-ppc64.tbl | 0 .../plugins/std/syscalls/Makefile.syscalls | 122 ++++++++++++++ compel/plugins/Makefile | 127 ++------------ .../include/uapi/std/asm/syscall-types.h | 1 - .../plugins/include/uapi/std/syscall-codes.h | 1 - compel/plugins/include/uapi/std/syscall.h | 1 - compel/plugins/std/string.c | 3 + criu/Makefile | 22 ++- criu/Makefile.crtools | 2 +- criu/arch/aarch64/Makefile | 2 + criu/arch/aarch64/Makefile.syscalls | 52 ------ criu/arch/aarch64/syscalls/syscall.def | 1 - criu/arch/arm/Makefile | 2 + criu/arch/arm/Makefile.syscalls | 52 ------ criu/arch/ppc64/Makefile | 2 + criu/arch/ppc64/Makefile.syscalls | 57 ------- criu/arch/x86/Makefile | 2 + criu/arch/x86/Makefile.syscalls | 158 ------------------ .../arch/x86/syscalls/syscall-common-x86-32.S | 36 ---- .../arch/x86/syscalls/syscall-common-x86-64.S | 21 --- criu/arch/x86/syscalls/syscall32.c | 85 ---------- criu/arch/x86/syscalls/syscall_32.tbl | 94 ----------- criu/arch/x86/syscalls/syscall_64.tbl | 105 ------------ criu/crtools.c | 2 + criu/pie/Makefile | 13 +- criu/pie/Makefile.library | 2 + criu/pie/parasite.c | 5 + criu/pie/restorer.c | 5 + 46 files changed, 311 insertions(+), 808 deletions(-) create mode 120000 compel/arch/aarch64/plugins/std/syscalls/Makefile.syscalls create mode 120000 compel/arch/aarch64/plugins/std/syscalls/gen-sys-exec-tbl.pl create mode 120000 compel/arch/aarch64/plugins/std/syscalls/gen-syscalls.pl rename {criu/arch/aarch64/include/asm => compel/arch/aarch64/plugins/std/syscalls}/syscall-aux.S (100%) rename {criu/arch/aarch64/include/asm => compel/arch/aarch64/plugins/std/syscalls}/syscall-aux.h (100%) rename {criu/arch/aarch64 => compel/arch/aarch64/plugins/std}/syscalls/syscall-common.S (100%) create mode 120000 compel/arch/aarch64/plugins/std/syscalls/syscall.def create mode 100644 compel/arch/arm/plugins/std/syscalls/Makefile.syscalls rename {criu/arch/scripts/arm => compel/arch/arm/plugins/std/syscalls}/gen-sys-exec-tbl.pl (100%) rename {criu/arch/scripts/arm => compel/arch/arm/plugins/std/syscalls}/gen-syscalls.pl (92%) rename {criu/arch/arm/include/asm => compel/arch/arm/plugins/std/syscalls}/syscall-aux.S (100%) rename {criu/arch/arm/include/asm => compel/arch/arm/plugins/std/syscalls}/syscall-aux.h (100%) rename {criu/arch/arm => compel/arch/arm/plugins/std}/syscalls/syscall-common.S (100%) rename {criu/arch/arm => compel/arch/arm/plugins/std}/syscalls/syscall.def (100%) create mode 100644 compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls rename {criu/arch/ppc64 => compel/arch/ppc64/plugins/std}/syscalls/syscall-common-ppc64.S (100%) rename {criu/arch/ppc64 => compel/arch/ppc64/plugins/std}/syscalls/syscall-ppc64.tbl (100%) create mode 100644 compel/arch/x86/plugins/std/syscalls/Makefile.syscalls delete mode 120000 compel/plugins/include/uapi/std/asm/syscall-types.h delete mode 120000 compel/plugins/include/uapi/std/syscall-codes.h delete mode 120000 compel/plugins/include/uapi/std/syscall.h delete mode 100644 criu/arch/aarch64/Makefile.syscalls delete mode 120000 criu/arch/aarch64/syscalls/syscall.def delete mode 100644 criu/arch/arm/Makefile.syscalls delete mode 100644 criu/arch/ppc64/Makefile.syscalls delete mode 100644 criu/arch/x86/Makefile.syscalls delete mode 100644 criu/arch/x86/syscalls/syscall-common-x86-32.S delete mode 100644 criu/arch/x86/syscalls/syscall-common-x86-64.S delete mode 100644 criu/arch/x86/syscalls/syscall32.c delete mode 100644 criu/arch/x86/syscalls/syscall_32.tbl delete mode 100644 criu/arch/x86/syscalls/syscall_64.tbl diff --git a/Makefile b/Makefile index dcd4c7e69..b693201f7 100644 --- a/Makefile +++ b/Makefile @@ -228,9 +228,9 @@ $(SOCCR_A): |soccr/built-in.o # # But note that we're already included # the nmk so we can reuse it there. -criu/%: images/built-in.o compel/compel-host $(VERSION_HEADER) .FORCE +criu/%: images/built-in.o compel/plugins/std.built-in.o compel/compel-host $(VERSION_HEADER) .FORCE $(Q) $(MAKE) $(build)=criu $@ -criu: images/built-in.o compel/compel-host $(SOCCR_A) $(VERSION_HEADER) +criu: images/built-in.o compel/plugins/std.built-in.o compel/compel-host $(SOCCR_A) $(VERSION_HEADER) $(Q) $(MAKE) $(build)=criu all .PHONY: criu @@ -256,6 +256,7 @@ clean: subclean $(Q) $(MAKE) $(build)=soccr $@ $(Q) $(MAKE) $(build)=lib $@ $(Q) $(MAKE) $(build)=compel $@ + $(Q) $(MAKE) $(build)=compel/plugins $@ .PHONY: clean # mrproper depends on clean in nmk @@ -265,6 +266,7 @@ mrproper: subclean $(Q) $(MAKE) $(build)=soccr $@ $(Q) $(MAKE) $(build)=lib $@ $(Q) $(MAKE) $(build)=compel $@ + $(Q) $(MAKE) $(build)=compel/plugins $@ $(Q) $(RM) $(CONFIG_HEADER) $(Q) $(RM) $(SOCCR_CONFIG) $(Q) $(RM) $(VERSION_HEADER) diff --git a/compel/Makefile b/compel/Makefile index 4d149a23e..bfb79237d 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -40,13 +40,3 @@ endif cleanup-y += compel/compel cleanup-y += compel/compel-host cleanup-y += compel/libcompel.so - -# -# FIXME Fake target for syscalls headers generation, -# drop after syscalls generation. -$(obj)/plugins/include/uapi/std/asm/syscall-types.h: $(obj)/arch/$(ARCH)/plugins/include/asm/syscall-types.h - $(call msg-gen,$@) - $(Q) ln -s ../../../../../arch/$(ARCH)/plugins/include/asm/syscall-types.h $@ - -cleanup-y += $(obj)/plugins/include/uapi/std/asm/syscall-types.h -$(obj)/compel-host: $(obj)/plugins/include/uapi/std/asm/syscall-types.h diff --git a/compel/arch/aarch64/plugins/std/syscalls/Makefile.syscalls b/compel/arch/aarch64/plugins/std/syscalls/Makefile.syscalls new file mode 120000 index 000000000..eba4d986c --- /dev/null +++ b/compel/arch/aarch64/plugins/std/syscalls/Makefile.syscalls @@ -0,0 +1 @@ +../../../../arm/plugins/std/syscalls/Makefile.syscalls \ No newline at end of file diff --git a/compel/arch/aarch64/plugins/std/syscalls/gen-sys-exec-tbl.pl b/compel/arch/aarch64/plugins/std/syscalls/gen-sys-exec-tbl.pl new file mode 120000 index 000000000..8d7e897ae --- /dev/null +++ b/compel/arch/aarch64/plugins/std/syscalls/gen-sys-exec-tbl.pl @@ -0,0 +1 @@ +../../../../arm/plugins/std/syscalls/gen-sys-exec-tbl.pl \ No newline at end of file diff --git a/compel/arch/aarch64/plugins/std/syscalls/gen-syscalls.pl b/compel/arch/aarch64/plugins/std/syscalls/gen-syscalls.pl new file mode 120000 index 000000000..5c9563611 --- /dev/null +++ b/compel/arch/aarch64/plugins/std/syscalls/gen-syscalls.pl @@ -0,0 +1 @@ +../../../../arm/plugins/std/syscalls/gen-syscalls.pl \ No newline at end of file diff --git a/criu/arch/aarch64/include/asm/syscall-aux.S b/compel/arch/aarch64/plugins/std/syscalls/syscall-aux.S similarity index 100% rename from criu/arch/aarch64/include/asm/syscall-aux.S rename to compel/arch/aarch64/plugins/std/syscalls/syscall-aux.S diff --git a/criu/arch/aarch64/include/asm/syscall-aux.h b/compel/arch/aarch64/plugins/std/syscalls/syscall-aux.h similarity index 100% rename from criu/arch/aarch64/include/asm/syscall-aux.h rename to compel/arch/aarch64/plugins/std/syscalls/syscall-aux.h diff --git a/criu/arch/aarch64/syscalls/syscall-common.S b/compel/arch/aarch64/plugins/std/syscalls/syscall-common.S similarity index 100% rename from criu/arch/aarch64/syscalls/syscall-common.S rename to compel/arch/aarch64/plugins/std/syscalls/syscall-common.S diff --git a/compel/arch/aarch64/plugins/std/syscalls/syscall.def b/compel/arch/aarch64/plugins/std/syscalls/syscall.def new file mode 120000 index 000000000..ebecde3cb --- /dev/null +++ b/compel/arch/aarch64/plugins/std/syscalls/syscall.def @@ -0,0 +1 @@ +../../../../arm/plugins/std/syscalls/syscall.def \ No newline at end of file diff --git a/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls b/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls new file mode 100644 index 000000000..453548120 --- /dev/null +++ b/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls @@ -0,0 +1,59 @@ +ccflags-y += -iquote $(PLUGIN_ARCH_DIR)/std/syscalls/ +asflags-y += -iquote $(PLUGIN_ARCH_DIR)/std/syscalls/ + +sys-types := $(obj)/include/uapi/std/syscall-types.h +sys-codes := $(obj)/include/uapi/std/syscall-codes.h +sys-proto := $(obj)/include/uapi/std/syscall.h + +sys-def := $(PLUGIN_ARCH_DIR)/std/syscalls/syscall.def +sys-asm-common-name := std/syscalls/syscall-common.S +sys-asm-common := $(PLUGIN_ARCH_DIR)/$(sys-asm-common-name) +sys-asm-types := $(obj)/include/uapi/std/asm/syscall-types.h +sys-exec-tbl = $(PLUGIN_ARCH_DIR)/std/sys-exec-tbl.c + +sys-gen := $(PLUGIN_ARCH_DIR)/std/syscalls/gen-syscalls.pl +sys-gen-tbl := $(PLUGIN_ARCH_DIR)/std/syscalls/gen-sys-exec-tbl.pl + +sys-asm := ./$(PLUGIN_ARCH_DIR)/std/syscalls/syscalls.S +std-obj-y += $(sys-asm:.S=).o + +ifeq ($(ARCH),arm) +arch_bits := 32 +else +arch_bits := 64 +endif + +sys-exec-tbl := sys-exec-tbl.c + +$(sys-asm) $(sys-types) $(sys-codes) $(sys-proto): $(sys-gen) $(sys-def) $(sys-asm-common) + $(E) " GEN " $@ + $(Q) perl \ + $(sys-gen) \ + $(sys-def) \ + $(sys-codes) \ + $(sys-proto) \ + $(sys-asm) \ + $(sys-asm-common-name) \ + $(sys-types) \ + $(arch_bits) + +$(sys-asm:.S=).o: $(sys-asm) + +$(sys-exec-tbl): $(sys-gen-tbl) $(sys-def) + $(E) " GEN " $@ + $(Q) perl \ + $(sys-gen-tbl) \ + $(sys-def) \ + $(sys-exec-tbl) \ + $(arch_bits) + +$(sys-asm-types): $(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h + $(call msg-gen, $@) + $(Q) ln -s ../../../../../../$(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h $(sys-asm-types) + $(Q) ln -s ../../../../../$(PLUGIN_ARCH_DIR)/std/syscalls/syscall-aux.S $(obj)/include/uapi/std/syscall-aux.S + $(Q) ln -s ../../../../../$(PLUGIN_ARCH_DIR)/std/syscalls/syscall-aux.h $(obj)/include/uapi/std/syscall-aux.h + +std-headers-deps += $(sys-codes) $(sys-proto) $(sys-asm-types) +mrproper-y += $(std-headers-deps) +mrproper-y += $(obj)/include/uapi/std/syscall-aux.S +mrproper-y += $(obj)/include/uapi/std/syscall-aux.h diff --git a/criu/arch/scripts/arm/gen-sys-exec-tbl.pl b/compel/arch/arm/plugins/std/syscalls/gen-sys-exec-tbl.pl similarity index 100% rename from criu/arch/scripts/arm/gen-sys-exec-tbl.pl rename to compel/arch/arm/plugins/std/syscalls/gen-sys-exec-tbl.pl diff --git a/criu/arch/scripts/arm/gen-syscalls.pl b/compel/arch/arm/plugins/std/syscalls/gen-syscalls.pl similarity index 92% rename from criu/arch/scripts/arm/gen-syscalls.pl rename to compel/arch/arm/plugins/std/syscalls/gen-syscalls.pl index ac524236d..c683e4998 100755 --- a/criu/arch/scripts/arm/gen-syscalls.pl +++ b/compel/arch/arm/plugins/std/syscalls/gen-syscalls.pl @@ -17,9 +17,9 @@ $prototypes =~ s/.*include\///g; my $bits = $ARGV[6]; my $codesdef = $codes; -$codesdef =~ tr/.-/_/; +$codesdef =~ tr/.\-\//_/; my $protosdef = $protos; -$protosdef =~ tr/.-/_/; +$protosdef =~ tr/.\-\//_/; my $code = "code$bits"; my $need_aux = 0; @@ -91,8 +91,8 @@ for () { } if ($need_aux == 1) { - print ASMOUT "#include \"asm/syscall-aux.S\"\n"; - print CODESOUT "#include \"asm/syscall-aux.h\"\n"; + print ASMOUT "#include \"uapi/std/syscall-aux.S\"\n"; + print CODESOUT "#include \"uapi/std/syscall-aux.h\"\n"; } print CODESOUT "#endif /* $codesdef */"; diff --git a/criu/arch/arm/include/asm/syscall-aux.S b/compel/arch/arm/plugins/std/syscalls/syscall-aux.S similarity index 100% rename from criu/arch/arm/include/asm/syscall-aux.S rename to compel/arch/arm/plugins/std/syscalls/syscall-aux.S diff --git a/criu/arch/arm/include/asm/syscall-aux.h b/compel/arch/arm/plugins/std/syscalls/syscall-aux.h similarity index 100% rename from criu/arch/arm/include/asm/syscall-aux.h rename to compel/arch/arm/plugins/std/syscalls/syscall-aux.h diff --git a/criu/arch/arm/syscalls/syscall-common.S b/compel/arch/arm/plugins/std/syscalls/syscall-common.S similarity index 100% rename from criu/arch/arm/syscalls/syscall-common.S rename to compel/arch/arm/plugins/std/syscalls/syscall-common.S diff --git a/criu/arch/arm/syscalls/syscall.def b/compel/arch/arm/plugins/std/syscalls/syscall.def similarity index 100% rename from criu/arch/arm/syscalls/syscall.def rename to compel/arch/arm/plugins/std/syscalls/syscall.def diff --git a/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls b/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls new file mode 100644 index 000000000..a955c1556 --- /dev/null +++ b/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls @@ -0,0 +1,57 @@ +ccflags-y += -iquote $(PLUGIN_ARCH_DIR)/std/syscalls/ +asflags-y += -iquote $(PLUGIN_ARCH_DIR)/std/syscalls/ + +sys-types := $(obj)/include/uapi/std/syscall-types.h +sys-codes := $(obj)/include/uapi/std/syscall-codes.h +sys-proto := $(obj)/include/uapi/std/syscall.h + +sys-def := $(PLUGIN_ARCH_DIR)/std/syscalls/syscall-ppc64.tbl +sys-asm-common-name := std/syscalls/syscall-common-ppc64.S +sys-asm-common := $(PLUGIN_ARCH_DIR)/$(sys-asm-common-name) +sys-asm-types := $(obj)/include/uapi/std/asm/syscall-types.h +sys-exec-tbl = $(PLUGIN_ARCH_DIR)/std/sys-exec-tbl.c + +sys-asm := ./$(PLUGIN_ARCH_DIR)/std/syscalls/syscalls.S +std-obj-y += $(sys-asm:.S=).o + +$(sys-codes): $(sys-def) + $(E) " GEN " $@ + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_CODES_H__" >> $@ + $(Q) echo "#define __ASM_CR_SYSCALL_CODES_H__" >> $@ + $(Q) cat $< | awk '/^__NR/{SYSN=$$1; sub("^__NR", "SYS", SYSN);'\ + 'print "\n#ifndef ", $$1, "\n#define", $$1, $$2, "\n#endif";'\ + 'print "#ifndef ", SYSN, "\n#define ", SYSN, $$1, "\n#endif"}' >> $@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_CODES_H__ */" >> $@ + +$(sys-proto): $(sys-def) + $(E) " GEN " $@ + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_PROTO_H__" >> $@ + $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H__" >> $@ + $(Q) echo "#include \"uapi/std/syscall-codes.h\"" >> $@ + $(Q) echo "#include \"uapi/std/syscall-types.h\"" >> $@ + $(Q) cat $< | awk '/^__NR/{print "extern long", $$3, substr($$0, index($$0,$$4)), ";"}' >> $@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H__ */" >> $@ + +$(sys-asm): $(sys-def) $(sys-asm-common) $(sys-codes) $(sys-proto) + $(E) " GEN " $@ + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#include \"uapi/std/syscall-codes.h\"" >> $@ + $(Q) echo "#include \"$(sys-asm-common-name)\"" >> $@ + $(Q) cat $< | awk '/^__NR/{print "SYSCALL(", $$3, ",", $$2, ")"}' >> $@ + +$(sys-exec-tbl): $(sys-def) $(sys-codes) $(sys-proto) + $(E) " GEN " $@ + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "static struct syscall_exec_desc sc_exec_table[] = {" >> $@ + $(Q) cat $< | awk '/^__NR/{print "SYSCALL(", substr($$3, 5), ",", $$2, ")"}' >> $@ + $(Q) echo " { }, /* terminator */" >> $@ + $(Q) echo "};" >> $@ + +$(sys-asm-types): $(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h + $(call msg-gen, $@) + $(Q) ln -s ../../../../../../$(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h $(sys-asm-types) + +std-headers-deps += $(sys-codes) $(sys-proto) $(sys-asm-types) +mrproper-y += $(std-headers-deps) diff --git a/criu/arch/ppc64/syscalls/syscall-common-ppc64.S b/compel/arch/ppc64/plugins/std/syscalls/syscall-common-ppc64.S similarity index 100% rename from criu/arch/ppc64/syscalls/syscall-common-ppc64.S rename to compel/arch/ppc64/plugins/std/syscalls/syscall-common-ppc64.S diff --git a/criu/arch/ppc64/syscalls/syscall-ppc64.tbl b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl similarity index 100% rename from criu/arch/ppc64/syscalls/syscall-ppc64.tbl rename to compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl diff --git a/compel/arch/x86/plugins/std/syscalls/Makefile.syscalls b/compel/arch/x86/plugins/std/syscalls/Makefile.syscalls new file mode 100644 index 000000000..040d1e3b6 --- /dev/null +++ b/compel/arch/x86/plugins/std/syscalls/Makefile.syscalls @@ -0,0 +1,122 @@ +std-obj-y += ./$(PLUGIN_ARCH_DIR)/std/syscalls-64.o + +sys-proto-types := $(obj)/include/uapi/std/syscall-types.h +sys-proto-generic := $(obj)/include/uapi/std/syscall.h +sys-codes-generic := $(obj)/include/uapi/std/syscall-codes.h +sys-codes = $(obj)/include/uapi/std/syscall-codes-$(1).h +sys-proto = $(obj)/include/uapi/std/syscall-$(1).h +sys-def = $(PLUGIN_ARCH_DIR)/std/syscalls/syscall_$(1).tbl +sys-asm = $(PLUGIN_ARCH_DIR)/std/syscalls-$(1).S +sys-asm-common-name = std/syscalls/syscall-common-x86-$(1).S +sys-asm-common = $(PLUGIN_ARCH_DIR)/$(sys-asm-common-name) +sys-asm-types := $(obj)/include/uapi/std/asm/syscall-types.h +sys-exec-tbl = $(PLUGIN_ARCH_DIR)/std/sys-exec-tbl-$(1).c + +sys-bits := 64 + +AV := $$$$ + +define gen-rule-sys-codes +$(sys-codes): $(sys-def) $(sys-proto-types) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) echo "#ifndef ASM_SYSCALL_CODES_H_$(1)__" >> $$@ + $(Q) echo "#define ASM_SYSCALL_CODES_H_$(1)__" >> $$@ + $(Q) cat $$< | awk '/^__NR/{SYSN=$(AV)1; \ + sub("^__NR", "SYS", SYSN); \ + print "\n#ifndef ", $(AV)1; \ + print "#define", $(AV)1, $(AV)2; \ + print "#endif"; \ + print "\n#ifndef ", SYSN; \ + print "#define ", SYSN, $(AV)1; \ + print "#endif";}' >> $$@ + $(Q) echo "#endif /* ASM_SYSCALL_CODES_H_$(1)__ */" >> $$@ +endef + +define gen-rule-sys-proto +$(sys-proto): $(sys-def) $(sys-proto-types) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) echo "#ifndef ASM_SYSCALL_PROTO_H_$(1)__" >> $$@ + $(Q) echo "#define ASM_SYSCALL_PROTO_H_$(1)__" >> $$@ + $(Q) echo '#include "uapi/std/syscall-codes-$(1).h"' >> $$@ + $(Q) echo '#include "uapi/std/syscall-types.h"' >> $$@ +ifeq ($(1),32) + $(Q) echo '#include "asm/syscall32.h"' >> $$@ +endif + $(Q) cat $$< | awk '/^__NR/{print "extern long", $(AV)3, \ + substr($(AV)0, index($(AV)0,$(AV)4)), ";"}' >> $$@ + $(Q) echo "#endif /* ASM_SYSCALL_PROTO_H_$(1)__ */" >> $$@ +endef + +define gen-rule-sys-asm +$(sys-asm): $(sys-def) $(sys-asm-common) $(sys-codes) $(sys-proto) $(sys-proto-types) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) echo '#include "uapi/std/syscall-codes-$(1).h"' >> $$@ + $(Q) echo '#include "$(sys-asm-common-name)"' >> $$@ + $(Q) cat $$< | awk '/^__NR/{print "SYSCALL(", $(AV)3, ",", $(AV)2, ")"}' >> $$@ +endef + +define gen-rule-sys-exec-tbl +$(sys-exec-tbl): $(sys-def) $(sys-codes) $(sys-proto) $(sys-proto-generic) $(sys-proto-types) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) cat $$< | awk '/^__NR/{print \ + "SYSCALL(", substr($(AV)3, 5), ",", $(AV)2, ")"}' >> $$@ +endef + +$(sys-codes-generic): $(PLUGIN_ARCH_DIR)/std/syscalls/syscall_32.tbl $(sys-proto-types) + $(call msg-gen, $@) + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_CODES_H__" >> $@ + $(Q) echo "#define __ASM_CR_SYSCALL_CODES_H__" >> $@ + $(Q) echo '#include "uapi/std/syscall-codes-64.h"' >> $@ + $(Q) cat $< | awk '/^__NR/{NR32=$$1; \ + sub("^__NR", "__NR32", NR32); \ + print "\n#ifndef ", NR32; \ + print "#define ", NR32, $$2; \ + print "#endif";}' >> $@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_CODES_H__ */" >> $@ +mrproper-y += $(sys-codes-generic) + +$(sys-proto-generic): $(strip $(call map,sys-proto,$(sys-bits))) $(sys-proto-types) + $(call msg-gen, $@) + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_PROTO_H__" >> $@ + $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H__" >> $@ + $(Q) echo "" >> $@ + $(Q) echo "#ifdef CONFIG_X86_32" >> $@ + $(Q) echo '#include "uapi/std/syscall-32.h"' >> $@ + $(Q) echo "#else" >> $@ + $(Q) echo '#include "uapi/std/syscall-64.h"' >> $@ + $(Q) echo "#endif /* CONFIG_X86_32 */" >> $@ + $(Q) echo "" >> $@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H__ */" >> $@ +mrproper-y += $(sys-proto-generic) + +define gen-rule-sys-exec-tbl +$(sys-exec-tbl): $(sys-def) $(sys-codes) $(sys-proto) $(sys-proto-generic) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) cat $$< | awk '/^__NR/{print \ + "SYSCALL(", substr($(AV)3, 5), ",", $(AV)2, ")"}' >> $$@ +endef + +$(eval $(call map,gen-rule-sys-codes,$(sys-bits))) +$(eval $(call map,gen-rule-sys-proto,$(sys-bits))) +$(eval $(call map,gen-rule-sys-asm,$(sys-bits))) +$(eval $(call map,gen-rule-sys-exec-tbl,$(sys-bits))) + +$(sys-asm-types): $(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h + $(call msg-gen, $@) + $(Q) ln -s ../../../../../../$(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h $(sys-asm-types) + +std-headers-deps += $(call sys-codes,$(sys-bits)) +std-headers-deps += $(call sys-proto,$(sys-bits)) +std-headers-deps += $(call sys-asm,$(sys-bits)) +std-headers-deps += $(call sys-exec-tbl,$(sys-bits)) +std-headers-deps += $(sys-codes-generic) +std-headers-deps += $(sys-proto-generic) +std-headers-deps += $(sys-asm-types) +mrproper-y += $(std-headers-deps) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index a30597ad8..436e40724 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -1,12 +1,13 @@ .PHONY: .FORCE -ARCH_DIR := compel/arch/$(ARCH)/plugins +PLUGIN_ARCH_DIR := compel/arch/$(ARCH)/plugins # # CFLAGS, ASFLAGS, LDFLAGS # General compel includes ccflags-y += -iquote $(SRC_DIR)/compel/include +ccflags-y += -fno-stack-protector # General compel/plugins includes ccflags-y += -iquote $(obj)/include @@ -15,13 +16,14 @@ asflags-y += -iquote $(obj)/include asflags-y += -iquote $(obj)/include/uapi # Arch compel/plugins includes -ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR)/include -asflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR)/include -asflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR) +ccflags-y += -iquote $(PLUGIN_ARCH_DIR)/include +asflags-y += -iquote $(PLUGIN_ARCH_DIR)/include +asflags-y += -iquote $(PLUGIN_ARCH_DIR) # General flags for assembly -asflags-y += -Wstrict-prototypes -Wa,--noexecstack +asflags-y += -fpie -Wstrict-prototypes -Wa,--noexecstack asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer +asflags-y += -fno-stack-protector # # Fds plugin @@ -38,111 +40,18 @@ shmem-obj-y += shmem/shmem.o target += std std-obj-y += std/std.o std-obj-y += std/string.o -std-obj-y += ./$(ARCH_DIR)/std/syscalls-64.o -std-obj-y += ./$(ARCH_DIR)/std/call32.o -std-obj-y += ./$(ARCH_DIR)/std/prologue.o -sys-proto-generic := $(obj)/include/uapi/std/syscall.h -sys-codes-generic := $(obj)/include/uapi/std/syscall-codes.h -sys-codes = $(obj)/include/uapi/std/syscall-codes-$(1).h -sys-proto = $(obj)/include/uapi/std/syscall-$(1).h -sys-def = $(ARCH_DIR)/std/syscalls/syscall_$(1).tbl -sys-asm = $(ARCH_DIR)/std/syscalls-$(1).S -sys-asm-common-name = std/syscalls/syscall-common-x86-$(1).S -sys-asm-common = $(ARCH_DIR)/$(sys-asm-common-name) +include ./$(PLUGIN_ARCH_DIR)/std/syscalls/Makefile.syscalls -sys-bits := 64 - -AV := $$$$ - -define gen-rule-sys-codes -$(sys-codes): $(sys-def) - $(call msg-gen, $$@) - $(Q) echo "/* Autogenerated, don't edit */" > $$@ - $(Q) echo "#ifndef ASM_SYSCALL_CODES_H_$(1)__" >> $$@ - $(Q) echo "#define ASM_SYSCALL_CODES_H_$(1)__" >> $$@ - $(Q) cat $$< | awk '/^__NR/{SYSN=$(AV)1; \ - sub("^__NR", "SYS", SYSN); \ - print "\n#ifndef ", $(AV)1; \ - print "#define", $(AV)1, $(AV)2; \ - print "#endif"; \ - print "\n#ifndef ", SYSN; \ - print "#define ", SYSN, $(AV)1; \ - print "#endif";}' >> $$@ - $(Q) echo "#endif /* ASM_SYSCALL_CODES_H_$(1)__ */" >> $$@ +define syscall-priority +$(addprefix $(obj)/,$($(1):%.o=%.d)): | $($(2)) +$(addprefix $(obj)/,$($(1):%.o=%.i)): | $($(2)) +$(addprefix $(obj)/,$($(1):%.o=%.s)): | $($(2)) +$(addprefix $(obj)/,$($(1))): | $($(2)) endef -define gen-rule-sys-proto -$(sys-proto): $(sys-def) - $(call msg-gen, $$@) - $(Q) echo "/* Autogenerated, don't edit */" > $$@ - $(Q) echo "#ifndef ASM_SYSCALL_PROTO_H_$(1)__" >> $$@ - $(Q) echo "#define ASM_SYSCALL_PROTO_H_$(1)__" >> $$@ - $(Q) echo '#include "std/syscall-codes-$(1).h"' >> $$@ - $(Q) echo '#include "syscall-types.h"' >> $$@ -ifeq ($(1),32) - $(Q) echo '#include "asm/syscall32.h"' >> $$@ -endif - $(Q) cat $$< | awk '/^__NR/{print "extern long", $(AV)3, \ - substr($(AV)0, index($(AV)0,$(AV)4)), ";"}' >> $$@ - $(Q) echo "#endif /* ASM_SYSCALL_PROTO_H_$(1)__ */" >> $$@ -endef - -define gen-rule-sys-asm -$(sys-asm): $(sys-def) $(sys-asm-common) $(sys-codes) $(sys-proto) - $(call msg-gen, $$@) - $(Q) echo "/* Autogenerated, don't edit */" > $$@ - $(Q) echo '#include "std/syscall-codes-$(1).h"' >> $$@ - $(Q) echo '#include "$(sys-asm-common-name)"' >> $$@ - $(Q) cat $$< | awk '/^__NR/{print "SYSCALL(", $(AV)3, ",", $(AV)2, ")"}' >> $$@ -endef - -define gen-rule-sys-exec-tbl -$(sys-exec-tbl): $(sys-def) $(sys-codes) $(sys-proto) $(sys-proto-generic) - $(call msg-gen, $$@) - $(Q) echo "/* Autogenerated, don't edit */" > $$@ - $(Q) cat $$< | awk '/^__NR/{print \ - "SYSCALL(", substr($(AV)3, 5), ",", $(AV)2, ")"}' >> $$@ -endef - -$(sys-codes-generic): $(ARCH_DIR)/std/syscalls/syscall_32.tbl - $(call msg-gen, $@) - $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) echo "#ifndef __ASM_CR_SYSCALL_CODES_H__" >> $@ - $(Q) echo "#define __ASM_CR_SYSCALL_CODES_H__" >> $@ - $(Q) echo '#include "std/syscall-codes-64.h"' >> $@ - $(Q) cat $< | awk '/^__NR/{NR32=$$1; \ - sub("^__NR", "__NR32", NR32); \ - print "\n#ifndef ", NR32; \ - print "#define ", NR32, $$2; \ - print "#endif";}' >> $@ - $(Q) echo "#endif /* __ASM_CR_SYSCALL_CODES_H__ */" >> $@ - -$(sys-proto-generic): $(strip $(call map,sys-proto,$(sys-bits))) - $(call msg-gen, $@) - $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) echo "#ifndef __ASM_CR_SYSCALL_PROTO_H__" >> $@ - $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H__" >> $@ - $(Q) echo "" >> $@ - $(Q) echo "#ifdef CONFIG_X86_32" >> $@ - $(Q) echo '#include "std/syscall-32.h"' >> $@ - $(Q) echo "#else" >> $@ - $(Q) echo '#include "std/syscall-64.h"' >> $@ - $(Q) echo "#endif /* CONFIG_X86_32 */" >> $@ - $(Q) echo "" >> $@ - $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H__ */" >> $@ - -$(eval $(call map,gen-rule-sys-codes,$(sys-bits))) -$(eval $(call map,gen-rule-sys-proto,$(sys-bits))) -$(eval $(call map,gen-rule-sys-asm,$(sys-bits))) - -std-headers-deps += $(call sys-codes,$(sys-bits)) -std-headers-deps += $(call sys-proto,$(sys-bits)) -std-headers-deps += $(call sys-asm,$(sys-bits)) -std-headers-deps += $(sys-codes-generic) -std-headers-deps += $(sys-proto-generic) - -$(addprefix $(obj)/,$(std-obj-y:%.o=%.d)): | $(std-headers-deps) -$(addprefix $(obj)/,$(std-obj-y:%.o=%.i)): | $(std-headers-deps) -$(addprefix $(obj)/,$(std-obj-y:%.o=%.s)): | $(std-headers-deps) -$(addprefix $(obj)/,$(std-obj-y)): | $(std-headers-deps) +# +# Almost all plugins depen on syscall headers +# and definitions so we have to order their +# generation manually. +$(foreach t,$(target),$(eval $(call syscall-priority,$(t)-obj-y,std-headers-deps))) diff --git a/compel/plugins/include/uapi/std/asm/syscall-types.h b/compel/plugins/include/uapi/std/asm/syscall-types.h deleted file mode 120000 index de3054eef..000000000 --- a/compel/plugins/include/uapi/std/asm/syscall-types.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../arch/x86/plugins/include/asm/syscall-types.h \ No newline at end of file diff --git a/compel/plugins/include/uapi/std/syscall-codes.h b/compel/plugins/include/uapi/std/syscall-codes.h deleted file mode 120000 index 4296e5019..000000000 --- a/compel/plugins/include/uapi/std/syscall-codes.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../criu/include/syscall-codes.h \ No newline at end of file diff --git a/compel/plugins/include/uapi/std/syscall.h b/compel/plugins/include/uapi/std/syscall.h deleted file mode 120000 index 697802a4d..000000000 --- a/compel/plugins/include/uapi/std/syscall.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../criu/include/syscall.h \ No newline at end of file diff --git a/compel/plugins/std/string.c b/compel/plugins/std/string.c index f4181f92a..6e5d42ed1 100644 --- a/compel/plugins/std/string.c +++ b/compel/plugins/std/string.c @@ -222,6 +222,8 @@ fin: void *std_memcpy(void *to, const void *from, unsigned int n) { + /* FIXME: Per-arch support */ +#if 0 int d0, d1, d2; asm volatile("rep ; movsl \n" "movl %4,%%ecx \n" @@ -232,6 +234,7 @@ void *std_memcpy(void *to, const void *from, unsigned int n) : "=&c" (d0), "=&D" (d1), "=&S" (d2) : "0" (n / 4), "g" (n), "1" ((long)to), "2" ((long)from) : "memory"); +#endif return to; } diff --git a/criu/Makefile b/criu/Makefile index 216306351..2b0989a57 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -35,16 +35,16 @@ include $(__nmk_dir)msg.mk # Needed libraries checks include $(SRC_DIR)/criu/Makefile.packages -# -# System calls library. -ifeq ($(ARCH),x86) -# Do not need 32-bit compatible syscall lib compiled in criu -SYSCALL-LIB := $(ARCH_DIR)/syscalls-64.built-in.o -else -SYSCALL-LIB := $(ARCH_DIR)/syscalls.built-in.o -endif -syscalls_lib: - $(Q) $(MAKE) $(call build-as,Makefile.syscalls,$(ARCH_DIR)) all +## +## System calls library. +#ifeq ($(ARCH),x86) +## Do not need 32-bit compatible syscall lib compiled in criu +#SYSCALL-LIB := $(ARCH_DIR)/syscalls-64.built-in.o +#else +#SYSCALL-LIB := $(ARCH_DIR)/syscalls.built-in.o +#endif +#syscalls_lib: +# $(Q) $(MAKE) $(call build-as,Makefile.syscalls,$(ARCH_DIR)) all .PHONY: syscalls_lib # @@ -95,7 +95,6 @@ subclean: $(Q) $(RM) $(obj)/*.{gcda,gcno,gcov} $(Q) $(RM) $(obj)/pie/*.{gcda,gcno,gcov} $(Q) $(RM) -r $(obj)/gcov - $(Q) $(MAKE) $(call build-as,Makefile.syscalls,$(ARCH_DIR)) clean $(Q) $(MAKE) $(build)=$(ARCH_DIR) clean $(Q) $(MAKE) $(call build-as,Makefile.library,$(PIE_DIR)) clean $(Q) $(MAKE) $(call build-as,Makefile.crtools,criu) clean @@ -107,7 +106,6 @@ clean: subclean # # Delete all generated files subproper: - $(Q) $(MAKE) $(call build-as,Makefile.syscalls,$(ARCH_DIR)) mrproper $(Q) $(MAKE) $(build)=$(ARCH_DIR) mrproper $(Q) $(MAKE) $(call build-as,Makefile.library,$(PIE_DIR)) mrproper $(Q) $(MAKE) $(call build-as,Makefile.crtools,criu) mrproper diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index cd96cdf17..9f3041eef 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -14,7 +14,7 @@ obj-y += cr-check.o obj-y += cr-dedup.o obj-y += cr-dump.o obj-y += cr-errno.o -obj-y += cr-exec.o +#obj-y += cr-exec.o obj-y += cr-restore.o obj-y += cr-service.o obj-y += crtools.o diff --git a/criu/arch/aarch64/Makefile b/criu/arch/aarch64/Makefile index e42e973e0..95775a2d3 100644 --- a/criu/arch/aarch64/Makefile +++ b/criu/arch/aarch64/Makefile @@ -3,6 +3,8 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) ccflags-y += -iquote $(obj)/include -iquote $(SRC_DIR)/criu/include ccflags-y += -iquote $(SRC_DIR)/include +ccflags-y += -iquote $(SRC_DIR)/compel/plugins/include +ccflags-y += -iquote $(SRC_DIR)/compel/include asflags-y += -D__ASSEMBLY__ obj-y += cpu.o diff --git a/criu/arch/aarch64/Makefile.syscalls b/criu/arch/aarch64/Makefile.syscalls deleted file mode 100644 index cef3f95dc..000000000 --- a/criu/arch/aarch64/Makefile.syscalls +++ /dev/null @@ -1,52 +0,0 @@ -builtin-name := syscalls.built-in.o - -CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) - -SYS-TYPES := ../../include/syscall-types.h -SYS-CODES := ../../include/syscall-codes.h -SYS-PROTO := ../../include/syscall.h - -SYS-DEF := syscall.def -SYS-ASM-COMMON := syscall-common.S - -SYS-GEN := ../scripts/arm/gen-syscalls.pl -SYS-GEN-TBL := ../scripts/arm/gen-sys-exec-tbl.pl - -asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer -asflags-y += -fpie -Wstrict-prototypes -Wa,--noexecstack -asflags-y += -iquote $(obj) -iquote $(obj)/include -iquote $(SRC_DIR)/criu/include - -SYS-ASM := syscalls.S -obj-y += $(SYS-ASM:.S=).o - -ARCH_BITS := 64 - -SYS-EXEC-TBL := sys-exec-tbl.c - -$(obj)/$(SYS-ASM): $(obj)/$(SYS-GEN) $(obj)/syscalls/$(SYS-DEF) $(obj)/syscalls/$(SYS-ASM-COMMON) - $(E) " GEN " $@ - $(Q) perl \ - $(obj)/$(SYS-GEN) \ - $(obj)/syscalls/$(SYS-DEF) \ - $(obj)/$(SYS-CODES) \ - $(obj)/$(SYS-PROTO) \ - $(obj)/$(SYS-ASM) \ - syscalls/$(SYS-ASM-COMMON) \ - $(obj)/$(SYS-TYPES) \ - $(ARCH_BITS) - -$(obj)/syscalls.o: $(obj)/$(SYS-ASM) - -$(obj)/$(SYS-EXEC-TBL): $(obj)/$(SYS-GEN-TBL) $(obj)/syscalls/$(SYS-DEF) - $(E) " GEN " $@ - $(Q) perl \ - $(obj)/$(SYS-GEN-TBL) \ - $(obj)/syscalls/$(SYS-DEF) \ - $(obj)/$(SYS-EXEC-TBL) \ - $(ARCH_BITS) - -all-y += $(obj)/$(SYS-EXEC-TBL) - -mrproper-y += $(obj)/$(SYS-EXEC-TBL) $(obj)/$(SYS-ASM) -mrproper-y += $(obj)/$(SYS-CODES) -mrproper-y += $(obj)/$(SYS-PROTO) diff --git a/criu/arch/aarch64/syscalls/syscall.def b/criu/arch/aarch64/syscalls/syscall.def deleted file mode 120000 index e9370a6e5..000000000 --- a/criu/arch/aarch64/syscalls/syscall.def +++ /dev/null @@ -1 +0,0 @@ -../../arm/syscalls/syscall.def \ No newline at end of file diff --git a/criu/arch/arm/Makefile b/criu/arch/arm/Makefile index d9033942c..8ab45cff4 100644 --- a/criu/arch/arm/Makefile +++ b/criu/arch/arm/Makefile @@ -2,6 +2,8 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include +ccflags-y += -iquote $(SRC_DIR)/compel/plugins/include +ccflags-y += -iquote $(SRC_DIR)/compel/include asflags-y += -D__ASSEMBLY__ diff --git a/criu/arch/arm/Makefile.syscalls b/criu/arch/arm/Makefile.syscalls deleted file mode 100644 index c5d1178fb..000000000 --- a/criu/arch/arm/Makefile.syscalls +++ /dev/null @@ -1,52 +0,0 @@ -builtin-name := syscalls.built-in.o - -CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) - -SYS-TYPES := ../../include/syscall-types.h -SYS-CODES := ../../include/syscall-codes.h -SYS-PROTO := ../../include/syscall.h - -SYS-DEF := syscall.def -SYS-ASM-COMMON := syscall-common.S - -SYS-GEN := ../scripts/arm/gen-syscalls.pl -SYS-GEN-TBL := ../scripts/arm/gen-sys-exec-tbl.pl - -asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer -asflags-y += -fpie -Wstrict-prototypes -Wa,--noexecstack -asflags-y += -iquote $(obj) -iquote $(obj)/include -iquote $(SRC_DIR)/criu/include - -SYS-ASM := syscalls.S -obj-y += $(SYS-ASM:.S=).o - -ARCH_BITS := 32 - -SYS-EXEC-TBL := sys-exec-tbl.c - -$(obj)/$(SYS-ASM): $(obj)/$(SYS-GEN) $(obj)/syscalls/$(SYS-DEF) $(obj)/syscalls/$(SYS-ASM-COMMON) - $(E) " GEN " $@ - $(Q) perl \ - $(obj)/$(SYS-GEN) \ - $(obj)/syscalls/$(SYS-DEF) \ - $(obj)/$(SYS-CODES) \ - $(obj)/$(SYS-PROTO) \ - $(obj)/$(SYS-ASM) \ - syscalls/$(SYS-ASM-COMMON) \ - $(obj)/$(SYS-TYPES) \ - $(ARCH_BITS) - -$(obj)/syscalls.o: $(obj)/$(SYS-ASM) - -$(obj)/$(SYS-EXEC-TBL): $(obj)/$(SYS-GEN-TBL) $(obj)/syscalls/$(SYS-DEF) - $(E) " GEN " $@ - $(Q) perl \ - $(obj)/$(SYS-GEN-TBL) \ - $(obj)/syscalls/$(SYS-DEF) \ - $(obj)/$(SYS-EXEC-TBL) \ - $(ARCH_BITS) - -all-y += $(obj)/$(SYS-EXEC-TBL) - -mrproper-y += $(obj)/$(SYS-EXEC-TBL) $(obj)/$(SYS-ASM) -mrproper-y += $(obj)/$(SYS-CODES) -mrproper-y += $(obj)/$(SYS-PROTO) diff --git a/criu/arch/ppc64/Makefile b/criu/arch/ppc64/Makefile index 21f6fdd2d..fda94369d 100644 --- a/criu/arch/ppc64/Makefile +++ b/criu/arch/ppc64/Makefile @@ -2,6 +2,8 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include +ccflags-y += -iquote $(SRC_DIR)/compel/plugins/include +ccflags-y += -iquote $(SRC_DIR)/compel/include obj-y += cpu.o obj-y += crtools.o diff --git a/criu/arch/ppc64/Makefile.syscalls b/criu/arch/ppc64/Makefile.syscalls deleted file mode 100644 index d11597821..000000000 --- a/criu/arch/ppc64/Makefile.syscalls +++ /dev/null @@ -1,57 +0,0 @@ -builtin-name := syscalls.built-in.o - -CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) - -SYS-TYPES := ../../include/syscall-types.h -SYS-CODES := ../../include/syscall-codes.h -SYS-PROTO := ../../include/syscall.h -SYS-DEF := syscall-ppc64.tbl -SYS-ASM-COMMON := syscall-common-ppc64.S - -asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer -asflags-y += -fpie -Wstrict-prototypes -Wa,--noexecstack -asflags-y += -iquote $(obj) -iquote $(obj)/include -iquote $(SRC_DIR)/criu/include - -SYS-ASM := syscalls.S -obj-y += $(SYS-ASM:.S=).o - -$(obj)/$(SYS-CODES): $(obj)/syscalls/$(SYS-DEF) - $(E) " GEN " $@ - $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) echo "#ifndef __ASM_CR_SYSCALL_CODES_H__" >> $@ - $(Q) echo "#define __ASM_CR_SYSCALL_CODES_H__" >> $@ - $(Q) cat $< | awk '/^__NR/{SYSN=$$1; sub("^__NR", "SYS", SYSN);'\ - 'print "\n#ifndef ", $$1, "\n#define", $$1, $$2, "\n#endif";'\ - 'print "#ifndef ", SYSN, "\n#define ", SYSN, $$1, "\n#endif"}' >> $@ - $(Q) echo "#endif /* __ASM_CR_SYSCALL_CODES_H__ */" >> $@ -mrproper-y += $(obj)/$(SYS-CODES) - -$(obj)/$(SYS-PROTO): $(obj)/syscalls/$(SYS-DEF) - $(E) " GEN " $@ - $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) echo "#ifndef __ASM_CR_SYSCALL_PROTO_H__" >> $@ - $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H__" >> $@ - $(Q) echo "#include \"syscall-codes.h\"" >> $@ - $(Q) echo "#include \"syscall-types.h\"" >> $@ - $(Q) cat $< | awk '/^__NR/{print "extern long", $$3, substr($$0, index($$0,$$4)), ";"}' >> $@ - $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H__ */" >> $@ -mrproper-y += $(obj)/$(SYS-PROTO) - -$(obj)/$(SYS-ASM): $(obj)/syscalls/$(SYS-DEF) $(obj)/syscalls/$(SYS-ASM-COMMON) $(obj)/$(SYS-CODES) $(obj)/$(SYS-PROTO) - $(E) " GEN " $@ - $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) echo "#include \"syscall-codes.h\"" >> $@ - $(Q) echo "#include \"syscalls/$(SYS-ASM-COMMON)\"" >> $@ - $(Q) cat $< | awk '/^__NR/{print "SYSCALL(", $$3, ",", $$2, ")"}' >> $@ -mrproper-y += $(obj)/$(SYS-ASM) - -SYS-EXEC-TBL := sys-exec-tbl.c -$(obj)/$(SYS-EXEC-TBL): $(obj)/syscalls/$(SYS-DEF) $(obj)/$(SYS-CODES) $(obj)/$(SYS-PROTO) - $(E) " GEN " $@ - $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) echo "static struct syscall_exec_desc sc_exec_table[] = {" >> $@ - $(Q) cat $< | awk '/^__NR/{print "SYSCALL(", substr($$3, 5), ",", $$2, ")"}' >> $@ - $(Q) echo " { }, /* terminator */" >> $@ - $(Q) echo "};" >> $@ -mrproper-y += $(obj)/$(SYS-EXEC-TBL) -all-y += $(obj)/$(SYS-EXEC-TBL) diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index bf5395fe9..04a0cb3d0 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -2,6 +2,8 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include +ccflags-y += -iquote $(SRC_DIR)/compel/plugins/include +ccflags-y += -iquote $(SRC_DIR)/compel/include asflags-y += -Wstrict-prototypes -Wa,--noexecstack asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer diff --git a/criu/arch/x86/Makefile.syscalls b/criu/arch/x86/Makefile.syscalls deleted file mode 100644 index 839f24c1b..000000000 --- a/criu/arch/x86/Makefile.syscalls +++ /dev/null @@ -1,158 +0,0 @@ -include $(__nmk_dir)msg.mk - -CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) -CFLAGS := $(filter-out -DCONFIG_X86_64,$(CFLAGS)) - -SYS-PROTO-GENERIC := $(obj)/../../include/syscall.h - -SYS-CODES-GENERIC = $(obj)/../../include/syscall-codes.h -SYS-CODES = $(obj)/../../include/syscall-codes-$(1).h -SYS-PROTO = $(obj)/../../include/syscall-$(1).h -SYS-DEF = $(obj)/syscalls/syscall_$(1).tbl -SYS-ASM = syscalls-$(1).S -SYS-ASM-COMMON = syscall-common-x86-$(1).S -SYS-EXEC-TBL = $(obj)/sys-exec-tbl-$(1).c - -target := -target_32 := syscalls-32 -target_64 := syscalls-64 - -SYS-BITS := 64 -ifeq ($(CONFIG_COMPAT),y) - SYS-BITS += 32 -endif - -# targets -define gen-targets -target += $(target_$(1)) -endef - -$(eval $(call map,gen-targets,$(SYS-BITS))) - -# AFLAGS, LDFLAGS -asflags-y += -Wstrict-prototypes -Wa,--noexecstack -asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer -asflags-y += -iquote $(obj) -iquote $(obj)/include -asflags-y += -iquote $(SRC_DIR)/criu/include - -AFLAGS_$(target_32) += -fno-pic -m32 -AFLAGS_$(target_64) += -fpie -LDFLAGS_$(target_32) += -m elf_i386 - -$(target_32)-obj-y += syscalls/syscall32.o -$(obj)/syscalls/syscall32.d: $(obj)/../../include/syscall-codes-32.h \ - $(obj)/../../include/syscall-32.h - -CFLAGS_syscall32.o += -fno-pic -m32 -DCR_NOGLIBC -DCONFIG_X86_32 -CFLAGS_syscall32.d += -fno-pic -m32 -DCR_NOGLIBC -DCONFIG_X86_32 -cleanup-y += $(obj)/syscalls/syscall32.o - -# Here are rules for 32/64-bit platforms. For compat mode we need both -# 32 and 64 bit syscalls, so generate the rules with SYS-BIT being -# $1 parameter in all gen-rule-* - -# awk variable should be escaped twice -AV := $$$$ - -define gen-rule-sys-codes -$(SYS-CODES): $(SYS-DEF) - $(call msg-gen, $$@) - $(Q) echo "/* Autogenerated, don't edit */" > $$@ - $(Q) echo "#ifndef __ASM_CR_SYSCALL_CODES_H_$(1)__" >> $$@ - $(Q) echo "#define __ASM_CR_SYSCALL_CODES_H_$(1)__" >> $$@ - $(Q) cat $$< | awk '/^__NR/{SYSN=$(AV)1; \ - sub("^__NR", "SYS", SYSN); \ - print "\n#ifndef ", $(AV)1; \ - print "#define", $(AV)1, $(AV)2; \ - print "#endif"; \ - print "\n#ifndef ", SYSN; \ - print "#define ", SYSN, $(AV)1; \ - print "#endif";}' >> $$@ - $(Q) echo "#endif /* __ASM_CR_SYSCALL_CODES_H_$(1)__ */" >> $$@ -mrproper-y += $(SYS-CODES) -endef - -define gen-rule-sys-proto -$(SYS-PROTO): $(SYS-DEF) - $(call msg-gen, $$@) - $(Q) echo "/* Autogenerated, don't edit */" > $$@ - $(Q) echo "#ifndef __ASM_CR_SYSCALL_PROTO_H_$(1)__" >> $$@ - $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H_$(1)__" >> $$@ - $(Q) echo "#ifndef CR_NOGLIBC" >> $$@ - $(Q) echo "# error This file should only be used in the parasite code" \ - >> $$@ - $(Q) echo "#endif" >> $$@ - $(Q) echo '#include "syscall-codes-$(1).h"' >> $$@ - $(Q) echo '#include "syscall-types.h"' >> $$@ -ifeq ($(1),32) - $(Q) echo '#include "asm/syscall32.h"' >> $$@ -endif - $(Q) cat $$< | awk '/^__NR/{print "extern long", $(AV)3, \ - substr($(AV)0, index($(AV)0,$(AV)4)), ";"}' >> $$@ - $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H_$(1)__ */" >> $$@ -mrproper-y += $(SYS-PROTO) -endef - -define gen-rule-sys-asm -$(obj)/$(SYS-ASM): $(SYS-DEF) $(obj)/syscalls/$(SYS-ASM-COMMON) \ - $(SYS-CODES) $(SYS-PROTO) - $(call msg-gen, $$@) - $(Q) echo "/* Autogenerated, don't edit */" > $$@ - $(Q) echo '#include "syscall-codes-$(1).h"' >> $$@ - $(Q) echo '#include "syscalls/$(SYS-ASM-COMMON)"' >> $$@ - $(Q) cat $$< | awk '/^__NR/{print "SYSCALL(", $(AV)3, ",", $(AV)2, ")"}'\ - >> $$@ -mrproper-y += $(obj)/$(SYS-ASM) -$(target_$(1))-obj-y += $(SYS-ASM:.S=).o -endef - -# for 32-bit $(SYS-ASM) -AFLAGS_syscalls-32.o += -fno-pic -m32 - -define gen-rule-sys-exec-tbl -$(SYS-EXEC-TBL): $(SYS-DEF) $(SYS-CODES) $(SYS-PROTO) $(SYS-PROTO-GENERIC) - $(call msg-gen, $$@) - $(Q) echo "/* Autogenerated, don't edit */" > $$@ - $(Q) cat $$< | awk '/^__NR/{print \ - "SYSCALL(", substr($(AV)3, 5), ",", $(AV)2, ")"}' >> $$@ -mrproper-y += $(SYS-EXEC-TBL) -all-y += $(SYS-EXEC-TBL) -endef - -# Some parts of criu need SYS_memfd_create and other ifndef/define syscalls -# Use 64-bit, native syscalls as-is, add __NR32_*/SYS32_* defines -# to generic file -$(SYS-CODES-GENERIC): $(obj)/syscalls/syscall_32.tbl - $(call msg-gen, $@) - $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) echo "#ifndef __ASM_CR_SYSCALL_CODES_H__" >> $@ - $(Q) echo "#define __ASM_CR_SYSCALL_CODES_H__" >> $@ - $(Q) echo '#include "syscall-codes-64.h"' >> $@ - $(Q) cat $< | awk '/^__NR/{NR32=$$1; \ - sub("^__NR", "__NR32", NR32); \ - print "\n#ifndef ", NR32; \ - print "#define ", NR32, $$2; \ - print "#endif";}' >> $@ - $(Q) echo "#endif /* __ASM_CR_SYSCALL_CODES_H__ */" >> $@ -mrproper-y += $(SYS-CODES-GENERIC) -all-y += $(SYS-CODES-GENERIC) - -$(SYS-PROTO-GENERIC): $(strip $(call map,SYS-PROTO,$(SYS-BITS))) - $(call msg-gen, $@) - $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) echo "#ifndef __ASM_CR_SYSCALL_PROTO_H__" >> $@ - $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H__" >> $@ - $(Q) echo "" >> $@ - $(Q) echo "#ifdef CONFIG_X86_32" >> $@ - $(Q) echo '#include "syscall-32.h"' >> $@ - $(Q) echo "#else" >> $@ - $(Q) echo '#include "syscall-64.h"' >> $@ - $(Q) echo "#endif /* CONFIG_X86_32 */" >> $@ - $(Q) echo "" >> $@ - $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H__ */" >> $@ -mrproper-y += $(SYS-PROTO-GENERIC) - -$(eval $(call map,gen-rule-sys-codes,$(SYS-BITS))) -$(eval $(call map,gen-rule-sys-proto,$(SYS-BITS))) -$(eval $(call map,gen-rule-sys-asm,$(SYS-BITS))) -$(eval $(call map,gen-rule-sys-exec-tbl,$(SYS-BITS))) diff --git a/criu/arch/x86/syscalls/syscall-common-x86-32.S b/criu/arch/x86/syscalls/syscall-common-x86-32.S deleted file mode 100644 index c1a726123..000000000 --- a/criu/arch/x86/syscalls/syscall-common-x86-32.S +++ /dev/null @@ -1,36 +0,0 @@ -#include "common/asm/linkage.h" - -#define SYSCALL(name, opcode) \ - ENTRY(name); \ - movl $opcode, %eax; \ - jmp __syscall_common; \ - END(name) - -ENTRY(__syscall_common) - pushl %ebx - pushl %esi - pushl %edi - pushl %ebp - -#define __arg(n) (4 * (n) + 20)(%esp) - movl __arg(0),%ebx - movl __arg(1),%ecx - movl __arg(2),%edx - movl __arg(3),%esi - movl __arg(4),%edi - movl __arg(5),%ebp -#undef __arg - - int $0x80 - - popl %ebp - popl %edi - popl %esi - popl %ebx - ret -END(__syscall_common) - -ENTRY(__cr_restore_rt) - movl $__NR_rt_sigreturn, %eax - jmp __syscall_common -END(__cr_restore_rt) diff --git a/criu/arch/x86/syscalls/syscall-common-x86-64.S b/criu/arch/x86/syscalls/syscall-common-x86-64.S deleted file mode 100644 index 74465c302..000000000 --- a/criu/arch/x86/syscalls/syscall-common-x86-64.S +++ /dev/null @@ -1,21 +0,0 @@ -#include "common/asm/linkage.h" - -#define SYSCALL(name, opcode) \ - ENTRY(name); \ - movl $opcode, %eax; \ - jmp __syscall_common; \ - END(name) - - .text - .align 4 - -ENTRY(__syscall_common) - movq %rcx, %r10 - syscall - ret -END(__syscall_common) - -ENTRY(__cr_restore_rt) - movq $__NR_rt_sigreturn, %rax - syscall -END(__cr_restore_rt) diff --git a/criu/arch/x86/syscalls/syscall32.c b/criu/arch/x86/syscalls/syscall32.c deleted file mode 100644 index 88af59330..000000000 --- a/criu/arch/x86/syscalls/syscall32.c +++ /dev/null @@ -1,85 +0,0 @@ -#include "asm/types.h" -#include "syscall-32.h" - -#define SYS_SOCKET 1 /* sys_socket(2) */ -#define SYS_BIND 2 /* sys_bind(2) */ -#define SYS_CONNECT 3 /* sys_connect(2) */ -#define SYS_SENDTO 11 /* sys_sendto(2) */ -#define SYS_RECVFROM 12 /* sys_recvfrom(2) */ -#define SYS_SHUTDOWN 13 /* sys_shutdown(2) */ -#define SYS_SETSOCKOPT 14 /* sys_setsockopt(2) */ -#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */ -#define SYS_SENDMSG 16 /* sys_sendmsg(2) */ -#define SYS_RECVMSG 17 /* sys_recvmsg(2) */ - -long sys_socket(int domain, int type, int protocol) -{ - u32 a[] = { (u32)domain, (u32)type, (u32)protocol }; - return sys_socketcall(SYS_SOCKET, (unsigned long *)a); -} - -long sys_connect(int sockfd, struct sockaddr *addr, int addrlen) -{ - u32 a[] = {(u32)sockfd, (u32)addr, (u32)addrlen}; - return sys_socketcall(SYS_CONNECT, (unsigned long *)a); -} - -long sys_sendto(int sockfd, void *buff, size_t len, unsigned int flags, struct sockaddr *addr, int addr_len) -{ - u32 a[] = {(u32)sockfd, (u32)buff, (u32)len, (u32)flags, (u32)addr, (u32)addr_len}; - return sys_socketcall(SYS_SENDTO, (unsigned long *)a); -} - -long sys_recvfrom(int sockfd, void *ubuf, size_t size, unsigned int flags, struct sockaddr *addr, int *addr_len) -{ - u32 a[] = {(u32)sockfd, (u32)ubuf, (u32)size, (u32)flags, (u32)addr, (u32)addr_len}; - return sys_socketcall(SYS_RECVFROM, (unsigned long *)a); -} - -long sys_sendmsg(int sockfd, const struct msghdr *msg, int flags) -{ - u32 a[] = {(u32)sockfd, (u32)msg, (u32)flags}; - return sys_socketcall(SYS_SENDMSG, (unsigned long *)a); -} - -long sys_recvmsg(int sockfd, struct msghdr *msg, int flags) -{ - u32 a[] = {(u32)sockfd, (u32)msg, (u32)flags}; - return sys_socketcall(SYS_RECVMSG, (unsigned long *)a); -} - -long sys_shutdown(int sockfd, int how) -{ - u32 a[] = {(u32)sockfd, (u32)how}; - return sys_socketcall(SYS_SHUTDOWN, (unsigned long *)a); -} - -long sys_bind(int sockfd, const struct sockaddr *addr, int addrlen) -{ - u32 a[] = {(u32)sockfd, (u32)addr, (u32)addrlen}; - return sys_socketcall(SYS_BIND, (unsigned long *)a); -} - -long sys_setsockopt(int sockfd, int level, int optname, const void *optval, unsigned int optlen) -{ - u32 a[] = {(u32)sockfd, (u32)level, (u32)optname, (u32)optval, (u32)optlen}; - return sys_socketcall(SYS_SETSOCKOPT, (unsigned long *)a); -} - -long sys_getsockopt(int sockfd, int level, int optname, const void *optval, unsigned int *optlen) -{ - u32 a[] = {(u32)sockfd, (u32)level, (u32)optname, (u32)optval, (u32)optlen}; - return sys_socketcall(SYS_GETSOCKOPT, (unsigned long *)a); -} - -#define SHMAT 21 - -long sys_shmat(int shmid, void *shmaddr, int shmflag) -{ - return sys_ipc(SHMAT, shmid, shmflag, 0, shmaddr, 0); -} - -long sys_pread(unsigned int fd, char *ubuf, u32 count, u64 pos) -{ - return sys_pread64(fd, ubuf, count, (u32)(pos & 0xffffffffu), (u32)(pos >> 32)); -} diff --git a/criu/arch/x86/syscalls/syscall_32.tbl b/criu/arch/x86/syscalls/syscall_32.tbl deleted file mode 100644 index 2bfe7ec2e..000000000 --- a/criu/arch/x86/syscalls/syscall_32.tbl +++ /dev/null @@ -1,94 +0,0 @@ -# -# System calls table, please make sure the table consist only the syscalls -# really used somewhere in project. -# -# code name arguments -# ------------------------------------------------------------------------------------------------------------------------------------------------------------- -__NR_restart_syscall 0 sys_restart_syscall (void) -__NR_exit 1 sys_exit (unsigned long error_code) -__NR_read 3 sys_read (int fd, void *buf, unsigned long count) -__NR_write 4 sys_write (int fd, const void *buf, unsigned long count) -__NR_open 5 sys_open (const char *filename, int flags, unsigned int mode) -__NR_close 6 sys_close (int fd) -__NR_unlink 10 sys_unlink (char *pathname) -__NR_lseek 19 sys_lseek (int fd, s32 offset, unsigned int origin) -__NR_getpid 20 sys_getpid (void) -__NR_mount 21 sys_mount (const char *dev_name, const char *dir_name, const char *type, unsigned long flags, const void *data) -__NR_ptrace 26 sys_ptrace (long request, pid_t pid, void *addr, void *data) -__NR_kill 37 sys_kill (long pid, int sig) -__NR_mkdir 39 sys_mkdir (const char *name, int mode) -__NR_rmdir 40 sys_rmdir (const char *name) -__NR_brk 45 sys_brk (void *addr) -__NR_umount2 52 sys_umount2 (char *name, int flags) -__NR_ioctl 54 sys_ioctl (unsigned int fd, unsigned int cmd, unsigned long arg) -__NR_fcntl 55 sys_fcntl (unsigned int fd, unsigned int cmd, unsigned long arg) -__NR_umask 60 sys_umask (int mask) -__NR_setrlimit 75 sys_setrlimit (unsigned int resource, struct krlimit *rlim) -__NR_gettimeofday 78 sys_gettimeofday (struct timeval *tv, struct timezone *tz) -__NR_munmap 91 sys_munmap (void *addr, unsigned long len) -__NR_setpriority 97 sys_setpriority (int which, int who, int nice) -__NR_socketcall 102 sys_socketcall (int call, unsigned long *args) -__NR_setitimer 104 sys_setitimer (int which, struct itimerval *in, struct itimerval *out) -__NR_getitimer 105 sys_getitimer (int which, struct itimerval *it) -__NR_wait4 114 sys_wait4 (pid_t pid, int *stat_addr, int options, struct rusage *ru) -__NR_ipc 117 sys_ipc (unsigned int call, int first, unsigned long second, unsigned long third, void *ptr, long fifth) -__NR_clone 120 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, void *child_tid) -__NR_mprotect 125 sys_mprotect (const void *addr, unsigned long len, unsigned long prot) -__NR_getpgid 132 sys_getpgid (pid_t pid) -__NR_personality 136 sys_personality (unsigned int personality) -__NR_flock 143 sys_flock (int fd, unsigned long cmd) -__NR_getsid 147 sys_getsid (void) -__NR_sched_setscheduler 156 sys_sched_setscheduler (int pid, int policy, struct sched_param *p) -__NR_nanosleep 162 sys_nanosleep (struct timespec *rqtp, struct timespec *rmtp) -__NR_mremap 163 sys_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) -__NR_prctl 172 sys_prctl (int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) -__NR_rt_sigreturn 173 sys_rt_sigreturn (void) -__NR_rt_sigaction 174 sys_sigaction (int signum, const rt_sigaction_t *act, rt_sigaction_t *oldact, size_t sigsetsize) -__NR_rt_sigprocmask 175 sys_sigprocmask (int how, k_rtsigset_t *set, k_rtsigset_t *oset, size_t sigsetsize) -__NR_rt_sigqueueinfo 178 sys_rt_sigqueueinfo (pid_t pid, int sig, siginfo_t *uinfo) -__NR_pread64 180 sys_pread64 (unsigned int fd, char *ubuf, u32 count, u32 poslo, u32 poshi) -__NR_capget 184 sys_capget (struct cap_header *h, struct cap_data *d) -__NR_capset 185 sys_capset (struct cap_header *h, struct cap_data *d) -__NR_sigaltstack 186 sys_sigaltstack (const void *uss_ptr, void *uoss_ptr) -__NR_mmap2 192 sys_mmap (void *addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) -__NR_getgroups32 205 sys_getgroups (int gsize, unsigned int *groups) -__NR_setgroups32 206 sys_setgroups (int gsize, unsigned int *groups) -__NR_setresuid32 208 sys_setresuid (int uid, int euid, int suid) -__NR_getresuid32 209 sys_getresuid (int *uid, int *euid, int *suid) -__NR_setresgid32 210 sys_setresgid (int gid, int egid, int sgid) -__NR_getresgid32 211 sys_getresgid (int *gid, int *egid, int *sgid) -__NR_setfsuid32 215 sys_setfsuid (int fsuid) -__NR_setfsgid32 216 sys_setfsgid (int fsgid) -__NR_mincore 218 sys_mincore (void *addr, unsigned long size, unsigned char *vec) -__NR_madvise 219 sys_madvise (unsigned long start, size_t len, int behavior) -__NR_gettid 224 sys_gettid (void) -__NR_futex 240 sys_futex (u32 *uaddr, int op, u32 val, struct timespec *utime, u32 *uaddr2, u32 val3) -__NR_set_thread_area 243 sys_set_thread_area (user_desc_t *info) -__NR_get_thread_area 244 sys_get_thread_area (user_desc_t *info) -__NR_io_setup 245 sys_io_setup (unsigned nr_reqs, aio_context_t *ctx32p) -__NR_io_getevents 247 sys_io_getevents (aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout) -__NR_io_submit 248 sys_io_submit (aio_context_t ctx_id, long nr, struct iocb **iocbpp) -__NR_exit_group 252 sys_exit_group (int error_code) -__NR_set_tid_address 258 sys_set_tid_address (int *tid_addr) -__NR_timer_create 259 sys_timer_create (clockid_t which_clock, struct sigevent *timer_event_spec, kernel_timer_t *created_timer_id) -__NR_timer_settime 260 sys_timer_settime (kernel_timer_t timer_id, int flags, struct itimerspec *new, struct itimerspec *old) -__NR_timer_gettime 261 sys_timer_gettime (int timer_id, struct itimerspec *setting) -__NR_timer_getoverrun 262 sys_timer_getoverrun (int timer_id) -__NR_timer_delete 263 sys_timer_delete (kernel_timer_t timer_id) -__NR_clock_gettime 265 sys_clock_gettime (int which_clock, struct timespec *tp) -__NR_waitid 284 sys_waitid (int which, pid_t pid, struct siginfo *infop, int options, struct rusage *ru) -__NR_openat 295 sys_openat (int dfd, const char *filename, int flags, int mode) -__NR_readlinkat 305 sys_readlinkat (int fd, const char *path, char *buf, int bufsize) -__NR_set_robust_list 311 sys_set_robust_list (struct robust_list_head *head, size_t len) -__NR_get_robust_list 312 sys_get_robust_list (int pid, struct robust_list_head **head_ptr, size_t *len_ptr) -__NR_vmsplice 316 sys_vmsplice (int fd, const struct iovec *iov, unsigned int nr_segs, unsigned int flags) -__NR_signalfd 321 sys_signalfd (int ufd, const k_rtsigset_t *sigmask, size_t sigsetsize) -__NR_timerfd_settime 325 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) -__NR_rt_tgsigqueueinfo 335 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *uinfo) -__NR_fanotify_init 338 sys_fanotify_init (unsigned int flags, unsigned int event_f_flags) -__NR_fanotify_mark 339 sys_fanotify_mark (int fanotify_fd, unsigned int flag, u32 mask, int dfd, const char *pathname) -__NR_open_by_handle_at 342 sys_open_by_handle_at (int mountdirfd, struct file_handle *handle, int flags) -__NR_setns 346 sys_setns (int fd, int nstype) -__NR_kcmp 349 sys_kcmp (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) -__NR_seccomp 354 sys_seccomp (unsigned int op, unsigned int flags, const char *uargs) -__NR_memfd_create 356 sys_memfd_create (const char *name, unsigned int flags) diff --git a/criu/arch/x86/syscalls/syscall_64.tbl b/criu/arch/x86/syscalls/syscall_64.tbl deleted file mode 100644 index 178a6b9bb..000000000 --- a/criu/arch/x86/syscalls/syscall_64.tbl +++ /dev/null @@ -1,105 +0,0 @@ -# -# System calls table, please make sure the table consist only the syscalls -# really used somewhere in project. -# -# __NR_name code name arguments -# ------------------------------------------------------------------------------------------------------------------------------------------------------------- -__NR_read 0 sys_read (int fd, void *buf, unsigned long count) -__NR_write 1 sys_write (int fd, const void *buf, unsigned long count) -__NR_open 2 sys_open (const char *filename, unsigned long flags, unsigned long mode) -__NR_close 3 sys_close (int fd) -__NR_lseek 8 sys_lseek (int fd, unsigned long offset, unsigned long origin) -__NR_mmap 9 sys_mmap (void *addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long offset) -__NR_mprotect 10 sys_mprotect (const void *addr, unsigned long len, unsigned long prot) -__NR_munmap 11 sys_munmap (void *addr, unsigned long len) -__NR_brk 12 sys_brk (void *addr) -__NR_rt_sigaction 13 sys_sigaction (int signum, const rt_sigaction_t *act, rt_sigaction_t *oldact, size_t sigsetsize) -__NR_rt_sigprocmask 14 sys_sigprocmask (int how, k_rtsigset_t *set, k_rtsigset_t *old, size_t sigsetsize) -__NR_rt_sigreturn 15 sys_rt_sigreturn (void) -__NR_ioctl 16 sys_ioctl (unsigned int fd, unsigned int cmd, unsigned long arg) -__NR_pread64 17 sys_pread (unsigned int fd, char *buf, size_t count, loff_t pos) -__NR_mremap 25 sys_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) -__NR_mincore 27 sys_mincore (void *addr, unsigned long size, unsigned char *vec) -__NR_madvise 28 sys_madvise (unsigned long start, size_t len, int behavior) -__NR_shmat 30 sys_shmat (int shmid, void *shmaddr, int shmflag) -__NR_dup2 33 sys_dup2 (int oldfd, int newfd) -__NR_nanosleep 35 sys_nanosleep (struct timespec *req, struct timespec *rem) -__NR_getitimer 36 sys_getitimer (int which, const struct itimerval *val) -__NR_setitimer 38 sys_setitimer (int which, const struct itimerval *val, struct itimerval *old) -__NR_getpid 39 sys_getpid (void) -__NR_socket 41 sys_socket (int domain, int type, int protocol) -__NR_connect 42 sys_connect (int sockfd, struct sockaddr *addr, int addrlen) -__NR_sendto 44 sys_sendto (int sockfd, void *buff, size_t len, unsigned int flags, struct sockaddr *addr, int addr_len) -__NR_recvfrom 45 sys_recvfrom (int sockfd, void *ubuf, size_t size, unsigned int flags, struct sockaddr *addr, int *addr_len) -__NR_sendmsg 46 sys_sendmsg (int sockfd, const struct msghdr *msg, int flags) -__NR_recvmsg 47 sys_recvmsg (int sockfd, struct msghdr *msg, int flags) -__NR_shutdown 48 sys_shutdown (int sockfd, int how) -__NR_bind 49 sys_bind (int sockfd, const struct sockaddr *addr, int addrlen) -__NR_setsockopt 54 sys_setsockopt (int sockfd, int level, int optname, const void *optval, socklen_t optlen) -__NR_getsockopt 55 sys_getsockopt (int sockfd, int level, int optname, const void *optval, socklen_t *optlen) -__NR_clone 56 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, void *child_tid) -__NR_exit 60 sys_exit (unsigned long error_code) -__NR_wait4 61 sys_wait4 (int pid, int *status, int options, struct rusage *ru) -__NR_kill 62 sys_kill (long pid, int sig) -__NR_fcntl 72 sys_fcntl (int fd, int type, long arg) -__NR_flock 73 sys_flock (int fd, unsigned long cmd) -__NR_mkdir 83 sys_mkdir (const char *name, int mode) -__NR_rmdir 84 sys_rmdir (const char *name) -__NR_unlink 87 sys_unlink (char *pathname) -__NR_umask 95 sys_umask (int mask) -__NR_gettimeofday 96 sys_gettimeofday (struct timeval *tv, struct timezone *tz) -__NR_ptrace 101 sys_ptrace (long request, pid_t pid, void *addr, void *data) -__NR_getgroups 115 sys_getgroups (int gsize, unsigned int *groups) -__NR_setgroups 116 sys_setgroups (int gsize, unsigned int *groups) -__NR_setresuid 117 sys_setresuid (int uid, int euid, int suid) -__NR_getresuid 118 sys_getresuid (int *uid, int *euid, int *suid) -__NR_setresgid 119 sys_setresgid (int gid, int egid, int sgid) -__NR_getresgid 120 sys_getresgid (int *gid, int *egid, int *sgid) -__NR_getpgid 121 sys_getpgid (pid_t pid) -__NR_setfsuid 122 sys_setfsuid (int fsuid) -__NR_setfsgid 123 sys_setfsgid (int fsgid) -__NR_getsid 124 sys_getsid (void) -__NR_capget 125 sys_capget (struct cap_header *h, struct cap_data *d) -__NR_capset 126 sys_capset (struct cap_header *h, struct cap_data *d) -__NR_rt_sigqueueinfo 129 sys_rt_sigqueueinfo (pid_t pid, int sig, siginfo_t *info) -__NR_sigaltstack 131 sys_sigaltstack (const void *uss, void *uoss) -__NR_personality 135 sys_personality (unsigned int personality) -__NR_setpriority 141 sys_setpriority (int which, int who, int nice) -__NR_sched_setscheduler 144 sys_sched_setscheduler (int pid, int policy, struct sched_param *p) -__NR_prctl 157 sys_prctl (int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) -__NR_arch_prctl 158 sys_arch_prctl (int option, unsigned long addr) -__NR_setrlimit 160 sys_setrlimit (int resource, struct krlimit *rlim) -__NR_mount 165 sys_mount (char *dev_nmae, char *dir_name, char *type, unsigned long flags, void *data) -__NR_umount2 166 sys_umount2 (char *name, int flags) -__NR_gettid 186 sys_gettid (void) -__NR_futex 202 sys_futex (u32 *uaddr, int op, u32 val, struct timespec *utime, u32 *uaddr2, u32 val3) -__NR_set_thread_area 205 sys_set_thread_area (user_desc_t *info) -__NR_io_setup 206 sys_io_setup (unsigned nr_events, aio_context_t *ctx) -__NR_io_getevents 208 sys_io_getevents (aio_context_t ctx, long min_nr, long nr, struct io_event *evs, struct timespec *tmo) -__NR_io_submit 209 sys_io_submit (aio_context_t ctx, long nr, struct iocb **iocbpp) -__NR_get_thread_area 211 sys_get_thread_area (user_desc_t *info) -__NR_set_tid_address 218 sys_set_tid_address (int *tid_addr) -__NR_restart_syscall 219 sys_restart_syscall (void) -__NR_sys_timer_create 222 sys_timer_create (clockid_t which_clock, struct sigevent *timer_event_spec, kernel_timer_t *created_timer_id) -__NR_sys_timer_settime 223 sys_timer_settime (kernel_timer_t timer_id, int flags, const struct itimerspec *new_setting, struct itimerspec *old_setting) -__NR_sys_timer_gettime 224 sys_timer_gettime (int timer_id, const struct itimerspec *setting) -__NR_sys_timer_getoverrun 225 sys_timer_getoverrun (int timer_id) -__NR_sys_timer_delete 226 sys_timer_delete (kernel_timer_t timer_id) -__NR_clock_gettime 228 sys_clock_gettime (const clockid_t which_clock, const struct timespec *tp) -__NR_exit_group 231 sys_exit_group (int error_code) -__NR_openat 257 sys_openat (int dfd, const char *filename, int flags, int mode) -__NR_waitid 247 sys_waitid (int which, pid_t pid, struct siginfo *infop, int options, struct rusage *ru) -__NR_readlinkat 267 sys_readlinkat (int fd, const char *path, char *buf, int bufsize) -__NR_set_robust_list 273 sys_set_robust_list (struct robust_list_head *head, size_t len) -__NR_get_robust_list 274 sys_get_robust_list (int pid, struct robust_list_head **head_ptr, size_t *len_ptr) -__NR_seccomp 317 sys_seccomp (unsigned int op, unsigned int flags, const char *uargs) -__NR_vmsplice 278 sys_vmsplice (int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags) -__NR_timerfd_settime 286 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) -__NR_signalfd4 289 sys_signalfd (int fd, k_rtsigset_t *mask, size_t sizemask, int flags) -__NR_rt_tgsigqueueinfo 297 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *info) -__NR_fanotify_init 300 sys_fanotify_init (unsigned int flags, unsigned int event_f_flags) -__NR_fanotify_mark 301 sys_fanotify_mark (int fanotify_fd, unsigned int flags, u64 mask, int dfd, const char *pathname) -__NR_open_by_handle_at 304 sys_open_by_handle_at (int mountdirfd, struct file_handle *handle, int flags) -__NR_setns 308 sys_setns (int fd, int nstype) -__NR_kcmp 312 sys_kcmp (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) -__NR_memfd_create 319 sys_memfd_create (const char *name, unsigned int flags) diff --git a/criu/crtools.c b/criu/crtools.c index 2be38425d..ef2e6f670 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -764,6 +764,7 @@ int main(int argc, char *argv[], char *envp[]) if (!strcmp(argv[optind], "check")) return cr_check() != 0; +#if 0 if (!strcmp(argv[optind], "exec")) { if (!pid) pid = tree_id; /* old usage */ @@ -771,6 +772,7 @@ int main(int argc, char *argv[], char *envp[]) goto opt_pid_missing; return cr_exec(pid, argv + optind + 1) != 0; } +#endif if (!strcmp(argv[optind], "page-server")) return cr_page_server(opts.daemon_mode, -1) != 0; diff --git a/criu/pie/Makefile b/criu/pie/Makefile index df3cd821f..040a68cd0 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -13,7 +13,7 @@ restorer-obj-y += restorer.o restorer-obj-y += ./$(ARCH_DIR)/restorer.o ifeq ($(ARCH),x86) - restorer-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o + restorer-obj-e += ./compel/plugins/std.built-in.o ifeq ($(CONFIG_COMPAT),y) restorer-obj-y += ./$(ARCH_DIR)/call32.o @@ -21,9 +21,9 @@ ifeq ($(ARCH),x86) endif native-obj-y += ./$(ARCH_DIR)/parasite-head-64.o - native-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o + native-obj-e += ./compel/plugins/std.built-in.o compat-obj-y += ./$(ARCH_DIR)/parasite-head-32.o - compat-obj-e += ./$(ARCH_DIR)/syscalls-32.built-in.o + compat-obj-e += ./compel/plugins/std-32.built-in.o AFLAGS_parasite-head-64.o += -fpie -DCONFIG_X86_64 AFLAGS_parasite-head-64.d += -fpie -DCONFIG_X86_64 @@ -32,8 +32,8 @@ ifeq ($(ARCH),x86) AFLAGS_parasite-head-32.d += -fno-pic -m32 -DCONFIG_X86_32 else native-obj-y += ./$(ARCH_DIR)/parasite-head.o - native-obj-e += ./$(ARCH_DIR)/syscalls.built-in.o - restorer-obj-e += ./$(ARCH_DIR)/syscalls.built-in.o + native-obj-e += ./compel/plugins/std.built-in.o + restorer-obj-e += ./compel/plugins/std.built-in.o endif target += $(parasite_target) restorer @@ -54,7 +54,8 @@ CFLAGS += -iquote $(SRC_DIR) CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 - +ccflags-y += -iquote $(SRC_DIR)/compel/plugins/include +ccflags-y += -iquote $(SRC_DIR)/compel/include ccflags-y += -DCR_NOGLIBC ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) NATIVE_CFLAGS := $(shell $(SRC_DIR)/compel/compel-host --arch=$(ARCH) cflags) diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index debd27d00..08ca0ee92 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -63,6 +63,8 @@ iquotes += -iquote $(SRC_DIR)/$(ARCH_DIR)/include iquotes += -iquote $(SRC_DIR) -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) $(iquotes) asflags-y := -D__ASSEMBLY__ $(iquotes) +ccflags-y += -iquote $(SRC_DIR)/compel/plugins/include +ccflags-y += -iquote $(SRC_DIR)/compel/include ifeq ($(SRCARCH),arm) ccflags-y += -marm diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index c1d7cf991..22b7ba25e 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -23,6 +23,11 @@ #include "asm/parasite.h" #include "restorer.h" +int compel_main(void *arg_p, unsigned int arg_s) +{ + return 0; +} + static int tsock = -1; static struct rt_sigframe *sigframe; diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index b8cc640bb..8c6eaeef2 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -61,6 +61,11 @@ static int n_helpers; static pid_t *zombies; static int n_zombies; +int compel_main(void *arg_p, unsigned int arg_s) +{ + return 0; +} + extern void cr_restore_rt (void) asm ("__cr_restore_rt") __attribute__ ((visibility ("hidden"))); From b204b1e39f06f3aa025234160c7cc4699d3492f0 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 28 Sep 2016 01:12:18 +0300 Subject: [PATCH 0116/4375] compel: criu -- Use sole syscalls object instead of std plugin @std plugin known to fail when trying to execute, investigating now. Meanwhile to not block tests lets use syscalls object file. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 040a68cd0..d92623650 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -13,7 +13,7 @@ restorer-obj-y += restorer.o restorer-obj-y += ./$(ARCH_DIR)/restorer.o ifeq ($(ARCH),x86) - restorer-obj-e += ./compel/plugins/std.built-in.o + restorer-obj-e += ./compel/arch/$(ARCH)/plugins/std/syscalls-64.o ifeq ($(CONFIG_COMPAT),y) restorer-obj-y += ./$(ARCH_DIR)/call32.o @@ -21,7 +21,7 @@ ifeq ($(ARCH),x86) endif native-obj-y += ./$(ARCH_DIR)/parasite-head-64.o - native-obj-e += ./compel/plugins/std.built-in.o + native-obj-e += ./compel/arch/$(ARCH)/plugins/std/syscalls-64.o compat-obj-y += ./$(ARCH_DIR)/parasite-head-32.o compat-obj-e += ./compel/plugins/std-32.built-in.o @@ -32,8 +32,8 @@ ifeq ($(ARCH),x86) AFLAGS_parasite-head-32.d += -fno-pic -m32 -DCONFIG_X86_32 else native-obj-y += ./$(ARCH_DIR)/parasite-head.o - native-obj-e += ./compel/plugins/std.built-in.o - restorer-obj-e += ./compel/plugins/std.built-in.o + native-obj-e += ./compel/arch/$(ARCH)/plugins/std/syscalls/syscalls.o + restorer-obj-e += ./compel/arch/$(ARCH)/plugins/std/syscalls/syscalls.o endif target += $(parasite_target) restorer From 84175119d100ad942ba1990c7d01b0d6a74988f7 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 28 Sep 2016 01:12:19 +0300 Subject: [PATCH 0117/4375] compel: travis -- Disable exec tests Not supported for a while. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index ac73981ad..75d15f5d6 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -54,7 +54,7 @@ bash ./test/jenkins/criu-fcg.sh bash ./test/jenkins/criu-inhfd.sh make -C test/others/mnt-ext-dev/ run -make -C test/others/exec/ run +#make -C test/others/exec/ run ./test/zdtm.py run -t zdtm/static/env00 --sibling From bc9cddbbac990359f43a807dae8ffd1c9ef9e61c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 27 Sep 2016 20:12:08 +0300 Subject: [PATCH 0118/4375] complel: plugins,std -- Don't forget to cleanup syscalls.S Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/arm/plugins/std/syscalls/Makefile.syscalls | 2 +- compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls b/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls index 453548120..6be8cacbd 100644 --- a/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls +++ b/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls @@ -53,7 +53,7 @@ $(sys-asm-types): $(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h $(Q) ln -s ../../../../../$(PLUGIN_ARCH_DIR)/std/syscalls/syscall-aux.S $(obj)/include/uapi/std/syscall-aux.S $(Q) ln -s ../../../../../$(PLUGIN_ARCH_DIR)/std/syscalls/syscall-aux.h $(obj)/include/uapi/std/syscall-aux.h -std-headers-deps += $(sys-codes) $(sys-proto) $(sys-asm-types) +std-headers-deps += $(sys-asm) $(sys-codes) $(sys-proto) $(sys-asm-types) mrproper-y += $(std-headers-deps) mrproper-y += $(obj)/include/uapi/std/syscall-aux.S mrproper-y += $(obj)/include/uapi/std/syscall-aux.h diff --git a/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls b/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls index a955c1556..65299cb1e 100644 --- a/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls +++ b/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls @@ -53,5 +53,5 @@ $(sys-asm-types): $(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h $(call msg-gen, $@) $(Q) ln -s ../../../../../../$(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h $(sys-asm-types) -std-headers-deps += $(sys-codes) $(sys-proto) $(sys-asm-types) +std-headers-deps += $(sys-asm) $(sys-codes) $(sys-proto) $(sys-asm-types) mrproper-y += $(std-headers-deps) From 2a43af12205200ba08cdf210c0f506ca97641ffa Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 27 Sep 2016 20:12:09 +0300 Subject: [PATCH 0119/4375] complel: plugins -- Disable coverage and mcount They are not supported in plugins. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 436e40724..09587d1e0 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -1,5 +1,6 @@ .PHONY: .FORCE +CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) PLUGIN_ARCH_DIR := compel/arch/$(ARCH)/plugins # From c1133055ec18289e98f73e4b3954a94bdd6117a7 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 7 Oct 2016 18:50:00 +0300 Subject: [PATCH 0120/4375] Add compel-host to .gitignore This is an addition to commit ed5b351. travis-ci: success for Add compel-host to .gitignore Cc: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4abbcaf7c..48ea4fb13 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ tags TAGS Makefile.local compel/compel +compel/compel-host images/*.c images/*.h images/google/protobuf/*.c From 219a99c74e4bd77f2d8481c3380e8c294cfe2e3e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 29 Sep 2016 00:34:00 +0300 Subject: [PATCH 0121/4375] compel: cli -- Add more flags into cflags report Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index ee6ccd53a..ca191c768 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -15,8 +15,14 @@ #include "version.h" #include "piegen.h" -static const char compel_cflags_pie[] = "-fpie -Wa,--noexecstack -fno-stack-protector"; -static const char compel_cflags_nopic[] = "-fno-pic -Wa,--noexecstack -fno-stack-protector"; +static const char compel_cflags_pie[] = + "-fpie -Wstrict-prototypes -Wa,--noexecstack " + "-fno-stack-protector -fno-jump-tables -nostdlib " + "-fomit-frame-pointer"; +static const char compel_cflags_nopic[] = + "-fno-pic -Wstrict-prototypes -Wa,--noexecstack " + "-fno-stack-protector -fno-jump-tables -nostdlib " + "-fomit-frame-pointer"; static const char compel_ldflags[] = "-r"; piegen_opt_t opts = { From 429da90376addb077d409276696578b0a506553b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 29 Sep 2016 00:34:00 +0300 Subject: [PATCH 0122/4375] compel: criu -- Use std plugin directly When compel build objects it provides ".compel.init" and ".compel.exit" setions for plugins init/exit routines and when we link PIE code in criu we simply zap them out but code still reference to them inside std text (even if we don't call them) so dont drop them. Eventually compel will be loading plugins by self but for now it's good for testing purpose to refernce the plugin inside criu code. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 8 ++++---- criu/pie/pie-reloc.lds.S.in | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index d92623650..040a68cd0 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -13,7 +13,7 @@ restorer-obj-y += restorer.o restorer-obj-y += ./$(ARCH_DIR)/restorer.o ifeq ($(ARCH),x86) - restorer-obj-e += ./compel/arch/$(ARCH)/plugins/std/syscalls-64.o + restorer-obj-e += ./compel/plugins/std.built-in.o ifeq ($(CONFIG_COMPAT),y) restorer-obj-y += ./$(ARCH_DIR)/call32.o @@ -21,7 +21,7 @@ ifeq ($(ARCH),x86) endif native-obj-y += ./$(ARCH_DIR)/parasite-head-64.o - native-obj-e += ./compel/arch/$(ARCH)/plugins/std/syscalls-64.o + native-obj-e += ./compel/plugins/std.built-in.o compat-obj-y += ./$(ARCH_DIR)/parasite-head-32.o compat-obj-e += ./compel/plugins/std-32.built-in.o @@ -32,8 +32,8 @@ ifeq ($(ARCH),x86) AFLAGS_parasite-head-32.d += -fno-pic -m32 -DCONFIG_X86_32 else native-obj-y += ./$(ARCH_DIR)/parasite-head.o - native-obj-e += ./compel/arch/$(ARCH)/plugins/std/syscalls/syscalls.o - restorer-obj-e += ./compel/arch/$(ARCH)/plugins/std/syscalls/syscalls.o + native-obj-e += ./compel/plugins/std.built-in.o + restorer-obj-e += ./compel/plugins/std.built-in.o endif target += $(parasite_target) restorer diff --git a/criu/pie/pie-reloc.lds.S.in b/criu/pie/pie-reloc.lds.S.in index c22a99e8f..2d0730cbd 100644 --- a/criu/pie/pie-reloc.lds.S.in +++ b/criu/pie/pie-reloc.lds.S.in @@ -3,6 +3,8 @@ SECTIONS .text : { *(.head.text) *(.text*) + *(.compel.init) + *(.compel.exit) } .data : { From 14881342087c8455f607e7c6b3c2424181530617 Mon Sep 17 00:00:00 2001 From: Laurent Dufour Date: Wed, 12 Oct 2016 19:39:00 +0300 Subject: [PATCH 0123/4375] compel: fix build break on ppc64le This patch fix a build break on ppc64le introduced by changes in the compel's build option. I factorized the common CFLAGS to make easier identifying particular flags required by some architectures. Fixes: fef01d79f7ee ("compel: cli -- Add more flags into cflags report") travis-ci: success for compel: fix build break on ppc64le Cc: Cyrill Gorcunov Signed-off-by: Laurent Dufour Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index ca191c768..f3d45e6a5 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -15,15 +15,15 @@ #include "version.h" #include "piegen.h" -static const char compel_cflags_pie[] = - "-fpie -Wstrict-prototypes -Wa,--noexecstack " - "-fno-stack-protector -fno-jump-tables -nostdlib " - "-fomit-frame-pointer"; -static const char compel_cflags_nopic[] = - "-fno-pic -Wstrict-prototypes -Wa,--noexecstack " - "-fno-stack-protector -fno-jump-tables -nostdlib " - "-fomit-frame-pointer"; -static const char compel_ldflags[] = "-r"; +#define CFLAGS_DEFAULT_SET \ + "-Wstrict-prototypes -Wa,--noexecstack " \ + "-fno-stack-protector -nostdlib -fomit-frame-pointer " + +#define COMPEL_CFLAGS_PIE CFLAGS_DEFAULT_SET "-fpie -fno-jump-tables" +#define COMPEL_CFLAGS_PIE_JPT CFLAGS_DEFAULT_SET "-fpie" +#define COMPEL_CFLAGS_NOPIC CFLAGS_DEFAULT_SET "-fno-pic -fno-jump-tables" + +#define COMPEL_LDFLAGS_DEFAULT "-r" piegen_opt_t opts = { .input_filename = NULL, @@ -99,19 +99,19 @@ int main(int argc, char *argv[]) static const compel_cflags_t compel_cflags[] = { { .arch = "x86", - .cflags = compel_cflags_pie, + .cflags = COMPEL_CFLAGS_PIE, }, { .arch = "ia32", - .cflags = compel_cflags_nopic, + .cflags = COMPEL_CFLAGS_NOPIC, }, { .arch = "aarch64", - .cflags = compel_cflags_pie, + .cflags = COMPEL_CFLAGS_PIE, }, { .arch = "arm", - .cflags = compel_cflags_pie, + .cflags = COMPEL_CFLAGS_PIE, }, { .arch = "ppc64", - .cflags = compel_cflags_pie, + .cflags = COMPEL_CFLAGS_PIE_JPT, }, }; @@ -190,7 +190,7 @@ int main(int argc, char *argv[]) } if (!strcmp(action, "ldflags")) { - printf("%s", compel_ldflags); + printf("%s", COMPEL_LDFLAGS_DEFAULT); return 0; } From 4442b7546f6c388046def2ef2d55064a16801da5 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 11 Oct 2016 18:46:40 -0700 Subject: [PATCH 0124/4375] criu/parasite-syscall.c: init a var Got the following from clang: > CC criu/parasite-syscall.o > criu/parasite-syscall.c:1494:6: error: variable 'parasite_size' is used > uninitialized whenever 'if' condition is false > [-Werror,-Wsometimes-uninitialized] > if (seized_native(ctl)) > ^~~~~~~~~~~~~~~~~~ > criu/parasite-syscall.c:1503:2: note: uninitialized use occurs here > parasite_size += ctl->args_size; > ^~~~~~~~~~~~~ > criu/parasite-syscall.c:1494:2: note: remove the 'if' if its condition > is always true > if (seized_native(ctl)) > ^~~~~~~~~~~~~~~~~~~~~~~ I look at the code and I'm still not quite sure whether parasite_size can end up being uninitialized. Looks like for CONFIG_X86_64 it can. So, let's initialize it. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/parasite-syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 8fbfa34d5..cdd4e7f2f 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -1461,7 +1461,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, { int ret; struct parasite_ctl *ctl; - unsigned long p, map_exchange_size, parasite_size; + unsigned long p, map_exchange_size, parasite_size = 0; BUG_ON(item->threads[0].real != pid); From b6c43007238247b35341f3bea3cc9eb7c52c07aa Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 11 Oct 2016 18:46:42 -0700 Subject: [PATCH 0125/4375] pie: Fix deps for own memcpy for x86 Cc: Laurent Dufour Cc: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Acked-by: Laurent Dufour Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/Makefile.library | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 08ca0ee92..3b5380194 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -13,6 +13,7 @@ ifeq ($(ARCH),x86) CFLAGS_native += -DCONFIG_X86_64 CFLAGS_compat += -fno-pic -m32 -DCONFIG_X86_32 CFLAGS_util-vdso-elf32.o += -DCONFIG_X86_32 + OBJS += ./$(ARCH_DIR)/memcpy.o endif OBJS += log-simple.o util-fd.o util.o string.o @@ -34,10 +35,6 @@ ifeq ($(SRCARCH),ppc64) ./$(ARCH_DIR)/memcmp_64.o ./$(ARCH_DIR)/misc.o endif -ifeq ($(SRCARCH),x86) - lib-y += ./$(ARCH_DIR)/memcpy.o -endif - define gen-native-objs native-lib-y += $(1) CFLAGS_$(1) := $(CFLAGS_native) From 1fe09eb358cbe21a5859ed63fe13fdd2b3dab0ae Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 12 Oct 2016 04:46:00 +0300 Subject: [PATCH 0126/4375] Makefiles: move -Wa,--noexecstack out of CFLAGS The problem is, -Wa is a flag for assembler, but CFLAGS are also used to generate dependencies, and clang complains loudly when it is used for deps: > > DEP compel/arch/x86/plugins/std/syscalls-64.d > > clang-3.8: error: argument unused during compilation: > > '-Wa,--noexecstack' This patch moved the noexecflag from assembler to linker. I am not 100% sure but the end result seems to be the same. This fixes dependency generation when using clang instead of gcc. I surely have done my research before proposing this change, and I have tested this change as good as I could. Sorry, I should have provided more background in the commit message. Here it goes. There are a few ways to have non-executable stack: 1. mark the assembler source file (.S) with .section .note.GNU-stack,"",%progbits 2. pass the -Wa,--noexecstack to compiler 3. pass the -z execstack to linker All three ways are fine, let's see them in greater details. Some people say (1) is the best way, but we have way too many .S files now (23 of them, to be exact). Anyway, I can certainly do it this way if you like, just let me know. It would look like this: --- a/compel/arch/aarch64/plugins/std/syscalls/syscall-aux.S +++ b/compel/arch/aarch64/plugins/std/syscalls/syscall-aux.S @@ -3,6 +3,8 @@ * that are not implemented in the AArch64 Linux kernel */ +.section .note.GNU-stack,"",%progbits + ENTRY(sys_open) mov x3, x2 mov x2, x1 Way (2) is what is currently used. Unfortunately it breaks dependency generation with clang. One way to fix it would be to filter-out the bad flag when we're generating deps. I tried experimenting with $(filter-out) function in Makefiles today but it's complicated and I failed to make it work. Way (3) is what this commit offers. It seem to work fine while being the least intrusive. Signed-off-by: Kir Kolyshkin Reviewed-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/Makefile | 3 ++- criu/pie/Makefile.library | 3 ++- lib/c/Makefile | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 09587d1e0..ac54f7c2e 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -22,9 +22,10 @@ asflags-y += -iquote $(PLUGIN_ARCH_DIR)/include asflags-y += -iquote $(PLUGIN_ARCH_DIR) # General flags for assembly -asflags-y += -fpie -Wstrict-prototypes -Wa,--noexecstack +asflags-y += -fpie -Wstrict-prototypes asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer asflags-y += -fno-stack-protector +ldflags-y += -z noexecstack # # Fds plugin diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 3b5380194..1b408d14c 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -1,7 +1,8 @@ target := native CFLAGS := $(filter-out -DCONFIG_X86_64,$(CFLAGS)) -CFLAGS += -Wa,--noexecstack -fno-stack-protector -DCR_NOGLIBC +CFLAGS += -fno-stack-protector -DCR_NOGLIBC +LDFLAGS += -z noexecstack CFLAGS_native += -fpie diff --git a/lib/c/Makefile b/lib/c/Makefile index 21bf85614..68cf2b9ce 100644 --- a/lib/c/Makefile +++ b/lib/c/Makefile @@ -4,4 +4,5 @@ obj-y += $(SRC_DIR)/images/rpc.pb-c.o ccflags-y += -iquote $(SRC_DIR)/criu/$(ARCH_DIR)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(obj)/.. ccflags-y += -iquote $(SRC_DIR)/images -ccflags-y += -fPIC -Wa,--noexecstack -fno-stack-protector +ccflags-y += -fPIC -fno-stack-protector +ldflags-y += -z noexecstack From 8c39a00037241a7191abaa177a215d39e3981fbe Mon Sep 17 00:00:00 2001 From: Tycho Andersen Date: Tue, 18 Oct 2016 21:53:05 +0000 Subject: [PATCH 0127/4375] gitignores: ignore some more generated files Signed-off-by: Tycho Andersen Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/.gitignore | 8 ++++++++ test/.gitignore | 1 + 2 files changed, 9 insertions(+) create mode 100644 compel/.gitignore diff --git a/compel/.gitignore b/compel/.gitignore new file mode 100644 index 000000000..c254402c3 --- /dev/null +++ b/compel/.gitignore @@ -0,0 +1,8 @@ +arch/x86/plugins/std/sys-exec-tbl-64.c +arch/x86/plugins/std/syscalls-64.S +include/version.h +plugins/include/uapi/std/asm/syscall-types.h +plugins/include/uapi/std/syscall-64.h +plugins/include/uapi/std/syscall-codes-64.h +plugins/include/uapi/std/syscall-codes.h +plugins/include/uapi/std/syscall.h diff --git a/test/.gitignore b/test/.gitignore index 7d3d4232b..6a735ba7a 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -13,3 +13,4 @@ /stats-restore /zdtm_mount_cgroups.lock /compel/handle_binary +/umount2 From efc87fce326a91f9de0ede4b8d2d4327ee1c5556 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 19 Oct 2016 22:21:00 +0300 Subject: [PATCH 0128/4375] compel: cli -- Show own version with option Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/compel/src/main.c b/compel/src/main.c index f3d45e6a5..6417dcf2a 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -115,7 +115,7 @@ int main(int argc, char *argv[]) }, }; - static const char short_opts[] = "a:f:o:s:p:v:r:u:h"; + static const char short_opts[] = "a:f:o:s:p:v:r:u:hV"; static struct option long_opts[] = { { "arch", required_argument, 0, 'a' }, { "file", required_argument, 0, 'f' }, @@ -126,6 +126,7 @@ int main(int argc, char *argv[]) { "variable", required_argument, 0, 'v' }, { "pcrelocs", required_argument, 0, 'r' }, { "help", required_argument, 0, 'h' }, + { "version", no_argument, 0, 'V' }, { }, }; @@ -172,6 +173,13 @@ int main(int argc, char *argv[]) break; case 'h': goto usage; + case 'V': + printf("Version: %d.%d.%d\n", + COMPEL_SO_VERSION_MAJOR, + COMPEL_SO_VERSION_MINOR, + COMPEL_SO_VERSION_SUBLEVEL); + exit(0); + break; default: break; } From 04ae288af36dd2dbb2dfb4623a7c6564860c568d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 20 Oct 2016 15:31:00 +0300 Subject: [PATCH 0129/4375] x86, tls: read no more than saved TLS entries While writing this, I somehow managed to miss the check of how many entries were saved in core image. So it may dereference here bs. Fixes: #228 Fixes: commit 6fde3b8c27db ("x86: restore TLS") travis-ci: success for x86, tls: read no more than saved TLS entries Cc: Andrei Vagin Cc: Cyrill Gorcunov Reported-by: Andrei Vagin Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/include/asm/restore.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/criu/arch/x86/include/asm/restore.h b/criu/arch/x86/include/asm/restore.h index c5aa7cdeb..7959e686b 100644 --- a/criu/arch/x86/include/asm/restore.h +++ b/criu/arch/x86/include/asm/restore.h @@ -31,12 +31,22 @@ static inline void core_get_tls(CoreEntry *pcore, tls_t *ptls) { ThreadInfoX86 *ti = pcore->thread_info; - int i; + size_t i; for (i = 0; i < GDT_ENTRY_TLS_NUM; i++) { user_desc_t *to = &ptls->desc[i]; - UserDescT *from = ti->tls[i]; + UserDescT *from; + /* + * If proto image has lesser TLS entries, + * mark them as not present (and thus skip restore). + */ + if (i >= ti->n_tls) { + to->seg_not_present = 1; + continue; + } + + from = ti->tls[i]; #define COPY_TLS(field) to->field = from->field COPY_TLS(entry_number); COPY_TLS(base_addr); From d2a1aa1b6b450e4c37d0150415a61e7a5950b79a Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 20 Oct 2016 20:02:26 -0700 Subject: [PATCH 0130/4375] compel: mv noexecstack from CFLAGS to LDFLAGS In a manner similar to one of commit 9303ed3 ("Makefiles: move -Wa,--noexecstack out of CFLAGS"), let's move this option to linker flags (see the abovementioned commit for reasoning). travis-ci: success for series starting with [1/3] compel: mv noexecstack from CFLAGS to LDFLAGS Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index 6417dcf2a..a30321bd4 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -16,14 +16,14 @@ #include "piegen.h" #define CFLAGS_DEFAULT_SET \ - "-Wstrict-prototypes -Wa,--noexecstack " \ + "-Wstrict-prototypes " \ "-fno-stack-protector -nostdlib -fomit-frame-pointer " #define COMPEL_CFLAGS_PIE CFLAGS_DEFAULT_SET "-fpie -fno-jump-tables" #define COMPEL_CFLAGS_PIE_JPT CFLAGS_DEFAULT_SET "-fpie" #define COMPEL_CFLAGS_NOPIC CFLAGS_DEFAULT_SET "-fno-pic -fno-jump-tables" -#define COMPEL_LDFLAGS_DEFAULT "-r" +#define COMPEL_LDFLAGS_DEFAULT "-r -z noexecstack" piegen_opt_t opts = { .input_filename = NULL, From 3da152a5ab612c740e1dbb965bc0fd9d82a60465 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 20 Oct 2016 20:02:27 -0700 Subject: [PATCH 0131/4375] compel: rm -fno-jump-tables from CFLAGS Three reasons: 1. this flag doesn't work for ppc64 (see commit dc7b08b); 2. clang is not aware of this flag; 3. all seems to work just fine without it. Cc: Laurent Dufour Cc: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index a30321bd4..625ae1188 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -19,9 +19,8 @@ "-Wstrict-prototypes " \ "-fno-stack-protector -nostdlib -fomit-frame-pointer " -#define COMPEL_CFLAGS_PIE CFLAGS_DEFAULT_SET "-fpie -fno-jump-tables" -#define COMPEL_CFLAGS_PIE_JPT CFLAGS_DEFAULT_SET "-fpie" -#define COMPEL_CFLAGS_NOPIC CFLAGS_DEFAULT_SET "-fno-pic -fno-jump-tables" +#define COMPEL_CFLAGS_PIE CFLAGS_DEFAULT_SET "-fpie" +#define COMPEL_CFLAGS_NOPIC CFLAGS_DEFAULT_SET "-fno-pic" #define COMPEL_LDFLAGS_DEFAULT "-r -z noexecstack" @@ -111,7 +110,7 @@ int main(int argc, char *argv[]) .cflags = COMPEL_CFLAGS_PIE, }, { .arch = "ppc64", - .cflags = COMPEL_CFLAGS_PIE_JPT, + .cflags = COMPEL_CFLAGS_PIE, }, }; From 084b0fb0ecbae7b0dbf73f2322e7d3a7597b1bcd Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 25 Oct 2016 22:08:31 -0700 Subject: [PATCH 0132/4375] compel/handle-elf.c: handle R_PPC64_REL32 When compiled with clang-3.8 on ppc, compel complains: > GEN criu/pie/parasite-native-blob.h > parasite_native_blob: Error (compel/src/lib/handle-elf-host.c:541): > Unsupported relocation of type 26 Look into R_PPC64_REL64/R_PPC64_ADDR64 and handle 32-bit the same way. travis-ci: success for PPC+clang compile fixes Cc: Laurent Dufour Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/lib/handle-elf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index 32759fe0f..c6b7874cc 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -415,6 +415,7 @@ int __handle_elf(void *mem, size_t size) break; case R_PPC64_ADDR32: + case R_PPC64_REL32: pr_debug("\t\t\tR_PPC64_ADDR32 at 0x%-4lx val 0x%x\n", place, (unsigned int)(value32 + addend32)); pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_INT, " From 44c15c6cd92d9d8add7f00653c66ebf444d267b6 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 30 Oct 2016 10:36:50 +0300 Subject: [PATCH 0133/4375] x86: Mark arch_task_compatible static travis-ci: success for Don't get task regs twice Signed-off-by: Pavel Emelyanov Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index d2660e4b4..b962a3ef1 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -96,7 +96,7 @@ int kdat_compat_sigreturn_test(void) #endif /* CONFIG_X86_64 */ int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs); -int arch_task_compatible(pid_t pid) +static int arch_task_compatible(pid_t pid) { user_regs_struct_t r; int ret = ptrace_get_regs(pid, &r); From da17b223f1e13747ed3305870d22105ef52933ae Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 30 Oct 2016 10:37:29 +0300 Subject: [PATCH 0134/4375] parasite: Do not get task regs twice on start First time regs are saved on ctl->orig.regs in parasite_prep_ctl, the 2nd time regs are got inside x86/arch_task_compatible, while it can use the on-ctl copy. travis-ci: success for Don't get task regs twice Signed-off-by: Pavel Emelyanov Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index b962a3ef1..dc3c93b89 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -95,16 +95,9 @@ int kdat_compat_sigreturn_test(void) } #endif /* CONFIG_X86_64 */ -int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs); -static int arch_task_compatible(pid_t pid) +static int arch_task_compatible(struct parasite_ctl *ctl) { - user_regs_struct_t r; - int ret = ptrace_get_regs(pid, &r); - - if (ret) - return -1; - - return !user_regs_native(&r); + return !user_regs_native(&ctl->orig.regs); } #define USER32_CS 0x23 @@ -133,7 +126,7 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) pid_t pid = ctl->rpid; int ret; - ret = arch_task_compatible(pid); + ret = arch_task_compatible(ctl); if (ret < 0) return false; From 976e13a193c8409d92d6c3bbdc5581f4d0fe36fd Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 26 Sep 2016 13:19:41 +0300 Subject: [PATCH 0135/4375] arch: Turn save_task_regs into pointer The get_task_regs() call now accepts a pointer on a function that is to keep obtained registers somwehere. In CRIU case this "somewhere" is CoreEntry, for generic compel user we'll need to add simple memcpy()-s to the library itself. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/crtools.c | 12 +++++------- criu/arch/aarch64/include/asm/dump.h | 4 +++- criu/arch/arm/crtools.c | 13 ++++++------- criu/arch/arm/include/asm/dump.h | 4 +++- criu/arch/ppc64/crtools.c | 9 +++++++-- criu/arch/ppc64/include/asm/dump.h | 4 +++- criu/arch/x86/crtools.c | 13 ++++++------- criu/arch/x86/include/asm/dump.h | 4 +++- criu/parasite-syscall.c | 4 ++-- 9 files changed, 38 insertions(+), 29 deletions(-) diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index 0e8a9bd7c..5510da19a 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -8,6 +8,7 @@ #include "common/compiler.h" #include "ptrace.h" #include "asm/processor-flags.h" +#include "asm/dump.h" #include "protobuf.h" #include "images/core.pb-c.h" #include "images/creds.pb-c.h" @@ -77,12 +78,9 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, return err; } -static int save_task_regs(CoreEntry *core, - user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd); - #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))(src)->e -int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) +int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) { struct iovec iov; user_fpregs_struct_t fpsimd; @@ -104,15 +102,15 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) goto err; } - ret = save_task_regs(core, ®s, &fpsimd); + ret = save(arg, ®s, &fpsimd); err: return ret; } -static int save_task_regs(CoreEntry *core, - user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd) +int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd) { int i; + CoreEntry *core = x; // Save the Aarch64 CPU state for (i = 0; i < 31; ++i) diff --git a/criu/arch/aarch64/include/asm/dump.h b/criu/arch/aarch64/include/asm/dump.h index 671c424da..c53f67c3d 100644 --- a/criu/arch/aarch64/include/asm/dump.h +++ b/criu/arch/aarch64/include/asm/dump.h @@ -1,7 +1,9 @@ #ifndef __CR_ASM_DUMP_H__ #define __CR_ASM_DUMP_H__ -extern int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core); +typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); +extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *); +extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *); extern int arch_alloc_thread_info(CoreEntry *core); extern void arch_free_thread_info(CoreEntry *core); diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index edf2bad95..73a82b46a 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -4,6 +4,7 @@ #include "types.h" #include "asm/restorer.h" #include "common/compiler.h" +#include "asm/dump.h" #include "ptrace.h" #include "asm/processor-flags.h" #include "protobuf.h" @@ -79,13 +80,10 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, return err; } -static int save_task_regs(CoreEntry *core, - user_regs_struct_t *regs, user_fpregs_struct_t *fpregs); - #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))((src)->ARM_##e) #define PTRACE_GETVFPREGS 27 -int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) +int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) { user_fpregs_struct_t vfp; int ret = -1; @@ -114,14 +112,15 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) } } - ret = save_task_regs(core, ®s, &vfp); + ret = save(arg, ®s, &vfp); err: return ret; } -static int save_task_regs(CoreEntry *core, - user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) +int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) { + CoreEntry *core = x; + // Save the ARM CPU state assign_reg(core->ti_arm->gpregs, regs, r0); diff --git a/criu/arch/arm/include/asm/dump.h b/criu/arch/arm/include/asm/dump.h index ae1588da8..fa83b8267 100644 --- a/criu/arch/arm/include/asm/dump.h +++ b/criu/arch/arm/include/asm/dump.h @@ -1,7 +1,9 @@ #ifndef __CR_ASM_DUMP_H__ #define __CR_ASM_DUMP_H__ -extern int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core); +typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); +extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *); +extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *); extern int arch_alloc_thread_info(CoreEntry *core); extern void arch_free_thread_info(CoreEntry *core); diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index 3914bfda0..9e98190e0 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -8,6 +8,7 @@ #include "types.h" #include "asm/fpu.h" #include "asm/restorer.h" +#include "asm/dump.h" #include "cr_options.h" #include "common/compiler.h" @@ -692,9 +693,13 @@ static int __copy_task_regs(user_regs_struct_t *regs, return 0; } +int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f) +{ + return __copy_task_regs(u, f, (CoreEntry *)arg); +} /****************************************************************************/ -int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) +int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) { user_fpregs_struct_t fpregs; int ret; @@ -703,7 +708,7 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) if (ret) return ret; - return __copy_task_regs(®s, &fpregs, core); + return save(arg, ®s, &fpregs); } int arch_alloc_thread_info(CoreEntry *core) diff --git a/criu/arch/ppc64/include/asm/dump.h b/criu/arch/ppc64/include/asm/dump.h index 1505fd298..0c88b7a56 100644 --- a/criu/arch/ppc64/include/asm/dump.h +++ b/criu/arch/ppc64/include/asm/dump.h @@ -1,7 +1,9 @@ #ifndef __CR_ASM_DUMP_H__ #define __CR_ASM_DUMP_H__ -extern int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core); +typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); +extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *); +extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *); extern int arch_alloc_thread_info(CoreEntry *core); extern void arch_free_thread_info(CoreEntry *core); diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index dc3c93b89..a66a8c650 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -11,6 +11,7 @@ #include "asm/parasite-syscall.h" #include "asm/restorer.h" #include "asm/fpu.h" +#include "asm/dump.h" #include "cr_options.h" #include "common/compiler.h" @@ -184,13 +185,11 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, return err; } -static int save_task_regs(CoreEntry *core, - user_regs_struct_t *regs, user_fpregs_struct_t *fpregs); - #define get_signed_user_reg(pregs, name) \ ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \ (int32_t)((pregs)->compat.name)) -int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) + +int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) { user_fpregs_struct_t xsave = { }, *xs = NULL; @@ -248,14 +247,14 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) xs = &xsave; out: - ret = save_task_regs(core, ®s, xs); + ret = save(arg, ®s, xs); err: return ret; } -static int save_task_regs(CoreEntry *core, - user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) +int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) { + CoreEntry *core = x; UserX86RegsEntry *gpregs = core->thread_info->gpregs; #define assign_reg(dst, src, e) do { dst->e = (__typeof__(dst->e))src.e; } while (0) diff --git a/criu/arch/x86/include/asm/dump.h b/criu/arch/x86/include/asm/dump.h index 9c3555236..4b928a8de 100644 --- a/criu/arch/x86/include/asm/dump.h +++ b/criu/arch/x86/include/asm/dump.h @@ -1,7 +1,9 @@ #ifndef __CR_ASM_DUMP_H__ #define __CR_ASM_DUMP_H__ -extern int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core); +typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); +extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *); +extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *); extern int arch_alloc_thread_info(CoreEntry *core); extern void arch_free_thread_info(CoreEntry *core); diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index cdd4e7f2f..f0765fbd8 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -667,7 +667,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, return -1; } - ret = get_task_regs(pid, octx.regs, core); + ret = get_task_regs(pid, octx.regs, save_task_regs, core); if (ret) { pr_err("Can't obtain regs for thread %d\n", pid); return -1; @@ -1427,7 +1427,7 @@ static int parasite_start_daemon(struct parasite_ctl *ctl, struct pstree_item *i * while in daemon it is not such. */ - if (get_task_regs(pid, ctl->orig.regs, item->core[0])) { + if (get_task_regs(pid, ctl->orig.regs, save_task_regs, item->core[0])) { pr_err("Can't obtain regs for thread %d\n", pid); return -1; } From 6e49bce78049f06167d4f16489ee3fe19e71acae Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 27 Sep 2016 20:04:14 +0300 Subject: [PATCH 0136/4375] seize: Split proc_status_creds into pieces There's a subset of this structure is required by seize_catch_task(), which in turn will go to compel library. So prepare for that. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 8 ++++---- criu/cr-exec.c | 2 +- criu/include/proc_parse.h | 9 +++------ criu/include/ptrace.h | 12 ++++++++++-- criu/proc_parse.c | 14 +++++++------- criu/ptrace.c | 14 +++++++------- criu/seccomp.c | 2 +- criu/seize.c | 12 ++++++------ 8 files changed, 39 insertions(+), 34 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 3da66d33e..8d7989c77 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -729,12 +729,12 @@ static int dump_task_core_all(struct parasite_ctl *ctl, goto err; creds = dmpi(item)->pi_creds; - if (creds->seccomp_mode != SECCOMP_MODE_DISABLED) { - pr_info("got seccomp mode %d for %d\n", creds->seccomp_mode, vpid(item)); + if (creds->s.seccomp_mode != SECCOMP_MODE_DISABLED) { + pr_info("got seccomp mode %d for %d\n", creds->s.seccomp_mode, vpid(item)); core->tc->has_seccomp_mode = true; - core->tc->seccomp_mode = creds->seccomp_mode; + core->tc->seccomp_mode = creds->s.seccomp_mode; - if (creds->seccomp_mode == SECCOMP_MODE_FILTER) { + if (creds->s.seccomp_mode == SECCOMP_MODE_FILTER) { core->tc->has_seccomp_filter = true; core->tc->seccomp_filter = creds->last_filter; } diff --git a/criu/cr-exec.c b/criu/cr-exec.c index 356e206d5..99ab10130 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -4,7 +4,7 @@ #include "int.h" #include "types.h" #include "crtools.h" -#include "ptrace.h" +#include "proc_parse.h" #include "pstree.h" #include "parasite-syscall.h" #include "vma.h" diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h index d1eed10ea..ce444e5d9 100644 --- a/criu/include/proc_parse.h +++ b/criu/include/proc_parse.h @@ -3,6 +3,7 @@ #include +#include "ptrace.h" #include "images/seccomp.pb-c.h" #define PROC_TASK_COMM_LEN 32 @@ -72,15 +73,11 @@ struct seccomp_info { #define PROC_CAP_SIZE 2 struct proc_status_creds { + struct seize_task_status s; + unsigned int uids[4]; unsigned int gids[4]; - char state; - int ppid; - unsigned long long sigpnd; - unsigned long long shdpnd; - - int seccomp_mode; u32 last_filter; /* diff --git a/criu/include/ptrace.h b/criu/include/ptrace.h index 748c6a64f..38ea5e85d 100644 --- a/criu/include/ptrace.h +++ b/criu/include/ptrace.h @@ -4,8 +4,6 @@ #include #include -#include "proc_parse.h" - /* some constants for ptrace */ #ifndef PTRACE_SEIZE # define PTRACE_SEIZE 0x4206 @@ -64,6 +62,16 @@ #define SI_EVENT(_si_code) (((_si_code) & 0xFFFF) >> 8) +struct seize_task_status { + char state; + int ppid; + unsigned long long sigpnd; + unsigned long long shdpnd; + int seccomp_mode; +}; + +struct proc_status_creds; + extern int seize_catch_task(pid_t pid); extern int seize_wait_task(pid_t pid, pid_t ppid, struct proc_status_creds *creds); extern int suspend_seccomp(pid_t pid); diff --git a/criu/proc_parse.c b/criu/proc_parse.c index f69e7d038..771e75ac7 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -993,8 +993,8 @@ int parse_pid_status(pid_t pid, struct proc_status_creds *cr) if (f.fd < 0) return -1; - cr->sigpnd = 0; - cr->shdpnd = 0; + cr->s.sigpnd = 0; + cr->s.shdpnd = 0; if (bfdopenr(&f)) return -1; @@ -1007,13 +1007,13 @@ int parse_pid_status(pid_t pid, struct proc_status_creds *cr) goto err_parse; if (!strncmp(str, "State:", 6)) { - cr->state = str[7]; + cr->s.state = str[7]; done++; continue; } if (!strncmp(str, "PPid:", 5)) { - if (sscanf(str, "PPid:\t%d", &cr->ppid) != 1) { + if (sscanf(str, "PPid:\t%d", &cr->s.ppid) != 1) { pr_err("Unable to parse: %s\n", str); goto err_parse; } @@ -1070,7 +1070,7 @@ int parse_pid_status(pid_t pid, struct proc_status_creds *cr) } if (!strncmp(str, "Seccomp:", 8)) { - if (sscanf(str + 9, "%d", &cr->seccomp_mode) != 1) { + if (sscanf(str + 9, "%d", &cr->s.seccomp_mode) != 1) { goto err_parse; } @@ -1084,7 +1084,7 @@ int parse_pid_status(pid_t pid, struct proc_status_creds *cr) if (sscanf(str + 7, "%llx", &sigpnd) != 1) goto err_parse; - cr->shdpnd |= sigpnd; + cr->s.shdpnd |= sigpnd; done++; continue; @@ -1094,7 +1094,7 @@ int parse_pid_status(pid_t pid, struct proc_status_creds *cr) if (sscanf(str + 7, "%llx", &sigpnd) != 1) goto err_parse; - cr->sigpnd |= sigpnd; + cr->s.sigpnd |= sigpnd; done++; continue; diff --git a/criu/ptrace.c b/criu/ptrace.c index 09f7cd9ea..4dd774c63 100644 --- a/criu/ptrace.c +++ b/criu/ptrace.c @@ -180,12 +180,12 @@ try_again: goto err; if (ret < 0 || WIFEXITED(status) || WIFSIGNALED(status)) { - if (creds->state != 'Z') { + if (creds->s.state != 'Z') { if (pid == getpid()) pr_err("The criu itself is within dumped tree.\n"); else pr_err("Unseizable non-zombie %d found, state %c, err %d/%d\n", - pid, creds->state, ret, wait_errno); + pid, creds->s.state, ret, wait_errno); return -1; } @@ -195,9 +195,9 @@ try_again: return TASK_DEAD; } - if ((ppid != -1) && (creds->ppid != ppid)) { + if ((ppid != -1) && (creds->s.ppid != ppid)) { pr_err("Task pid reused while suspending (%d: %d -> %d)\n", - pid, ppid, creds->ppid); + pid, ppid, creds->s.ppid); goto err; } @@ -229,13 +229,13 @@ try_again: goto try_again; } - if (creds->seccomp_mode != SECCOMP_MODE_DISABLED && suspend_seccomp(pid) < 0) + if (creds->s.seccomp_mode != SECCOMP_MODE_DISABLED && suspend_seccomp(pid) < 0) goto err; nr_sigstop = 0; - if (creds->sigpnd & (1 << (SIGSTOP - 1))) + if (creds->s.sigpnd & (1 << (SIGSTOP - 1))) nr_sigstop++; - if (creds->shdpnd & (1 << (SIGSTOP - 1))) + if (creds->s.shdpnd & (1 << (SIGSTOP - 1))) nr_sigstop++; if (si.si_signo == SIGSTOP) nr_sigstop++; diff --git a/criu/seccomp.c b/criu/seccomp.c index d906dc057..15bd69fe9 100644 --- a/criu/seccomp.c +++ b/criu/seccomp.c @@ -50,7 +50,7 @@ static int collect_filter_for_pstree(struct pstree_item *item) void *m; if (item->pid->state == TASK_DEAD || - dmpi(item)->pi_creds->seccomp_mode != SECCOMP_MODE_FILTER) + dmpi(item)->pi_creds->s.seccomp_mode != SECCOMP_MODE_FILTER) return 0; for (i = 0; true; i++) { diff --git a/criu/seize.c b/criu/seize.c index 40381c72e..bd41a8842 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -15,7 +15,7 @@ #include "cr-errno.h" #include "pstree.h" #include "criu-log.h" -#include "ptrace.h" +#include "proc_parse.h" #include "seize.h" #include "stats.h" #include "xmalloc.h" @@ -660,11 +660,11 @@ static bool creds_dumpable(struct proc_status_creds *parent, parent->gids[1], child->gids[1], parent->gids[2], child->gids[2], parent->gids[3], child->gids[3], - parent->state, child->state, - parent->ppid, child->ppid, - parent->sigpnd, child->sigpnd, - parent->shdpnd, child->shdpnd, - parent->seccomp_mode, child->seccomp_mode, + parent->s.state, child->s.state, + parent->s.ppid, child->s.ppid, + parent->s.sigpnd, child->s.sigpnd, + parent->s.shdpnd, child->s.shdpnd, + parent->s.seccomp_mode, child->s.seccomp_mode, parent->last_filter, child->last_filter); } return false; From 903be4131d9df4a00dd9d35fd1ccaff05b896523 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 27 Sep 2016 20:07:32 +0300 Subject: [PATCH 0137/4375] seize: Make seize_wait_task() parse task status via callback When seizeing task we need to parse /proc/pid/status for its state, parent, signals and seccomp status. In criu case we also parse other stuff in one go, so make this parsing be a callback which criu will provide. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-exec.c | 2 +- criu/include/proc_parse.h | 2 +- criu/include/ptrace.h | 6 +++--- criu/proc_parse.c | 3 ++- criu/ptrace.c | 20 +++++++++++--------- criu/seize.c | 6 +++--- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/criu/cr-exec.c b/criu/cr-exec.c index 99ab10130..9941cc038 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -143,7 +143,7 @@ int cr_exec(int pid, char **opt) * mess with creds in this use case anyway. */ - prev_state = ret = seize_wait_task(pid, -1, &creds); + prev_state = ret = seize_wait_task(pid, -1, parse_pid_status, &creds.s); if (ret < 0) { pr_err("Can't seize task %d\n", pid); goto out; diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h index ce444e5d9..d5fbaf7a0 100644 --- a/criu/include/proc_parse.h +++ b/criu/include/proc_parse.h @@ -96,7 +96,7 @@ extern int parse_pid_stat(pid_t pid, struct proc_pid_stat *s); extern unsigned int parse_pid_loginuid(pid_t pid, int *err, bool ignore_noent); extern int parse_pid_oom_score_adj(pid_t pid, int *err); extern int prepare_loginuid(unsigned int value, unsigned int loglevel); -extern int parse_pid_status(pid_t pid, struct proc_status_creds *); +extern int parse_pid_status(pid_t pid, struct seize_task_status *); extern int parse_file_locks(void); extern int get_fd_mntid(int fd, int *mnt_id); diff --git a/criu/include/ptrace.h b/criu/include/ptrace.h index 38ea5e85d..2b45c2311 100644 --- a/criu/include/ptrace.h +++ b/criu/include/ptrace.h @@ -70,10 +70,10 @@ struct seize_task_status { int seccomp_mode; }; -struct proc_status_creds; - extern int seize_catch_task(pid_t pid); -extern int seize_wait_task(pid_t pid, pid_t ppid, struct proc_status_creds *creds); +extern int seize_wait_task(pid_t pid, pid_t ppid, + int (*get_status)(int pid, struct seize_task_status *), + struct seize_task_status *st); extern int suspend_seccomp(pid_t pid); extern int unseize_task(pid_t pid, int orig_state, int state); extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes); diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 771e75ac7..5e9780a41 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -981,8 +981,9 @@ static int cap_parse(char *str, unsigned int *res) return 0; } -int parse_pid_status(pid_t pid, struct proc_status_creds *cr) +int parse_pid_status(pid_t pid, struct seize_task_status *ss) { + struct proc_status_creds *cr = container_of(ss, struct proc_status_creds, s); struct bfd f; int done = 0; int ret = -1; diff --git a/criu/ptrace.c b/criu/ptrace.c index 4dd774c63..0d96eea50 100644 --- a/criu/ptrace.c +++ b/criu/ptrace.c @@ -148,7 +148,9 @@ static int skip_sigstop(int pid, int nr_signals) * of it so the task would not know if it was saddled * up with someone else. */ -int seize_wait_task(pid_t pid, pid_t ppid, struct proc_status_creds *creds) +int seize_wait_task(pid_t pid, pid_t ppid, + int (*get_status)(int pid, struct seize_task_status *), + struct seize_task_status *ss) { siginfo_t si; int status, nr_sigstop; @@ -175,17 +177,17 @@ try_again: wait_errno = errno; } - ret2 = parse_pid_status(pid, creds); + ret2 = get_status(pid, ss); if (ret2) goto err; if (ret < 0 || WIFEXITED(status) || WIFSIGNALED(status)) { - if (creds->s.state != 'Z') { + if (ss->state != 'Z') { if (pid == getpid()) pr_err("The criu itself is within dumped tree.\n"); else pr_err("Unseizable non-zombie %d found, state %c, err %d/%d\n", - pid, creds->s.state, ret, wait_errno); + pid, ss->state, ret, wait_errno); return -1; } @@ -195,9 +197,9 @@ try_again: return TASK_DEAD; } - if ((ppid != -1) && (creds->s.ppid != ppid)) { + if ((ppid != -1) && (ss->ppid != ppid)) { pr_err("Task pid reused while suspending (%d: %d -> %d)\n", - pid, ppid, creds->s.ppid); + pid, ppid, ss->ppid); goto err; } @@ -229,13 +231,13 @@ try_again: goto try_again; } - if (creds->s.seccomp_mode != SECCOMP_MODE_DISABLED && suspend_seccomp(pid) < 0) + if (ss->seccomp_mode != SECCOMP_MODE_DISABLED && suspend_seccomp(pid) < 0) goto err; nr_sigstop = 0; - if (creds->s.sigpnd & (1 << (SIGSTOP - 1))) + if (ss->sigpnd & (1 << (SIGSTOP - 1))) nr_sigstop++; - if (creds->s.shdpnd & (1 << (SIGSTOP - 1))) + if (ss->shdpnd & (1 << (SIGSTOP - 1))) nr_sigstop++; if (si.si_signo == SIGSTOP) nr_sigstop++; diff --git a/criu/seize.c b/criu/seize.c index bd41a8842..72d00040f 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -488,7 +488,7 @@ static int collect_children(struct pstree_item *item) goto free; } - ret = seize_wait_task(pid, item->pid->real, creds); + ret = seize_wait_task(pid, item->pid->real, parse_pid_status, &creds->s); if (ret < 0) { /* * Here is a race window between parse_children() and seize(), @@ -714,7 +714,7 @@ static int collect_threads(struct pstree_item *item) if (!opts.freeze_cgroup && seize_catch_task(pid)) continue; - ret = seize_wait_task(pid, item_ppid(item), &t_creds); + ret = seize_wait_task(pid, item_ppid(item), parse_pid_status, &t_creds.s); if (ret < 0) { /* * Here is a race window between parse_threads() and seize(), @@ -853,7 +853,7 @@ int collect_pstree(void) if (!creds) goto err; - ret = seize_wait_task(pid, -1, creds); + ret = seize_wait_task(pid, -1, parse_pid_status, &creds->s); if (ret < 0) goto err; From 71a4b46cdb6ffcc7683f4309ba305c0e739a0080 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 26 Sep 2016 13:20:23 +0300 Subject: [PATCH 0138/4375] infect: Introduce infect_ctx This structure will become the part of compel A[PB]I and will be used by compel clients as configuration structure. For now put there the pointer on a socket living in victim's netns. If empty (-1), compel will create this socket its own, but CRIU already creates such in an effective manner. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/parasite-syscall.h | 6 ++++++ criu/parasite-syscall.c | 19 +++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 95296c558..b161a47ab 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -26,6 +26,10 @@ struct thread_ctx { user_regs_struct_t regs; }; +struct infect_ctx { + int *p_sock; +}; + /* parasite control block */ struct parasite_ctl { int rpid; /* Real pid of the victim */ @@ -34,6 +38,8 @@ struct parasite_ctl { void *sigreturn_addr; /* A place for the breakpoint */ unsigned long map_length; + struct infect_ctx ictx; + /* thread leader data */ bool daemonized; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index f0765fbd8..c10f6596d 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -446,7 +446,7 @@ static int restore_child_handler() } static int prepare_tsock(struct parasite_ctl *ctl, pid_t pid, - struct parasite_init_args *args, struct ns_id *net) + struct parasite_init_args *args) { static int ssock = -1; @@ -454,8 +454,13 @@ static int prepare_tsock(struct parasite_ctl *ctl, pid_t pid, args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid()); if (ssock == -1) { - ssock = net->net.seqsk; - net->net.seqsk = -1; + ssock = *ctl->ictx.p_sock; + if (ssock == -1) { + pr_err("No socket in ictx\n"); + goto err; + } + + *ctl->ictx.p_sock = -1; if (bind(ssock, (struct sockaddr *)&args->h_addr, args->h_addr_len) < 0) { pr_perror("Can't bind socket"); @@ -499,7 +504,7 @@ static int accept_tsock(struct parasite_ctl *ctl) return 0; } -static int parasite_init_daemon(struct parasite_ctl *ctl, struct ns_id *net) +static int parasite_init_daemon(struct parasite_ctl *ctl) { struct parasite_init_args *args; pid_t pid = ctl->rpid; @@ -515,7 +520,7 @@ static int parasite_init_daemon(struct parasite_ctl *ctl, struct ns_id *net) futex_set(&args->daemon_connected, 0); - if (prepare_tsock(ctl, pid, args, net)) + if (prepare_tsock(ctl, pid, args)) goto err; /* after this we can catch parasite errors in chld handler */ @@ -1435,7 +1440,7 @@ static int parasite_start_daemon(struct parasite_ctl *ctl, struct pstree_item *i if (construct_sigframe(ctl->sigframe, ctl->rsigframe, &ctl->orig.sigmask, item->core[0])) return -1; - if (parasite_init_daemon(ctl, dmpi(item)->netns)) + if (parasite_init_daemon(ctl)) return -1; return 0; @@ -1475,6 +1480,8 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, if (!ctl) return NULL; + ctl->ictx.p_sock = &dmpi(item)->netns->net.seqsk; + parasite_ensure_args_size(dump_pages_args_size(vma_area_list)); parasite_ensure_args_size(aio_rings_args_size(vma_area_list)); From 7745501409a4627ca9bae4a450ef83c0348d0173 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 28 Sep 2016 11:15:50 +0300 Subject: [PATCH 0139/4375] infect: Introduce flags on ictx These will control various behavior of infection engine. For now only fault-injections. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/parasite-syscall.h | 4 ++++ criu/parasite-syscall.c | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index b161a47ab..b1ca5024f 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -28,8 +28,12 @@ struct thread_ctx { struct infect_ctx { int *p_sock; + unsigned long flags; /* fine-tune (e.g. faults) */ }; +#define INFECT_NO_MEMFD 0x1 /* don't use memfd() */ +#define INFECT_FAIL_CONNECT 0x2 /* make parasite connect() fail */ + /* parasite control block */ struct parasite_ctl { int rpid; /* Real pid of the victim */ diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index c10f6596d..c485391d8 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -474,7 +474,7 @@ static int prepare_tsock(struct parasite_ctl *ctl, pid_t pid, } /* Check a case when parasite can't initialize a command socket */ - if (fault_injected(FI_PARASITE_CONNECT)) + if (ctl->ictx.flags & INFECT_FAIL_CONNECT) args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid() + 1); /* @@ -1317,7 +1317,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) int ret, fd, lfd; bool __maybe_unused compat_task = !seized_native(ctl); - if (fault_injected(FI_NO_MEMFD)) + if (ctl->ictx.flags & INFECT_NO_MEMFD) return 1; BUILD_BUG_ON(sizeof(orig_code) < sizeof(long)); @@ -1482,6 +1482,11 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ctl->ictx.p_sock = &dmpi(item)->netns->net.seqsk; + if (fault_injected(FI_NO_MEMFD)) + ctl->ictx.flags |= INFECT_NO_MEMFD; + if (fault_injected(FI_PARASITE_CONNECT)) + ctl->ictx.flags |= INFECT_FAIL_CONNECT; + parasite_ensure_args_size(dump_pages_args_size(vma_area_list)); parasite_ensure_args_size(aio_rings_args_size(vma_area_list)); From 3569b51eef0ba5dd4dd70f306319b29293189f43 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 28 Sep 2016 11:22:29 +0300 Subject: [PATCH 0140/4375] infect: Place sigchild handler on ictx To track victim health state criu sets up the sigchild handler. So will have to do the compel, but the ability to request for own handler would be required. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/parasite-syscall.h | 2 ++ criu/parasite-syscall.c | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index b1ca5024f..d0ab8c61d 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -29,6 +29,8 @@ struct thread_ctx { struct infect_ctx { int *p_sock; unsigned long flags; /* fine-tune (e.g. faults) */ + + void (*child_handler)(int, siginfo_t *, void *); /* hander for SIGCHLD deaths */ }; #define INFECT_NO_MEMFD 0x1 /* don't use memfd() */ diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index c485391d8..d447c8ee1 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -411,10 +411,10 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) exit(1); } -static int setup_child_handler() +static int setup_child_handler(struct parasite_ctl *ctl) { struct sigaction sa = { - .sa_sigaction = sigchld_handler, + .sa_sigaction = ctl->ictx.child_handler, .sa_flags = SA_SIGINFO | SA_RESTART, }; @@ -524,7 +524,7 @@ static int parasite_init_daemon(struct parasite_ctl *ctl) goto err; /* after this we can catch parasite errors in chld handler */ - if (setup_child_handler()) + if (setup_child_handler(ctl)) goto err; regs = ctl->orig.regs; @@ -1480,6 +1480,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, if (!ctl) return NULL; + ctl->ictx.child_handler = sigchld_handler; ctl->ictx.p_sock = &dmpi(item)->netns->net.seqsk; if (fault_injected(FI_NO_MEMFD)) From c0e468dd2eccfa5e2a797860462ff579a662b479 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 26 Sep 2016 13:20:56 +0300 Subject: [PATCH 0141/4375] infect: Add registers keeping on infect_ctx Two calls -- to keep the registers and to put them back onto sigframe. For CRIU the keeping is performed on CoreEntry. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/parasite-syscall.h | 9 +++++++++ criu/parasite-syscall.c | 17 +++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index d0ab8c61d..2c9619534 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -20,6 +20,7 @@ struct cr_imgset; struct fd_opts; struct pid; struct parasite_dump_cgroup_args; +struct rt_sigframe; struct thread_ctx { k_rtsigset_t sigmask; @@ -28,6 +29,14 @@ struct thread_ctx { struct infect_ctx { int *p_sock; + + /* + * Regs manipulation context. + */ + int (*save_regs)(void *, user_regs_struct_t *, user_fpregs_struct_t *); + int (*make_sigframe)(void *, struct rt_sigframe *, struct rt_sigframe *, k_rtsigset_t *); + void *regs_arg; + unsigned long flags; /* fine-tune (e.g. faults) */ void (*child_handler)(int, siginfo_t *, void *); /* hander for SIGCHLD deaths */ diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index d447c8ee1..83dbec07e 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -1422,9 +1422,10 @@ void parasite_ensure_args_size(unsigned long sz) parasite_args_size = sz; } -static int parasite_start_daemon(struct parasite_ctl *ctl, struct pstree_item *item) +static int parasite_start_daemon(struct parasite_ctl *ctl) { pid_t pid = ctl->rpid; + struct infect_ctx *ictx = &ctl->ictx; /* * Get task registers before going daemon, since the @@ -1432,12 +1433,12 @@ static int parasite_start_daemon(struct parasite_ctl *ctl, struct pstree_item *i * while in daemon it is not such. */ - if (get_task_regs(pid, ctl->orig.regs, save_task_regs, item->core[0])) { + if (get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) { pr_err("Can't obtain regs for thread %d\n", pid); return -1; } - if (construct_sigframe(ctl->sigframe, ctl->rsigframe, &ctl->orig.sigmask, item->core[0])) + if (ictx->make_sigframe(ictx->regs_arg, ctl->sigframe, ctl->rsigframe, &ctl->orig.sigmask)) return -1; if (parasite_init_daemon(ctl)) @@ -1461,6 +1462,11 @@ static int parasite_start_daemon(struct parasite_ctl *ctl, struct pstree_item *i __export_parasite_args); \ } while (0) +static int make_sigframe(void *arg, struct rt_sigframe *sf, struct rt_sigframe *rtsf, k_rtsigset_t *bs) +{ + return construct_sigframe(sf, rtsf, bs, (CoreEntry *)arg); +} + struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, struct vm_area_list *vma_area_list) { @@ -1482,6 +1488,9 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ctl->ictx.child_handler = sigchld_handler; ctl->ictx.p_sock = &dmpi(item)->netns->net.seqsk; + ctl->ictx.save_regs = save_task_regs; + ctl->ictx.make_sigframe = make_sigframe; + ctl->ictx.regs_arg = item->core[0]; if (fault_injected(FI_NO_MEMFD)) ctl->ictx.flags |= INFECT_NO_MEMFD; @@ -1545,7 +1554,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ctl->r_thread_stack = ctl->remote_map + p; } - if (parasite_start_daemon(ctl, item)) + if (parasite_start_daemon(ctl)) goto err_restore; dmpi(item)->parasite_ctl = ctl; From 2c76fc8a530d388eeafe22a027438633d9f76df3 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 27 Sep 2016 17:39:42 +0300 Subject: [PATCH 0142/4375] infect: Keep entry point for first syscall on ictx This is the address of an executable VMA. To get one we need to parse /proc/pid/maps, compel will do it, but since criu already parses this file (to dump task vmas), we can provide the address via ictx. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-exec.c | 4 +++- criu/cr-restore.c | 2 +- criu/include/parasite-syscall.h | 4 ++-- criu/parasite-syscall.c | 17 ++++++++--------- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/criu/cr-exec.c b/criu/cr-exec.c index 9941cc038..7b4c8f9cd 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -166,12 +166,14 @@ int cr_exec(int pid, char **opt) goto out_unseize; } - ctl = parasite_prep_ctl(pid, p_start); + ctl = parasite_prep_ctl(pid); if (!ctl) { pr_err("Can't prep ctl %d\n", pid); goto out_unseize; } + ctl->ictx.syscall_ip = p_start; + si = find_syscall(sys_name, ctl); if (!si) { pr_err("Unknown syscall [%s]\n", sys_name); diff --git a/criu/cr-restore.c b/criu/cr-restore.c index dcc49d00c..88ca34e57 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1654,7 +1654,7 @@ static void finalize_restore(void) continue; /* Unmap the restorer blob */ - ctl = parasite_prep_ctl(pid, 0); + ctl = parasite_prep_ctl(pid); if (ctl == NULL) continue; diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 2c9619534..b70282fc2 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -37,6 +37,7 @@ struct infect_ctx { int (*make_sigframe)(void *, struct rt_sigframe *, struct rt_sigframe *, k_rtsigset_t *); void *regs_arg; + unsigned long syscall_ip; /* entry point of infection */ unsigned long flags; /* fine-tune (e.g. faults) */ void (*child_handler)(int, siginfo_t *, void *); /* hander for SIGCHLD deaths */ @@ -67,7 +68,6 @@ struct parasite_ctl { void *r_thread_stack; /* stack for non-leader threads */ unsigned long parasite_ip; /* service routine start ip */ - unsigned long syscall_ip; /* entry point of infection */ unsigned int *addr_cmd; /* addr for command */ void *addr_args; /* address for arguments */ @@ -122,7 +122,7 @@ extern struct parasite_ctl *parasite_infect_seized(pid_t pid, struct vm_area_list *vma_area_list); extern void parasite_ensure_args_size(unsigned long sz); extern unsigned long get_exec_start(struct vm_area_list *); -extern struct parasite_ctl *parasite_prep_ctl(pid_t pid, unsigned long exec_start); +extern struct parasite_ctl *parasite_prep_ctl(pid_t pid); extern int parasite_map_exchange(struct parasite_ctl *ctl, unsigned long size); extern int parasite_dump_cgroup(struct parasite_ctl *ctl, struct parasite_dump_cgroup_args *cgroup); diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 83dbec07e..7f492695b 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -224,18 +224,18 @@ int __parasite_execute_syscall(struct parasite_ctl *ctl, * we will need it to restore original program content. */ memcpy(code_orig, code_syscall, sizeof(code_orig)); - if (ptrace_swap_area(pid, (void *)ctl->syscall_ip, + if (ptrace_swap_area(pid, (void *)ctl->ictx.syscall_ip, (void *)code_orig, sizeof(code_orig))) { pr_err("Can't inject syscall blob (pid: %d)\n", pid); return -1; } - err = parasite_run(pid, PTRACE_CONT, ctl->syscall_ip, 0, regs, &ctl->orig); + err = parasite_run(pid, PTRACE_CONT, ctl->ictx.syscall_ip, 0, regs, &ctl->orig); if (!err) err = parasite_trap(ctl, pid, regs, &ctl->orig); if (ptrace_poke_area(pid, (void *)code_orig, - (void *)ctl->syscall_ip, sizeof(code_orig))) { + (void *)ctl->ictx.syscall_ip, sizeof(code_orig))) { pr_err("Can't restore syscall blob (pid: %d)\n", ctl->rpid); err = -1; } @@ -1244,7 +1244,7 @@ err: } /* If vma_area_list is NULL, a place for injecting syscall will not be set. */ -struct parasite_ctl *parasite_prep_ctl(pid_t pid, unsigned long exec_start) +struct parasite_ctl *parasite_prep_ctl(pid_t pid) { struct parasite_ctl *ctl = NULL; @@ -1266,9 +1266,6 @@ struct parasite_ctl *parasite_prep_ctl(pid_t pid, unsigned long exec_start) BUILD_BUG_ON(PARASITE_START_AREA_MIN < BUILTIN_SYSCALL_SIZE + MEMFD_FNAME_SZ); - ctl->syscall_ip = exec_start; - pr_debug("Parasite syscall_ip at %p\n", (void *)ctl->syscall_ip); - return ctl; err: @@ -1310,7 +1307,7 @@ static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size) static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) { - void *where = (void *)ctl->syscall_ip + BUILTIN_SYSCALL_SIZE; + void *where = (void *)ctl->ictx.syscall_ip + BUILTIN_SYSCALL_SIZE; u8 orig_code[MEMFD_FNAME_SZ] = MEMFD_FNAME; pid_t pid = ctl->rpid; unsigned long sret = -ENOSYS; @@ -1482,7 +1479,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, return NULL; } - ctl = parasite_prep_ctl(pid, p); + ctl = parasite_prep_ctl(pid); if (!ctl) return NULL; @@ -1491,6 +1488,8 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ctl->ictx.save_regs = save_task_regs; ctl->ictx.make_sigframe = make_sigframe; ctl->ictx.regs_arg = item->core[0]; + ctl->ictx.syscall_ip = p; + pr_debug("Parasite syscall_ip at %#lx\n", p); if (fault_injected(FI_NO_MEMFD)) ctl->ictx.flags |= INFECT_NO_MEMFD; From 1fe80294ec11a28abc0722b9a02e9717b6e81f3b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 26 Sep 2016 13:21:10 +0300 Subject: [PATCH 0143/4375] infect: The big split of infection routine Now we can split the parasite_infect_seized() into CRIU-specific part and independent part that is to become compel code. The API to infect() is for now a bit clumsy, but I will rectify one a bit more in the next patches. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/parasite-syscall.c | 47 ++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 7f492695b..3eba20efc 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -1464,12 +1464,13 @@ static int make_sigframe(void *arg, struct rt_sigframe *sf, struct rt_sigframe * return construct_sigframe(sf, rtsf, bs, (CoreEntry *)arg); } +static int infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size); + struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, struct vm_area_list *vma_area_list) { - int ret; struct parasite_ctl *ctl; - unsigned long p, map_exchange_size, parasite_size = 0; + unsigned long p; BUG_ON(item->threads[0].real != pid); @@ -1499,8 +1500,26 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, parasite_ensure_args_size(dump_pages_args_size(vma_area_list)); parasite_ensure_args_size(aio_rings_args_size(vma_area_list)); + if (infect(ctl, item->nr_threads, parasite_args_size) < 0) { + parasite_cure_seized(ctl); + return NULL; + } + + parasite_args_size = PARASITE_ARG_SIZE_MIN; /* reset for next task */ + memcpy(&item->core[0]->tc->blk_sigset, &ctl->orig.sigmask, sizeof(k_rtsigset_t)); + dmpi(item)->parasite_ctl = ctl; + + return ctl; +} + +static int infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size) +{ + int ret; + unsigned long p, map_exchange_size, parasite_size = 0; + if (!arch_can_dump_task(ctl)) - goto err_restore; + goto err; + /* * Inject a parasite engine. Ie allocate memory inside alien * space and copy engine code there. Then re-map the engine @@ -1515,20 +1534,17 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, parasite_size = pie_size(parasite_compat); #endif - ctl->args_size = round_up(parasite_args_size, PAGE_SIZE); - parasite_args_size = PARASITE_ARG_SIZE_MIN; /* reset for next task */ + ctl->args_size = round_up(args_size, PAGE_SIZE); parasite_size += ctl->args_size; map_exchange_size = parasite_size; map_exchange_size += RESTORE_STACK_SIGFRAME + PARASITE_STACK_SIZE; - if (item->nr_threads > 1) + if (nr_threads > 1) map_exchange_size += PARASITE_STACK_SIZE; - memcpy(&item->core[0]->tc->blk_sigset, &ctl->orig.sigmask, sizeof(k_rtsigset_t)); - ret = parasite_map_exchange(ctl, map_exchange_size); if (ret) - goto err_restore; + goto err; pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map); @@ -1548,21 +1564,18 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, p += PARASITE_STACK_SIZE; ctl->rstack = ctl->remote_map + p; - if (item->nr_threads > 1) { + if (nr_threads > 1) { p += PARASITE_STACK_SIZE; ctl->r_thread_stack = ctl->remote_map + p; } if (parasite_start_daemon(ctl)) - goto err_restore; + goto err; - dmpi(item)->parasite_ctl = ctl; + return 0; - return ctl; - -err_restore: - parasite_cure_seized(ctl); - return NULL; +err: + return -1; } int ptrace_stop_pie(pid_t pid, void *addr, enum trace_flags *tf) From 6dc2e2decd0505cd30fa4adcfa40daf0f3586c70 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 27 Sep 2016 18:12:25 +0300 Subject: [PATCH 0144/4375] infect: Introduce skeleton for soon-to-be compel code We'll collect the compel code here and will move all these files into compel library by the last patch of this set. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/Makefile.crtools | 1 + criu/include/infect.h | 3 +++ criu/infect.c | 1 + 3 files changed, 5 insertions(+) create mode 100644 criu/include/infect.h create mode 100644 criu/infect.c diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 9f3041eef..41de00877 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -3,6 +3,7 @@ ccflags-y += -iquote compel/plugins/include ccflags-y += -iquote compel/include ccflags-y += -iquote compel/arch/$(ARCH)/plugins/std +obj-y += infect.o obj-y += action-scripts.o obj-y += external.o obj-y += aio.o diff --git a/criu/include/infect.h b/criu/include/infect.h new file mode 100644 index 000000000..1d2bdf532 --- /dev/null +++ b/criu/include/infect.h @@ -0,0 +1,3 @@ +#ifndef __COMPEL_INFECT_H__ +#define __COMPEL_INFECT_H__ +#endif diff --git a/criu/infect.c b/criu/infect.c new file mode 100644 index 000000000..ac3897c3e --- /dev/null +++ b/criu/infect.c @@ -0,0 +1 @@ +#include "infect.h" From ea470224b62d4168de99dd77b27c80d847db2d60 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 27 Sep 2016 18:15:30 +0300 Subject: [PATCH 0145/4375] infect: Move seize_catch_task -> compel_stop_task Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-exec.c | 3 ++- criu/include/infect.h | 1 + criu/include/ptrace.h | 1 - criu/infect.c | 39 +++++++++++++++++++++++++++++++++++++++ criu/ptrace.c | 34 ---------------------------------- criu/seize.c | 9 +++++---- 6 files changed, 47 insertions(+), 40 deletions(-) diff --git a/criu/cr-exec.c b/criu/cr-exec.c index 7b4c8f9cd..1f4394bd2 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -11,6 +11,7 @@ #include "log.h" #include "util.h" #include "kerndat.h" +#include "infect.h" struct syscall_exec_desc { char *name; @@ -135,7 +136,7 @@ int cr_exec(int pid, char **opt) goto out; } - if (seize_catch_task(pid)) + if (compel_stop_task(pid)) goto out; /* diff --git a/criu/include/infect.h b/criu/include/infect.h index 1d2bdf532..d148a78e3 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -1,3 +1,4 @@ #ifndef __COMPEL_INFECT_H__ #define __COMPEL_INFECT_H__ +extern int compel_stop_task(int pid); #endif diff --git a/criu/include/ptrace.h b/criu/include/ptrace.h index 2b45c2311..6d4bd92db 100644 --- a/criu/include/ptrace.h +++ b/criu/include/ptrace.h @@ -70,7 +70,6 @@ struct seize_task_status { int seccomp_mode; }; -extern int seize_catch_task(pid_t pid); extern int seize_wait_task(pid_t pid, pid_t ppid, int (*get_status)(int pid, struct seize_task_status *), struct seize_task_status *st); diff --git a/criu/infect.c b/criu/infect.c index ac3897c3e..0a625b4d1 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -1 +1,40 @@ +#include +#include + +#include "log.h" #include "infect.h" + +int compel_stop_task(int pid) +{ + int ret; + + ret = ptrace(PTRACE_SEIZE, pid, NULL, 0); + if (ret) { + /* + * ptrace API doesn't allow to distinguish + * attaching to zombie from other errors. + * All errors will be handled in seize_wait_task(). + */ + pr_warn("Unable to interrupt task: %d (%s)\n", pid, strerror(errno)); + return ret; + } + + /* + * If we SEIZE-d the task stop it before going + * and reading its stat from proc. Otherwise task + * may die _while_ we're doing it and we'll have + * inconsistent seize/state pair. + * + * If task dies after we seize it but before we + * do this interrupt, we'll notice it via proc. + */ + ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL); + if (ret < 0) { + pr_warn("SEIZE %d: can't interrupt task: %s", pid, strerror(errno)); + if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) + pr_perror("Unable to detach from %d", pid); + } + + return ret; +} + diff --git a/criu/ptrace.c b/criu/ptrace.c index 0d96eea50..2bbf67ade 100644 --- a/criu/ptrace.c +++ b/criu/ptrace.c @@ -68,40 +68,6 @@ int suspend_seccomp(pid_t pid) return 0; } -int seize_catch_task(pid_t pid) -{ - int ret; - - ret = ptrace(PTRACE_SEIZE, pid, NULL, 0); - if (ret) { - /* - * ptrace API doesn't allow to distinguish - * attaching to zombie from other errors. - * All errors will be handled in seize_wait_task(). - */ - pr_warn("Unable to interrupt task: %d (%s)\n", pid, strerror(errno)); - return ret; - } - - /* - * If we SEIZE-d the task stop it before going - * and reading its stat from proc. Otherwise task - * may die _while_ we're doing it and we'll have - * inconsistent seize/state pair. - * - * If task dies after we seize it but before we - * do this interrupt, we'll notice it via proc. - */ - ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL); - if (ret < 0) { - pr_warn("SEIZE %d: can't interrupt task: %s", pid, strerror(errno)); - if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) - pr_perror("Unable to detach from %d", pid); - } - - return ret; -} - static int skip_sigstop(int pid, int nr_signals) { int i, status, ret; diff --git a/criu/seize.c b/criu/seize.c index 72d00040f..354692901 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -20,6 +20,7 @@ #include "stats.h" #include "xmalloc.h" #include "util.h" +#include "infect.h" #define NR_ATTEMPTS 5 @@ -128,7 +129,7 @@ static int seize_cgroup_tree(char *root_path, const char *state) return -1; } - if (!seize_catch_task(pid)) { + if (!compel_stop_task(pid)) { pr_debug("SEIZE %d: success\n", pid); processes_to_wait++; } else if (state == frozen) { @@ -480,7 +481,7 @@ static int collect_children(struct pstree_item *item) if (!opts.freeze_cgroup) /* fails when meets a zombie */ - seize_catch_task(pid); + compel_stop_task(pid); creds = xzalloc(sizeof(*creds)); if (!creds) { @@ -711,7 +712,7 @@ static int collect_threads(struct pstree_item *item) pr_info("\tSeizing %d's %d thread\n", item->pid->real, pid); - if (!opts.freeze_cgroup && seize_catch_task(pid)) + if (!opts.freeze_cgroup && compel_stop_task(pid)) continue; ret = seize_wait_task(pid, item_ppid(item), parse_pid_status, &t_creds.s); @@ -844,7 +845,7 @@ int collect_pstree(void) if (opts.freeze_cgroup && freeze_processes()) goto err; - if (!opts.freeze_cgroup && seize_catch_task(pid)) { + if (!opts.freeze_cgroup && compel_stop_task(pid)) { set_cr_errno(ESRCH); goto err; } From 7d3e7b05fee2413f329cc3fb91de60a31b3c9b21 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 27 Sep 2016 20:16:07 +0300 Subject: [PATCH 0146/4375] infect: Move seize_wait_task -> compel_wait_task Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-exec.c | 3 +- criu/include/infect.h | 22 +++++ criu/include/proc_parse.h | 2 +- criu/include/ptrace.h | 11 --- criu/infect.c | 191 +++++++++++++++++++++++++++++++++++++- criu/ptrace.c | 162 -------------------------------- criu/seize.c | 7 +- 7 files changed, 219 insertions(+), 179 deletions(-) diff --git a/criu/cr-exec.c b/criu/cr-exec.c index 1f4394bd2..b275287d0 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -5,6 +5,7 @@ #include "types.h" #include "crtools.h" #include "proc_parse.h" +#include "ptrace.h" #include "pstree.h" #include "parasite-syscall.h" #include "vma.h" @@ -144,7 +145,7 @@ int cr_exec(int pid, char **opt) * mess with creds in this use case anyway. */ - prev_state = ret = seize_wait_task(pid, -1, parse_pid_status, &creds.s); + prev_state = ret = compel_wait_task(pid, -1, parse_pid_status, &creds.s); if (ret < 0) { pr_err("Can't seize task %d\n", pid); goto out; diff --git a/criu/include/infect.h b/criu/include/infect.h index d148a78e3..dbd721b14 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -1,4 +1,26 @@ #ifndef __COMPEL_INFECT_H__ #define __COMPEL_INFECT_H__ extern int compel_stop_task(int pid); + +struct seize_task_status { + char state; + int ppid; + unsigned long long sigpnd; + unsigned long long shdpnd; + int seccomp_mode; +}; + +extern int compel_wait_task(int pid, int ppid, + int (*get_status)(int pid, struct seize_task_status *), + struct seize_task_status *st); + +/* + * FIXME -- these should be mapped to pid.h's + */ + +#define TASK_ALIVE 0x1 +#define TASK_DEAD 0x2 +#define TASK_STOPPED 0x3 +#define TASK_ZOMBIE 0x6 + #endif diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h index d5fbaf7a0..04359e247 100644 --- a/criu/include/proc_parse.h +++ b/criu/include/proc_parse.h @@ -3,7 +3,7 @@ #include -#include "ptrace.h" +#include "infect.h" #include "images/seccomp.pb-c.h" #define PROC_TASK_COMM_LEN 32 diff --git a/criu/include/ptrace.h b/criu/include/ptrace.h index 6d4bd92db..1e79972b4 100644 --- a/criu/include/ptrace.h +++ b/criu/include/ptrace.h @@ -62,17 +62,6 @@ #define SI_EVENT(_si_code) (((_si_code) & 0xFFFF) >> 8) -struct seize_task_status { - char state; - int ppid; - unsigned long long sigpnd; - unsigned long long shdpnd; - int seccomp_mode; -}; - -extern int seize_wait_task(pid_t pid, pid_t ppid, - int (*get_status)(int pid, struct seize_task_status *), - struct seize_task_status *st); extern int suspend_seccomp(pid_t pid); extern int unseize_task(pid_t pid, int orig_state, int state); extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes); diff --git a/criu/infect.c b/criu/infect.c index 0a625b4d1..de48b428c 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -1,9 +1,26 @@ +#include +#include #include +#include #include +#include +#include #include "log.h" #include "infect.h" +#define PTRACE_EVENT_STOP 128 + +#ifndef SECCOMP_MODE_DISABLED +#define SECCOMP_MODE_DISABLED 0 +#endif + +#ifndef PTRACE_O_SUSPEND_SECCOMP +# define PTRACE_O_SUSPEND_SECCOMP (1 << 21) +#endif + +#define SI_EVENT(_si_code) (((_si_code) & 0xFFFF) >> 8) + int compel_stop_task(int pid) { int ret; @@ -13,7 +30,7 @@ int compel_stop_task(int pid) /* * ptrace API doesn't allow to distinguish * attaching to zombie from other errors. - * All errors will be handled in seize_wait_task(). + * All errors will be handled in compel_wait_task(). */ pr_warn("Unable to interrupt task: %d (%s)\n", pid, strerror(errno)); return ret; @@ -38,3 +55,175 @@ int compel_stop_task(int pid) return ret; } +static int skip_sigstop(int pid, int nr_signals) +{ + int i, status, ret; + + /* + * 1) SIGSTOP is queued, but isn't handled yet: + * SGISTOP can't be blocked, so we need to wait when the kernel + * handles this signal. + * + * Otherwise the process will be stopped immediately after + * starting it. + * + * 2) A seized task was stopped: + * PTRACE_SEIZE doesn't affect signal or group stop state. + * Currently ptrace reported that task is in stopped state. + * We need to start task again, and it will be trapped + * immediately, because we sent PTRACE_INTERRUPT to it. + */ + for (i = 0; i < nr_signals; i++) { + ret = ptrace(PTRACE_CONT, pid, 0, 0); + if (ret) { + pr_perror("Unable to start process"); + return -1; + } + + ret = wait4(pid, &status, __WALL, NULL); + if (ret < 0) { + pr_perror("SEIZE %d: can't wait task", pid); + return -1; + } + + if (!WIFSTOPPED(status)) { + pr_err("SEIZE %d: task not stopped after seize\n", pid); + return -1; + } + } + return 0; +} + +static int do_suspend_seccomp(pid_t pid) +{ + if (ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_SUSPEND_SECCOMP) < 0) { + pr_perror("suspending seccomp failed"); + return -1; + } + + return 0; +} + +/* + * This routine seizes task putting it into a special + * state where we can manipulate the task via ptrace + * interface, and finally we can detach ptrace out of + * of it so the task would not know if it was saddled + * up with someone else. + */ +int compel_wait_task(int pid, int ppid, + int (*get_status)(int pid, struct seize_task_status *), + struct seize_task_status *ss) +{ + siginfo_t si; + int status, nr_sigstop; + int ret = 0, ret2, wait_errno = 0; + + /* + * It's ugly, but the ptrace API doesn't allow to distinguish + * attaching to zombie from other errors. Thus we have to parse + * the target's /proc/pid/stat. Sad, but parse whatever else + * we might need at that early point. + */ + +try_again: + + ret = wait4(pid, &status, __WALL, NULL); + if (ret < 0) { + /* + * wait4() can expectedly fail only in a first time + * if a task is zombie. If we are here from try_again, + * this means that we are tracing this task. + * + * So here we can be only once in this function. + */ + wait_errno = errno; + } + + ret2 = get_status(pid, ss); + if (ret2) + goto err; + + if (ret < 0 || WIFEXITED(status) || WIFSIGNALED(status)) { + if (ss->state != 'Z') { + if (pid == getpid()) + pr_err("The criu itself is within dumped tree.\n"); + else + pr_err("Unseizable non-zombie %d found, state %c, err %d/%d\n", + pid, ss->state, ret, wait_errno); + return -1; + } + + if (ret < 0) + return TASK_ZOMBIE; + else + return TASK_DEAD; + } + + if ((ppid != -1) && (ss->ppid != ppid)) { + pr_err("Task pid reused while suspending (%d: %d -> %d)\n", + pid, ppid, ss->ppid); + goto err; + } + + if (!WIFSTOPPED(status)) { + pr_err("SEIZE %d: task not stopped after seize\n", pid); + goto err; + } + + ret = ptrace(PTRACE_GETSIGINFO, pid, NULL, &si); + if (ret < 0) { + pr_perror("SEIZE %d: can't read signfo", pid); + goto err; + } + + if (SI_EVENT(si.si_code) != PTRACE_EVENT_STOP) { + /* + * Kernel notifies us about the task being seized received some + * event other than the STOP, i.e. -- a signal. Let the task + * handle one and repeat. + */ + + if (ptrace(PTRACE_CONT, pid, NULL, + (void *)(unsigned long)si.si_signo)) { + pr_perror("Can't continue signal handling, aborting"); + goto err; + } + + ret = 0; + goto try_again; + } + + if (ss->seccomp_mode != SECCOMP_MODE_DISABLED && do_suspend_seccomp(pid) < 0) + goto err; + + nr_sigstop = 0; + if (ss->sigpnd & (1 << (SIGSTOP - 1))) + nr_sigstop++; + if (ss->shdpnd & (1 << (SIGSTOP - 1))) + nr_sigstop++; + if (si.si_signo == SIGSTOP) + nr_sigstop++; + + if (nr_sigstop) { + if (skip_sigstop(pid, nr_sigstop)) + goto err_stop; + + return TASK_STOPPED; + } + + if (si.si_signo == SIGTRAP) + return TASK_ALIVE; + else { + pr_err("SEIZE %d: unsupported stop signal %d\n", pid, si.si_signo); + goto err; + } + +err_stop: + kill(pid, SIGSTOP); +err: + if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) + pr_perror("Unable to detach from %d", pid); + return -1; +} + diff --git a/criu/ptrace.c b/criu/ptrace.c index 2bbf67ade..f013346e3 100644 --- a/criu/ptrace.c +++ b/criu/ptrace.c @@ -68,168 +68,6 @@ int suspend_seccomp(pid_t pid) return 0; } -static int skip_sigstop(int pid, int nr_signals) -{ - int i, status, ret; - - /* - * 1) SIGSTOP is queued, but isn't handled yet: - * SGISTOP can't be blocked, so we need to wait when the kernel - * handles this signal. - * - * Otherwise the process will be stopped immediately after - * starting it. - * - * 2) A seized task was stopped: - * PTRACE_SEIZE doesn't affect signal or group stop state. - * Currently ptrace reported that task is in stopped state. - * We need to start task again, and it will be trapped - * immediately, because we sent PTRACE_INTERRUPT to it. - */ - for (i = 0; i < nr_signals; i++) { - ret = ptrace(PTRACE_CONT, pid, 0, 0); - if (ret) { - pr_perror("Unable to start process"); - return -1; - } - - ret = wait4(pid, &status, __WALL, NULL); - if (ret < 0) { - pr_perror("SEIZE %d: can't wait task", pid); - return -1; - } - - if (!WIFSTOPPED(status)) { - pr_err("SEIZE %d: task not stopped after seize\n", pid); - return -1; - } - } - return 0; -} - -/* - * This routine seizes task putting it into a special - * state where we can manipulate the task via ptrace - * interface, and finally we can detach ptrace out of - * of it so the task would not know if it was saddled - * up with someone else. - */ -int seize_wait_task(pid_t pid, pid_t ppid, - int (*get_status)(int pid, struct seize_task_status *), - struct seize_task_status *ss) -{ - siginfo_t si; - int status, nr_sigstop; - int ret = 0, ret2, wait_errno = 0; - - /* - * It's ugly, but the ptrace API doesn't allow to distinguish - * attaching to zombie from other errors. Thus we have to parse - * the target's /proc/pid/stat. Sad, but parse whatever else - * we might need at that early point. - */ - -try_again: - - ret = wait4(pid, &status, __WALL, NULL); - if (ret < 0) { - /* - * wait4() can expectedly fail only in a first time - * if a task is zombie. If we are here from try_again, - * this means that we are tracing this task. - * - * So here we can be only once in this function. - */ - wait_errno = errno; - } - - ret2 = get_status(pid, ss); - if (ret2) - goto err; - - if (ret < 0 || WIFEXITED(status) || WIFSIGNALED(status)) { - if (ss->state != 'Z') { - if (pid == getpid()) - pr_err("The criu itself is within dumped tree.\n"); - else - pr_err("Unseizable non-zombie %d found, state %c, err %d/%d\n", - pid, ss->state, ret, wait_errno); - return -1; - } - - if (ret < 0) - return TASK_ZOMBIE; - else - return TASK_DEAD; - } - - if ((ppid != -1) && (ss->ppid != ppid)) { - pr_err("Task pid reused while suspending (%d: %d -> %d)\n", - pid, ppid, ss->ppid); - goto err; - } - - if (!WIFSTOPPED(status)) { - pr_err("SEIZE %d: task not stopped after seize\n", pid); - goto err; - } - - ret = ptrace(PTRACE_GETSIGINFO, pid, NULL, &si); - if (ret < 0) { - pr_perror("SEIZE %d: can't read signfo", pid); - goto err; - } - - if (SI_EVENT(si.si_code) != PTRACE_EVENT_STOP) { - /* - * Kernel notifies us about the task being seized received some - * event other than the STOP, i.e. -- a signal. Let the task - * handle one and repeat. - */ - - if (ptrace(PTRACE_CONT, pid, NULL, - (void *)(unsigned long)si.si_signo)) { - pr_perror("Can't continue signal handling, aborting"); - goto err; - } - - ret = 0; - goto try_again; - } - - if (ss->seccomp_mode != SECCOMP_MODE_DISABLED && suspend_seccomp(pid) < 0) - goto err; - - nr_sigstop = 0; - if (ss->sigpnd & (1 << (SIGSTOP - 1))) - nr_sigstop++; - if (ss->shdpnd & (1 << (SIGSTOP - 1))) - nr_sigstop++; - if (si.si_signo == SIGSTOP) - nr_sigstop++; - - if (nr_sigstop) { - if (skip_sigstop(pid, nr_sigstop)) - goto err_stop; - - return TASK_STOPPED; - } - - if (si.si_signo == SIGTRAP) - return TASK_ALIVE; - else { - pr_err("SEIZE %d: unsupported stop signal %d\n", pid, si.si_signo); - goto err; - } - -err_stop: - kill(pid, SIGSTOP); -err: - if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) - pr_perror("Unable to detach from %d", pid); - return -1; -} - int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes) { unsigned long w; diff --git a/criu/seize.c b/criu/seize.c index 354692901..35ecf2580 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -15,6 +15,7 @@ #include "cr-errno.h" #include "pstree.h" #include "criu-log.h" +#include "ptrace.h" #include "proc_parse.h" #include "seize.h" #include "stats.h" @@ -489,7 +490,7 @@ static int collect_children(struct pstree_item *item) goto free; } - ret = seize_wait_task(pid, item->pid->real, parse_pid_status, &creds->s); + ret = compel_wait_task(pid, item->pid->real, parse_pid_status, &creds->s); if (ret < 0) { /* * Here is a race window between parse_children() and seize(), @@ -715,7 +716,7 @@ static int collect_threads(struct pstree_item *item) if (!opts.freeze_cgroup && compel_stop_task(pid)) continue; - ret = seize_wait_task(pid, item_ppid(item), parse_pid_status, &t_creds.s); + ret = compel_wait_task(pid, item_ppid(item), parse_pid_status, &t_creds.s); if (ret < 0) { /* * Here is a race window between parse_threads() and seize(), @@ -854,7 +855,7 @@ int collect_pstree(void) if (!creds) goto err; - ret = seize_wait_task(pid, -1, parse_pid_status, &creds->s); + ret = compel_wait_task(pid, -1, parse_pid_status, &creds->s); if (ret < 0) goto err; From 2724375919f59dbe72f85bbd40373d595bd39e28 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 28 Sep 2016 10:47:17 +0300 Subject: [PATCH 0147/4375] infect: Make parasite_ctl private This structure will be internal to compel. Users will only see one as opaque pointer and read data from it using calls. Exception for now -- infect_ictx. This is a configuration structure that will be embeded into ctl and seen outside. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/crtools.c | 2 +- criu/arch/arm/crtools.c | 2 +- criu/arch/ppc64/crtools.c | 1 + criu/arch/x86/crtools.c | 1 + criu/cr-exec.c | 1 + criu/include/infect-priv.h | 35 +++++++++++++++++++++++++++++++++ criu/include/parasite-syscall.h | 34 +++++--------------------------- criu/infect.c | 3 +++ criu/parasite-syscall.c | 9 ++++++++- 9 files changed, 56 insertions(+), 32 deletions(-) create mode 100644 criu/include/infect-priv.h diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index 5510da19a..5263dd008 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -17,7 +17,7 @@ #include "util.h" #include "cpu.h" #include "restorer.h" - +#include "infect-priv.h" /* * Injected syscall instruction diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index 73a82b46a..6ca2fe386 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -18,7 +18,7 @@ #include "restorer.h" #include "errno.h" #include "kerndat.h" - +#include "infect-priv.h" /* * Injected syscall instruction diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index 9e98190e0..e4a27350c 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -18,6 +18,7 @@ #include "util.h" #include "cpu.h" #include "errno.h" +#include "infect-priv.h" #include "protobuf.h" #include "images/core.pb-c.h" diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index a66a8c650..8059ea22d 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -24,6 +24,7 @@ #include "errno.h" #include "uapi/std/syscall-codes.h" #include "kerndat.h" +#include "infect-priv.h" #include "protobuf.h" #include "images/core.pb-c.h" diff --git a/criu/cr-exec.c b/criu/cr-exec.c index b275287d0..f07d71317 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -13,6 +13,7 @@ #include "util.h" #include "kerndat.h" #include "infect.h" +#include "infect-priv.h" struct syscall_exec_desc { char *name; diff --git a/criu/include/infect-priv.h b/criu/include/infect-priv.h new file mode 100644 index 000000000..a461ffa2c --- /dev/null +++ b/criu/include/infect-priv.h @@ -0,0 +1,35 @@ +#ifndef __COMPEL_INFECT_PRIV_H__ +#define __COMPEL_INFECT_PRIV_H__ + +#include + +/* parasite control block */ +struct parasite_ctl { + int rpid; /* Real pid of the victim */ + void *remote_map; + void *local_map; + void *sigreturn_addr; /* A place for the breakpoint */ + unsigned long map_length; + + struct infect_ctx ictx; + + /* thread leader data */ + bool daemonized; + + struct thread_ctx orig; + + void *rstack; /* thread leader stack*/ + struct rt_sigframe *sigframe; + struct rt_sigframe *rsigframe; /* address in a parasite */ + + void *r_thread_stack; /* stack for non-leader threads */ + + unsigned long parasite_ip; /* service routine start ip */ + + unsigned int *addr_cmd; /* addr for command */ + void *addr_args; /* address for arguments */ + unsigned long args_size; + int tsock; /* transport socket for transferring fds */ +}; + +#endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index b70282fc2..65d4217c2 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -46,34 +46,7 @@ struct infect_ctx { #define INFECT_NO_MEMFD 0x1 /* don't use memfd() */ #define INFECT_FAIL_CONNECT 0x2 /* make parasite connect() fail */ -/* parasite control block */ -struct parasite_ctl { - int rpid; /* Real pid of the victim */ - void *remote_map; - void *local_map; - void *sigreturn_addr; /* A place for the breakpoint */ - unsigned long map_length; - - struct infect_ctx ictx; - - /* thread leader data */ - bool daemonized; - - struct thread_ctx orig; - - void *rstack; /* thread leader stack*/ - struct rt_sigframe *sigframe; - struct rt_sigframe *rsigframe; /* address in a parasite */ - - void *r_thread_stack; /* stack for non-leader threads */ - - unsigned long parasite_ip; /* service routine start ip */ - - unsigned int *addr_cmd; /* addr for command */ - void *addr_args; /* address for arguments */ - unsigned long args_size; - int tsock; /* transport socket for transferring fds */ -}; +struct parasite_ctl; extern int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_imgset); extern int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct pstree_item *); @@ -84,10 +57,13 @@ extern int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc #define parasite_args(ctl, type) \ ({ \ + void *___ret; \ BUILD_BUG_ON(sizeof(type) > PARASITE_ARG_SIZE_MIN); \ - ctl->addr_args; \ + ___ret = parasite_args_p(ctl); \ + ___ret; \ }) +extern void *parasite_args_p(struct parasite_ctl *ctl); extern void *parasite_args_s(struct parasite_ctl *ctl, int args_size); extern int parasite_send_fd(struct parasite_ctl *ctl, int fd); diff --git a/criu/infect.c b/criu/infect.c index de48b428c..860525c92 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -6,8 +6,11 @@ #include #include +#include "parasite-syscall.h" + #include "log.h" #include "infect.h" +#include "infect-priv.h" #define PTRACE_EVENT_STOP 128 diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 3eba20efc..bbc9a9378 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -42,6 +42,8 @@ #include "restorer.h" #include "pie/pie-relocs.h" +#include "infect-priv.h" + #define MEMFD_FNAME "CRIUMFD" #define MEMFD_FNAME_SZ sizeof(MEMFD_FNAME) @@ -243,10 +245,15 @@ int __parasite_execute_syscall(struct parasite_ctl *ctl, return err; } +void *parasite_args_p(struct parasite_ctl *ctl) +{ + return ctl->addr_args; +} + void *parasite_args_s(struct parasite_ctl *ctl, int args_size) { BUG_ON(args_size > ctl->args_size); - return ctl->addr_args; + return parasite_args_p(ctl); } static int parasite_run_in_thread(pid_t pid, unsigned int cmd, From bb33a7742a7bcc50fd9f13625ef6f1d34b4f2b27 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 28 Sep 2016 11:29:01 +0300 Subject: [PATCH 0148/4375] infect: Move infect() into infect.c Not only infect() routine but all dependant code too. This is the core of the library actually. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-exec.c | 2 +- criu/include/infect-priv.h | 2 + criu/include/infect.h | 4 + criu/infect.c | 299 ++++++++++++++++++++++++++++++++++++- criu/parasite-syscall.c | 293 +----------------------------------- 5 files changed, 308 insertions(+), 292 deletions(-) diff --git a/criu/cr-exec.c b/criu/cr-exec.c index f07d71317..4762a8b90 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -4,10 +4,10 @@ #include "int.h" #include "types.h" #include "crtools.h" +#include "parasite-syscall.h" #include "proc_parse.h" #include "ptrace.h" #include "pstree.h" -#include "parasite-syscall.h" #include "vma.h" #include "log.h" #include "util.h" diff --git a/criu/include/infect-priv.h b/criu/include/infect-priv.h index a461ffa2c..8a1ab610d 100644 --- a/criu/include/infect-priv.h +++ b/criu/include/infect-priv.h @@ -32,4 +32,6 @@ struct parasite_ctl { int tsock; /* transport socket for transferring fds */ }; +int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack, + user_regs_struct_t *regs, struct thread_ctx *octx); #endif diff --git a/criu/include/infect.h b/criu/include/infect.h index dbd721b14..9cfbfe084 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -23,4 +23,8 @@ extern int compel_wait_task(int pid, int ppid, #define TASK_STOPPED 0x3 #define TASK_ZOMBIE 0x6 +struct parasite_ctl; + +extern int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size); + #endif diff --git a/criu/infect.c b/criu/infect.c index 860525c92..3fc89df5d 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -6,12 +6,23 @@ #include #include +#include "ptrace.h" +#include "signal.h" +#include "asm/parasite-syscall.h" +#include "asm/dump.h" +#include "restorer.h" +#include "parasite.h" #include "parasite-syscall.h" - +#include "pie-relocs.h" +#include "parasite-blob.h" +#include "sigframe.h" #include "log.h" #include "infect.h" #include "infect-priv.h" +/* XXX will be removed soon */ +extern int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m); + #define PTRACE_EVENT_STOP 128 #ifndef SECCOMP_MODE_DISABLED @@ -230,3 +241,289 @@ err: return -1; } +static int gen_parasite_saddr(struct sockaddr_un *saddr, int key) +{ + int sun_len; + + saddr->sun_family = AF_UNIX; + snprintf(saddr->sun_path, UNIX_PATH_MAX, + "X/crtools-pr-%d", key); + + sun_len = SUN_LEN(saddr); + *saddr->sun_path = '\0'; + + return sun_len; +} + +static int prepare_tsock(struct parasite_ctl *ctl, pid_t pid, + struct parasite_init_args *args) +{ + static int ssock = -1; + + pr_info("Putting tsock into pid %d\n", pid); + args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid()); + + if (ssock == -1) { + ssock = *ctl->ictx.p_sock; + if (ssock == -1) { + pr_err("No socket in ictx\n"); + goto err; + } + + *ctl->ictx.p_sock = -1; + + if (bind(ssock, (struct sockaddr *)&args->h_addr, args->h_addr_len) < 0) { + pr_perror("Can't bind socket"); + goto err; + } + + if (listen(ssock, 1)) { + pr_perror("Can't listen on transport socket"); + goto err; + } + } + + /* Check a case when parasite can't initialize a command socket */ + if (ctl->ictx.flags & INFECT_FAIL_CONNECT) + args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid() + 1); + + /* + * Set to -1 to prevent any accidental misuse. The + * only valid user of it is accept_tsock(). + */ + ctl->tsock = -ssock; + return 0; +err: + close_safe(&ssock); + return -1; +} + +static int setup_child_handler(struct parasite_ctl *ctl) +{ + struct sigaction sa = { + .sa_sigaction = ctl->ictx.child_handler, + .sa_flags = SA_SIGINFO | SA_RESTART, + }; + + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGCHLD); + if (sigaction(SIGCHLD, &sa, NULL)) { + pr_perror("Unable to setup SIGCHLD handler"); + return -1; + } + + return 0; +} + +int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack, + user_regs_struct_t *regs, struct thread_ctx *octx) +{ + k_rtsigset_t block; + + ksigfillset(&block); + if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &block)) { + pr_perror("Can't block signals for %d", pid); + goto err_sig; + } + + parasite_setup_regs(ip, stack, regs); + if (ptrace_set_regs(pid, regs)) { + pr_perror("Can't set registers for %d", pid); + goto err_regs; + } + + if (ptrace(cmd, pid, NULL, NULL)) { + pr_perror("Can't run parasite at %d", pid); + goto err_cont; + } + + return 0; + +err_cont: + if (ptrace_set_regs(pid, &octx->regs)) + pr_perror("Can't restore regs for %d", pid); +err_regs: + if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &octx->sigmask)) + pr_perror("Can't restore sigmask for %d", pid); +err_sig: + return -1; +} + +static int accept_tsock(struct parasite_ctl *ctl) +{ + int sock; + int ask = -ctl->tsock; /* this '-' is explained above */ + + sock = accept(ask, NULL, 0); + if (sock < 0) { + pr_perror("Can't accept connection to the transport socket"); + close(ask); + return -1; + } + + ctl->tsock = sock; + return 0; +} + +static int parasite_init_daemon(struct parasite_ctl *ctl) +{ + struct parasite_init_args *args; + pid_t pid = ctl->rpid; + user_regs_struct_t regs; + struct ctl_msg m = { }; + + *ctl->addr_cmd = PARASITE_CMD_INIT_DAEMON; + + args = parasite_args(ctl, struct parasite_init_args); + + args->sigframe = (uintptr_t)ctl->rsigframe; + args->log_level = log_get_loglevel(); + + futex_set(&args->daemon_connected, 0); + + if (prepare_tsock(ctl, pid, args)) + goto err; + + /* after this we can catch parasite errors in chld handler */ + if (setup_child_handler(ctl)) + goto err; + + regs = ctl->orig.regs; + if (parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, ctl->rstack, ®s, &ctl->orig)) + goto err; + + futex_wait_while_eq(&args->daemon_connected, 0); + if (futex_get(&args->daemon_connected) != 1) { + errno = -(int)futex_get(&args->daemon_connected); + pr_perror("Unable to connect a transport socket"); + goto err; + } + + if (accept_tsock(ctl) < 0) + goto err; + + if (parasite_send_fd(ctl, log_get_fd())) + goto err; + + pr_info("Wait for parasite being daemonized...\n"); + + if (parasite_wait_ack(ctl->tsock, PARASITE_CMD_INIT_DAEMON, &m)) { + pr_err("Can't switch parasite %d to daemon mode %d\n", + pid, m.err); + goto err; + } + + ctl->sigreturn_addr = args->sigreturn_addr; + ctl->daemonized = true; + pr_info("Parasite %d has been switched to daemon mode\n", pid); + return 0; +err: + return -1; +} + +static int parasite_start_daemon(struct parasite_ctl *ctl) +{ + pid_t pid = ctl->rpid; + struct infect_ctx *ictx = &ctl->ictx; + + /* + * Get task registers before going daemon, since the + * get_task_regs needs to call ptrace on _stopped_ task, + * while in daemon it is not such. + */ + + if (get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) { + pr_err("Can't obtain regs for thread %d\n", pid); + return -1; + } + + if (ictx->make_sigframe(ictx->regs_arg, ctl->sigframe, ctl->rsigframe, &ctl->orig.sigmask)) + return -1; + + if (parasite_init_daemon(ctl)) + return -1; + + return 0; +} + +#define init_parasite_ctl(ctl, blob_type) \ + do { \ + memcpy(ctl->local_map, parasite_##blob_type##_blob, \ + sizeof(parasite_##blob_type##_blob)); \ + ELF_RELOCS_APPLY(parasite_##blob_type, \ + ctl->local_map, ctl->remote_map); \ + /* Setup the rest of a control block */ \ + ctl->parasite_ip = (unsigned long)parasite_sym(ctl->remote_map, \ + blob_type, __export_parasite_head_start); \ + ctl->addr_cmd = parasite_sym(ctl->local_map, blob_type, \ + __export_parasite_cmd); \ + ctl->addr_args = parasite_sym(ctl->local_map, blob_type, \ + __export_parasite_args); \ + } while (0) + +int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size) +{ + int ret; + unsigned long p, map_exchange_size, parasite_size = 0; + + if (!arch_can_dump_task(ctl)) + goto err; + + /* + * Inject a parasite engine. Ie allocate memory inside alien + * space and copy engine code there. Then re-map the engine + * locally, so we will get an easy way to access engine memory + * without using ptrace at all. + */ + + if (seized_native(ctl)) + parasite_size = pie_size(parasite_native); +#ifdef CONFIG_COMPAT + else + parasite_size = pie_size(parasite_compat); +#endif + + ctl->args_size = round_up(args_size, PAGE_SIZE); + parasite_size += ctl->args_size; + + map_exchange_size = parasite_size; + map_exchange_size += RESTORE_STACK_SIGFRAME + PARASITE_STACK_SIZE; + if (nr_threads > 1) + map_exchange_size += PARASITE_STACK_SIZE; + + ret = parasite_map_exchange(ctl, map_exchange_size); + if (ret) + goto err; + + pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map); + + if (seized_native(ctl)) + init_parasite_ctl(ctl, native); +#ifdef CONFIG_COMPAT + else + init_parasite_ctl(ctl, compat); +#endif + + p = parasite_size; + + ctl->rsigframe = ctl->remote_map + p; + ctl->sigframe = ctl->local_map + p; + + p += RESTORE_STACK_SIGFRAME; + p += PARASITE_STACK_SIZE; + ctl->rstack = ctl->remote_map + p; + + if (nr_threads > 1) { + p += PARASITE_STACK_SIZE; + ctl->r_thread_stack = ctl->remote_map + p; + } + + if (parasite_start_daemon(ctl)) + goto err; + + return 0; + +err: + return -1; +} + diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index bbc9a9378..62841a2aa 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -16,7 +16,6 @@ #include "imgset.h" #include "ptrace.h" #include "parasite-syscall.h" -#include "parasite-blob.h" #include "parasite.h" #include "crtools.h" #include "namespaces.h" @@ -42,6 +41,7 @@ #include "restorer.h" #include "pie/pie-relocs.h" +#include "infect.h" #include "infect-priv.h" #define MEMFD_FNAME "CRIUMFD" @@ -126,39 +126,6 @@ bool seized_native(struct parasite_ctl *ctl) { return user_regs_native(&ctl->orig.regs); } -static int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack, - user_regs_struct_t *regs, struct thread_ctx *octx) -{ - k_rtsigset_t block; - - ksigfillset(&block); - if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &block)) { - pr_perror("Can't block signals for %d", pid); - goto err_sig; - } - - parasite_setup_regs(ip, stack, regs); - if (ptrace_set_regs(pid, regs)) { - pr_perror("Can't set registers for %d", pid); - goto err_regs; - } - - if (ptrace(cmd, pid, NULL, NULL)) { - pr_perror("Can't run parasite at %d", pid); - goto err_cont; - } - - return 0; - -err_cont: - if (ptrace_set_regs(pid, &octx->regs)) - pr_perror("Can't restore regs for %d", pid); -err_regs: - if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &octx->sigmask)) - pr_perror("Can't restore sigmask for %d", pid); -err_sig: - return -1; -} /* we run at @regs->ip */ static int parasite_trap(struct parasite_ctl *ctl, pid_t pid, @@ -296,7 +263,7 @@ static int __parasite_send_cmd(int sockfd, struct ctl_msg *m) return 0; } -static int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m) +int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m) { int ret; @@ -364,20 +331,6 @@ int parasite_execute_daemon(unsigned int cmd, struct parasite_ctl *ctl) return ret; } -static int gen_parasite_saddr(struct sockaddr_un *saddr, int key) -{ - int sun_len; - - saddr->sun_family = AF_UNIX; - snprintf(saddr->sun_path, UNIX_PATH_MAX, - "X/crtools-pr-%d", key); - - sun_len = SUN_LEN(saddr); - *saddr->sun_path = '\0'; - - return sun_len; -} - int parasite_send_fd(struct parasite_ctl *ctl, int fd) { if (send_fd(ctl->tsock, NULL, 0, fd) < 0) { @@ -418,23 +371,6 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) exit(1); } -static int setup_child_handler(struct parasite_ctl *ctl) -{ - struct sigaction sa = { - .sa_sigaction = ctl->ictx.child_handler, - .sa_flags = SA_SIGINFO | SA_RESTART, - }; - - sigemptyset(&sa.sa_mask); - sigaddset(&sa.sa_mask, SIGCHLD); - if (sigaction(SIGCHLD, &sa, NULL)) { - pr_perror("Unable to setup SIGCHLD handler"); - return -1; - } - - return 0; -} - static int restore_child_handler() { struct sigaction sa = { @@ -452,121 +388,6 @@ static int restore_child_handler() return 0; } -static int prepare_tsock(struct parasite_ctl *ctl, pid_t pid, - struct parasite_init_args *args) -{ - static int ssock = -1; - - pr_info("Putting tsock into pid %d\n", pid); - args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid()); - - if (ssock == -1) { - ssock = *ctl->ictx.p_sock; - if (ssock == -1) { - pr_err("No socket in ictx\n"); - goto err; - } - - *ctl->ictx.p_sock = -1; - - if (bind(ssock, (struct sockaddr *)&args->h_addr, args->h_addr_len) < 0) { - pr_perror("Can't bind socket"); - goto err; - } - - if (listen(ssock, 1)) { - pr_perror("Can't listen on transport socket"); - goto err; - } - } - - /* Check a case when parasite can't initialize a command socket */ - if (ctl->ictx.flags & INFECT_FAIL_CONNECT) - args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid() + 1); - - /* - * Set to -1 to prevent any accidental misuse. The - * only valid user of it is accept_tsock(). - */ - ctl->tsock = -ssock; - return 0; -err: - close_safe(&ssock); - return -1; -} - -static int accept_tsock(struct parasite_ctl *ctl) -{ - int sock; - int ask = -ctl->tsock; /* this '-' is explained above */ - - sock = accept(ask, NULL, 0); - if (sock < 0) { - pr_perror("Can't accept connection to the transport socket"); - close(ask); - return -1; - } - - ctl->tsock = sock; - return 0; -} - -static int parasite_init_daemon(struct parasite_ctl *ctl) -{ - struct parasite_init_args *args; - pid_t pid = ctl->rpid; - user_regs_struct_t regs; - struct ctl_msg m = { }; - - *ctl->addr_cmd = PARASITE_CMD_INIT_DAEMON; - - args = parasite_args(ctl, struct parasite_init_args); - - args->sigframe = (uintptr_t)ctl->rsigframe; - args->log_level = log_get_loglevel(); - - futex_set(&args->daemon_connected, 0); - - if (prepare_tsock(ctl, pid, args)) - goto err; - - /* after this we can catch parasite errors in chld handler */ - if (setup_child_handler(ctl)) - goto err; - - regs = ctl->orig.regs; - if (parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, ctl->rstack, ®s, &ctl->orig)) - goto err; - - futex_wait_while_eq(&args->daemon_connected, 0); - if (futex_get(&args->daemon_connected) != 1) { - errno = -(int)futex_get(&args->daemon_connected); - pr_perror("Unable to connect a transport socket"); - goto err; - } - - if (accept_tsock(ctl) < 0) - goto err; - - if (parasite_send_fd(ctl, log_get_fd())) - goto err; - - pr_info("Wait for parasite being daemonized...\n"); - - if (parasite_wait_ack(ctl->tsock, PARASITE_CMD_INIT_DAEMON, &m)) { - pr_err("Can't switch parasite %d to daemon mode %d\n", - pid, m.err); - goto err; - } - - ctl->sigreturn_addr = args->sigreturn_addr; - ctl->daemonized = true; - pr_info("Parasite %d has been switched to daemon mode\n", pid); - return 0; -err: - return -1; -} - static int alloc_groups_copy_creds(CredsEntry *ce, struct parasite_dump_creds *c) { BUILD_BUG_ON(sizeof(ce->groups[0]) != sizeof(c->groups[0])); @@ -1426,53 +1247,11 @@ void parasite_ensure_args_size(unsigned long sz) parasite_args_size = sz; } -static int parasite_start_daemon(struct parasite_ctl *ctl) -{ - pid_t pid = ctl->rpid; - struct infect_ctx *ictx = &ctl->ictx; - - /* - * Get task registers before going daemon, since the - * get_task_regs needs to call ptrace on _stopped_ task, - * while in daemon it is not such. - */ - - if (get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) { - pr_err("Can't obtain regs for thread %d\n", pid); - return -1; - } - - if (ictx->make_sigframe(ictx->regs_arg, ctl->sigframe, ctl->rsigframe, &ctl->orig.sigmask)) - return -1; - - if (parasite_init_daemon(ctl)) - return -1; - - return 0; -} - -#define init_parasite_ctl(ctl, blob_type) \ - do { \ - memcpy(ctl->local_map, parasite_##blob_type##_blob, \ - sizeof(parasite_##blob_type##_blob)); \ - ELF_RELOCS_APPLY(parasite_##blob_type, \ - ctl->local_map, ctl->remote_map); \ - /* Setup the rest of a control block */ \ - ctl->parasite_ip = (unsigned long)parasite_sym(ctl->remote_map, \ - blob_type, __export_parasite_head_start); \ - ctl->addr_cmd = parasite_sym(ctl->local_map, blob_type, \ - __export_parasite_cmd); \ - ctl->addr_args = parasite_sym(ctl->local_map, blob_type, \ - __export_parasite_args); \ - } while (0) - static int make_sigframe(void *arg, struct rt_sigframe *sf, struct rt_sigframe *rtsf, k_rtsigset_t *bs) { return construct_sigframe(sf, rtsf, bs, (CoreEntry *)arg); } -static int infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size); - struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, struct vm_area_list *vma_area_list) { @@ -1507,7 +1286,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, parasite_ensure_args_size(dump_pages_args_size(vma_area_list)); parasite_ensure_args_size(aio_rings_args_size(vma_area_list)); - if (infect(ctl, item->nr_threads, parasite_args_size) < 0) { + if (compel_infect(ctl, item->nr_threads, parasite_args_size) < 0) { parasite_cure_seized(ctl); return NULL; } @@ -1519,72 +1298,6 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, return ctl; } -static int infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size) -{ - int ret; - unsigned long p, map_exchange_size, parasite_size = 0; - - if (!arch_can_dump_task(ctl)) - goto err; - - /* - * Inject a parasite engine. Ie allocate memory inside alien - * space and copy engine code there. Then re-map the engine - * locally, so we will get an easy way to access engine memory - * without using ptrace at all. - */ - - if (seized_native(ctl)) - parasite_size = pie_size(parasite_native); -#ifdef CONFIG_COMPAT - else - parasite_size = pie_size(parasite_compat); -#endif - - ctl->args_size = round_up(args_size, PAGE_SIZE); - parasite_size += ctl->args_size; - - map_exchange_size = parasite_size; - map_exchange_size += RESTORE_STACK_SIGFRAME + PARASITE_STACK_SIZE; - if (nr_threads > 1) - map_exchange_size += PARASITE_STACK_SIZE; - - ret = parasite_map_exchange(ctl, map_exchange_size); - if (ret) - goto err; - - pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map); - - if (seized_native(ctl)) - init_parasite_ctl(ctl, native); -#ifdef CONFIG_COMPAT - else - init_parasite_ctl(ctl, compat); -#endif - - p = parasite_size; - - ctl->rsigframe = ctl->remote_map + p; - ctl->sigframe = ctl->local_map + p; - - p += RESTORE_STACK_SIGFRAME; - p += PARASITE_STACK_SIZE; - ctl->rstack = ctl->remote_map + p; - - if (nr_threads > 1) { - p += PARASITE_STACK_SIZE; - ctl->r_thread_stack = ctl->remote_map + p; - } - - if (parasite_start_daemon(ctl)) - goto err; - - return 0; - -err: - return -1; -} - int ptrace_stop_pie(pid_t pid, void *addr, enum trace_flags *tf) { int ret; From e156ab5a62c4e8f43945ce43ffd386fdff5b9574 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 28 Sep 2016 11:50:25 +0300 Subject: [PATCH 0149/4375] infect: Move parasite_prep_ctl into infect.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-exec.c | 2 +- criu/cr-restore.c | 2 +- criu/include/infect.h | 3 ++ criu/include/parasite-syscall.h | 1 - criu/infect.c | 47 +++++++++++++++++++++++++++++++ criu/parasite-syscall.c | 49 ++------------------------------- 6 files changed, 54 insertions(+), 50 deletions(-) diff --git a/criu/cr-exec.c b/criu/cr-exec.c index 4762a8b90..e5609abb0 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -169,7 +169,7 @@ int cr_exec(int pid, char **opt) goto out_unseize; } - ctl = parasite_prep_ctl(pid); + ctl = compel_prepare(pid); if (!ctl) { pr_err("Can't prep ctl %d\n", pid); goto out_unseize; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 88ca34e57..503d32f64 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1654,7 +1654,7 @@ static void finalize_restore(void) continue; /* Unmap the restorer blob */ - ctl = parasite_prep_ctl(pid); + ctl = compel_prepare(pid); if (ctl == NULL) continue; diff --git a/criu/include/infect.h b/criu/include/infect.h index 9cfbfe084..fa6dac88c 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -24,7 +24,10 @@ extern int compel_wait_task(int pid, int ppid, #define TASK_ZOMBIE 0x6 struct parasite_ctl; +struct thread_ctx; +extern struct parasite_ctl *compel_prepare(int pid); extern int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size); +extern int compel_prepare_thread(int pid, struct thread_ctx *ctx); #endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 65d4217c2..9e151df87 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -98,7 +98,6 @@ extern struct parasite_ctl *parasite_infect_seized(pid_t pid, struct vm_area_list *vma_area_list); extern void parasite_ensure_args_size(unsigned long sz); extern unsigned long get_exec_start(struct vm_area_list *); -extern struct parasite_ctl *parasite_prep_ctl(pid_t pid); extern int parasite_map_exchange(struct parasite_ctl *ctl, unsigned long size); extern int parasite_dump_cgroup(struct parasite_ctl *ctl, struct parasite_dump_cgroup_args *cgroup); diff --git a/criu/infect.c b/criu/infect.c index 3fc89df5d..4668884de 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -20,6 +20,9 @@ #include "infect.h" #include "infect-priv.h" +#define MEMFD_FNAME "CRIUMFD" +#define MEMFD_FNAME_SZ sizeof(MEMFD_FNAME) + /* XXX will be removed soon */ extern int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m); @@ -527,3 +530,47 @@ err: return -1; } +int compel_prepare_thread(int pid, struct thread_ctx *ctx) +{ + if (ptrace(PTRACE_GETSIGMASK, pid, sizeof(k_rtsigset_t), &ctx->sigmask)) { + pr_perror("can't get signal blocking mask for %d", pid); + return -1; + } + + if (ptrace_get_regs(pid, &ctx->regs)) { + pr_perror("Can't obtain registers (pid: %d)", pid); + return -1; + } + + return 0; +} + +struct parasite_ctl *compel_prepare(int pid) +{ + struct parasite_ctl *ctl = NULL; + + /* + * Control block early setup. + */ + ctl = xzalloc(sizeof(*ctl)); + if (!ctl) { + pr_err("Parasite control block allocation failed (pid: %d)\n", pid); + goto err; + } + + ctl->tsock = -1; + + if (compel_prepare_thread(pid, &ctl->orig)) + goto err; + + ctl->rpid = pid; + + BUILD_BUG_ON(PARASITE_START_AREA_MIN < BUILTIN_SYSCALL_SIZE + MEMFD_FNAME_SZ); + + return ctl; + +err: + xfree(ctl); + return NULL; +} + diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 62841a2aa..b1458ec24 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -91,21 +91,6 @@ static inline int ptrace_set_regs(int pid, user_regs_struct_t *regs) } #endif -static int get_thread_ctx(int pid, struct thread_ctx *ctx) -{ - if (ptrace(PTRACE_GETSIGMASK, pid, sizeof(k_rtsigset_t), &ctx->sigmask)) { - pr_perror("can't get signal blocking mask for %d", pid); - return -1; - } - - if (ptrace_get_regs(pid, &ctx->regs)) { - pr_perror("Can't obtain registers (pid: %d)", pid); - return -1; - } - - return 0; -} - static int restore_thread_ctx(int pid, struct thread_ctx *ctx) { int ret = 0; @@ -481,7 +466,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, pc->cap_last_cap = kdat.last_cap; - ret = get_thread_ctx(pid, &octx); + ret = compel_prepare_thread(pid, &octx); if (ret) return -1; @@ -1071,36 +1056,6 @@ err: return ret; } -/* If vma_area_list is NULL, a place for injecting syscall will not be set. */ -struct parasite_ctl *parasite_prep_ctl(pid_t pid) -{ - struct parasite_ctl *ctl = NULL; - - /* - * Control block early setup. - */ - ctl = xzalloc(sizeof(*ctl)); - if (!ctl) { - pr_err("Parasite control block allocation failed (pid: %d)\n", pid); - goto err; - } - - ctl->tsock = -1; - - if (get_thread_ctx(pid, &ctl->orig)) - goto err; - - ctl->rpid = pid; - - BUILD_BUG_ON(PARASITE_START_AREA_MIN < BUILTIN_SYSCALL_SIZE + MEMFD_FNAME_SZ); - - return ctl; - -err: - xfree(ctl); - return NULL; -} - static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size) { int fd; @@ -1266,7 +1221,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, return NULL; } - ctl = parasite_prep_ctl(pid); + ctl = compel_prepare(pid); if (!ctl) return NULL; From 3a53b5892292b0de8dbf5a8acd8b2bdda0236c78 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 28 Sep 2016 12:01:01 +0300 Subject: [PATCH 0150/4375] infect: Move parasite_stop_daemon and parasite_cure_* into infect.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 12 +-- criu/cr-exec.c | 2 +- criu/include/infect.h | 4 + criu/include/parasite-syscall.h | 4 - criu/infect.c | 172 +++++++++++++++++++++++++++++++ criu/parasite-syscall.c | 174 +------------------------------- 6 files changed, 184 insertions(+), 184 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 8d7989c77..546ea4853 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1187,7 +1187,7 @@ static int pre_dump_one_task(struct pstree_item *item) if (ret) goto err_cure; - if (parasite_cure_remote(parasite_ctl)) + if (compel_cure_remote(parasite_ctl)) pr_err("Can't cure (pid: %d) from parasite\n", pid); err_free: free_mappings(&vmas); @@ -1195,7 +1195,7 @@ err: return ret; err_cure: - if (parasite_cure_seized(parasite_ctl)) + if (compel_cure(parasite_ctl)) pr_err("Can't cure (pid: %d) from parasite\n", pid); goto err_free; } @@ -1370,7 +1370,7 @@ static int dump_one_task(struct pstree_item *item) goto err_cure; } - ret = parasite_stop_daemon(parasite_ctl); + ret = compel_stop_daemon(parasite_ctl); if (ret) { pr_err("Can't cure (pid: %d) from parasite\n", pid); goto err; @@ -1382,7 +1382,7 @@ static int dump_one_task(struct pstree_item *item) goto err; } - ret = parasite_cure_seized(parasite_ctl); + ret = compel_cure(parasite_ctl); if (ret) { pr_err("Can't cure (pid: %d) from parasite\n", pid); goto err; @@ -1411,7 +1411,7 @@ err: err_cure: close_cr_imgset(&cr_imgset); err_cure_imgset: - parasite_cure_seized(parasite_ctl); + compel_cure(parasite_ctl); goto err; } @@ -1488,7 +1488,7 @@ static int cr_pre_dump_finish(int ret) timing_stop(TIME_MEMWRITE); destroy_page_pipe(mem_pp); - parasite_cure_local(ctl); + compel_cure_local(ctl); } free_pstree(root_item); diff --git a/criu/cr-exec.c b/criu/cr-exec.c index e5609abb0..6001d0b03 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -191,7 +191,7 @@ int cr_exec(int pid, char **opt) exit_code = 0; out_cure: - parasite_cure_seized(ctl); + compel_cure(ctl); out_unseize: unseize_task(pid, prev_state, prev_state); out: diff --git a/criu/include/infect.h b/criu/include/infect.h index fa6dac88c..1d1a2131b 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -30,4 +30,8 @@ extern struct parasite_ctl *compel_prepare(int pid); extern int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size); extern int compel_prepare_thread(int pid, struct thread_ctx *ctx); +extern int compel_stop_daemon(struct parasite_ctl *ctl); +extern int compel_cure_remote(struct parasite_ctl *ctl); +extern int compel_cure_local(struct parasite_ctl *ctl); +extern int compel_cure(struct parasite_ctl *ctl); #endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 9e151df87..271c05f27 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -90,9 +90,6 @@ extern int parasite_drain_fds_seized(struct parasite_ctl *ctl, int *lfds, struct fd_opts *flags); extern int parasite_get_proc_fd_seized(struct parasite_ctl *ctl); -extern int parasite_cure_remote(struct parasite_ctl *ctl); -extern int parasite_cure_local(struct parasite_ctl *ctl); -extern int parasite_cure_seized(struct parasite_ctl *ctl); extern struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, struct vm_area_list *vma_area_list); @@ -129,7 +126,6 @@ enum trace_flags { TRACE_EXIT, }; -extern int parasite_stop_daemon(struct parasite_ctl *ctl); extern int parasite_stop_on_syscall(int tasks, int sys_nr, int sys_nr_compat, enum trace_flags trace); extern int parasite_unmap(struct parasite_ctl *ctl, unsigned long addr); diff --git a/criu/infect.c b/criu/infect.c index 4668884de..943ff8070 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -318,6 +318,23 @@ static int setup_child_handler(struct parasite_ctl *ctl) return 0; } +static int restore_child_handler() +{ + struct sigaction sa = { + .sa_handler = SIG_DFL, /* XXX -- should be original? */ + .sa_flags = SA_SIGINFO | SA_RESTART, + }; + + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGCHLD); + if (sigaction(SIGCHLD, &sa, NULL)) { + pr_perror("Unable to setup SIGCHLD handler"); + return -1; + } + + return 0; +} + int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack, user_regs_struct_t *regs, struct thread_ctx *octx) { @@ -574,3 +591,158 @@ err: return NULL; } +static bool task_in_parasite(struct parasite_ctl *ctl, user_regs_struct_t *regs) +{ + void *addr = (void *) REG_IP(*regs); + return addr >= ctl->remote_map && + addr < ctl->remote_map + ctl->map_length; +} + +static int parasite_fini_seized(struct parasite_ctl *ctl) +{ + pid_t pid = ctl->rpid; + user_regs_struct_t regs; + int status, ret = 0; + enum trace_flags flag; + + /* stop getting chld from parasite -- we're about to step-by-step it */ + if (restore_child_handler()) + return -1; + + /* Start to trace syscalls for each thread */ + if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) { + pr_perror("Unable to interrupt the process"); + return -1; + } + + pr_debug("Waiting for %d to trap\n", pid); + if (wait4(pid, &status, __WALL, NULL) != pid) { + pr_perror("Waited pid mismatch (pid: %d)", pid); + return -1; + } + + pr_debug("Daemon %d exited trapping\n", pid); + if (!WIFSTOPPED(status)) { + pr_err("Task is still running (pid: %d)\n", pid); + return -1; + } + + ret = ptrace_get_regs(pid, ®s); + if (ret) { + pr_perror("Unable to get registers"); + return -1; + } + + if (!task_in_parasite(ctl, ®s)) { + pr_err("The task is not in parasite code\n"); + return -1; + } + + ret = __parasite_execute_daemon(PARASITE_CMD_FINI, ctl); + close_safe(&ctl->tsock); + if (ret) + return -1; + + /* Go to sigreturn as closer as we can */ + ret = ptrace_stop_pie(pid, ctl->sigreturn_addr, &flag); + if (ret < 0) + return ret; + + if (parasite_stop_on_syscall(1, __NR(rt_sigreturn, 0), + __NR(rt_sigreturn, 1), flag)) + return -1; + + if (ptrace_flush_breakpoints(pid)) + return -1; + + /* + * All signals are unblocked now. The kernel notifies about leaving + * syscall before starting to deliver signals. All parasite code are + * executed with blocked signals, so we can sefly unmap a parasite blob. + */ + + return 0; +} + +int compel_stop_daemon(struct parasite_ctl *ctl) +{ + if (ctl->daemonized) { + /* + * Looks like a previous attempt failed, we should do + * nothing in this case. parasite will try to cure itself. + */ + if (ctl->tsock < 0) + return -1; + + if (parasite_fini_seized(ctl)) { + close_safe(&ctl->tsock); + return -1; + } + } + + ctl->daemonized = false; + + return 0; +} + +int compel_cure_remote(struct parasite_ctl *ctl) +{ + if (compel_stop_daemon(ctl)) + return -1; + + if (!ctl->remote_map) + return 0; + + /* Unseizing task with parasite -- it does it himself */ + if (ctl->addr_cmd) { + struct parasite_unmap_args *args; + + *ctl->addr_cmd = PARASITE_CMD_UNMAP; + + args = parasite_args(ctl, struct parasite_unmap_args); + args->parasite_start = ctl->remote_map; + args->parasite_len = ctl->map_length; + if (parasite_unmap(ctl, ctl->parasite_ip)) + return -1; + } else { + unsigned long ret; + + syscall_seized(ctl, __NR(munmap, !seized_native(ctl)), &ret, + (unsigned long)ctl->remote_map, ctl->map_length, + 0, 0, 0, 0); + if (ret) { + pr_err("munmap for remote map %p, %lu returned %lu\n", + ctl->remote_map, ctl->map_length, ret); + return -1; + } + } + + return 0; +} + +int compel_cure_local(struct parasite_ctl *ctl) +{ + int ret = 0; + + if (ctl->local_map) { + if (munmap(ctl->local_map, ctl->map_length)) { + pr_err("munmap failed (pid: %d)\n", ctl->rpid); + ret = -1; + } + } + + free(ctl); + return ret; +} + +int compel_cure(struct parasite_ctl *ctl) +{ + int ret; + + ret = compel_cure_remote(ctl); + if (!ret) + ret = compel_cure_local(ctl); + + return ret; +} + diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index b1458ec24..71f20be49 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -356,23 +356,6 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) exit(1); } -static int restore_child_handler() -{ - struct sigaction sa = { - .sa_handler = SIG_DFL, - .sa_flags = SA_SIGINFO | SA_RESTART, - }; - - sigemptyset(&sa.sa_mask); - sigaddset(&sa.sa_mask, SIGCHLD); - if (sigaction(SIGCHLD, &sa, NULL)) { - pr_perror("Unable to setup SIGCHLD handler"); - return -1; - } - - return 0; -} - static int alloc_groups_copy_creds(CredsEntry *ce, struct parasite_dump_creds *c) { BUILD_BUG_ON(sizeof(ce->groups[0]) != sizeof(c->groups[0])); @@ -766,79 +749,6 @@ int parasite_get_proc_fd_seized(struct parasite_ctl *ctl) /* This is officially the 50000'th line in the CRIU source code */ -static bool task_in_parasite(struct parasite_ctl *ctl, user_regs_struct_t *regs) -{ - void *addr = (void *) REG_IP(*regs); - return addr >= ctl->remote_map && - addr < ctl->remote_map + ctl->map_length; -} - -static int parasite_fini_seized(struct parasite_ctl *ctl) -{ - pid_t pid = ctl->rpid; - user_regs_struct_t regs; - int status, ret = 0; - enum trace_flags flag; - - /* stop getting chld from parasite -- we're about to step-by-step it */ - if (restore_child_handler()) - return -1; - - /* Start to trace syscalls for each thread */ - if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) { - pr_perror("Unable to interrupt the process"); - return -1; - } - - pr_debug("Waiting for %d to trap\n", pid); - if (wait4(pid, &status, __WALL, NULL) != pid) { - pr_perror("Waited pid mismatch (pid: %d)", pid); - return -1; - } - - pr_debug("Daemon %d exited trapping\n", pid); - if (!WIFSTOPPED(status)) { - pr_err("Task is still running (pid: %d)\n", pid); - return -1; - } - - ret = ptrace_get_regs(pid, ®s); - if (ret) { - pr_perror("Unable to get registers"); - return -1; - } - - if (!task_in_parasite(ctl, ®s)) { - pr_err("The task is not in parasite code\n"); - return -1; - } - - ret = __parasite_execute_daemon(PARASITE_CMD_FINI, ctl); - close_safe(&ctl->tsock); - if (ret) - return -1; - - /* Go to sigreturn as closer as we can */ - ret = ptrace_stop_pie(pid, ctl->sigreturn_addr, &flag); - if (ret < 0) - return ret; - - if (parasite_stop_on_syscall(1, __NR(rt_sigreturn, 0), - __NR(rt_sigreturn, 1), flag)) - return -1; - - if (ptrace_flush_breakpoints(pid)) - return -1; - - /* - * All signals are unblocked now. The kernel notifies about leaving - * syscall before starting to deliver signals. All parasite code are - * executed with blocked signals, so we can sefly unmap a parasite blob. - */ - - return 0; -} - static bool task_is_trapped(int status, pid_t pid) { if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) @@ -950,88 +860,6 @@ goon: return 0; } -int parasite_stop_daemon(struct parasite_ctl *ctl) -{ - if (ctl->daemonized) { - /* - * Looks like a previous attempt failed, we should do - * nothing in this case. parasite will try to cure itself. - */ - if (ctl->tsock < 0) - return -1; - - if (parasite_fini_seized(ctl)) { - close_safe(&ctl->tsock); - return -1; - } - } - - ctl->daemonized = false; - - return 0; -} - -int parasite_cure_remote(struct parasite_ctl *ctl) -{ - if (parasite_stop_daemon(ctl)) - return -1; - - if (!ctl->remote_map) - return 0; - - /* Unseizing task with parasite -- it does it himself */ - if (ctl->addr_cmd) { - struct parasite_unmap_args *args; - - *ctl->addr_cmd = PARASITE_CMD_UNMAP; - - args = parasite_args(ctl, struct parasite_unmap_args); - args->parasite_start = ctl->remote_map; - args->parasite_len = ctl->map_length; - if (parasite_unmap(ctl, ctl->parasite_ip)) - return -1; - } else { - unsigned long ret; - - syscall_seized(ctl, __NR(munmap, !seized_native(ctl)), &ret, - (unsigned long)ctl->remote_map, ctl->map_length, - 0, 0, 0, 0); - if (ret) { - pr_err("munmap for remote map %p, %lu returned %lu\n", - ctl->remote_map, ctl->map_length, ret); - return -1; - } - } - - return 0; -} - -int parasite_cure_local(struct parasite_ctl *ctl) -{ - int ret = 0; - - if (ctl->local_map) { - if (munmap(ctl->local_map, ctl->map_length)) { - pr_err("munmap failed (pid: %d)\n", ctl->rpid); - ret = -1; - } - } - - free(ctl); - return ret; -} - -int parasite_cure_seized(struct parasite_ctl *ctl) -{ - int ret; - - ret = parasite_cure_remote(ctl); - if (!ret) - ret = parasite_cure_local(ctl); - - return ret; -} - /* * parasite_unmap() is used for unmapping parasite and restorer blobs. * A blob can contain code for unmapping itself, so the porcess is @@ -1242,7 +1070,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, parasite_ensure_args_size(aio_rings_args_size(vma_area_list)); if (compel_infect(ctl, item->nr_threads, parasite_args_size) < 0) { - parasite_cure_seized(ctl); + compel_cure(ctl); return NULL; } From d4b415eb861bdbfe410ba285d1a342e4e7e58e7b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 28 Sep 2016 12:12:09 +0300 Subject: [PATCH 0151/4375] infect: Move parasite_args* into infect.c This is the code that lets caller place arguments into memory shared between parasite and compel (or caller). Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/aio.c | 3 ++- criu/cr-dump.c | 2 ++ criu/include/infect.h | 13 ++++++++++++ criu/include/parasite-syscall.h | 10 --------- criu/include/parasite.h | 3 +-- criu/infect.c | 15 +++++++++++-- criu/mem.c | 3 ++- criu/parasite-syscall.c | 37 ++++++++++++--------------------- criu/vdso.c | 3 ++- 9 files changed, 48 insertions(+), 41 deletions(-) diff --git a/criu/aio.c b/criu/aio.c index 540fe641c..c031e3919 100644 --- a/criu/aio.c +++ b/criu/aio.c @@ -11,6 +11,7 @@ #include "parasite.h" #include "parasite-syscall.h" #include "images/mm.pb-c.h" +#include "infect.h" #define NR_IOEVENTS_IN_NPAGES(npages) ((PAGE_SIZE * npages - sizeof(struct aio_ring)) / sizeof(struct io_event)) @@ -104,7 +105,7 @@ int parasite_collect_aios(struct parasite_ctl *ctl, struct vm_area_list *vmas) * creation. */ - aa = parasite_args_s(ctl, aio_rings_args_size(vmas)); + aa = compel_parasite_args_s(ctl, aio_rings_args_size(vmas)); pa = &aa->ring[0]; list_for_each_entry(vma, &vmas->h, list) { if (!vma_area_is(vma, VMA_AREA_AIORING)) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 546ea4853..e6575ea51 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -720,6 +720,8 @@ static int dump_task_core_all(struct parasite_ctl *ctl, struct proc_status_creds *creds; struct parasite_dump_cgroup_args cgroup_args, *info = NULL; + BUILD_BUG_ON(sizeof(cgroup_args) < PARASITE_ARG_SIZE_MIN); + pr_info("\n"); pr_info("Dumping core (pid: %d)\n", pid); pr_info("----------------------------------------\n"); diff --git a/criu/include/infect.h b/criu/include/infect.h index 1d1a2131b..5ab38425f 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -34,4 +34,17 @@ extern int compel_stop_daemon(struct parasite_ctl *ctl); extern int compel_cure_remote(struct parasite_ctl *ctl); extern int compel_cure_local(struct parasite_ctl *ctl); extern int compel_cure(struct parasite_ctl *ctl); + +#define PARASITE_ARG_SIZE_MIN ( 1 << 12) + +#define compel_parasite_args(ctl, type) \ + ({ \ + void *___ret; \ + BUILD_BUG_ON(sizeof(type) > PARASITE_ARG_SIZE_MIN); \ + ___ret = compel_parasite_args_p(ctl); \ + ___ret; \ + }) + +extern void *compel_parasite_args_p(struct parasite_ctl *ctl); +extern void *compel_parasite_args_s(struct parasite_ctl *ctl, int args_size); #endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 271c05f27..ec4bef4d6 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -55,16 +55,6 @@ struct proc_posix_timers_stat; extern int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, struct parasite_ctl *ctl, struct pstree_item *); -#define parasite_args(ctl, type) \ - ({ \ - void *___ret; \ - BUILD_BUG_ON(sizeof(type) > PARASITE_ARG_SIZE_MIN); \ - ___ret = parasite_args_p(ctl); \ - ___ret; \ - }) - -extern void *parasite_args_p(struct parasite_ctl *ctl); -extern void *parasite_args_s(struct parasite_ctl *ctl, int args_size); extern int parasite_send_fd(struct parasite_ctl *ctl, int fd); /* diff --git a/criu/include/parasite.h b/criu/include/parasite.h index 965b1dcf3..af7b7c10d 100644 --- a/criu/include/parasite.h +++ b/criu/include/parasite.h @@ -2,7 +2,6 @@ #define __CR_PARASITE_H__ #define PARASITE_STACK_SIZE (16 << 10) -#define PARASITE_ARG_SIZE_MIN ( 1 << 12) #define PARASITE_START_AREA_MIN (4096) #define PARASITE_MAX_SIZE (64 << 10) @@ -272,7 +271,7 @@ struct parasite_dump_cgroup_args { * * The string is null terminated. */ - char contents[PARASITE_ARG_SIZE_MIN]; + char contents[1 << 12]; }; /* the parasite prefix is added by gen_offsets.sh */ diff --git a/criu/infect.c b/criu/infect.c index 943ff8070..c65aa4237 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -394,7 +394,7 @@ static int parasite_init_daemon(struct parasite_ctl *ctl) *ctl->addr_cmd = PARASITE_CMD_INIT_DAEMON; - args = parasite_args(ctl, struct parasite_init_args); + args = compel_parasite_args(ctl, struct parasite_init_args); args->sigframe = (uintptr_t)ctl->rsigframe; args->log_level = log_get_loglevel(); @@ -699,7 +699,7 @@ int compel_cure_remote(struct parasite_ctl *ctl) *ctl->addr_cmd = PARASITE_CMD_UNMAP; - args = parasite_args(ctl, struct parasite_unmap_args); + args = compel_parasite_args(ctl, struct parasite_unmap_args); args->parasite_start = ctl->remote_map; args->parasite_len = ctl->map_length; if (parasite_unmap(ctl, ctl->parasite_ip)) @@ -746,3 +746,14 @@ int compel_cure(struct parasite_ctl *ctl) return ret; } +void *compel_parasite_args_p(struct parasite_ctl *ctl) +{ + return ctl->addr_args; +} + +void *compel_parasite_args_s(struct parasite_ctl *ctl, int args_size) +{ + BUG_ON(args_size > ctl->args_size); + return compel_parasite_args_p(ctl); +} + diff --git a/criu/mem.c b/criu/mem.c index 629e61f53..e881f4938 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -25,6 +25,7 @@ #include "files-reg.h" #include "pagemap-cache.h" #include "fault-injection.h" +#include "infect.h" #include "protobuf.h" #include "images/pagemap.pb-c.h" @@ -188,7 +189,7 @@ static struct parasite_dump_pages_args *prep_dump_pages_args(struct parasite_ctl struct parasite_vma_entry *p_vma; struct vma_area *vma; - args = parasite_args_s(ctl, dump_pages_args_size(vma_area_list)); + args = compel_parasite_args_s(ctl, dump_pages_args_size(vma_area_list)); p_vma = pargs_vmas(args); args->nr_vmas = 0; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 71f20be49..6a8268230 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -197,17 +197,6 @@ int __parasite_execute_syscall(struct parasite_ctl *ctl, return err; } -void *parasite_args_p(struct parasite_ctl *ctl) -{ - return ctl->addr_args; -} - -void *parasite_args_s(struct parasite_ctl *ctl, int args_size) -{ - BUG_ON(args_size > ctl->args_size); - return parasite_args_p(ctl); -} - static int parasite_run_in_thread(pid_t pid, unsigned int cmd, struct parasite_ctl *ctl, struct thread_ctx *octx) @@ -400,10 +389,10 @@ int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEn int ret; if (seized_native(ctl)) { - args = parasite_args(ctl, struct parasite_dump_thread); + args = compel_parasite_args(ctl, struct parasite_dump_thread); pc = args->creds; } else { - args_c = parasite_args(ctl, struct parasite_dump_thread_compat); + args_c = compel_parasite_args(ctl, struct parasite_dump_thread_compat); pc = args_c->creds; } @@ -440,10 +429,10 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, BUG_ON(id == 0); /* Leader is dumped in dump_task_core_all */ if (seized_native(ctl)) { - args = parasite_args(ctl, struct parasite_dump_thread); + args = compel_parasite_args(ctl, struct parasite_dump_thread); pc = args->creds; } else { - args_c = parasite_args(ctl, struct parasite_dump_thread_compat); + args_c = compel_parasite_args(ctl, struct parasite_dump_thread_compat); pc = args_c->creds; } @@ -503,9 +492,9 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_ bool native_task = seized_native(ctl); if (native_task) - args = parasite_args(ctl, struct parasite_dump_sa_args); + args = compel_parasite_args(ctl, struct parasite_dump_sa_args); else - args_c = parasite_args(ctl, struct parasite_dump_sa_args_compat); + args_c = compel_parasite_args(ctl, struct parasite_dump_sa_args_compat); ret = parasite_execute_daemon(PARASITE_CMD_DUMP_SIGACTS, ctl); if (ret < 0) @@ -555,9 +544,9 @@ int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct pstree_item *i int ret; if (seized_native(ctl)) - args = parasite_args(ctl, struct parasite_dump_itimers_args); + args = compel_parasite_args(ctl, struct parasite_dump_itimers_args); else - args_c = parasite_args(ctl, struct parasite_dump_itimers_args_compat); + args_c = compel_parasite_args(ctl, struct parasite_dump_itimers_args_compat); ret = parasite_execute_daemon(PARASITE_CMD_DUMP_ITIMERS, ctl); if (ret < 0) @@ -646,7 +635,7 @@ int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, args_size = posix_timers_dump_size(proc_args->timer_n); else args_size = posix_timers_compat_dump_size(proc_args->timer_n); - args = parasite_args_s(ctl, args_size); + args = compel_parasite_args_s(ctl, args_size); set_posix_timer_arg(args, ctl, timer_n, proc_args->timer_n); @@ -677,7 +666,7 @@ int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_mis { struct parasite_dump_misc *ma; - ma = parasite_args(ctl, struct parasite_dump_misc); + ma = compel_parasite_args(ctl, struct parasite_dump_misc); if (parasite_execute_daemon(PARASITE_CMD_DUMP_MISC, ctl) < 0) return -1; @@ -689,7 +678,7 @@ struct parasite_tty_args *parasite_dump_tty(struct parasite_ctl *ctl, int fd, in { struct parasite_tty_args *p; - p = parasite_args(ctl, struct parasite_tty_args); + p = compel_parasite_args(ctl, struct parasite_tty_args); p->fd = fd; p->type = type; @@ -707,7 +696,7 @@ int parasite_drain_fds_seized(struct parasite_ctl *ctl, struct parasite_drain_fd *args; size = drain_fds_size(dfds); - args = parasite_args_s(ctl, size); + args = compel_parasite_args_s(ctl, size); args->nr_fds = nr_fds; memcpy(&args->fds, dfds->fds + off, sizeof(int) * nr_fds); @@ -1012,7 +1001,7 @@ int parasite_dump_cgroup(struct parasite_ctl *ctl, struct parasite_dump_cgroup_a int ret; struct parasite_dump_cgroup_args *ca; - ca = parasite_args(ctl, struct parasite_dump_cgroup_args); + ca = compel_parasite_args(ctl, struct parasite_dump_cgroup_args); ret = parasite_execute_daemon(PARASITE_CMD_DUMP_CGROUP, ctl); if (ret) { pr_err("Parasite failed to dump /proc/self/cgroup\n"); diff --git a/criu/vdso.c b/criu/vdso.c index 1d70f8a61..63d32db87 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -19,6 +19,7 @@ #include "log.h" #include "mem.h" #include "vma.h" +#include "infect.h" #ifdef LOG_PREFIX # undef LOG_PREFIX @@ -46,7 +47,7 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct vma_area *vma; off_t off; - args = parasite_args(ctl, struct parasite_vdso_vma_entry); + args = compel_parasite_args(ctl, struct parasite_vdso_vma_entry); if (kdat.pmap == PM_FULL) { BUG_ON(vdso_pfn == VDSO_BAD_PFN); fd = open_proc(pid, "pagemap"); From 93d6aeb862c267f3b215c9deebfe1f8bf3d0c150 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 28 Sep 2016 13:55:21 +0300 Subject: [PATCH 0152/4375] infect: Move parasite_execute_syscall() into infect.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/crtools.c | 3 ++- criu/arch/arm/crtools.c | 3 ++- criu/arch/ppc64/crtools.c | 3 ++- criu/arch/x86/crtools.c | 5 +++-- criu/include/infect.h | 6 ++++++ criu/include/parasite-syscall.h | 2 -- criu/infect.c | 36 +++++++++++++++++++++++++++++++++ criu/parasite-syscall.c | 33 +----------------------------- 8 files changed, 52 insertions(+), 39 deletions(-) diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index 5263dd008..a02b63ac0 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -17,6 +17,7 @@ #include "util.h" #include "cpu.h" #include "restorer.h" +#include "infect.h" #include "infect-priv.h" /* @@ -72,7 +73,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, regs.regs[6] = 0; regs.regs[7] = 0; - err = __parasite_execute_syscall(ctl, ®s, code_syscall); + err = compel_execute_syscall(ctl, ®s, code_syscall); *ret = regs.regs[0]; return err; diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index 6ca2fe386..66a42cada 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -18,6 +18,7 @@ #include "restorer.h" #include "errno.h" #include "kerndat.h" +#include "infect.h" #include "infect-priv.h" /* @@ -74,7 +75,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, regs.ARM_r4 = arg5; regs.ARM_r5 = arg6; - err = __parasite_execute_syscall(ctl, ®s, code_syscall); + err = compel_execute_syscall(ctl, ®s, code_syscall); *ret = regs.ARM_r0; return err; diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index e4a27350c..14d2dc70c 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -18,6 +18,7 @@ #include "util.h" #include "cpu.h" #include "errno.h" +#include "infect.h" #include "infect-priv.h" #include "protobuf.h" @@ -87,7 +88,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, regs.gpr[7] = arg5; regs.gpr[8] = arg6; - err = __parasite_execute_syscall(ctl, ®s, (char*)code_syscall); + err = compel_execute_syscall(ctl, ®s, (char*)code_syscall); *ret = regs.gpr[3]; return err; diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 8059ea22d..535821cb8 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -25,6 +25,7 @@ #include "uapi/std/syscall-codes.h" #include "kerndat.h" #include "infect-priv.h" +#include "infect.h" #include "protobuf.h" #include "images/core.pb-c.h" @@ -167,7 +168,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, r->r8 = arg5; r->r9 = arg6; - err = __parasite_execute_syscall(ctl, ®s, code_syscall); + err = compel_execute_syscall(ctl, ®s, code_syscall); } else { user_regs_struct32 *r = ®s.compat; @@ -179,7 +180,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, r->di = arg5; r->bp = arg6; - err = __parasite_execute_syscall(ctl, ®s, code_int_80); + err = compel_execute_syscall(ctl, ®s, code_int_80); } *ret = get_user_reg(®s, ax); diff --git a/criu/include/infect.h b/criu/include/infect.h index 5ab38425f..38e22465a 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -1,5 +1,8 @@ #ifndef __COMPEL_INFECT_H__ #define __COMPEL_INFECT_H__ + +#include "types.h" + extern int compel_stop_task(int pid); struct seize_task_status { @@ -47,4 +50,7 @@ extern int compel_cure(struct parasite_ctl *ctl); extern void *compel_parasite_args_p(struct parasite_ctl *ctl); extern void *compel_parasite_args_s(struct parasite_ctl *ctl, int args_size); + +extern int compel_execute_syscall(struct parasite_ctl *ctl, + user_regs_struct_t *regs, const char *code_syscall); #endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index ec4bef4d6..6d3e5fdfc 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -99,8 +99,6 @@ extern int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6); -extern int __parasite_execute_syscall(struct parasite_ctl *ctl, - user_regs_struct_t *regs, const char *code_syscall); extern bool arch_can_dump_task(struct parasite_ctl *ctl); extern bool seized_native(struct parasite_ctl *ctl); diff --git a/criu/infect.c b/criu/infect.c index c65aa4237..4a984677f 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -369,6 +369,42 @@ err_sig: return -1; } +/* XXX will be removed soon */ +extern int parasite_trap(struct parasite_ctl *ctl, pid_t pid, + user_regs_struct_t *regs, + struct thread_ctx *octx); + +int compel_execute_syscall(struct parasite_ctl *ctl, + user_regs_struct_t *regs, const char *code_syscall) +{ + pid_t pid = ctl->rpid; + int err; + u8 code_orig[BUILTIN_SYSCALL_SIZE]; + + /* + * Inject syscall instruction and remember original code, + * we will need it to restore original program content. + */ + memcpy(code_orig, code_syscall, sizeof(code_orig)); + if (ptrace_swap_area(pid, (void *)ctl->ictx.syscall_ip, + (void *)code_orig, sizeof(code_orig))) { + pr_err("Can't inject syscall blob (pid: %d)\n", pid); + return -1; + } + + err = parasite_run(pid, PTRACE_CONT, ctl->ictx.syscall_ip, 0, regs, &ctl->orig); + if (!err) + err = parasite_trap(ctl, pid, regs, &ctl->orig); + + if (ptrace_poke_area(pid, (void *)code_orig, + (void *)ctl->ictx.syscall_ip, sizeof(code_orig))) { + pr_err("Can't restore syscall blob (pid: %d)\n", ctl->rpid); + err = -1; + } + + return err; +} + static int accept_tsock(struct parasite_ctl *ctl) { int sock; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 6a8268230..83cbd6c34 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -113,7 +113,7 @@ bool seized_native(struct parasite_ctl *ctl) } /* we run at @regs->ip */ -static int parasite_trap(struct parasite_ctl *ctl, pid_t pid, +int parasite_trap(struct parasite_ctl *ctl, pid_t pid, user_regs_struct_t *regs, struct thread_ctx *octx) { @@ -166,37 +166,6 @@ err: return ret; } -int __parasite_execute_syscall(struct parasite_ctl *ctl, - user_regs_struct_t *regs, const char *code_syscall) -{ - pid_t pid = ctl->rpid; - int err; - u8 code_orig[BUILTIN_SYSCALL_SIZE]; - - /* - * Inject syscall instruction and remember original code, - * we will need it to restore original program content. - */ - memcpy(code_orig, code_syscall, sizeof(code_orig)); - if (ptrace_swap_area(pid, (void *)ctl->ictx.syscall_ip, - (void *)code_orig, sizeof(code_orig))) { - pr_err("Can't inject syscall blob (pid: %d)\n", pid); - return -1; - } - - err = parasite_run(pid, PTRACE_CONT, ctl->ictx.syscall_ip, 0, regs, &ctl->orig); - if (!err) - err = parasite_trap(ctl, pid, regs, &ctl->orig); - - if (ptrace_poke_area(pid, (void *)code_orig, - (void *)ctl->ictx.syscall_ip, sizeof(code_orig))) { - pr_err("Can't restore syscall blob (pid: %d)\n", ctl->rpid); - err = -1; - } - - return err; -} - static int parasite_run_in_thread(pid_t pid, unsigned int cmd, struct parasite_ctl *ctl, struct thread_ctx *octx) From 6a4279dd9e7e005b9f1c3da42cad6077bb834330 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 28 Sep 2016 13:58:44 +0300 Subject: [PATCH 0153/4375] infect: Move parasite_run_in_thread() into infect.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/infect.h | 3 +++ criu/infect.c | 22 ++++++++++++++++++++++ criu/parasite-syscall.c | 24 +----------------------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/criu/include/infect.h b/criu/include/infect.h index 38e22465a..a521fe49c 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -53,4 +53,7 @@ extern void *compel_parasite_args_s(struct parasite_ctl *ctl, int args_size); extern int compel_execute_syscall(struct parasite_ctl *ctl, user_regs_struct_t *regs, const char *code_syscall); +extern int compel_run_in_thread(pid_t pid, unsigned int cmd, + struct parasite_ctl *ctl, + struct thread_ctx *octx); #endif diff --git a/criu/infect.c b/criu/infect.c index 4a984677f..70ebebe3d 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -793,3 +793,25 @@ void *compel_parasite_args_s(struct parasite_ctl *ctl, int args_size) return compel_parasite_args_p(ctl); } +int compel_run_in_thread(pid_t pid, unsigned int cmd, + struct parasite_ctl *ctl, + struct thread_ctx *octx) +{ + void *stack = ctl->r_thread_stack; + user_regs_struct_t regs = octx->regs; + int ret; + + *ctl->addr_cmd = cmd; + + ret = parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, stack, ®s, octx); + if (ret == 0) + ret = parasite_trap(ctl, pid, ®s, octx); + if (ret == 0) + ret = (int)REG_RES(regs); + + if (ret) + pr_err("Parasite exited with %d\n", ret); + + return ret; +} + diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 83cbd6c34..3d2f44616 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -166,28 +166,6 @@ err: return ret; } -static int parasite_run_in_thread(pid_t pid, unsigned int cmd, - struct parasite_ctl *ctl, - struct thread_ctx *octx) -{ - void *stack = ctl->r_thread_stack; - user_regs_struct_t regs = octx->regs; - int ret; - - *ctl->addr_cmd = cmd; - - ret = parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, stack, ®s, octx); - if (ret == 0) - ret = parasite_trap(ctl, pid, ®s, octx); - if (ret == 0) - ret = (int)REG_RES(regs); - - if (ret) - pr_err("Parasite exited with %d\n", ret); - - return ret; -} - static int __parasite_send_cmd(int sockfd, struct ctl_msg *m) { int ret; @@ -414,7 +392,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, tc->has_blk_sigset = true; memcpy(&tc->blk_sigset, &octx.sigmask, sizeof(k_rtsigset_t)); - ret = parasite_run_in_thread(pid, PARASITE_CMD_DUMP_THREAD, ctl, &octx); + ret = compel_run_in_thread(pid, PARASITE_CMD_DUMP_THREAD, ctl, &octx); if (ret) { pr_err("Can't init thread in parasite %d\n", pid); return -1; From 34db99e3c8f8a5fec5d523e24ee35ed30ea5ad57 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 28 Sep 2016 14:07:16 +0300 Subject: [PATCH 0154/4375] infect: Move parasite_unmap() into infect.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/include/infect-priv.h | 2 -- criu/include/infect.h | 2 ++ criu/include/parasite-syscall.h | 1 - criu/infect.c | 31 +++++++++++++++++++++++++++++-- criu/parasite-syscall.c | 26 +------------------------- 6 files changed, 33 insertions(+), 31 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 503d32f64..7d74f2e86 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1658,7 +1658,7 @@ static void finalize_restore(void) if (ctl == NULL) continue; - parasite_unmap(ctl, (unsigned long)rsti(item)->munmap_restorer); + compel_unmap(ctl, (unsigned long)rsti(item)->munmap_restorer); xfree(ctl); diff --git a/criu/include/infect-priv.h b/criu/include/infect-priv.h index 8a1ab610d..a461ffa2c 100644 --- a/criu/include/infect-priv.h +++ b/criu/include/infect-priv.h @@ -32,6 +32,4 @@ struct parasite_ctl { int tsock; /* transport socket for transferring fds */ }; -int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack, - user_regs_struct_t *regs, struct thread_ctx *octx); #endif diff --git a/criu/include/infect.h b/criu/include/infect.h index a521fe49c..d528eabf7 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -56,4 +56,6 @@ extern int compel_execute_syscall(struct parasite_ctl *ctl, extern int compel_run_in_thread(pid_t pid, unsigned int cmd, struct parasite_ctl *ctl, struct thread_ctx *octx); + +extern int compel_unmap(struct parasite_ctl *ctl, unsigned long addr); #endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 6d3e5fdfc..d21d0862a 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -116,7 +116,6 @@ enum trace_flags { extern int parasite_stop_on_syscall(int tasks, int sys_nr, int sys_nr_compat, enum trace_flags trace); -extern int parasite_unmap(struct parasite_ctl *ctl, unsigned long addr); extern int ptrace_stop_pie(pid_t pid, void *addr, enum trace_flags *tf); #endif /* __CR_PARASITE_SYSCALL_H__ */ diff --git a/criu/infect.c b/criu/infect.c index 70ebebe3d..548e4acc0 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -335,7 +335,7 @@ static int restore_child_handler() return 0; } -int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack, +static int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack, user_regs_struct_t *regs, struct thread_ctx *octx) { k_rtsigset_t block; @@ -738,7 +738,7 @@ int compel_cure_remote(struct parasite_ctl *ctl) args = compel_parasite_args(ctl, struct parasite_unmap_args); args->parasite_start = ctl->remote_map; args->parasite_len = ctl->map_length; - if (parasite_unmap(ctl, ctl->parasite_ip)) + if (compel_unmap(ctl, ctl->parasite_ip)) return -1; } else { unsigned long ret; @@ -815,3 +815,30 @@ int compel_run_in_thread(pid_t pid, unsigned int cmd, return ret; } +/* XXX will be removed soon */ + +extern int restore_thread_ctx(int pid, struct thread_ctx *ctx); +/* + * compel_unmap() is used for unmapping parasite and restorer blobs. + * A blob can contain code for unmapping itself, so the porcess is + * trapped on the exit from the munmap syscall. + */ +int compel_unmap(struct parasite_ctl *ctl, unsigned long addr) +{ + user_regs_struct_t regs = ctl->orig.regs; + pid_t pid = ctl->rpid; + int ret = -1; + + ret = parasite_run(pid, PTRACE_SYSCALL, addr, ctl->rstack, ®s, &ctl->orig); + if (ret) + goto err; + + ret = parasite_stop_on_syscall(1, __NR(munmap, 0), + __NR(munmap, 1), TRACE_ENTER); + + if (restore_thread_ctx(pid, &ctl->orig)) + ret = -1; +err: + return ret; +} + diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 3d2f44616..8e38126ef 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -91,7 +91,7 @@ static inline int ptrace_set_regs(int pid, user_regs_struct_t *regs) } #endif -static int restore_thread_ctx(int pid, struct thread_ctx *ctx) +int restore_thread_ctx(int pid, struct thread_ctx *ctx) { int ret = 0; @@ -796,30 +796,6 @@ goon: return 0; } -/* - * parasite_unmap() is used for unmapping parasite and restorer blobs. - * A blob can contain code for unmapping itself, so the porcess is - * trapped on the exit from the munmap syscall. - */ -int parasite_unmap(struct parasite_ctl *ctl, unsigned long addr) -{ - user_regs_struct_t regs = ctl->orig.regs; - pid_t pid = ctl->rpid; - int ret = -1; - - ret = parasite_run(pid, PTRACE_SYSCALL, addr, ctl->rstack, ®s, &ctl->orig); - if (ret) - goto err; - - ret = parasite_stop_on_syscall(1, __NR(munmap, 0), - __NR(munmap, 1), TRACE_ENTER); - - if (restore_thread_ctx(pid, &ctl->orig)) - ret = -1; -err: - return ret; -} - static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size) { int fd; From 511a6ffd29588030a7b995d42c309387840ae984 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 28 Sep 2016 14:08:20 +0300 Subject: [PATCH 0155/4375] infect: Move parasite_trap() into infect.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/infect.c | 60 +++++++++++++++++++++++++++++++++++++---- criu/parasite-syscall.c | 54 ------------------------------------- 2 files changed, 55 insertions(+), 59 deletions(-) diff --git a/criu/infect.c b/criu/infect.c index 548e4acc0..3b2d47c33 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -370,9 +370,62 @@ err_sig: } /* XXX will be removed soon */ -extern int parasite_trap(struct parasite_ctl *ctl, pid_t pid, +extern int restore_thread_ctx(int pid, struct thread_ctx *ctx); + +/* we run at @regs->ip */ +static int parasite_trap(struct parasite_ctl *ctl, pid_t pid, user_regs_struct_t *regs, - struct thread_ctx *octx); + struct thread_ctx *octx) +{ + siginfo_t siginfo; + int status; + int ret = -1; + + /* + * Most ideas are taken from Tejun Heo's parasite thread + * https://code.google.com/p/ptrace-parasite/ + */ + + if (wait4(pid, &status, __WALL, NULL) != pid) { + pr_perror("Waited pid mismatch (pid: %d)", pid); + goto err; + } + + if (!WIFSTOPPED(status)) { + pr_err("Task is still running (pid: %d)\n", pid); + goto err; + } + + if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo)) { + pr_perror("Can't get siginfo (pid: %d)", pid); + goto err; + } + + if (ptrace_get_regs(pid, regs)) { + pr_perror("Can't obtain registers (pid: %d)", pid); + goto err; + } + + if (WSTOPSIG(status) != SIGTRAP || siginfo.si_code != ARCH_SI_TRAP) { + pr_debug("** delivering signal %d si_code=%d\n", + siginfo.si_signo, siginfo.si_code); + + pr_err("Unexpected %d task interruption, aborting\n", pid); + goto err; + } + + /* + * We've reached this point if int3 is triggered inside our + * parasite code. So we're done. + */ + ret = 0; +err: + if (restore_thread_ctx(pid, octx)) + ret = -1; + + return ret; +} + int compel_execute_syscall(struct parasite_ctl *ctl, user_regs_struct_t *regs, const char *code_syscall) @@ -815,9 +868,6 @@ int compel_run_in_thread(pid_t pid, unsigned int cmd, return ret; } -/* XXX will be removed soon */ - -extern int restore_thread_ctx(int pid, struct thread_ctx *ctx); /* * compel_unmap() is used for unmapping parasite and restorer blobs. * A blob can contain code for unmapping itself, so the porcess is diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 8e38126ef..201f11bc9 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -112,60 +112,6 @@ bool seized_native(struct parasite_ctl *ctl) return user_regs_native(&ctl->orig.regs); } -/* we run at @regs->ip */ -int parasite_trap(struct parasite_ctl *ctl, pid_t pid, - user_regs_struct_t *regs, - struct thread_ctx *octx) -{ - siginfo_t siginfo; - int status; - int ret = -1; - - /* - * Most ideas are taken from Tejun Heo's parasite thread - * https://code.google.com/p/ptrace-parasite/ - */ - - if (wait4(pid, &status, __WALL, NULL) != pid) { - pr_perror("Waited pid mismatch (pid: %d)", pid); - goto err; - } - - if (!WIFSTOPPED(status)) { - pr_err("Task is still running (pid: %d)\n", pid); - goto err; - } - - if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo)) { - pr_perror("Can't get siginfo (pid: %d)", pid); - goto err; - } - - if (ptrace_get_regs(pid, regs)) { - pr_perror("Can't obtain registers (pid: %d)", pid); - goto err; - } - - if (WSTOPSIG(status) != SIGTRAP || siginfo.si_code != ARCH_SI_TRAP) { - pr_debug("** delivering signal %d si_code=%d\n", - siginfo.si_signo, siginfo.si_code); - - pr_err("Unexpected %d task interruption, aborting\n", pid); - goto err; - } - - /* - * We've reached this point if int3 is triggered inside our - * parasite code. So we're done. - */ - ret = 0; -err: - if (restore_thread_ctx(pid, octx)) - ret = -1; - - return ret; -} - static int __parasite_send_cmd(int sockfd, struct ctl_msg *m) { int ret; From b071c6e3f0755c8470f3ba38f99b689a14fb12e1 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 28 Sep 2016 14:09:14 +0300 Subject: [PATCH 0156/4375] infect: Move restore_thread_ctx() into infect.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/infect.c | 18 ++++++++++++++++-- criu/parasite-syscall.c | 16 ---------------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/criu/infect.c b/criu/infect.c index 3b2d47c33..62732aff6 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -369,8 +369,22 @@ err_sig: return -1; } -/* XXX will be removed soon */ -extern int restore_thread_ctx(int pid, struct thread_ctx *ctx); +static int restore_thread_ctx(int pid, struct thread_ctx *ctx) +{ + int ret = 0; + + if (ptrace_set_regs(pid, &ctx->regs)) { + pr_perror("Can't restore registers (pid: %d)", pid); + ret = -1; + } + if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &ctx->sigmask)) { + pr_perror("Can't block signals"); + ret = -1; + } + + return ret; +} + /* we run at @regs->ip */ static int parasite_trap(struct parasite_ctl *ctl, pid_t pid, diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 201f11bc9..d8f911fb6 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -91,22 +91,6 @@ static inline int ptrace_set_regs(int pid, user_regs_struct_t *regs) } #endif -int restore_thread_ctx(int pid, struct thread_ctx *ctx) -{ - int ret = 0; - - if (ptrace_set_regs(pid, &ctx->regs)) { - pr_perror("Can't restore registers (pid: %d)", pid); - ret = -1; - } - if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &ctx->sigmask)) { - pr_perror("Can't block signals"); - ret = -1; - } - - return ret; -} - bool seized_native(struct parasite_ctl *ctl) { return user_regs_native(&ctl->orig.regs); From 754a2d9501f5cd2e8e425f14021017c96174d462 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 29 Sep 2016 16:22:19 +0300 Subject: [PATCH 0157/4375] infect: Move parasite_map_exchange() into infect.c Note -- this will go away from compel API with cr-exec.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-exec.c | 2 +- criu/include/infect-priv.h | 5 ++ criu/include/parasite-syscall.h | 1 - criu/infect.c | 128 +++++++++++++++++++++++++++++++- criu/parasite-syscall.c | 126 ------------------------------- 5 files changed, 130 insertions(+), 132 deletions(-) diff --git a/criu/cr-exec.c b/criu/cr-exec.c index 6001d0b03..4af4571d2 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -61,7 +61,7 @@ static int execute_syscall(struct parasite_ctl *ctl, int len; if (!r_mem) { - err = parasite_map_exchange(ctl, PAGE_SIZE); + err = compel_map_exchange(ctl, PAGE_SIZE); if (err) return err; diff --git a/criu/include/infect-priv.h b/criu/include/infect-priv.h index a461ffa2c..fe8e22d11 100644 --- a/criu/include/infect-priv.h +++ b/criu/include/infect-priv.h @@ -32,4 +32,9 @@ struct parasite_ctl { int tsock; /* transport socket for transferring fds */ }; +#define MEMFD_FNAME "CRIUMFD" +#define MEMFD_FNAME_SZ sizeof(MEMFD_FNAME) + +/* XXX -- remove with cr-exec.c */ +extern int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size); #endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index d21d0862a..f05bb7409 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -85,7 +85,6 @@ extern struct parasite_ctl *parasite_infect_seized(pid_t pid, struct vm_area_list *vma_area_list); extern void parasite_ensure_args_size(unsigned long sz); extern unsigned long get_exec_start(struct vm_area_list *); -extern int parasite_map_exchange(struct parasite_ctl *ctl, unsigned long size); extern int parasite_dump_cgroup(struct parasite_ctl *ctl, struct parasite_dump_cgroup_args *cgroup); diff --git a/criu/infect.c b/criu/infect.c index 62732aff6..66f6c3745 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -20,9 +20,6 @@ #include "infect.h" #include "infect-priv.h" -#define MEMFD_FNAME "CRIUMFD" -#define MEMFD_FNAME_SZ sizeof(MEMFD_FNAME) - /* XXX will be removed soon */ extern int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m); @@ -569,6 +566,129 @@ static int parasite_start_daemon(struct parasite_ctl *ctl) return 0; } +static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size) +{ + int fd; + + ctl->remote_map = mmap_seized(ctl, NULL, size, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_SHARED, -1, 0); + if (!ctl->remote_map) { + pr_err("Can't allocate memory for parasite blob (pid: %d)\n", ctl->rpid); + return -1; + } + + ctl->map_length = round_up(size, page_size()); + + fd = open_proc_rw(ctl->rpid, "map_files/%p-%p", + ctl->remote_map, ctl->remote_map + ctl->map_length); + if (fd < 0) + return -1; + + ctl->local_map = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FILE, fd, 0); + close(fd); + + if (ctl->local_map == MAP_FAILED) { + ctl->local_map = NULL; + pr_perror("Can't map remote parasite map"); + return -1; + } + + return 0; +} + +static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) +{ + void *where = (void *)ctl->ictx.syscall_ip + BUILTIN_SYSCALL_SIZE; + u8 orig_code[MEMFD_FNAME_SZ] = MEMFD_FNAME; + pid_t pid = ctl->rpid; + unsigned long sret = -ENOSYS; + int ret, fd, lfd; + bool __maybe_unused compat_task = !seized_native(ctl); + + if (ctl->ictx.flags & INFECT_NO_MEMFD) + return 1; + + BUILD_BUG_ON(sizeof(orig_code) < sizeof(long)); + + if (ptrace_swap_area(pid, where, (void *)orig_code, sizeof(orig_code))) { + pr_err("Can't inject memfd args (pid: %d)\n", pid); + return -1; + } + + ret = syscall_seized(ctl, __NR(memfd_create, compat_task), &sret, + (unsigned long)where, 0, 0, 0, 0, 0); + + if (ptrace_poke_area(pid, orig_code, where, sizeof(orig_code))) { + fd = (int)(long)sret; + if (fd >= 0) + syscall_seized(ctl, __NR(close, compat_task), &sret, + fd, 0, 0, 0, 0, 0); + pr_err("Can't restore memfd args (pid: %d)\n", pid); + return -1; + } + + if (ret < 0) + return ret; + + fd = (int)(long)sret; + if (fd == -ENOSYS) + return 1; + if (fd < 0) + return fd; + + ctl->map_length = round_up(size, page_size()); + lfd = open_proc_rw(ctl->rpid, "fd/%d", fd); + if (lfd < 0) + goto err_cure; + + if (ftruncate(lfd, ctl->map_length) < 0) { + pr_perror("Fail to truncate memfd for parasite"); + goto err_cure; + } + + ctl->remote_map = mmap_seized(ctl, NULL, size, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FILE | MAP_SHARED, fd, 0); + if (!ctl->remote_map) { + pr_err("Can't rmap memfd for parasite blob\n"); + goto err_curef; + } + + ctl->local_map = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FILE, lfd, 0); + if (ctl->local_map == MAP_FAILED) { + ctl->local_map = NULL; + pr_perror("Can't lmap memfd for parasite blob"); + goto err_curef; + } + + syscall_seized(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); + close(lfd); + + pr_info("Set up parasite blob using memfd\n"); + return 0; + +err_curef: + close(lfd); +err_cure: + syscall_seized(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); + return -1; +} + +int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size) +{ + int ret; + + ret = parasite_memfd_exchange(ctl, size); + if (ret == 1) { + pr_info("MemFD parasite doesn't work, goto legacy mmap\n"); + ret = parasite_mmap_exchange(ctl, size); + } + return ret; +} + #define init_parasite_ctl(ctl, blob_type) \ do { \ memcpy(ctl->local_map, parasite_##blob_type##_blob, \ @@ -614,7 +734,7 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l if (nr_threads > 1) map_exchange_size += PARASITE_STACK_SIZE; - ret = parasite_map_exchange(ctl, map_exchange_size); + ret = compel_map_exchange(ctl, map_exchange_size); if (ret) goto err; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index d8f911fb6..bd411ed37 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -44,9 +44,6 @@ #include "infect.h" #include "infect-priv.h" -#define MEMFD_FNAME "CRIUMFD" -#define MEMFD_FNAME_SZ sizeof(MEMFD_FNAME) - unsigned long get_exec_start(struct vm_area_list *vmas) { struct vma_area *vma_area; @@ -726,129 +723,6 @@ goon: return 0; } -static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size) -{ - int fd; - - ctl->remote_map = mmap_seized(ctl, NULL, size, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANONYMOUS | MAP_SHARED, -1, 0); - if (!ctl->remote_map) { - pr_err("Can't allocate memory for parasite blob (pid: %d)\n", ctl->rpid); - return -1; - } - - ctl->map_length = round_up(size, page_size()); - - fd = open_proc_rw(ctl->rpid, "map_files/%p-%p", - ctl->remote_map, ctl->remote_map + ctl->map_length); - if (fd < 0) - return -1; - - ctl->local_map = mmap(NULL, size, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_FILE, fd, 0); - close(fd); - - if (ctl->local_map == MAP_FAILED) { - ctl->local_map = NULL; - pr_perror("Can't map remote parasite map"); - return -1; - } - - return 0; -} - -static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) -{ - void *where = (void *)ctl->ictx.syscall_ip + BUILTIN_SYSCALL_SIZE; - u8 orig_code[MEMFD_FNAME_SZ] = MEMFD_FNAME; - pid_t pid = ctl->rpid; - unsigned long sret = -ENOSYS; - int ret, fd, lfd; - bool __maybe_unused compat_task = !seized_native(ctl); - - if (ctl->ictx.flags & INFECT_NO_MEMFD) - return 1; - - BUILD_BUG_ON(sizeof(orig_code) < sizeof(long)); - - if (ptrace_swap_area(pid, where, (void *)orig_code, sizeof(orig_code))) { - pr_err("Can't inject memfd args (pid: %d)\n", pid); - return -1; - } - - ret = syscall_seized(ctl, __NR(memfd_create, compat_task), &sret, - (unsigned long)where, 0, 0, 0, 0, 0); - - if (ptrace_poke_area(pid, orig_code, where, sizeof(orig_code))) { - fd = (int)(long)sret; - if (fd >= 0) - syscall_seized(ctl, __NR(close, compat_task), &sret, - fd, 0, 0, 0, 0, 0); - pr_err("Can't restore memfd args (pid: %d)\n", pid); - return -1; - } - - if (ret < 0) - return ret; - - fd = (int)(long)sret; - if (fd == -ENOSYS) - return 1; - if (fd < 0) - return fd; - - ctl->map_length = round_up(size, page_size()); - lfd = open_proc_rw(ctl->rpid, "fd/%d", fd); - if (lfd < 0) - goto err_cure; - - if (ftruncate(lfd, ctl->map_length) < 0) { - pr_perror("Fail to truncate memfd for parasite"); - goto err_cure; - } - - ctl->remote_map = mmap_seized(ctl, NULL, size, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_FILE | MAP_SHARED, fd, 0); - if (!ctl->remote_map) { - pr_err("Can't rmap memfd for parasite blob\n"); - goto err_curef; - } - - ctl->local_map = mmap(NULL, size, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_FILE, lfd, 0); - if (ctl->local_map == MAP_FAILED) { - ctl->local_map = NULL; - pr_perror("Can't lmap memfd for parasite blob"); - goto err_curef; - } - - syscall_seized(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); - close(lfd); - - pr_info("Set up parasite blob using memfd\n"); - return 0; - -err_curef: - close(lfd); -err_cure: - syscall_seized(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); - return -1; -} - -int parasite_map_exchange(struct parasite_ctl *ctl, unsigned long size) -{ - int ret; - - ret = parasite_memfd_exchange(ctl, size); - if (ret == 1) { - pr_info("MemFD parasite doesn't work, goto legacy mmap\n"); - ret = parasite_mmap_exchange(ctl, size); - } - return ret; -} - int parasite_dump_cgroup(struct parasite_ctl *ctl, struct parasite_dump_cgroup_args *cgroup) { int ret; From 18248ce4bdcba5c1deacbd9b7deb9554b869132c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 29 Sep 2016 16:37:34 +0300 Subject: [PATCH 0158/4375] infect: Move unseize_task() into infect.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-exec.c | 2 +- criu/include/infect.h | 1 + criu/include/ptrace.h | 1 - criu/infect.c | 35 +++++++++++++++++++++++++++++++++++ criu/ptrace.c | 35 ----------------------------------- criu/seize.c | 2 +- 6 files changed, 38 insertions(+), 38 deletions(-) diff --git a/criu/cr-exec.c b/criu/cr-exec.c index 4af4571d2..8e0348796 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -193,7 +193,7 @@ int cr_exec(int pid, char **opt) out_cure: compel_cure(ctl); out_unseize: - unseize_task(pid, prev_state, prev_state); + compel_unseize_task(pid, prev_state, prev_state); out: return exit_code; } diff --git a/criu/include/infect.h b/criu/include/infect.h index d528eabf7..b906617e0 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -16,6 +16,7 @@ struct seize_task_status { extern int compel_wait_task(int pid, int ppid, int (*get_status)(int pid, struct seize_task_status *), struct seize_task_status *st); +extern int compel_unseize_task(pid_t pid, int orig_state, int state); /* * FIXME -- these should be mapped to pid.h's diff --git a/criu/include/ptrace.h b/criu/include/ptrace.h index 1e79972b4..22649c346 100644 --- a/criu/include/ptrace.h +++ b/criu/include/ptrace.h @@ -63,7 +63,6 @@ #define SI_EVENT(_si_code) (((_si_code) & 0xFFFF) >> 8) extern int suspend_seccomp(pid_t pid); -extern int unseize_task(pid_t pid, int orig_state, int state); extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes); extern int ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes); extern int ptrace_swap_area(pid_t pid, void *dst, void *src, long bytes); diff --git a/criu/infect.c b/criu/infect.c index 66f6c3745..e4770fb3b 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -241,6 +241,41 @@ err: return -1; } +int compel_unseize_task(pid_t pid, int orig_st, int st) +{ + pr_debug("\tUnseizing %d into %d\n", pid, st); + + if (st == TASK_DEAD) { + kill(pid, SIGKILL); + return 0; + } else if (st == TASK_STOPPED) { + /* + * Task might have had STOP in queue. We detected such + * guy as TASK_STOPPED, but cleared signal to run the + * parasite code. hus after detach the task will become + * running. That said -- STOP everyone regardless of + * the initial state. + */ + kill(pid, SIGSTOP); + } else if (st == TASK_ALIVE) { + /* + * Same as in the comment above -- there might be a + * task with STOP in queue that would get lost after + * detach, so stop it again. + */ + if (orig_st == TASK_STOPPED) + kill(pid, SIGSTOP); + } else + pr_err("Unknown final state %d\n", st); + + if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) { + pr_perror("Unable to detach from %d", pid); + return -1; + } + + return 0; +} + static int gen_parasite_saddr(struct sockaddr_un *saddr, int key) { int sun_len; diff --git a/criu/ptrace.c b/criu/ptrace.c index f013346e3..15908c17d 100644 --- a/criu/ptrace.c +++ b/criu/ptrace.c @@ -23,41 +23,6 @@ #include "seccomp.h" #include "cr_options.h" -int unseize_task(pid_t pid, int orig_st, int st) -{ - pr_debug("\tUnseizing %d into %d\n", pid, st); - - if (st == TASK_DEAD) { - kill(pid, SIGKILL); - return 0; - } else if (st == TASK_STOPPED) { - /* - * Task might have had STOP in queue. We detected such - * guy as TASK_STOPPED, but cleared signal to run the - * parasite code. hus after detach the task will become - * running. That said -- STOP everyone regardless of - * the initial state. - */ - kill(pid, SIGSTOP); - } else if (st == TASK_ALIVE) { - /* - * Same as in the comment above -- there might be a - * task with STOP in queue that would get lost after - * detach, so stop it again. - */ - if (orig_st == TASK_STOPPED) - kill(pid, SIGSTOP); - } else - pr_err("Unknown final state %d\n", st); - - if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) { - pr_perror("Unable to detach from %d", pid); - return -1; - } - - return 0; -} - int suspend_seccomp(pid_t pid) { if (ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_SUSPEND_SECCOMP) < 0) { diff --git a/criu/seize.c b/criu/seize.c index 35ecf2580..51daadf43 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -538,7 +538,7 @@ static void unseize_task_and_threads(const struct pstree_item *item, int st) * the item->state is the state task was in when we seized one. */ - unseize_task(item->pid->real, item->pid->state, st); + compel_unseize_task(item->pid->real, item->pid->state, st); if (st == TASK_DEAD) return; From 315b0d82aa5d1d059f414a4b9136a8fc36c370b5 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 29 Sep 2016 16:43:29 +0300 Subject: [PATCH 0159/4375] infect: Move pie tracing code into infect.c Note -- presumably it's another functionality block inside compel, so another .c file might be tempting here. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 6 +- criu/include/infect.h | 17 ++++ criu/include/parasite-syscall.h | 17 +--- criu/infect.c | 153 +++++++++++++++++++++++++++++++- criu/parasite-syscall.c | 147 +----------------------------- 5 files changed, 174 insertions(+), 166 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 7d74f2e86..fdceacbc2 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -69,6 +69,7 @@ #include "file-lock.h" #include "action-scripts.h" #include "shmem.h" +#include "infect.h" #include "aio.h" #include "lsm.h" #include "seccomp.h" @@ -1615,7 +1616,8 @@ static int catch_tasks(bool root_seized, enum trace_flags *flag) return -1; } - ret = ptrace_stop_pie(pid, rsti(item)->breakpoint, flag); + ret = compel_stop_pie(pid, rsti(item)->breakpoint, + flag, fault_injected(FI_NO_BREAKPOINTS)); if (ret < 0) return -1; } @@ -1969,7 +1971,7 @@ static int restore_root_task(struct pstree_item *init) futex_set_and_wake(&task_entries->start, CR_STATE_COMPLETE); if (ret == 0) - ret = parasite_stop_on_syscall(task_entries->nr_threads, + ret = compel_stop_on_syscall(task_entries->nr_threads, __NR(rt_sigreturn, 0), __NR(rt_sigreturn, 1), flag); if (clear_breakpoints()) diff --git a/criu/include/infect.h b/criu/include/infect.h index b906617e0..4f7ae1c85 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -58,5 +58,22 @@ extern int compel_run_in_thread(pid_t pid, unsigned int cmd, struct parasite_ctl *ctl, struct thread_ctx *octx); +/* + * The PTRACE_SYSCALL will trap task twice -- on + * enter into and on exit from syscall. If we trace + * a single task, we may skip half of all getregs + * calls -- on exit we don't need them. + */ +enum trace_flags { + TRACE_ALL, + TRACE_ENTER, + TRACE_EXIT, +}; + +extern int compel_stop_on_syscall(int tasks, int sys_nr, + int sys_nr_compat, enum trace_flags trace); + +extern int compel_stop_pie(pid_t pid, void *addr, enum trace_flags *tf, bool no_bp); + extern int compel_unmap(struct parasite_ctl *ctl, unsigned long addr); #endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index f05bb7409..bcdc8b369 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -45,6 +45,7 @@ struct infect_ctx { #define INFECT_NO_MEMFD 0x1 /* don't use memfd() */ #define INFECT_FAIL_CONNECT 0x2 /* make parasite connect() fail */ +#define INFECT_NO_BREAKPOINTS 0x4 /* no breakpoints in pie tracking */ struct parasite_ctl; @@ -101,20 +102,4 @@ extern int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, extern bool arch_can_dump_task(struct parasite_ctl *ctl); extern bool seized_native(struct parasite_ctl *ctl); -/* - * The PTRACE_SYSCALL will trap task twice -- on - * enter into and on exit from syscall. If we trace - * a single task, we may skip half of all getregs - * calls -- on exit we don't need them. - */ -enum trace_flags { - TRACE_ALL, - TRACE_ENTER, - TRACE_EXIT, -}; - -extern int parasite_stop_on_syscall(int tasks, int sys_nr, - int sys_nr_compat, enum trace_flags trace); -extern int ptrace_stop_pie(pid_t pid, void *addr, enum trace_flags *tf); - #endif /* __CR_PARASITE_SYSCALL_H__ */ diff --git a/criu/infect.c b/criu/infect.c index e4770fb3b..123d86304 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -902,11 +902,12 @@ static int parasite_fini_seized(struct parasite_ctl *ctl) return -1; /* Go to sigreturn as closer as we can */ - ret = ptrace_stop_pie(pid, ctl->sigreturn_addr, &flag); + ret = compel_stop_pie(pid, ctl->sigreturn_addr, &flag, + ctl->ictx.flags & INFECT_NO_BREAKPOINTS); if (ret < 0) return ret; - if (parasite_stop_on_syscall(1, __NR(rt_sigreturn, 0), + if (compel_stop_on_syscall(1, __NR(rt_sigreturn, 0), __NR(rt_sigreturn, 1), flag)) return -1; @@ -1052,7 +1053,7 @@ int compel_unmap(struct parasite_ctl *ctl, unsigned long addr) if (ret) goto err; - ret = parasite_stop_on_syscall(1, __NR(munmap, 0), + ret = compel_stop_on_syscall(1, __NR(munmap, 0), __NR(munmap, 1), TRACE_ENTER); if (restore_thread_ctx(pid, &ctl->orig)) @@ -1061,3 +1062,149 @@ err: return ret; } +int compel_stop_pie(pid_t pid, void *addr, enum trace_flags *tf, bool no_bp) +{ + int ret; + + if (no_bp) { + pr_debug("Force no-breakpoints restore\n"); + ret = 0; + } else + ret = ptrace_set_breakpoint(pid, addr); + if (ret < 0) + return ret; + + if (ret > 0) { + /* + * PIE will stop on a breakpoint, next + * stop after that will be syscall enter. + */ + *tf = TRACE_EXIT; + return 0; + } + + /* + * No breakpoints available -- start tracing it + * in a per-syscall manner. + */ + ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); + if (ret) { + pr_perror("Unable to restart the %d process", pid); + return -1; + } + + *tf = TRACE_ENTER; + return 0; +} + +static bool task_is_trapped(int status, pid_t pid) +{ + if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) + return true; + + pr_err("Task %d is in unexpected state: %x\n", pid, status); + if (WIFEXITED(status)) + pr_err("Task exited with %d\n", WEXITSTATUS(status)); + if (WIFSIGNALED(status)) + pr_err("Task signaled with %d: %s\n", + WTERMSIG(status), strsignal(WTERMSIG(status))); + if (WIFSTOPPED(status)) + pr_err("Task stopped with %d: %s\n", + WSTOPSIG(status), strsignal(WSTOPSIG(status))); + if (WIFCONTINUED(status)) + pr_err("Task continued\n"); + + return false; +} + +static inline int is_required_syscall(user_regs_struct_t *regs, pid_t pid, + const int sys_nr, const int sys_nr_compat) +{ + const char *mode = user_regs_native(regs) ? "native" : "compat"; + int req_sysnr = user_regs_native(regs) ? sys_nr : sys_nr_compat; + + pr_debug("%d (%s) is going to execute the syscall %lu, required is %d\n", + pid, mode, REG_SYSCALL_NR(*regs), req_sysnr); + + return (REG_SYSCALL_NR(*regs) == req_sysnr); +} + +/* + * Trap tasks on the exit from the specified syscall + * + * tasks - number of processes, which should be trapped + * sys_nr - the required syscall number + * sys_nr_compat - the required compatible syscall number + */ +int compel_stop_on_syscall(int tasks, + const int sys_nr, const int sys_nr_compat, + enum trace_flags trace) +{ + user_regs_struct_t regs; + int status, ret; + pid_t pid; + + if (tasks > 1) + trace = TRACE_ALL; + + /* Stop all threads on the enter point in sys_rt_sigreturn */ + while (tasks) { + pid = wait4(-1, &status, __WALL, NULL); + if (pid == -1) { + pr_perror("wait4 failed"); + return -1; + } + + if (!task_is_trapped(status, pid)) + return -1; + + pr_debug("%d was trapped\n", pid); + + if (trace == TRACE_EXIT) { + trace = TRACE_ENTER; + pr_debug("`- Expecting exit\n"); + goto goon; + } + if (trace == TRACE_ENTER) + trace = TRACE_EXIT; + + ret = ptrace_get_regs(pid, ®s); + if (ret) { + pr_perror("ptrace"); + return -1; + } + + if (is_required_syscall(®s, pid, sys_nr, sys_nr_compat)) { + /* + * The process is going to execute the required syscall, + * the next stop will be on the exit from this syscall + */ + ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); + if (ret) { + pr_perror("ptrace"); + return -1; + } + + pid = wait4(pid, &status, __WALL, NULL); + if (pid == -1) { + pr_perror("wait4 failed"); + return -1; + } + + if (!task_is_trapped(status, pid)) + return -1; + + pr_debug("%d was stopped\n", pid); + tasks--; + continue; + } +goon: + ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); + if (ret) { + pr_perror("ptrace"); + return -1; + } + } + + return 0; +} diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index bd411ed37..657e67594 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -612,117 +612,6 @@ int parasite_get_proc_fd_seized(struct parasite_ctl *ctl) /* This is officially the 50000'th line in the CRIU source code */ -static bool task_is_trapped(int status, pid_t pid) -{ - if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) - return true; - - pr_err("Task %d is in unexpected state: %x\n", pid, status); - if (WIFEXITED(status)) - pr_err("Task exited with %d\n", WEXITSTATUS(status)); - if (WIFSIGNALED(status)) - pr_err("Task signaled with %d: %s\n", - WTERMSIG(status), strsignal(WTERMSIG(status))); - if (WIFSTOPPED(status)) - pr_err("Task stopped with %d: %s\n", - WSTOPSIG(status), strsignal(WSTOPSIG(status))); - if (WIFCONTINUED(status)) - pr_err("Task continued\n"); - - return false; -} - -static inline int is_required_syscall(user_regs_struct_t *regs, pid_t pid, - const int sys_nr, const int sys_nr_compat) -{ - const char *mode = user_regs_native(regs) ? "native" : "compat"; - int req_sysnr = user_regs_native(regs) ? sys_nr : sys_nr_compat; - - pr_debug("%d (%s) is going to execute the syscall %lu, required is %d\n", - pid, mode, REG_SYSCALL_NR(*regs), req_sysnr); - - return (REG_SYSCALL_NR(*regs) == req_sysnr); -} -/* - * Trap tasks on the exit from the specified syscall - * - * tasks - number of processes, which should be trapped - * sys_nr - the required syscall number - * sys_nr_compat - the required compatible syscall number - */ -int parasite_stop_on_syscall(int tasks, - const int sys_nr, const int sys_nr_compat, - enum trace_flags trace) -{ - user_regs_struct_t regs; - int status, ret; - pid_t pid; - - if (tasks > 1) - trace = TRACE_ALL; - - /* Stop all threads on the enter point in sys_rt_sigreturn */ - while (tasks) { - pid = wait4(-1, &status, __WALL, NULL); - if (pid == -1) { - pr_perror("wait4 failed"); - return -1; - } - - if (!task_is_trapped(status, pid)) - return -1; - - pr_debug("%d was trapped\n", pid); - - if (trace == TRACE_EXIT) { - trace = TRACE_ENTER; - pr_debug("`- Expecting exit\n"); - goto goon; - } - if (trace == TRACE_ENTER) - trace = TRACE_EXIT; - - ret = ptrace_get_regs(pid, ®s); - if (ret) { - pr_perror("ptrace"); - return -1; - } - - if (is_required_syscall(®s, pid, sys_nr, sys_nr_compat)) { - /* - * The process is going to execute the required syscall, - * the next stop will be on the exit from this syscall - */ - ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); - if (ret) { - pr_perror("ptrace"); - return -1; - } - - pid = wait4(pid, &status, __WALL, NULL); - if (pid == -1) { - pr_perror("wait4 failed"); - return -1; - } - - if (!task_is_trapped(status, pid)) - return -1; - - pr_debug("%d was stopped\n", pid); - tasks--; - continue; - } -goon: - ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); - if (ret) { - pr_perror("ptrace"); - return -1; - } - } - - return 0; -} - int parasite_dump_cgroup(struct parasite_ctl *ctl, struct parasite_dump_cgroup_args *cgroup) { int ret; @@ -781,6 +670,8 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ctl->ictx.flags |= INFECT_NO_MEMFD; if (fault_injected(FI_PARASITE_CONNECT)) ctl->ictx.flags |= INFECT_FAIL_CONNECT; + if (fault_injected(FI_NO_BREAKPOINTS)) + ctl->ictx.flags |= INFECT_NO_BREAKPOINTS; parasite_ensure_args_size(dump_pages_args_size(vma_area_list)); parasite_ensure_args_size(aio_rings_args_size(vma_area_list)); @@ -797,37 +688,3 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, return ctl; } -int ptrace_stop_pie(pid_t pid, void *addr, enum trace_flags *tf) -{ - int ret; - - if (fault_injected(FI_NO_BREAKPOINTS)) { - pr_debug("Force no-breakpoints restore\n"); - ret = 0; - } else - ret = ptrace_set_breakpoint(pid, addr); - if (ret < 0) - return ret; - - if (ret > 0) { - /* - * PIE will stop on a breakpoint, next - * stop after that will be syscall enter. - */ - *tf = TRACE_EXIT; - return 0; - } - - /* - * No breakpoints available -- start tracing it - * in a per-syscall manner. - */ - ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); - if (ret) { - pr_perror("Unable to restart the %d process", pid); - return -1; - } - - *tf = TRACE_ENTER; - return 0; -} From 795049e6a7fd30d51b741587487860252cc7346b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Sep 2016 14:34:50 +0300 Subject: [PATCH 0160/4375] infect: Move parasite RPC code into infect-rpc.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/Makefile.crtools | 1 + criu/aio.c | 3 +- criu/include/infect-priv.h | 3 + criu/include/infect-rpc.h | 20 ++++++ criu/include/parasite-syscall.h | 10 --- criu/include/parasite.h | 12 ---- criu/infect-rpc.c | 97 +++++++++++++++++++++++++ criu/infect.c | 10 ++- criu/mem.c | 9 +-- criu/parasite-syscall.c | 124 ++++++-------------------------- criu/pie/parasite.c | 1 + criu/vdso.c | 3 +- 12 files changed, 157 insertions(+), 136 deletions(-) create mode 100644 criu/include/infect-rpc.h create mode 100644 criu/infect-rpc.c diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 41de00877..04ba7b3f7 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -4,6 +4,7 @@ ccflags-y += -iquote compel/include ccflags-y += -iquote compel/arch/$(ARCH)/plugins/std obj-y += infect.o +obj-y += infect-rpc.o obj-y += action-scripts.o obj-y += external.o obj-y += aio.o diff --git a/criu/aio.c b/criu/aio.c index c031e3919..011a1afcf 100644 --- a/criu/aio.c +++ b/criu/aio.c @@ -12,6 +12,7 @@ #include "parasite-syscall.h" #include "images/mm.pb-c.h" #include "infect.h" +#include "infect-rpc.h" #define NR_IOEVENTS_IN_NPAGES(npages) ((PAGE_SIZE * npages - sizeof(struct aio_ring)) / sizeof(struct io_event)) @@ -119,7 +120,7 @@ int parasite_collect_aios(struct parasite_ctl *ctl, struct vm_area_list *vmas) } aa->nr_rings = vmas->nr_aios; - if (parasite_execute_daemon(PARASITE_CMD_CHECK_AIOS, ctl)) + if (compel_rpc_call_sync(PARASITE_CMD_CHECK_AIOS, ctl)) return -1; return 0; diff --git a/criu/include/infect-priv.h b/criu/include/infect-priv.h index fe8e22d11..b33a63516 100644 --- a/criu/include/infect-priv.h +++ b/criu/include/infect-priv.h @@ -35,6 +35,9 @@ struct parasite_ctl { #define MEMFD_FNAME "CRIUMFD" #define MEMFD_FNAME_SZ sizeof(MEMFD_FNAME) +struct ctl_msg; +int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m); + /* XXX -- remove with cr-exec.c */ extern int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size); #endif diff --git a/criu/include/infect-rpc.h b/criu/include/infect-rpc.h new file mode 100644 index 000000000..117dfc1bb --- /dev/null +++ b/criu/include/infect-rpc.h @@ -0,0 +1,20 @@ +#ifndef __COMPEL_INFECT_RPC_H__ +#define __COMPEL_INFECT_RPC_H__ +extern int compel_rpc_sync(unsigned int cmd, struct parasite_ctl *ctl); +extern int compel_rpc_call(unsigned int cmd, struct parasite_ctl *ctl); +extern int compel_rpc_call_sync(unsigned int cmd, struct parasite_ctl *ctl); +extern int compel_rpc_sock(struct parasite_ctl *ctl); + +struct ctl_msg { + unsigned int cmd; /* command itself */ + unsigned int ack; /* ack on command */ + int err; /* error code on reply */ +}; + +#define ctl_msg_cmd(_cmd) \ + (struct ctl_msg){.cmd = _cmd, } + +#define ctl_msg_ack(_cmd, _err) \ + (struct ctl_msg){.cmd = _cmd, .ack = _cmd, .err = _err, } + +#endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index bcdc8b369..0d7d86f57 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -58,16 +58,6 @@ extern int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc extern int parasite_send_fd(struct parasite_ctl *ctl, int fd); -/* - * Execute a command in parasite when it's in daemon mode. - * The __-ed version is asyncronous (doesn't wait for ack). - */ -extern int parasite_execute_daemon(unsigned int cmd, struct parasite_ctl *ctl); -extern int __parasite_execute_daemon(unsigned int cmd, struct parasite_ctl *ctl); - -extern int __parasite_wait_daemon_ack(unsigned int cmd, - struct parasite_ctl *ctl); - extern int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_misc *misc); extern int parasite_dump_creds(struct parasite_ctl *ctl, struct _CredsEntry *ce); extern int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, struct _CoreEntry *core); diff --git a/criu/include/parasite.h b/criu/include/parasite.h index af7b7c10d..b68961bbf 100644 --- a/criu/include/parasite.h +++ b/criu/include/parasite.h @@ -52,18 +52,6 @@ enum { PARASITE_CMD_MAX, }; -struct ctl_msg { - unsigned int cmd; /* command itself */ - unsigned int ack; /* ack on command */ - int err; /* error code on reply */ -}; - -#define ctl_msg_cmd(_cmd) \ - (struct ctl_msg){.cmd = _cmd, } - -#define ctl_msg_ack(_cmd, _err) \ - (struct ctl_msg){.cmd = _cmd, .ack = _cmd, .err = _err, } - struct parasite_init_args { int h_addr_len; struct sockaddr_un h_addr; diff --git a/criu/infect-rpc.c b/criu/infect-rpc.c new file mode 100644 index 000000000..51b9132ca --- /dev/null +++ b/criu/infect-rpc.c @@ -0,0 +1,97 @@ +#include "xmalloc.h" +#include "types.h" +#include "parasite.h" +#include "parasite-syscall.h" +#include "infect.h" +#include "infect-priv.h" +#include "infect-rpc.h" + +static int __parasite_send_cmd(int sockfd, struct ctl_msg *m) +{ + int ret; + + ret = send(sockfd, m, sizeof(*m), 0); + if (ret == -1) { + pr_perror("Failed to send command %d to daemon", m->cmd); + return -1; + } else if (ret != sizeof(*m)) { + pr_err("Message to daemon is trimmed (%d/%d)\n", + (int)sizeof(*m), ret); + return -1; + } + + pr_debug("Sent msg to daemon %d %d %d\n", m->cmd, m->ack, m->err); + return 0; +} + +int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m) +{ + int ret; + + pr_debug("Wait for ack %d on daemon socket\n", cmd); + + while (1) { + memzero(m, sizeof(*m)); + + ret = recv(sockfd, m, sizeof(*m), MSG_WAITALL); + if (ret == -1) { + pr_perror("Failed to read ack"); + return -1; + } else if (ret != sizeof(*m)) { + pr_err("Message reply from daemon is trimmed (%d/%d)\n", + (int)sizeof(*m), ret); + return -1; + } + pr_debug("Fetched ack: %d %d %d\n", + m->cmd, m->ack, m->err); + + if (m->cmd != cmd || m->ack != cmd) { + pr_err("Communication error, this is not " + "the ack we expected\n"); + return -1; + } + return 0; + } + + return -1; +} + +int compel_rpc_sync(unsigned int cmd, struct parasite_ctl *ctl) +{ + struct ctl_msg m; + + if (parasite_wait_ack(ctl->tsock, cmd, &m)) + return -1; + + if (m.err != 0) { + pr_err("Command %d for daemon failed with %d\n", + cmd, m.err); + return -1; + } + + return 0; +} + +int compel_rpc_call(unsigned int cmd, struct parasite_ctl *ctl) +{ + struct ctl_msg m; + + m = ctl_msg_cmd(cmd); + return __parasite_send_cmd(ctl->tsock, &m); +} + +int compel_rpc_call_sync(unsigned int cmd, struct parasite_ctl *ctl) +{ + int ret; + + ret = compel_rpc_call(cmd, ctl); + if (!ret) + ret = compel_rpc_sync(cmd, ctl); + + return ret; +} + +int compel_rpc_sock(struct parasite_ctl *ctl) +{ + return ctl->tsock; +} diff --git a/criu/infect.c b/criu/infect.c index 123d86304..623ea5444 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -6,6 +6,7 @@ #include #include +#include "infect.h" #include "ptrace.h" #include "signal.h" #include "asm/parasite-syscall.h" @@ -16,13 +17,10 @@ #include "pie-relocs.h" #include "parasite-blob.h" #include "sigframe.h" -#include "log.h" -#include "infect.h" +#include "criu-log.h" +#include "infect-rpc.h" #include "infect-priv.h" -/* XXX will be removed soon */ -extern int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m); - #define PTRACE_EVENT_STOP 128 #ifndef SECCOMP_MODE_DISABLED @@ -896,7 +894,7 @@ static int parasite_fini_seized(struct parasite_ctl *ctl) return -1; } - ret = __parasite_execute_daemon(PARASITE_CMD_FINI, ctl); + ret = compel_rpc_call(PARASITE_CMD_FINI, ctl); close_safe(&ctl->tsock); if (ret) return -1; diff --git a/criu/mem.c b/criu/mem.c index e881f4938..5e6851990 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -26,6 +26,7 @@ #include "pagemap-cache.h" #include "fault-injection.h" #include "infect.h" +#include "infect-rpc.h" #include "protobuf.h" #include "images/pagemap.pb-c.h" @@ -232,14 +233,14 @@ static int drain_pages(struct page_pipe *pp, struct parasite_ctl *ctl, pr_debug("PPB: %d pages %d segs %u pipe %d off\n", args->nr_pages, args->nr_segs, ppb->pipe_size, args->off); - ret = __parasite_execute_daemon(PARASITE_CMD_DUMPPAGES, ctl); + ret = compel_rpc_call(PARASITE_CMD_DUMPPAGES, ctl); if (ret < 0) return -1; ret = parasite_send_fd(ctl, ppb->p[1]); if (ret) return -1; - ret = __parasite_wait_daemon_ack(PARASITE_CMD_DUMPPAGES, ctl); + ret = compel_rpc_sync(PARASITE_CMD_DUMPPAGES, ctl); if (ret < 0) return -1; @@ -419,7 +420,7 @@ int parasite_dump_pages_seized(struct pstree_item *item, */ pargs->add_prot = PROT_READ; - ret = parasite_execute_daemon(PARASITE_CMD_MPROTECT_VMAS, ctl); + ret = compel_rpc_call_sync(PARASITE_CMD_MPROTECT_VMAS, ctl); if (ret) { pr_err("Can't dump unprotect vmas with parasite\n"); return ret; @@ -438,7 +439,7 @@ int parasite_dump_pages_seized(struct pstree_item *item, } pargs->add_prot = 0; - if (parasite_execute_daemon(PARASITE_CMD_MPROTECT_VMAS, ctl)) { + if (compel_rpc_call_sync(PARASITE_CMD_MPROTECT_VMAS, ctl)) { pr_err("Can't rollback unprotected vmas with parasite\n"); ret = -1; } diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 657e67594..a8a3e09e6 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -42,6 +42,7 @@ #include "pie/pie-relocs.h" #include "infect.h" +#include "infect-rpc.h" #include "infect-priv.h" unsigned long get_exec_start(struct vm_area_list *vmas) @@ -93,95 +94,12 @@ bool seized_native(struct parasite_ctl *ctl) return user_regs_native(&ctl->orig.regs); } -static int __parasite_send_cmd(int sockfd, struct ctl_msg *m) -{ - int ret; - - ret = send(sockfd, m, sizeof(*m), 0); - if (ret == -1) { - pr_perror("Failed to send command %d to daemon", m->cmd); - return -1; - } else if (ret != sizeof(*m)) { - pr_err("Message to daemon is trimmed (%d/%d)\n", - (int)sizeof(*m), ret); - return -1; - } - - pr_debug("Sent msg to daemon %d %d %d\n", m->cmd, m->ack, m->err); - return 0; -} - -int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m) -{ - int ret; - - pr_debug("Wait for ack %d on daemon socket\n", cmd); - - while (1) { - memzero(m, sizeof(*m)); - - ret = recv(sockfd, m, sizeof(*m), MSG_WAITALL); - if (ret == -1) { - pr_perror("Failed to read ack"); - return -1; - } else if (ret != sizeof(*m)) { - pr_err("Message reply from daemon is trimmed (%d/%d)\n", - (int)sizeof(*m), ret); - return -1; - } - pr_debug("Fetched ack: %d %d %d\n", - m->cmd, m->ack, m->err); - - if (m->cmd != cmd || m->ack != cmd) { - pr_err("Communication error, this is not " - "the ack we expected\n"); - return -1; - } - return 0; - } - - return -1; -} - -int __parasite_wait_daemon_ack(unsigned int cmd, - struct parasite_ctl *ctl) -{ - struct ctl_msg m; - - if (parasite_wait_ack(ctl->tsock, cmd, &m)) - return -1; - - if (m.err != 0) { - pr_err("Command %d for daemon failed with %d\n", - cmd, m.err); - return -1; - } - - return 0; -} - -int __parasite_execute_daemon(unsigned int cmd, struct parasite_ctl *ctl) -{ - struct ctl_msg m; - - m = ctl_msg_cmd(cmd); - return __parasite_send_cmd(ctl->tsock, &m); -} - -int parasite_execute_daemon(unsigned int cmd, struct parasite_ctl *ctl) -{ - int ret; - - ret = __parasite_execute_daemon(cmd, ctl); - if (!ret) - ret = __parasite_wait_daemon_ack(cmd, ctl); - - return ret; -} - int parasite_send_fd(struct parasite_ctl *ctl, int fd) { - if (send_fd(ctl->tsock, NULL, 0, fd) < 0) { + int sk; + + sk = compel_rpc_sock(ctl); + if (send_fd(sk, NULL, 0, fd) < 0) { pr_perror("Can't send file descriptor"); return -1; } @@ -272,7 +190,7 @@ int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEn pc->cap_last_cap = kdat.last_cap; - ret = parasite_execute_daemon(PARASITE_CMD_DUMP_THREAD, ctl); + ret = compel_rpc_call_sync(PARASITE_CMD_DUMP_THREAD, ctl); if (ret < 0) return ret; @@ -370,7 +288,7 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_ else args_c = compel_parasite_args(ctl, struct parasite_dump_sa_args_compat); - ret = parasite_execute_daemon(PARASITE_CMD_DUMP_SIGACTS, ctl); + ret = compel_rpc_call_sync(PARASITE_CMD_DUMP_SIGACTS, ctl); if (ret < 0) return ret; @@ -422,7 +340,7 @@ int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct pstree_item *i else args_c = compel_parasite_args(ctl, struct parasite_dump_itimers_args_compat); - ret = parasite_execute_daemon(PARASITE_CMD_DUMP_ITIMERS, ctl); + ret = compel_rpc_call_sync(PARASITE_CMD_DUMP_ITIMERS, ctl); if (ret < 0) return ret; @@ -519,7 +437,7 @@ int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, i++; } - ret = parasite_execute_daemon(PARASITE_CMD_DUMP_POSIX_TIMERS, ctl); + ret = compel_rpc_call_sync(PARASITE_CMD_DUMP_POSIX_TIMERS, ctl); if (ret < 0) goto end_posix; @@ -541,7 +459,7 @@ int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_mis struct parasite_dump_misc *ma; ma = compel_parasite_args(ctl, struct parasite_dump_misc); - if (parasite_execute_daemon(PARASITE_CMD_DUMP_MISC, ctl) < 0) + if (compel_rpc_call_sync(PARASITE_CMD_DUMP_MISC, ctl) < 0) return -1; *misc = *ma; @@ -556,7 +474,7 @@ struct parasite_tty_args *parasite_dump_tty(struct parasite_ctl *ctl, int fd, in p->fd = fd; p->type = type; - if (parasite_execute_daemon(PARASITE_CMD_DUMP_TTY, ctl) < 0) + if (compel_rpc_call_sync(PARASITE_CMD_DUMP_TTY, ctl) < 0) return NULL; return p; @@ -566,7 +484,7 @@ int parasite_drain_fds_seized(struct parasite_ctl *ctl, struct parasite_drain_fd *dfds, int nr_fds, int off, int *lfds, struct fd_opts *opts) { - int ret = -1, size; + int ret = -1, size, sk; struct parasite_drain_fd *args; size = drain_fds_size(dfds); @@ -574,35 +492,37 @@ int parasite_drain_fds_seized(struct parasite_ctl *ctl, args->nr_fds = nr_fds; memcpy(&args->fds, dfds->fds + off, sizeof(int) * nr_fds); - ret = __parasite_execute_daemon(PARASITE_CMD_DRAIN_FDS, ctl); + ret = compel_rpc_call(PARASITE_CMD_DRAIN_FDS, ctl); if (ret) { pr_err("Parasite failed to drain descriptors\n"); goto err; } - ret = recv_fds(ctl->tsock, lfds, nr_fds, opts, sizeof(struct fd_opts)); + sk = compel_rpc_sock(ctl); + ret = recv_fds(sk, lfds, nr_fds, opts, sizeof(struct fd_opts)); if (ret) pr_err("Can't retrieve FDs from socket\n"); - ret |= __parasite_wait_daemon_ack(PARASITE_CMD_DRAIN_FDS, ctl); + ret |= compel_rpc_sync(PARASITE_CMD_DRAIN_FDS, ctl); err: return ret; } int parasite_get_proc_fd_seized(struct parasite_ctl *ctl) { - int ret = -1, fd; + int ret = -1, fd, sk; - ret = __parasite_execute_daemon(PARASITE_CMD_GET_PROC_FD, ctl); + ret = compel_rpc_call(PARASITE_CMD_GET_PROC_FD, ctl); if (ret) { pr_err("Parasite failed to get proc fd\n"); return ret; } - fd = recv_fd(ctl->tsock); + sk = compel_rpc_sock(ctl); + fd = recv_fd(sk); if (fd < 0) pr_err("Can't retrieve FD from socket\n"); - if (__parasite_wait_daemon_ack(PARASITE_CMD_GET_PROC_FD, ctl)) { + if (compel_rpc_sync(PARASITE_CMD_GET_PROC_FD, ctl)) { close_safe(&fd); return -1; } @@ -618,7 +538,7 @@ int parasite_dump_cgroup(struct parasite_ctl *ctl, struct parasite_dump_cgroup_a struct parasite_dump_cgroup_args *ca; ca = compel_parasite_args(ctl, struct parasite_dump_cgroup_args); - ret = parasite_execute_daemon(PARASITE_CMD_DUMP_CGROUP, ctl); + ret = compel_rpc_call_sync(PARASITE_CMD_DUMP_CGROUP, ctl); if (ret) { pr_err("Parasite failed to dump /proc/self/cgroup\n"); return ret; diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index 22b7ba25e..66dd6cd2f 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -19,6 +19,7 @@ #include "criu-log.h" #include "tty.h" #include "aio.h" +#include "infect-rpc.h" #include "asm/parasite.h" #include "restorer.h" diff --git a/criu/vdso.c b/criu/vdso.c index 63d32db87..1a283d4fb 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -20,6 +20,7 @@ #include "mem.h" #include "vma.h" #include "infect.h" +#include "infect-rpc.h" #ifdef LOG_PREFIX # undef LOG_PREFIX @@ -111,7 +112,7 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, args->try_fill_symtable = (fd < 0) ? true : false; args->is_vdso = false; - if (parasite_execute_daemon(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) { + if (compel_rpc_call_sync(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) { pr_err("Parasite failed to poke for mark\n"); goto err; } From 329d2c156b87ba53469394904dab91de5291a7cc Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Sep 2016 14:56:28 +0300 Subject: [PATCH 0161/4375] infect: Move seized_native() into infect.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/sys-exec-tbl.c | 3 ++- criu/include/infect.h | 3 +++ criu/include/parasite-syscall.h | 1 - criu/infect.c | 13 +++++++++---- criu/mem.c | 2 +- criu/parasite-syscall.c | 25 ++++++++++--------------- criu/vdso.c | 2 +- 7 files changed, 26 insertions(+), 23 deletions(-) diff --git a/criu/arch/x86/sys-exec-tbl.c b/criu/arch/x86/sys-exec-tbl.c index f52578736..1051af06f 100644 --- a/criu/arch/x86/sys-exec-tbl.c +++ b/criu/arch/x86/sys-exec-tbl.c @@ -1,3 +1,4 @@ +#include "infect.h" static struct syscall_exec_desc sc_exec_table_64[] = { #include "sys-exec-tbl-64.c" @@ -29,7 +30,7 @@ find_syscall_table(char *name, struct syscall_exec_desc *tbl) #ifdef CONFIG_COMPAT struct syscall_exec_desc * find_syscall(char *name, struct parasite_ctl *ctl) { - if (seized_native(ctl)) + if (compel_mode_native(ctl)) return find_syscall_table(name, sc_exec_table_64); else return find_syscall_table(name, sc_exec_table_32); diff --git a/criu/include/infect.h b/criu/include/infect.h index 4f7ae1c85..8335127d8 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -76,4 +76,7 @@ extern int compel_stop_on_syscall(int tasks, int sys_nr, extern int compel_stop_pie(pid_t pid, void *addr, enum trace_flags *tf, bool no_bp); extern int compel_unmap(struct parasite_ctl *ctl, unsigned long addr); + +extern int compel_mode_native(struct parasite_ctl *ctl); + #endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 0d7d86f57..15b4abfd8 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -90,6 +90,5 @@ extern int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, unsigned long arg5, unsigned long arg6); extern bool arch_can_dump_task(struct parasite_ctl *ctl); -extern bool seized_native(struct parasite_ctl *ctl); #endif /* __CR_PARASITE_SYSCALL_H__ */ diff --git a/criu/infect.c b/criu/infect.c index 623ea5444..8e5d5714a 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -638,7 +638,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) pid_t pid = ctl->rpid; unsigned long sret = -ENOSYS; int ret, fd, lfd; - bool __maybe_unused compat_task = !seized_native(ctl); + bool __maybe_unused compat_task = !compel_mode_native(ctl); if (ctl->ictx.flags & INFECT_NO_MEMFD) return 1; @@ -752,7 +752,7 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l * without using ptrace at all. */ - if (seized_native(ctl)) + if (compel_mode_native(ctl)) parasite_size = pie_size(parasite_native); #ifdef CONFIG_COMPAT else @@ -773,7 +773,7 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map); - if (seized_native(ctl)) + if (compel_mode_native(ctl)) init_parasite_ctl(ctl, native); #ifdef CONFIG_COMPAT else @@ -964,7 +964,7 @@ int compel_cure_remote(struct parasite_ctl *ctl) } else { unsigned long ret; - syscall_seized(ctl, __NR(munmap, !seized_native(ctl)), &ret, + syscall_seized(ctl, __NR(munmap, !compel_mode_native(ctl)), &ret, (unsigned long)ctl->remote_map, ctl->map_length, 0, 0, 0, 0); if (ret) { @@ -1206,3 +1206,8 @@ goon: return 0; } + +int compel_mode_native(struct parasite_ctl *ctl) +{ + return user_regs_native(&ctl->orig.regs); +} diff --git a/criu/mem.c b/criu/mem.c index 5e6851990..46389d3cc 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -306,7 +306,7 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, * use, i.e. on non-lazy non-predump. */ cpp_flags |= PP_CHUNK_MODE; - if (!seized_native(ctl)) + if (!compel_mode_native(ctl)) cpp_flags |= PP_COMPAT; pp = create_page_pipe(vma_area_list->priv_size, pargs_iovs(args), cpp_flags); diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index a8a3e09e6..db0436b11 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -89,11 +89,6 @@ static inline int ptrace_set_regs(int pid, user_regs_struct_t *regs) } #endif -bool seized_native(struct parasite_ctl *ctl) -{ - return user_regs_native(&ctl->orig.regs); -} - int parasite_send_fd(struct parasite_ctl *ctl, int fd) { int sk; @@ -180,7 +175,7 @@ int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEn struct parasite_dump_creds *pc; int ret; - if (seized_native(ctl)) { + if (compel_mode_native(ctl)) { args = compel_parasite_args(ctl, struct parasite_dump_thread); pc = args->creds; } else { @@ -200,7 +195,7 @@ int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEn return -1; } - if (seized_native(ctl)) + if (compel_mode_native(ctl)) return dump_thread_core(pid, core, true, args); else return dump_thread_core(pid, core, false, args_c); @@ -220,7 +215,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, BUG_ON(id == 0); /* Leader is dumped in dump_task_core_all */ - if (seized_native(ctl)) { + if (compel_mode_native(ctl)) { args = compel_parasite_args(ctl, struct parasite_dump_thread); pc = args->creds; } else { @@ -255,7 +250,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, return -1; } - if (seized_native(ctl)) { + if (compel_mode_native(ctl)) { tid->ns[0].virt = args->tid; return dump_thread_core(pid, core, true, args); } else { @@ -281,7 +276,7 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_ int ret, sig; struct cr_img *img; SaEntry se = SA_ENTRY__INIT; - bool native_task = seized_native(ctl); + bool native_task = compel_mode_native(ctl); if (native_task) args = compel_parasite_args(ctl, struct parasite_dump_sa_args); @@ -335,7 +330,7 @@ int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct pstree_item *i struct parasite_dump_itimers_args_compat *args_c = NULL; int ret; - if (seized_native(ctl)) + if (compel_mode_native(ctl)) args = compel_parasite_args(ctl, struct parasite_dump_itimers_args); else args_c = compel_parasite_args(ctl, struct parasite_dump_itimers_args_compat); @@ -344,7 +339,7 @@ int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct pstree_item *i if (ret < 0) return ret; - if (seized_native(ctl)) + if (compel_mode_native(ctl)) ASSIGN_ITIMER(args); else ASSIGN_ITIMER(args_c); @@ -373,7 +368,7 @@ static int core_alloc_posix_timers(TaskTimersEntry *tte, int n, #define set_posix_timer_arg(args, ctl, m, val) \ do { \ - if (seized_native(ctl)) \ + if (compel_mode_native(ctl)) \ ASSIGN_TYPED( \ ((struct parasite_dump_posix_timers_args*)args)->m, val); \ else \ @@ -383,7 +378,7 @@ do { \ #define get_posix_timer_arg(out, m) \ do { \ - if (seized_native(ctl)) \ + if (compel_mode_native(ctl)) \ ASSIGN_TYPED( \ out, ((struct parasite_dump_posix_timers_args*)args)->m); \ else \ @@ -423,7 +418,7 @@ int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, if (core_alloc_posix_timers(tte, proc_args->timer_n, &pte)) return -1; - if (seized_native(ctl)) + if (compel_mode_native(ctl)) args_size = posix_timers_dump_size(proc_args->timer_n); else args_size = posix_timers_compat_dump_size(proc_args->timer_n); diff --git a/criu/vdso.c b/criu/vdso.c index 1a283d4fb..7a50587f6 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -106,7 +106,7 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, * XXX: For compatible tasks, vDSO pfn is different from * our native vdso_pfn. Check vma explicitly. */ - if (!seized_native(ctl)) + if (!compel_mode_native(ctl)) args->try_fill_symtable = true; else args->try_fill_symtable = (fd < 0) ? true : false; From 5e75d49946bd4c96edb02003ce4fc6bdea5fb54b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Sep 2016 14:58:29 +0300 Subject: [PATCH 0162/4375] infect: Move sigmask getter (from ctl) into infec.c ... and hide compel priv from parasite-syscall. Now it's completely isolated inside compel. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/infect.h | 2 ++ criu/infect.c | 5 +++++ criu/parasite-syscall.c | 3 +-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/criu/include/infect.h b/criu/include/infect.h index 8335127d8..973913d21 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -79,4 +79,6 @@ extern int compel_unmap(struct parasite_ctl *ctl, unsigned long addr); extern int compel_mode_native(struct parasite_ctl *ctl); +extern k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl); + #endif diff --git a/criu/infect.c b/criu/infect.c index 8e5d5714a..a7c03df58 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -1211,3 +1211,8 @@ int compel_mode_native(struct parasite_ctl *ctl) { return user_regs_native(&ctl->orig.regs); } + +k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl) +{ + return &ctl->orig.sigmask; +} diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index db0436b11..5f816a734 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -43,7 +43,6 @@ #include "infect.h" #include "infect-rpc.h" -#include "infect-priv.h" unsigned long get_exec_start(struct vm_area_list *vmas) { @@ -597,7 +596,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, } parasite_args_size = PARASITE_ARG_SIZE_MIN; /* reset for next task */ - memcpy(&item->core[0]->tc->blk_sigset, &ctl->orig.sigmask, sizeof(k_rtsigset_t)); + memcpy(&item->core[0]->tc->blk_sigset, compel_task_sigmask(ctl), sizeof(k_rtsigset_t)); dmpi(item)->parasite_ctl = ctl; return ctl; From f98a557529107cfaead76a0bc984b5919a225ba0 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Sep 2016 14:53:49 +0300 Subject: [PATCH 0163/4375] infect: Introduce API to configure the infection I.e. -- the infect_ctX structure. Now it's in infect.h and is aimed for compel sources. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 2 +- criu/include/infect.h | 24 ++++++++++++++++++++++++ criu/include/parasite-syscall.h | 20 -------------------- criu/infect.c | 5 +++++ criu/parasite-syscall.c | 21 ++++++++++++--------- 5 files changed, 42 insertions(+), 30 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 535821cb8..ee1625e14 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -24,8 +24,8 @@ #include "errno.h" #include "uapi/std/syscall-codes.h" #include "kerndat.h" -#include "infect-priv.h" #include "infect.h" +#include "infect-priv.h" #include "protobuf.h" #include "images/core.pb-c.h" diff --git a/criu/include/infect.h b/criu/include/infect.h index 973913d21..072143eed 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -81,4 +81,28 @@ extern int compel_mode_native(struct parasite_ctl *ctl); extern k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl); +struct rt_sigframe; + +struct infect_ctx { + int *p_sock; + + /* + * Regs manipulation context. + */ + int (*save_regs)(void *, user_regs_struct_t *, user_fpregs_struct_t *); + int (*make_sigframe)(void *, struct rt_sigframe *, struct rt_sigframe *, k_rtsigset_t *); + void *regs_arg; + + unsigned long syscall_ip; /* entry point of infection */ + unsigned long flags; /* fine-tune (e.g. faults) */ + + void (*child_handler)(int, siginfo_t *, void *); /* hander for SIGCHLD deaths */ +}; + +extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *); + +#define INFECT_NO_MEMFD 0x1 /* don't use memfd() */ +#define INFECT_FAIL_CONNECT 0x2 /* make parasite connect() fail */ +#define INFECT_NO_BREAKPOINTS 0x4 /* no breakpoints in pie tracking */ + #endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 15b4abfd8..2efec72d4 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -27,26 +27,6 @@ struct thread_ctx { user_regs_struct_t regs; }; -struct infect_ctx { - int *p_sock; - - /* - * Regs manipulation context. - */ - int (*save_regs)(void *, user_regs_struct_t *, user_fpregs_struct_t *); - int (*make_sigframe)(void *, struct rt_sigframe *, struct rt_sigframe *, k_rtsigset_t *); - void *regs_arg; - - unsigned long syscall_ip; /* entry point of infection */ - unsigned long flags; /* fine-tune (e.g. faults) */ - - void (*child_handler)(int, siginfo_t *, void *); /* hander for SIGCHLD deaths */ -}; - -#define INFECT_NO_MEMFD 0x1 /* don't use memfd() */ -#define INFECT_FAIL_CONNECT 0x2 /* make parasite connect() fail */ -#define INFECT_NO_BREAKPOINTS 0x4 /* no breakpoints in pie tracking */ - struct parasite_ctl; extern int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_imgset); diff --git a/criu/infect.c b/criu/infect.c index a7c03df58..15e117139 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -1216,3 +1216,8 @@ k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl) { return &ctl->orig.sigmask; } + +struct infect_ctx *compel_infect_ctx(struct parasite_ctl *ctl) +{ + return &ctl->ictx; +} diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 5f816a734..8ff128287 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -558,6 +558,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, struct vm_area_list *vma_area_list) { struct parasite_ctl *ctl; + struct infect_ctx *ictx; unsigned long p; BUG_ON(item->threads[0].real != pid); @@ -572,20 +573,22 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, if (!ctl) return NULL; - ctl->ictx.child_handler = sigchld_handler; - ctl->ictx.p_sock = &dmpi(item)->netns->net.seqsk; - ctl->ictx.save_regs = save_task_regs; - ctl->ictx.make_sigframe = make_sigframe; - ctl->ictx.regs_arg = item->core[0]; - ctl->ictx.syscall_ip = p; + ictx = compel_infect_ctx(ctl); + + ictx->child_handler = sigchld_handler; + ictx->p_sock = &dmpi(item)->netns->net.seqsk; + ictx->save_regs = save_task_regs; + ictx->make_sigframe = make_sigframe; + ictx->regs_arg = item->core[0]; + ictx->syscall_ip = p; pr_debug("Parasite syscall_ip at %#lx\n", p); if (fault_injected(FI_NO_MEMFD)) - ctl->ictx.flags |= INFECT_NO_MEMFD; + ictx->flags |= INFECT_NO_MEMFD; if (fault_injected(FI_PARASITE_CONNECT)) - ctl->ictx.flags |= INFECT_FAIL_CONNECT; + ictx->flags |= INFECT_FAIL_CONNECT; if (fault_injected(FI_NO_BREAKPOINTS)) - ctl->ictx.flags |= INFECT_NO_BREAKPOINTS; + ictx->flags |= INFECT_NO_BREAKPOINTS; parasite_ensure_args_size(dump_pages_args_size(vma_area_list)); parasite_ensure_args_size(aio_rings_args_size(vma_area_list)); From 590856f51a6e874a3684ab2b5f77e3564d0b23c4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 19 Oct 2016 12:17:27 +0300 Subject: [PATCH 0164/4375] infect: Introduce arch part Same split as was previously done with parasite-syscall.c now with arch/*/crtools.c files. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/Makefile | 1 + criu/arch/aarch64/infect.c | 5 +++++ criu/arch/arm/Makefile | 1 + criu/arch/arm/infect.c | 5 +++++ criu/arch/ppc64/Makefile | 1 + criu/arch/ppc64/infect.c | 5 +++++ criu/arch/x86/Makefile | 1 + criu/arch/x86/infect.c | 5 +++++ 8 files changed, 24 insertions(+) create mode 100644 criu/arch/aarch64/infect.c create mode 100644 criu/arch/arm/infect.c create mode 100644 criu/arch/ppc64/infect.c create mode 100644 criu/arch/x86/infect.c diff --git a/criu/arch/aarch64/Makefile b/criu/arch/aarch64/Makefile index 95775a2d3..065a1fb75 100644 --- a/criu/arch/aarch64/Makefile +++ b/criu/arch/aarch64/Makefile @@ -11,3 +11,4 @@ obj-y += cpu.o obj-y += crtools.o obj-y += sigframe.o obj-y += bitops.o +obj-y += infect.o diff --git a/criu/arch/aarch64/infect.c b/criu/arch/aarch64/infect.c new file mode 100644 index 000000000..c1c1174aa --- /dev/null +++ b/criu/arch/aarch64/infect.c @@ -0,0 +1,5 @@ +#include +#include "asm/types.h" +#include "parasite-syscall.h" +#include "infect.h" +#include "infect-priv.h" diff --git a/criu/arch/arm/Makefile b/criu/arch/arm/Makefile index 8ab45cff4..cb725c5d9 100644 --- a/criu/arch/arm/Makefile +++ b/criu/arch/arm/Makefile @@ -11,3 +11,4 @@ obj-y += cpu.o obj-y += crtools.o obj-y += sigframe.o obj-y += bitops.o +obj-y += infect.o diff --git a/criu/arch/arm/infect.c b/criu/arch/arm/infect.c new file mode 100644 index 000000000..c1c1174aa --- /dev/null +++ b/criu/arch/arm/infect.c @@ -0,0 +1,5 @@ +#include +#include "asm/types.h" +#include "parasite-syscall.h" +#include "infect.h" +#include "infect-priv.h" diff --git a/criu/arch/ppc64/Makefile b/criu/arch/ppc64/Makefile index fda94369d..abbb7ce66 100644 --- a/criu/arch/ppc64/Makefile +++ b/criu/arch/ppc64/Makefile @@ -8,3 +8,4 @@ ccflags-y += -iquote $(SRC_DIR)/compel/include obj-y += cpu.o obj-y += crtools.o obj-y += sigframe.o +obj-y += infect.o diff --git a/criu/arch/ppc64/infect.c b/criu/arch/ppc64/infect.c new file mode 100644 index 000000000..c1c1174aa --- /dev/null +++ b/criu/arch/ppc64/infect.c @@ -0,0 +1,5 @@ +#include +#include "asm/types.h" +#include "parasite-syscall.h" +#include "infect.h" +#include "infect-priv.h" diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index 04a0cb3d0..bffa3f52a 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -12,6 +12,7 @@ asflags-y += -iquote $(obj)/include obj-y += cpu.o obj-y += crtools.o obj-y += sigframe.o +obj-y += infect.o ifeq ($(CONFIG_COMPAT),y) obj-y += sigaction_compat.o obj-y += call32.o diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c new file mode 100644 index 000000000..c1c1174aa --- /dev/null +++ b/criu/arch/x86/infect.c @@ -0,0 +1,5 @@ +#include +#include "asm/types.h" +#include "parasite-syscall.h" +#include "infect.h" +#include "infect-priv.h" From 3b8dcf0266c56364653871db45e0c0ef01951cf6 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 19 Oct 2016 12:32:44 +0300 Subject: [PATCH 0165/4375] infect: Move get_task_regs-s into arch/infect.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/crtools.c | 27 --- criu/arch/aarch64/include/asm/dump.h | 2 - criu/arch/aarch64/infect.c | 36 ++++ criu/arch/arm/crtools.c | 35 ---- criu/arch/arm/include/asm/dump.h | 2 - criu/arch/arm/infect.c | 42 +++++ criu/arch/ppc64/crtools.c | 232 -------------------------- criu/arch/ppc64/include/asm/dump.h | 2 - criu/arch/ppc64/infect.c | 238 +++++++++++++++++++++++++++ criu/arch/x86/crtools.c | 67 -------- criu/arch/x86/include/asm/dump.h | 2 - criu/arch/x86/infect.c | 73 ++++++++ criu/include/infect.h | 3 + criu/infect.c | 4 +- criu/parasite-syscall.c | 2 +- 15 files changed, 395 insertions(+), 372 deletions(-) diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index a02b63ac0..b3e5e55fc 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -81,33 +81,6 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))(src)->e -int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) -{ - struct iovec iov; - user_fpregs_struct_t fpsimd; - int ret; - - pr_info("Dumping GP/FPU registers for %d\n", pid); - - iov.iov_base = ®s; - iov.iov_len = sizeof(user_regs_struct_t); - if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov))) { - pr_perror("Failed to obtain CPU registers for %d", pid); - goto err; - } - - iov.iov_base = &fpsimd; - iov.iov_len = sizeof(fpsimd); - if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov))) { - pr_perror("Failed to obtain FPU registers for %d", pid); - goto err; - } - - ret = save(arg, ®s, &fpsimd); -err: - return ret; -} - int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd) { int i; diff --git a/criu/arch/aarch64/include/asm/dump.h b/criu/arch/aarch64/include/asm/dump.h index c53f67c3d..8a9666289 100644 --- a/criu/arch/aarch64/include/asm/dump.h +++ b/criu/arch/aarch64/include/asm/dump.h @@ -1,9 +1,7 @@ #ifndef __CR_ASM_DUMP_H__ #define __CR_ASM_DUMP_H__ -typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *); -extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *); extern int arch_alloc_thread_info(CoreEntry *core); extern void arch_free_thread_info(CoreEntry *core); diff --git a/criu/arch/aarch64/infect.c b/criu/arch/aarch64/infect.c index c1c1174aa..92b3c73b1 100644 --- a/criu/arch/aarch64/infect.c +++ b/criu/arch/aarch64/infect.c @@ -1,5 +1,41 @@ +#include #include +#include +#include +#include "asm/parasite-syscall.h" +#include "uapi/std/syscall-codes.h" #include "asm/types.h" +#include "criu-log.h" +#include "kerndat.h" #include "parasite-syscall.h" +#include "errno.h" #include "infect.h" #include "infect-priv.h" + +int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) +{ + struct iovec iov; + user_fpregs_struct_t fpsimd; + int ret; + + pr_info("Dumping GP/FPU registers for %d\n", pid); + + iov.iov_base = ®s; + iov.iov_len = sizeof(user_regs_struct_t); + if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov))) { + pr_perror("Failed to obtain CPU registers for %d", pid); + goto err; + } + + iov.iov_base = &fpsimd; + iov.iov_len = sizeof(fpsimd); + if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov))) { + pr_perror("Failed to obtain FPU registers for %d", pid); + goto err; + } + + ret = save(arg, ®s, &fpsimd); +err: + return ret; +} + diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index 66a42cada..fb267fe85 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -83,41 +83,6 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))((src)->ARM_##e) -#define PTRACE_GETVFPREGS 27 -int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) -{ - user_fpregs_struct_t vfp; - int ret = -1; - - pr_info("Dumping GP/FPU registers for %d\n", pid); - - if (ptrace(PTRACE_GETVFPREGS, pid, NULL, &vfp)) { - pr_perror("Can't obtain FPU registers for %d", pid); - goto err; - } - - /* Did we come from a system call? */ - if ((int)regs.ARM_ORIG_r0 >= 0) { - /* Restart the system call */ - switch ((long)(int)regs.ARM_r0) { - case -ERESTARTNOHAND: - case -ERESTARTSYS: - case -ERESTARTNOINTR: - regs.ARM_r0 = regs.ARM_ORIG_r0; - regs.ARM_pc -= 4; - break; - case -ERESTART_RESTARTBLOCK: - regs.ARM_r0 = __NR_restart_syscall; - regs.ARM_pc -= 4; - break; - } - } - - ret = save(arg, ®s, &vfp); -err: - return ret; -} - int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) { CoreEntry *core = x; diff --git a/criu/arch/arm/include/asm/dump.h b/criu/arch/arm/include/asm/dump.h index fa83b8267..f08e53843 100644 --- a/criu/arch/arm/include/asm/dump.h +++ b/criu/arch/arm/include/asm/dump.h @@ -1,9 +1,7 @@ #ifndef __CR_ASM_DUMP_H__ #define __CR_ASM_DUMP_H__ -typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *); -extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *); extern int arch_alloc_thread_info(CoreEntry *core); extern void arch_free_thread_info(CoreEntry *core); diff --git a/criu/arch/arm/infect.c b/criu/arch/arm/infect.c index c1c1174aa..d524d5130 100644 --- a/criu/arch/arm/infect.c +++ b/criu/arch/arm/infect.c @@ -1,5 +1,47 @@ +#include #include +#include "asm/parasite-syscall.h" +#include "uapi/std/syscall-codes.h" #include "asm/types.h" +#include "criu-log.h" +#include "kerndat.h" #include "parasite-syscall.h" +#include "errno.h" #include "infect.h" #include "infect-priv.h" + +#define PTRACE_GETVFPREGS 27 +int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) +{ + user_fpregs_struct_t vfp; + int ret = -1; + + pr_info("Dumping GP/FPU registers for %d\n", pid); + + if (ptrace(PTRACE_GETVFPREGS, pid, NULL, &vfp)) { + pr_perror("Can't obtain FPU registers for %d", pid); + goto err; + } + + /* Did we come from a system call? */ + if ((int)regs.ARM_ORIG_r0 >= 0) { + /* Restart the system call */ + switch ((long)(int)regs.ARM_r0) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + regs.ARM_r0 = regs.ARM_ORIG_r0; + regs.ARM_pc -= 4; + break; + case -ERESTART_RESTARTBLOCK: + regs.ARM_r0 = __NR_restart_syscall; + regs.ARM_pc -= 4; + break; + } + } + + ret = save(arg, ®s, &vfp); +err: + return ret; +} + diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index 14d2dc70c..fbcdf5149 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -25,15 +25,6 @@ #include "images/core.pb-c.h" #include "images/creds.pb-c.h" -#ifndef NT_PPC_TM_SPR -#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */ -#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */ -#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */ -#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */ -#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */ -#endif - - /* * Injected syscall instruction */ @@ -118,55 +109,6 @@ static UserPpc64FpstateEntry *copy_fp_regs(uint64_t *fpregs) return fpe; } -/* This is the layout of the POWER7 VSX registers and the way they - * overlap with the existing FPR and VMX registers. - * - * VSR doubleword 0 VSR doubleword 1 - * ---------------------------------------------------------------- - * VSR[0] | FPR[0] | | - * ---------------------------------------------------------------- - * VSR[1] | FPR[1] | | - * ---------------------------------------------------------------- - * | ... | | - * ---------------------------------------------------------------- - * VSR[30] | FPR[30] | | - * ---------------------------------------------------------------- - * VSR[31] | FPR[31] | | - * ---------------------------------------------------------------- - * VSR[32] | VR[0] | - * ---------------------------------------------------------------- - * VSR[33] | VR[1] | - * ---------------------------------------------------------------- - * | ... | - * ---------------------------------------------------------------- - * VSR[62] | VR[30] | - * ---------------------------------------------------------------- - * VSR[63] | VR[31] | - * ---------------------------------------------------------------- - * - * PTRACE_GETFPREGS returns FPR[0..31] + FPSCR - * PTRACE_GETVRREGS returns VR[0..31] + VSCR + VRSAVE - * PTRACE_GETVSRREGS returns VSR[0..31] - * - * PTRACE_GETVSRREGS and PTRACE_GETFPREGS are required since we need - * to save FPSCR too. - * - * There 32 VSX double word registers to save since the 32 first VSX double - * word registers are saved through FPR[0..32] and the remaining registers - * are saved when saving the Altivec registers VR[0..32]. - */ - -static int get_fpu_regs(pid_t pid, user_fpregs_struct_t *fp) -{ - if (ptrace(PTRACE_GETFPREGS, pid, 0, (void *)&fp->fpregs) < 0) { - pr_perror("Couldn't get floating-point registers"); - return -1; - } - fp->flags |= USER_FPREGS_FL_FP; - - return 0; -} - static void put_fpu_regs(mcontext_t *mc, UserPpc64FpstateEntry *fpe) { int i; @@ -209,24 +151,6 @@ static UserPpc64VrstateEntry *copy_altivec_regs(__vector128 *vrregs) return vse; } -static int get_altivec_regs(pid_t pid, user_fpregs_struct_t *fp) -{ - if (ptrace(PTRACE_GETVRREGS, pid, 0, (void*)&fp->vrregs) < 0) { - /* PTRACE_GETVRREGS returns EIO if Altivec is not supported. - * This should not happen if msr_vec is set. */ - if (errno != EIO) { - pr_perror("Couldn't get Altivec registers"); - return -1; - } - pr_debug("Altivec not supported\n"); - } - else { - pr_debug("Dumping Altivec registers\n"); - fp->flags |= USER_FPREGS_FL_ALTIVEC; - } - return 0; -} - static int put_altivec_regs(mcontext_t *mc, UserPpc64VrstateEntry *vse) { vrregset_t *v_regs = (vrregset_t *)(((unsigned long)mc->vmx_reserve + 15) & ~0xful); @@ -278,35 +202,6 @@ static UserPpc64VsxstateEntry* copy_vsx_regs(uint64_t *vsregs) return vse; } -/* - * Since the FPR[0-31] is stored in the first double word of VSR[0-31] and - * FPR are saved through the FP state, there is no need to save the upper part - * of the first 32 VSX registers. - * Furthermore, the 32 last VSX registers are also the 32 Altivec registers - * already saved, so no need to save them. - * As a consequence, only the doubleword 1 of the 32 first VSX registers have - * to be saved (the ones are returned by PTRACE_GETVSRREGS). - */ -static int get_vsx_regs(pid_t pid, user_fpregs_struct_t *fp) -{ - if (ptrace(PTRACE_GETVSRREGS, pid, 0, (void*)fp->vsxregs) < 0) { - /* - * EIO is returned in the case PTRACE_GETVRREGS is not - * supported. - */ - if (errno != EIO) { - pr_perror("Couldn't get VSX registers"); - return -1; - } - pr_debug("VSX register's dump not supported.\n"); - } - else { - pr_debug("Dumping VSX registers\n"); - fp->flags |= USER_FPREGS_FL_VSX; - } - return 0; -} - static int put_vsx_regs(mcontext_t *mc, UserPpc64VsxstateEntry *vse) { uint64_t *buf; @@ -415,56 +310,6 @@ static void xfree_tm_state(UserPpc64TmRegsEntry *tme) } } -static int get_tm_regs(pid_t pid, user_fpregs_struct_t *fpregs) -{ - struct iovec iov; - - pr_debug("Dumping TM registers\n"); - -#define TM_REQUIRED 0 -#define TM_OPTIONAL 1 -#define PTRACE_GET_TM(s,n,c,u) do { \ - iov.iov_base = &s; \ - iov.iov_len = sizeof(s); \ - if (ptrace(PTRACE_GETREGSET, pid, c, &iov)) { \ - if (!u || errno != EIO) { \ - pr_perror("Couldn't get TM "n); \ - pr_err("Your kernel seems to not support the " \ - "new TM ptrace API (>= 4.8)\n"); \ - goto out_free; \ - } \ - pr_debug("TM "n" not supported.\n"); \ - iov.iov_base = NULL; \ - } \ -} while(0) - - /* Get special registers */ - PTRACE_GET_TM(fpregs->tm.tm_spr_regs, "SPR", NT_PPC_TM_SPR, TM_REQUIRED); - - /* Get checkpointed regular registers */ - PTRACE_GET_TM(fpregs->tm.regs, "GPR", NT_PPC_TM_CGPR, TM_REQUIRED); - - /* Get checkpointed FP registers */ - PTRACE_GET_TM(fpregs->tm.fpregs, "FPR", NT_PPC_TM_CFPR, TM_OPTIONAL); - if (iov.iov_base) - fpregs->tm.flags |= USER_FPREGS_FL_FP; - - /* Get checkpointed VMX (Altivec) registers */ - PTRACE_GET_TM(fpregs->tm.vrregs, "VMX", NT_PPC_TM_CVMX, TM_OPTIONAL); - if (iov.iov_base) - fpregs->tm.flags |= USER_FPREGS_FL_ALTIVEC; - - /* Get checkpointed VSX registers */ - PTRACE_GET_TM(fpregs->tm.vsxregs, "VSX", NT_PPC_TM_CVSX, TM_OPTIONAL); - if (iov.iov_base) - fpregs->tm.flags |= USER_FPREGS_FL_VSX; - - return 0; - -out_free: - return -1; /* still failing the checkpoint */ -} - static int put_tm_regs(struct rt_sigframe *f, UserPpc64TmRegsEntry *tme) { /* @@ -499,71 +344,6 @@ static int put_tm_regs(struct rt_sigframe *f, UserPpc64TmRegsEntry *tme) } /****************************************************************************/ -static int __get_task_regs(pid_t pid, user_regs_struct_t *regs, - user_fpregs_struct_t *fpregs) -{ - pr_info("Dumping GP/FPU registers for %d\n", pid); - - /* - * This is inspired by kernel function check_syscall_restart in - * arch/powerpc/kernel/signal.c - */ -#ifndef TRAP -#define TRAP(r) ((r).trap & ~0xF) -#endif - - if (TRAP(*regs) == 0x0C00 && regs->ccr & 0x10000000) { - /* Restart the system call */ - switch (regs->gpr[3]) { - case ERESTARTNOHAND: - case ERESTARTSYS: - case ERESTARTNOINTR: - regs->gpr[3] = regs->orig_gpr3; - regs->nip -= 4; - break; - case ERESTART_RESTARTBLOCK: - regs->gpr[0] = __NR_restart_syscall; - regs->nip -= 4; - break; - } - } - - /* Resetting trap since we are now coming from user space. */ - regs->trap = 0; - - fpregs->flags = 0; - /* - * Check for Transactional Memory operation in progress. - * Until we have support of TM register's state through the ptrace API, - * we can't checkpoint process with TM operation in progress (almost - * impossible) or suspended (easy to get). - */ - if (MSR_TM_ACTIVE(regs->msr)) { - pr_debug("Task %d has %s TM operation at 0x%lx\n", - pid, - (regs->msr & MSR_TMS) ? "a suspended" : "an active", - regs->nip); - if (get_tm_regs(pid, fpregs)) - return -1; - fpregs->flags = USER_FPREGS_FL_TM; - } - - if (get_fpu_regs(pid, fpregs)) - return -1; - - if (get_altivec_regs(pid, fpregs)) - return -1; - - if (fpregs->flags & USER_FPREGS_FL_ALTIVEC) { - /* - * Save the VSX registers if Altivec registers are supported - */ - if (get_vsx_regs(pid, fpregs)) - return -1; - } - return 0; -} - static int copy_tm_regs(user_regs_struct_t *regs, user_fpregs_struct_t *fpregs, CoreEntry *core) { @@ -701,18 +481,6 @@ int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f) } /****************************************************************************/ -int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) -{ - user_fpregs_struct_t fpregs; - int ret; - - ret = __get_task_regs(pid, ®s, &fpregs); - if (ret) - return ret; - - return save(arg, ®s, &fpregs); -} - int arch_alloc_thread_info(CoreEntry *core) { ThreadInfoPpc64 *ti_ppc64; diff --git a/criu/arch/ppc64/include/asm/dump.h b/criu/arch/ppc64/include/asm/dump.h index 0c88b7a56..6439adafd 100644 --- a/criu/arch/ppc64/include/asm/dump.h +++ b/criu/arch/ppc64/include/asm/dump.h @@ -1,9 +1,7 @@ #ifndef __CR_ASM_DUMP_H__ #define __CR_ASM_DUMP_H__ -typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *); -extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *); extern int arch_alloc_thread_info(CoreEntry *core); extern void arch_free_thread_info(CoreEntry *core); diff --git a/criu/arch/ppc64/infect.c b/criu/arch/ppc64/infect.c index c1c1174aa..6c9692f7c 100644 --- a/criu/arch/ppc64/infect.c +++ b/criu/arch/ppc64/infect.c @@ -1,5 +1,243 @@ +#include #include +#include +#include +#include "uapi/std/syscall-codes.h" #include "asm/types.h" +#include "ptrace.h" #include "parasite-syscall.h" +#include "errno.h" +#include "criu-log.h" #include "infect.h" #include "infect-priv.h" + +#ifndef NT_PPC_TM_SPR +#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */ +#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */ +#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */ +#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */ +#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */ +#endif + +/* This is the layout of the POWER7 VSX registers and the way they + * overlap with the existing FPR and VMX registers. + * + * VSR doubleword 0 VSR doubleword 1 + * ---------------------------------------------------------------- + * VSR[0] | FPR[0] | | + * ---------------------------------------------------------------- + * VSR[1] | FPR[1] | | + * ---------------------------------------------------------------- + * | ... | | + * ---------------------------------------------------------------- + * VSR[30] | FPR[30] | | + * ---------------------------------------------------------------- + * VSR[31] | FPR[31] | | + * ---------------------------------------------------------------- + * VSR[32] | VR[0] | + * ---------------------------------------------------------------- + * VSR[33] | VR[1] | + * ---------------------------------------------------------------- + * | ... | + * ---------------------------------------------------------------- + * VSR[62] | VR[30] | + * ---------------------------------------------------------------- + * VSR[63] | VR[31] | + * ---------------------------------------------------------------- + * + * PTRACE_GETFPREGS returns FPR[0..31] + FPSCR + * PTRACE_GETVRREGS returns VR[0..31] + VSCR + VRSAVE + * PTRACE_GETVSRREGS returns VSR[0..31] + * + * PTRACE_GETVSRREGS and PTRACE_GETFPREGS are required since we need + * to save FPSCR too. + * + * There 32 VSX double word registers to save since the 32 first VSX double + * word registers are saved through FPR[0..32] and the remaining registers + * are saved when saving the Altivec registers VR[0..32]. + */ + +static int get_fpu_regs(pid_t pid, user_fpregs_struct_t *fp) +{ + if (ptrace(PTRACE_GETFPREGS, pid, 0, (void *)&fp->fpregs) < 0) { + pr_perror("Couldn't get floating-point registers"); + return -1; + } + fp->flags |= USER_FPREGS_FL_FP; + + return 0; +} + +static int get_altivec_regs(pid_t pid, user_fpregs_struct_t *fp) +{ + if (ptrace(PTRACE_GETVRREGS, pid, 0, (void*)&fp->vrregs) < 0) { + /* PTRACE_GETVRREGS returns EIO if Altivec is not supported. + * This should not happen if msr_vec is set. */ + if (errno != EIO) { + pr_perror("Couldn't get Altivec registers"); + return -1; + } + pr_debug("Altivec not supported\n"); + } + else { + pr_debug("Dumping Altivec registers\n"); + fp->flags |= USER_FPREGS_FL_ALTIVEC; + } + return 0; +} + +/* + * Since the FPR[0-31] is stored in the first double word of VSR[0-31] and + * FPR are saved through the FP state, there is no need to save the upper part + * of the first 32 VSX registers. + * Furthermore, the 32 last VSX registers are also the 32 Altivec registers + * already saved, so no need to save them. + * As a consequence, only the doubleword 1 of the 32 first VSX registers have + * to be saved (the ones are returned by PTRACE_GETVSRREGS). + */ +static int get_vsx_regs(pid_t pid, user_fpregs_struct_t *fp) +{ + if (ptrace(PTRACE_GETVSRREGS, pid, 0, (void*)fp->vsxregs) < 0) { + /* + * EIO is returned in the case PTRACE_GETVRREGS is not + * supported. + */ + if (errno != EIO) { + pr_perror("Couldn't get VSX registers"); + return -1; + } + pr_debug("VSX register's dump not supported.\n"); + } + else { + pr_debug("Dumping VSX registers\n"); + fp->flags |= USER_FPREGS_FL_VSX; + } + return 0; +} + +static int get_tm_regs(pid_t pid, user_fpregs_struct_t *fpregs) +{ + struct iovec iov; + + pr_debug("Dumping TM registers\n"); + +#define TM_REQUIRED 0 +#define TM_OPTIONAL 1 +#define PTRACE_GET_TM(s,n,c,u) do { \ + iov.iov_base = &s; \ + iov.iov_len = sizeof(s); \ + if (ptrace(PTRACE_GETREGSET, pid, c, &iov)) { \ + if (!u || errno != EIO) { \ + pr_perror("Couldn't get TM "n); \ + pr_err("Your kernel seems to not support the " \ + "new TM ptrace API (>= 4.8)\n"); \ + goto out_free; \ + } \ + pr_debug("TM "n" not supported.\n"); \ + iov.iov_base = NULL; \ + } \ +} while(0) + + /* Get special registers */ + PTRACE_GET_TM(fpregs->tm.tm_spr_regs, "SPR", NT_PPC_TM_SPR, TM_REQUIRED); + + /* Get checkpointed regular registers */ + PTRACE_GET_TM(fpregs->tm.regs, "GPR", NT_PPC_TM_CGPR, TM_REQUIRED); + + /* Get checkpointed FP registers */ + PTRACE_GET_TM(fpregs->tm.fpregs, "FPR", NT_PPC_TM_CFPR, TM_OPTIONAL); + if (iov.iov_base) + fpregs->tm.flags |= USER_FPREGS_FL_FP; + + /* Get checkpointed VMX (Altivec) registers */ + PTRACE_GET_TM(fpregs->tm.vrregs, "VMX", NT_PPC_TM_CVMX, TM_OPTIONAL); + if (iov.iov_base) + fpregs->tm.flags |= USER_FPREGS_FL_ALTIVEC; + + /* Get checkpointed VSX registers */ + PTRACE_GET_TM(fpregs->tm.vsxregs, "VSX", NT_PPC_TM_CVSX, TM_OPTIONAL); + if (iov.iov_base) + fpregs->tm.flags |= USER_FPREGS_FL_VSX; + + return 0; + +out_free: + return -1; /* still failing the checkpoint */ +} + +static int __get_task_regs(pid_t pid, user_regs_struct_t *regs, + user_fpregs_struct_t *fpregs) +{ + pr_info("Dumping GP/FPU registers for %d\n", pid); + + /* + * This is inspired by kernel function check_syscall_restart in + * arch/powerpc/kernel/signal.c + */ +#ifndef TRAP +#define TRAP(r) ((r).trap & ~0xF) +#endif + + if (TRAP(*regs) == 0x0C00 && regs->ccr & 0x10000000) { + /* Restart the system call */ + switch (regs->gpr[3]) { + case ERESTARTNOHAND: + case ERESTARTSYS: + case ERESTARTNOINTR: + regs->gpr[3] = regs->orig_gpr3; + regs->nip -= 4; + break; + case ERESTART_RESTARTBLOCK: + regs->gpr[0] = __NR_restart_syscall; + regs->nip -= 4; + break; + } + } + + /* Resetting trap since we are now coming from user space. */ + regs->trap = 0; + + fpregs->flags = 0; + /* + * Check for Transactional Memory operation in progress. + * Until we have support of TM register's state through the ptrace API, + * we can't checkpoint process with TM operation in progress (almost + * impossible) or suspended (easy to get). + */ + if (MSR_TM_ACTIVE(regs->msr)) { + pr_debug("Task %d has %s TM operation at 0x%lx\n", + pid, + (regs->msr & MSR_TMS) ? "a suspended" : "an active", + regs->nip); + if (get_tm_regs(pid, fpregs)) + return -1; + fpregs->flags = USER_FPREGS_FL_TM; + } + + if (get_fpu_regs(pid, fpregs)) + return -1; + + if (get_altivec_regs(pid, fpregs)) + return -1; + + if (fpregs->flags & USER_FPREGS_FL_ALTIVEC) { + /* + * Save the VSX registers if Altivec registers are supported + */ + if (get_vsx_regs(pid, fpregs)) + return -1; + } + return 0; +} + +int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) +{ + user_fpregs_struct_t fpregs; + int ret; + + ret = __get_task_regs(pid, ®s, &fpregs); + if (ret) + return ret; + + return save(arg, ®s, &fpregs); +} diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index ee1625e14..de25413a2 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -187,73 +187,6 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, return err; } -#define get_signed_user_reg(pregs, name) \ - ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \ - (int32_t)((pregs)->compat.name)) - -int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) -{ - user_fpregs_struct_t xsave = { }, *xs = NULL; - - struct iovec iov; - int ret = -1; - - pr_info("Dumping general registers for %d in %s mode\n", pid, - user_regs_native(®s) ? "native" : "compat"); - - /* Did we come from a system call? */ - if (get_signed_user_reg(®s, orig_ax) >= 0) { - /* Restart the system call */ - switch (get_signed_user_reg(®s, ax)) { - case -ERESTARTNOHAND: - case -ERESTARTSYS: - case -ERESTARTNOINTR: - set_user_reg(®s, ax, get_user_reg(®s, orig_ax)); - set_user_reg(®s, ip, get_user_reg(®s, ip) - 2); - break; - case -ERESTART_RESTARTBLOCK: - pr_warn("Will restore %d with interrupted system call\n", pid); - set_user_reg(®s, ax, -EINTR); - break; - } - } - -#ifndef PTRACE_GETREGSET -# define PTRACE_GETREGSET 0x4204 -#endif - - if (!cpu_has_feature(X86_FEATURE_FPU)) - goto out; - - /* - * FPU fetched either via fxsave or via xsave, - * thus decode it accrodingly. - */ - - pr_info("Dumping GP/FPU registers for %d\n", pid); - - if (cpu_has_feature(X86_FEATURE_OSXSAVE)) { - iov.iov_base = &xsave; - iov.iov_len = sizeof(xsave); - - if (ptrace(PTRACE_GETREGSET, pid, (unsigned int)NT_X86_XSTATE, &iov) < 0) { - pr_perror("Can't obtain FPU registers for %d", pid); - goto err; - } - } else { - if (ptrace(PTRACE_GETFPREGS, pid, NULL, &xsave)) { - pr_perror("Can't obtain FPU registers for %d", pid); - goto err; - } - } - - xs = &xsave; -out: - ret = save(arg, ®s, xs); -err: - return ret; -} - int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) { CoreEntry *core = x; diff --git a/criu/arch/x86/include/asm/dump.h b/criu/arch/x86/include/asm/dump.h index 4b928a8de..61e53dced 100644 --- a/criu/arch/x86/include/asm/dump.h +++ b/criu/arch/x86/include/asm/dump.h @@ -1,9 +1,7 @@ #ifndef __CR_ASM_DUMP_H__ #define __CR_ASM_DUMP_H__ -typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *); -extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *); extern int arch_alloc_thread_info(CoreEntry *core); extern void arch_free_thread_info(CoreEntry *core); diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index c1c1174aa..c604b8841 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -1,5 +1,78 @@ +#include #include +#include +#include +#include "asm/fpu.h" #include "asm/types.h" +#include "errno.h" +#include "asm/cpu.h" #include "parasite-syscall.h" #include "infect.h" #include "infect-priv.h" + +#define get_signed_user_reg(pregs, name) \ + ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \ + (int32_t)((pregs)->compat.name)) + +int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) +{ + user_fpregs_struct_t xsave = { }, *xs = NULL; + + struct iovec iov; + int ret = -1; + + pr_info("Dumping general registers for %d in %s mode\n", pid, + user_regs_native(®s) ? "native" : "compat"); + + /* Did we come from a system call? */ + if (get_signed_user_reg(®s, orig_ax) >= 0) { + /* Restart the system call */ + switch (get_signed_user_reg(®s, ax)) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + set_user_reg(®s, ax, get_user_reg(®s, orig_ax)); + set_user_reg(®s, ip, get_user_reg(®s, ip) - 2); + break; + case -ERESTART_RESTARTBLOCK: + pr_warn("Will restore %d with interrupted system call\n", pid); + set_user_reg(®s, ax, -EINTR); + break; + } + } + +#ifndef PTRACE_GETREGSET +# define PTRACE_GETREGSET 0x4204 +#endif + + if (!cpu_has_feature(X86_FEATURE_FPU)) + goto out; + + /* + * FPU fetched either via fxsave or via xsave, + * thus decode it accrodingly. + */ + + pr_info("Dumping GP/FPU registers for %d\n", pid); + + if (cpu_has_feature(X86_FEATURE_OSXSAVE)) { + iov.iov_base = &xsave; + iov.iov_len = sizeof(xsave); + + if (ptrace(PTRACE_GETREGSET, pid, (unsigned int)NT_X86_XSTATE, &iov) < 0) { + pr_perror("Can't obtain FPU registers for %d", pid); + goto err; + } + } else { + if (ptrace(PTRACE_GETFPREGS, pid, NULL, &xsave)) { + pr_perror("Can't obtain FPU registers for %d", pid); + goto err; + } + } + + xs = &xsave; +out: + ret = save(arg, ®s, xs); +err: + return ret; +} diff --git a/criu/include/infect.h b/criu/include/infect.h index 072143eed..40ec9132d 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -105,4 +105,7 @@ extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *); #define INFECT_FAIL_CONNECT 0x2 /* make parasite connect() fail */ #define INFECT_NO_BREAKPOINTS 0x4 /* no breakpoints in pie tracking */ +typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); +extern int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *); + #endif diff --git a/criu/infect.c b/criu/infect.c index 15e117139..b958054d2 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -581,11 +581,11 @@ static int parasite_start_daemon(struct parasite_ctl *ctl) /* * Get task registers before going daemon, since the - * get_task_regs needs to call ptrace on _stopped_ task, + * compel_get_task_regs needs to call ptrace on _stopped_ task, * while in daemon it is not such. */ - if (get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) { + if (compel_get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) { pr_err("Can't obtain regs for thread %d\n", pid); return -1; } diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 8ff128287..bbd0c2b01 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -243,7 +243,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, return -1; } - ret = get_task_regs(pid, octx.regs, save_task_regs, core); + ret = compel_get_task_regs(pid, octx.regs, save_task_regs, core); if (ret) { pr_err("Can't obtain regs for thread %d\n", pid); return -1; From 62e1ba93516de44c42249499e681b31f3e4a1c57 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 19 Oct 2016 12:43:00 +0300 Subject: [PATCH 0166/4375] infect: Move mmap_seized() and syscall_seized() into arch/infect.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/crtools.c | 60 ------------ .../aarch64/include/asm/parasite-syscall.h | 4 - criu/arch/aarch64/infect.c | 59 ++++++++++++ criu/arch/arm/crtools.c | 60 ------------ criu/arch/arm/include/asm/parasite-syscall.h | 4 - criu/arch/arm/infect.c | 60 ++++++++++++ criu/arch/ppc64/crtools.c | 54 ----------- .../arch/ppc64/include/asm/parasite-syscall.h | 4 - criu/arch/ppc64/infect.c | 54 +++++++++++ criu/arch/x86/crtools.c | 89 ------------------ criu/arch/x86/include/asm/parasite-syscall.h | 4 - criu/arch/x86/infect.c | 93 +++++++++++++++++++ criu/cr-exec.c | 2 +- criu/include/infect-priv.h | 9 ++ criu/include/parasite-syscall.h | 5 - criu/infect.c | 14 +-- 16 files changed, 283 insertions(+), 292 deletions(-) diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index b3e5e55fc..e7e7be9c3 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -20,23 +20,6 @@ #include "infect.h" #include "infect-priv.h" -/* - * Injected syscall instruction - */ -const char code_syscall[] = { - 0x01, 0x00, 0x00, 0xd4, /* SVC #0 */ - 0x00, 0x00, 0x20, 0xd4 /* BRK #0 */ -}; - -static const int -code_syscall_aligned = round_up(sizeof(code_syscall), sizeof(long)); - -static inline void __always_unused __check_code_syscall(void) -{ - BUILD_BUG_ON(code_syscall_aligned != BUILTIN_SYSCALL_SIZE); - BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); -} - void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) { regs->pc = new_ip; @@ -52,33 +35,6 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) return true; } -int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, - unsigned long arg1, - unsigned long arg2, - unsigned long arg3, - unsigned long arg4, - unsigned long arg5, - unsigned long arg6) -{ - user_regs_struct_t regs = ctl->orig.regs; - int err; - - regs.regs[8] = (unsigned long)nr; - regs.regs[0] = arg1; - regs.regs[1] = arg2; - regs.regs[2] = arg3; - regs.regs[3] = arg4; - regs.regs[4] = arg5; - regs.regs[5] = arg6; - regs.regs[6] = 0; - regs.regs[7] = 0; - - err = compel_execute_syscall(ctl, ®s, code_syscall); - - *ret = regs.regs[0]; - return err; -} - #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))(src)->e int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd) @@ -179,22 +135,6 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) return 0; } -void *mmap_seized( - struct parasite_ctl *ctl, - void *addr, size_t length, int prot, - int flags, int fd, off_t offset) -{ - unsigned long map; - int err; - - err = syscall_seized(ctl, __NR_mmap, &map, - (unsigned long)addr, length, prot, flags, fd, offset); - if (err < 0 || (long)map < 0) - map = 0; - - return (void *)map; -} - int restore_gpregs(struct rt_sigframe *f, UserRegsEntry *r) { #define CPREG1(d) f->uc.uc_mcontext.d = r->d diff --git a/criu/arch/aarch64/include/asm/parasite-syscall.h b/criu/arch/aarch64/include/asm/parasite-syscall.h index 7a5591ad5..e420ccbdc 100644 --- a/criu/arch/aarch64/include/asm/parasite-syscall.h +++ b/criu/arch/aarch64/include/asm/parasite-syscall.h @@ -9,8 +9,4 @@ struct parasite_ctl; void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); -void *mmap_seized(struct parasite_ctl *ctl, - void *addr, size_t length, int prot, - int flags, int fd, off_t offset); - #endif diff --git a/criu/arch/aarch64/infect.c b/criu/arch/aarch64/infect.c index 92b3c73b1..2411cd6e8 100644 --- a/criu/arch/aarch64/infect.c +++ b/criu/arch/aarch64/infect.c @@ -12,6 +12,23 @@ #include "infect.h" #include "infect-priv.h" +/* + * Injected syscall instruction + */ +const char code_syscall[] = { + 0x01, 0x00, 0x00, 0xd4, /* SVC #0 */ + 0x00, 0x00, 0x20, 0xd4 /* BRK #0 */ +}; + +static const int +code_syscall_aligned = round_up(sizeof(code_syscall), sizeof(long)); + +static inline void __always_unused __check_code_syscall(void) +{ + BUILD_BUG_ON(code_syscall_aligned != BUILTIN_SYSCALL_SIZE); + BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); +} + int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) { struct iovec iov; @@ -39,3 +56,45 @@ err: return ret; } +int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5, + unsigned long arg6) +{ + user_regs_struct_t regs = ctl->orig.regs; + int err; + + regs.regs[8] = (unsigned long)nr; + regs.regs[0] = arg1; + regs.regs[1] = arg2; + regs.regs[2] = arg3; + regs.regs[3] = arg4; + regs.regs[4] = arg5; + regs.regs[5] = arg6; + regs.regs[6] = 0; + regs.regs[7] = 0; + + err = compel_execute_syscall(ctl, ®s, code_syscall); + + *ret = regs.regs[0]; + return err; +} + +void *mmap_re(struct parasite_ctl *ctl, + void *addr, size_t length, int prot, + int flags, int fd, off_t offset) +{ + unsigned long map; + int err; + + err = compel_syscall(ctl, __NR_mmap, &map, + (unsigned long)addr, length, prot, flags, fd, offset); + if (err < 0 || (long)map < 0) + map = 0; + + return (void *)map; +} + diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index fb267fe85..78fa02a99 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -21,23 +21,6 @@ #include "infect.h" #include "infect-priv.h" -/* - * Injected syscall instruction - */ -const char code_syscall[] = { - 0x00, 0x00, 0x00, 0xef, /* SVC #0 */ - 0xf0, 0x01, 0xf0, 0xe7 /* UDF #32 */ -}; - -static const int -code_syscall_aligned = round_up(sizeof(code_syscall), sizeof(long)); - -static inline __always_unused void __check_code_syscall(void) -{ - BUILD_BUG_ON(code_syscall_aligned != BUILTIN_SYSCALL_SIZE); - BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); -} - void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) { regs->ARM_pc = new_ip; @@ -56,31 +39,6 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) return true; } -int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, - unsigned long arg1, - unsigned long arg2, - unsigned long arg3, - unsigned long arg4, - unsigned long arg5, - unsigned long arg6) -{ - user_regs_struct_t regs = ctl->orig.regs; - int err; - - regs.ARM_r7 = (unsigned long)nr; - regs.ARM_r0 = arg1; - regs.ARM_r1 = arg2; - regs.ARM_r2 = arg3; - regs.ARM_r3 = arg4; - regs.ARM_r4 = arg5; - regs.ARM_r5 = arg6; - - err = compel_execute_syscall(ctl, ®s, code_syscall); - - *ret = regs.ARM_r0; - return err; -} - #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))((src)->ARM_##e) int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) @@ -172,24 +130,6 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) return 0; } -void *mmap_seized(struct parasite_ctl *ctl, - void *addr, size_t length, int prot, - int flags, int fd, off_t offset) -{ - unsigned long map; - int err; - - if (offset & ~PAGE_MASK) - return 0; - - err = syscall_seized(ctl, __NR_mmap2, &map, - (unsigned long)addr, length, prot, flags, fd, offset >> 12); - if (err < 0 || map > kdat.task_size) - map = 0; - - return (void *)map; -} - int restore_gpregs(struct rt_sigframe *f, UserArmRegsEntry *r) { #define CPREG1(d) f->sig.uc.uc_mcontext.arm_##d = r->d diff --git a/criu/arch/arm/include/asm/parasite-syscall.h b/criu/arch/arm/include/asm/parasite-syscall.h index 7a5591ad5..e420ccbdc 100644 --- a/criu/arch/arm/include/asm/parasite-syscall.h +++ b/criu/arch/arm/include/asm/parasite-syscall.h @@ -9,8 +9,4 @@ struct parasite_ctl; void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); -void *mmap_seized(struct parasite_ctl *ctl, - void *addr, size_t length, int prot, - int flags, int fd, off_t offset); - #endif diff --git a/criu/arch/arm/infect.c b/criu/arch/arm/infect.c index d524d5130..ec84c20aa 100644 --- a/criu/arch/arm/infect.c +++ b/criu/arch/arm/infect.c @@ -10,6 +10,23 @@ #include "infect.h" #include "infect-priv.h" +/* + * Injected syscall instruction + */ +const char code_syscall[] = { + 0x00, 0x00, 0x00, 0xef, /* SVC #0 */ + 0xf0, 0x01, 0xf0, 0xe7 /* UDF #32 */ +}; + +static const int +code_syscall_aligned = round_up(sizeof(code_syscall), sizeof(long)); + +static inline __always_unused void __check_code_syscall(void) +{ + BUILD_BUG_ON(code_syscall_aligned != BUILTIN_SYSCALL_SIZE); + BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); +} + #define PTRACE_GETVFPREGS 27 int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) { @@ -45,3 +62,46 @@ err: return ret; } +int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5, + unsigned long arg6) +{ + user_regs_struct_t regs = ctl->orig.regs; + int err; + + regs.ARM_r7 = (unsigned long)nr; + regs.ARM_r0 = arg1; + regs.ARM_r1 = arg2; + regs.ARM_r2 = arg3; + regs.ARM_r3 = arg4; + regs.ARM_r4 = arg5; + regs.ARM_r5 = arg6; + + err = compel_execute_syscall(ctl, ®s, code_syscall); + + *ret = regs.ARM_r0; + return err; +} + +void *remote_mmap(struct parasite_ctl *ctl, + void *addr, size_t length, int prot, + int flags, int fd, off_t offset) +{ + unsigned long map; + int err; + + if (offset & ~PAGE_MASK) + return 0; + + err = compel_syscall(ctl, __NR_mmap2, &map, + (unsigned long)addr, length, prot, flags, fd, offset >> 12); + if (err < 0 || map > kdat.task_size) + map = 0; + + return (void *)map; +} + diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index fbcdf5149..33c1ec416 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -25,20 +25,6 @@ #include "images/core.pb-c.h" #include "images/creds.pb-c.h" -/* - * Injected syscall instruction - */ -const u32 code_syscall[] = { - 0x44000002, /* sc */ - 0x0fe00000 /* twi 31,0,0 */ -}; - -static inline void __always_unused __check_code_syscall(void) -{ - BUILD_BUG_ON(sizeof(code_syscall) != BUILTIN_SYSCALL_SIZE); - BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); -} - void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) { /* @@ -60,31 +46,6 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) return true; } -int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, - unsigned long arg1, - unsigned long arg2, - unsigned long arg3, - unsigned long arg4, - unsigned long arg5, - unsigned long arg6) -{ - user_regs_struct_t regs = ctl->orig.regs; - int err; - - regs.gpr[0] = (unsigned long)nr; - regs.gpr[3] = arg1; - regs.gpr[4] = arg2; - regs.gpr[5] = arg3; - regs.gpr[6] = arg4; - regs.gpr[7] = arg5; - regs.gpr[8] = arg6; - - err = compel_execute_syscall(ctl, ®s, (char*)code_syscall); - - *ret = regs.gpr[3]; - return err; -} - static UserPpc64FpstateEntry *copy_fp_regs(uint64_t *fpregs) { UserPpc64FpstateEntry *fpe; @@ -565,18 +526,3 @@ int restore_gpregs(struct rt_sigframe *f, UserPpc64RegsEntry *r) return 0; } - -void *mmap_seized(struct parasite_ctl *ctl, - void *addr, size_t length, int prot, - int flags, int fd, off_t offset) -{ - unsigned long map = 0; - int err; - - err = syscall_seized(ctl, __NR_mmap, &map, - (unsigned long)addr, length, prot, flags, fd, offset); - if (err < 0 || (long)map < 0) - map = 0; - - return (void *)map; -} diff --git a/criu/arch/ppc64/include/asm/parasite-syscall.h b/criu/arch/ppc64/include/asm/parasite-syscall.h index 7a5591ad5..e420ccbdc 100644 --- a/criu/arch/ppc64/include/asm/parasite-syscall.h +++ b/criu/arch/ppc64/include/asm/parasite-syscall.h @@ -9,8 +9,4 @@ struct parasite_ctl; void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); -void *mmap_seized(struct parasite_ctl *ctl, - void *addr, size_t length, int prot, - int flags, int fd, off_t offset); - #endif diff --git a/criu/arch/ppc64/infect.c b/criu/arch/ppc64/infect.c index 6c9692f7c..c76bef5e7 100644 --- a/criu/arch/ppc64/infect.c +++ b/criu/arch/ppc64/infect.c @@ -19,6 +19,20 @@ #define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */ #endif +/* + * Injected syscall instruction + */ +const u32 code_syscall[] = { + 0x44000002, /* sc */ + 0x0fe00000 /* twi 31,0,0 */ +}; + +static inline void __check_code_syscall(void) +{ + BUILD_BUG_ON(sizeof(code_syscall) != BUILTIN_SYSCALL_SIZE); + BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); +} + /* This is the layout of the POWER7 VSX registers and the way they * overlap with the existing FPR and VMX registers. * @@ -241,3 +255,43 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, v return save(arg, ®s, &fpregs); } + +int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5, + unsigned long arg6) +{ + user_regs_struct_t regs = ctl->orig.regs; + int err; + + regs.gpr[0] = (unsigned long)nr; + regs.gpr[3] = arg1; + regs.gpr[4] = arg2; + regs.gpr[5] = arg3; + regs.gpr[6] = arg4; + regs.gpr[7] = arg5; + regs.gpr[8] = arg6; + + err = compel_execute_syscall(ctl, ®s, (char*)code_syscall); + + *ret = regs.gpr[3]; + return err; +} + +void *remote_mmap(struct parasite_ctl *ctl, + void *addr, size_t length, int prot, + int flags, int fd, off_t offset) +{ + unsigned long map = 0; + int err; + + err = compel_syscall(ctl, __NR_mmap, &map, + (unsigned long)addr, length, prot, flags, fd, offset); + if (err < 0 || (long)map < 0) + map = 0; + + return (void *)map; +} diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index de25413a2..2cf3bacf8 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -31,31 +31,6 @@ #include "images/core.pb-c.h" #include "images/creds.pb-c.h" -/* - * Injected syscall instruction - */ -const char code_syscall[] = { - 0x0f, 0x05, /* syscall */ - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc /* int 3, ... */ -}; - -const char code_int_80[] = { - 0xcd, 0x80, /* int $0x80 */ - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc /* int 3, ... */ -}; - -static const int -code_syscall_aligned = round_up(sizeof(code_syscall), sizeof(long)); -static const int -code_int_80_aligned = round_up(sizeof(code_syscall), sizeof(long)); - -static inline __always_unused void __check_code_syscall(void) -{ - BUILD_BUG_ON(code_int_80_aligned != BUILTIN_SYSCALL_SIZE); - BUILD_BUG_ON(code_syscall_aligned != BUILTIN_SYSCALL_SIZE); - BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); -} - /* * regs must be inited when calling this function from original context */ @@ -146,47 +121,6 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) return true; } -int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, - unsigned long arg1, - unsigned long arg2, - unsigned long arg3, - unsigned long arg4, - unsigned long arg5, - unsigned long arg6) -{ - user_regs_struct_t regs = ctl->orig.regs; - int err; - - if (user_regs_native(®s)) { - user_regs_struct64 *r = ®s.native; - - r->ax = (uint64_t)nr; - r->di = arg1; - r->si = arg2; - r->dx = arg3; - r->r10 = arg4; - r->r8 = arg5; - r->r9 = arg6; - - err = compel_execute_syscall(ctl, ®s, code_syscall); - } else { - user_regs_struct32 *r = ®s.compat; - - r->ax = (uint32_t)nr; - r->bx = arg1; - r->cx = arg2; - r->dx = arg3; - r->si = arg4; - r->di = arg5; - r->bp = arg6; - - err = compel_execute_syscall(ctl, ®s, code_int_80); - } - - *ret = get_user_reg(®s, ax); - return err; -} - int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) { CoreEntry *core = x; @@ -548,29 +482,6 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) return 0; } -void *mmap_seized(struct parasite_ctl *ctl, - void *addr, size_t length, int prot, - int flags, int fd, off_t offset) -{ - unsigned long map; - int err; - bool compat_task = !user_regs_native(&ctl->orig.regs); - - err = syscall_seized(ctl, __NR(mmap, compat_task), &map, - (unsigned long)addr, length, prot, flags, fd, offset); - if (err < 0) - return NULL; - - if (IS_ERR_VALUE(map)) { - if (map == -EACCES && (prot & PROT_WRITE) && (prot & PROT_EXEC)) - pr_warn("mmap(PROT_WRITE | PROT_EXEC) failed for %d, " - "check selinux execmem policy\n", ctl->rpid); - return NULL; - } - - return (void *)map; -} - #ifdef CONFIG_X86_64 #define CPREG32(d) f->compat.uc.uc_mcontext.d = r->d #else diff --git a/criu/arch/x86/include/asm/parasite-syscall.h b/criu/arch/x86/include/asm/parasite-syscall.h index cbc0442dd..18c746f6f 100644 --- a/criu/arch/x86/include/asm/parasite-syscall.h +++ b/criu/arch/x86/include/asm/parasite-syscall.h @@ -20,8 +20,4 @@ struct parasite_ctl; void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); -void *mmap_seized(struct parasite_ctl *ctl, - void *addr, size_t length, int prot, - int flags, int fd, off_t offset); - #endif diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index c604b8841..f9aad4bf0 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -2,6 +2,10 @@ #include #include #include +#include +#include "asm/parasite-syscall.h" +#include "uapi/std/syscall-codes.h" +#include "err.h" #include "asm/fpu.h" #include "asm/types.h" #include "errno.h" @@ -10,6 +14,31 @@ #include "infect.h" #include "infect-priv.h" +/* + * Injected syscall instruction + */ +const char code_syscall[] = { + 0x0f, 0x05, /* syscall */ + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc /* int 3, ... */ +}; + +const char code_int_80[] = { + 0xcd, 0x80, /* int $0x80 */ + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc /* int 3, ... */ +}; + +static const int +code_syscall_aligned = round_up(sizeof(code_syscall), sizeof(long)); +static const int +code_int_80_aligned = round_up(sizeof(code_syscall), sizeof(long)); + +static inline __always_unused void __check_code_syscall(void) +{ + BUILD_BUG_ON(code_int_80_aligned != BUILTIN_SYSCALL_SIZE); + BUILD_BUG_ON(code_syscall_aligned != BUILTIN_SYSCALL_SIZE); + BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); +} + #define get_signed_user_reg(pregs, name) \ ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \ (int32_t)((pregs)->compat.name)) @@ -76,3 +105,67 @@ out: err: return ret; } + +int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5, + unsigned long arg6) +{ + user_regs_struct_t regs = ctl->orig.regs; + int err; + + if (user_regs_native(®s)) { + user_regs_struct64 *r = ®s.native; + + r->ax = (uint64_t)nr; + r->di = arg1; + r->si = arg2; + r->dx = arg3; + r->r10 = arg4; + r->r8 = arg5; + r->r9 = arg6; + + err = compel_execute_syscall(ctl, ®s, code_syscall); + } else { + user_regs_struct32 *r = ®s.compat; + + r->ax = (uint32_t)nr; + r->bx = arg1; + r->cx = arg2; + r->dx = arg3; + r->si = arg4; + r->di = arg5; + r->bp = arg6; + + err = compel_execute_syscall(ctl, ®s, code_int_80); + } + + *ret = get_user_reg(®s, ax); + return err; +} + +void *remote_mmap(struct parasite_ctl *ctl, + void *addr, size_t length, int prot, + int flags, int fd, off_t offset) +{ + unsigned long map; + int err; + bool compat_task = !user_regs_native(&ctl->orig.regs); + + err = compel_syscall(ctl, __NR(mmap, compat_task), &map, + (unsigned long)addr, length, prot, flags, fd, offset); + if (err < 0) + return NULL; + + if (IS_ERR_VALUE(map)) { + if (map == -EACCES && (prot & PROT_WRITE) && (prot & PROT_EXEC)) + pr_warn("mmap(PROT_WRITE | PROT_EXEC) failed for %d, " + "check selinux execmem policy\n", ctl->rpid); + return NULL; + } + + return (void *)map; +} diff --git a/criu/cr-exec.c b/criu/cr-exec.c index 8e0348796..29a02bd77 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -98,7 +98,7 @@ static int execute_syscall(struct parasite_ctl *ctl, pr_info("Calling %d with %lu %lu %lu %lu %lu %lu\n", scd->nr, args[0], args[1], args[2], args[3], args[4], args[5]); - err = syscall_seized(ctl, scd->nr, &ret, + err = compel_syscall(ctl, scd->nr, &ret, args[0], args[1], args[2], args[3], args[4], args[5]); if (err) return err; diff --git a/criu/include/infect-priv.h b/criu/include/infect-priv.h index b33a63516..3ddd1175f 100644 --- a/criu/include/infect-priv.h +++ b/criu/include/infect-priv.h @@ -40,4 +40,13 @@ int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m); /* XXX -- remove with cr-exec.c */ extern int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size); +extern int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, + unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, + unsigned long arg5, unsigned long arg6); + + +extern void *remote_mmap(struct parasite_ctl *ctl, + void *addr, size_t length, int prot, + int flags, int fd, off_t offset); #endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 2efec72d4..5c4ca6de5 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -64,11 +64,6 @@ extern struct parasite_tty_args *parasite_dump_tty(struct parasite_ctl *ctl, int extern int parasite_init_threads_seized(struct parasite_ctl *ctl, struct pstree_item *item); extern int parasite_fini_threads_seized(struct parasite_ctl *ctl); -extern int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, - unsigned long arg1, unsigned long arg2, - unsigned long arg3, unsigned long arg4, - unsigned long arg5, unsigned long arg6); - extern bool arch_can_dump_task(struct parasite_ctl *ctl); #endif /* __CR_PARASITE_SYSCALL_H__ */ diff --git a/criu/infect.c b/criu/infect.c index b958054d2..83675fe3f 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -603,7 +603,7 @@ static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size) { int fd; - ctl->remote_map = mmap_seized(ctl, NULL, size, + ctl->remote_map = remote_mmap(ctl, NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_SHARED, -1, 0); if (!ctl->remote_map) { @@ -650,13 +650,13 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) return -1; } - ret = syscall_seized(ctl, __NR(memfd_create, compat_task), &sret, + ret = compel_syscall(ctl, __NR(memfd_create, compat_task), &sret, (unsigned long)where, 0, 0, 0, 0, 0); if (ptrace_poke_area(pid, orig_code, where, sizeof(orig_code))) { fd = (int)(long)sret; if (fd >= 0) - syscall_seized(ctl, __NR(close, compat_task), &sret, + compel_syscall(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); pr_err("Can't restore memfd args (pid: %d)\n", pid); return -1; @@ -681,7 +681,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) goto err_cure; } - ctl->remote_map = mmap_seized(ctl, NULL, size, + ctl->remote_map = remote_mmap(ctl, NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FILE | MAP_SHARED, fd, 0); if (!ctl->remote_map) { @@ -697,7 +697,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) goto err_curef; } - syscall_seized(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); + compel_syscall(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); close(lfd); pr_info("Set up parasite blob using memfd\n"); @@ -706,7 +706,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) err_curef: close(lfd); err_cure: - syscall_seized(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); + compel_syscall(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); return -1; } @@ -964,7 +964,7 @@ int compel_cure_remote(struct parasite_ctl *ctl) } else { unsigned long ret; - syscall_seized(ctl, __NR(munmap, !compel_mode_native(ctl)), &ret, + compel_syscall(ctl, __NR(munmap, !compel_mode_native(ctl)), &ret, (unsigned long)ctl->remote_map, ctl->map_length, 0, 0, 0, 0); if (ret) { From df217daa3188a0df08a7fd08ba903ff67ff139b4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 19 Oct 2016 12:44:01 +0300 Subject: [PATCH 0167/4375] infect: Remove infect-priv.h from arch/crtools.c Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/crtools.c | 1 - criu/arch/arm/crtools.c | 1 - criu/arch/ppc64/crtools.c | 1 - criu/arch/x86/crtools.c | 1 - 4 files changed, 4 deletions(-) diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index e7e7be9c3..8a92a5f83 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -18,7 +18,6 @@ #include "cpu.h" #include "restorer.h" #include "infect.h" -#include "infect-priv.h" void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) { diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index 78fa02a99..bc63e6282 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -19,7 +19,6 @@ #include "errno.h" #include "kerndat.h" #include "infect.h" -#include "infect-priv.h" void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) { diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index 33c1ec416..057dd8494 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -19,7 +19,6 @@ #include "cpu.h" #include "errno.h" #include "infect.h" -#include "infect-priv.h" #include "protobuf.h" #include "images/core.pb-c.h" diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 2cf3bacf8..c23e944ce 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -25,7 +25,6 @@ #include "uapi/std/syscall-codes.h" #include "kerndat.h" #include "infect.h" -#include "infect-priv.h" #include "protobuf.h" #include "images/core.pb-c.h" From 432351d6b73aa7f94a8ba71a030850d1717239ee Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 27 Oct 2016 01:15:00 +0300 Subject: [PATCH 0168/4375] compel: Create symlink into arch dir inside uapi headers To be able to include compel/asm/ headers when needed. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 3 +++ Makefile.compel | 15 +++++++++++++++ .../aarch64/src/lib/include/uapi/asm/.gitignore | 0 .../arch/arm/src/lib/include/uapi/asm/.gitignore | 0 .../ppc64/src/lib/include/uapi/asm/.gitignore | 0 .../arch/x86/src/lib/include/uapi/asm/.gitignore | 0 6 files changed, 18 insertions(+) create mode 100644 compel/arch/aarch64/src/lib/include/uapi/asm/.gitignore create mode 100644 compel/arch/arm/src/lib/include/uapi/asm/.gitignore create mode 100644 compel/arch/ppc64/src/lib/include/uapi/asm/.gitignore create mode 100644 compel/arch/x86/src/lib/include/uapi/asm/.gitignore diff --git a/Makefile b/Makefile index b693201f7..0db379099 100644 --- a/Makefile +++ b/Makefile @@ -272,6 +272,9 @@ mrproper: subclean $(Q) $(RM) $(VERSION_HEADER) $(Q) $(RM) $(COMPEL_VERSION_HEADER) $(Q) $(RM) include/common/asm + $(Q) $(RM) compel/include/uapi/compel + $(Q) $(RM) compel/include/uapi/asm + $(Q) $(RM) compel/include/asm $(Q) $(RM) cscope.* $(Q) $(RM) tags TAGS .PHONY: mrproper diff --git a/Makefile.compel b/Makefile.compel index e3edd558d..a5999581b 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -11,6 +11,21 @@ $(COMPEL_VERSION_HEADER): $(SRC_DIR)/Makefile.versions $(Q) echo "#define COMPEL_SO_VERSION_SUBLEVEL " $(COMPEL_SO_VERSION_SUBLEVEL) >> $(COMPEL_VERSION_HEADER) $(Q) echo "#endif /* COMPEL_SO_VERSION_H__ */" >> $(COMPEL_VERSION_HEADER) +$(SRC_DIR)/compel/include/uapi/compel: $(SRC_DIR)/compel/include/uapi + $(call msg-gen, $@) + $(Q) ln -s $^ $@ +$(COMPEL_VERSION_HEADER): $(SRC_DIR)/compel/include/uapi/compel + +$(SRC_DIR)/compel/include/uapi/asm: $(SRC_DIR)/compel/arch/$(ARCH)/src/lib/include/uapi/asm + $(call msg-gen, $@) + $(Q) ln -s $^ $@ +$(COMPEL_VERSION_HEADER): $(SRC_DIR)/compel/include/uapi/asm + +$(SRC_DIR)/compel/include/asm: $(SRC_DIR)/compel/arch/$(ARCH)/src/lib/include + $(call msg-gen, $@) + $(Q) ln -s $^ $@ +$(COMPEL_VERSION_HEADER): $(SRC_DIR)/compel/include/asm + # # Compel itself. compel/%: $(COMPEL_VERSION_HEADER) $(CONFIG_HEADER) .FORCE diff --git a/compel/arch/aarch64/src/lib/include/uapi/asm/.gitignore b/compel/arch/aarch64/src/lib/include/uapi/asm/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/compel/arch/arm/src/lib/include/uapi/asm/.gitignore b/compel/arch/arm/src/lib/include/uapi/asm/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/.gitignore b/compel/arch/ppc64/src/lib/include/uapi/asm/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/compel/arch/x86/src/lib/include/uapi/asm/.gitignore b/compel/arch/x86/src/lib/include/uapi/asm/.gitignore new file mode 100644 index 000000000..e69de29bb From 2abf96bb755746217be48622c832d339c22b257d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 27 Oct 2016 11:15:54 +0300 Subject: [PATCH 0169/4375] infect: Move ksigset helpers into compel Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/signal.h => compel/include/uapi/ksigset.h | 4 ++-- criu/include/infect.h | 1 + criu/infect.c | 1 - criu/pie/restorer.c | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) rename criu/include/signal.h => compel/include/uapi/ksigset.h (87%) diff --git a/criu/include/signal.h b/compel/include/uapi/ksigset.h similarity index 87% rename from criu/include/signal.h rename to compel/include/uapi/ksigset.h index 788b8e2b4..412899c8c 100644 --- a/criu/include/signal.h +++ b/compel/include/uapi/ksigset.h @@ -1,5 +1,5 @@ -#ifndef __CR_SIGNAL_H__ -#define __CR_SIGNAL_H__ +#ifndef __COMPEL_KSIGSET_H__ +#define __COMPEL_KSIGSET_H__ static inline void ksigfillset(k_rtsigset_t *set) { diff --git a/criu/include/infect.h b/criu/include/infect.h index 40ec9132d..46d4691df 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -2,6 +2,7 @@ #define __COMPEL_INFECT_H__ #include "types.h" +#include "compel/include/uapi/ksigset.h" extern int compel_stop_task(int pid); diff --git a/criu/infect.c b/criu/infect.c index 83675fe3f..496843acf 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -8,7 +8,6 @@ #include "infect.h" #include "ptrace.h" -#include "signal.h" #include "asm/parasite-syscall.h" #include "asm/dump.h" #include "restorer.h" diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 8c6eaeef2..884749f3b 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -22,6 +22,7 @@ #include "common/compiler.h" #include "string.h" #include "uapi/std/syscall.h" +#include "uapi/ksigset.h" #include "signal.h" #include "config.h" #include "prctl.h" From 3e2f895732e6b80c5b7428e53ad5b671974a3354 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 27 Oct 2016 11:22:42 +0300 Subject: [PATCH 0170/4375] infect: Remove parasite.h from infect.c This header describes CRIU parasite code, it has nothing to do with infect, so remove it. To do this we need to: * Detach infect RPC commands from criu-parasite ones * Move parasite_init_args and parasite_unmap_args into infect * Move PARASITE_AREA_MIN into infect * Hiding PARASITE_STACK_SIZE-s in infect * Hiding parasite symbols resolvers in infect Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/infect-rpc.h | 43 +++++++++++++++++++++++++++++++++++++++ criu/include/infect.h | 2 ++ criu/include/parasite.h | 40 ++---------------------------------- criu/infect-rpc.c | 4 +++- criu/infect.c | 12 ++++++++++- 5 files changed, 61 insertions(+), 40 deletions(-) diff --git a/criu/include/infect-rpc.h b/criu/include/infect-rpc.h index 117dfc1bb..d2f89a7d4 100644 --- a/criu/include/infect-rpc.h +++ b/criu/include/infect-rpc.h @@ -1,5 +1,10 @@ #ifndef __COMPEL_INFECT_RPC_H__ #define __COMPEL_INFECT_RPC_H__ + +#include +#include + +struct parasite_ctl; extern int compel_rpc_sync(unsigned int cmd, struct parasite_ctl *ctl); extern int compel_rpc_call(unsigned int cmd, struct parasite_ctl *ctl); extern int compel_rpc_call_sync(unsigned int cmd, struct parasite_ctl *ctl); @@ -17,4 +22,42 @@ struct ctl_msg { #define ctl_msg_ack(_cmd, _err) \ (struct ctl_msg){.cmd = _cmd, .ack = _cmd, .err = _err, } +/* + * NOTE: each command's args should be arch-independed sized. + * If you want to use one of the standard types, declare + * alternative type for compatible tasks in parasite-compat.h + */ +enum { + PARASITE_CMD_IDLE = 0, + PARASITE_CMD_ACK, + + PARASITE_CMD_INIT_DAEMON, + PARASITE_CMD_UNMAP, + + /* + * This must be greater than INITs. + */ + PARASITE_CMD_FINI, + + PARASITE_USER_CMDS, +}; + +struct parasite_init_args { + int h_addr_len; + struct sockaddr_un h_addr; + + int log_level; + + u64 sigframe; /* pointer to sigframe */ + + void *sigreturn_addr; + futex_t daemon_connected; +}; + +struct parasite_unmap_args { + void *parasite_start; + unsigned long parasite_len; +}; + + #endif diff --git a/criu/include/infect.h b/criu/include/infect.h index 46d4691df..6d4c5d392 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -4,6 +4,8 @@ #include "types.h" #include "compel/include/uapi/ksigset.h" +#define PARASITE_START_AREA_MIN (4096) + extern int compel_stop_task(int pid); struct seize_task_status { diff --git a/criu/include/parasite.h b/criu/include/parasite.h index b68961bbf..cd6d793f8 100644 --- a/criu/include/parasite.h +++ b/criu/include/parasite.h @@ -1,9 +1,6 @@ #ifndef __CR_PARASITE_H__ #define __CR_PARASITE_H__ -#define PARASITE_STACK_SIZE (16 << 10) -#define PARASITE_START_AREA_MIN (4096) - #define PARASITE_MAX_SIZE (64 << 10) #ifndef __ASSEMBLY__ @@ -16,6 +13,7 @@ #include "image.h" #include "util-pie.h" #include "common/lock.h" +#include "infect-rpc.h" #include "images/vma.pb-c.h" #include "images/tty.pb-c.h" @@ -23,18 +21,7 @@ #define __head __used __section(.head.text) enum { - PARASITE_CMD_IDLE = 0, - PARASITE_CMD_ACK, - - PARASITE_CMD_INIT_DAEMON, - PARASITE_CMD_DUMP_THREAD, - PARASITE_CMD_UNMAP, - - /* - * This must be greater than INITs. - */ - PARASITE_CMD_FINI, - + PARASITE_CMD_DUMP_THREAD = PARASITE_USER_CMDS, PARASITE_CMD_MPROTECT_VMAS, PARASITE_CMD_DUMPPAGES, @@ -52,23 +39,6 @@ enum { PARASITE_CMD_MAX, }; -struct parasite_init_args { - int h_addr_len; - struct sockaddr_un h_addr; - - int log_level; - - u64 sigframe; /* pointer to sigframe */ - - void *sigreturn_addr; - futex_t daemon_connected; -}; - -struct parasite_unmap_args { - void *parasite_start; - unsigned long parasite_len; -}; - struct parasite_vma_entry { unsigned long start; @@ -262,12 +232,6 @@ struct parasite_dump_cgroup_args { char contents[1 << 12]; }; -/* the parasite prefix is added by gen_offsets.sh */ -#define __pblob_offset(ptype, symbol) \ - parasite_ ## ptype ## _blob_offset__ ## symbol -#define parasite_sym(pblob, ptype, symbol) \ - ((void *)(pblob) + __pblob_offset(ptype, symbol)) - #endif /* !__ASSEMBLY__ */ #endif /* __CR_PARASITE_H__ */ diff --git a/criu/infect-rpc.c b/criu/infect-rpc.c index 51b9132ca..73d963def 100644 --- a/criu/infect-rpc.c +++ b/criu/infect-rpc.c @@ -1,7 +1,9 @@ #include "xmalloc.h" #include "types.h" -#include "parasite.h" #include "parasite-syscall.h" +#include "log.h" +#include "common/bug.h" +#include "lock.h" #include "infect.h" #include "infect-priv.h" #include "infect-rpc.h" diff --git a/criu/infect.c b/criu/infect.c index 496843acf..3df9179d9 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -11,7 +11,6 @@ #include "asm/parasite-syscall.h" #include "asm/dump.h" #include "restorer.h" -#include "parasite.h" #include "parasite-syscall.h" #include "pie-relocs.h" #include "parasite-blob.h" @@ -20,6 +19,11 @@ #include "infect-rpc.h" #include "infect-priv.h" +#define UNIX_PATH_MAX (sizeof(struct sockaddr_un) - \ + (size_t)((struct sockaddr_un *) 0)->sun_path) + +#define PARASITE_STACK_SIZE (16 << 10) + #define PTRACE_EVENT_STOP 128 #ifndef SECCOMP_MODE_DISABLED @@ -721,6 +725,12 @@ int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size) return ret; } +/* the parasite prefix is added by gen_offsets.sh */ +#define __pblob_offset(ptype, symbol) \ + parasite_ ## ptype ## _blob_offset__ ## symbol +#define parasite_sym(pblob, ptype, symbol) \ + ((void *)(pblob) + __pblob_offset(ptype, symbol)) + #define init_parasite_ctl(ctl, blob_type) \ do { \ memcpy(ctl->local_map, parasite_##blob_type##_blob, \ From cd368c8e088e1e6cece7672722724379f6f93bce Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 27 Oct 2016 11:26:55 +0300 Subject: [PATCH 0171/4375] infect: Move ptrace_get/set_regs() into ptrace.c The criu/ptrace.c will also go into compel sources, so detach the needed code from CRIU as well. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 43 -------------------------------- criu/arch/x86/include/asm/dump.h | 4 --- criu/arch/x86/infect.c | 43 ++++++++++++++++++++++++++++++++ criu/include/ptrace.h | 5 ++++ criu/infect.c | 1 - criu/parasite-syscall.c | 20 --------------- criu/ptrace.c | 20 ++++++++++++++- 7 files changed, 67 insertions(+), 69 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index c23e944ce..73accb13d 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -211,49 +211,6 @@ int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpre return 0; } -int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs) -{ - struct iovec iov; - int ret; - - iov.iov_base = ®s->native; - iov.iov_len = sizeof(user_regs_struct64); - - ret = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov); - if (ret == -1) { - pr_perror("PTRACE_GETREGSET failed"); - return -1; - } - - if (iov.iov_len == sizeof(regs->native)) { - regs->__is_native = NATIVE_MAGIC; - return ret; - } - if (iov.iov_len == sizeof(regs->compat)) { - regs->__is_native = COMPAT_MAGIC; - return ret; - } - - pr_err("PTRACE_GETREGSET read %zu bytes for pid %d, but native/compat regs sizes are %zu/%zu bytes", - iov.iov_len, pid, - sizeof(regs->native), sizeof(regs->compat)); - return -1; -} - -int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs) -{ - struct iovec iov; - - if (user_regs_native(regs)) { - iov.iov_base = ®s->native; - iov.iov_len = sizeof(user_regs_struct64); - } else { - iov.iov_base = ®s->compat; - iov.iov_len = sizeof(user_regs_struct32); - } - return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov); -} - static void alloc_tls(ThreadInfoX86 *ti, void **mempool) { int i; diff --git a/criu/arch/x86/include/asm/dump.h b/criu/arch/x86/include/asm/dump.h index 61e53dced..ca7cd675f 100644 --- a/criu/arch/x86/include/asm/dump.h +++ b/criu/arch/x86/include/asm/dump.h @@ -5,10 +5,6 @@ extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *); extern int arch_alloc_thread_info(CoreEntry *core); extern void arch_free_thread_info(CoreEntry *core); -#define ARCH_HAS_GET_REGS -extern int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs); -extern int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs); - static inline void core_put_tls(CoreEntry *core, tls_t tls) { ThreadInfoX86 *ti = core->thread_info; diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index f9aad4bf0..38abde2d9 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -169,3 +169,46 @@ void *remote_mmap(struct parasite_ctl *ctl, return (void *)map; } + +int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs) +{ + struct iovec iov; + int ret; + + iov.iov_base = ®s->native; + iov.iov_len = sizeof(user_regs_struct64); + + ret = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov); + if (ret == -1) { + pr_perror("PTRACE_GETREGSET failed"); + return -1; + } + + if (iov.iov_len == sizeof(regs->native)) { + regs->__is_native = NATIVE_MAGIC; + return ret; + } + if (iov.iov_len == sizeof(regs->compat)) { + regs->__is_native = COMPAT_MAGIC; + return ret; + } + + pr_err("PTRACE_GETREGSET read %zu bytes for pid %d, but native/compat regs sizes are %zu/%zu bytes", + iov.iov_len, pid, + sizeof(regs->native), sizeof(regs->compat)); + return -1; +} + +int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs) +{ + struct iovec iov; + + if (user_regs_native(regs)) { + iov.iov_base = ®s->native; + iov.iov_len = sizeof(user_regs_struct64); + } else { + iov.iov_base = ®s->compat; + iov.iov_len = sizeof(user_regs_struct32); + } + return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov); +} diff --git a/criu/include/ptrace.h b/criu/include/ptrace.h index 22649c346..e3f3374d5 100644 --- a/criu/include/ptrace.h +++ b/criu/include/ptrace.h @@ -4,6 +4,8 @@ #include #include +#include "types.h" + /* some constants for ptrace */ #ifndef PTRACE_SEIZE # define PTRACE_SEIZE 0x4206 @@ -67,4 +69,7 @@ extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes); extern int ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes); extern int ptrace_swap_area(pid_t pid, void *dst, void *src, long bytes); +extern int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs); +extern int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs); + #endif /* __CR_PTRACE_H__ */ diff --git a/criu/infect.c b/criu/infect.c index 3df9179d9..ff5a2805b 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -9,7 +9,6 @@ #include "infect.h" #include "ptrace.h" #include "asm/parasite-syscall.h" -#include "asm/dump.h" #include "restorer.h" #include "parasite-syscall.h" #include "pie-relocs.h" diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index bbd0c2b01..80a28e420 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -68,26 +68,6 @@ unsigned long get_exec_start(struct vm_area_list *vmas) return 0; } -#ifndef ARCH_HAS_GET_REGS -static inline int ptrace_get_regs(int pid, user_regs_struct_t *regs) -{ - struct iovec iov; - - iov.iov_base = regs; - iov.iov_len = sizeof(user_regs_struct_t); - return ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov); -} - -static inline int ptrace_set_regs(int pid, user_regs_struct_t *regs) -{ - struct iovec iov; - - iov.iov_base = regs; - iov.iov_len = sizeof(user_regs_struct_t); - return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov); -} -#endif - int parasite_send_fd(struct parasite_ctl *ctl, int fd) { int sk; diff --git a/criu/ptrace.c b/criu/ptrace.c index 15908c17d..8b9e166ec 100644 --- a/criu/ptrace.c +++ b/criu/ptrace.c @@ -7,7 +7,8 @@ #include #include #include - +#include +#include #include #include #include @@ -82,3 +83,20 @@ int ptrace_swap_area(pid_t pid, void *dst, void *src, long bytes) return 0; } + +int __attribute__((weak)) ptrace_get_regs(int pid, user_regs_struct_t *regs) { + struct iovec iov; + + iov.iov_base = regs; + iov.iov_len = sizeof(user_regs_struct_t); + return ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov); +} + +int __attribute__((weak)) ptrace_set_regs(int pid, user_regs_struct_t *regs) +{ + struct iovec iov; + + iov.iov_base = regs; + iov.iov_len = sizeof(user_regs_struct_t); + return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov); +} From 5156b096b1d58cf0f115089ea0a763065adc8b87 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 27 Oct 2016 11:28:43 +0300 Subject: [PATCH 0172/4375] infect: Move thread_ctx structure into infect For now it's becoming the part of the compel API and lets us remove parasite-syscall.h from infect.c. The former header includes declarations of CRIU dumping routines that work with parasite code. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/infect.h | 5 ++++- criu/include/parasite-syscall.h | 5 ----- criu/infect-rpc.c | 1 - criu/infect.c | 1 - 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/criu/include/infect.h b/criu/include/infect.h index 6d4c5d392..a161ae238 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -31,7 +31,10 @@ extern int compel_unseize_task(pid_t pid, int orig_state, int state); #define TASK_ZOMBIE 0x6 struct parasite_ctl; -struct thread_ctx; +struct thread_ctx { + k_rtsigset_t sigmask; + user_regs_struct_t regs; +}; extern struct parasite_ctl *compel_prepare(int pid); extern int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size); diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 5c4ca6de5..30cb36b83 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -22,11 +22,6 @@ struct pid; struct parasite_dump_cgroup_args; struct rt_sigframe; -struct thread_ctx { - k_rtsigset_t sigmask; - user_regs_struct_t regs; -}; - struct parasite_ctl; extern int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_imgset); diff --git a/criu/infect-rpc.c b/criu/infect-rpc.c index 73d963def..858a4c0b6 100644 --- a/criu/infect-rpc.c +++ b/criu/infect-rpc.c @@ -1,6 +1,5 @@ #include "xmalloc.h" #include "types.h" -#include "parasite-syscall.h" #include "log.h" #include "common/bug.h" #include "lock.h" diff --git a/criu/infect.c b/criu/infect.c index ff5a2805b..62ec77c36 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -8,7 +8,6 @@ #include "infect.h" #include "ptrace.h" -#include "asm/parasite-syscall.h" #include "restorer.h" #include "parasite-syscall.h" #include "pie-relocs.h" From 6fee9c70a787c5368976562888711687f8218d98 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 27 Oct 2016 12:10:30 +0300 Subject: [PATCH 0173/4375] infect: Remove parasite-syscall.h from infect This is * Move parasite_setup_regs() and related into arch/infect * Move arch_can_dump_task() into infect * Move parasite_send_fd() into infect-util and completes parasite-syscall.h removal. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/include/ptrace.h | 4 + compel/arch/aarch64/src/lib/include/syscall.h | 4 + compel/arch/arm/src/lib/include/ptrace.h | 4 + compel/arch/arm/src/lib/include/syscall.h | 4 + compel/arch/ppc64/src/lib/include/ptrace.h | 4 + compel/arch/ppc64/src/lib/include/syscall.h | 4 + compel/arch/x86/src/lib/include/ptrace.h | 4 + compel/arch/x86/src/lib/include/syscall.h | 4 + criu/Makefile.crtools | 1 + criu/arch/aarch64/crtools.c | 15 ---- .../aarch64/include/asm/parasite-syscall.h | 6 -- criu/arch/aarch64/infect.c | 14 ++++ criu/arch/arm/crtools.c | 18 ----- criu/arch/arm/include/asm/parasite-syscall.h | 6 -- criu/arch/arm/infect.c | 17 +++++ criu/arch/ppc64/crtools.c | 21 ----- .../arch/ppc64/include/asm/parasite-syscall.h | 6 -- criu/arch/ppc64/infect.c | 21 +++++ criu/arch/x86/crtools.c | 66 ---------------- criu/arch/x86/include/asm/parasite-syscall.h | 6 -- criu/arch/x86/infect.c | 76 +++++++++++++++++++ criu/cr-restore.c | 1 + criu/include/infect-priv.h | 5 ++ criu/include/infect-util.h | 5 ++ criu/include/parasite-syscall.h | 6 -- criu/infect-util.c | 20 +++++ criu/infect.c | 6 +- criu/mem.c | 3 +- criu/parasite-syscall.c | 12 --- 29 files changed, 198 insertions(+), 165 deletions(-) create mode 100644 compel/arch/aarch64/src/lib/include/ptrace.h create mode 100644 compel/arch/aarch64/src/lib/include/syscall.h create mode 100644 compel/arch/arm/src/lib/include/ptrace.h create mode 100644 compel/arch/arm/src/lib/include/syscall.h create mode 100644 compel/arch/ppc64/src/lib/include/ptrace.h create mode 100644 compel/arch/ppc64/src/lib/include/syscall.h create mode 100644 compel/arch/x86/src/lib/include/ptrace.h create mode 100644 compel/arch/x86/src/lib/include/syscall.h create mode 100644 criu/include/infect-util.h create mode 100644 criu/infect-util.c diff --git a/compel/arch/aarch64/src/lib/include/ptrace.h b/compel/arch/aarch64/src/lib/include/ptrace.h new file mode 100644 index 000000000..9cf7d460d --- /dev/null +++ b/compel/arch/aarch64/src/lib/include/ptrace.h @@ -0,0 +1,4 @@ +#ifndef __COMPEL_PTRACE_H__ +#define __COMPEL_PTRACE_H__ +#define ARCH_SI_TRAP TRAP_BRKPT +#endif diff --git a/compel/arch/aarch64/src/lib/include/syscall.h b/compel/arch/aarch64/src/lib/include/syscall.h new file mode 100644 index 000000000..e2ec1272e --- /dev/null +++ b/compel/arch/aarch64/src/lib/include/syscall.h @@ -0,0 +1,4 @@ +#ifndef __COMPEL_SYSCALL_H__ +#define __COMPEL_SYSCALL_H__ +#define __NR(syscall, compat) __NR_##syscall +#endif diff --git a/compel/arch/arm/src/lib/include/ptrace.h b/compel/arch/arm/src/lib/include/ptrace.h new file mode 100644 index 000000000..9cf7d460d --- /dev/null +++ b/compel/arch/arm/src/lib/include/ptrace.h @@ -0,0 +1,4 @@ +#ifndef __COMPEL_PTRACE_H__ +#define __COMPEL_PTRACE_H__ +#define ARCH_SI_TRAP TRAP_BRKPT +#endif diff --git a/compel/arch/arm/src/lib/include/syscall.h b/compel/arch/arm/src/lib/include/syscall.h new file mode 100644 index 000000000..e2ec1272e --- /dev/null +++ b/compel/arch/arm/src/lib/include/syscall.h @@ -0,0 +1,4 @@ +#ifndef __COMPEL_SYSCALL_H__ +#define __COMPEL_SYSCALL_H__ +#define __NR(syscall, compat) __NR_##syscall +#endif diff --git a/compel/arch/ppc64/src/lib/include/ptrace.h b/compel/arch/ppc64/src/lib/include/ptrace.h new file mode 100644 index 000000000..9cf7d460d --- /dev/null +++ b/compel/arch/ppc64/src/lib/include/ptrace.h @@ -0,0 +1,4 @@ +#ifndef __COMPEL_PTRACE_H__ +#define __COMPEL_PTRACE_H__ +#define ARCH_SI_TRAP TRAP_BRKPT +#endif diff --git a/compel/arch/ppc64/src/lib/include/syscall.h b/compel/arch/ppc64/src/lib/include/syscall.h new file mode 100644 index 000000000..e2ec1272e --- /dev/null +++ b/compel/arch/ppc64/src/lib/include/syscall.h @@ -0,0 +1,4 @@ +#ifndef __COMPEL_SYSCALL_H__ +#define __COMPEL_SYSCALL_H__ +#define __NR(syscall, compat) __NR_##syscall +#endif diff --git a/compel/arch/x86/src/lib/include/ptrace.h b/compel/arch/x86/src/lib/include/ptrace.h new file mode 100644 index 000000000..991f1152a --- /dev/null +++ b/compel/arch/x86/src/lib/include/ptrace.h @@ -0,0 +1,4 @@ +#ifndef __COMPEL_PTRACE_H__ +#define __COMPEL_PTRACE_H__ +#define ARCH_SI_TRAP SI_KERNEL +#endif diff --git a/compel/arch/x86/src/lib/include/syscall.h b/compel/arch/x86/src/lib/include/syscall.h new file mode 100644 index 000000000..6d7df1861 --- /dev/null +++ b/compel/arch/x86/src/lib/include/syscall.h @@ -0,0 +1,4 @@ +#ifndef __COMPEL_SYSCALL_H__ +#define __COMPEL_SYSCALL_H__ +#define __NR(syscall, compat) ((compat) ? __NR32_##syscall : __NR_##syscall) +#endif diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 04ba7b3f7..502f33133 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -5,6 +5,7 @@ ccflags-y += -iquote compel/arch/$(ARCH)/plugins/std obj-y += infect.o obj-y += infect-rpc.o +obj-y += infect-util.o obj-y += action-scripts.o obj-y += external.o obj-y += aio.o diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index 8a92a5f83..02205453e 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -19,21 +19,6 @@ #include "restorer.h" #include "infect.h" -void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) -{ - regs->pc = new_ip; - if (stack) - regs->sp = (unsigned long)stack; -} - -bool arch_can_dump_task(struct parasite_ctl *ctl) -{ - /* - * TODO: Add proper check here - */ - return true; -} - #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))(src)->e int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd) diff --git a/criu/arch/aarch64/include/asm/parasite-syscall.h b/criu/arch/aarch64/include/asm/parasite-syscall.h index e420ccbdc..6008c3792 100644 --- a/criu/arch/aarch64/include/asm/parasite-syscall.h +++ b/criu/arch/aarch64/include/asm/parasite-syscall.h @@ -3,10 +3,4 @@ struct parasite_ctl; -#define ARCH_SI_TRAP TRAP_BRKPT - -#define __NR(syscall, compat) __NR_##syscall - -void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); - #endif diff --git a/criu/arch/aarch64/infect.c b/criu/arch/aarch64/infect.c index 2411cd6e8..263ea5a55 100644 --- a/criu/arch/aarch64/infect.c +++ b/criu/arch/aarch64/infect.c @@ -98,3 +98,17 @@ void *mmap_re(struct parasite_ctl *ctl, return (void *)map; } +void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) +{ + regs->pc = new_ip; + if (stack) + regs->sp = (unsigned long)stack; +} + +bool arch_can_dump_task(struct parasite_ctl *ctl) +{ + /* + * TODO: Add proper check here + */ + return true; +} diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index bc63e6282..8ce1e6619 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -20,24 +20,6 @@ #include "kerndat.h" #include "infect.h" -void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) -{ - regs->ARM_pc = new_ip; - if (stack) - regs->ARM_sp = (unsigned long)stack; - - /* Make sure flags are in known state */ - regs->ARM_cpsr &= PSR_f | PSR_s | PSR_x | MODE32_BIT; -} - -bool arch_can_dump_task(struct parasite_ctl *ctl) -{ - /* - * TODO: Add proper check here - */ - return true; -} - #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))((src)->ARM_##e) int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) diff --git a/criu/arch/arm/include/asm/parasite-syscall.h b/criu/arch/arm/include/asm/parasite-syscall.h index e420ccbdc..6008c3792 100644 --- a/criu/arch/arm/include/asm/parasite-syscall.h +++ b/criu/arch/arm/include/asm/parasite-syscall.h @@ -3,10 +3,4 @@ struct parasite_ctl; -#define ARCH_SI_TRAP TRAP_BRKPT - -#define __NR(syscall, compat) __NR_##syscall - -void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); - #endif diff --git a/criu/arch/arm/infect.c b/criu/arch/arm/infect.c index ec84c20aa..50d1d5b68 100644 --- a/criu/arch/arm/infect.c +++ b/criu/arch/arm/infect.c @@ -105,3 +105,20 @@ void *remote_mmap(struct parasite_ctl *ctl, return (void *)map; } +void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) +{ + regs->ARM_pc = new_ip; + if (stack) + regs->ARM_sp = (unsigned long)stack; + + /* Make sure flags are in known state */ + regs->ARM_cpsr &= PSR_f | PSR_s | PSR_x | MODE32_BIT; +} + +bool arch_can_dump_task(struct parasite_ctl *ctl) +{ + /* + * TODO: Add proper check here + */ + return true; +} diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index 057dd8494..e634c7b71 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -24,27 +24,6 @@ #include "images/core.pb-c.h" #include "images/creds.pb-c.h" -void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) -{ - /* - * OpenPOWER ABI requires that r12 is set to the calling function addressi - * to compute the TOC pointer. - */ - regs->gpr[12] = new_ip; - regs->nip = new_ip; - if (stack) - regs->gpr[1] = (unsigned long) stack; - regs->trap = 0; -} - -bool arch_can_dump_task(struct parasite_ctl *ctl) -{ - /* - * TODO: We should detect 32bit task when BE support is done. - */ - return true; -} - static UserPpc64FpstateEntry *copy_fp_regs(uint64_t *fpregs) { UserPpc64FpstateEntry *fpe; diff --git a/criu/arch/ppc64/include/asm/parasite-syscall.h b/criu/arch/ppc64/include/asm/parasite-syscall.h index e420ccbdc..6008c3792 100644 --- a/criu/arch/ppc64/include/asm/parasite-syscall.h +++ b/criu/arch/ppc64/include/asm/parasite-syscall.h @@ -3,10 +3,4 @@ struct parasite_ctl; -#define ARCH_SI_TRAP TRAP_BRKPT - -#define __NR(syscall, compat) __NR_##syscall - -void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); - #endif diff --git a/criu/arch/ppc64/infect.c b/criu/arch/ppc64/infect.c index c76bef5e7..029509ee3 100644 --- a/criu/arch/ppc64/infect.c +++ b/criu/arch/ppc64/infect.c @@ -295,3 +295,24 @@ void *remote_mmap(struct parasite_ctl *ctl, return (void *)map; } + +void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) +{ + /* + * OpenPOWER ABI requires that r12 is set to the calling function addressi + * to compute the TOC pointer. + */ + regs->gpr[12] = new_ip; + regs->nip = new_ip; + if (stack) + regs->gpr[1] = (unsigned long) stack; + regs->trap = 0; +} + +bool arch_can_dump_task(struct parasite_ctl *ctl) +{ + /* + * TODO: We should detect 32bit task when BE support is done. + */ + return true; +} diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 73accb13d..3484455dd 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -7,7 +7,6 @@ #include #include "types.h" -#include "asm/processor-flags.h" #include "asm/parasite-syscall.h" #include "asm/restorer.h" #include "asm/fpu.h" @@ -30,23 +29,6 @@ #include "images/core.pb-c.h" #include "images/creds.pb-c.h" -/* - * regs must be inited when calling this function from original context - */ -void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) -{ - set_user_reg(regs, ip, new_ip); - if (stack) - set_user_reg(regs, sp, (unsigned long) stack); - - /* Avoid end of syscall processing */ - set_user_reg(regs, orig_ax, -1); - - /* Make sure flags are in known state */ - set_user_reg(regs, flags, get_user_reg(regs, flags) & - ~(X86_EFLAGS_TF | X86_EFLAGS_DF | X86_EFLAGS_IF)); -} - #ifdef CONFIG_X86_64 /* Remaps 64-bit vDSO on the same addr, where it already is */ int kdat_compat_sigreturn_test(void) @@ -72,54 +54,6 @@ int kdat_compat_sigreturn_test(void) } #endif /* CONFIG_X86_64 */ -static int arch_task_compatible(struct parasite_ctl *ctl) -{ - return !user_regs_native(&ctl->orig.regs); -} - -#define USER32_CS 0x23 -#define USER_CS 0x33 - -static bool ldt_task_selectors(pid_t pid) -{ - unsigned long cs; - - errno = 0; - /* - * Offset of register must be from 64-bit set even for - * compatible tasks. Fix this to support native i386 tasks - */ - cs = ptrace(PTRACE_PEEKUSER, pid, offsetof(user_regs_struct64, cs), 0); - if (errno != 0) { - pr_perror("Can't get CS register for %d", pid); - return -1; - } - - return cs != USER_CS && cs != USER32_CS; -} - -bool arch_can_dump_task(struct parasite_ctl *ctl) -{ - pid_t pid = ctl->rpid; - int ret; - - ret = arch_task_compatible(ctl); - if (ret < 0) - return false; - - if (ret && !kdat.has_compat_sigreturn) { - pr_err("Can't dump task %d running in 32-bit mode\n", pid); - return false; - } - - if (ldt_task_selectors(pid)) { - pr_err("Can't dump task %d with LDT descriptors\n", pid); - return false; - } - - return true; -} - int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) { CoreEntry *core = x; diff --git a/criu/arch/x86/include/asm/parasite-syscall.h b/criu/arch/x86/include/asm/parasite-syscall.h index 18c746f6f..fd5b26c7c 100644 --- a/criu/arch/x86/include/asm/parasite-syscall.h +++ b/criu/arch/x86/include/asm/parasite-syscall.h @@ -5,10 +5,6 @@ struct parasite_ctl; -#define ARCH_SI_TRAP SI_KERNEL - -#define __NR(syscall, compat) ((compat) ? __NR32_##syscall : __NR_##syscall) - /* * For x86_32 __NR_mmap inside the kernel represents old_mmap system * call, but since we didn't use it yet lets go further and simply @@ -18,6 +14,4 @@ struct parasite_ctl; #define __NR32_mmap __NR32_mmap2 -void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); - #endif diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index 38abde2d9..19d65d76f 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -3,14 +3,19 @@ #include #include #include + +#include "asm/processor-flags.h" #include "asm/parasite-syscall.h" #include "uapi/std/syscall-codes.h" +#include "compel/include/asm/syscall.h" #include "err.h" #include "asm/fpu.h" #include "asm/types.h" #include "errno.h" #include "asm/cpu.h" #include "parasite-syscall.h" +#include "ptrace.h" +#include "kerndat.h" #include "infect.h" #include "infect-priv.h" @@ -170,6 +175,77 @@ void *remote_mmap(struct parasite_ctl *ctl, return (void *)map; } +/* + * regs must be inited when calling this function from original context + */ +void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) +{ + set_user_reg(regs, ip, new_ip); + if (stack) + set_user_reg(regs, sp, (unsigned long) stack); + + /* Avoid end of syscall processing */ + set_user_reg(regs, orig_ax, -1); + + /* Make sure flags are in known state */ + set_user_reg(regs, flags, get_user_reg(regs, flags) & + ~(X86_EFLAGS_TF | X86_EFLAGS_DF | X86_EFLAGS_IF)); +} + +#define USER32_CS 0x23 +#define USER_CS 0x33 + +static bool ldt_task_selectors(pid_t pid) +{ + unsigned long cs; + + errno = 0; + /* + * Offset of register must be from 64-bit set even for + * compatible tasks. Fix this to support native i386 tasks + */ + cs = ptrace(PTRACE_PEEKUSER, pid, offsetof(user_regs_struct64, cs), 0); + if (errno != 0) { + pr_perror("Can't get CS register for %d", pid); + return -1; + } + + return cs != USER_CS && cs != USER32_CS; +} + +static int arch_task_compatible(pid_t pid) +{ + user_regs_struct_t r; + int ret = ptrace_get_regs(pid, &r); + + if (ret) + return -1; + + return !user_regs_native(&r); +} + +bool arch_can_dump_task(struct parasite_ctl *ctl) +{ + pid_t pid = ctl->rpid; + int ret; + + ret = arch_task_compatible(pid); + if (ret < 0) + return false; + + if (ret && !kdat.has_compat_sigreturn) { + pr_err("Can't dump task %d running in 32-bit mode\n", pid); + return false; + } + + if (ldt_task_selectors(pid)) { + pr_err("Can't dump task %d with LDT descriptors\n", pid); + return false; + } + + return true; +} + int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs) { struct iovec iov; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index fdceacbc2..b9e9827ee 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -81,6 +81,7 @@ #include "parasite-syscall.h" #include "files-reg.h" #include "uapi/std/syscall-codes.h" +#include "compel/include/asm/syscall.h" #include "protobuf.h" #include "images/sa.pb-c.h" diff --git a/criu/include/infect-priv.h b/criu/include/infect-priv.h index 3ddd1175f..c994981d1 100644 --- a/criu/include/infect-priv.h +++ b/criu/include/infect-priv.h @@ -3,6 +3,8 @@ #include +#define BUILTIN_SYSCALL_SIZE 8 + /* parasite control block */ struct parasite_ctl { int rpid; /* Real pid of the victim */ @@ -46,7 +48,10 @@ extern int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, unsigned long arg5, unsigned long arg6); +extern void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); extern void *remote_mmap(struct parasite_ctl *ctl, void *addr, size_t length, int prot, int flags, int fd, off_t offset); +extern bool arch_can_dump_task(struct parasite_ctl *ctl); + #endif diff --git a/criu/include/infect-util.h b/criu/include/infect-util.h new file mode 100644 index 000000000..bd2010c3b --- /dev/null +++ b/criu/include/infect-util.h @@ -0,0 +1,5 @@ +#ifndef __COMPEL_INFECT_UTIL_H__ +#define __COMPEL_INFECT_UTIL_H__ +struct parasite_ctl; +extern int compel_util_send_fd(struct parasite_ctl *ctl, int fd); +#endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 30cb36b83..88318916b 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -6,8 +6,6 @@ #include "config.h" #include "asm/parasite-syscall.h" -#define BUILTIN_SYSCALL_SIZE 8 - struct parasite_dump_thread; struct parasite_dump_misc; struct parasite_drain_fd; @@ -31,8 +29,6 @@ struct proc_posix_timers_stat; extern int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, struct parasite_ctl *ctl, struct pstree_item *); -extern int parasite_send_fd(struct parasite_ctl *ctl, int fd); - extern int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_misc *misc); extern int parasite_dump_creds(struct parasite_ctl *ctl, struct _CredsEntry *ce); extern int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, struct _CoreEntry *core); @@ -59,6 +55,4 @@ extern struct parasite_tty_args *parasite_dump_tty(struct parasite_ctl *ctl, int extern int parasite_init_threads_seized(struct parasite_ctl *ctl, struct pstree_item *item); extern int parasite_fini_threads_seized(struct parasite_ctl *ctl); -extern bool arch_can_dump_task(struct parasite_ctl *ctl); - #endif /* __CR_PARASITE_SYSCALL_H__ */ diff --git a/criu/infect-util.c b/criu/infect-util.c new file mode 100644 index 000000000..8db32afdf --- /dev/null +++ b/criu/infect-util.c @@ -0,0 +1,20 @@ +#include "int.h" +#include "log.h" +#include "common/bug.h" +#include "lock.h" +#include "util-pie.h" +#include "infect-rpc.h" +#include "infect-util.h" + +int compel_util_send_fd(struct parasite_ctl *ctl, int fd) +{ + int sk; + + sk = compel_rpc_sock(ctl); + if (send_fd(sk, NULL, 0, fd) < 0) { + pr_perror("Can't send file descriptor"); + return -1; + } + return 0; +} + diff --git a/criu/infect.c b/criu/infect.c index 62ec77c36..48ad1effd 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -6,16 +6,18 @@ #include #include +#include "compel/include/asm/ptrace.h" +#include "compel/include/asm/syscall.h" #include "infect.h" #include "ptrace.h" #include "restorer.h" -#include "parasite-syscall.h" #include "pie-relocs.h" #include "parasite-blob.h" #include "sigframe.h" #include "criu-log.h" #include "infect-rpc.h" #include "infect-priv.h" +#include "infect-util.h" #define UNIX_PATH_MAX (sizeof(struct sockaddr_un) - \ (size_t)((struct sockaddr_un *) 0)->sun_path) @@ -556,7 +558,7 @@ static int parasite_init_daemon(struct parasite_ctl *ctl) if (accept_tsock(ctl) < 0) goto err; - if (parasite_send_fd(ctl, log_get_fd())) + if (compel_util_send_fd(ctl, log_get_fd())) goto err; pr_info("Wait for parasite being daemonized...\n"); diff --git a/criu/mem.c b/criu/mem.c index 46389d3cc..757e13668 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -27,6 +27,7 @@ #include "fault-injection.h" #include "infect.h" #include "infect-rpc.h" +#include "infect-util.h" #include "protobuf.h" #include "images/pagemap.pb-c.h" @@ -236,7 +237,7 @@ static int drain_pages(struct page_pipe *pp, struct parasite_ctl *ctl, ret = compel_rpc_call(PARASITE_CMD_DUMPPAGES, ctl); if (ret < 0) return -1; - ret = parasite_send_fd(ctl, ppb->p[1]); + ret = compel_util_send_fd(ctl, ppb->p[1]); if (ret) return -1; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 80a28e420..26cd9afa6 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -68,18 +68,6 @@ unsigned long get_exec_start(struct vm_area_list *vmas) return 0; } -int parasite_send_fd(struct parasite_ctl *ctl, int fd) -{ - int sk; - - sk = compel_rpc_sock(ctl); - if (send_fd(sk, NULL, 0, fd) < 0) { - pr_perror("Can't send file descriptor"); - return -1; - } - return 0; -} - /* * We need to detect parasite crashes not to hang on socket operations. * Since CRIU holds parasite with ptrace, it will receive SIGCHLD if the From c954ac161868a63a572a00140b4f81092581c44f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 27 Oct 2016 14:25:46 +0300 Subject: [PATCH 0174/4375] infect: Move breakpoints management into infect This removes restorer.h from infect. The header describes routines, structures and constants messing with restorer blob. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/include/ptrace.h | 11 ++++ compel/arch/arm/src/lib/include/ptrace.h | 11 ++++ compel/arch/ppc64/src/lib/include/ptrace.h | 11 ++++ compel/arch/x86/src/lib/include/ptrace.h | 2 + criu/arch/aarch64/include/asm/restorer.h | 10 ---- criu/arch/arm/include/asm/restorer.h | 10 ---- criu/arch/ppc64/include/asm/restorer.h | 10 ---- criu/arch/x86/crtools.c | 59 ------------------- criu/arch/x86/infect.c | 60 ++++++++++++++++++++ criu/infect.c | 13 ++++- 10 files changed, 106 insertions(+), 91 deletions(-) diff --git a/compel/arch/aarch64/src/lib/include/ptrace.h b/compel/arch/aarch64/src/lib/include/ptrace.h index 9cf7d460d..e18454df2 100644 --- a/compel/arch/aarch64/src/lib/include/ptrace.h +++ b/compel/arch/aarch64/src/lib/include/ptrace.h @@ -1,4 +1,15 @@ #ifndef __COMPEL_PTRACE_H__ #define __COMPEL_PTRACE_H__ #define ARCH_SI_TRAP TRAP_BRKPT + +static inline int ptrace_set_breakpoint(pid_t pid, void *addr) +{ + return 0; +} + +static inline int ptrace_flush_breakpoints(pid_t pid) +{ + return 0; +} + #endif diff --git a/compel/arch/arm/src/lib/include/ptrace.h b/compel/arch/arm/src/lib/include/ptrace.h index 9cf7d460d..e18454df2 100644 --- a/compel/arch/arm/src/lib/include/ptrace.h +++ b/compel/arch/arm/src/lib/include/ptrace.h @@ -1,4 +1,15 @@ #ifndef __COMPEL_PTRACE_H__ #define __COMPEL_PTRACE_H__ #define ARCH_SI_TRAP TRAP_BRKPT + +static inline int ptrace_set_breakpoint(pid_t pid, void *addr) +{ + return 0; +} + +static inline int ptrace_flush_breakpoints(pid_t pid) +{ + return 0; +} + #endif diff --git a/compel/arch/ppc64/src/lib/include/ptrace.h b/compel/arch/ppc64/src/lib/include/ptrace.h index 9cf7d460d..0274c2675 100644 --- a/compel/arch/ppc64/src/lib/include/ptrace.h +++ b/compel/arch/ppc64/src/lib/include/ptrace.h @@ -1,4 +1,15 @@ #ifndef __COMPEL_PTRACE_H__ #define __COMPEL_PTRACE_H__ #define ARCH_SI_TRAP TRAP_BRKPT + +static inline int ptrace_set_breakpoint(pid_t pid, void *addr) +{ + return 0; +} + +static inline int ptrace_flush_breakpoints(pid_t pid) +{ + return 0; +} + #endif diff --git a/compel/arch/x86/src/lib/include/ptrace.h b/compel/arch/x86/src/lib/include/ptrace.h index 991f1152a..844ea0efd 100644 --- a/compel/arch/x86/src/lib/include/ptrace.h +++ b/compel/arch/x86/src/lib/include/ptrace.h @@ -1,4 +1,6 @@ #ifndef __COMPEL_PTRACE_H__ #define __COMPEL_PTRACE_H__ #define ARCH_SI_TRAP SI_KERNEL +extern int ptrace_set_breakpoint(pid_t pid, void *addr); +extern int ptrace_flush_breakpoints(pid_t pid); #endif diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h index e23ab11fb..b842a74ef 100644 --- a/criu/arch/aarch64/include/asm/restorer.h +++ b/criu/arch/aarch64/include/asm/restorer.h @@ -62,16 +62,6 @@ static inline void restore_tls(tls_t *ptls) asm("msr tpidr_el0, %0" : : "r" (*ptls)); } -static inline int ptrace_set_breakpoint(pid_t pid, void *addr) -{ - return 0; -} - -static inline int ptrace_flush_breakpoints(pid_t pid) -{ - return 0; -} - static inline void *alloc_compat_syscall_stack(void) { return NULL; } static inline void free_compat_syscall_stack(void *stack32) { } static inline int diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h index 07bf4aeb2..536286d4c 100644 --- a/criu/arch/arm/include/asm/restorer.h +++ b/criu/arch/arm/include/asm/restorer.h @@ -72,16 +72,6 @@ static inline void restore_tls(tls_t *ptls) { ); } -static inline int ptrace_set_breakpoint(pid_t pid, void *addr) -{ - return 0; -} - -static inline int ptrace_flush_breakpoints(pid_t pid) -{ - return 0; -} - static inline void *alloc_compat_syscall_stack(void) { return NULL; } static inline void free_compat_syscall_stack(void *stack32) { } static inline int diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h index afd00c519..5342fab68 100644 --- a/criu/arch/ppc64/include/asm/restorer.h +++ b/criu/arch/ppc64/include/asm/restorer.h @@ -55,16 +55,6 @@ int restore_nonsigframe_gpregs(UserPpc64RegsEntry *r); /* Nothing to do, TLS is accessed through r13 */ static inline void restore_tls(tls_t *ptls) { (void)ptls; } -static inline int ptrace_set_breakpoint(pid_t pid, void *addr) -{ - return 0; -} - -static inline int ptrace_flush_breakpoints(pid_t pid) -{ - return 0; -} - /* * Defined in arch/ppc64/syscall-common-ppc64.S */ diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 3484455dd..2eb2914a6 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -450,61 +449,3 @@ int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) } #endif -/* Copied from the gdb header gdb/nat/x86-dregs.h */ - -/* Debug registers' indices. */ -#define DR_FIRSTADDR 0 -#define DR_LASTADDR 3 -#define DR_NADDR 4 /* The number of debug address registers. */ -#define DR_STATUS 6 /* Index of debug status register (DR6). */ -#define DR_CONTROL 7 /* Index of debug control register (DR7). */ - -#define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit. */ -#define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit. */ -#define DR_ENABLE_SIZE 2 /* Two enable bits per debug register. */ - -/* Locally enable the break/watchpoint in the I'th debug register. */ -#define X86_DR_LOCAL_ENABLE(i) (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))) - -int ptrace_set_breakpoint(pid_t pid, void *addr) -{ - int ret; - - /* Set a breakpoint */ - if (ptrace(PTRACE_POKEUSER, pid, - offsetof(struct user, u_debugreg[DR_FIRSTADDR]), - addr)) { - pr_perror("Unable to setup a breakpoint into %d", pid); - return -1; - } - - /* Enable the breakpoint */ - if (ptrace(PTRACE_POKEUSER, pid, - offsetof(struct user, u_debugreg[DR_CONTROL]), - X86_DR_LOCAL_ENABLE(DR_FIRSTADDR))) { - pr_perror("Unable to enable the breakpoint for %d", pid); - return -1; - } - - ret = ptrace(PTRACE_CONT, pid, NULL, NULL); - if (ret) { - pr_perror("Unable to restart the stopped tracee process %d", pid); - return -1; - } - - return 1; -} - -int ptrace_flush_breakpoints(pid_t pid) -{ - /* Disable the breakpoint */ - if (ptrace(PTRACE_POKEUSER, pid, - offsetof(struct user, u_debugreg[DR_CONTROL]), - 0)) { - pr_perror("Unable to disable the breakpoint for %d", pid); - return -1; - } - - return 0; -} - diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index 19d65d76f..515b24294 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -3,11 +3,13 @@ #include #include #include +#include #include "asm/processor-flags.h" #include "asm/parasite-syscall.h" #include "uapi/std/syscall-codes.h" #include "compel/include/asm/syscall.h" +#include "compel/include/asm/ptrace.h" #include "err.h" #include "asm/fpu.h" #include "asm/types.h" @@ -246,6 +248,64 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) return true; } +/* Copied from the gdb header gdb/nat/x86-dregs.h */ + +/* Debug registers' indices. */ +#define DR_FIRSTADDR 0 +#define DR_LASTADDR 3 +#define DR_NADDR 4 /* The number of debug address registers. */ +#define DR_STATUS 6 /* Index of debug status register (DR6). */ +#define DR_CONTROL 7 /* Index of debug control register (DR7). */ + +#define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit. */ +#define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit. */ +#define DR_ENABLE_SIZE 2 /* Two enable bits per debug register. */ + +/* Locally enable the break/watchpoint in the I'th debug register. */ +#define X86_DR_LOCAL_ENABLE(i) (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))) + +int ptrace_set_breakpoint(pid_t pid, void *addr) +{ + int ret; + + /* Set a breakpoint */ + if (ptrace(PTRACE_POKEUSER, pid, + offsetof(struct user, u_debugreg[DR_FIRSTADDR]), + addr)) { + pr_perror("Unable to setup a breakpoint into %d", pid); + return -1; + } + + /* Enable the breakpoint */ + if (ptrace(PTRACE_POKEUSER, pid, + offsetof(struct user, u_debugreg[DR_CONTROL]), + X86_DR_LOCAL_ENABLE(DR_FIRSTADDR))) { + pr_perror("Unable to enable the breakpoint for %d", pid); + return -1; + } + + ret = ptrace(PTRACE_CONT, pid, NULL, NULL); + if (ret) { + pr_perror("Unable to restart the stopped tracee process %d", pid); + return -1; + } + + return 1; +} + +int ptrace_flush_breakpoints(pid_t pid) +{ + /* Disable the breakpoint */ + if (ptrace(PTRACE_POKEUSER, pid, + offsetof(struct user, u_debugreg[DR_CONTROL]), + 0)) { + pr_perror("Unable to disable the breakpoint for %d", pid); + return -1; + } + + return 0; +} + int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs) { struct iovec iov; diff --git a/criu/infect.c b/criu/infect.c index 48ad1effd..fbfda054d 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -4,21 +4,30 @@ #include #include #include +#include +#include #include +#include "xmalloc.h" +#include "uapi/std/syscall-codes.h" +#include "uapi/std/asm/syscall-types.h" #include "compel/include/asm/ptrace.h" #include "compel/include/asm/syscall.h" +#include "asm/sigframe.h" #include "infect.h" #include "ptrace.h" -#include "restorer.h" #include "pie-relocs.h" #include "parasite-blob.h" -#include "sigframe.h" #include "criu-log.h" +#include "common/bug.h" +#include "lock.h" #include "infect-rpc.h" #include "infect-priv.h" #include "infect-util.h" +#include +#include "util.h" + #define UNIX_PATH_MAX (sizeof(struct sockaddr_un) - \ (size_t)((struct sockaddr_un *) 0)->sun_path) From f15dfc61072a57d88275b8a04e76165d1285b1ea Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 27 Oct 2016 15:01:34 +0300 Subject: [PATCH 0175/4375] infect: Move __NR32_mmap into compel headers This remove parasite-syscall.h from infect. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/include/syscall.h | 9 +++++++++ criu/arch/x86/include/asm/parasite-syscall.h | 9 --------- criu/arch/x86/infect.c | 2 -- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/compel/arch/x86/src/lib/include/syscall.h b/compel/arch/x86/src/lib/include/syscall.h index 6d7df1861..9af1b1f99 100644 --- a/compel/arch/x86/src/lib/include/syscall.h +++ b/compel/arch/x86/src/lib/include/syscall.h @@ -1,4 +1,13 @@ #ifndef __COMPEL_SYSCALL_H__ #define __COMPEL_SYSCALL_H__ #define __NR(syscall, compat) ((compat) ? __NR32_##syscall : __NR_##syscall) + +/* + * For x86_32 __NR_mmap inside the kernel represents old_mmap system + * call, but since we didn't use it yet lets go further and simply + * define own alias for __NR_mmap2 which would allow us to unify code + * between 32 and 64 bits version. + */ +#define __NR32_mmap __NR32_mmap2 + #endif diff --git a/criu/arch/x86/include/asm/parasite-syscall.h b/criu/arch/x86/include/asm/parasite-syscall.h index fd5b26c7c..a2b5e75ff 100644 --- a/criu/arch/x86/include/asm/parasite-syscall.h +++ b/criu/arch/x86/include/asm/parasite-syscall.h @@ -5,13 +5,4 @@ struct parasite_ctl; -/* - * For x86_32 __NR_mmap inside the kernel represents old_mmap system - * call, but since we didn't use it yet lets go further and simply - * define own alias for __NR_mmap2 which would allow us to unify code - * between 32 and 64 bits version. - */ -#define __NR32_mmap __NR32_mmap2 - - #endif diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index 515b24294..0ac507916 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -6,7 +6,6 @@ #include #include "asm/processor-flags.h" -#include "asm/parasite-syscall.h" #include "uapi/std/syscall-codes.h" #include "compel/include/asm/syscall.h" #include "compel/include/asm/ptrace.h" @@ -15,7 +14,6 @@ #include "asm/types.h" #include "errno.h" #include "asm/cpu.h" -#include "parasite-syscall.h" #include "ptrace.h" #include "kerndat.h" #include "infect.h" From 3a90e8e7f696f44c6c6939aef1f79ce6c9c962b3 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 27 Oct 2016 14:27:23 +0300 Subject: [PATCH 0176/4375] infect: Reshuffle headers Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/infect.c | 13 +++++++------ criu/infect-rpc.c | 4 ++-- criu/infect-util.c | 1 + criu/infect.c | 19 ++++++++++--------- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index 0ac507916..b71b9735e 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -5,17 +5,18 @@ #include #include +#include "errno.h" #include "asm/processor-flags.h" +#include "asm/fpu.h" +#include "asm/cpu.h" +#include "kerndat.h" + #include "uapi/std/syscall-codes.h" #include "compel/include/asm/syscall.h" #include "compel/include/asm/ptrace.h" -#include "err.h" -#include "asm/fpu.h" -#include "asm/types.h" -#include "errno.h" -#include "asm/cpu.h" +#include "common/err.h" +#include "asm/infect-types.h" #include "ptrace.h" -#include "kerndat.h" #include "infect.h" #include "infect-priv.h" diff --git a/criu/infect-rpc.c b/criu/infect-rpc.c index 858a4c0b6..c8b97a297 100644 --- a/criu/infect-rpc.c +++ b/criu/infect-rpc.c @@ -1,8 +1,8 @@ -#include "xmalloc.h" -#include "types.h" #include "log.h" #include "common/bug.h" +#include "common/xmalloc.h" #include "lock.h" + #include "infect.h" #include "infect-priv.h" #include "infect-rpc.h" diff --git a/criu/infect-util.c b/criu/infect-util.c index 8db32afdf..4c0537fdc 100644 --- a/criu/infect-util.c +++ b/criu/infect-util.c @@ -3,6 +3,7 @@ #include "common/bug.h" #include "lock.h" #include "util-pie.h" + #include "infect-rpc.h" #include "infect-util.h" diff --git a/criu/infect.c b/criu/infect.c index fbfda054d..2afc19832 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -8,7 +8,16 @@ #include #include -#include "xmalloc.h" +#include "pie-relocs.h" +#include "parasite-blob.h" +#include "criu-log.h" +#include "common/bug.h" +#include "common/xmalloc.h" +#include "lock.h" + +#include +#include "util.h" + #include "uapi/std/syscall-codes.h" #include "uapi/std/asm/syscall-types.h" #include "compel/include/asm/ptrace.h" @@ -16,18 +25,10 @@ #include "asm/sigframe.h" #include "infect.h" #include "ptrace.h" -#include "pie-relocs.h" -#include "parasite-blob.h" -#include "criu-log.h" -#include "common/bug.h" -#include "lock.h" #include "infect-rpc.h" #include "infect-priv.h" #include "infect-util.h" -#include -#include "util.h" - #define UNIX_PATH_MAX (sizeof(struct sockaddr_un) - \ (size_t)((struct sockaddr_un *) 0)->sun_path) From 468a64922543a54fd4bb3b701b67ab5cca3e3641 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 27 Oct 2016 16:18:09 +0300 Subject: [PATCH 0177/4375] infect: Move errno.h to compel Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- {criu => compel}/include/errno.h | 4 ++-- criu/arch/aarch64/infect.c | 2 +- criu/arch/arm/crtools.c | 1 - criu/arch/arm/infect.c | 2 +- criu/arch/ppc64/crtools.c | 1 - criu/arch/ppc64/infect.c | 2 +- criu/arch/x86/crtools.c | 1 - criu/arch/x86/infect.c | 2 +- 8 files changed, 6 insertions(+), 9 deletions(-) rename {criu => compel}/include/errno.h (72%) diff --git a/criu/include/errno.h b/compel/include/errno.h similarity index 72% rename from criu/include/errno.h rename to compel/include/errno.h index 5c2322e9f..d41fd5391 100644 --- a/criu/include/errno.h +++ b/compel/include/errno.h @@ -1,5 +1,5 @@ -#ifndef __CR_ERRNO_H__ -#define __CR_ERRNO_H__ +#ifndef __COMPEL_ERRNO_H__ +#define __COMPEL_ERRNO_H__ #define ERESTARTSYS 512 #define ERESTARTNOINTR 513 diff --git a/criu/arch/aarch64/infect.c b/criu/arch/aarch64/infect.c index 263ea5a55..79f64d095 100644 --- a/criu/arch/aarch64/infect.c +++ b/criu/arch/aarch64/infect.c @@ -8,7 +8,7 @@ #include "criu-log.h" #include "kerndat.h" #include "parasite-syscall.h" -#include "errno.h" +#include "compel/include/errno.h" #include "infect.h" #include "infect-priv.h" diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index 8ce1e6619..6c95fe853 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -16,7 +16,6 @@ #include "elf.h" #include "parasite-syscall.h" #include "restorer.h" -#include "errno.h" #include "kerndat.h" #include "infect.h" diff --git a/criu/arch/arm/infect.c b/criu/arch/arm/infect.c index 50d1d5b68..1ad01472f 100644 --- a/criu/arch/arm/infect.c +++ b/criu/arch/arm/infect.c @@ -6,7 +6,7 @@ #include "criu-log.h" #include "kerndat.h" #include "parasite-syscall.h" -#include "errno.h" +#include "compel/include/errno.h" #include "infect.h" #include "infect-priv.h" diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index e634c7b71..cd4df6417 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -17,7 +17,6 @@ #include "log.h" #include "util.h" #include "cpu.h" -#include "errno.h" #include "infect.h" #include "protobuf.h" diff --git a/criu/arch/ppc64/infect.c b/criu/arch/ppc64/infect.c index 029509ee3..feefc1448 100644 --- a/criu/arch/ppc64/infect.c +++ b/criu/arch/ppc64/infect.c @@ -6,7 +6,7 @@ #include "asm/types.h" #include "ptrace.h" #include "parasite-syscall.h" -#include "errno.h" +#include "compel/include/errno.h" #include "criu-log.h" #include "infect.h" #include "infect-priv.h" diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 2eb2914a6..01fcfed45 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -19,7 +19,6 @@ #include "log.h" #include "util.h" #include "cpu.h" -#include "errno.h" #include "uapi/std/syscall-codes.h" #include "kerndat.h" #include "infect.h" diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index b71b9735e..e2fca9bf3 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -5,12 +5,12 @@ #include #include -#include "errno.h" #include "asm/processor-flags.h" #include "asm/fpu.h" #include "asm/cpu.h" #include "kerndat.h" +#include "compel/include/errno.h" #include "uapi/std/syscall-codes.h" #include "compel/include/asm/syscall.h" #include "compel/include/asm/ptrace.h" From dec9a2505416bd43333a8b4e6e2ebbf0b09c1cba Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 27 Oct 2016 16:23:27 +0300 Subject: [PATCH 0178/4375] infect: Move processor-flags.h into compel Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .../asm => compel/arch/arm/src/lib/include}/processor-flags.h | 0 .../asm => compel/arch/x86/src/lib/include}/processor-flags.h | 0 criu/arch/aarch64/crtools.c | 1 - criu/arch/aarch64/include/asm/processor-flags.h | 4 ---- criu/arch/arm/crtools.c | 2 +- criu/arch/ppc64/include/asm/processor-flags.h | 4 ---- criu/arch/x86/infect.c | 2 +- 7 files changed, 2 insertions(+), 11 deletions(-) rename {criu/arch/arm/include/asm => compel/arch/arm/src/lib/include}/processor-flags.h (100%) rename {criu/arch/x86/include/asm => compel/arch/x86/src/lib/include}/processor-flags.h (100%) delete mode 100644 criu/arch/aarch64/include/asm/processor-flags.h delete mode 100644 criu/arch/ppc64/include/asm/processor-flags.h diff --git a/criu/arch/arm/include/asm/processor-flags.h b/compel/arch/arm/src/lib/include/processor-flags.h similarity index 100% rename from criu/arch/arm/include/asm/processor-flags.h rename to compel/arch/arm/src/lib/include/processor-flags.h diff --git a/criu/arch/x86/include/asm/processor-flags.h b/compel/arch/x86/src/lib/include/processor-flags.h similarity index 100% rename from criu/arch/x86/include/asm/processor-flags.h rename to compel/arch/x86/src/lib/include/processor-flags.h diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index 02205453e..8e4f48656 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -7,7 +7,6 @@ #include "asm/restorer.h" #include "common/compiler.h" #include "ptrace.h" -#include "asm/processor-flags.h" #include "asm/dump.h" #include "protobuf.h" #include "images/core.pb-c.h" diff --git a/criu/arch/aarch64/include/asm/processor-flags.h b/criu/arch/aarch64/include/asm/processor-flags.h deleted file mode 100644 index c1888af36..000000000 --- a/criu/arch/aarch64/include/asm/processor-flags.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef __CR_PROCESSOR_FLAGS_H__ -#define __CR_PROCESSOR_FLAGS_H__ - -#endif diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index 6c95fe853..d0576d5ae 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -6,7 +6,7 @@ #include "common/compiler.h" #include "asm/dump.h" #include "ptrace.h" -#include "asm/processor-flags.h" +#include "compel/include/asm/processor-flags.h" #include "protobuf.h" #include "images/core.pb-c.h" #include "images/creds.pb-c.h" diff --git a/criu/arch/ppc64/include/asm/processor-flags.h b/criu/arch/ppc64/include/asm/processor-flags.h deleted file mode 100644 index c1888af36..000000000 --- a/criu/arch/ppc64/include/asm/processor-flags.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef __CR_PROCESSOR_FLAGS_H__ -#define __CR_PROCESSOR_FLAGS_H__ - -#endif diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index e2fca9bf3..10f319391 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -5,11 +5,11 @@ #include #include -#include "asm/processor-flags.h" #include "asm/fpu.h" #include "asm/cpu.h" #include "kerndat.h" +#include "compel/include/asm/processor-flags.h" #include "compel/include/errno.h" #include "uapi/std/syscall-codes.h" #include "compel/include/asm/syscall.h" From f3021b6ab5a6a91eac8d163d7ebb59941a56d1b1 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 27 Oct 2016 18:07:10 +0300 Subject: [PATCH 0179/4375] infect: Remove criu util.h from infect This includes * The close_safe() routine for infect * Callback for opening proc files on infect_ctx Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/infect.h | 5 +++++ criu/infect.c | 16 +++++++++++----- criu/parasite-syscall.c | 1 + 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/criu/include/infect.h b/criu/include/infect.h index a161ae238..51c6247c4 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -89,6 +89,9 @@ extern k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl); struct rt_sigframe; +typedef int (*open_proc_fn)(int pid, int mode, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); + struct infect_ctx { int *p_sock; @@ -103,6 +106,8 @@ struct infect_ctx { unsigned long flags; /* fine-tune (e.g. faults) */ void (*child_handler)(int, siginfo_t *, void *); /* hander for SIGCHLD deaths */ + + open_proc_fn open_proc; }; extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *); diff --git a/criu/infect.c b/criu/infect.c index 2afc19832..432fdd2aa 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "pie-relocs.h" @@ -15,9 +16,6 @@ #include "common/xmalloc.h" #include "lock.h" -#include -#include "util.h" - #include "uapi/std/syscall-codes.h" #include "uapi/std/asm/syscall-types.h" #include "compel/include/asm/ptrace.h" @@ -46,6 +44,14 @@ #define SI_EVENT(_si_code) (((_si_code) & 0xFFFF) >> 8) +static inline void close_safe(int *pfd) +{ + if (*pfd > -1) { + close(*pfd); + *pfd = -1; + } +} + int compel_stop_task(int pid) { int ret; @@ -626,7 +632,7 @@ static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size) ctl->map_length = round_up(size, page_size()); - fd = open_proc_rw(ctl->rpid, "map_files/%p-%p", + fd = ctl->ictx.open_proc(ctl->rpid, O_RDWR, "map_files/%p-%p", ctl->remote_map, ctl->remote_map + ctl->map_length); if (fd < 0) return -1; @@ -685,7 +691,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) return fd; ctl->map_length = round_up(size, page_size()); - lfd = open_proc_rw(ctl->rpid, "fd/%d", fd); + lfd = ctl->ictx.open_proc(ctl->rpid, O_RDWR, "fd/%d", fd); if (lfd < 0) goto err_cure; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 26cd9afa6..0a8d6fe68 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -543,6 +543,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ictx = compel_infect_ctx(ctl); + ictx->open_proc = do_open_proc; ictx->child_handler = sigchld_handler; ictx->p_sock = &dmpi(item)->netns->net.seqsk; ictx->save_regs = save_task_regs; From f81d69da31d030adc4bda3ebe6b015952dbfc029 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 27 Oct 2016 19:34:17 +0300 Subject: [PATCH 0180/4375] infect: Remove types.h from infect.h Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/infect-rpc.h | 26 ++++++++++++-------------- criu/include/infect.h | 2 +- criu/infect.c | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/criu/include/infect-rpc.h b/criu/include/infect-rpc.h index d2f89a7d4..9569b6794 100644 --- a/criu/include/infect-rpc.h +++ b/criu/include/infect-rpc.h @@ -3,6 +3,7 @@ #include #include +#include struct parasite_ctl; extern int compel_rpc_sync(unsigned int cmd, struct parasite_ctl *ctl); @@ -11,9 +12,9 @@ extern int compel_rpc_call_sync(unsigned int cmd, struct parasite_ctl *ctl); extern int compel_rpc_sock(struct parasite_ctl *ctl); struct ctl_msg { - unsigned int cmd; /* command itself */ - unsigned int ack; /* ack on command */ - int err; /* error code on reply */ + uint32_t cmd; /* command itself */ + uint32_t ack; /* ack on command */ + int32_t err; /* error code on reply */ }; #define ctl_msg_cmd(_cmd) \ @@ -43,20 +44,17 @@ enum { }; struct parasite_init_args { - int h_addr_len; - struct sockaddr_un h_addr; - - int log_level; - - u64 sigframe; /* pointer to sigframe */ - - void *sigreturn_addr; - futex_t daemon_connected; + int32_t h_addr_len; + struct sockaddr_un h_addr; + int32_t log_level; + uint64_t sigreturn_addr; + uint64_t sigframe; /* pointer to sigframe */ + futex_t daemon_connected; }; struct parasite_unmap_args { - void *parasite_start; - unsigned long parasite_len; + uint64_t parasite_start; + uint64_t parasite_len; }; diff --git a/criu/include/infect.h b/criu/include/infect.h index 51c6247c4..f1692c29d 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -1,7 +1,7 @@ #ifndef __COMPEL_INFECT_H__ #define __COMPEL_INFECT_H__ -#include "types.h" +#include "asm/infect-types.h" #include "compel/include/uapi/ksigset.h" #define PARASITE_START_AREA_MIN (4096) diff --git a/criu/infect.c b/criu/infect.c index 432fdd2aa..1f1a5c59a 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -585,7 +585,7 @@ static int parasite_init_daemon(struct parasite_ctl *ctl) goto err; } - ctl->sigreturn_addr = args->sigreturn_addr; + ctl->sigreturn_addr = (void*)(uintptr_t)args->sigreturn_addr; ctl->daemonized = true; pr_info("Parasite %d has been switched to daemon mode\n", pid); return 0; From bb8b8e84f98b8b9ac459676ee5d19fe548fa4a56 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 18 Oct 2016 17:59:02 +0300 Subject: [PATCH 0181/4375] compel: Remove criu's int.h from infect Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/Makefile | 1 - .../arch/arm/plugins/std/syscalls/syscall.def | 4 +- .../plugins/std/syscalls/syscall-ppc64.tbl | 4 +- .../arch/x86/plugins/std/syscalls/syscall32.c | 24 ++++++------ .../x86/plugins/std/syscalls/syscall_32.tbl | 8 ++-- .../x86/plugins/std/syscalls/syscall_64.tbl | 4 +- compel/include/int.h | 1 - .../plugins/include/uapi/std/syscall-types.h | 11 +++--- compel/plugins/std/std.c | 1 - compel/src/lib/handle-elf.c | 37 +++++++++---------- 10 files changed, 45 insertions(+), 50 deletions(-) delete mode 120000 compel/include/int.h diff --git a/compel/Makefile b/compel/Makefile index bfb79237d..8fcfcff67 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -7,7 +7,6 @@ COMPEL_SO_VERSION_CODE := $(shell expr $(COMPEL_SO_VERSION_MAJOR) \* 65536 \+ $( ccflags-y += -iquote compel/arch/$(ARCH)/src/lib/include ccflags-y += -iquote compel/include ccflags-y += -iquote compel/plugins/include -ccflags-y += -iquote $(SRC_DIR)/criu/include ccflags-y += -fPIC lib-y += arch/$(ARCH)/src/lib/handle-elf.o diff --git a/compel/arch/arm/plugins/std/syscalls/syscall.def b/compel/arch/arm/plugins/std/syscalls/syscall.def index f14b37a92..647bc2033 100644 --- a/compel/arch/arm/plugins/std/syscalls/syscall.def +++ b/compel/arch/arm/plugins/std/syscalls/syscall.def @@ -77,7 +77,7 @@ setrlimit 164 75 (int resource, struct krlimit *rlim) mount 40 21 (char *dev_nmae, char *dir_name, char *type, unsigned long flags, void *data) umount2 39 52 (char *name, int flags) gettid 178 224 (void) -futex 98 240 (u32 *uaddr, int op, u32 val, struct timespec *utime, u32 *uaddr2, u32 val3) +futex 98 240 (uint32_t *uaddr, int op, uint32_t val, struct timespec *utime, uint32_t *uaddr2, uint32_t val3) set_tid_address 96 256 (int *tid_addr) restart_syscall 128 0 (void) timer_create 107 257 (clockid_t which_clock, struct sigevent *timer_event_spec, kernel_timer_t *created_timer_id) @@ -94,7 +94,7 @@ rt_tgsigqueueinfo 240 363 (pid_t tgid, pid_t pid, int sig, siginfo_t *info) vmsplice 75 343 (int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags) timerfd_settime 86 353 (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) fanotify_init 262 367 (unsigned int flags, unsigned int event_f_flags) -fanotify_mark 263 368 (int fanotify_fd, unsigned int flags, u64 mask, int dfd, const char *pathname) +fanotify_mark 263 368 (int fanotify_fd, unsigned int flags, uint64_t mask, int dfd, const char *pathname) open_by_handle_at 265 371 (int mountdirfd, struct file_handle *handle, int flags) setns 268 375 (int fd, int nstype) kcmp 272 378 (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) diff --git a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl index f6e5fe20b..23d54b38f 100644 --- a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl +++ b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl @@ -74,7 +74,7 @@ __NR_setrlimit 75 sys_setrlimit (int resource, struct krlimit *rlim) __NR_mount 21 sys_mount (char *dev_nmae, char *dir_name, char *type, unsigned long flags, void *data) __NR_umount2 52 sys_umount2 (char *name, int flags) __NR_gettid 207 sys_gettid (void) -__NR_futex 221 sys_futex (u32 *uaddr, int op, u32 val, struct timespec *utime, u32 *uaddr2, u32 val3) +__NR_futex 221 sys_futex (uint32_t *uaddr, int op, uint32_t val, struct timespec *utime, uint32_t *uaddr2, uint32_t val3) __NR_set_tid_address 232 sys_set_tid_address (int *tid_addr) __NR_restart_syscall 0 sys_restart_syscall (void) __NR_sys_timer_create 240 sys_timer_create (clockid_t which_clock, struct sigevent *timer_event_spec, kernel_timer_t *created_timer_id) @@ -93,7 +93,7 @@ __NR_timerfd_settime 311 sys_timerfd_settime (int ufd, int flags, const struct __NR_signalfd4 313 sys_signalfd (int fd, k_rtsigset_t *mask, size_t sizemask, int flags) __NR_rt_tgsigqueueinfo 322 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *info) __NR_fanotify_init 323 sys_fanotify_init (unsigned int flags, unsigned int event_f_flags) -__NR_fanotify_mark 324 sys_fanotify_mark (int fanotify_fd, unsigned int flags, u64 mask, int dfd, const char *pathname) +__NR_fanotify_mark 324 sys_fanotify_mark (int fanotify_fd, unsigned int flags, uint64_t mask, int dfd, const char *pathname) __NR_open_by_handle_at 346 sys_open_by_handle_at (int mountdirfd, struct file_handle *handle, int flags) __NR_setns 350 sys_setns (int fd, int nstype) __NR_kcmp 354 sys_kcmp (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall32.c b/compel/arch/x86/plugins/std/syscalls/syscall32.c index 88af59330..e172cacff 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall32.c +++ b/compel/arch/x86/plugins/std/syscalls/syscall32.c @@ -14,61 +14,61 @@ long sys_socket(int domain, int type, int protocol) { - u32 a[] = { (u32)domain, (u32)type, (u32)protocol }; + uint32_t a[] = { (uint32_t)domain, (uint32_t)type, (uint32_t)protocol }; return sys_socketcall(SYS_SOCKET, (unsigned long *)a); } long sys_connect(int sockfd, struct sockaddr *addr, int addrlen) { - u32 a[] = {(u32)sockfd, (u32)addr, (u32)addrlen}; + uint32_t a[] = {(uint32_t)sockfd, (uint32_t)addr, (uint32_t)addrlen}; return sys_socketcall(SYS_CONNECT, (unsigned long *)a); } long sys_sendto(int sockfd, void *buff, size_t len, unsigned int flags, struct sockaddr *addr, int addr_len) { - u32 a[] = {(u32)sockfd, (u32)buff, (u32)len, (u32)flags, (u32)addr, (u32)addr_len}; + uint32_t a[] = {(uint32_t)sockfd, (uint32_t)buff, (uint32_t)len, (uint32_t)flags, (uint32_t)addr, (uint32_t)addr_len}; return sys_socketcall(SYS_SENDTO, (unsigned long *)a); } long sys_recvfrom(int sockfd, void *ubuf, size_t size, unsigned int flags, struct sockaddr *addr, int *addr_len) { - u32 a[] = {(u32)sockfd, (u32)ubuf, (u32)size, (u32)flags, (u32)addr, (u32)addr_len}; + uint32_t a[] = {(uint32_t)sockfd, (uint32_t)ubuf, (uint32_t)size, (uint32_t)flags, (uint32_t)addr, (uint32_t)addr_len}; return sys_socketcall(SYS_RECVFROM, (unsigned long *)a); } long sys_sendmsg(int sockfd, const struct msghdr *msg, int flags) { - u32 a[] = {(u32)sockfd, (u32)msg, (u32)flags}; + uint32_t a[] = {(uint32_t)sockfd, (uint32_t)msg, (uint32_t)flags}; return sys_socketcall(SYS_SENDMSG, (unsigned long *)a); } long sys_recvmsg(int sockfd, struct msghdr *msg, int flags) { - u32 a[] = {(u32)sockfd, (u32)msg, (u32)flags}; + uint32_t a[] = {(uint32_t)sockfd, (uint32_t)msg, (uint32_t)flags}; return sys_socketcall(SYS_RECVMSG, (unsigned long *)a); } long sys_shutdown(int sockfd, int how) { - u32 a[] = {(u32)sockfd, (u32)how}; + uint32_t a[] = {(uint32_t)sockfd, (uint32_t)how}; return sys_socketcall(SYS_SHUTDOWN, (unsigned long *)a); } long sys_bind(int sockfd, const struct sockaddr *addr, int addrlen) { - u32 a[] = {(u32)sockfd, (u32)addr, (u32)addrlen}; + uint32_t a[] = {(uint32_t)sockfd, (uint32_t)addr, (uint32_t)addrlen}; return sys_socketcall(SYS_BIND, (unsigned long *)a); } long sys_setsockopt(int sockfd, int level, int optname, const void *optval, unsigned int optlen) { - u32 a[] = {(u32)sockfd, (u32)level, (u32)optname, (u32)optval, (u32)optlen}; + uint32_t a[] = {(uint32_t)sockfd, (uint32_t)level, (uint32_t)optname, (uint32_t)optval, (uint32_t)optlen}; return sys_socketcall(SYS_SETSOCKOPT, (unsigned long *)a); } long sys_getsockopt(int sockfd, int level, int optname, const void *optval, unsigned int *optlen) { - u32 a[] = {(u32)sockfd, (u32)level, (u32)optname, (u32)optval, (u32)optlen}; + uint32_t a[] = {(uint32_t)sockfd, (uint32_t)level, (uint32_t)optname, (uint32_t)optval, (uint32_t)optlen}; return sys_socketcall(SYS_GETSOCKOPT, (unsigned long *)a); } @@ -79,7 +79,7 @@ long sys_shmat(int shmid, void *shmaddr, int shmflag) return sys_ipc(SHMAT, shmid, shmflag, 0, shmaddr, 0); } -long sys_pread(unsigned int fd, char *ubuf, u32 count, u64 pos) +long sys_pread(unsigned int fd, char *ubuf, uint32_t count, uint64_t pos) { - return sys_pread64(fd, ubuf, count, (u32)(pos & 0xffffffffu), (u32)(pos >> 32)); + return sys_pread64(fd, ubuf, count, (uint32_t)(pos & 0xffffffffu), (uint32_t)(pos >> 32)); } diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl index 4f7e42194..5d6cebd6e 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl @@ -11,7 +11,7 @@ __NR_write 4 sys_write (int fd, const void *buf, unsigned long count) __NR_open 5 sys_open (const char *filename, int flags, unsigned int mode) __NR_close 6 sys_close (int fd) __NR_unlink 10 sys_unlink (char *pathname) -__NR_lseek 19 sys_lseek (int fd, s32 offset, unsigned int origin) +__NR_lseek 19 sys_lseek (int fd, int32_t offset, unsigned int origin) __NR_getpid 20 sys_getpid (void) __NR_mount 21 sys_mount (const char *dev_name, const char *dir_name, const char *type, unsigned long flags, const void *data) __NR_ptrace 26 sys_ptrace (long request, pid_t pid, void *addr, void *data) @@ -46,7 +46,7 @@ __NR_rt_sigreturn 173 sys_rt_sigreturn (void) __NR_rt_sigaction 174 sys_sigaction (int signum, const rt_sigaction_t *act, rt_sigaction_t *oldact, size_t sigsetsize) __NR_rt_sigprocmask 175 sys_sigprocmask (int how, k_rtsigset_t *set, k_rtsigset_t *oset, size_t sigsetsize) __NR_rt_sigqueueinfo 178 sys_rt_sigqueueinfo (pid_t pid, int sig, siginfo_t *uinfo) -__NR_pread64 180 sys_pread64 (unsigned int fd, char *ubuf, u32 count, u32 poslo, u32 poshi) +__NR_pread64 180 sys_pread64 (unsigned int fd, char *ubuf, uint32_t count, uint32_t poslo, uint32_t poshi) __NR_capget 184 sys_capget (struct cap_header *h, struct cap_data *d) __NR_capset 185 sys_capset (struct cap_header *h, struct cap_data *d) __NR_sigaltstack 186 sys_sigaltstack (const void *uss_ptr, void *uoss_ptr) @@ -62,7 +62,7 @@ __NR_setfsgid32 216 sys_setfsgid (int fsgid) __NR_mincore 218 sys_mincore (void *addr, unsigned long size, unsigned char *vec) __NR_madvise 219 sys_madvise (unsigned long start, size_t len, int behavior) __NR_gettid 224 sys_gettid (void) -__NR_futex 240 sys_futex (u32 *uaddr, int op, u32 val, struct timespec *utime, u32 *uaddr2, u32 val3) +__NR_futex 240 sys_futex (uint32_t *uaddr, int op, uint32_t val, struct timespec *utime, uint32_t *uaddr2, uint32_t val3) __NR_set_thread_area 243 sys_set_thread_area (user_desc_t *info) __NR_get_thread_area 244 sys_get_thread_area (user_desc_t *info) __NR_io_setup 245 sys_io_setup (unsigned nr_reqs, aio_context_t *ctx32p) @@ -86,7 +86,7 @@ __NR_signalfd 321 sys_signalfd (int ufd, const k_rtsigset_t *sigmask, size_t __NR_timerfd_settime 325 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) __NR_rt_tgsigqueueinfo 335 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *uinfo) __NR_fanotify_init 338 sys_fanotify_init (unsigned int flags, unsigned int event_f_flags) -__NR_fanotify_mark 339 sys_fanotify_mark (int fanotify_fd, unsigned int flag, u32 mask, int dfd, const char *pathname) +__NR_fanotify_mark 339 sys_fanotify_mark (int fanotify_fd, unsigned int flag, uint32_t mask, int dfd, const char *pathname) __NR_open_by_handle_at 342 sys_open_by_handle_at (int mountdirfd, struct file_handle *handle, int flags) __NR_setns 346 sys_setns (int fd, int nstype) __NR_kcmp 349 sys_kcmp (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl index 9a36b6826..35262c002 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl @@ -72,7 +72,7 @@ __NR_setrlimit 160 sys_setrlimit (int resource, struct krlimit *rlim) __NR_mount 165 sys_mount (char *dev_nmae, char *dir_name, char *type, unsigned long flags, void *data) __NR_umount2 166 sys_umount2 (char *name, int flags) __NR_gettid 186 sys_gettid (void) -__NR_futex 202 sys_futex (u32 *uaddr, int op, u32 val, struct timespec *utime, u32 *uaddr2, u32 val3) +__NR_futex 202 sys_futex (uint32_t *uaddr, int op, uint32_t val, struct timespec *utime, uint32_t *uaddr2, uint32_t val3) __NR_set_thread_area 205 sys_set_thread_area (user_desc_t *info) __NR_io_setup 206 sys_io_setup (unsigned nr_events, aio_context_t *ctx) __NR_io_getevents 208 sys_io_getevents (aio_context_t ctx, long min_nr, long nr, struct io_event *evs, struct timespec *tmo) @@ -98,7 +98,7 @@ __NR_timerfd_settime 286 sys_timerfd_settime (int ufd, int flags, const struct __NR_signalfd4 289 sys_signalfd (int fd, k_rtsigset_t *mask, size_t sizemask, int flags) __NR_rt_tgsigqueueinfo 297 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *info) __NR_fanotify_init 300 sys_fanotify_init (unsigned int flags, unsigned int event_f_flags) -__NR_fanotify_mark 301 sys_fanotify_mark (int fanotify_fd, unsigned int flags, u64 mask, int dfd, const char *pathname) +__NR_fanotify_mark 301 sys_fanotify_mark (int fanotify_fd, unsigned int flags, uint64_t mask, int dfd, const char *pathname) __NR_open_by_handle_at 304 sys_open_by_handle_at (int mountdirfd, struct file_handle *handle, int flags) __NR_setns 308 sys_setns (int fd, int nstype) __NR_kcmp 312 sys_kcmp (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) diff --git a/compel/include/int.h b/compel/include/int.h deleted file mode 120000 index 5c118d596..000000000 --- a/compel/include/int.h +++ /dev/null @@ -1 +0,0 @@ -../../criu/include/asm-generic/int.h \ No newline at end of file diff --git a/compel/plugins/include/uapi/std/syscall-types.h b/compel/plugins/include/uapi/std/syscall-types.h index 3296153b3..645b1ba0e 100644 --- a/compel/plugins/include/uapi/std/syscall-types.h +++ b/compel/plugins/include/uapi/std/syscall-types.h @@ -10,21 +10,20 @@ #include #include #include +#include #include #include #include -#include "int.h" - struct cap_header { - u32 version; + uint32_t version; int pid; }; struct cap_data { - u32 eff; - u32 prm; - u32 inh; + uint32_t eff; + uint32_t prm; + uint32_t inh; }; struct robust_list_head; diff --git a/compel/plugins/std/std.c b/compel/plugins/std/std.c index ada3f09d2..705629f47 100644 --- a/compel/plugins/std/std.c +++ b/compel/plugins/std/std.c @@ -1,6 +1,5 @@ #include -#include "int.h" #include "uapi/plugins.h" #include "uapi/plugin-std.h" diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index c6b7874cc..32b715cd0 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -13,8 +14,6 @@ #include "uapi/compel.h" -#include "asm-generic/int.h" - #include "handle-elf.h" #include "piegen.h" @@ -147,7 +146,7 @@ int __handle_elf(void *mem, size_t size) size_t i, k, nr_gotpcrel = 0; #ifdef ELF_PPC64 - s64 toc_offset = 0; + int64_t toc_offset = 0; #endif int ret = -EINVAL; @@ -284,8 +283,8 @@ int __handle_elf(void *mem, size_t size) (unsigned)sh->sh_info, &secstrings[sh->sh_name]); for (k = 0; k < sh->sh_size / sh->sh_entsize; k++) { - s64 __maybe_unused addend64, __maybe_unused value64; - s32 __maybe_unused addend32, __maybe_unused value32; + int64_t __maybe_unused addend64, __maybe_unused value64; + int32_t __maybe_unused addend32, __maybe_unused value32; unsigned long place; const char *name; void *where; @@ -331,11 +330,11 @@ int __handle_elf(void *mem, size_t size) } if (sh->sh_type == SHT_REL) { - addend32 = *(s32 *)where; - addend64 = *(s64 *)where; + addend32 = *(int32_t *)where; + addend64 = *(int64_t *)where; } else { - addend32 = (s32)r->rela.r_addend; - addend64 = (s64)r->rela.r_addend; + addend32 = (int32_t)r->rela.r_addend; + addend64 = (int64_t)r->rela.r_addend; } place = sh_rel->sh_addr + r->rel.r_offset; @@ -344,8 +343,8 @@ int __handle_elf(void *mem, size_t size) (unsigned long)sym->st_value, addend32, (long)addend64, (long)place, name); if (sym->st_shndx == SHN_ABS) { - value32 = (s32)sym->st_value; - value64 = (s64)sym->st_value; + value32 = (int32_t)sym->st_value; + value64 = (int64_t)sym->st_value; } else { Elf_Shdr *sh_src; @@ -357,8 +356,8 @@ int __handle_elf(void *mem, size_t size) sh_src = sec_hdrs[sym->st_shndx]; ptr_func_exit(sh_src); - value32 = (s32)sh_src->sh_addr + (s32)sym->st_value; - value64 = (s64)sh_src->sh_addr + (s64)sym->st_value; + value32 = (int32_t)sh_src->sh_addr + (int32_t)sym->st_value; + value64 = (int64_t)sh_src->sh_addr + (int64_t)sym->st_value; } #ifdef ELF_PPC64 @@ -499,18 +498,18 @@ int __handle_elf(void *mem, size_t size) (unsigned int)place, (long)addend64, (long)value64); break; case R_X86_64_PC32: /* Symbol + Addend - Place (4 bytes) */ - pr_debug("\t\t\t\tR_X86_64_PC32 at 0x%-4lx val 0x%x\n", place, value32 + addend32 - (s32)place); + pr_debug("\t\t\t\tR_X86_64_PC32 at 0x%-4lx val 0x%x\n", place, value32 + addend32 - (int32_t)place); /* * R_X86_64_PC32 are relative, patch them inplace. */ - *((s32 *)where) = value32 + addend32 - place; + *((int32_t *)where) = value32 + addend32 - place; break; case R_X86_64_PLT32: /* ProcLinkage + Addend - Place (4 bytes) */ - pr_debug("\t\t\t\tR_X86_64_PLT32 at 0x%-4lx val 0x%x\n", place, value32 + addend32 - (s32)place); + pr_debug("\t\t\t\tR_X86_64_PLT32 at 0x%-4lx val 0x%x\n", place, value32 + addend32 - (int32_t)place); /* * R_X86_64_PLT32 are relative, patch them inplace. */ - *((s32 *)where) = value32 + addend32 - place; + *((int32_t *)where) = value32 + addend32 - place; break; case R_X86_64_GOTPCREL: /* SymbolOffsetInGot + GOT + Addend - Place (4 bytes) */ pr_debug("\t\t\t\tR_X86_64_GOTPCREL at 0x%-4lx val 0x%x\n", place, value32); @@ -529,11 +528,11 @@ int __handle_elf(void *mem, size_t size) (unsigned int)place, addend32, value32); break; case R_386_PC32: /* Symbol + Addend - Place */ - pr_debug("\t\t\t\tR_386_PC32 at 0x%-4lx val 0x%x\n", place, value32 + addend32 - (s32)place); + pr_debug("\t\t\t\tR_386_PC32 at 0x%-4lx val 0x%x\n", place, value32 + addend32 - (int32_t)place); /* * R_386_PC32 are relative, patch them inplace. */ - *((s32 *)where) = value32 + addend32 - place; + *((int32_t *)where) = value32 + addend32 - place; break; #endif From a714fff5a3d799cbf4d4f05fef8e7e095fb26443 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 27 Oct 2016 19:05:28 +0300 Subject: [PATCH 0182/4375] compel: Use common's compiler.h And drop compel/include symlink. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/include/compiler.h | 1 - compel/include/piegen.h | 3 ++- compel/plugins/fds/fds.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) delete mode 120000 compel/include/compiler.h diff --git a/compel/include/compiler.h b/compel/include/compiler.h deleted file mode 120000 index ef56d20f6..000000000 --- a/compel/include/compiler.h +++ /dev/null @@ -1 +0,0 @@ -../../criu/include/compiler.h \ No newline at end of file diff --git a/compel/include/piegen.h b/compel/include/piegen.h index f1ed2e13d..9789fa0a0 100644 --- a/compel/include/piegen.h +++ b/compel/include/piegen.h @@ -5,7 +5,8 @@ #include #include -#include "compiler.h" + +#include "common/compiler.h" typedef struct { char *input_filename; diff --git a/compel/plugins/fds/fds.c b/compel/plugins/fds/fds.c index fa739058f..a7966e5de 100644 --- a/compel/plugins/fds/fds.c +++ b/compel/plugins/fds/fds.c @@ -6,7 +6,7 @@ #include "std-priv.h" -#include "compiler.h" +#include "common/compiler.h" #define __sys(foo) sys_##foo #define __std(foo) std_##foo From a0810481e571a22bffe27120a9d73fb9b0d7f8d8 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 27 Oct 2016 19:01:21 +0300 Subject: [PATCH 0183/4375] compel: Include compel headers as system ones Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- Makefile.compel | 20 +++++++++++++------ compel/Makefile | 5 +++++ .../arm/plugins/std/syscalls/gen-syscalls.pl | 16 +++++++-------- .../plugins/std/syscalls/Makefile.syscalls | 6 +++--- .../plugins/std/syscalls/Makefile.syscalls | 12 +++++------ compel/include/uapi/plugins | 1 + compel/plugins/Makefile | 7 +++++++ .../plugins/include/uapi/std/syscall-types.h | 2 +- criu/Makefile | 5 ++--- criu/Makefile.crtools | 5 ++--- criu/arch/aarch64/Makefile | 4 ++-- criu/arch/aarch64/include/asm/types.h | 2 +- criu/arch/aarch64/infect.c | 2 +- criu/arch/aarch64/restorer.c | 2 +- criu/arch/aarch64/vdso-pie.c | 2 +- criu/arch/arm/Makefile | 5 +++-- criu/arch/arm/include/asm/types.h | 2 +- criu/arch/arm/infect.c | 2 +- criu/arch/arm/restorer.c | 2 +- criu/arch/ppc64/Makefile | 4 ++-- criu/arch/ppc64/include/asm/types.h | 2 +- criu/arch/ppc64/infect.c | 2 +- criu/arch/ppc64/restorer.c | 2 +- criu/arch/ppc64/vdso-pie.c | 2 +- criu/arch/x86/Makefile | 4 ++-- criu/arch/x86/crtools.c | 2 +- criu/arch/x86/include/asm/infect-types.h | 2 +- criu/arch/x86/include/asm/restorer.h | 2 +- criu/arch/x86/include/asm/types.h | 2 +- criu/arch/x86/infect.c | 4 ++-- criu/arch/x86/restorer.c | 2 +- criu/arch/x86/sigaction_compat.c | 2 +- criu/arch/x86/vdso-pie.c | 2 +- criu/cr-restore.c | 2 +- criu/fsnotify.c | 2 +- criu/include/infect.h | 2 +- criu/include/sigframe-common.h | 3 +-- criu/infect.c | 4 ++-- criu/kerndat.c | 2 +- criu/parasite-syscall.c | 2 +- criu/pie/Makefile | 5 ++--- criu/pie/Makefile.library | 4 ++-- criu/pie/log-simple.c | 2 +- criu/pie/parasite-vdso.c | 2 +- criu/pie/parasite.c | 2 +- criu/pie/pie-relocs.c | 2 +- criu/pie/pie-relocs.h | 2 +- criu/pie/restorer.c | 4 ++-- criu/pie/util-fd.c | 2 +- criu/pie/util.c | 2 +- criu/shmem.c | 2 +- include/common/lock.h | 2 +- 52 files changed, 101 insertions(+), 83 deletions(-) create mode 120000 compel/include/uapi/plugins diff --git a/Makefile.compel b/Makefile.compel index a5999581b..84d5c0769 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -26,30 +26,38 @@ $(SRC_DIR)/compel/include/asm: $(SRC_DIR)/compel/arch/$(ARCH)/src/lib/include $(Q) ln -s $^ $@ $(COMPEL_VERSION_HEADER): $(SRC_DIR)/compel/include/asm +compel-uapi-links += $(SRC_DIR)/compel/include/uapi/compel +compel-uapi-links += $(SRC_DIR)/compel/include/uapi/asm +compel-uapi-links += $(SRC_DIR)/compel/include/asm + +compel-deps += $(compel-uapi-links) +compel-deps += $(COMPEL_VERSION_HEADER) +compel-deps += $(CONFIG_HEADER) + # # Compel itself. -compel/%: $(COMPEL_VERSION_HEADER) $(CONFIG_HEADER) .FORCE +compel/%: $(compel-deps) .FORCE $(Q) $(MAKE) $(build)=compel $@ # # Plugins -compel/plugins/%: $(COMPEL_VERSION_HEADER) $(CONFIG_HEADER) .FORCE +compel/plugins/%: $(compel-deps) .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ # # GNU make 4.x supports targets matching via wide # match targeting, where GNU make 3.x series (used on # Travis) is not, so we have to write them here explicitly. -compel/plugins/std.built-in.o: $(COMPEL_VERSION_HEADER) .FORCE +compel/plugins/std.built-in.o: $(compel-deps) .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ -compel/plugins/shmem.built-in.o: $(COMPEL_VERSION_HEADER) .FORCE +compel/plugins/shmem.built-in.o: $(compel-deps) .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ -compel/plugins/fds.built-in.o: $(COMPEL_VERSION_HEADER) .FORCE +compel/plugins/fds.built-in.o: $(compel-deps) .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ -compel/compel: compel/built-in.o compel/lib.a $(COMPEL_VERSION_HEADER) +compel/compel: compel/built-in.o compel/lib.a | $(compel-deps) $(call msg-link, $@) $(Q) $(CC) $(CFLAGS) $^ $(WRAPFLAGS) $(LDFLAGS) -rdynamic -o $@ diff --git a/compel/Makefile b/compel/Makefile index 8fcfcff67..2cc11f7fb 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -9,6 +9,11 @@ ccflags-y += -iquote compel/include ccflags-y += -iquote compel/plugins/include ccflags-y += -fPIC +# +# UAPI inclusion, referred as +ccflags-y += -I compel/include/uapi +ccflags-y += -I compel/plugins/include/uapi + lib-y += arch/$(ARCH)/src/lib/handle-elf.o host-lib-y += arch/$(ARCH)/src/lib/handle-elf.o lib-y += src/lib/handle-elf.o diff --git a/compel/arch/arm/plugins/std/syscalls/gen-syscalls.pl b/compel/arch/arm/plugins/std/syscalls/gen-syscalls.pl index c683e4998..a0942114d 100755 --- a/compel/arch/arm/plugins/std/syscalls/gen-syscalls.pl +++ b/compel/arch/arm/plugins/std/syscalls/gen-syscalls.pl @@ -6,14 +6,14 @@ use warnings; my $in = $ARGV[0]; my $codesout = $ARGV[1]; my $codes = $ARGV[1]; -$codes =~ s/.*include\///g; +$codes =~ s/.*include\/uapi\//compel\/plugins\//g; my $protosout = $ARGV[2]; my $protos = $ARGV[2]; -$protos =~ s/.*include\///g; +$protos =~ s/.*include\/uapi\//compel\/plugins\//g; my $asmout = $ARGV[3]; my $asmcommon = $ARGV[4]; my $prototypes = $ARGV[5]; -$prototypes =~ s/.*include\///g; +$prototypes =~ s/.*include\/uapi\//compel\/plugins\//g; my $bits = $ARGV[6]; my $codesdef = $codes; @@ -42,13 +42,13 @@ print PROTOSOUT <<"END"; /* Autogenerated, don't edit */ #ifndef $protosdef #define $protosdef -#include "$prototypes" -#include "$codes" +#include <$prototypes> +#include <$codes> END print ASMOUT <<"END"; /* Autogenerated, don't edit */ -#include "$codes" +#include <$codes> #include "$asmcommon" END @@ -91,8 +91,8 @@ for () { } if ($need_aux == 1) { - print ASMOUT "#include \"uapi/std/syscall-aux.S\"\n"; - print CODESOUT "#include \"uapi/std/syscall-aux.h\"\n"; + print ASMOUT "#include \n"; + print CODESOUT "#include \n"; } print CODESOUT "#endif /* $codesdef */"; diff --git a/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls b/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls index 65299cb1e..3a0d172ae 100644 --- a/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls +++ b/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls @@ -29,15 +29,15 @@ $(sys-proto): $(sys-def) $(Q) echo "/* Autogenerated, don't edit */" > $@ $(Q) echo "#ifndef __ASM_CR_SYSCALL_PROTO_H__" >> $@ $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H__" >> $@ - $(Q) echo "#include \"uapi/std/syscall-codes.h\"" >> $@ - $(Q) echo "#include \"uapi/std/syscall-types.h\"" >> $@ + $(Q) echo "#include " >> $@ + $(Q) echo "#include " >> $@ $(Q) cat $< | awk '/^__NR/{print "extern long", $$3, substr($$0, index($$0,$$4)), ";"}' >> $@ $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H__ */" >> $@ $(sys-asm): $(sys-def) $(sys-asm-common) $(sys-codes) $(sys-proto) $(E) " GEN " $@ $(Q) echo "/* Autogenerated, don't edit */" > $@ - $(Q) echo "#include \"uapi/std/syscall-codes.h\"" >> $@ + $(Q) echo "#include " >> $@ $(Q) echo "#include \"$(sys-asm-common-name)\"" >> $@ $(Q) cat $< | awk '/^__NR/{print "SYSCALL(", $$3, ",", $$2, ")"}' >> $@ diff --git a/compel/arch/x86/plugins/std/syscalls/Makefile.syscalls b/compel/arch/x86/plugins/std/syscalls/Makefile.syscalls index 040d1e3b6..522ee89fd 100644 --- a/compel/arch/x86/plugins/std/syscalls/Makefile.syscalls +++ b/compel/arch/x86/plugins/std/syscalls/Makefile.syscalls @@ -39,8 +39,8 @@ $(sys-proto): $(sys-def) $(sys-proto-types) $(Q) echo "/* Autogenerated, don't edit */" > $$@ $(Q) echo "#ifndef ASM_SYSCALL_PROTO_H_$(1)__" >> $$@ $(Q) echo "#define ASM_SYSCALL_PROTO_H_$(1)__" >> $$@ - $(Q) echo '#include "uapi/std/syscall-codes-$(1).h"' >> $$@ - $(Q) echo '#include "uapi/std/syscall-types.h"' >> $$@ + $(Q) echo '#include ' >> $$@ + $(Q) echo '#include ' >> $$@ ifeq ($(1),32) $(Q) echo '#include "asm/syscall32.h"' >> $$@ endif @@ -53,7 +53,7 @@ define gen-rule-sys-asm $(sys-asm): $(sys-def) $(sys-asm-common) $(sys-codes) $(sys-proto) $(sys-proto-types) $(call msg-gen, $$@) $(Q) echo "/* Autogenerated, don't edit */" > $$@ - $(Q) echo '#include "uapi/std/syscall-codes-$(1).h"' >> $$@ + $(Q) echo '#include ' >> $$@ $(Q) echo '#include "$(sys-asm-common-name)"' >> $$@ $(Q) cat $$< | awk '/^__NR/{print "SYSCALL(", $(AV)3, ",", $(AV)2, ")"}' >> $$@ endef @@ -71,7 +71,7 @@ $(sys-codes-generic): $(PLUGIN_ARCH_DIR)/std/syscalls/syscall_32.tbl $(sys-proto $(Q) echo "/* Autogenerated, don't edit */" > $@ $(Q) echo "#ifndef __ASM_CR_SYSCALL_CODES_H__" >> $@ $(Q) echo "#define __ASM_CR_SYSCALL_CODES_H__" >> $@ - $(Q) echo '#include "uapi/std/syscall-codes-64.h"' >> $@ + $(Q) echo '#include ' >> $@ $(Q) cat $< | awk '/^__NR/{NR32=$$1; \ sub("^__NR", "__NR32", NR32); \ print "\n#ifndef ", NR32; \ @@ -87,9 +87,9 @@ $(sys-proto-generic): $(strip $(call map,sys-proto,$(sys-bits))) $(sys-proto-typ $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H__" >> $@ $(Q) echo "" >> $@ $(Q) echo "#ifdef CONFIG_X86_32" >> $@ - $(Q) echo '#include "uapi/std/syscall-32.h"' >> $@ + $(Q) echo '#include ' >> $@ $(Q) echo "#else" >> $@ - $(Q) echo '#include "uapi/std/syscall-64.h"' >> $@ + $(Q) echo '#include ' >> $@ $(Q) echo "#endif /* CONFIG_X86_32 */" >> $@ $(Q) echo "" >> $@ $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H__ */" >> $@ diff --git a/compel/include/uapi/plugins b/compel/include/uapi/plugins new file mode 120000 index 000000000..7ff4c6055 --- /dev/null +++ b/compel/include/uapi/plugins @@ -0,0 +1 @@ +../../plugins/include/uapi \ No newline at end of file diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index ac54f7c2e..dfbc812a5 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -6,6 +6,13 @@ PLUGIN_ARCH_DIR := compel/arch/$(ARCH)/plugins # # CFLAGS, ASFLAGS, LDFLAGS +# +# UAPI inclusion, referred as +ccflags-y += -I compel/include/uapi +ccflags-y += -I compel/plugins/include/uapi +asflags-y += -I compel/include/uapi +asflags-y += -I compel/plugins/include/uapi + # General compel includes ccflags-y += -iquote $(SRC_DIR)/compel/include ccflags-y += -fno-stack-protector diff --git a/compel/plugins/include/uapi/std/syscall-types.h b/compel/plugins/include/uapi/std/syscall-types.h index 645b1ba0e..119edb77e 100644 --- a/compel/plugins/include/uapi/std/syscall-types.h +++ b/compel/plugins/include/uapi/std/syscall-types.h @@ -51,6 +51,6 @@ struct krlimit { /* Type of timers in the kernel. */ typedef int kernel_timer_t; -#include "uapi/std/asm/syscall-types.h" +#include #endif /* COMPEL_SYSCALL_TYPES_H__ */ diff --git a/criu/Makefile b/criu/Makefile index 2b0989a57..35febd8e8 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -17,9 +17,8 @@ ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR) ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR)/include ccflags-y += -iquote $(SRC_DIR)/ ccflags-y += -I/usr/include/libnl3 -ccflags-y += -iquote compel/plugins/include -ccflags-y += -iquote compel/include -ccflags-y += -iquote compel/arch/$(ARCH)/plugins/std +ccflags-y += -I compel/include/uapi +ccflags-y += -I compel/plugins/include/uapi export ccflags-y diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 502f33133..278760b54 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -1,7 +1,6 @@ ccflags-y += -iquote criu/$(ARCH) -ccflags-y += -iquote compel/plugins/include -ccflags-y += -iquote compel/include -ccflags-y += -iquote compel/arch/$(ARCH)/plugins/std +ccflags-y += -I compel/include/uapi +ccflags-y += -I compel/plugins/include/uapi obj-y += infect.o obj-y += infect-rpc.o diff --git a/criu/arch/aarch64/Makefile b/criu/arch/aarch64/Makefile index 065a1fb75..e269de4c8 100644 --- a/criu/arch/aarch64/Makefile +++ b/criu/arch/aarch64/Makefile @@ -3,8 +3,8 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) ccflags-y += -iquote $(obj)/include -iquote $(SRC_DIR)/criu/include ccflags-y += -iquote $(SRC_DIR)/include -ccflags-y += -iquote $(SRC_DIR)/compel/plugins/include -ccflags-y += -iquote $(SRC_DIR)/compel/include +ccflags-y += -I compel/include/uapi +ccflags-y += -I compel/plugins/include/uapi asflags-y += -D__ASSEMBLY__ obj-y += cpu.o diff --git a/criu/arch/aarch64/include/asm/types.h b/criu/arch/aarch64/include/asm/types.h index 17353ac95..a84aea18e 100644 --- a/criu/arch/aarch64/include/asm/types.h +++ b/criu/arch/aarch64/include/asm/types.h @@ -10,7 +10,7 @@ #include "bitops.h" #include "asm/int.h" -#include "uapi/std/asm/syscall-types.h" +#include #define core_is_compat(core) false diff --git a/criu/arch/aarch64/infect.c b/criu/arch/aarch64/infect.c index 79f64d095..067e558e0 100644 --- a/criu/arch/aarch64/infect.c +++ b/criu/arch/aarch64/infect.c @@ -3,7 +3,7 @@ #include #include #include "asm/parasite-syscall.h" -#include "uapi/std/syscall-codes.h" +#include #include "asm/types.h" #include "criu-log.h" #include "kerndat.h" diff --git a/criu/arch/aarch64/restorer.c b/criu/arch/aarch64/restorer.c index 72c9c4a97..69f7dbe1e 100644 --- a/criu/arch/aarch64/restorer.c +++ b/criu/arch/aarch64/restorer.c @@ -3,7 +3,7 @@ #include "restorer.h" #include "asm/restorer.h" -#include "uapi/std/syscall.h" +#include #include "log.h" #include "asm/fpu.h" #include "cpu.h" diff --git a/criu/arch/aarch64/vdso-pie.c b/criu/arch/aarch64/vdso-pie.c index 8612b2622..55de8cb08 100644 --- a/criu/arch/aarch64/vdso-pie.c +++ b/criu/arch/aarch64/vdso-pie.c @@ -2,7 +2,7 @@ #include "asm/types.h" -#include "uapi/std/syscall.h" +#include #include "parasite-vdso.h" #include "log.h" #include "common/bug.h" diff --git a/criu/arch/arm/Makefile b/criu/arch/arm/Makefile index cb725c5d9..da513ebca 100644 --- a/criu/arch/arm/Makefile +++ b/criu/arch/arm/Makefile @@ -2,8 +2,9 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include -ccflags-y += -iquote $(SRC_DIR)/compel/plugins/include -ccflags-y += -iquote $(SRC_DIR)/compel/include + +ccflags-y += -I compel/include/uapi +ccflags-y += -I compel/plugins/include/uapi asflags-y += -D__ASSEMBLY__ diff --git a/criu/arch/arm/include/asm/types.h b/criu/arch/arm/include/asm/types.h index e4dfd2cf1..99543fa9e 100644 --- a/criu/arch/arm/include/asm/types.h +++ b/criu/arch/arm/include/asm/types.h @@ -9,7 +9,7 @@ #include "bitops.h" #include "asm/int.h" -#include "uapi/std/asm/syscall-types.h" +#include #define core_is_compat(core) false diff --git a/criu/arch/arm/infect.c b/criu/arch/arm/infect.c index 1ad01472f..357d4492b 100644 --- a/criu/arch/arm/infect.c +++ b/criu/arch/arm/infect.c @@ -1,7 +1,7 @@ #include #include #include "asm/parasite-syscall.h" -#include "uapi/std/syscall-codes.h" +#include #include "asm/types.h" #include "criu-log.h" #include "kerndat.h" diff --git a/criu/arch/arm/restorer.c b/criu/arch/arm/restorer.c index 8eb18a8ad..fe206e1a7 100644 --- a/criu/arch/arm/restorer.c +++ b/criu/arch/arm/restorer.c @@ -3,7 +3,7 @@ #include "restorer.h" #include "asm/restorer.h" -#include "uapi/std/syscall.h" +#include #include "log.h" #include "asm/fpu.h" #include "cpu.h" diff --git a/criu/arch/ppc64/Makefile b/criu/arch/ppc64/Makefile index abbb7ce66..cd7c41250 100644 --- a/criu/arch/ppc64/Makefile +++ b/criu/arch/ppc64/Makefile @@ -2,8 +2,8 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include -ccflags-y += -iquote $(SRC_DIR)/compel/plugins/include -ccflags-y += -iquote $(SRC_DIR)/compel/include +ccflags-y += -I compel/include/uapi +ccflags-y += -I compel/plugins/include/uapi obj-y += cpu.o obj-y += crtools.o diff --git a/criu/arch/ppc64/include/asm/types.h b/criu/arch/ppc64/include/asm/types.h index 25e2125b2..a23d50035 100644 --- a/criu/arch/ppc64/include/asm/types.h +++ b/criu/arch/ppc64/include/asm/types.h @@ -9,7 +9,7 @@ #include "bitops.h" #include "asm/int.h" -#include "uapi/std/asm/syscall-types.h" +#include typedef UserPpc64RegsEntry UserRegsEntry; diff --git a/criu/arch/ppc64/infect.c b/criu/arch/ppc64/infect.c index feefc1448..d9a356a5e 100644 --- a/criu/arch/ppc64/infect.c +++ b/criu/arch/ppc64/infect.c @@ -2,7 +2,7 @@ #include #include #include -#include "uapi/std/syscall-codes.h" +#include #include "asm/types.h" #include "ptrace.h" #include "parasite-syscall.h" diff --git a/criu/arch/ppc64/restorer.c b/criu/arch/ppc64/restorer.c index 3f0aff87a..4dda4bd16 100644 --- a/criu/arch/ppc64/restorer.c +++ b/criu/arch/ppc64/restorer.c @@ -4,7 +4,7 @@ #include "asm/restorer.h" #include "asm/fpu.h" -#include "uapi/std/syscall.h" +#include #include "log.h" int restore_nonsigframe_gpregs(UserPpc64RegsEntry *r) diff --git a/criu/arch/ppc64/vdso-pie.c b/criu/arch/ppc64/vdso-pie.c index fbca7f51a..2c46c1613 100644 --- a/criu/arch/ppc64/vdso-pie.c +++ b/criu/arch/ppc64/vdso-pie.c @@ -3,7 +3,7 @@ #include "asm/types.h" -#include "uapi/std/syscall.h" +#include #include "parasite-vdso.h" #include "log.h" #include "common/bug.h" diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index bffa3f52a..fcbb67129 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -2,8 +2,8 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include -ccflags-y += -iquote $(SRC_DIR)/compel/plugins/include -ccflags-y += -iquote $(SRC_DIR)/compel/include +ccflags-y += -I compel/include/uapi +ccflags-y += -I compel/plugins/include/uapi asflags-y += -Wstrict-prototypes -Wa,--noexecstack asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 01fcfed45..32508367d 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -19,7 +19,7 @@ #include "log.h" #include "util.h" #include "cpu.h" -#include "uapi/std/syscall-codes.h" +#include #include "kerndat.h" #include "infect.h" diff --git a/criu/arch/x86/include/asm/infect-types.h b/criu/arch/x86/include/asm/infect-types.h index 65fc3d997..bbc6bcf22 100644 --- a/criu/arch/x86/include/asm/infect-types.h +++ b/criu/arch/x86/include/asm/infect-types.h @@ -7,7 +7,7 @@ #include "log.h" #include "common/bug.h" #include "common/page.h" -#include "syscall-types.h" +#include #define SIGMAX 64 #define SIGMAX_OLD 31 diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index 43a1b6989..e70526089 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -4,7 +4,7 @@ #include "asm/types.h" #include "asm/fpu.h" #include "images/core.pb-c.h" -#include "uapi/std/syscall-codes.h" +#include #include "sigframe.h" diff --git a/criu/arch/x86/include/asm/types.h b/criu/arch/x86/include/asm/types.h index 84a29ec12..dbf284035 100644 --- a/criu/arch/x86/include/asm/types.h +++ b/criu/arch/x86/include/asm/types.h @@ -8,7 +8,7 @@ #include "bitops.h" #include "asm/int.h" -#include "uapi/std/asm/syscall-types.h" +#include #include "images/core.pb-c.h" diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index 10f319391..fe9d581bb 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -11,8 +11,8 @@ #include "compel/include/asm/processor-flags.h" #include "compel/include/errno.h" -#include "uapi/std/syscall-codes.h" -#include "compel/include/asm/syscall.h" +#include +#include #include "compel/include/asm/ptrace.h" #include "common/err.h" #include "asm/infect-types.h" diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index 052d91a67..01ed669e5 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -7,7 +7,7 @@ #include "asm/fpu.h" #include "asm/string.h" -#include "uapi/std/syscall.h" +#include #include "log.h" #include "cpu.h" diff --git a/criu/arch/x86/sigaction_compat.c b/criu/arch/x86/sigaction_compat.c index 214b2058b..af7234696 100644 --- a/criu/arch/x86/sigaction_compat.c +++ b/criu/arch/x86/sigaction_compat.c @@ -5,7 +5,7 @@ #include #ifdef CR_NOGLIBC -# include "uapi/std/syscall.h" +# include #else # define sys_mmap mmap # define sys_munmap munmap diff --git a/criu/arch/x86/vdso-pie.c b/criu/arch/x86/vdso-pie.c index 07652d2fd..990a2771f 100644 --- a/criu/arch/x86/vdso-pie.c +++ b/criu/arch/x86/vdso-pie.c @@ -3,7 +3,7 @@ #include "string.h" #include "asm/types.h" -#include "uapi/std/syscall.h" +#include #include "parasite-vdso.h" #include "log.h" #include "common/bug.h" diff --git a/criu/cr-restore.c b/criu/cr-restore.c index b9e9827ee..2ec4d0bcc 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -80,7 +80,7 @@ #include "parasite-syscall.h" #include "files-reg.h" -#include "uapi/std/syscall-codes.h" +#include #include "compel/include/asm/syscall.h" #include "protobuf.h" diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 9a591a625..0dcb07c7c 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -41,7 +41,7 @@ #include "namespaces.h" #include "pstree.h" #include "fault-injection.h" -#include "uapi/std/syscall-codes.h" +#include #include "protobuf.h" #include "images/fsnotify.pb-c.h" diff --git a/criu/include/infect.h b/criu/include/infect.h index f1692c29d..2db90e618 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -2,7 +2,7 @@ #define __COMPEL_INFECT_H__ #include "asm/infect-types.h" -#include "compel/include/uapi/ksigset.h" +#include #define PARASITE_START_AREA_MIN (4096) diff --git a/criu/include/sigframe-common.h b/criu/include/sigframe-common.h index a714467dc..0796bb374 100644 --- a/criu/include/sigframe-common.h +++ b/criu/include/sigframe-common.h @@ -9,8 +9,7 @@ #endif #include -#include "syscall-types.h" -#include "asm/types.h" +#include struct rt_sigframe; diff --git a/criu/infect.c b/criu/infect.c index 1f1a5c59a..bea009e85 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -16,8 +16,8 @@ #include "common/xmalloc.h" #include "lock.h" -#include "uapi/std/syscall-codes.h" -#include "uapi/std/asm/syscall-types.h" +#include +#include #include "compel/include/asm/ptrace.h" #include "compel/include/asm/syscall.h" #include "asm/sigframe.h" diff --git a/criu/kerndat.c b/criu/kerndat.c index f3c654a39..9f7eb0fd7 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -27,7 +27,7 @@ #include "proc_parse.h" #include "config.h" #include "sk-inet.h" -#include "uapi/std/syscall-codes.h" +#include struct kerndat_s kdat = { }; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 0a8d6fe68..3bec47554 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -29,7 +29,7 @@ #include "proc_parse.h" #include "aio.h" #include "fault-injection.h" -#include "uapi/std/syscall-codes.h" +#include #include "signal.h" #include "sigframe.h" diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 040a68cd0..0c764170f 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -46,7 +46,6 @@ target += $(parasite_target) restorer # CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) CFLAGS := $(filter-out -DCONFIG_X86_64,$(CFLAGS)) -CFLAGS += -iquote $(SRC_DIR)/compel/include CFLAGS += -iquote $(SRC_DIR)/criu/arch/$(ARCH)/include CFLAGS += -iquote $(SRC_DIR)/criu/include CFLAGS += -iquote $(SRC_DIR)/include @@ -54,8 +53,8 @@ CFLAGS += -iquote $(SRC_DIR) CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 -ccflags-y += -iquote $(SRC_DIR)/compel/plugins/include -ccflags-y += -iquote $(SRC_DIR)/compel/include +ccflags-y += -I compel/include/uapi +ccflags-y += -I compel/plugins/include/uapi ccflags-y += -DCR_NOGLIBC ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) NATIVE_CFLAGS := $(shell $(SRC_DIR)/compel/compel-host --arch=$(ARCH) cflags) diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 1b408d14c..a76ee4b35 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -61,8 +61,8 @@ iquotes += -iquote $(SRC_DIR)/$(ARCH_DIR)/include iquotes += -iquote $(SRC_DIR) -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) $(iquotes) asflags-y := -D__ASSEMBLY__ $(iquotes) -ccflags-y += -iquote $(SRC_DIR)/compel/plugins/include -ccflags-y += -iquote $(SRC_DIR)/compel/include +ccflags-y += -I compel/plugins/include/uapi +ccflags-y += -I compel/include/uapi ifeq ($(SRCARCH),arm) ccflags-y += -marm diff --git a/criu/pie/log-simple.c b/criu/pie/log-simple.c index 3f8a73623..f54bb0133 100644 --- a/criu/pie/log-simple.c +++ b/criu/pie/log-simple.c @@ -4,7 +4,7 @@ #include "types.h" #include "string.h" #include "common/bitsperlong.h" -#include "uapi/std/syscall.h" +#include #include "log.h" struct simple_buf { diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 7914de6f6..601c37f68 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -12,7 +12,7 @@ #include "int.h" #include "types.h" #include "page.h" -#include "uapi/std/syscall.h" +#include #include "image.h" #include "parasite-vdso.h" #include "vma.h" diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index 66dd6cd2f..8e1fdf8d4 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -9,7 +9,7 @@ #include "int.h" #include "types.h" -#include "uapi/std/syscall.h" +#include #include "parasite.h" #include "config.h" #include "fcntl.h" diff --git a/criu/pie/pie-relocs.c b/criu/pie/pie-relocs.c index eac507b55..f0802a0a2 100644 --- a/criu/pie/pie-relocs.c +++ b/criu/pie/pie-relocs.c @@ -17,7 +17,7 @@ #include "log.h" #include "common/compiler.h" -#include "compel/include/uapi/compel.h" +#include #include "common/bug.h" __maybe_unused void elf_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *elf_relocs, size_t nr_relocs) diff --git a/criu/pie/pie-relocs.h b/criu/pie/pie-relocs.h index 1cabfe1d9..2fc5f6a33 100644 --- a/criu/pie/pie-relocs.h +++ b/criu/pie/pie-relocs.h @@ -1,7 +1,7 @@ #ifndef __PIE_RELOCS_H__ #define __PIE_RELOCS_H__ -#include "compel/include/uapi/compel.h" +#include #include "common/compiler.h" #include "config.h" diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 884749f3b..edcc1934e 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -21,8 +21,8 @@ #include "types.h" #include "common/compiler.h" #include "string.h" -#include "uapi/std/syscall.h" -#include "uapi/ksigset.h" +#include +#include #include "signal.h" #include "config.h" #include "prctl.h" diff --git a/criu/pie/util-fd.c b/criu/pie/util-fd.c index 0e6291f9d..df7daea6f 100644 --- a/criu/pie/util-fd.c +++ b/criu/pie/util-fd.c @@ -11,7 +11,7 @@ #include "string.h" #ifdef CR_NOGLIBC -# include "uapi/std/syscall.h" +# include # define __sys(foo) sys_##foo # define __sys_err(ret) ret #else diff --git a/criu/pie/util.c b/criu/pie/util.c index ed2949745..4945483f6 100644 --- a/criu/pie/util.c +++ b/criu/pie/util.c @@ -13,7 +13,7 @@ #include "util-pie.h" #ifdef CR_NOGLIBC -# include "uapi/std/syscall.h" +# include # define __sys(foo) sys_##foo #else # define __sys(foo) foo diff --git a/criu/shmem.c b/criu/shmem.c index 997c20f36..a0821413d 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -16,7 +16,7 @@ #include "vma.h" #include "mem.h" #include "config.h" -#include "uapi/std/syscall-codes.h" +#include #include "bitops.h" #include "log.h" #include "types.h" diff --git a/include/common/lock.h b/include/common/lock.h index bcd1145f0..4782b638f 100644 --- a/include/common/lock.h +++ b/include/common/lock.h @@ -15,7 +15,7 @@ #define LOCK_BUG() LOCK_BUG_ON(1) #ifdef CR_NOGLIBC -# include "uapi/std/syscall.h" +# include #else # include # include From 5f6c28567ad40cecde34aac33e8d37849b861f9b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 25 Oct 2016 12:39:16 +0300 Subject: [PATCH 0184/4375] compel: Rename shipped library to libcompel.a Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- Makefile.compel | 4 ++-- compel/Makefile | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile.compel b/Makefile.compel index 84d5c0769..885665011 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -57,7 +57,7 @@ compel/plugins/shmem.built-in.o: $(compel-deps) .FORCE compel/plugins/fds.built-in.o: $(compel-deps) .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ -compel/compel: compel/built-in.o compel/lib.a | $(compel-deps) +compel/compel: compel/built-in.o compel/libcompel.a | $(compel-deps) $(call msg-link, $@) $(Q) $(CC) $(CFLAGS) $^ $(WRAPFLAGS) $(LDFLAGS) -rdynamic -o $@ @@ -65,6 +65,6 @@ compel/compel: compel/built-in.o compel/lib.a | $(compel-deps) # And compel library. LIBCOMPEL_SO := libcompel.so LIBCOMPEL_SO_CFLAGS += $(CFLAGS) -rdynamic -Wl,-soname,$(LIBCOMPEL_SO).$(COMPEL_SO_VERSION_MAJOR) -compel/$(LIBCOMPEL_SO): compel/lib.a +compel/$(LIBCOMPEL_SO): compel/libcompel.a $(call msg-link, $@) $(Q) $(CC) -shared $(LIBCOMPEL_SO_CFLAGS) -o $@ -Wl,--whole-archive $^ -Wl,--no-whole-archive $(LDFLAGS) diff --git a/compel/Makefile b/compel/Makefile index 2cc11f7fb..71e646ce8 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -14,6 +14,7 @@ ccflags-y += -fPIC ccflags-y += -I compel/include/uapi ccflags-y += -I compel/plugins/include/uapi +lib-name := libcompel.a lib-y += arch/$(ARCH)/src/lib/handle-elf.o host-lib-y += arch/$(ARCH)/src/lib/handle-elf.o lib-y += src/lib/handle-elf.o From 1a30731b1fbc53a1f9a5aa056cab10bcf6594c3b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 18 Oct 2016 20:58:26 +0300 Subject: [PATCH 0185/4375] compel: Add callback-based log engine pr_out is only special left in piegen engine, the rest use compel's pr_x output. Probably we will need to enhance it one day to make same close to what we have in criu. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/Makefile | 2 + compel/arch/aarch64/src/lib/handle-elf.c | 1 + compel/arch/arm/src/lib/handle-elf.c | 1 + compel/arch/ppc64/src/lib/handle-elf.c | 1 + compel/arch/x86/src/lib/handle-elf.c | 1 + compel/include/log.h | 61 ++++++++++++++++++++++++ compel/include/piegen.h | 23 --------- compel/include/uapi/compel.h | 8 ++++ compel/include/uapi/loglevels.h | 13 +++++ compel/src/lib/handle-elf.c | 1 + compel/src/lib/log-host.c | 1 + compel/src/lib/log.c | 38 +++++++++++++++ compel/src/main.c | 20 ++++++-- 13 files changed, 144 insertions(+), 27 deletions(-) create mode 100644 compel/include/log.h create mode 100644 compel/include/uapi/loglevels.h create mode 120000 compel/src/lib/log-host.c create mode 100644 compel/src/lib/log.c diff --git a/compel/Makefile b/compel/Makefile index 71e646ce8..f47d48805 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -19,6 +19,8 @@ lib-y += arch/$(ARCH)/src/lib/handle-elf.o host-lib-y += arch/$(ARCH)/src/lib/handle-elf.o lib-y += src/lib/handle-elf.o host-lib-y += src/lib/handle-elf.o +lib-y += src/lib/log.o +host-lib-y += src/lib/log.o ifeq ($(ARCH),x86) lib-y += src/lib/handle-elf-32.o diff --git a/compel/arch/aarch64/src/lib/handle-elf.c b/compel/arch/aarch64/src/lib/handle-elf.c index 633a382cc..1c3686c48 100644 --- a/compel/arch/aarch64/src/lib/handle-elf.c +++ b/compel/arch/aarch64/src/lib/handle-elf.c @@ -4,6 +4,7 @@ #include "handle-elf.h" #include "piegen.h" +#include "log.h" static const unsigned char __maybe_unused elf_ident_64_le[EI_NIDENT] = { diff --git a/compel/arch/arm/src/lib/handle-elf.c b/compel/arch/arm/src/lib/handle-elf.c index e2df0f90d..8abf8dad1 100644 --- a/compel/arch/arm/src/lib/handle-elf.c +++ b/compel/arch/arm/src/lib/handle-elf.c @@ -4,6 +4,7 @@ #include "handle-elf.h" #include "piegen.h" +#include "log.h" static const unsigned char __maybe_unused elf_ident_32[EI_NIDENT] = { diff --git a/compel/arch/ppc64/src/lib/handle-elf.c b/compel/arch/ppc64/src/lib/handle-elf.c index 6491f2085..3d4020f59 100644 --- a/compel/arch/ppc64/src/lib/handle-elf.c +++ b/compel/arch/ppc64/src/lib/handle-elf.c @@ -4,6 +4,7 @@ #include "handle-elf.h" #include "piegen.h" +#include "log.h" static const unsigned char __maybe_unused elf_ident_64_le[EI_NIDENT] = { diff --git a/compel/arch/x86/src/lib/handle-elf.c b/compel/arch/x86/src/lib/handle-elf.c index 7cfbaa1dd..38e27abd3 100644 --- a/compel/arch/x86/src/lib/handle-elf.c +++ b/compel/arch/x86/src/lib/handle-elf.c @@ -4,6 +4,7 @@ #include "handle-elf.h" #include "piegen.h" +#include "log.h" static const unsigned char __maybe_unused elf_ident_64_le[EI_NIDENT] = { diff --git a/compel/include/log.h b/compel/include/log.h new file mode 100644 index 000000000..4619e8ab4 --- /dev/null +++ b/compel/include/log.h @@ -0,0 +1,61 @@ +#ifndef COMPEL_LOG_H__ +#define COMPEL_LOG_H__ + +#include "uapi/compel/compel.h" +#include "uapi/compel/loglevels.h" + +#ifndef LOG_PREFIX +# define LOG_PREFIX +#endif + +static inline int pr_quelled(unsigned int loglevel) +{ + return compel_log_get_loglevel() < loglevel && loglevel != LOG_MSG; +} + +extern void compel_print_on_level(unsigned int loglevel, const char *format, ...); + +#define pr_msg(fmt, ...) \ + compel_print_on_level(LOG_MSG, \ + fmt, ##__VA_ARGS__) + +#define pr_info(fmt, ...) \ + compel_print_on_level(LOG_INFO, \ + LOG_PREFIX fmt, ##__VA_ARGS__) + +#define pr_err(fmt, ...) \ + compel_print_on_level(LOG_ERROR, \ + "Error (%s:%d): " LOG_PREFIX fmt, \ + __FILE__, __LINE__, ##__VA_ARGS__) + +#define pr_err_once(fmt, ...) \ + do { \ + static bool __printed; \ + if (!__printed) { \ + pr_err(fmt, ##__VA_ARGS__); \ + __printed = 1; \ + } \ + } while (0) + +#define pr_warn(fmt, ...) \ + compel_print_on_level(LOG_WARN, \ + "Warn (%s:%d): " LOG_PREFIX fmt, \ + __FILE__, __LINE__, ##__VA_ARGS__) + +#define pr_warn_once(fmt, ...) \ + do { \ + static bool __printed; \ + if (!__printed) { \ + pr_warn(fmt, ##__VA_ARGS__); \ + __printed = 1; \ + } \ + } while (0) + +#define pr_debug(fmt, ...) \ + compel_print_on_level(LOG_DEBUG, \ + LOG_PREFIX fmt, ##__VA_ARGS__) + +#define pr_perror(fmt, ...) \ + pr_err(fmt ": %m\n", ##__VA_ARGS__) + +#endif /* COMPEL_LOG_H__ */ diff --git a/compel/include/piegen.h b/compel/include/piegen.h index 9789fa0a0..d240cd642 100644 --- a/compel/include/piegen.h +++ b/compel/include/piegen.h @@ -17,8 +17,6 @@ typedef struct { char *var_name; char *nrgotpcrel_name; FILE *fout; - FILE *ferr; - FILE *fdebug; } piegen_opt_t; extern piegen_opt_t opts; @@ -29,27 +27,6 @@ do { \ fprintf(opts.fout, fmt, ##__VA_ARGS__); \ } while (0) -#define pr_debug(fmt, ...) \ -do { \ - if (opts.fdebug) \ - fprintf(opts.fdebug, "%s: "fmt, \ - opts.stream_name, ##__VA_ARGS__); \ -} while (0) - -#define pr_err(fmt, ...) \ -do { \ - if (opts.ferr) \ - fprintf(opts.ferr, "%s: Error (%s:%d): "fmt, \ - opts.stream_name, __FILE__, __LINE__, ##__VA_ARGS__); \ -} while (0) - -#define pr_perror(fmt, ...) \ -do { \ - if (opts.ferr) \ - fprintf(opts.ferr, "%s: Error (%s:%d): "fmt ": %m\n", \ - opts.stream_name, __FILE__, __LINE__, ##__VA_ARGS__); \ -} while (0) - extern int handle_binary(void *mem, size_t size); #endif /* COMPEL_PIEGEN_H__ */ diff --git a/compel/include/uapi/compel.h b/compel/include/uapi/compel.h index 10507ce3f..278a85455 100644 --- a/compel/include/uapi/compel.h +++ b/compel/include/uapi/compel.h @@ -2,6 +2,7 @@ #define UAPI_COMPEL_H__ #include +#include #define COMPEL_TYPE_INT (1u << 0) #define COMPEL_TYPE_LONG (1u << 1) @@ -14,4 +15,11 @@ typedef struct { long value; } compel_reloc_t; +/* + * Logging + */ +typedef void (*compel_log_fn)(unsigned int lvl, const char *fmt, va_list parms); +extern void compel_log_init(compel_log_fn log_fn, unsigned int level); +extern unsigned int compel_log_get_loglevel(void); + #endif /* UAPI_COMPEL_H__ */ diff --git a/compel/include/uapi/loglevels.h b/compel/include/uapi/loglevels.h new file mode 100644 index 000000000..f7cdcc448 --- /dev/null +++ b/compel/include/uapi/loglevels.h @@ -0,0 +1,13 @@ +#ifndef UAPI_COMPEL_LOGLEVELS_H__ +#define UAPI_COMPEL_LOGLEVELS_H__ + +#define LOG_UNSET (-1) +#define LOG_MSG (0) /* Print message regardless of log level */ +#define LOG_ERROR (1) /* Errors only, when we're in trouble */ +#define LOG_WARN (2) /* Warnings, dazen and confused but trying to continue */ +#define LOG_INFO (3) /* Informative, everything is fine */ +#define LOG_DEBUG (4) /* Debug only */ + +#define DEFAULT_LOGLEVEL LOG_WARN + +#endif /* UAPI_COMPEL_LOGLEVELS_H__ */ diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index 32b715cd0..ec41771db 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -16,6 +16,7 @@ #include "handle-elf.h" #include "piegen.h" +#include "log.h" /* Check if pointer is out-of-bound */ static bool __ptr_oob(const uintptr_t ptr, const uintptr_t start, const size_t size) diff --git a/compel/src/lib/log-host.c b/compel/src/lib/log-host.c new file mode 120000 index 000000000..918e3d32f --- /dev/null +++ b/compel/src/lib/log-host.c @@ -0,0 +1 @@ +log.c \ No newline at end of file diff --git a/compel/src/lib/log.c b/compel/src/lib/log.c new file mode 100644 index 000000000..4c98407c6 --- /dev/null +++ b/compel/src/lib/log.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "log.h" + +static unsigned int current_loglevel = DEFAULT_LOGLEVEL; +static compel_log_fn logfn; + +void compel_log_init(compel_log_fn log_fn, unsigned int level) +{ + logfn = log_fn; + current_loglevel = level; +} + +unsigned int compel_log_get_loglevel(void) +{ + return current_loglevel; +} + +void compel_print_on_level(unsigned int loglevel, const char *format, ...) +{ + va_list params; + compel_log_fn fn = logfn; + + if (fn != NULL && !pr_quelled(loglevel)) { + va_start(params, format); + fn(loglevel, format, params); + va_end(params); + } +} diff --git a/compel/src/main.c b/compel/src/main.c index 625ae1188..643b6a96c 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -12,8 +12,11 @@ #include #include +#include "uapi/compel/compel.h" + #include "version.h" #include "piegen.h" +#include "log.h" #define CFLAGS_DEFAULT_SET \ "-Wstrict-prototypes " \ @@ -81,15 +84,19 @@ err: return ret; } +static void cli_log(unsigned int lvl, const char *fmt, va_list parms) +{ + if (!pr_quelled(lvl)) + vprintf(fmt, parms); +} + int main(int argc, char *argv[]) { const char *current_cflags = NULL; + int log_level = DEFAULT_LOGLEVEL; int opt, idx, i; char *action; - opts.fdebug = stdout; - opts.ferr = stderr; - typedef struct { const char *arch; const char *cflags; @@ -114,7 +121,7 @@ int main(int argc, char *argv[]) }, }; - static const char short_opts[] = "a:f:o:s:p:v:r:u:hV"; + static const char short_opts[] = "a:f:o:s:p:v:r:u:hVl:"; static struct option long_opts[] = { { "arch", required_argument, 0, 'a' }, { "file", required_argument, 0, 'f' }, @@ -126,6 +133,7 @@ int main(int argc, char *argv[]) { "pcrelocs", required_argument, 0, 'r' }, { "help", required_argument, 0, 'h' }, { "version", no_argument, 0, 'V' }, + { "log-level", required_argument, 0, 'l' }, { }, }; @@ -170,6 +178,9 @@ int main(int argc, char *argv[]) case 'r': opts.nrgotpcrel_name = optarg; break; + case 'l': + break; + log_level = atoi(optarg); case 'h': goto usage; case 'V': @@ -204,6 +215,7 @@ int main(int argc, char *argv[]) if (!strcmp(action, "piegen")) { if (!opts.input_filename) goto usage; + compel_log_init(&cli_log, log_level); return piegen(); } From aabb45becec8b443ef3971cd65e70f77bcbb5ca6 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 19 Oct 2016 14:06:56 +0300 Subject: [PATCH 0186/4375] compel: Move cpu interface to compel We will need it when parasite engine will be creating signal frames. Export appropriate headers and use it in CRIU by linking with libcompel.a. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- Makefile | 4 +- Makefile.compel | 1 + compel/Makefile | 2 + compel/arch/aarch64/src/lib/cpu.c | 28 +++ .../aarch64/src/lib/include/uapi/asm/cpu.h | 6 + .../lib/include/uapi/asm/processor-flags.h | 4 + compel/arch/arm/src/lib/cpu.c | 28 +++ .../arch/arm/src/lib/include/uapi/asm/cpu.h | 6 + .../include/{ => uapi/asm}/processor-flags.h | 0 compel/arch/ppc64/src/lib/cpu.c | 42 ++++ .../arch/ppc64/src/lib/include/uapi/asm/cpu.h | 10 + .../lib/include/uapi/asm/processor-flags.h | 4 + .../src/lib/include/uapi/asm/processor.h | 4 + compel/arch/x86/src/lib/cpu.c | 189 ++++++++++++++++++ .../arch/x86/src/lib/include/uapi}/asm/cpu.h | 25 +-- .../include/{ => uapi/asm}/processor-flags.h | 0 compel/include/uapi/cpu.h | 14 ++ criu/Makefile | 1 + criu/arch/aarch64/cpu.c | 5 - criu/arch/aarch64/crtools.c | 2 + criu/arch/aarch64/include/asm/cpu.h | 1 - criu/arch/arm/cpu.c | 5 - criu/arch/arm/crtools.c | 2 + criu/arch/arm/include/asm/cpu.h | 1 - criu/arch/ppc64/cpu.c | 17 +- criu/arch/ppc64/include/asm/cpu.h | 1 - criu/arch/x86/cpu.c | 175 +--------------- criu/arch/x86/infect.c | 3 +- criu/include/cpu.h | 3 +- 29 files changed, 365 insertions(+), 218 deletions(-) create mode 100644 compel/arch/aarch64/src/lib/cpu.c create mode 100644 compel/arch/aarch64/src/lib/include/uapi/asm/cpu.h create mode 100644 compel/arch/aarch64/src/lib/include/uapi/asm/processor-flags.h create mode 100644 compel/arch/arm/src/lib/cpu.c create mode 100644 compel/arch/arm/src/lib/include/uapi/asm/cpu.h rename compel/arch/arm/src/lib/include/{ => uapi/asm}/processor-flags.h (100%) create mode 100644 compel/arch/ppc64/src/lib/cpu.c create mode 100644 compel/arch/ppc64/src/lib/include/uapi/asm/cpu.h create mode 100644 compel/arch/ppc64/src/lib/include/uapi/asm/processor-flags.h create mode 100644 compel/arch/ppc64/src/lib/include/uapi/asm/processor.h create mode 100644 compel/arch/x86/src/lib/cpu.c rename {criu/arch/x86/include => compel/arch/x86/src/lib/include/uapi}/asm/cpu.h (95%) rename compel/arch/x86/src/lib/include/{ => uapi/asm}/processor-flags.h (100%) create mode 100644 compel/include/uapi/cpu.h delete mode 100644 criu/arch/aarch64/include/asm/cpu.h delete mode 100644 criu/arch/arm/include/asm/cpu.h delete mode 100644 criu/arch/ppc64/include/asm/cpu.h diff --git a/Makefile b/Makefile index 0db379099..ea76a1246 100644 --- a/Makefile +++ b/Makefile @@ -228,9 +228,9 @@ $(SOCCR_A): |soccr/built-in.o # # But note that we're already included # the nmk so we can reuse it there. -criu/%: images/built-in.o compel/plugins/std.built-in.o compel/compel-host $(VERSION_HEADER) .FORCE +criu/%: images/built-in.o compel/plugins/std.built-in.o compel/libcompel.a compel/compel-host $(VERSION_HEADER) .FORCE $(Q) $(MAKE) $(build)=criu $@ -criu: images/built-in.o compel/plugins/std.built-in.o compel/compel-host $(SOCCR_A) $(VERSION_HEADER) +criu: images/built-in.o compel/plugins/std.built-in.o compel/libcompel.a compel/compel-host $(SOCCR_A) $(VERSION_HEADER) $(Q) $(MAKE) $(build)=criu all .PHONY: criu diff --git a/Makefile.compel b/Makefile.compel index 885665011..366f604e9 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -33,6 +33,7 @@ compel-uapi-links += $(SRC_DIR)/compel/include/asm compel-deps += $(compel-uapi-links) compel-deps += $(COMPEL_VERSION_HEADER) compel-deps += $(CONFIG_HEADER) +compel-deps += include/common/asm # # Compel itself. diff --git a/compel/Makefile b/compel/Makefile index f47d48805..d421bc078 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -22,6 +22,8 @@ host-lib-y += src/lib/handle-elf.o lib-y += src/lib/log.o host-lib-y += src/lib/log.o +lib-y += arch/$(ARCH)/src/lib/cpu.o + ifeq ($(ARCH),x86) lib-y += src/lib/handle-elf-32.o host-lib-y += src/lib/handle-elf-32.o diff --git a/compel/arch/aarch64/src/lib/cpu.c b/compel/arch/aarch64/src/lib/cpu.c new file mode 100644 index 000000000..9e5d0d7fe --- /dev/null +++ b/compel/arch/aarch64/src/lib/cpu.c @@ -0,0 +1,28 @@ +#include +#include + +#include "uapi/compel/cpu.h" + +#include "common/bitops.h" + +#include "log.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "cpu: " + +static compel_cpuinfo_t rt_info; +static bool rt_info_done = false; + +void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } +void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } +int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } +int compel_cpuid(compel_cpuinfo_t *info) { return 0; } + +bool cpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_cpu_cap(&rt_info, feature); +} diff --git a/compel/arch/aarch64/src/lib/include/uapi/asm/cpu.h b/compel/arch/aarch64/src/lib/include/uapi/asm/cpu.h new file mode 100644 index 000000000..c35460e15 --- /dev/null +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/cpu.h @@ -0,0 +1,6 @@ +#ifndef UAPI_COMPEL_ASM_CPU_H__ +#define UAPI_COMPEL_ASM_CPU_H__ + +typedef struct { } compel_cpuinfo_t; + +#endif /* UAPI_COMPEL_ASM_CPU_H__ */ diff --git a/compel/arch/aarch64/src/lib/include/uapi/asm/processor-flags.h b/compel/arch/aarch64/src/lib/include/uapi/asm/processor-flags.h new file mode 100644 index 000000000..15719184a --- /dev/null +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/processor-flags.h @@ -0,0 +1,4 @@ +#ifndef UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ +#define UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ + +#endif /* UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ */ diff --git a/compel/arch/arm/src/lib/cpu.c b/compel/arch/arm/src/lib/cpu.c new file mode 100644 index 000000000..9e5d0d7fe --- /dev/null +++ b/compel/arch/arm/src/lib/cpu.c @@ -0,0 +1,28 @@ +#include +#include + +#include "uapi/compel/cpu.h" + +#include "common/bitops.h" + +#include "log.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "cpu: " + +static compel_cpuinfo_t rt_info; +static bool rt_info_done = false; + +void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } +void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } +int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } +int compel_cpuid(compel_cpuinfo_t *info) { return 0; } + +bool cpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_cpu_cap(&rt_info, feature); +} diff --git a/compel/arch/arm/src/lib/include/uapi/asm/cpu.h b/compel/arch/arm/src/lib/include/uapi/asm/cpu.h new file mode 100644 index 000000000..c35460e15 --- /dev/null +++ b/compel/arch/arm/src/lib/include/uapi/asm/cpu.h @@ -0,0 +1,6 @@ +#ifndef UAPI_COMPEL_ASM_CPU_H__ +#define UAPI_COMPEL_ASM_CPU_H__ + +typedef struct { } compel_cpuinfo_t; + +#endif /* UAPI_COMPEL_ASM_CPU_H__ */ diff --git a/compel/arch/arm/src/lib/include/processor-flags.h b/compel/arch/arm/src/lib/include/uapi/asm/processor-flags.h similarity index 100% rename from compel/arch/arm/src/lib/include/processor-flags.h rename to compel/arch/arm/src/lib/include/uapi/asm/processor-flags.h diff --git a/compel/arch/ppc64/src/lib/cpu.c b/compel/arch/ppc64/src/lib/cpu.c new file mode 100644 index 000000000..e324b80f9 --- /dev/null +++ b/compel/arch/ppc64/src/lib/cpu.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +#include "uapi/compel/cpu.h" + +#include "common/bitops.h" + +#include "log.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "cpu: " + +static compel_cpuinfo_t rt_info; +static bool rt_info_done = false; + +void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } +void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } +int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } + +int compel_cpuid(compel_cpuinfo_t *info) +{ + info->hwcap[0] = getauxval(AT_HWCAP); + info->hwcap[1] = getauxval(AT_HWCAP2); + + if (!info->hwcap[0] || !info->hwcap[1]) { + pr_err("Can't read the hardware capabilities"); + return -1; + } + + return 0; +} + +bool cpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_cpu_cap(&rt_info, feature); +} diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/cpu.h b/compel/arch/ppc64/src/lib/include/uapi/asm/cpu.h new file mode 100644 index 000000000..59925868c --- /dev/null +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/cpu.h @@ -0,0 +1,10 @@ +#ifndef UAPI_COMPEL_ASM_CPU_H__ +#define UAPI_COMPEL_ASM_CPU_H__ + +#include + +typedef struct { + uint64_t hwcap[2]; +} compel_cpuinfo_t; + +#endif /* UAPI_COMPEL_ASM_CPU_H__ */ diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/processor-flags.h b/compel/arch/ppc64/src/lib/include/uapi/asm/processor-flags.h new file mode 100644 index 000000000..15719184a --- /dev/null +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/processor-flags.h @@ -0,0 +1,4 @@ +#ifndef UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ +#define UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ + +#endif /* UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ */ diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/processor.h b/compel/arch/ppc64/src/lib/include/uapi/asm/processor.h new file mode 100644 index 000000000..7376f8879 --- /dev/null +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/processor.h @@ -0,0 +1,4 @@ +#ifndef UAPI_COMPEL_ASM_PROCESSOR_H__ +#define UAPI_COMPEL_ASM_PROCESSOR_H__ + +#endif /* UAPI_COMPEL_ASM_PROCESSOR_H__ */ diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c new file mode 100644 index 000000000..7962a61c6 --- /dev/null +++ b/compel/arch/x86/src/lib/cpu.c @@ -0,0 +1,189 @@ +#include +#include + +#include "uapi/compel/cpu.h" + +#include "common/bitops.h" +#include "common/compiler.h" + +#include "log.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "cpu: " + +static compel_cpuinfo_t rt_info; +static bool rt_info_done = false; + +void compel_set_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) +{ + if (likely(feature < NCAPINTS_BITS)) + set_bit(feature, (unsigned long *)c->x86_capability); +} + +void compel_clear_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) +{ + if (likely(feature < NCAPINTS_BITS)) + clear_bit(feature, (unsigned long *)c->x86_capability); +} + +int compel_test_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) +{ + if (likely(feature < NCAPINTS_BITS)) + return test_bit(feature, (unsigned long *)c->x86_capability); + return 0; +} + +int compel_cpuid(compel_cpuinfo_t *c) +{ + /* + * See cpu_detect() in the kernel, also + * read cpuid specs not only from general + * SDM but for extended instructions set + * reference. + */ + + /* Get vendor name */ + cpuid(0x00000000, + (unsigned int *)&c->cpuid_level, + (unsigned int *)&c->x86_vendor_id[0], + (unsigned int *)&c->x86_vendor_id[8], + (unsigned int *)&c->x86_vendor_id[4]); + + if (!strcmp(c->x86_vendor_id, "GenuineIntel")) { + c->x86_vendor = X86_VENDOR_INTEL; + } else if (!strcmp(c->x86_vendor_id, "AuthenticAMD")) { + c->x86_vendor = X86_VENDOR_AMD; + } else { + pr_err("Unsupported CPU vendor %s\n", + c->x86_vendor_id); + return -1; + } + + c->x86_family = 4; + + /* Intel-defined flags: level 0x00000001 */ + if (c->cpuid_level >= 0x00000001) { + uint32_t eax, ebx, ecx, edx; + + cpuid(0x00000001, &eax, &ebx, &ecx, &edx); + c->x86_family = (eax >> 8) & 0xf; + c->x86_model = (eax >> 4) & 0xf; + c->x86_mask = eax & 0xf; + + if (c->x86_family == 0xf) + c->x86_family += (eax >> 20) & 0xff; + if (c->x86_family >= 0x6) + c->x86_model += ((eax >> 16) & 0xf) << 4; + + c->x86_capability[0] = edx; + c->x86_capability[4] = ecx; + } + + /* Additional Intel-defined flags: level 0x00000007 */ + if (c->cpuid_level >= 0x00000007) { + uint32_t eax, ebx, ecx, edx; + + cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx); + c->x86_capability[9] = ebx; + c->x86_capability[11] = ecx; + } + + /* Extended state features: level 0x0000000d */ + if (c->cpuid_level >= 0x0000000d) { + uint32_t eax, ebx, ecx, edx; + + cpuid_count(0x0000000d, 1, &eax, &ebx, &ecx, &edx); + c->x86_capability[10] = eax; + } + + /* AMD-defined flags: level 0x80000001 */ + c->extended_cpuid_level = cpuid_eax(0x80000000); + + if ((c->extended_cpuid_level & 0xffff0000) == 0x80000000) { + if (c->extended_cpuid_level >= 0x80000001) { + c->x86_capability[1] = cpuid_edx(0x80000001); + c->x86_capability[6] = cpuid_ecx(0x80000001); + } + } + + /* + * We're don't care about scattered features for now, + * otherwise look into init_scattered_cpuid_features() + * in kernel. + */ + + if (c->extended_cpuid_level >= 0x80000004) { + unsigned int *v; + char *p, *q; + v = (unsigned int *)c->x86_model_id; + cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); + cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); + cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); + c->x86_model_id[48] = 0; + + /* + * Intel chips right-justify this string for some dumb reason; + * undo that brain damage: + */ + p = q = &c->x86_model_id[0]; + while (*p == ' ') + p++; + if (p != q) { + while (*p) + *q++ = *p++; + while (q <= &c->x86_model_id[48]) + *q++ = '\0'; /* Zero-pad the rest */ + } + } + + /* On x86-64 NOP is always present */ + compel_set_cpu_cap(c, X86_FEATURE_NOPL); + + switch (c->x86_vendor) { + case X86_VENDOR_INTEL: + /* + * Strictly speaking we need to read MSR_IA32_MISC_ENABLE + * here but on ring3 it's impossible. + */ + if (c->x86_family == 15) { + compel_clear_cpu_cap(c, X86_FEATURE_REP_GOOD); + compel_clear_cpu_cap(c, X86_FEATURE_ERMS); + } else if (c->x86_family == 6) { + /* On x86-64 rep is fine */ + compel_set_cpu_cap(c, X86_FEATURE_REP_GOOD); + } + + /* See filter_cpuid_features in kernel */ + if ((int32_t)c->cpuid_level < (int32_t)0x0000000d) + compel_clear_cpu_cap(c, X86_FEATURE_XSAVE); + break; + case X86_VENDOR_AMD: + /* + * Bit 31 in normal CPUID used for nonstandard 3DNow ID; + * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway + */ + compel_clear_cpu_cap(c, 0 * 32 + 31); + if (c->x86_family >= 0x10) + compel_set_cpu_cap(c, X86_FEATURE_REP_GOOD); + if (c->x86_family == 0xf) { + uint32_t level; + + /* On C+ stepping K8 rep microcode works well for copy/memset */ + level = cpuid_eax(1); + if ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58) + compel_set_cpu_cap(c, X86_FEATURE_REP_GOOD); + } + break; + } + + return 0; +} + +bool cpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_cpu_cap(&rt_info, feature); +} diff --git a/criu/arch/x86/include/asm/cpu.h b/compel/arch/x86/src/lib/include/uapi/asm/cpu.h similarity index 95% rename from criu/arch/x86/include/asm/cpu.h rename to compel/arch/x86/src/lib/include/uapi/asm/cpu.h index 6f49229d6..f79ace1fc 100644 --- a/criu/arch/x86/include/asm/cpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/cpu.h @@ -1,7 +1,7 @@ #ifndef __CR_ASM_CPU_H__ #define __CR_ASM_CPU_H__ -#include "asm/types.h" +#include /* * Adopted from linux kernel and enhanced from Intel/AMD manuals. @@ -176,8 +176,6 @@ static inline unsigned int cpuid_edx(unsigned int op) return edx; } -#define X86_FEATURE_VERSION 1 - enum { X86_VENDOR_INTEL = 0, X86_VENDOR_AMD = 1, @@ -186,22 +184,17 @@ enum { }; struct cpuinfo_x86 { - u8 x86_family; - u8 x86_vendor; - u8 x86_model; - u8 x86_mask; - u32 x86_capability[NCAPINTS]; - u32 extended_cpuid_level; + uint8_t x86_family; + uint8_t x86_vendor; + uint8_t x86_model; + uint8_t x86_mask; + uint32_t x86_capability[NCAPINTS]; + uint32_t extended_cpuid_level; int cpuid_level; char x86_vendor_id[16]; char x86_model_id[64]; }; -extern bool cpu_has_feature(unsigned int feature); -extern int cpu_init(void); -extern int cpu_dump_cpuinfo(void); -extern int cpu_validate_cpuinfo(void); -extern int cpuinfo_dump(void); -extern int cpuinfo_check(void); +typedef struct cpuinfo_x86 compel_cpuinfo_t; -#endif /* __CR_CPU_H__ */ +#endif /* __CR_ASM_CPU_H__ */ diff --git a/compel/arch/x86/src/lib/include/processor-flags.h b/compel/arch/x86/src/lib/include/uapi/asm/processor-flags.h similarity index 100% rename from compel/arch/x86/src/lib/include/processor-flags.h rename to compel/arch/x86/src/lib/include/uapi/asm/processor-flags.h diff --git a/compel/include/uapi/cpu.h b/compel/include/uapi/cpu.h new file mode 100644 index 000000000..662883bc9 --- /dev/null +++ b/compel/include/uapi/cpu.h @@ -0,0 +1,14 @@ +#ifndef UAPI_COMPEL_CPU_H__ +#define UAPI_COMPEL_CPU_H__ + +#include + +#include + +extern void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); +extern void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); +extern int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); +extern int compel_cpuid(compel_cpuinfo_t *info); +extern bool cpu_has_feature(unsigned int feature); + +#endif /* UAPI_COMPEL_CPU_H__ */ diff --git a/criu/Makefile b/criu/Makefile index 35febd8e8..6c06029e7 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -73,6 +73,7 @@ PROGRAM-BUILTINS += images/built-in.o PROGRAM-BUILTINS += $(obj)/built-in.o PROGRAM-BUILTINS += $(ARCH-LIB) PROGRAM-BUILTINS += soccr/libsoccr.a +PROGRAM-BUILTINS += compel/libcompel.a $(obj)/built-in.o: pie $(Q) $(MAKE) $(call build-as,Makefile.crtools,criu) all diff --git a/criu/arch/aarch64/cpu.c b/criu/arch/aarch64/cpu.c index 040fe14fc..34313fb15 100644 --- a/criu/arch/aarch64/cpu.c +++ b/criu/arch/aarch64/cpu.c @@ -4,11 +4,6 @@ #include #include "cpu.h" -bool cpu_has_feature(unsigned int feature) -{ - return false; -} - int cpu_init(void) { return 0; diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index 8e4f48656..fd34484df 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -4,6 +4,8 @@ #include #include "types.h" +#include + #include "asm/restorer.h" #include "common/compiler.h" #include "ptrace.h" diff --git a/criu/arch/aarch64/include/asm/cpu.h b/criu/arch/aarch64/include/asm/cpu.h deleted file mode 100644 index 59118c211..000000000 --- a/criu/arch/aarch64/include/asm/cpu.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/criu/arch/arm/cpu.c b/criu/arch/arm/cpu.c index 040fe14fc..34313fb15 100644 --- a/criu/arch/arm/cpu.c +++ b/criu/arch/arm/cpu.c @@ -4,11 +4,6 @@ #include #include "cpu.h" -bool cpu_has_feature(unsigned int feature) -{ - return false; -} - int cpu_init(void) { return 0; diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index d0576d5ae..07c6473f5 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -2,6 +2,8 @@ #include #include "types.h" +#include + #include "asm/restorer.h" #include "common/compiler.h" #include "asm/dump.h" diff --git a/criu/arch/arm/include/asm/cpu.h b/criu/arch/arm/include/asm/cpu.h deleted file mode 100644 index 59118c211..000000000 --- a/criu/arch/arm/include/asm/cpu.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/criu/arch/ppc64/cpu.c b/criu/arch/ppc64/cpu.c index 222bc62d1..aecba7801 100644 --- a/criu/arch/ppc64/cpu.c +++ b/criu/arch/ppc64/cpu.c @@ -6,7 +6,6 @@ #include #include "asm/types.h" -#include "asm/cpu.h" #include "cr_options.h" #include "image.h" @@ -17,7 +16,7 @@ #include "protobuf.h" #include "images/cpuinfo.pb-c.h" -static uint64_t hwcap[2]; +static compel_cpuinfo_t rt_cpuinfo; #ifdef __LITTLE_ENDIAN__ #define CURRENT_ENDIANNESS CPUINFO_PPC64_ENTRY__ENDIANNESS__LITTLEENDIAN @@ -27,14 +26,7 @@ static uint64_t hwcap[2]; int cpu_init(void) { - hwcap[0] = getauxval(AT_HWCAP); - hwcap[1] = getauxval(AT_HWCAP2); - - if (!hwcap[0] || !hwcap[1]) { - pr_err("Can't read the hardware capabilities"); - return -1; - } - return 0; + return compel_cpuid(&rt_cpuinfo); } int cpu_dump_cpuinfo(void) @@ -54,7 +46,7 @@ int cpu_dump_cpuinfo(void) cpu_ppc64_info.endian = CURRENT_ENDIANNESS; cpu_ppc64_info.n_hwcap = 2; - cpu_ppc64_info.hwcap = hwcap; + cpu_ppc64_info.hwcap = rt_cpuinfo.hwcap; ret = pb_write_one(img, &cpu_info, PB_CPUINFO); @@ -92,7 +84,8 @@ int cpu_validate_cpuinfo(void) } #define CHECK_FEATURE(s,f) do { \ - if ((cpu_ppc64_entry->hwcap[s] & f) && !(hwcap[s] & f)) { \ + if ((cpu_ppc64_entry->hwcap[s] & f) && \ + !(rt_cpuinfo.hwcap[s] & f)) { \ pr_err("CPU Feature %s required by image " \ "is not supported on host.\n", #f); \ goto error; \ diff --git a/criu/arch/ppc64/include/asm/cpu.h b/criu/arch/ppc64/include/asm/cpu.h deleted file mode 100644 index 59118c211..000000000 --- a/criu/arch/ppc64/include/asm/cpu.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index 49fe203c3..d2b835286 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -10,6 +10,7 @@ #include "asm/types.h" #include "asm/cpu.h" #include "asm/fpu.h" +#include #include "common/compiler.h" @@ -26,181 +27,11 @@ #undef LOG_PREFIX #define LOG_PREFIX "cpu: " -static struct cpuinfo_x86 rt_cpu_info; - -static void set_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) -{ - if (likely(feature < NCAPINTS_BITS)) - set_bit(feature, (unsigned long *)c->x86_capability); -} - -static void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) -{ - if (likely(feature < NCAPINTS_BITS)) - clear_bit(feature, (unsigned long *)c->x86_capability); -} - -static int test_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) -{ - if (likely(feature < NCAPINTS_BITS)) - return test_bit(feature, (unsigned long *)c->x86_capability); - return 0; -} - -bool cpu_has_feature(unsigned int feature) -{ - return test_cpu_cap(&rt_cpu_info, feature); -} - -static int cpu_init_cpuid(struct cpuinfo_x86 *c) -{ - /* - * See cpu_detect() in the kernel, also - * read cpuid specs not only from general - * SDM but for extended instructions set - * reference. - */ - - /* Get vendor name */ - cpuid(0x00000000, - (unsigned int *)&c->cpuid_level, - (unsigned int *)&c->x86_vendor_id[0], - (unsigned int *)&c->x86_vendor_id[8], - (unsigned int *)&c->x86_vendor_id[4]); - - if (!strcmp(c->x86_vendor_id, "GenuineIntel")) { - c->x86_vendor = X86_VENDOR_INTEL; - } else if (!strcmp(c->x86_vendor_id, "AuthenticAMD")) { - c->x86_vendor = X86_VENDOR_AMD; - } else { - pr_err("Unsupported CPU vendor %s\n", - c->x86_vendor_id); - return -1; - } - - c->x86_family = 4; - - /* Intel-defined flags: level 0x00000001 */ - if (c->cpuid_level >= 0x00000001) { - u32 eax, ebx, ecx, edx; - - cpuid(0x00000001, &eax, &ebx, &ecx, &edx); - c->x86_family = (eax >> 8) & 0xf; - c->x86_model = (eax >> 4) & 0xf; - c->x86_mask = eax & 0xf; - - if (c->x86_family == 0xf) - c->x86_family += (eax >> 20) & 0xff; - if (c->x86_family >= 0x6) - c->x86_model += ((eax >> 16) & 0xf) << 4; - - c->x86_capability[0] = edx; - c->x86_capability[4] = ecx; - } - - /* Additional Intel-defined flags: level 0x00000007 */ - if (c->cpuid_level >= 0x00000007) { - u32 eax, ebx, ecx, edx; - - cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx); - c->x86_capability[9] = ebx; - c->x86_capability[11] = ecx; - } - - /* Extended state features: level 0x0000000d */ - if (c->cpuid_level >= 0x0000000d) { - u32 eax, ebx, ecx, edx; - - cpuid_count(0x0000000d, 1, &eax, &ebx, &ecx, &edx); - c->x86_capability[10] = eax; - } - - /* AMD-defined flags: level 0x80000001 */ - c->extended_cpuid_level = cpuid_eax(0x80000000); - - if ((c->extended_cpuid_level & 0xffff0000) == 0x80000000) { - if (c->extended_cpuid_level >= 0x80000001) { - c->x86_capability[1] = cpuid_edx(0x80000001); - c->x86_capability[6] = cpuid_ecx(0x80000001); - } - } - - /* - * We're don't care about scattered features for now, - * otherwise look into init_scattered_cpuid_features() - * in kernel. - */ - - if (c->extended_cpuid_level >= 0x80000004) { - unsigned int *v; - char *p, *q; - v = (unsigned int *)c->x86_model_id; - cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); - cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); - cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); - c->x86_model_id[48] = 0; - - /* - * Intel chips right-justify this string for some dumb reason; - * undo that brain damage: - */ - p = q = &c->x86_model_id[0]; - while (*p == ' ') - p++; - if (p != q) { - while (*p) - *q++ = *p++; - while (q <= &c->x86_model_id[48]) - *q++ = '\0'; /* Zero-pad the rest */ - } - } - - /* On x86-64 NOP is always present */ - set_cpu_cap(c, X86_FEATURE_NOPL); - - switch (c->x86_vendor) { - case X86_VENDOR_INTEL: - /* - * Strictly speaking we need to read MSR_IA32_MISC_ENABLE - * here but on ring3 it's impossible. - */ - if (c->x86_family == 15) { - clear_cpu_cap(c, X86_FEATURE_REP_GOOD); - clear_cpu_cap(c, X86_FEATURE_ERMS); - } else if (c->x86_family == 6) { - /* On x86-64 rep is fine */ - set_cpu_cap(c, X86_FEATURE_REP_GOOD); - } - - /* See filter_cpuid_features in kernel */ - if ((s32)c->cpuid_level < (s32)0x0000000d) - clear_cpu_cap(c, X86_FEATURE_XSAVE); - break; - case X86_VENDOR_AMD: - /* - * Bit 31 in normal CPUID used for nonstandard 3DNow ID; - * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway - */ - clear_cpu_cap(c, 0 * 32 + 31); - if (c->x86_family >= 0x10) - set_cpu_cap(c, X86_FEATURE_REP_GOOD); - if (c->x86_family == 0xf) { - u32 level; - - /* On C+ stepping K8 rep microcode works well for copy/memset */ - level = cpuid_eax(1); - if ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58) - set_cpu_cap(c, X86_FEATURE_REP_GOOD); - } - break; - } - - return 0; -} +static compel_cpuinfo_t rt_cpu_info; int cpu_init(void) { - if (cpu_init_cpuid(&rt_cpu_info)) + if (compel_cpuid(&rt_cpu_info)) return -1; BUILD_BUG_ON(sizeof(struct xsave_struct) != XSAVE_SIZE); diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index fe9d581bb..4dc2f93db 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -9,7 +9,8 @@ #include "asm/cpu.h" #include "kerndat.h" -#include "compel/include/asm/processor-flags.h" +#include +#include #include "compel/include/errno.h" #include #include diff --git a/criu/include/cpu.h b/criu/include/cpu.h index e94525a9e..e30696790 100644 --- a/criu/include/cpu.h +++ b/criu/include/cpu.h @@ -1,9 +1,8 @@ #ifndef __CR_CPU_H__ #define __CR_CPU_H__ -#include "asm/cpu.h" +#include -extern bool cpu_has_feature(unsigned int feature); extern int cpu_init(void); extern int cpu_dump_cpuinfo(void); extern int cpu_validate_cpuinfo(void); From 5a6d2cea0651f0866a97f1246791a78c3e5b3f15 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 28 Oct 2016 11:41:28 +0300 Subject: [PATCH 0187/4375] criu: Fix headers for non-x86 arches. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/include/uapi/ksigset.h | 2 ++ criu/arch/aarch64/crtools.c | 1 + criu/arch/aarch64/include/asm/infect-types.h | 2 ++ criu/arch/aarch64/infect.c | 2 +- criu/arch/arm/crtools.c | 2 +- criu/arch/arm/include/asm/infect-types.h | 2 ++ criu/arch/arm/infect.c | 1 + criu/arch/ppc64/include/asm/restorer.h | 1 + criu/cr-restore.c | 2 ++ criu/infect.c | 1 + 10 files changed, 14 insertions(+), 2 deletions(-) diff --git a/compel/include/uapi/ksigset.h b/compel/include/uapi/ksigset.h index 412899c8c..ed6950a33 100644 --- a/compel/include/uapi/ksigset.h +++ b/compel/include/uapi/ksigset.h @@ -1,6 +1,8 @@ #ifndef __COMPEL_KSIGSET_H__ #define __COMPEL_KSIGSET_H__ +#include + static inline void ksigfillset(k_rtsigset_t *set) { int i; diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index fd34484df..d3cbc7e6f 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -6,6 +6,7 @@ #include "types.h" #include +#include "asm/infect-types.h" #include "asm/restorer.h" #include "common/compiler.h" #include "ptrace.h" diff --git a/criu/arch/aarch64/include/asm/infect-types.h b/criu/arch/aarch64/include/asm/infect-types.h index 714881c57..ff9e53e7c 100644 --- a/criu/arch/aarch64/include/asm/infect-types.h +++ b/criu/arch/aarch64/include/asm/infect-types.h @@ -7,6 +7,8 @@ #include #include "common/page.h" +#include "page.h" + #define SIGMAX 64 #define SIGMAX_OLD 31 diff --git a/criu/arch/aarch64/infect.c b/criu/arch/aarch64/infect.c index 067e558e0..3a9cb10cd 100644 --- a/criu/arch/aarch64/infect.c +++ b/criu/arch/aarch64/infect.c @@ -83,7 +83,7 @@ int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, return err; } -void *mmap_re(struct parasite_ctl *ctl, +void *remote_mmap(struct parasite_ctl *ctl, void *addr, size_t length, int prot, int flags, int fd, off_t offset) { diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index 07c6473f5..aa3860e93 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -4,11 +4,11 @@ #include "types.h" #include +#include "asm/infect-types.h" #include "asm/restorer.h" #include "common/compiler.h" #include "asm/dump.h" #include "ptrace.h" -#include "compel/include/asm/processor-flags.h" #include "protobuf.h" #include "images/core.pb-c.h" #include "images/creds.pb-c.h" diff --git a/criu/arch/arm/include/asm/infect-types.h b/criu/arch/arm/include/asm/infect-types.h index 9c2092e5d..91b4c1e98 100644 --- a/criu/arch/arm/include/asm/infect-types.h +++ b/criu/arch/arm/include/asm/infect-types.h @@ -5,6 +5,8 @@ #include #include "common/page.h" +#include "page.h" + #define SIGMAX 64 #define SIGMAX_OLD 31 diff --git a/criu/arch/arm/infect.c b/criu/arch/arm/infect.c index 357d4492b..6fe6142be 100644 --- a/criu/arch/arm/infect.c +++ b/criu/arch/arm/infect.c @@ -2,6 +2,7 @@ #include #include "asm/parasite-syscall.h" #include +#include #include "asm/types.h" #include "criu-log.h" #include "kerndat.h" diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h index 5342fab68..e99f2751b 100644 --- a/criu/arch/ppc64/include/asm/restorer.h +++ b/criu/arch/ppc64/include/asm/restorer.h @@ -5,6 +5,7 @@ #include #include #include "asm/types.h" +#include "asm/infect-types.h" #include "sigframe.h" diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 2ec4d0bcc..7c0baa9b8 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -23,6 +23,8 @@ #include +#include "compel/include/asm/ptrace.h" + #include "types.h" #include "ptrace.h" #include "common/compiler.h" diff --git a/criu/infect.c b/criu/infect.c index bea009e85..5d26ad3e0 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -20,6 +20,7 @@ #include #include "compel/include/asm/ptrace.h" #include "compel/include/asm/syscall.h" +#include "asm/infect-types.h" #include "asm/sigframe.h" #include "infect.h" #include "ptrace.h" From b05f06664425a7e5a1def5d3e2367fc57d752374 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 28 Oct 2016 16:04:18 +0300 Subject: [PATCH 0188/4375] compel: Move fpu.h into it Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- .../arch/aarch64/src/lib/include/uapi}/asm/fpu.h | 0 .../include => compel/arch/arm/src/lib/include/uapi}/asm/fpu.h | 0 .../arch/ppc64/src/lib/include/uapi}/asm/fpu.h | 0 .../include => compel/arch/x86/src/lib/include/uapi}/asm/fpu.h | 0 criu/arch/aarch64/restorer.c | 2 +- criu/arch/arm/restorer.c | 2 +- criu/arch/ppc64/crtools.c | 2 +- criu/arch/ppc64/restorer.c | 2 +- criu/arch/x86/cpu.c | 2 +- criu/arch/x86/crtools.c | 2 +- criu/arch/x86/include/asm/restorer.h | 2 +- criu/arch/x86/include/asm/sigframe.h | 2 +- criu/arch/x86/infect.c | 3 ++- criu/arch/x86/restorer.c | 2 +- criu/arch/x86/sigaction_compat.c | 2 +- criu/include/restorer.h | 2 +- 16 files changed, 13 insertions(+), 12 deletions(-) rename {criu/arch/aarch64/include => compel/arch/aarch64/src/lib/include/uapi}/asm/fpu.h (100%) rename {criu/arch/arm/include => compel/arch/arm/src/lib/include/uapi}/asm/fpu.h (100%) rename {criu/arch/ppc64/include => compel/arch/ppc64/src/lib/include/uapi}/asm/fpu.h (100%) rename {criu/arch/x86/include => compel/arch/x86/src/lib/include/uapi}/asm/fpu.h (100%) diff --git a/criu/arch/aarch64/include/asm/fpu.h b/compel/arch/aarch64/src/lib/include/uapi/asm/fpu.h similarity index 100% rename from criu/arch/aarch64/include/asm/fpu.h rename to compel/arch/aarch64/src/lib/include/uapi/asm/fpu.h diff --git a/criu/arch/arm/include/asm/fpu.h b/compel/arch/arm/src/lib/include/uapi/asm/fpu.h similarity index 100% rename from criu/arch/arm/include/asm/fpu.h rename to compel/arch/arm/src/lib/include/uapi/asm/fpu.h diff --git a/criu/arch/ppc64/include/asm/fpu.h b/compel/arch/ppc64/src/lib/include/uapi/asm/fpu.h similarity index 100% rename from criu/arch/ppc64/include/asm/fpu.h rename to compel/arch/ppc64/src/lib/include/uapi/asm/fpu.h diff --git a/criu/arch/x86/include/asm/fpu.h b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h similarity index 100% rename from criu/arch/x86/include/asm/fpu.h rename to compel/arch/x86/src/lib/include/uapi/asm/fpu.h diff --git a/criu/arch/aarch64/restorer.c b/criu/arch/aarch64/restorer.c index 69f7dbe1e..ce9c1b410 100644 --- a/criu/arch/aarch64/restorer.c +++ b/criu/arch/aarch64/restorer.c @@ -5,7 +5,7 @@ #include #include "log.h" -#include "asm/fpu.h" +#include #include "cpu.h" int restore_nonsigframe_gpregs(UserRegsEntry *r) diff --git a/criu/arch/arm/restorer.c b/criu/arch/arm/restorer.c index fe206e1a7..21234b95d 100644 --- a/criu/arch/arm/restorer.c +++ b/criu/arch/arm/restorer.c @@ -5,7 +5,7 @@ #include #include "log.h" -#include "asm/fpu.h" +#include #include "cpu.h" int restore_nonsigframe_gpregs(UserArmRegsEntry *r) diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index cd4df6417..3d662542e 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -6,7 +6,7 @@ #include #include "types.h" -#include "asm/fpu.h" +#include #include "asm/restorer.h" #include "asm/dump.h" diff --git a/criu/arch/ppc64/restorer.c b/criu/arch/ppc64/restorer.c index 4dda4bd16..7172e44c3 100644 --- a/criu/arch/ppc64/restorer.c +++ b/criu/arch/ppc64/restorer.c @@ -2,7 +2,7 @@ #include "restorer.h" #include "asm/restorer.h" -#include "asm/fpu.h" +#include #include #include "log.h" diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index d2b835286..9f8083db0 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -9,7 +9,7 @@ #include "bitops.h" #include "asm/types.h" #include "asm/cpu.h" -#include "asm/fpu.h" +#include #include #include "common/compiler.h" diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 32508367d..886a2c7a3 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -8,7 +8,7 @@ #include "types.h" #include "asm/parasite-syscall.h" #include "asm/restorer.h" -#include "asm/fpu.h" +#include #include "asm/dump.h" #include "cr_options.h" diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index e70526089..0b081bdcd 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -2,7 +2,7 @@ #define __CR_ASM_RESTORER_H__ #include "asm/types.h" -#include "asm/fpu.h" +#include #include "images/core.pb-c.h" #include diff --git a/criu/arch/x86/include/asm/sigframe.h b/criu/arch/x86/include/asm/sigframe.h index b03aaf6cb..3badc5124 100644 --- a/criu/arch/x86/include/asm/sigframe.h +++ b/criu/arch/x86/include/asm/sigframe.h @@ -4,7 +4,7 @@ #include #include -#include "asm/fpu.h" +#include #define SIGFRAME_MAX_OFFSET 8 diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index 4dc2f93db..6abad63c3 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -5,7 +5,8 @@ #include #include -#include "asm/fpu.h" +#include + #include "asm/cpu.h" #include "kerndat.h" diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index 01ed669e5..050241cca 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -4,7 +4,7 @@ #include "types.h" #include "restorer.h" #include "asm/restorer.h" -#include "asm/fpu.h" +#include #include "asm/string.h" #include diff --git a/criu/arch/x86/sigaction_compat.c b/criu/arch/x86/sigaction_compat.c index af7234696..076c014ef 100644 --- a/criu/arch/x86/sigaction_compat.c +++ b/criu/arch/x86/sigaction_compat.c @@ -1,5 +1,5 @@ #include "asm/restorer.h" -#include "asm/fpu.h" +#include #include "asm/string.h" #include diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 0fc47e283..c5cb97b45 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -9,7 +9,7 @@ #include "int.h" #include "types.h" #include "common/compiler.h" -#include "asm/fpu.h" +#include #include "common/lock.h" #include "util.h" #include "asm/restorer.h" From 5e48c690c7080252e69fb5d3bb72a5cec5a00724 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 28 Oct 2016 19:19:01 +0300 Subject: [PATCH 0189/4375] compel: Build syscalls before the compel We will use syscall types in compel infect engine itself so make sure they are built earlier. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- Makefile.compel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.compel b/Makefile.compel index 366f604e9..42d05bc41 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -37,7 +37,7 @@ compel-deps += include/common/asm # # Compel itself. -compel/%: $(compel-deps) .FORCE +compel/%: $(compel-deps) compel/plugins/std.built-in.o .FORCE $(Q) $(MAKE) $(build)=compel $@ # From 721e7fa5daae7863816a9f033854163d3ef867eb Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 30 Oct 2016 22:54:29 +0300 Subject: [PATCH 0190/4375] infect x86: Remove kdat The kdat is used to check whether we have compat sigreturn in the kernel. Compel can check it himself, but criu already knows this. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/infect.c | 3 +-- criu/include/infect.h | 1 + criu/parasite-syscall.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index 6abad63c3..d4208ab54 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -8,7 +8,6 @@ #include #include "asm/cpu.h" -#include "kerndat.h" #include #include @@ -236,7 +235,7 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) if (ret < 0) return false; - if (ret && !kdat.has_compat_sigreturn) { + if (ret && !(ctl->ictx.flags & INFECT_HAS_COMPAT_SIGRETURN)) { pr_err("Can't dump task %d running in 32-bit mode\n", pid); return false; } diff --git a/criu/include/infect.h b/criu/include/infect.h index 2db90e618..c0f31d16b 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -115,6 +115,7 @@ extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *); #define INFECT_NO_MEMFD 0x1 /* don't use memfd() */ #define INFECT_FAIL_CONNECT 0x2 /* make parasite connect() fail */ #define INFECT_NO_BREAKPOINTS 0x4 /* no breakpoints in pie tracking */ +#define INFECT_HAS_COMPAT_SIGRETURN 0x8 typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); extern int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *); diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 3bec47554..0d7355362 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -558,6 +558,8 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ictx->flags |= INFECT_FAIL_CONNECT; if (fault_injected(FI_NO_BREAKPOINTS)) ictx->flags |= INFECT_NO_BREAKPOINTS; + if (kdat.has_compat_sigreturn) + ictx->flags |= INFECT_HAS_COMPAT_SIGRETURN; parasite_ensure_args_size(dump_pages_args_size(vma_area_list)); parasite_ensure_args_size(aio_rings_args_size(vma_area_list)); From a406965e972f91375e6848c83e54aacb0da99273 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 30 Oct 2016 22:56:39 +0300 Subject: [PATCH 0191/4375] infect arm & aarch64: Remove kdat In these gents the task_size should be known. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/infect.c | 1 - criu/arch/arm/infect.c | 3 +-- criu/include/infect.h | 1 + criu/parasite-syscall.c | 1 + 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/arch/aarch64/infect.c b/criu/arch/aarch64/infect.c index 3a9cb10cd..aeb734781 100644 --- a/criu/arch/aarch64/infect.c +++ b/criu/arch/aarch64/infect.c @@ -6,7 +6,6 @@ #include #include "asm/types.h" #include "criu-log.h" -#include "kerndat.h" #include "parasite-syscall.h" #include "compel/include/errno.h" #include "infect.h" diff --git a/criu/arch/arm/infect.c b/criu/arch/arm/infect.c index 6fe6142be..b22e98d9c 100644 --- a/criu/arch/arm/infect.c +++ b/criu/arch/arm/infect.c @@ -5,7 +5,6 @@ #include #include "asm/types.h" #include "criu-log.h" -#include "kerndat.h" #include "parasite-syscall.h" #include "compel/include/errno.h" #include "infect.h" @@ -100,7 +99,7 @@ void *remote_mmap(struct parasite_ctl *ctl, err = compel_syscall(ctl, __NR_mmap2, &map, (unsigned long)addr, length, prot, flags, fd, offset >> 12); - if (err < 0 || map > kdat.task_size) + if (err < 0 || map > ctl->ictx.task_size) map = 0; return (void *)map; diff --git a/criu/include/infect.h b/criu/include/infect.h index c0f31d16b..fc4f949f9 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -102,6 +102,7 @@ struct infect_ctx { int (*make_sigframe)(void *, struct rt_sigframe *, struct rt_sigframe *, k_rtsigset_t *); void *regs_arg; + unsigned long task_size; unsigned long syscall_ip; /* entry point of infection */ unsigned long flags; /* fine-tune (e.g. faults) */ diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 0d7355362..59d067351 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -549,6 +549,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ictx->save_regs = save_task_regs; ictx->make_sigframe = make_sigframe; ictx->regs_arg = item->core[0]; + ictx->task_size = kdat.task_size; ictx->syscall_ip = p; pr_debug("Parasite syscall_ip at %#lx\n", p); From e92c3266923fc2863a85c02cae51aee1c6aa474b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 28 Oct 2016 14:00:55 +0300 Subject: [PATCH 0192/4375] compel: Update with move lock.h into include/common/ Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/infect-rpc.c | 2 +- criu/infect-util.c | 2 +- criu/infect.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/infect-rpc.c b/criu/infect-rpc.c index c8b97a297..0994bcb35 100644 --- a/criu/infect-rpc.c +++ b/criu/infect-rpc.c @@ -1,7 +1,7 @@ #include "log.h" #include "common/bug.h" #include "common/xmalloc.h" -#include "lock.h" +#include "common/lock.h" #include "infect.h" #include "infect-priv.h" diff --git a/criu/infect-util.c b/criu/infect-util.c index 4c0537fdc..275e2ec81 100644 --- a/criu/infect-util.c +++ b/criu/infect-util.c @@ -1,7 +1,7 @@ #include "int.h" #include "log.h" #include "common/bug.h" -#include "lock.h" +#include "common/lock.h" #include "util-pie.h" #include "infect-rpc.h" diff --git a/criu/infect.c b/criu/infect.c index 5d26ad3e0..75d525858 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -14,7 +14,7 @@ #include "criu-log.h" #include "common/bug.h" #include "common/xmalloc.h" -#include "lock.h" +#include "common/lock.h" #include #include From 6606dc722c67da3e62a2eb578fea1d70ae3ee51c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 2 Nov 2016 03:41:57 +0300 Subject: [PATCH 0193/4375] scm: Switch compel fd plugin onto common Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/fds/fds.c | 18 ++-- compel/plugins/include/uapi/plugin-fds.h | 18 +--- compel/src/shared/fds.c | 113 ----------------------- 3 files changed, 9 insertions(+), 140 deletions(-) delete mode 100644 compel/src/shared/fds.c diff --git a/compel/plugins/fds/fds.c b/compel/plugins/fds/fds.c index a7966e5de..a19c66287 100644 --- a/compel/plugins/fds/fds.c +++ b/compel/plugins/fds/fds.c @@ -1,3 +1,5 @@ +#include + #include "uapi/plugins.h" #include "uapi/std/syscall.h" @@ -5,22 +7,14 @@ #include "uapi/plugin-fds.h" #include "std-priv.h" +#include "log.h" #include "common/compiler.h" +#include "common/bug.h" #define __sys(foo) sys_##foo -#define __std(foo) std_##foo +#define __memcpy std_memcpy -#include "../../src/shared/fds.c" - -int fds_send(int *fds, int nr_fds) -{ - return fds_send_via(std_ctl_sock(), fds, nr_fds); -} - -int fds_recv(int *fds, int nr_fds) -{ - return fds_recv_via(std_ctl_sock(), fds, nr_fds); -} +#include "common/scm-code.c" PLUGIN_REGISTER_DUMMY(fds) diff --git a/compel/plugins/include/uapi/plugin-fds.h b/compel/plugins/include/uapi/plugin-fds.h index 96991eaa4..0ce83afbd 100644 --- a/compel/plugins/include/uapi/plugin-fds.h +++ b/compel/plugins/include/uapi/plugin-fds.h @@ -5,23 +5,11 @@ #ifndef __COMPEL_PLUGIN_FDS_H__ #define __COMPEL_PLUGIN_FDS_H__ -extern int fds_send(int *fds, int nr_fds); -extern int fds_recv(int *fds, int nr_fds); +#include "common/scm.h" -static inline int fds_send_one(int fd) +static inline int send_fd(int sock, struct sockaddr_un *saddr, int saddr_len, int fd) { - return fds_send(&fd, 1); -} - -static inline int fds_recv_one(void) -{ - int fd, ret; - - ret = fds_recv(&fd, 1); - if (ret) - fd = -1; - - return fd; + return send_fds(sock, saddr, saddr_len, &fd, 1, false); } #endif /* __COMPEL_PLUGIN_FDS_H__ */ diff --git a/compel/src/shared/fds.c b/compel/src/shared/fds.c deleted file mode 100644 index 9bf49cbdd..000000000 --- a/compel/src/shared/fds.c +++ /dev/null @@ -1,113 +0,0 @@ -#include -#include - -/* - * Because of kernel doing kmalloc for user data passed - * in SCM messages, and there is kernel's SCM_MAX_FD as a limit - * for descriptors passed at once we're trying to reduce - * the pressue on kernel memory manager and use predefined - * known to work well size of the message buffer. - */ -#define CR_SCM_MSG_SIZE (1024) -#define CR_SCM_MAX_FD (252) - -struct scm_fdset { - struct msghdr hdr; - struct iovec iov; - char msg_buf[CR_SCM_MSG_SIZE]; - char f; -}; - -static void scm_fdset_init_chunk(struct scm_fdset *fdset, int nr_fds) -{ - struct cmsghdr *cmsg; - - fdset->hdr.msg_controllen = CMSG_LEN(sizeof(int) * nr_fds); - - cmsg = CMSG_FIRSTHDR(&fdset->hdr); - cmsg->cmsg_len = fdset->hdr.msg_controllen; -} - -static int *scm_fdset_init(struct scm_fdset *fdset) -{ - struct cmsghdr *cmsg; - - BUILD_BUG_ON(sizeof(fdset->msg_buf) < (CMSG_SPACE(sizeof(int) * CR_SCM_MAX_FD))); - - fdset->iov.iov_base = &fdset->f; - fdset->iov.iov_len = 1; - - fdset->hdr.msg_iov = &fdset->iov; - fdset->hdr.msg_iovlen = 1; - fdset->hdr.msg_name = NULL; - fdset->hdr.msg_namelen = 0; - - fdset->hdr.msg_control = &fdset->msg_buf; - fdset->hdr.msg_controllen = CMSG_LEN(sizeof(int) * CR_SCM_MAX_FD); - - cmsg = CMSG_FIRSTHDR(&fdset->hdr); - cmsg->cmsg_len = fdset->hdr.msg_controllen; - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - - return (int *)CMSG_DATA(cmsg); -} - -int fds_send_via(int sock, int *fds, int nr_fds) -{ - struct scm_fdset fdset; - int i, min_fd, ret; - int *cmsg_data; - - cmsg_data = scm_fdset_init(&fdset); - - for (i = 0; i < nr_fds; i += min_fd) { - min_fd = min(CR_SCM_MAX_FD, nr_fds - i); - scm_fdset_init_chunk(&fdset, min_fd); - __std(memcpy(cmsg_data, &fds[i], sizeof(int) * min_fd)); - ret = __sys(sendmsg(sock, &fdset.hdr, 0)); - if (ret <= 0) - return ret ? : -1; - } - - return 0; -} - -int fds_recv_via(int sock, int *fds, int nr_fds) -{ - struct scm_fdset fdset; - struct cmsghdr *cmsg; - int *cmsg_data; - int ret; - int i, min_fd; - - cmsg_data = scm_fdset_init(&fdset); - for (i = 0; i < nr_fds; i += min_fd) { - min_fd = min(CR_SCM_MAX_FD, nr_fds - i); - scm_fdset_init_chunk(&fdset, min_fd); - - ret = __sys(recvmsg(sock, &fdset.hdr, 0)); - if (ret <= 0) - return ret ? : -1; - - cmsg = CMSG_FIRSTHDR(&fdset.hdr); - if (!cmsg || cmsg->cmsg_type != SCM_RIGHTS) - return -1; - if (fdset.hdr.msg_flags & MSG_CTRUNC) - return -2; - - min_fd = (cmsg->cmsg_len - sizeof(struct cmsghdr)) / sizeof(int); - /* - * In case if kernel screwed the recepient, most probably - * the caller stack frame will be overwriten, just scream - * and exit. - */ - if (unlikely(min_fd > CR_SCM_MAX_FD)) - *(volatile unsigned long *)NULL = 0xdead0000 + __LINE__; - if (unlikely(min_fd <= 0)) - return -1; - __std(memcpy(&fds[i], cmsg_data, sizeof(int) * min_fd)); - } - - return 0; -} From 9df806aedd0b759391c67f969c77644da775f51d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 31 Oct 2016 18:05:56 +0300 Subject: [PATCH 0194/4375] pie: Detach infect This moves the previously splitted routines into pie/infect.c. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/include/asm/sigframe.h | 1 + criu/include/infect-pie.h | 7 + criu/pie/Makefile | 2 + criu/pie/compat/infect-compat.c | 1 + criu/pie/infect.c | 220 +++++++++++++++++++++++++++ criu/pie/parasite.c | 219 ++------------------------ 6 files changed, 242 insertions(+), 208 deletions(-) create mode 100644 criu/include/infect-pie.h create mode 120000 criu/pie/compat/infect-compat.c create mode 100644 criu/pie/infect.c diff --git a/criu/arch/x86/include/asm/sigframe.h b/criu/arch/x86/include/asm/sigframe.h index 3badc5124..8e33ce6db 100644 --- a/criu/arch/x86/include/asm/sigframe.h +++ b/criu/arch/x86/include/asm/sigframe.h @@ -5,6 +5,7 @@ #include #include +#include #define SIGFRAME_MAX_OFFSET 8 diff --git a/criu/include/infect-pie.h b/criu/include/infect-pie.h new file mode 100644 index 000000000..b00d7dd25 --- /dev/null +++ b/criu/include/infect-pie.h @@ -0,0 +1,7 @@ +#ifndef __CR_INFECT_PIE_H__ +#define __CR_INFECT_PIE_H__ +extern int parasite_daemon_cmd(int cmd, void *args); +extern int parasite_trap_cmd(int cmd, void *args); +extern void parasite_cleanup(void); +extern int parasite_get_rpc_sock(void); +#endif diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 0c764170f..59dea726c 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -7,7 +7,9 @@ ifeq ($(CONFIG_COMPAT),y) endif native-obj-y += parasite.o +native-obj-y += infect.o compat-obj-y += compat/parasite-compat.o +compat-obj-y += compat/infect-compat.o restorer-obj-y += restorer.o restorer-obj-y += ./$(ARCH_DIR)/restorer.o diff --git a/criu/pie/compat/infect-compat.c b/criu/pie/compat/infect-compat.c new file mode 120000 index 000000000..87c7722b6 --- /dev/null +++ b/criu/pie/compat/infect-compat.c @@ -0,0 +1 @@ +../infect.c \ No newline at end of file diff --git a/criu/pie/infect.c b/criu/pie/infect.c new file mode 100644 index 000000000..f24336932 --- /dev/null +++ b/criu/pie/infect.c @@ -0,0 +1,220 @@ +#include "common/compiler.h" +#include "common/lock.h" +#include "int.h" +#include "util-pie.h" + +#include "criu-log.h" +#include "common/bug.h" +#include "sigframe.h" +#include "infect-rpc.h" +#include "infect-pie.h" + +static int tsock = -1; + +static struct rt_sigframe *sigframe; + +int parasite_get_rpc_sock(void) +{ + return tsock; +} + +/* RPC helpers */ +static int __parasite_daemon_reply_ack(unsigned int cmd, int err) +{ + struct ctl_msg m; + int ret; + + m = ctl_msg_ack(cmd, err); + ret = sys_sendto(tsock, &m, sizeof(m), 0, NULL, 0); + if (ret != sizeof(m)) { + pr_err("Sent only %d bytes while %zu expected\n", ret, sizeof(m)); + return -1; + } + + pr_debug("__sent ack msg: %d %d %d\n", + m.cmd, m.ack, m.err); + + return 0; +} + +static int __parasite_daemon_wait_msg(struct ctl_msg *m) +{ + int ret; + + pr_debug("Daemon waits for command\n"); + + while (1) { + *m = (struct ctl_msg){ }; + ret = sys_recvfrom(tsock, m, sizeof(*m), MSG_WAITALL, NULL, 0); + if (ret != sizeof(*m)) { + pr_err("Trimmed message received (%d/%d)\n", + (int)sizeof(*m), ret); + return -1; + } + + pr_debug("__fetched msg: %d %d %d\n", + m->cmd, m->ack, m->err); + return 0; + } + + return -1; +} + +/* Core infect code */ + +static noinline void fini_sigreturn(unsigned long new_sp) +{ + ARCH_RT_SIGRETURN(new_sp, sigframe); +} + +static int fini(void) +{ + unsigned long new_sp; + + parasite_cleanup(); + + new_sp = (long)sigframe + RT_SIGFRAME_OFFSET(sigframe); + pr_debug("%ld: new_sp=%lx ip %lx\n", sys_gettid(), + new_sp, RT_SIGFRAME_REGIP(sigframe)); + + sys_close(tsock); + log_set_fd(-1); + + fini_sigreturn(new_sp); + + BUG(); + + return -1; +} + +static noinline __used int noinline parasite_daemon(void *args) +{ + struct ctl_msg m; + int ret = -1; + + pr_debug("Running daemon thread leader\n"); + + /* Reply we're alive */ + if (__parasite_daemon_reply_ack(PARASITE_CMD_INIT_DAEMON, 0)) + goto out; + + ret = 0; + + while (1) { + if (__parasite_daemon_wait_msg(&m)) + break; + + if (ret && m.cmd != PARASITE_CMD_FINI) { + pr_err("Command rejected\n"); + continue; + } + + if (m.cmd == PARASITE_CMD_FINI) + goto out; + + ret = parasite_daemon_cmd(m.cmd, args); + + if (__parasite_daemon_reply_ack(m.cmd, ret)) + break; + + if (ret) { + pr_err("Close the control socket for writing\n"); + sys_shutdown(tsock, SHUT_WR); + } + } + +out: + fini(); + + return 0; +} + +static noinline int unmap_itself(void *data) +{ + struct parasite_unmap_args *args = data; + + sys_munmap(args->parasite_start, args->parasite_len); + /* + * This call to sys_munmap must never return. Instead, the controlling + * process must trap us on the exit from munmap. + */ + + BUG(); + return -1; +} + +static noinline __used int parasite_init_daemon(void *data) +{ + struct parasite_init_args *args = data; + int ret; + + args->sigreturn_addr = (uint64_t)(uintptr_t)fini_sigreturn; + sigframe = (void*)(uintptr_t)args->sigframe; + + ret = tsock = sys_socket(PF_UNIX, SOCK_SEQPACKET, 0); + if (tsock < 0) { + pr_err("Can't create socket: %d\n", tsock); + goto err; + } + + ret = sys_connect(tsock, (struct sockaddr *)&args->h_addr, args->h_addr_len); + if (ret < 0) { + pr_err("Can't connect the control socket\n"); + goto err; + } + + futex_set_and_wake(&args->daemon_connected, 1); + + ret = recv_fd(tsock); + if (ret >= 0) { + log_set_fd(ret); + log_set_loglevel(args->log_level); + ret = 0; + } else + goto err; + + parasite_daemon(data); + +err: + futex_set_and_wake(&args->daemon_connected, ret); + fini(); + BUG(); + + return -1; +} + +#ifndef __parasite_entry +# define __parasite_entry +#endif + +int __used __parasite_entry parasite_service(unsigned int cmd, void *args) +{ + pr_info("Parasite cmd %d/%x process\n", cmd, cmd); + + switch (cmd) { + case PARASITE_CMD_INIT_DAEMON: + return parasite_init_daemon(args); + case PARASITE_CMD_UNMAP: + return unmap_itself(args); + } + + return parasite_trap_cmd(cmd, args); +} + +/* + * Mainally, -fstack-protector is disabled for parasite. + * But we share some object files, compiled for CRIU with parasite. + * Those files (like cpu.c) may be compiled with stack protector + * support. We can't use gcc-ld provided stackprotector callback, + * as Glibc is unmapped. Let's just try to cure application in + * case of stack smashing in parasite. + */ +void __stack_chk_fail(void) +{ + /* + * Smash didn't happen in printing part, as it's not shared + * with CRIU, therefore compiled with -fnostack-protector. + */ + pr_err("Stack smash detected in parasite\n"); + fini(); +} diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index 8e1fdf8d4..b4a476227 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -20,19 +20,17 @@ #include "tty.h" #include "aio.h" #include "infect-rpc.h" +#include "infect-pie.h" #include "asm/parasite.h" #include "restorer.h" +#include "infect-pie.h" int compel_main(void *arg_p, unsigned int arg_s) { return 0; } -static int tsock = -1; - -static struct rt_sigframe *sigframe; - /* * PARASITE_CMD_DUMPPAGES is called many times and the parasite args contains * an array of VMAs at this time, so VMAs can be unprotected in any moment @@ -73,9 +71,10 @@ static int mprotect_vmas(struct parasite_dump_pages_args *args) static int dump_pages(struct parasite_dump_pages_args *args) { - int p, ret; + int p, ret, tsock; struct iovec *iovs; + tsock = parasite_get_rpc_sock(); p = recv_fd(tsock); if (p < 0) return -1; @@ -330,7 +329,7 @@ static int fill_fds_opts(struct parasite_drain_fd *fds, struct fd_opts *opts) static int drain_fds(struct parasite_drain_fd *args) { - int ret; + int ret, tsock; struct fd_opts *opts; /* @@ -343,6 +342,7 @@ static int drain_fds(struct parasite_drain_fd *args) if (ret) return ret; + tsock = parasite_get_rpc_sock(); ret = send_fds(tsock, NULL, 0, args->fds, args->nr_fds, opts, sizeof(struct fd_opts)); if (ret) @@ -411,7 +411,7 @@ static int get_proc_fd(void) static int parasite_get_proc_fd(void) { - int fd, ret; + int fd, ret, tsock; fd = get_proc_fd(); if (fd < 0) { @@ -419,6 +419,7 @@ static int parasite_get_proc_fd(void) return -1; } + tsock = parasite_get_rpc_sock(); ret = send_fd(tsock, NULL, 0, fd); sys_close(fd); return ret; @@ -622,53 +623,7 @@ static int parasite_dump_cgroup(struct parasite_dump_cgroup_args *args) return 0; } -static int __parasite_daemon_reply_ack(unsigned int cmd, int err) -{ - struct ctl_msg m; - int ret; - - m = ctl_msg_ack(cmd, err); - ret = sys_sendto(tsock, &m, sizeof(m), 0, NULL, 0); - if (ret != sizeof(m)) { - pr_err("Sent only %d bytes while %zu expected\n", ret, sizeof(m)); - return -1; - } - - pr_debug("__sent ack msg: %d %d %d\n", - m.cmd, m.ack, m.err); - - return 0; -} - -static int __parasite_daemon_wait_msg(struct ctl_msg *m) -{ - int ret; - - pr_debug("Daemon waits for command\n"); - - while (1) { - *m = (struct ctl_msg){ }; - ret = sys_recvfrom(tsock, m, sizeof(*m), MSG_WAITALL, NULL, 0); - if (ret != sizeof(*m)) { - pr_err("Trimmed message received (%d/%d)\n", - (int)sizeof(*m), ret); - return -1; - } - - pr_debug("__fetched msg: %d %d %d\n", - m->cmd, m->ack, m->err); - return 0; - } - - return -1; -} - -static noinline void fini_sigreturn(unsigned long new_sp) -{ - ARCH_RT_SIGRETURN(new_sp, sigframe); -} - -static void parasite_cleanup(void) +void parasite_cleanup(void) { if (mprotect_args) { mprotect_args->add_prot = 0; @@ -676,27 +631,7 @@ static void parasite_cleanup(void) } } -static int fini(void) -{ - unsigned long new_sp; - - parasite_cleanup(); - - new_sp = (long)sigframe + RT_SIGFRAME_OFFSET(sigframe); - pr_debug("%ld: new_sp=%lx ip %lx\n", sys_gettid(), - new_sp, RT_SIGFRAME_REGIP(sigframe)); - - sys_close(tsock); - log_set_fd(-1); - - fini_sigreturn(new_sp); - - BUG(); - - return -1; -} - -static int parasite_daemon_cmd(int cmd, void *args) +int parasite_daemon_cmd(int cmd, void *args) { int ret; @@ -749,103 +684,7 @@ static int parasite_daemon_cmd(int cmd, void *args) return ret; } -static noinline __used int noinline parasite_daemon(void *args) -{ - struct ctl_msg m; - int ret = -1; - - pr_debug("Running daemon thread leader\n"); - - /* Reply we're alive */ - if (__parasite_daemon_reply_ack(PARASITE_CMD_INIT_DAEMON, 0)) - goto out; - - ret = 0; - - while (1) { - if (__parasite_daemon_wait_msg(&m)) - break; - - if (ret && m.cmd != PARASITE_CMD_FINI) { - pr_err("Command rejected\n"); - continue; - } - - if (m.cmd == PARASITE_CMD_FINI) - goto out; - - ret = parasite_daemon_cmd(m.cmd, args); - - if (__parasite_daemon_reply_ack(m.cmd, ret)) - break; - - if (ret) { - pr_err("Close the control socket for writing\n"); - sys_shutdown(tsock, SHUT_WR); - } - } - -out: - fini(); - - return 0; -} - -static noinline int unmap_itself(void *data) -{ - struct parasite_unmap_args *args = data; - - sys_munmap(args->parasite_start, args->parasite_len); - /* - * This call to sys_munmap must never return. Instead, the controlling - * process must trap us on the exit from munmap. - */ - - BUG(); - return -1; -} - -static noinline __used int parasite_init_daemon(void *data) -{ - struct parasite_init_args *args = data; - int ret; - - args->sigreturn_addr = fini_sigreturn; - sigframe = (void*)(uintptr_t)args->sigframe; - - ret = tsock = sys_socket(PF_UNIX, SOCK_SEQPACKET, 0); - if (tsock < 0) { - pr_err("Can't create socket: %d\n", tsock); - goto err; - } - - ret = sys_connect(tsock, (struct sockaddr *)&args->h_addr, args->h_addr_len); - if (ret < 0) { - pr_err("Can't connect the control socket\n"); - goto err; - } - - futex_set_and_wake(&args->daemon_connected, 1); - - ret = recv_fd(tsock); - if (ret >= 0) { - log_set_fd(ret); - log_set_loglevel(args->log_level); - ret = 0; - } else - goto err; - - parasite_daemon(data); - -err: - futex_set_and_wake(&args->daemon_connected, ret); - fini(); - BUG(); - - return -1; -} - -static int parasite_trap_cmd(int cmd, void *args) +int parasite_trap_cmd(int cmd, void *args) { switch (cmd) { case PARASITE_CMD_DUMP_THREAD: @@ -855,39 +694,3 @@ static int parasite_trap_cmd(int cmd, void *args) pr_err("Unknown command to parasite: %d\n", cmd); return -EINVAL; } - -#ifndef __parasite_entry -# define __parasite_entry -#endif - -int __used __parasite_entry parasite_service(unsigned int cmd, void *args) -{ - pr_info("Parasite cmd %d/%x process\n", cmd, cmd); - - switch (cmd) { - case PARASITE_CMD_INIT_DAEMON: - return parasite_init_daemon(args); - case PARASITE_CMD_UNMAP: - return unmap_itself(args); - } - - return parasite_trap_cmd(cmd, args); -} - -/* - * Mainally, -fstack-protector is disabled for parasite. - * But we share some object files, compiled for CRIU with parasite. - * Those files (like cpu.c) may be compiled with stack protector - * support. We can't use gcc-ld provided stackprotector callback, - * as Glibc is unmapped. Let's just try to cure application in - * case of stack smashing in parasite. - */ -void __stack_chk_fail(void) -{ - /* - * Smash didn't happen in printing part, as it's not shared - * with CRIU, therefore compiled with -fnostack-protector. - */ - pr_err("Stack smash detected in parasite\n"); - fini(); -} From 2a014c09ebc8d2bff430ecdd30b072e665ac7bcf Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 2 Nov 2016 20:02:17 +0300 Subject: [PATCH 0195/4375] criu: Call compel with debug level when building blobs Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 59dea726c..9bf5a4762 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -162,6 +162,7 @@ $(eval $(call map,gen-rule-built-in.bin.o,$(parasite_target))) $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host $(call msg-gen, $@) $(Q) $(SRC_DIR)/compel/compel-host piegen -f $< \ + -l 4 \ -v $(call target-name,$@)_relocs \ -p $(call target-name,$@)_blob_offset__ \ -s $(call target-name,$@)_blob \ From 2e944f721a5f6f957c1c0248869f5bbf53fcd210 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 3 Nov 2016 02:08:14 +0300 Subject: [PATCH 0196/4375] infect: Add log_fd on ictx This is the descriptor to be used by parasite code for messages. In pure compel environment this will have to be some file provided by caller or a pipe from which libcompel will pull messages. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/infect.h | 2 ++ criu/infect.c | 6 +++++- criu/parasite-syscall.c | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/criu/include/infect.h b/criu/include/infect.h index fc4f949f9..3f3913ac3 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -109,6 +109,8 @@ struct infect_ctx { void (*child_handler)(int, siginfo_t *, void *); /* hander for SIGCHLD deaths */ open_proc_fn open_proc; + + int log_fd; /* fd for parasite code to send messages to */ }; extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *); diff --git a/criu/infect.c b/criu/infect.c index 75d525858..73888f176 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -575,7 +575,7 @@ static int parasite_init_daemon(struct parasite_ctl *ctl) if (accept_tsock(ctl) < 0) goto err; - if (compel_util_send_fd(ctl, log_get_fd())) + if (compel_util_send_fd(ctl, ctl->ictx.log_fd)) goto err; pr_info("Wait for parasite being daemonized...\n"); @@ -768,6 +768,9 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l int ret; unsigned long p, map_exchange_size, parasite_size = 0; + if (ctl->ictx.log_fd < 0) + goto err; + if (!arch_can_dump_task(ctl)) goto err; @@ -858,6 +861,7 @@ struct parasite_ctl *compel_prepare(int pid) } ctl->tsock = -1; + ctl->ictx.log_fd = -1; if (compel_prepare_thread(pid, &ctl->orig)) goto err; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 59d067351..a75d2ffe7 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -562,6 +562,8 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, if (kdat.has_compat_sigreturn) ictx->flags |= INFECT_HAS_COMPAT_SIGRETURN; + ictx->log_fd = log_get_fd(); + parasite_ensure_args_size(dump_pages_args_size(vma_area_list)); parasite_ensure_args_size(aio_rings_args_size(vma_area_list)); From 901ccfb8caf4ff16387e114304d329cd32c1ca18 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 3 Nov 2016 20:29:58 +0300 Subject: [PATCH 0197/4375] infect-rpc: Split into priv and uapi parts Some pieces from infect-rpc are used by criu's pie code which will soon be moved into compel std plugin itself, so prepare for this. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/infect-rpc.h | 46 +---------------------------------- criu/include/rpc-pie-priv.h | 48 +++++++++++++++++++++++++++++++++++++ criu/infect-rpc.c | 3 +++ criu/infect.c | 1 + criu/pie/infect.c | 1 + 5 files changed, 54 insertions(+), 45 deletions(-) create mode 100644 criu/include/rpc-pie-priv.h diff --git a/criu/include/infect-rpc.h b/criu/include/infect-rpc.h index 9569b6794..0176c1142 100644 --- a/criu/include/infect-rpc.h +++ b/criu/include/infect-rpc.h @@ -11,51 +11,7 @@ extern int compel_rpc_call(unsigned int cmd, struct parasite_ctl *ctl); extern int compel_rpc_call_sync(unsigned int cmd, struct parasite_ctl *ctl); extern int compel_rpc_sock(struct parasite_ctl *ctl); -struct ctl_msg { - uint32_t cmd; /* command itself */ - uint32_t ack; /* ack on command */ - int32_t err; /* error code on reply */ -}; - -#define ctl_msg_cmd(_cmd) \ - (struct ctl_msg){.cmd = _cmd, } - -#define ctl_msg_ack(_cmd, _err) \ - (struct ctl_msg){.cmd = _cmd, .ack = _cmd, .err = _err, } - -/* - * NOTE: each command's args should be arch-independed sized. - * If you want to use one of the standard types, declare - * alternative type for compatible tasks in parasite-compat.h - */ -enum { - PARASITE_CMD_IDLE = 0, - PARASITE_CMD_ACK, - - PARASITE_CMD_INIT_DAEMON, - PARASITE_CMD_UNMAP, - - /* - * This must be greater than INITs. - */ - PARASITE_CMD_FINI, - - PARASITE_USER_CMDS, -}; - -struct parasite_init_args { - int32_t h_addr_len; - struct sockaddr_un h_addr; - int32_t log_level; - uint64_t sigreturn_addr; - uint64_t sigframe; /* pointer to sigframe */ - futex_t daemon_connected; -}; - -struct parasite_unmap_args { - uint64_t parasite_start; - uint64_t parasite_len; -}; +#define PARASITE_USER_CMDS 64 #endif diff --git a/criu/include/rpc-pie-priv.h b/criu/include/rpc-pie-priv.h new file mode 100644 index 000000000..3d9091159 --- /dev/null +++ b/criu/include/rpc-pie-priv.h @@ -0,0 +1,48 @@ +#ifndef __COMPEL_RPC_H__ +#define __COMPEL_RPC_H__ +struct ctl_msg { + uint32_t cmd; /* command itself */ + uint32_t ack; /* ack on command */ + int32_t err; /* error code on reply */ +}; + +#define ctl_msg_cmd(_cmd) \ + (struct ctl_msg){.cmd = _cmd, } + +#define ctl_msg_ack(_cmd, _err) \ + (struct ctl_msg){.cmd = _cmd, .ack = _cmd, .err = _err, } + +/* + * NOTE: each command's args should be arch-independed sized. + * If you want to use one of the standard types, declare + * alternative type for compatible tasks in parasite-compat.h + */ +enum { + PARASITE_CMD_IDLE = 0, + PARASITE_CMD_ACK, + + PARASITE_CMD_INIT_DAEMON, + PARASITE_CMD_UNMAP, + + /* + * This must be greater than INITs. + */ + PARASITE_CMD_FINI, + + __PARASITE_END_CMDS, +}; + +struct parasite_init_args { + int32_t h_addr_len; + struct sockaddr_un h_addr; + int32_t log_level; + uint64_t sigreturn_addr; + uint64_t sigframe; /* pointer to sigframe */ + futex_t daemon_connected; +}; + +struct parasite_unmap_args { + uint64_t parasite_start; + uint64_t parasite_len; +}; +#endif diff --git a/criu/infect-rpc.c b/criu/infect-rpc.c index 0994bcb35..265a4ad2f 100644 --- a/criu/infect-rpc.c +++ b/criu/infect-rpc.c @@ -6,11 +6,14 @@ #include "infect.h" #include "infect-priv.h" #include "infect-rpc.h" +#include "rpc-pie-priv.h" static int __parasite_send_cmd(int sockfd, struct ctl_msg *m) { int ret; + BUILD_BUG_ON(PARASITE_USER_CMDS < __PARASITE_END_CMDS); + ret = send(sockfd, m, sizeof(*m), 0); if (ret == -1) { pr_perror("Failed to send command %d to daemon", m->cmd); diff --git a/criu/infect.c b/criu/infect.c index 73888f176..da14411c5 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -27,6 +27,7 @@ #include "infect-rpc.h" #include "infect-priv.h" #include "infect-util.h" +#include "rpc-pie-priv.h" #define UNIX_PATH_MAX (sizeof(struct sockaddr_un) - \ (size_t)((struct sockaddr_un *) 0)->sun_path) diff --git a/criu/pie/infect.c b/criu/pie/infect.c index f24336932..2a4cf40f8 100644 --- a/criu/pie/infect.c +++ b/criu/pie/infect.c @@ -8,6 +8,7 @@ #include "sigframe.h" #include "infect-rpc.h" #include "infect-pie.h" +#include "rpc-pie-priv.h" static int tsock = -1; From e9700c4ff495e63c9a411d16015aeddb6b8105ba Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 4 Nov 2016 00:30:00 +0300 Subject: [PATCH 0198/4375] infect: Introduce and use parasite_blob_desc The _desc is to describe where libcompel should task parasite code from. For now the parasite is taken as piece of memory, but more ways to load the code will come soon. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/infect-priv.h | 2 ++ criu/include/infect.h | 14 +++++++++++ criu/infect.c | 48 +++++++++++--------------------------- criu/parasite-syscall.c | 36 ++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 34 deletions(-) diff --git a/criu/include/infect-priv.h b/criu/include/infect-priv.h index c994981d1..db5259c2c 100644 --- a/criu/include/infect-priv.h +++ b/criu/include/infect-priv.h @@ -32,6 +32,8 @@ struct parasite_ctl { void *addr_args; /* address for arguments */ unsigned long args_size; int tsock; /* transport socket for transferring fds */ + + struct parasite_blob_desc pblob; }; #define MEMFD_FNAME "CRIUMFD" diff --git a/criu/include/infect.h b/criu/include/infect.h index 3f3913ac3..71255b54c 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -3,6 +3,7 @@ #include "asm/infect-types.h" #include +#include #define PARASITE_START_AREA_MIN (4096) @@ -120,6 +121,19 @@ extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *); #define INFECT_NO_BREAKPOINTS 0x4 /* no breakpoints in pie tracking */ #define INFECT_HAS_COMPAT_SIGRETURN 0x8 +struct parasite_blob_desc { + const void *mem; + size_t bsize; /* size of the blob */ + size_t size; /* size of the blob with relocs */ + unsigned long parasite_ip_off; + unsigned long addr_cmd_off; + unsigned long addr_arg_off; + compel_reloc_t *relocs; + unsigned int nr_relocs; +}; + +extern struct parasite_blob_desc *compel_parasite_blob_desc(struct parasite_ctl *); + typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); extern int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *); diff --git a/criu/infect.c b/criu/infect.c index da14411c5..d77f85097 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -10,7 +10,6 @@ #include #include "pie-relocs.h" -#include "parasite-blob.h" #include "criu-log.h" #include "common/bug.h" #include "common/xmalloc.h" @@ -743,27 +742,6 @@ int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size) return ret; } -/* the parasite prefix is added by gen_offsets.sh */ -#define __pblob_offset(ptype, symbol) \ - parasite_ ## ptype ## _blob_offset__ ## symbol -#define parasite_sym(pblob, ptype, symbol) \ - ((void *)(pblob) + __pblob_offset(ptype, symbol)) - -#define init_parasite_ctl(ctl, blob_type) \ - do { \ - memcpy(ctl->local_map, parasite_##blob_type##_blob, \ - sizeof(parasite_##blob_type##_blob)); \ - ELF_RELOCS_APPLY(parasite_##blob_type, \ - ctl->local_map, ctl->remote_map); \ - /* Setup the rest of a control block */ \ - ctl->parasite_ip = (unsigned long)parasite_sym(ctl->remote_map, \ - blob_type, __export_parasite_head_start); \ - ctl->addr_cmd = parasite_sym(ctl->local_map, blob_type, \ - __export_parasite_cmd); \ - ctl->addr_args = parasite_sym(ctl->local_map, blob_type, \ - __export_parasite_args); \ - } while (0) - int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size) { int ret; @@ -782,12 +760,7 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l * without using ptrace at all. */ - if (compel_mode_native(ctl)) - parasite_size = pie_size(parasite_native); -#ifdef CONFIG_COMPAT - else - parasite_size = pie_size(parasite_compat); -#endif + parasite_size = ctl->pblob.size; ctl->args_size = round_up(args_size, PAGE_SIZE); parasite_size += ctl->args_size; @@ -803,12 +776,14 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map); - if (compel_mode_native(ctl)) - init_parasite_ctl(ctl, native); -#ifdef CONFIG_COMPAT - else - init_parasite_ctl(ctl, compat); -#endif + ctl->parasite_ip = (unsigned long)(ctl->remote_map + ctl->pblob.parasite_ip_off); + ctl->addr_cmd = ctl->local_map + ctl->pblob.addr_cmd_off; + ctl->addr_args = ctl->local_map + ctl->pblob.addr_arg_off; + + memcpy(ctl->local_map, ctl->pblob.mem, ctl->pblob.size); + if (ctl->pblob.nr_relocs) + elf_relocs_apply(ctl->local_map, ctl->remote_map, ctl->pblob.bsize, + ctl->pblob.relocs, ctl->pblob.nr_relocs); p = parasite_size; @@ -1252,3 +1227,8 @@ struct infect_ctx *compel_infect_ctx(struct parasite_ctl *ctl) { return &ctl->ictx; } + +struct parasite_blob_desc *compel_parasite_blob_desc(struct parasite_ctl *ctl) +{ + return &ctl->pblob; +} diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index a75d2ffe7..43d6efbe0 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -5,6 +5,7 @@ #include #include +#include "common/compiler.h" #include "types.h" #include "protobuf.h" #include "images/sa.pb-c.h" @@ -43,6 +44,7 @@ #include "infect.h" #include "infect-rpc.h" +#include "parasite-blob.h" unsigned long get_exec_start(struct vm_area_list *vmas) { @@ -522,11 +524,37 @@ static int make_sigframe(void *arg, struct rt_sigframe *sf, struct rt_sigframe * return construct_sigframe(sf, rtsf, bs, (CoreEntry *)arg); } +/* the parasite prefix is added by gen_offsets.sh */ +#define pblob_offset(ptype, symbol) \ + parasite_ ## ptype ## _blob_offset__ ## symbol + +#ifdef CONFIG_PIEGEN +#define init_blob_relocs(bdesc, blob_type) \ + do { \ + bdesc->relocs = parasite_##blob_type##_relocs; \ + bdesc->nr_relocs = ARRAY_SIZE(parasite_##blob_type##_relocs); \ + } while (0) +#else +#define init_blob_relocs(bdesc, blob_type) +#endif + +#define init_blob_desc(bdesc, blob_type) do { \ + pbd->size = pie_size(parasite_##blob_type); \ + bdesc->mem = parasite_##blob_type##_blob; \ + bdesc->bsize = sizeof(parasite_##blob_type##_blob); \ + /* Setup the rest of a control block */ \ + bdesc->parasite_ip_off = pblob_offset(blob_type, __export_parasite_head_start); \ + bdesc->addr_cmd_off = pblob_offset(blob_type, __export_parasite_cmd); \ + bdesc->addr_arg_off = pblob_offset(blob_type, __export_parasite_args); \ + init_blob_relocs(bdesc, blob_type); \ + } while (0) + struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, struct vm_area_list *vma_area_list) { struct parasite_ctl *ctl; struct infect_ctx *ictx; + struct parasite_blob_desc *pbd; unsigned long p; BUG_ON(item->threads[0].real != pid); @@ -564,6 +592,14 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ictx->log_fd = log_get_fd(); + pbd = compel_parasite_blob_desc(ctl); + if (compel_mode_native(ctl)) + init_blob_desc(pbd, native); +#ifdef CONFIG_COMPAT + else + init_blob_desc(pbd, compat); +#endif + parasite_ensure_args_size(dump_pages_args_size(vma_area_list)); parasite_ensure_args_size(aio_rings_args_size(vma_area_list)); From fd814de1d3f7b0971f8ca55e761d5c385902a5d3 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 7 Nov 2016 01:20:46 +0300 Subject: [PATCH 0199/4375] infect: Move compel_relocs_apply into engine It will move into compel on a final pass. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/Makefile.crtools | 1 - criu/include/infect.h | 2 ++ criu/infect.c | 33 ++++++++++++++++++++++++++--- criu/pie/pie-relocs.c | 49 ------------------------------------------- criu/pie/pie-relocs.h | 4 +--- 5 files changed, 33 insertions(+), 56 deletions(-) delete mode 100644 criu/pie/pie-relocs.c diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 278760b54..c9dbceb08 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -50,7 +50,6 @@ obj-y += page-pipe.o obj-y += pagemap.o obj-y += page-xfer.o obj-y += parasite-syscall.o -obj-y += pie/pie-relocs.o obj-y += pie-util-fd.o obj-y += pie-util.o obj-y += pipes.o diff --git a/criu/include/infect.h b/criu/include/infect.h index 71255b54c..760bdb80d 100644 --- a/criu/include/infect.h +++ b/criu/include/infect.h @@ -137,4 +137,6 @@ extern struct parasite_blob_desc *compel_parasite_blob_desc(struct parasite_ctl typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); extern int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *); +extern void compel_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *elf_relocs, size_t nr_relocs); + #endif diff --git a/criu/infect.c b/criu/infect.c index d77f85097..4c6c4927f 100644 --- a/criu/infect.c +++ b/criu/infect.c @@ -9,7 +9,6 @@ #include #include -#include "pie-relocs.h" #include "criu-log.h" #include "common/bug.h" #include "common/xmalloc.h" @@ -730,6 +729,34 @@ err_cure: return -1; } +void compel_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *elf_relocs, size_t nr_relocs) +{ + size_t i, j; + + for (i = 0, j = 0; i < nr_relocs; i++) { + if (elf_relocs[i].type & COMPEL_TYPE_LONG) { + long *where = mem + elf_relocs[i].offset; + long *p = mem + size; + + if (elf_relocs[i].type & COMPEL_TYPE_GOTPCREL) { + int *value = (int *)where; + int rel; + + p[j] = (long)vbase + elf_relocs[i].value; + rel = (unsigned)((void *)&p[j] - (void *)mem) - elf_relocs[i].offset + elf_relocs[i].addend; + + *value = rel; + j++; + } else + *where = elf_relocs[i].value + elf_relocs[i].addend + (unsigned long)vbase; + } else if (elf_relocs[i].type & COMPEL_TYPE_INT) { + int *where = (mem + elf_relocs[i].offset); + *where = elf_relocs[i].value + elf_relocs[i].addend + (unsigned long)vbase; + } else + BUG(); + } +} + int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size) { int ret; @@ -782,8 +809,8 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l memcpy(ctl->local_map, ctl->pblob.mem, ctl->pblob.size); if (ctl->pblob.nr_relocs) - elf_relocs_apply(ctl->local_map, ctl->remote_map, ctl->pblob.bsize, - ctl->pblob.relocs, ctl->pblob.nr_relocs); + compel_relocs_apply(ctl->local_map, ctl->remote_map, ctl->pblob.bsize, + ctl->pblob.relocs, ctl->pblob.nr_relocs); p = parasite_size; diff --git a/criu/pie/pie-relocs.c b/criu/pie/pie-relocs.c deleted file mode 100644 index f0802a0a2..000000000 --- a/criu/pie/pie-relocs.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "asm-generic/int.h" - -#include "log.h" - -#include "common/compiler.h" -#include -#include "common/bug.h" - -__maybe_unused void elf_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *elf_relocs, size_t nr_relocs) -{ - size_t i, j; - - for (i = 0, j = 0; i < nr_relocs; i++) { - if (elf_relocs[i].type & COMPEL_TYPE_LONG) { - long *where = mem + elf_relocs[i].offset; - long *p = mem + size; - - if (elf_relocs[i].type & COMPEL_TYPE_GOTPCREL) { - int *value = (int *)where; - int rel; - - p[j] = (long)vbase + elf_relocs[i].value; - rel = (unsigned)((void *)&p[j] - (void *)mem) - elf_relocs[i].offset + elf_relocs[i].addend; - - *value = rel; - j++; - } else - *where = elf_relocs[i].value + elf_relocs[i].addend + (unsigned long)vbase; - } else if (elf_relocs[i].type & COMPEL_TYPE_INT) { - int *where = (mem + elf_relocs[i].offset); - *where = elf_relocs[i].value + elf_relocs[i].addend + (unsigned long)vbase; - } else - BUG(); - } -} diff --git a/criu/pie/pie-relocs.h b/criu/pie/pie-relocs.h index 2fc5f6a33..442e70d13 100644 --- a/criu/pie/pie-relocs.h +++ b/criu/pie/pie-relocs.h @@ -8,12 +8,10 @@ #ifdef CONFIG_PIEGEN -extern __maybe_unused void elf_relocs_apply(void *mem, void *vbase, size_t size, - compel_reloc_t *elf_relocs, size_t nr_relocs); #define pie_size(__pie_name) (round_up(sizeof(__pie_name##_blob) + \ __pie_name ## _nr_gotpcrel * sizeof(long), page_size())) #define ELF_RELOCS_APPLY(__pie_name, __mem, __vbase) \ - elf_relocs_apply(__mem, __vbase, sizeof(__pie_name##_blob), \ + compel_relocs_apply(__mem, __vbase, sizeof(__pie_name##_blob), \ __pie_name##_relocs, ARRAY_SIZE(__pie_name##_relocs)) #else From 51092282de6daca5cc8927c88b52e58314d40c00 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 28 Oct 2016 18:11:31 +0300 Subject: [PATCH 0200/4375] compel: Move sigframe code into compel We use it in both -- parasite engine and criu, so export them as well. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- .../arch/aarch64/src/lib/include/uapi}/asm/sigframe.h | 2 +- .../arch/arm/src/lib/include/uapi}/asm/sigframe.h | 2 +- .../arch/ppc64/src/lib/include/uapi}/asm/sigframe.h | 2 +- .../arch/x86/src/lib/include/uapi}/asm/sigframe.h | 2 +- {criu/include => compel/include/uapi}/sigframe-common.h | 0 criu/arch/aarch64/include/asm/restorer.h | 2 +- criu/arch/arm/include/asm/restorer.h | 2 +- criu/arch/ppc64/include/asm/restorer.h | 2 +- criu/arch/x86/include/asm/restorer.h | 2 +- criu/include/sigframe.h | 2 +- 10 files changed, 9 insertions(+), 9 deletions(-) rename {criu/arch/aarch64/include => compel/arch/aarch64/src/lib/include/uapi}/asm/sigframe.h (97%) rename {criu/arch/arm/include => compel/arch/arm/src/lib/include/uapi}/asm/sigframe.h (98%) rename {criu/arch/ppc64/include => compel/arch/ppc64/src/lib/include/uapi}/asm/sigframe.h (98%) rename {criu/arch/x86/include => compel/arch/x86/src/lib/include/uapi}/asm/sigframe.h (99%) rename {criu/include => compel/include/uapi}/sigframe-common.h (100%) diff --git a/criu/arch/aarch64/include/asm/sigframe.h b/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h similarity index 97% rename from criu/arch/aarch64/include/asm/sigframe.h rename to compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h index 3e8d63fb8..c890d1034 100644 --- a/criu/arch/aarch64/include/asm/sigframe.h +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h @@ -21,7 +21,7 @@ struct aux_context { // XXX: the idetifier rt_sigcontext is expected to be struct by the CRIU code #define rt_sigcontext sigcontext -#include "sigframe-common.h" +#include /* Copied from the kernel source arch/arm64/kernel/signal.c */ diff --git a/criu/arch/arm/include/asm/sigframe.h b/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h similarity index 98% rename from criu/arch/arm/include/asm/sigframe.h rename to compel/arch/arm/src/lib/include/uapi/asm/sigframe.h index c9433e07b..65ae8a8b9 100644 --- a/criu/arch/arm/include/asm/sigframe.h +++ b/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h @@ -51,7 +51,7 @@ struct aux_sigframe { unsigned long end_magic; } __attribute__((aligned(8))); -#include "sigframe-common.h" +#include struct sigframe { struct rt_ucontext uc; diff --git a/criu/arch/ppc64/include/asm/sigframe.h b/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h similarity index 98% rename from criu/arch/ppc64/include/asm/sigframe.h rename to compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h index 498bf8a8c..bfaee8784 100644 --- a/criu/arch/ppc64/include/asm/sigframe.h +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h @@ -17,7 +17,7 @@ // XXX: the idetifier rt_sigcontext is expected to be struct by the CRIU code #define rt_sigcontext sigcontext -#include "sigframe-common.h" +#include #define RT_SIGFRAME_OFFSET(rt_sigframe) 0 diff --git a/criu/arch/x86/include/asm/sigframe.h b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h similarity index 99% rename from criu/arch/x86/include/asm/sigframe.h rename to compel/arch/x86/src/lib/include/uapi/asm/sigframe.h index 8e33ce6db..3caed449c 100644 --- a/criu/arch/x86/include/asm/sigframe.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h @@ -66,7 +66,7 @@ struct rt_sigcontext_32 { uint32_t cr2; }; -#include "sigframe-common.h" +#include /* * XXX: move declarations to generic sigframe.h or sigframe-compat.h diff --git a/criu/include/sigframe-common.h b/compel/include/uapi/sigframe-common.h similarity index 100% rename from criu/include/sigframe-common.h rename to compel/include/uapi/sigframe-common.h diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h index b842a74ef..b5dd42e54 100644 --- a/criu/arch/aarch64/include/asm/restorer.h +++ b/criu/arch/aarch64/include/asm/restorer.h @@ -7,7 +7,7 @@ #include "asm/types.h" #include "images/core.pb-c.h" -#include "sigframe.h" +#include #define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \ thread_args, clone_restore_fn) \ diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h index 536286d4c..7e4b09c89 100644 --- a/criu/arch/arm/include/asm/restorer.h +++ b/criu/arch/arm/include/asm/restorer.h @@ -4,7 +4,7 @@ #include "asm/types.h" #include "images/core.pb-c.h" -#include "sigframe.h" +#include #define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \ thread_args, clone_restore_fn) \ diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h index e99f2751b..399bdfb52 100644 --- a/criu/arch/ppc64/include/asm/restorer.h +++ b/criu/arch/ppc64/include/asm/restorer.h @@ -7,7 +7,7 @@ #include "asm/types.h" #include "asm/infect-types.h" -#include "sigframe.h" +#include /* * Clone trampoline diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index 0b081bdcd..e5636aef5 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -6,7 +6,7 @@ #include "images/core.pb-c.h" #include -#include "sigframe.h" +#include #ifdef CONFIG_COMPAT extern void *alloc_compat_syscall_stack(void); diff --git a/criu/include/sigframe.h b/criu/include/sigframe.h index bdda22262..b63d9f0e5 100644 --- a/criu/include/sigframe.h +++ b/criu/include/sigframe.h @@ -5,7 +5,7 @@ #ifndef __CR_SIGFRAME_H__ #define __CR_SIGFRAME_H__ -#include "asm/sigframe.h" +#include #include "images/core.pb-c.h" extern int construct_sigframe(struct rt_sigframe *sigframe, From cbe24fb9c438f147fdd70c41f2a66844457ffed4 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 31 Oct 2016 15:06:48 +0300 Subject: [PATCH 0201/4375] compel: Move in parasite engine This is the final patch in the series. It does a bunch of renames and fixes headers respectively. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/Makefile | 5 +++++ .../include/{ptrace.h => uapi/asm/breakpoints.h} | 4 ++-- .../src/lib/include/uapi}/asm/infect-types.h | 2 -- .../arch/aarch64/src/lib}/infect.c | 8 +++----- .../include/{ptrace.h => uapi/asm/breakpoints.h} | 4 ++-- .../arm/src/lib/include/uapi}/asm/infect-types.h | 2 -- .../arch/arm/src/lib/include/uapi/asm/sigframe.h | 2 ++ .../arch/arm => compel/arch/arm/src/lib}/infect.c | 8 +++----- .../include/{ptrace.h => uapi/asm/breakpoints.h} | 4 ++-- .../src/lib/include/uapi}/asm/infect-types.h | 0 .../ppc64 => compel/arch/ppc64/src/lib}/infect.c | 12 ++++++------ .../include/{ptrace.h => uapi/asm/breakpoints.h} | 4 ++-- .../x86/src/lib/include/uapi}/asm/infect-types.h | 0 .../arch/x86 => compel/arch/x86/src/lib}/infect.c | 7 ++++--- {criu => compel}/include/infect-priv.h | 0 {criu => compel}/include/rpc-pie-priv.h | 0 compel/include/uapi/compel.h | 6 ++++++ .../include => compel/include/uapi}/infect-rpc.h | 0 .../include => compel/include/uapi}/infect-util.h | 0 {criu/include => compel/include/uapi}/infect.h | 7 ++++++- {criu/include => compel/include/uapi}/ptrace.h | 9 +++++---- {criu => compel/src/lib}/infect-rpc.c | 0 {criu => compel/src/lib}/infect-util.c | 4 ++-- {criu => compel/src/lib}/infect.c | 15 ++++++++------- {criu => compel/src/lib}/ptrace.c | 12 +++++------- criu/Makefile.crtools | 4 ---- criu/aio.c | 3 +-- criu/arch/aarch64/Makefile | 1 - criu/arch/aarch64/crtools.c | 6 +++--- criu/arch/aarch64/sigframe.c | 2 +- criu/arch/arm/Makefile | 1 - criu/arch/arm/crtools.c | 8 ++++---- criu/arch/arm/sigframe.c | 2 +- criu/arch/ppc64/Makefile | 1 - criu/arch/ppc64/crtools.c | 4 ++-- criu/arch/ppc64/include/asm/restorer.h | 2 +- criu/arch/x86/Makefile | 1 - criu/arch/x86/crtools.c | 4 ++-- criu/arch/x86/sys-exec-tbl.c | 2 +- criu/cr-check.c | 2 +- criu/cr-dump.c | 1 - criu/cr-exec.c | 3 +-- criu/cr-restore.c | 6 ++---- criu/include/proc_parse.h | 2 +- criu/include/ptrace-compat.h | 8 +++++--- criu/include/types.h | 2 +- criu/mem.c | 4 +--- criu/parasite-syscall.c | 4 +++- criu/pie/infect.c | 2 +- criu/pie/parasite.c | 2 -- criu/seccomp.c | 2 +- criu/seize.c | 4 ++-- criu/vdso.c | 3 +-- 53 files changed, 99 insertions(+), 102 deletions(-) rename compel/arch/aarch64/src/lib/include/{ptrace.h => uapi/asm/breakpoints.h} (74%) rename {criu/arch/aarch64/include => compel/arch/aarch64/src/lib/include/uapi}/asm/infect-types.h (98%) rename {criu/arch/aarch64 => compel/arch/aarch64/src/lib}/infect.c (94%) rename compel/arch/arm/src/lib/include/{ptrace.h => uapi/asm/breakpoints.h} (74%) rename {criu/arch/arm/include => compel/arch/arm/src/lib/include/uapi}/asm/infect-types.h (99%) rename {criu/arch/arm => compel/arch/arm/src/lib}/infect.c (94%) rename compel/arch/ppc64/src/lib/include/{ptrace.h => uapi/asm/breakpoints.h} (75%) rename {criu/arch/ppc64/include => compel/arch/ppc64/src/lib/include/uapi}/asm/infect-types.h (100%) rename {criu/arch/ppc64 => compel/arch/ppc64/src/lib}/infect.c (98%) rename compel/arch/x86/src/lib/include/{ptrace.h => uapi/asm/breakpoints.h} (68%) rename {criu/arch/x86/include => compel/arch/x86/src/lib/include/uapi}/asm/infect-types.h (100%) rename {criu/arch/x86 => compel/arch/x86/src/lib}/infect.c (98%) rename {criu => compel}/include/infect-priv.h (100%) rename {criu => compel}/include/rpc-pie-priv.h (100%) rename {criu/include => compel/include/uapi}/infect-rpc.h (100%) rename {criu/include => compel/include/uapi}/infect-util.h (100%) rename {criu/include => compel/include/uapi}/infect.h (97%) rename {criu/include => compel/include/uapi}/ptrace.h (91%) rename {criu => compel/src/lib}/infect-rpc.c (100%) rename {criu => compel/src/lib}/infect-util.c (87%) rename {criu => compel/src/lib}/infect.c (99%) rename {criu => compel/src/lib}/ptrace.c (93%) diff --git a/compel/Makefile b/compel/Makefile index d421bc078..ad98e9d6d 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -23,6 +23,11 @@ lib-y += src/lib/log.o host-lib-y += src/lib/log.o lib-y += arch/$(ARCH)/src/lib/cpu.o +lib-y += arch/$(ARCH)/src/lib/infect.o +lib-y += src/lib/infect-rpc.o +lib-y += src/lib/infect-util.o +lib-y += src/lib/infect.o +lib-y += src/lib/ptrace.o ifeq ($(ARCH),x86) lib-y += src/lib/handle-elf-32.o diff --git a/compel/arch/aarch64/src/lib/include/ptrace.h b/compel/arch/aarch64/src/lib/include/uapi/asm/breakpoints.h similarity index 74% rename from compel/arch/aarch64/src/lib/include/ptrace.h rename to compel/arch/aarch64/src/lib/include/uapi/asm/breakpoints.h index e18454df2..5f090490d 100644 --- a/compel/arch/aarch64/src/lib/include/ptrace.h +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/breakpoints.h @@ -1,5 +1,5 @@ -#ifndef __COMPEL_PTRACE_H__ -#define __COMPEL_PTRACE_H__ +#ifndef __COMPEL_BREAKPOINTS_H__ +#define __COMPEL_BREAKPOINTS_H__ #define ARCH_SI_TRAP TRAP_BRKPT static inline int ptrace_set_breakpoint(pid_t pid, void *addr) diff --git a/criu/arch/aarch64/include/asm/infect-types.h b/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h similarity index 98% rename from criu/arch/aarch64/include/asm/infect-types.h rename to compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h index ff9e53e7c..714881c57 100644 --- a/criu/arch/aarch64/include/asm/infect-types.h +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h @@ -7,8 +7,6 @@ #include #include "common/page.h" -#include "page.h" - #define SIGMAX 64 #define SIGMAX_OLD 31 diff --git a/criu/arch/aarch64/infect.c b/compel/arch/aarch64/src/lib/infect.c similarity index 94% rename from criu/arch/aarch64/infect.c rename to compel/arch/aarch64/src/lib/infect.c index aeb734781..fceea2816 100644 --- a/criu/arch/aarch64/infect.c +++ b/compel/arch/aarch64/src/lib/infect.c @@ -2,12 +2,10 @@ #include #include #include -#include "asm/parasite-syscall.h" #include -#include "asm/types.h" -#include "criu-log.h" -#include "parasite-syscall.h" -#include "compel/include/errno.h" +#include "uapi/compel/asm/infect-types.h" +#include "log.h" +#include "errno.h" #include "infect.h" #include "infect-priv.h" diff --git a/compel/arch/arm/src/lib/include/ptrace.h b/compel/arch/arm/src/lib/include/uapi/asm/breakpoints.h similarity index 74% rename from compel/arch/arm/src/lib/include/ptrace.h rename to compel/arch/arm/src/lib/include/uapi/asm/breakpoints.h index e18454df2..5f090490d 100644 --- a/compel/arch/arm/src/lib/include/ptrace.h +++ b/compel/arch/arm/src/lib/include/uapi/asm/breakpoints.h @@ -1,5 +1,5 @@ -#ifndef __COMPEL_PTRACE_H__ -#define __COMPEL_PTRACE_H__ +#ifndef __COMPEL_BREAKPOINTS_H__ +#define __COMPEL_BREAKPOINTS_H__ #define ARCH_SI_TRAP TRAP_BRKPT static inline int ptrace_set_breakpoint(pid_t pid, void *addr) diff --git a/criu/arch/arm/include/asm/infect-types.h b/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h similarity index 99% rename from criu/arch/arm/include/asm/infect-types.h rename to compel/arch/arm/src/lib/include/uapi/asm/infect-types.h index 91b4c1e98..9c2092e5d 100644 --- a/criu/arch/arm/include/asm/infect-types.h +++ b/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h @@ -5,8 +5,6 @@ #include #include "common/page.h" -#include "page.h" - #define SIGMAX 64 #define SIGMAX_OLD 31 diff --git a/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h b/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h index 65ae8a8b9..3e7bc0104 100644 --- a/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h @@ -1,6 +1,8 @@ #ifndef UAPI_COMPEL_ASM_SIGFRAME_H__ #define UAPI_COMPEL_ASM_SIGFRAME_H__ +#include + /* Copied from the Linux kernel header arch/arm/include/asm/sigcontext.h */ struct rt_sigcontext { diff --git a/criu/arch/arm/infect.c b/compel/arch/arm/src/lib/infect.c similarity index 94% rename from criu/arch/arm/infect.c rename to compel/arch/arm/src/lib/infect.c index b22e98d9c..b440ff736 100644 --- a/criu/arch/arm/infect.c +++ b/compel/arch/arm/src/lib/infect.c @@ -1,12 +1,10 @@ #include #include -#include "asm/parasite-syscall.h" #include #include -#include "asm/types.h" -#include "criu-log.h" -#include "parasite-syscall.h" -#include "compel/include/errno.h" +#include "uapi/compel/asm/infect-types.h" +#include "log.h" +#include "errno.h" #include "infect.h" #include "infect-priv.h" diff --git a/compel/arch/ppc64/src/lib/include/ptrace.h b/compel/arch/ppc64/src/lib/include/uapi/asm/breakpoints.h similarity index 75% rename from compel/arch/ppc64/src/lib/include/ptrace.h rename to compel/arch/ppc64/src/lib/include/uapi/asm/breakpoints.h index 0274c2675..1ab89af76 100644 --- a/compel/arch/ppc64/src/lib/include/ptrace.h +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/breakpoints.h @@ -1,5 +1,5 @@ -#ifndef __COMPEL_PTRACE_H__ -#define __COMPEL_PTRACE_H__ +#ifndef __COMPEL_BREAKPOINTS_H__ +#define __COMPEL_BREAKPOINTS_H__ #define ARCH_SI_TRAP TRAP_BRKPT static inline int ptrace_set_breakpoint(pid_t pid, void *addr) diff --git a/criu/arch/ppc64/include/asm/infect-types.h b/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h similarity index 100% rename from criu/arch/ppc64/include/asm/infect-types.h rename to compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h diff --git a/criu/arch/ppc64/infect.c b/compel/arch/ppc64/src/lib/infect.c similarity index 98% rename from criu/arch/ppc64/infect.c rename to compel/arch/ppc64/src/lib/infect.c index d9a356a5e..959098b8c 100644 --- a/criu/arch/ppc64/infect.c +++ b/compel/arch/ppc64/src/lib/infect.c @@ -1,13 +1,13 @@ #include #include #include +#include #include #include -#include "asm/types.h" -#include "ptrace.h" -#include "parasite-syscall.h" -#include "compel/include/errno.h" -#include "criu-log.h" +#include "uapi/compel/asm/infect-types.h" +#include "errno.h" +#include "log.h" +#include "common/bug.h" #include "infect.h" #include "infect-priv.h" @@ -22,7 +22,7 @@ /* * Injected syscall instruction */ -const u32 code_syscall[] = { +const uint32_t code_syscall[] = { 0x44000002, /* sc */ 0x0fe00000 /* twi 31,0,0 */ }; diff --git a/compel/arch/x86/src/lib/include/ptrace.h b/compel/arch/x86/src/lib/include/uapi/asm/breakpoints.h similarity index 68% rename from compel/arch/x86/src/lib/include/ptrace.h rename to compel/arch/x86/src/lib/include/uapi/asm/breakpoints.h index 844ea0efd..980f25d06 100644 --- a/compel/arch/x86/src/lib/include/ptrace.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/breakpoints.h @@ -1,5 +1,5 @@ -#ifndef __COMPEL_PTRACE_H__ -#define __COMPEL_PTRACE_H__ +#ifndef __COMPEL_BREAKPOINTS_H__ +#define __COMPEL_BREAKPOINTS_H__ #define ARCH_SI_TRAP SI_KERNEL extern int ptrace_set_breakpoint(pid_t pid, void *addr); extern int ptrace_flush_breakpoints(pid_t pid); diff --git a/criu/arch/x86/include/asm/infect-types.h b/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h similarity index 100% rename from criu/arch/x86/include/asm/infect-types.h rename to compel/arch/x86/src/lib/include/uapi/asm/infect-types.h diff --git a/criu/arch/x86/infect.c b/compel/arch/x86/src/lib/infect.c similarity index 98% rename from criu/arch/x86/infect.c rename to compel/arch/x86/src/lib/infect.c index d4208ab54..53cae1dc5 100644 --- a/criu/arch/x86/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -11,15 +11,16 @@ #include #include -#include "compel/include/errno.h" +#include "errno.h" #include #include -#include "compel/include/asm/ptrace.h" +#include "asm/ptrace.h" #include "common/err.h" #include "asm/infect-types.h" -#include "ptrace.h" +#include "uapi/compel/ptrace.h" #include "infect.h" #include "infect-priv.h" +#include "log.h" /* * Injected syscall instruction diff --git a/criu/include/infect-priv.h b/compel/include/infect-priv.h similarity index 100% rename from criu/include/infect-priv.h rename to compel/include/infect-priv.h diff --git a/criu/include/rpc-pie-priv.h b/compel/include/rpc-pie-priv.h similarity index 100% rename from criu/include/rpc-pie-priv.h rename to compel/include/rpc-pie-priv.h diff --git a/compel/include/uapi/compel.h b/compel/include/uapi/compel.h index 278a85455..3554c1599 100644 --- a/compel/include/uapi/compel.h +++ b/compel/include/uapi/compel.h @@ -4,6 +4,8 @@ #include #include +#include + #define COMPEL_TYPE_INT (1u << 0) #define COMPEL_TYPE_LONG (1u << 1) #define COMPEL_TYPE_GOTPCREL (1u << 2) @@ -22,4 +24,8 @@ typedef void (*compel_log_fn)(unsigned int lvl, const char *fmt, va_list parms); extern void compel_log_init(compel_log_fn log_fn, unsigned int level); extern unsigned int compel_log_get_loglevel(void); +#include +#include +#include + #endif /* UAPI_COMPEL_H__ */ diff --git a/criu/include/infect-rpc.h b/compel/include/uapi/infect-rpc.h similarity index 100% rename from criu/include/infect-rpc.h rename to compel/include/uapi/infect-rpc.h diff --git a/criu/include/infect-util.h b/compel/include/uapi/infect-util.h similarity index 100% rename from criu/include/infect-util.h rename to compel/include/uapi/infect-util.h diff --git a/criu/include/infect.h b/compel/include/uapi/infect.h similarity index 97% rename from criu/include/infect.h rename to compel/include/uapi/infect.h index 760bdb80d..38051f437 100644 --- a/criu/include/infect.h +++ b/compel/include/uapi/infect.h @@ -1,10 +1,15 @@ #ifndef __COMPEL_INFECT_H__ #define __COMPEL_INFECT_H__ -#include "asm/infect-types.h" +#include + +#include +#include #include #include +#include "common/compiler.h" + #define PARASITE_START_AREA_MIN (4096) extern int compel_stop_task(int pid); diff --git a/criu/include/ptrace.h b/compel/include/uapi/ptrace.h similarity index 91% rename from criu/include/ptrace.h rename to compel/include/uapi/ptrace.h index e3f3374d5..2ab9e1c76 100644 --- a/criu/include/ptrace.h +++ b/compel/include/uapi/ptrace.h @@ -1,10 +1,11 @@ -#ifndef __CR_PTRACE_H__ -#define __CR_PTRACE_H__ +#ifndef UAPI_COMPEL_PTRACE_H__ +#define UAPI_COMPEL_PTRACE_H__ #include #include -#include "types.h" +#include +#include /* some constants for ptrace */ #ifndef PTRACE_SEIZE @@ -72,4 +73,4 @@ extern int ptrace_swap_area(pid_t pid, void *dst, void *src, long bytes); extern int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs); extern int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs); -#endif /* __CR_PTRACE_H__ */ +#endif /* UAPI_COMPEL_PTRACE_H__ */ diff --git a/criu/infect-rpc.c b/compel/src/lib/infect-rpc.c similarity index 100% rename from criu/infect-rpc.c rename to compel/src/lib/infect-rpc.c diff --git a/criu/infect-util.c b/compel/src/lib/infect-util.c similarity index 87% rename from criu/infect-util.c rename to compel/src/lib/infect-util.c index 275e2ec81..99dbee062 100644 --- a/criu/infect-util.c +++ b/compel/src/lib/infect-util.c @@ -1,8 +1,8 @@ -#include "int.h" #include "log.h" #include "common/bug.h" #include "common/lock.h" -#include "util-pie.h" + +#include "uapi/compel/plugins/plugin-fds.h" #include "infect-rpc.h" #include "infect-util.h" diff --git a/criu/infect.c b/compel/src/lib/infect.c similarity index 99% rename from criu/infect.c rename to compel/src/lib/infect.c index 4c6c4927f..6a3724636 100644 --- a/criu/infect.c +++ b/compel/src/lib/infect.c @@ -9,19 +9,20 @@ #include #include -#include "criu-log.h" +#include "log.h" #include "common/bug.h" #include "common/xmalloc.h" #include "common/lock.h" +#include "common/page.h" #include #include -#include "compel/include/asm/ptrace.h" -#include "compel/include/asm/syscall.h" +#include "asm/ptrace.h" +#include "uapi/compel/plugins/std/syscall.h" #include "asm/infect-types.h" #include "asm/sigframe.h" #include "infect.h" -#include "ptrace.h" +#include "uapi/compel/ptrace.h" #include "infect-rpc.h" #include "infect-priv.h" #include "infect-util.h" @@ -495,7 +496,7 @@ int compel_execute_syscall(struct parasite_ctl *ctl, { pid_t pid = ctl->rpid; int err; - u8 code_orig[BUILTIN_SYSCALL_SIZE]; + uint8_t code_orig[BUILTIN_SYSCALL_SIZE]; /* * Inject syscall instruction and remember original code, @@ -549,7 +550,7 @@ static int parasite_init_daemon(struct parasite_ctl *ctl) args = compel_parasite_args(ctl, struct parasite_init_args); args->sigframe = (uintptr_t)ctl->rsigframe; - args->log_level = log_get_loglevel(); + args->log_level = compel_log_get_loglevel(); futex_set(&args->daemon_connected, 0); @@ -653,7 +654,7 @@ static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size) static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) { void *where = (void *)ctl->ictx.syscall_ip + BUILTIN_SYSCALL_SIZE; - u8 orig_code[MEMFD_FNAME_SZ] = MEMFD_FNAME; + uint8_t orig_code[MEMFD_FNAME_SZ] = MEMFD_FNAME; pid_t pid = ctl->rpid; unsigned long sret = -ENOSYS; int ret, fd, lfd; diff --git a/criu/ptrace.c b/compel/src/lib/ptrace.c similarity index 93% rename from criu/ptrace.c rename to compel/src/lib/ptrace.c index 8b9e166ec..c2991b5d8 100644 --- a/criu/ptrace.c +++ b/compel/src/lib/ptrace.c @@ -15,14 +15,12 @@ #include #include -#include "int.h" #include "common/compiler.h" -#include "util.h" -#include "ptrace.h" -#include "pid.h" -#include "proc_parse.h" -#include "seccomp.h" -#include "cr_options.h" + +#include "uapi/compel/asm/infect-types.h" +#include "uapi/compel/ptrace.h" + +#include "log.h" int suspend_seccomp(pid_t pid) { diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index c9dbceb08..668cc2869 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -2,9 +2,6 @@ ccflags-y += -iquote criu/$(ARCH) ccflags-y += -I compel/include/uapi ccflags-y += -I compel/plugins/include/uapi -obj-y += infect.o -obj-y += infect-rpc.o -obj-y += infect-util.o obj-y += action-scripts.o obj-y += external.o obj-y += aio.o @@ -58,7 +55,6 @@ obj-y += proc_parse.o obj-y += protobuf-desc.o obj-y += protobuf.o obj-y += pstree.o -obj-y += ptrace.o obj-y += rbtree.o obj-y += rst-malloc.o obj-y += seccomp.o diff --git a/criu/aio.c b/criu/aio.c index 011a1afcf..27c251df5 100644 --- a/criu/aio.c +++ b/criu/aio.c @@ -11,8 +11,7 @@ #include "parasite.h" #include "parasite-syscall.h" #include "images/mm.pb-c.h" -#include "infect.h" -#include "infect-rpc.h" +#include #define NR_IOEVENTS_IN_NPAGES(npages) ((PAGE_SIZE * npages - sizeof(struct aio_ring)) / sizeof(struct io_event)) diff --git a/criu/arch/aarch64/Makefile b/criu/arch/aarch64/Makefile index e269de4c8..858e1a583 100644 --- a/criu/arch/aarch64/Makefile +++ b/criu/arch/aarch64/Makefile @@ -11,4 +11,3 @@ obj-y += cpu.o obj-y += crtools.o obj-y += sigframe.o obj-y += bitops.o -obj-y += infect.o diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index d3cbc7e6f..f98743a23 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -6,10 +6,10 @@ #include "types.h" #include -#include "asm/infect-types.h" +#include #include "asm/restorer.h" #include "common/compiler.h" -#include "ptrace.h" +#include #include "asm/dump.h" #include "protobuf.h" #include "images/core.pb-c.h" @@ -19,7 +19,7 @@ #include "util.h" #include "cpu.h" #include "restorer.h" -#include "infect.h" +#include #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))(src)->e diff --git a/criu/arch/aarch64/sigframe.c b/criu/arch/aarch64/sigframe.c index e8d99529a..be57c1670 100644 --- a/criu/arch/aarch64/sigframe.c +++ b/criu/arch/aarch64/sigframe.c @@ -1,5 +1,5 @@ #include "asm/types.h" -#include "asm/infect-types.h" +#include #include "asm/sigframe.h" int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, diff --git a/criu/arch/arm/Makefile b/criu/arch/arm/Makefile index da513ebca..ec32a9d6b 100644 --- a/criu/arch/arm/Makefile +++ b/criu/arch/arm/Makefile @@ -12,4 +12,3 @@ obj-y += cpu.o obj-y += crtools.o obj-y += sigframe.o obj-y += bitops.o -obj-y += infect.o diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index aa3860e93..c216cdc5c 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -4,11 +4,11 @@ #include "types.h" #include -#include "asm/infect-types.h" +#include #include "asm/restorer.h" #include "common/compiler.h" #include "asm/dump.h" -#include "ptrace.h" +#include #include "protobuf.h" #include "images/core.pb-c.h" #include "images/creds.pb-c.h" @@ -18,8 +18,8 @@ #include "elf.h" #include "parasite-syscall.h" #include "restorer.h" -#include "kerndat.h" -#include "infect.h" + +#include #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))((src)->ARM_##e) diff --git a/criu/arch/arm/sigframe.c b/criu/arch/arm/sigframe.c index e8d99529a..be57c1670 100644 --- a/criu/arch/arm/sigframe.c +++ b/criu/arch/arm/sigframe.c @@ -1,5 +1,5 @@ #include "asm/types.h" -#include "asm/infect-types.h" +#include #include "asm/sigframe.h" int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, diff --git a/criu/arch/ppc64/Makefile b/criu/arch/ppc64/Makefile index cd7c41250..12b8ad2e3 100644 --- a/criu/arch/ppc64/Makefile +++ b/criu/arch/ppc64/Makefile @@ -8,4 +8,3 @@ ccflags-y += -I compel/plugins/include/uapi obj-y += cpu.o obj-y += crtools.o obj-y += sigframe.o -obj-y += infect.o diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index 3d662542e..074490956 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -12,12 +12,12 @@ #include "cr_options.h" #include "common/compiler.h" -#include "ptrace.h" +#include #include "parasite-syscall.h" #include "log.h" #include "util.h" #include "cpu.h" -#include "infect.h" +#include #include "protobuf.h" #include "images/core.pb-c.h" diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h index 399bdfb52..c779a1869 100644 --- a/criu/arch/ppc64/include/asm/restorer.h +++ b/criu/arch/ppc64/include/asm/restorer.h @@ -5,7 +5,7 @@ #include #include #include "asm/types.h" -#include "asm/infect-types.h" +#include #include diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index fcbb67129..6744f9a27 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -12,7 +12,6 @@ asflags-y += -iquote $(obj)/include obj-y += cpu.o obj-y += crtools.o obj-y += sigframe.o -obj-y += infect.o ifeq ($(CONFIG_COMPAT),y) obj-y += sigaction_compat.o obj-y += call32.o diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 886a2c7a3..c59face98 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -14,14 +14,14 @@ #include "cr_options.h" #include "common/compiler.h" #include "restorer.h" -#include "ptrace.h" +#include #include "parasite-syscall.h" #include "log.h" #include "util.h" #include "cpu.h" #include #include "kerndat.h" -#include "infect.h" +#include #include "protobuf.h" #include "images/core.pb-c.h" diff --git a/criu/arch/x86/sys-exec-tbl.c b/criu/arch/x86/sys-exec-tbl.c index 1051af06f..608dc2510 100644 --- a/criu/arch/x86/sys-exec-tbl.c +++ b/criu/arch/x86/sys-exec-tbl.c @@ -1,4 +1,4 @@ -#include "infect.h" +#include static struct syscall_exec_desc sc_exec_table_64[] = { #include "sys-exec-tbl-64.c" diff --git a/criu/cr-check.c b/criu/cr-check.c index 82e5a9d9e..fc0c2e99d 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -38,7 +38,7 @@ #include "proc_parse.h" #include "mount.h" #include "tty.h" -#include "ptrace.h" +#include #include "ptrace-compat.h" #include "kerndat.h" #include "timerfd.h" diff --git a/criu/cr-dump.c b/criu/cr-dump.c index e6575ea51..ded343ed8 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -42,7 +42,6 @@ #include "cr_options.h" #include "servicefd.h" #include "string.h" -#include "ptrace.h" #include "ptrace-compat.h" #include "util.h" #include "namespaces.h" diff --git a/criu/cr-exec.c b/criu/cr-exec.c index 29a02bd77..b39c77238 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -12,8 +12,7 @@ #include "log.h" #include "util.h" #include "kerndat.h" -#include "infect.h" -#include "infect-priv.h" +#include struct syscall_exec_desc { char *name; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 7c0baa9b8..2448360c9 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -23,10 +23,8 @@ #include -#include "compel/include/asm/ptrace.h" - #include "types.h" -#include "ptrace.h" +#include #include "common/compiler.h" #include "cr_options.h" @@ -71,7 +69,7 @@ #include "file-lock.h" #include "action-scripts.h" #include "shmem.h" -#include "infect.h" +#include #include "aio.h" #include "lsm.h" #include "seccomp.h" diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h index 04359e247..d67ac5e56 100644 --- a/criu/include/proc_parse.h +++ b/criu/include/proc_parse.h @@ -3,7 +3,7 @@ #include -#include "infect.h" +#include #include "images/seccomp.pb-c.h" #define PROC_TASK_COMM_LEN 32 diff --git a/criu/include/ptrace-compat.h b/criu/include/ptrace-compat.h index f6cc8b932..295fb01c6 100644 --- a/criu/include/ptrace-compat.h +++ b/criu/include/ptrace-compat.h @@ -1,8 +1,10 @@ -#ifndef __CR_PTRACE_ARCH_H__ -#define __CR_PTRACE_ARCH_H__ +#ifndef __CR_PTRACE_H__ +#define __CR_PTRACE_H__ #include #include + +#include "types.h" #include "config.h" #ifndef CONFIG_HAS_PTRACE_PEEKSIGINFO @@ -13,4 +15,4 @@ struct ptrace_peeksiginfo_args { }; #endif -#endif /* __CR_PTRACE_ARCH_H__ */ +#endif /* __CR_PTRACE_H__ */ diff --git a/criu/include/types.h b/criu/include/types.h index 36f24085a..7600f3592 100644 --- a/criu/include/types.h +++ b/criu/include/types.h @@ -1,5 +1,5 @@ #ifndef __CR_INC_TYPES_H__ #define __CR_INC_TYPES_H__ -#include "asm/infect-types.h" +#include #include "asm/types.h" #endif diff --git a/criu/mem.c b/criu/mem.c index 757e13668..26c370ac9 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -25,9 +25,7 @@ #include "files-reg.h" #include "pagemap-cache.h" #include "fault-injection.h" -#include "infect.h" -#include "infect-rpc.h" -#include "infect-util.h" +#include #include "protobuf.h" #include "images/pagemap.pb-c.h" diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 43d6efbe0..dc7a831e4 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -15,7 +15,7 @@ #include "images/pagemap.pb-c.h" #include "imgset.h" -#include "ptrace.h" +#include #include "parasite-syscall.h" #include "parasite.h" #include "crtools.h" @@ -46,6 +46,8 @@ #include "infect-rpc.h" #include "parasite-blob.h" +#include + unsigned long get_exec_start(struct vm_area_list *vmas) { struct vma_area *vma_area; diff --git a/criu/pie/infect.c b/criu/pie/infect.c index 2a4cf40f8..1863a1ee9 100644 --- a/criu/pie/infect.c +++ b/criu/pie/infect.c @@ -8,7 +8,7 @@ #include "sigframe.h" #include "infect-rpc.h" #include "infect-pie.h" -#include "rpc-pie-priv.h" +#include "compel/include/rpc-pie-priv.h" static int tsock = -1; diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index b4a476227..e84d63405 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -19,8 +19,6 @@ #include "criu-log.h" #include "tty.h" #include "aio.h" -#include "infect-rpc.h" -#include "infect-pie.h" #include "asm/parasite.h" #include "restorer.h" diff --git a/criu/seccomp.c b/criu/seccomp.c index 15bd69fe9..c5e7a7d93 100644 --- a/criu/seccomp.c +++ b/criu/seccomp.c @@ -7,7 +7,7 @@ #include "imgset.h" #include "kcmp.h" #include "pstree.h" -#include "ptrace.h" +#include #include "proc_parse.h" #include "restorer.h" #include "seccomp.h" diff --git a/criu/seize.c b/criu/seize.c index 51daadf43..263f5a928 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -15,13 +15,13 @@ #include "cr-errno.h" #include "pstree.h" #include "criu-log.h" -#include "ptrace.h" +#include #include "proc_parse.h" #include "seize.h" #include "stats.h" #include "xmalloc.h" #include "util.h" -#include "infect.h" +#include #define NR_ATTEMPTS 5 diff --git a/criu/vdso.c b/criu/vdso.c index 7a50587f6..dbbf84e09 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -19,8 +19,7 @@ #include "log.h" #include "mem.h" #include "vma.h" -#include "infect.h" -#include "infect-rpc.h" +#include #ifdef LOG_PREFIX # undef LOG_PREFIX From a9c99c09a00c9c7e91b68a50aa76e97c03ff4bc2 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 8 Nov 2016 16:27:00 +0300 Subject: [PATCH 0202/4375] cr-dump: add compel/ptrace.h include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Need in PTRACE_PEEKSIGINFO declarations: criu/cr-dump.c: In function ‘dump_signal_queue’: criu/cr-dump.c:901:16: error: ‘PTRACE_PEEKSIGINFO_SHARED’ undeclared (first use in this function) arg.flags |= PTRACE_PEEKSIGINFO_SHARED; ^ criu/cr-dump.c:901:16: note: each undeclared identifier is reported only once for each function it appears in criu/cr-dump.c:920:21: error: ‘PTRACE_PEEKSIGINFO’ undeclared (first use in this function) nr = ret = ptrace(PTRACE_PEEKSIGINFO, tid, &arg, si); ^ Can be squashed with commit 638b0c2f11e1 ("compel: Move in parasite engine"). Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index ded343ed8..afb5a51b8 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -42,6 +42,7 @@ #include "cr_options.h" #include "servicefd.h" #include "string.h" +#include #include "ptrace-compat.h" #include "util.h" #include "namespaces.h" From 48be6e55d44fafc6c34e0b315d83a9b8ff99a0cf Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 8 Nov 2016 19:55:00 +0300 Subject: [PATCH 0203/4375] criu: call compel_log_init() at start Otherwise, messages printed by libcompel are omitted from logs. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/crtools.c | 1 + criu/include/log.h | 4 ++++ criu/log.c | 4 ++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index ef2e6f670..3c761a557 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -706,6 +706,7 @@ int main(int argc, char *argv[], char *envp[]) if (log_init(opts.output)) return 1; libsoccr_set_log(log_level, print_on_level); + compel_log_init(vprint_on_level, log_get_loglevel()); pr_debug("Version: %s (gitid %s)\n", CRIU_VERSION, CRIU_GITID); if (opts.deprecated_ok) diff --git a/criu/include/log.h b/criu/include/log.h index d53a470ed..2ecadb359 100644 --- a/criu/include/log.h +++ b/criu/include/log.h @@ -7,6 +7,10 @@ #include #include +#include + +extern void vprint_on_level(unsigned int loglevel, const char *format, + va_list params); #endif /* CR_NOGLIBC */ diff --git a/criu/log.c b/criu/log.c index bf9cc31de..a2beabdb0 100644 --- a/criu/log.c +++ b/criu/log.c @@ -209,7 +209,7 @@ unsigned int log_get_loglevel(void) return current_loglevel; } -static void __print_on_level(unsigned int loglevel, const char *format, va_list params) +void vprint_on_level(unsigned int loglevel, const char *format, va_list params) { int fd, size, ret, off = 0; int __errno = errno; @@ -246,7 +246,7 @@ void print_on_level(unsigned int loglevel, const char *format, ...) va_list params; va_start(params, format); - __print_on_level(loglevel, format, params); + vprint_on_level(loglevel, format, params); va_end(params); } From 7b6c60b0eebc29e2ad9c54cd03bfc2ee36e6ff62 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 11 Nov 2016 21:51:00 +0300 Subject: [PATCH 0204/4375] compel: plugins,std -- Use proper quotes in exported header In UAPI there should be no -iquote-d headers. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/include/uapi/plugin-std.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/plugins/include/uapi/plugin-std.h b/compel/plugins/include/uapi/plugin-std.h index b77a7b449..97a13388a 100644 --- a/compel/plugins/include/uapi/plugin-std.h +++ b/compel/plugins/include/uapi/plugin-std.h @@ -1,7 +1,7 @@ #ifndef COMPEL_PLUGIN_STD_STD_H__ #define COMPEL_PLUGIN_STD_STD_H__ -#include "uapi/plugins.h" -#include "uapi/std/syscall.h" +#include +#include #endif /* COMPEL_PLUGIN_STD_STD_H__ */ From 93d0494e3ebb5dd4ac91b7a68e6cf7f94d5409f1 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 11 Nov 2016 21:52:00 +0300 Subject: [PATCH 0205/4375] compel: plugins,std -- Include string helpers They will be needed for log module. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/include/uapi/plugin-std.h | 1 + 1 file changed, 1 insertion(+) diff --git a/compel/plugins/include/uapi/plugin-std.h b/compel/plugins/include/uapi/plugin-std.h index 97a13388a..f91e2acbd 100644 --- a/compel/plugins/include/uapi/plugin-std.h +++ b/compel/plugins/include/uapi/plugin-std.h @@ -3,5 +3,6 @@ #include #include +#include #endif /* COMPEL_PLUGIN_STD_STD_H__ */ From d9c284c3e975ecbc04d66d8b907643ed31f8229c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 11 Nov 2016 21:52:00 +0300 Subject: [PATCH 0206/4375] compel: plugins,std -- Implement generic std_memcpy The routine was #if0ed for a while (taken from older compel), now it's time to provide any generic version. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/std/string.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/compel/plugins/std/string.c b/compel/plugins/std/string.c index 6e5d42ed1..e987e408e 100644 --- a/compel/plugins/std/string.c +++ b/compel/plugins/std/string.c @@ -222,19 +222,11 @@ fin: void *std_memcpy(void *to, const void *from, unsigned int n) { - /* FIXME: Per-arch support */ -#if 0 - int d0, d1, d2; - asm volatile("rep ; movsl \n" - "movl %4,%%ecx \n" - "andl $3,%%ecx \n" - "jz 1f \n" - "rep ; movsb \n" - "1:" - : "=&c" (d0), "=&D" (d1), "=&S" (d2) - : "0" (n / 4), "g" (n), "1" ((long)to), "2" ((long)from) - : "memory"); -#endif + char *tmp = to; + const char *s = from; + + while (n--) + *tmp++ = *s++; return to; } From 6d5a8930a9959c89823936f6b9bcf484ab65af4d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 11 Nov 2016 21:52:00 +0300 Subject: [PATCH 0207/4375] criu: pie, parasite-head -- Drop unneeded parasite.h inclusion This header was never actually required here. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/parasite-head.S | 1 - criu/arch/arm/parasite-head.S | 1 - criu/arch/ppc64/parasite-head.S | 1 - criu/arch/x86/parasite-head-32.S | 1 - criu/arch/x86/parasite-head-64.S | 1 - 5 files changed, 5 deletions(-) diff --git a/criu/arch/aarch64/parasite-head.S b/criu/arch/aarch64/parasite-head.S index 7e82c43be..5e7067f6b 100644 --- a/criu/arch/aarch64/parasite-head.S +++ b/criu/arch/aarch64/parasite-head.S @@ -1,5 +1,4 @@ #include "common/asm/linkage.h" -#include "parasite.h" .section .head.text, "ax" ENTRY(__export_parasite_head_start) diff --git a/criu/arch/arm/parasite-head.S b/criu/arch/arm/parasite-head.S index 77eef32c0..e72646b50 100644 --- a/criu/arch/arm/parasite-head.S +++ b/criu/arch/arm/parasite-head.S @@ -1,5 +1,4 @@ #include "common/asm/linkage.h" -#include "parasite.h" .section .head.text, "ax" ENTRY(__export_parasite_head_start) diff --git a/criu/arch/ppc64/parasite-head.S b/criu/arch/ppc64/parasite-head.S index e24c338a3..c870efdc2 100644 --- a/criu/arch/ppc64/parasite-head.S +++ b/criu/arch/ppc64/parasite-head.S @@ -1,5 +1,4 @@ #include "common/asm/linkage.h" -#include "parasite.h" .section .head.text .align 8 diff --git a/criu/arch/x86/parasite-head-32.S b/criu/arch/x86/parasite-head-32.S index 50c032a90..f08cc1c3c 100644 --- a/criu/arch/x86/parasite-head-32.S +++ b/criu/arch/x86/parasite-head-32.S @@ -1,5 +1,4 @@ #include "common/asm/linkage.h" -#include "parasite.h" .section .head.text, "ax" diff --git a/criu/arch/x86/parasite-head-64.S b/criu/arch/x86/parasite-head-64.S index bb6f95232..9622af1ee 100644 --- a/criu/arch/x86/parasite-head-64.S +++ b/criu/arch/x86/parasite-head-64.S @@ -1,5 +1,4 @@ #include "common/asm/linkage.h" -#include "parasite.h" .section .head.text, "ax" From 0be8beb666ab030e8f9e67d9db9c71a576fbd4d2 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 11 Nov 2016 21:52:00 +0300 Subject: [PATCH 0208/4375] compel: Add lds scripts for PIE code In CRIU these are auto-generated, we want to have them in compel and it looks like it's better to have them fixed rather than generated. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/scripts/compel-pack.lds.S | 32 ++++++++++++++++ compel/arch/arm/scripts/compel-pack.lds.S | 32 ++++++++++++++++ compel/arch/ppc64/scripts/compel-pack.lds.S | 36 ++++++++++++++++++ .../arch/x86/scripts/compel-pack-compat.lds.S | 37 +++++++++++++++++++ compel/arch/x86/scripts/compel-pack.lds.S | 37 +++++++++++++++++++ compel/arch/x86/scripts/pack.lds.S | 30 --------------- 6 files changed, 174 insertions(+), 30 deletions(-) create mode 100644 compel/arch/aarch64/scripts/compel-pack.lds.S create mode 100644 compel/arch/arm/scripts/compel-pack.lds.S create mode 100644 compel/arch/ppc64/scripts/compel-pack.lds.S create mode 100644 compel/arch/x86/scripts/compel-pack-compat.lds.S create mode 100644 compel/arch/x86/scripts/compel-pack.lds.S delete mode 100644 compel/arch/x86/scripts/pack.lds.S diff --git a/compel/arch/aarch64/scripts/compel-pack.lds.S b/compel/arch/aarch64/scripts/compel-pack.lds.S new file mode 100644 index 000000000..b07e68c1d --- /dev/null +++ b/compel/arch/aarch64/scripts/compel-pack.lds.S @@ -0,0 +1,32 @@ +OUTPUT_ARCH(aarch64) +SECTIONS +{ + .crblob 0x0 : { + *(.head.text) + *(.text*) + . = ALIGN(32); + *(.data*) + . = ALIGN(32); + *(.rodata*) + . = ALIGN(32); + *(.bss*) + . = ALIGN(32); + *(.got*) + . = ALIGN(32); + *(.toc*) + . = ALIGN(32); + } =0x00000000, + + /DISCARD/ : { + *(.debug*) + *(.comment*) + *(.note*) + *(.group*) + *(.eh_frame*) + *(*) + } + +/* Parasite args should have 4 bytes align, as we have futex inside. */ +. = ALIGN(4); +__export_parasite_args = .; +} diff --git a/compel/arch/arm/scripts/compel-pack.lds.S b/compel/arch/arm/scripts/compel-pack.lds.S new file mode 100644 index 000000000..fe402787f --- /dev/null +++ b/compel/arch/arm/scripts/compel-pack.lds.S @@ -0,0 +1,32 @@ +OUTPUT_ARCH(arm) +SECTIONS +{ + .crblob 0x0 : { + *(.head.text) + *(.text*) + . = ALIGN(32); + *(.data*) + . = ALIGN(32); + *(.rodata*) + . = ALIGN(32); + *(.bss*) + . = ALIGN(32); + *(.got*) + . = ALIGN(32); + *(.toc*) + . = ALIGN(32); + } =0x00000000, + + /DISCARD/ : { + *(.debug*) + *(.comment*) + *(.note*) + *(.group*) + *(.eh_frame*) + *(*) + } + +/* Parasite args should have 4 bytes align, as we have futex inside. */ +. = ALIGN(4); +__export_parasite_args = .; +} diff --git a/compel/arch/ppc64/scripts/compel-pack.lds.S b/compel/arch/ppc64/scripts/compel-pack.lds.S new file mode 100644 index 000000000..5da9a0846 --- /dev/null +++ b/compel/arch/ppc64/scripts/compel-pack.lds.S @@ -0,0 +1,36 @@ +OUTPUT_ARCH(powerpc:common64) +SECTIONS +{ + .text : { + *(.head.text) + *(.text*) + *(.compel.exit) + *(.compel.init) + } + + .data : { + *(.data*) + *(.bss*) + } + + .rodata : { + *(.rodata*) + *(.got*) + } + + .toc : ALIGN(8) { + *(.toc*) + } + + /DISCARD/ : { + *(.debug*) + *(.comment*) + *(.note*) + *(.group*) + *(.eh_frame*) + } + +/* Parasite args should have 4 bytes align, as we have futex inside. */ +. = ALIGN(4); +__export_parasite_args = .; +} diff --git a/compel/arch/x86/scripts/compel-pack-compat.lds.S b/compel/arch/x86/scripts/compel-pack-compat.lds.S new file mode 100644 index 000000000..67adf96a0 --- /dev/null +++ b/compel/arch/x86/scripts/compel-pack-compat.lds.S @@ -0,0 +1,37 @@ +OUTPUT_ARCH(i386) +TARGET(elf32-i386) +SECTIONS +{ + .text : { + *(.head.text) + *(.text*) + *(.compel.exit) + *(.compel.init) + } + + .data : { + *(.data*) + *(.bss*) + } + + .rodata : { + *(.rodata*) + *(.got*) + } + + .toc : ALIGN(8) { + *(.toc*) + } + + /DISCARD/ : { + *(.debug*) + *(.comment*) + *(.note*) + *(.group*) + *(.eh_frame*) + } + +/* Parasite args should have 4 bytes align, as we have futex inside. */ +. = ALIGN(4); +__export_parasite_args = .; +} diff --git a/compel/arch/x86/scripts/compel-pack.lds.S b/compel/arch/x86/scripts/compel-pack.lds.S new file mode 100644 index 000000000..cd6584ffe --- /dev/null +++ b/compel/arch/x86/scripts/compel-pack.lds.S @@ -0,0 +1,37 @@ +OUTPUT_ARCH(i386:x86-64) +TARGET(elf64-x86-64) +SECTIONS +{ + .text : { + *(.head.text) + *(.text*) + *(.compel.exit) + *(.compel.init) + } + + .data : { + *(.data*) + *(.bss*) + } + + .rodata : { + *(.rodata*) + *(.got*) + } + + .toc : ALIGN(8) { + *(.toc*) + } + + /DISCARD/ : { + *(.debug*) + *(.comment*) + *(.note*) + *(.group*) + *(.eh_frame*) + } + +/* Parasite args should have 4 bytes align, as we have futex inside. */ +. = ALIGN(4); +__export_parasite_args = .; +} diff --git a/compel/arch/x86/scripts/pack.lds.S b/compel/arch/x86/scripts/pack.lds.S deleted file mode 100644 index 3b94b3ecd..000000000 --- a/compel/arch/x86/scripts/pack.lds.S +++ /dev/null @@ -1,30 +0,0 @@ -OUTPUT_ARCH(i386:x86-64) -SECTIONS -{ - . = ALIGN(64); - .text : { - *(.compel.prologue.text) - *(.text*) - } =0x0 - - . = ALIGN(64); - .compel.init : { - *(.compel.init) - } =0xff - - . = ALIGN(64); - .data : { - *(.data*) - *(.bss*) - *(.rodata*) - } =0x0 - - /DISCARD/ : { - *(.debug*) - *(.comment*) - *(.note*) - *(.group*) - *(.eh_frame*) - *(*) - } -} From 3a7e027b5e80b4948c02439aa18a6c5ec99a35df Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 11 Nov 2016 21:52:00 +0300 Subject: [PATCH 0209/4375] criu: pie -- Switch to use compel shipped lds scripts Now when *.lds is in compel we can switch to it. Also -- remove the criu lds generation code. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 54 ++++++++----------------------------- criu/pie/pie-reloc.lds.S.in | 35 ------------------------ criu/pie/pie.lds.S.in | 31 --------------------- 3 files changed, 11 insertions(+), 109 deletions(-) delete mode 100644 criu/pie/pie-reloc.lds.S.in delete mode 100644 criu/pie/pie.lds.S.in diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 9bf5a4762..c010964a3 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -6,6 +6,9 @@ ifeq ($(CONFIG_COMPAT),y) parasite_target += compat endif +compel_pack_lds-native := $(SRC_DIR)/compel/arch/$(ARCH)/scripts/compel-pack.lds.S +compel_pack_lds-compat := $(SRC_DIR)/compel/arch/$(ARCH)/scripts/compel-pack-compat.lds.S + native-obj-y += parasite.o native-obj-y += infect.o compat-obj-y += compat/parasite-compat.o @@ -97,46 +100,12 @@ GEN-OFFSETS := $(obj)/../../scripts/gen-offsets.sh BLOBS += $(obj)/restorer-blob.h define gen-pields-blobs-var -PIELDS += $(obj)/pie.lds-$(1).S BLOBS += $(obj)/parasite-$(1)-blob.h endef $(eval $(call map,gen-pields-blobs-var,$(parasite_target))) .SECONDARY: -ifeq ($(piegen-y),y) -PIELDS_INCLUDE := $(obj)/pie-reloc.lds.S.in -else -PIELDS_INCLUDE := $(obj)/pie.lds.S.in -endif - -ifeq ($(ARCH),x86) -$(obj)/pie.lds-native.S: $(PIELDS_INCLUDE) - $(call msg-gen, $@) - $(Q) echo "OUTPUT_ARCH(i386:x86-64)" > $@ - $(Q) echo "TARGET(elf64-x86-64)" >> $@ - $(Q) cat $< >> $@ - -$(obj)/pie.lds-compat.S: $(PIELDS_INCLUDE) - $(call msg-gen, $@) - $(Q) echo "OUTPUT_ARCH(i386)" > $@ - $(Q) echo "TARGET(elf32-i386)" >> $@ - $(Q) cat $< >> $@ -else # !x86 -ifeq ($(filter-out i386 ia32,$(ARCH)),) -$(PIELDS): $(PIELDS_INCLUDE) - $(call msg-gen, $@) - $(Q) echo "OUTPUT_ARCH(i386)" > $@ - $(Q) echo "TARGET(elf32-i386)" >> $@ - $(Q) cat $< >> $@ -else # arm, aarch64, ppc64 -$(PIELDS): $(PIELDS_INCLUDE) - $(call msg-gen, $@) - $(Q) echo "OUTPUT_ARCH($(LDARCH))" > $@ - $(Q) cat $< >> $@ -endif # non i386 -endif # non x86 ARCH - # for C files, we need "parasite-native" to be "parasite_native" target-name = $(patsubst criu/pie/%_blob.h,%,$(subst -,_,$(1))) @@ -146,16 +115,16 @@ ifeq ($(strip $(V)),) endif $(obj)/restorer.built-in.bin.o: $(obj)/restorer.built-in.o \ - $(obj)/native.lib.a $(obj)/pie.lds-native.S + $(obj)/native.lib.a $(compel_pack_lds-native) $(call msg-gen, $@) - $(Q) $(LD) -r -T $(obj)/pie.lds-native.S -o $@ $< $(obj)/native.lib.a + $(Q) $(LD) -r -T $(compel_pack_lds-native) -o $@ $< $(obj)/native.lib.a # $1 - binary mode: native/compat define gen-rule-built-in.bin.o $(obj)/parasite-$(1).built-in.bin.o: $(obj)/$(1).built-in.o \ - $(obj)/$(1).lib.a $(obj)/pie.lds-$(1).S + $(obj)/$(1).lib.a $(compel_pack_lds-$(1)) $$(call msg-gen, $$@) - $(Q) $(LD) -r -T $(obj)/pie.lds-$(1).S -o $$@ $$< $(obj)/$(1).lib.a + $(Q) $(LD) -r -T $(compel_pack_lds-$(1)) -o $$@ $$< $(obj)/$(1).lib.a endef $(eval $(call map,gen-rule-built-in.bin.o,$(parasite_target))) @@ -179,17 +148,17 @@ endif define gen-rule-built-in.bin.o $(obj)/parasite-$(1).built-in.bin.o: $(obj)/$(1).built-in.o \ - $(obj)/pie.lds-$(1).S $(obj)/native.lib.a + $(compel_pack_lds-$(1)) $(obj)/native.lib.a $$(call msg-gen, $$@) - $(Q) $(LD) $(LD_R) -T $(obj)/pie.lds-$(1).S -o $$@ $$< $(obj)/native.lib.a + $(Q) $(LD) $(LD_R) -T $(compel_pack_lds-$(1)) -o $$@ $$< $(obj)/native.lib.a endef $(eval $(call map,gen-rule-built-in.bin.o,$(parasite_target))) $(obj)/restorer.built-in.bin.o: $(obj)/restorer.built-in.o \ - $(obj)/pie.lds-native.S $(obj)/native.lib.a + $(compel_pack_lds-native) $(obj)/native.lib.a $(call msg-gen, $@) - $(Q) $(LD) $(LD_R) -T $(obj)/pie.lds-native.S -o $@ $< $(obj)/native.lib.a + $(Q) $(LD) $(LD_R) -T $(compel_pack_lds-native) -o $@ $< $(obj)/native.lib.a $(obj)/%.built-in.bin: $(obj)/%.built-in.bin.o $(call msg-gen, $@) @@ -206,7 +175,6 @@ all-y += $(BLOBS) # blobs and pields are in cleanup, rather than in mrproper because # we want them to be re-generated after `make clean && make` cleanup-y += $(BLOBS) -cleanup-y += $(PIELDS) cleanup-y += $(obj)/*.bin cleanup-y += $(obj)/*.built-in.bin.o cleanup-y += $(obj)/*.built-in.bin diff --git a/criu/pie/pie-reloc.lds.S.in b/criu/pie/pie-reloc.lds.S.in deleted file mode 100644 index 2d0730cbd..000000000 --- a/criu/pie/pie-reloc.lds.S.in +++ /dev/null @@ -1,35 +0,0 @@ -SECTIONS -{ - .text : { - *(.head.text) - *(.text*) - *(.compel.init) - *(.compel.exit) - } - - .data : { - *(.data*) - *(.bss*) - } - - .rodata : { - *(.rodata*) - *(.got*) - } - - .toc : ALIGN(8) { - *(.toc*) - } - - /DISCARD/ : { - *(.debug*) - *(.comment*) - *(.note*) - *(.group*) - *(.eh_frame*) - } - -/* Parasite args should have 4 bytes align, as we have futex inside. */ -. = ALIGN(4); -__export_parasite_args = .; -} diff --git a/criu/pie/pie.lds.S.in b/criu/pie/pie.lds.S.in deleted file mode 100644 index f745d355e..000000000 --- a/criu/pie/pie.lds.S.in +++ /dev/null @@ -1,31 +0,0 @@ -SECTIONS -{ - .crblob 0x0 : { - *(.head.text) - *(.text*) - . = ALIGN(32); - *(.data*) - . = ALIGN(32); - *(.rodata*) - . = ALIGN(32); - *(.bss*) - . = ALIGN(32); - *(.got*) - . = ALIGN(32); - *(.toc*) - . = ALIGN(32); - } =0x00000000, - - /DISCARD/ : { - *(.debug*) - *(.comment*) - *(.note*) - *(.group*) - *(.eh_frame*) - *(*) - } - -/* Parasite args should have 4 bytes align, as we have futex inside. */ -. = ALIGN(4); -__export_parasite_args = .; -} From 32405371eee1e1a6141b869509d46a2b1a4339e3 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 11 Nov 2016 21:52:00 +0300 Subject: [PATCH 0210/4375] compel: plugins,fds -- Add missing headers into uapi This plugin is all about sending scm-s over unix sockets, so having this stuff there is helpful. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/include/uapi/plugin-fds.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compel/plugins/include/uapi/plugin-fds.h b/compel/plugins/include/uapi/plugin-fds.h index 0ce83afbd..6a96f7681 100644 --- a/compel/plugins/include/uapi/plugin-fds.h +++ b/compel/plugins/include/uapi/plugin-fds.h @@ -5,6 +5,8 @@ #ifndef __COMPEL_PLUGIN_FDS_H__ #define __COMPEL_PLUGIN_FDS_H__ +#include + #include "common/scm.h" static inline int send_fd(int sock, struct sockaddr_un *saddr, int saddr_len, int fd) From fa6243b65e9bf450251d2aae8a937961a491fabe Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 11 Nov 2016 21:52:00 +0300 Subject: [PATCH 0211/4375] compel: plugins -- Add missing flags into compilation These were lost when moving code from CRIU, so pull them back in. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index dfbc812a5..4cfeced4c 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -1,6 +1,6 @@ .PHONY: .FORCE -CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) +CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) -DCR_NOGLIBC PLUGIN_ARCH_DIR := compel/arch/$(ARCH)/plugins # @@ -15,7 +15,7 @@ asflags-y += -I compel/plugins/include/uapi # General compel includes ccflags-y += -iquote $(SRC_DIR)/compel/include -ccflags-y += -fno-stack-protector +ccflags-y += -fpie -fno-stack-protector # General compel/plugins includes ccflags-y += -iquote $(obj)/include From 3821b3423e2fed986d1477c484c31925a89f8726 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 15 Nov 2016 12:42:00 +0300 Subject: [PATCH 0212/4375] scm: Unweave fds mess Currently criu built with criu/pie-util-fd (which is a symlink to criu/pie/util-fd) with same flags as we use in general compel infection code. Moreover the criu link with libcompel.a, so we get a problem where send_fds/recv_fds are multiple defined. Lets rather unweave this mess: - drop criu/pie-util-fd.c completely - move send_fd/recv_fd inliners into scm.h Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/include/uapi/plugin-fds.h | 5 ----- compel/src/lib/infect.c | 9 +++++++++ criu/Makefile.crtools | 1 - criu/pie-util-fd.c | 1 - 4 files changed, 9 insertions(+), 7 deletions(-) delete mode 120000 criu/pie-util-fd.c diff --git a/compel/plugins/include/uapi/plugin-fds.h b/compel/plugins/include/uapi/plugin-fds.h index 6a96f7681..4d2feedb3 100644 --- a/compel/plugins/include/uapi/plugin-fds.h +++ b/compel/plugins/include/uapi/plugin-fds.h @@ -9,9 +9,4 @@ #include "common/scm.h" -static inline int send_fd(int sock, struct sockaddr_un *saddr, int saddr_len, int fd) -{ - return send_fds(sock, saddr, saddr_len, &fd, 1, false); -} - #endif /* __COMPEL_PLUGIN_FDS_H__ */ diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 6a3724636..237ea7ae0 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -27,6 +27,15 @@ #include "infect-priv.h" #include "infect-util.h" #include "rpc-pie-priv.h" +#include "infect-util.h" + +#define __sys(foo) foo +#define __memcpy memcpy + +#define SCM_FDSET_HAS_OPTS + +#include "common/scm.h" +#include "common/scm-code.c" #define UNIX_PATH_MAX (sizeof(struct sockaddr_un) - \ (size_t)((struct sockaddr_un *) 0)->sun_path) diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 668cc2869..dabb1baa8 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -47,7 +47,6 @@ obj-y += page-pipe.o obj-y += pagemap.o obj-y += page-xfer.o obj-y += parasite-syscall.o -obj-y += pie-util-fd.o obj-y += pie-util.o obj-y += pipes.o obj-y += plugin.o diff --git a/criu/pie-util-fd.c b/criu/pie-util-fd.c deleted file mode 120000 index 4af261ede..000000000 --- a/criu/pie-util-fd.c +++ /dev/null @@ -1 +0,0 @@ -pie/util-fd.c \ No newline at end of file From 64bb75a859cd64df4ebc205059858823a9bf08ec Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 15 Nov 2016 12:43:00 +0300 Subject: [PATCH 0213/4375] compel: Drop off handle-elf routines from library piegen mode is cli only, so no need for them in library. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index ad98e9d6d..27ef59c52 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -15,10 +15,6 @@ ccflags-y += -I compel/include/uapi ccflags-y += -I compel/plugins/include/uapi lib-name := libcompel.a -lib-y += arch/$(ARCH)/src/lib/handle-elf.o -host-lib-y += arch/$(ARCH)/src/lib/handle-elf.o -lib-y += src/lib/handle-elf.o -host-lib-y += src/lib/handle-elf.o lib-y += src/lib/log.o host-lib-y += src/lib/log.o @@ -30,11 +26,12 @@ lib-y += src/lib/infect.o lib-y += src/lib/ptrace.o ifeq ($(ARCH),x86) -lib-y += src/lib/handle-elf-32.o -host-lib-y += src/lib/handle-elf-32.o +obj-y += src/lib/handle-elf-32.o endif obj-y += src/main.o +obj-y += arch/$(ARCH)/src/lib/handle-elf.o +obj-y += src/lib/handle-elf.o ifeq ($(ARCH),x86) CFLAGS_handle-elf-32.o += -UCONFIG_X86_64 -DCONFIG_X86_32 From 80e2500cf972e43d5af88b9d95f3518ec21c1b3f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 14 Nov 2016 16:04:54 +0300 Subject: [PATCH 0214/4375] compel: Introduce compel_thread_sigmask The plan is to rectify the thread infection API and hide thread_ctx from uapi eventually, so here's the symmetrical to compel_task_sigmask() call for threads. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 1 + compel/src/lib/infect.c | 7 ++++++- criu/parasite-syscall.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 38051f437..c444a6edd 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -92,6 +92,7 @@ extern int compel_unmap(struct parasite_ctl *ctl, unsigned long addr); extern int compel_mode_native(struct parasite_ctl *ctl); extern k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl); +extern k_rtsigset_t *compel_thread_sigmask(struct thread_ctx *tctx); struct rt_sigframe; diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 237ea7ae0..c8e954bce 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -1255,9 +1255,14 @@ int compel_mode_native(struct parasite_ctl *ctl) return user_regs_native(&ctl->orig.regs); } +k_rtsigset_t *compel_thread_sigmask(struct thread_ctx *tctx) +{ + return &tctx->sigmask; +} + k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl) { - return &ctl->orig.sigmask; + return compel_thread_sigmask(&ctl->orig); } struct infect_ctx *compel_infect_ctx(struct parasite_ctl *ctl) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index dc7a831e4..7efad53ab 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -201,7 +201,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, return -1; tc->has_blk_sigset = true; - memcpy(&tc->blk_sigset, &octx.sigmask, sizeof(k_rtsigset_t)); + memcpy(&tc->blk_sigset, compel_thread_sigmask(&octx), sizeof(k_rtsigset_t)); ret = compel_run_in_thread(pid, PARASITE_CMD_DUMP_THREAD, ctl, &octx); if (ret) { From fc0b62e921d0631112e83ce4712234303f846e27 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 14 Nov 2016 16:05:08 +0300 Subject: [PATCH 0215/4375] compel: Introduce parasite_thread_ctl The structure is opaque hander for thread infection. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 11 +++++++--- compel/src/lib/infect.c | 42 +++++++++++++++++++++++++++++++----- criu/parasite-syscall.c | 24 +++++++++++++-------- 3 files changed, 60 insertions(+), 17 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index c444a6edd..d7ef921b7 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -42,9 +42,14 @@ struct thread_ctx { user_regs_struct_t regs; }; +struct parasite_thread_ctl { + struct thread_ctx th; +}; + extern struct parasite_ctl *compel_prepare(int pid); extern int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size); -extern int compel_prepare_thread(int pid, struct thread_ctx *ctx); +extern struct parasite_thread_ctl *compel_prepare_thread(struct parasite_ctl *ctl, int pid); +extern void compel_release_thread(struct parasite_thread_ctl *); extern int compel_stop_daemon(struct parasite_ctl *ctl); extern int compel_cure_remote(struct parasite_ctl *ctl); @@ -68,7 +73,7 @@ extern int compel_execute_syscall(struct parasite_ctl *ctl, user_regs_struct_t *regs, const char *code_syscall); extern int compel_run_in_thread(pid_t pid, unsigned int cmd, struct parasite_ctl *ctl, - struct thread_ctx *octx); + struct parasite_thread_ctl *tctl); /* * The PTRACE_SYSCALL will trap task twice -- on @@ -92,7 +97,7 @@ extern int compel_unmap(struct parasite_ctl *ctl, unsigned long addr); extern int compel_mode_native(struct parasite_ctl *ctl); extern k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl); -extern k_rtsigset_t *compel_thread_sigmask(struct thread_ctx *tctx); +extern k_rtsigset_t *compel_thread_sigmask(struct parasite_thread_ctl *tctl); struct rt_sigframe; diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index c8e954bce..9f691f1ef 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -54,6 +54,8 @@ #define SI_EVENT(_si_code) (((_si_code) & 0xFFFF) >> 8) +static int prepare_thread(int pid, struct thread_ctx *ctx); + static inline void close_safe(int *pfd) { if (*pfd > -1) { @@ -845,7 +847,22 @@ err: return -1; } -int compel_prepare_thread(int pid, struct thread_ctx *ctx) +struct parasite_thread_ctl *compel_prepare_thread(struct parasite_ctl *ctl, int pid) +{ + struct parasite_thread_ctl *tctl; + + tctl = xmalloc(sizeof(*tctl)); + if (tctl) { + if (prepare_thread(pid, &tctl->th)) { + xfree(tctl); + tctl = NULL; + } + } + + return tctl; +} + +static int prepare_thread(int pid, struct thread_ctx *ctx) { if (ptrace(PTRACE_GETSIGMASK, pid, sizeof(k_rtsigset_t), &ctx->sigmask)) { pr_perror("can't get signal blocking mask for %d", pid); @@ -860,6 +877,15 @@ int compel_prepare_thread(int pid, struct thread_ctx *ctx) return 0; } +void compel_release_thread(struct parasite_thread_ctl *tctl) +{ + /* + * No stuff to cure in thread here, all routines leave the + * guy intact (for now) + */ + xfree(tctl); +} + struct parasite_ctl *compel_prepare(int pid) { struct parasite_ctl *ctl = NULL; @@ -876,7 +902,7 @@ struct parasite_ctl *compel_prepare(int pid) ctl->tsock = -1; ctl->ictx.log_fd = -1; - if (compel_prepare_thread(pid, &ctl->orig)) + if (prepare_thread(pid, &ctl->orig)) goto err; ctl->rpid = pid; @@ -1059,8 +1085,9 @@ void *compel_parasite_args_s(struct parasite_ctl *ctl, int args_size) int compel_run_in_thread(pid_t pid, unsigned int cmd, struct parasite_ctl *ctl, - struct thread_ctx *octx) + struct parasite_thread_ctl *tctl) { + struct thread_ctx *octx = &tctl->th; void *stack = ctl->r_thread_stack; user_regs_struct_t regs = octx->regs; int ret; @@ -1255,14 +1282,19 @@ int compel_mode_native(struct parasite_ctl *ctl) return user_regs_native(&ctl->orig.regs); } -k_rtsigset_t *compel_thread_sigmask(struct thread_ctx *tctx) +static inline k_rtsigset_t *thread_ctx_sigmask(struct thread_ctx *tctx) { return &tctx->sigmask; } +k_rtsigset_t *compel_thread_sigmask(struct parasite_thread_ctl *tctl) +{ + return thread_ctx_sigmask(&tctl->th); +} + k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl) { - return compel_thread_sigmask(&ctl->orig); + return thread_ctx_sigmask(&ctl->orig); } struct infect_ctx *compel_infect_ctx(struct parasite_ctl *ctl) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 7efad53ab..f4b92619b 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -182,7 +182,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, CredsEntry *creds = tc->creds; struct parasite_dump_creds *pc; int ret; - struct thread_ctx octx; + struct parasite_thread_ctl *tctl; BUG_ON(id == 0); /* Leader is dumped in dump_task_core_all */ @@ -196,31 +196,33 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, pc->cap_last_cap = kdat.last_cap; - ret = compel_prepare_thread(pid, &octx); - if (ret) + tctl = compel_prepare_thread(ctl, pid); + if (!tctl) return -1; tc->has_blk_sigset = true; - memcpy(&tc->blk_sigset, compel_thread_sigmask(&octx), sizeof(k_rtsigset_t)); + memcpy(&tc->blk_sigset, compel_thread_sigmask(tctl), sizeof(k_rtsigset_t)); - ret = compel_run_in_thread(pid, PARASITE_CMD_DUMP_THREAD, ctl, &octx); + ret = compel_run_in_thread(pid, PARASITE_CMD_DUMP_THREAD, ctl, tctl); if (ret) { pr_err("Can't init thread in parasite %d\n", pid); - return -1; + goto err_rth; } ret = alloc_groups_copy_creds(creds, pc); if (ret) { pr_err("Can't copy creds for thread %d\n", pid); - return -1; + goto err_rth; } - ret = compel_get_task_regs(pid, octx.regs, save_task_regs, core); + ret = compel_get_task_regs(pid, tctl->th.regs, save_task_regs, core); if (ret) { pr_err("Can't obtain regs for thread %d\n", pid); - return -1; + goto err_rth; } + compel_release_thread(tctl); + if (compel_mode_native(ctl)) { tid->ns[0].virt = args->tid; return dump_thread_core(pid, core, true, args); @@ -228,6 +230,10 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, tid->ns[0].virt = args_c->tid; return dump_thread_core(pid, core, false, args_c); } + +err_rth: + compel_release_thread(tctl); + return -1; } #define ASSIGN_SAS(se, args) \ From 72e4804b07fa9172a0d0575b993263165e0a3243 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 14 Nov 2016 16:05:22 +0300 Subject: [PATCH 0216/4375] compel: Prepare to hide parasite_thread_ctl This only means introducing a compel_get_task_regs wrapper over the get_task_regs() call that works on thread-ctl, not thread-ctx. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/infect.c | 2 +- compel/arch/arm/src/lib/infect.c | 2 +- compel/arch/ppc64/src/lib/infect.c | 2 +- compel/arch/x86/src/lib/infect.c | 2 +- compel/include/infect-priv.h | 1 + compel/include/uapi/infect.h | 2 +- compel/src/lib/infect.c | 7 ++++++- criu/parasite-syscall.c | 2 +- 8 files changed, 13 insertions(+), 7 deletions(-) diff --git a/compel/arch/aarch64/src/lib/infect.c b/compel/arch/aarch64/src/lib/infect.c index fceea2816..95d6fc592 100644 --- a/compel/arch/aarch64/src/lib/infect.c +++ b/compel/arch/aarch64/src/lib/infect.c @@ -26,7 +26,7 @@ static inline void __always_unused __check_code_syscall(void) BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); } -int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) +int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) { struct iovec iov; user_fpregs_struct_t fpsimd; diff --git a/compel/arch/arm/src/lib/infect.c b/compel/arch/arm/src/lib/infect.c index b440ff736..b45239211 100644 --- a/compel/arch/arm/src/lib/infect.c +++ b/compel/arch/arm/src/lib/infect.c @@ -26,7 +26,7 @@ static inline __always_unused void __check_code_syscall(void) } #define PTRACE_GETVFPREGS 27 -int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) +int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) { user_fpregs_struct_t vfp; int ret = -1; diff --git a/compel/arch/ppc64/src/lib/infect.c b/compel/arch/ppc64/src/lib/infect.c index 959098b8c..b208f3dbb 100644 --- a/compel/arch/ppc64/src/lib/infect.c +++ b/compel/arch/ppc64/src/lib/infect.c @@ -244,7 +244,7 @@ static int __get_task_regs(pid_t pid, user_regs_struct_t *regs, return 0; } -int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) +int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) { user_fpregs_struct_t fpregs; int ret; diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index 53cae1dc5..af46c6526 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -51,7 +51,7 @@ static inline __always_unused void __check_code_syscall(void) ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \ (int32_t)((pregs)->compat.name)) -int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) +int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) { user_fpregs_struct_t xsave = { }, *xs = NULL; diff --git a/compel/include/infect-priv.h b/compel/include/infect-priv.h index db5259c2c..2ba85cf47 100644 --- a/compel/include/infect-priv.h +++ b/compel/include/infect-priv.h @@ -55,5 +55,6 @@ extern void *remote_mmap(struct parasite_ctl *ctl, void *addr, size_t length, int prot, int flags, int fd, off_t offset); extern bool arch_can_dump_task(struct parasite_ctl *ctl); +extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg); #endif diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index d7ef921b7..f0520ff72 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -146,7 +146,7 @@ struct parasite_blob_desc { extern struct parasite_blob_desc *compel_parasite_blob_desc(struct parasite_ctl *); typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); -extern int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *); +extern int compel_get_thread_regs(pid_t pid, struct parasite_thread_ctl *, save_regs_t, void *); extern void compel_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *elf_relocs, size_t nr_relocs); diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 9f691f1ef..b8e229302 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -616,7 +616,7 @@ static int parasite_start_daemon(struct parasite_ctl *ctl) * while in daemon it is not such. */ - if (compel_get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) { + if (get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) { pr_err("Can't obtain regs for thread %d\n", pid); return -1; } @@ -1297,6 +1297,11 @@ k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl) return thread_ctx_sigmask(&ctl->orig); } +int compel_get_thread_regs(pid_t pid, struct parasite_thread_ctl *tctl, save_regs_t save, void * arg) +{ + return get_task_regs(pid, tctl->th.regs, save, arg); +} + struct infect_ctx *compel_infect_ctx(struct parasite_ctl *ctl) { return &ctl->ictx; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index f4b92619b..1a052a098 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -215,7 +215,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, goto err_rth; } - ret = compel_get_task_regs(pid, tctl->th.regs, save_task_regs, core); + ret = compel_get_thread_regs(pid, tctl, save_task_regs, core); if (ret) { pr_err("Can't obtain regs for thread %d\n", pid); goto err_rth; From d0caedd190afef82dfd5fdd890f35373addbdf4e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 14 Nov 2016 16:05:36 +0300 Subject: [PATCH 0217/4375] compel: Hide parasite_thread_ctl Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/infect-priv.h | 9 +++++++++ compel/include/uapi/infect.h | 9 +-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/compel/include/infect-priv.h b/compel/include/infect-priv.h index 2ba85cf47..da56f0804 100644 --- a/compel/include/infect-priv.h +++ b/compel/include/infect-priv.h @@ -5,6 +5,11 @@ #define BUILTIN_SYSCALL_SIZE 8 +struct thread_ctx { + k_rtsigset_t sigmask; + user_regs_struct_t regs; +}; + /* parasite control block */ struct parasite_ctl { int rpid; /* Real pid of the victim */ @@ -36,6 +41,10 @@ struct parasite_ctl { struct parasite_blob_desc pblob; }; +struct parasite_thread_ctl { + struct thread_ctx th; +}; + #define MEMFD_FNAME "CRIUMFD" #define MEMFD_FNAME_SZ sizeof(MEMFD_FNAME) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index f0520ff72..28f0c469b 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -37,14 +37,7 @@ extern int compel_unseize_task(pid_t pid, int orig_state, int state); #define TASK_ZOMBIE 0x6 struct parasite_ctl; -struct thread_ctx { - k_rtsigset_t sigmask; - user_regs_struct_t regs; -}; - -struct parasite_thread_ctl { - struct thread_ctx th; -}; +struct parasite_thread_ctl; extern struct parasite_ctl *compel_prepare(int pid); extern int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size); From a722258d59f52706a28aa542093f075bf166360a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 14 Nov 2016 16:05:49 +0300 Subject: [PATCH 0218/4375] compel: Relax the thread mgmt API Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/infect-priv.h | 2 ++ compel/include/uapi/infect.h | 6 ++---- compel/src/lib/infect.c | 13 ++++++++----- criu/parasite-syscall.c | 4 ++-- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/compel/include/infect-priv.h b/compel/include/infect-priv.h index da56f0804..4eda1acdd 100644 --- a/compel/include/infect-priv.h +++ b/compel/include/infect-priv.h @@ -42,6 +42,8 @@ struct parasite_ctl { }; struct parasite_thread_ctl { + int tid; + struct parasite_ctl *ctl; struct thread_ctx th; }; diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 28f0c469b..75fc4a7a9 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -64,9 +64,7 @@ extern void *compel_parasite_args_s(struct parasite_ctl *ctl, int args_size); extern int compel_execute_syscall(struct parasite_ctl *ctl, user_regs_struct_t *regs, const char *code_syscall); -extern int compel_run_in_thread(pid_t pid, unsigned int cmd, - struct parasite_ctl *ctl, - struct parasite_thread_ctl *tctl); +extern int compel_run_in_thread(struct parasite_thread_ctl *tctl, unsigned int cmd); /* * The PTRACE_SYSCALL will trap task twice -- on @@ -139,7 +137,7 @@ struct parasite_blob_desc { extern struct parasite_blob_desc *compel_parasite_blob_desc(struct parasite_ctl *); typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); -extern int compel_get_thread_regs(pid_t pid, struct parasite_thread_ctl *, save_regs_t, void *); +extern int compel_get_thread_regs(struct parasite_thread_ctl *, save_regs_t, void *); extern void compel_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *elf_relocs, size_t nr_relocs); diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index b8e229302..78427591d 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -856,6 +856,9 @@ struct parasite_thread_ctl *compel_prepare_thread(struct parasite_ctl *ctl, int if (prepare_thread(pid, &tctl->th)) { xfree(tctl); tctl = NULL; + } else { + tctl->tid = pid; + tctl->ctl = ctl; } } @@ -1083,10 +1086,10 @@ void *compel_parasite_args_s(struct parasite_ctl *ctl, int args_size) return compel_parasite_args_p(ctl); } -int compel_run_in_thread(pid_t pid, unsigned int cmd, - struct parasite_ctl *ctl, - struct parasite_thread_ctl *tctl) +int compel_run_in_thread(struct parasite_thread_ctl *tctl, unsigned int cmd) { + int pid = tctl->tid; + struct parasite_ctl *ctl = tctl->ctl; struct thread_ctx *octx = &tctl->th; void *stack = ctl->r_thread_stack; user_regs_struct_t regs = octx->regs; @@ -1297,9 +1300,9 @@ k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl) return thread_ctx_sigmask(&ctl->orig); } -int compel_get_thread_regs(pid_t pid, struct parasite_thread_ctl *tctl, save_regs_t save, void * arg) +int compel_get_thread_regs(struct parasite_thread_ctl *tctl, save_regs_t save, void * arg) { - return get_task_regs(pid, tctl->th.regs, save, arg); + return get_task_regs(tctl->tid, tctl->th.regs, save, arg); } struct infect_ctx *compel_infect_ctx(struct parasite_ctl *ctl) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 1a052a098..be93b319e 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -203,7 +203,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, tc->has_blk_sigset = true; memcpy(&tc->blk_sigset, compel_thread_sigmask(tctl), sizeof(k_rtsigset_t)); - ret = compel_run_in_thread(pid, PARASITE_CMD_DUMP_THREAD, ctl, tctl); + ret = compel_run_in_thread(tctl, PARASITE_CMD_DUMP_THREAD); if (ret) { pr_err("Can't init thread in parasite %d\n", pid); goto err_rth; @@ -215,7 +215,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, goto err_rth; } - ret = compel_get_thread_regs(pid, tctl, save_task_regs, core); + ret = compel_get_thread_regs(tctl, save_task_regs, core); if (ret) { pr_err("Can't obtain regs for thread %d\n", pid); goto err_rth; From 5dac5448cf192d1756190e2560992cdfbff0bddd Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 14 Nov 2016 16:06:02 +0300 Subject: [PATCH 0219/4375] compel: Move log-related stuff into include/uapi/log.h This cleans up the main-entry header compel.h Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/compel.h | 8 +------- compel/include/uapi/log.h | 7 +++++++ 2 files changed, 8 insertions(+), 7 deletions(-) create mode 100644 compel/include/uapi/log.h diff --git a/compel/include/uapi/compel.h b/compel/include/uapi/compel.h index 3554c1599..a3faa18d9 100644 --- a/compel/include/uapi/compel.h +++ b/compel/include/uapi/compel.h @@ -17,13 +17,7 @@ typedef struct { long value; } compel_reloc_t; -/* - * Logging - */ -typedef void (*compel_log_fn)(unsigned int lvl, const char *fmt, va_list parms); -extern void compel_log_init(compel_log_fn log_fn, unsigned int level); -extern unsigned int compel_log_get_loglevel(void); - +#include #include #include #include diff --git a/compel/include/uapi/log.h b/compel/include/uapi/log.h new file mode 100644 index 000000000..cd3bf2aff --- /dev/null +++ b/compel/include/uapi/log.h @@ -0,0 +1,7 @@ +#ifndef __COMPEL_UAPI_LOG_H__ +#define __COMPEL_UAPI_LOG_H__ +#include +typedef void (*compel_log_fn)(unsigned int lvl, const char *fmt, va_list parms); +extern void compel_log_init(compel_log_fn log_fn, unsigned int level); +extern unsigned int compel_log_get_loglevel(void); +#endif From b46e5ec1184ff3903370f20ab3eda5a88c6f8a80 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 14 Nov 2016 16:06:15 +0300 Subject: [PATCH 0220/4375] compel: Move relocs stuff into include/uapi/handle-elf.h The same as prev patch -- clean up the compel.h Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/compel.h | 13 +------------ compel/include/uapi/handle-elf.h | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 compel/include/uapi/handle-elf.h diff --git a/compel/include/uapi/compel.h b/compel/include/uapi/compel.h index a3faa18d9..318a472da 100644 --- a/compel/include/uapi/compel.h +++ b/compel/include/uapi/compel.h @@ -5,18 +5,7 @@ #include #include - -#define COMPEL_TYPE_INT (1u << 0) -#define COMPEL_TYPE_LONG (1u << 1) -#define COMPEL_TYPE_GOTPCREL (1u << 2) - -typedef struct { - unsigned int offset; - unsigned int type; - long addend; - long value; -} compel_reloc_t; - +#include #include #include #include diff --git a/compel/include/uapi/handle-elf.h b/compel/include/uapi/handle-elf.h new file mode 100644 index 000000000..ddeecb0d5 --- /dev/null +++ b/compel/include/uapi/handle-elf.h @@ -0,0 +1,15 @@ +#ifndef __COMPEL_UAPI_HANDLE_ELF__ +#define __COMPEL_UAPI_HANDLE_ELF__ + +#define COMPEL_TYPE_INT (1u << 0) +#define COMPEL_TYPE_LONG (1u << 1) +#define COMPEL_TYPE_GOTPCREL (1u << 2) + +typedef struct { + unsigned int offset; + unsigned int type; + long addend; + long value; +} compel_reloc_t; + +#endif From 387361946ec4f01b82459d9eb3e50c1693ecc1c2 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 16 Nov 2016 18:06:48 +0300 Subject: [PATCH 0221/4375] criu: pie,log -- Prepate to move into compel std plugin - Add uapi header and start using it - Add std_ prefix into functions and constants - Drop unneeded headers travis-ci: success for compel: The final infect move and install target Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/include/uapi/std/log.h | 14 ++++++++++++++ criu/include/log.h | 9 --------- criu/pie/infect.c | 7 ++++--- criu/pie/log-simple.c | 27 +++++++++++++-------------- criu/pie/restorer.c | 15 ++++++++------- 5 files changed, 39 insertions(+), 33 deletions(-) create mode 100644 compel/plugins/include/uapi/std/log.h diff --git a/compel/plugins/include/uapi/std/log.h b/compel/plugins/include/uapi/std/log.h new file mode 100644 index 000000000..4b2bf8afa --- /dev/null +++ b/compel/plugins/include/uapi/std/log.h @@ -0,0 +1,14 @@ +#ifndef COMPEL_PLUGIN_STD_LOG_H__ +#define COMPEL_PLUGIN_STD_LOG_H__ + +#define STD_LOG_SIMPLE_CHUNK 79 + +extern void std_log_set_fd(int fd); +extern void std_log_set_loglevel(unsigned int level); +extern int std_vprint_num(char *buf, int blen, int num, char **ps); +extern void std_sprintf(char output[STD_LOG_SIMPLE_CHUNK], const char *format, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); +extern void print_on_level(unsigned int loglevel, const char *format, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); + +#endif /* COMPEL_PLUGIN_STD_LOG_H__ */ diff --git a/criu/include/log.h b/criu/include/log.h index 2ecadb359..9c4c28386 100644 --- a/criu/include/log.h +++ b/criu/include/log.h @@ -72,15 +72,6 @@ extern void print_on_level(unsigned int loglevel, const char *format, ...) #define pr_perror(fmt, ...) \ pr_err(fmt ": %s\n", ##__VA_ARGS__, strerror(errno)) -#else - -#define LOG_SIMPLE_CHUNK 79 - -extern int vprint_num(char *buf, int blen, int num, char **ps); -extern void simple_sprintf(char output[LOG_SIMPLE_CHUNK], const char *format, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); - #endif /* CR_NOGLIBC */ - #endif /* __CR_LOG_H__ */ diff --git a/criu/pie/infect.c b/criu/pie/infect.c index 1863a1ee9..b75900755 100644 --- a/criu/pie/infect.c +++ b/criu/pie/infect.c @@ -3,6 +3,7 @@ #include "int.h" #include "util-pie.h" +#include #include "criu-log.h" #include "common/bug.h" #include "sigframe.h" @@ -79,7 +80,7 @@ static int fini(void) new_sp, RT_SIGFRAME_REGIP(sigframe)); sys_close(tsock); - log_set_fd(-1); + std_log_set_fd(-1); fini_sigreturn(new_sp); @@ -168,8 +169,8 @@ static noinline __used int parasite_init_daemon(void *data) ret = recv_fd(tsock); if (ret >= 0) { - log_set_fd(ret); - log_set_loglevel(args->log_level); + std_log_set_fd(ret); + std_log_set_loglevel(args->log_level); ret = 0; } else goto err; diff --git a/criu/pie/log-simple.c b/criu/pie/log-simple.c index f54bb0133..e324a871a 100644 --- a/criu/pie/log-simple.c +++ b/criu/pie/log-simple.c @@ -1,14 +1,13 @@ #include -#include "int.h" -#include "types.h" #include "string.h" #include "common/bitsperlong.h" #include -#include "log.h" +#include +#include struct simple_buf { - char buf[LOG_SIMPLE_CHUNK]; + char buf[STD_LOG_SIMPLE_CHUNK]; char *bp; int prefix_len; void (*flush)(struct simple_buf *b); @@ -59,7 +58,7 @@ static void sbuf_log_init(struct simple_buf *b) timediff(&start, &now); /* Seconds */ - n = vprint_num(pbuf, sizeof(pbuf), (unsigned)now.tv_sec, &s); + n = std_vprint_num(pbuf, sizeof(pbuf), (unsigned)now.tv_sec, &s); pad_num(&s, &n, 2); b->bp[0] = '('; memcpy(b->bp + 1, s, n); @@ -67,14 +66,14 @@ static void sbuf_log_init(struct simple_buf *b) b->bp += n + 2; /* Mu-seconds */ - n = vprint_num(pbuf, sizeof(pbuf), (unsigned)now.tv_usec, &s); + n = std_vprint_num(pbuf, sizeof(pbuf), (unsigned)now.tv_usec, &s); pad_num(&s, &n, 6); memcpy(b->bp, s, n); b->bp[n] = ')'; b->bp += n + 1; } - n = vprint_num(pbuf, sizeof(pbuf), sys_gettid(), &s); + n = std_vprint_num(pbuf, sizeof(pbuf), sys_gettid(), &s); b->bp[0] = 'p'; b->bp[1] = 'i'; b->bp[2] = 'e'; @@ -100,12 +99,12 @@ static void sbuf_log_flush(struct simple_buf *b) static void sbuf_putc(struct simple_buf *b, char c) { /* TODO: maybe some warning or error here? */ - if (b->bp - b->buf >= LOG_SIMPLE_CHUNK) + if (b->bp - b->buf >= STD_LOG_SIMPLE_CHUNK) return; *b->bp = c; b->bp++; - if (b->bp - b->buf >= LOG_SIMPLE_CHUNK - 2) { + if (b->bp - b->buf >= STD_LOG_SIMPLE_CHUNK - 2) { b->bp[0] = '>'; b->bp[1] = '\n'; b->bp += 2; @@ -114,13 +113,13 @@ static void sbuf_putc(struct simple_buf *b, char c) } } -void log_set_fd(int fd) +void std_log_set_fd(int fd) { sys_close(logfd); logfd = fd; } -void log_set_loglevel(unsigned int level) +void std_log_set_loglevel(unsigned int level) { cur_loglevel = level; } @@ -138,7 +137,7 @@ static void print_string(const char *msg, struct simple_buf *b) } } -int vprint_num(char *buf, int blen, int num, char **ps) +int std_vprint_num(char *buf, int blen, int num, char **ps) { int neg = 0; char *s; @@ -175,7 +174,7 @@ static void print_num(int num, struct simple_buf *b) char buf[12], *s; buf[11] = '\0'; - vprint_num(buf, sizeof(buf) - 1, num, &s); + std_vprint_num(buf, sizeof(buf) - 1, num, &s); print_string(s, b); } @@ -341,7 +340,7 @@ void print_on_level(unsigned int loglevel, const char *format, ...) sbuf_log_flush(&b); } -void simple_sprintf(char output[LOG_SIMPLE_CHUNK], const char *format, ...) +void std_sprintf(char output[STD_LOG_SIMPLE_CHUNK], const char *format, ...) { va_list args; struct simple_buf b; diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index edcc1934e..be1840c9e 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -22,6 +22,7 @@ #include "common/compiler.h" #include "string.h" #include +#include #include #include "signal.h" #include "config.h" @@ -103,14 +104,14 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) static int lsm_set_label(char *label, int procfd) { int ret = -1, len, lsmfd; - char path[LOG_SIMPLE_CHUNK]; + char path[STD_LOG_SIMPLE_CHUNK]; if (!label) return 0; pr_info("restoring lsm profile %s\n", label); - simple_sprintf(path, "self/task/%ld/attr/current", sys_gettid()); + std_sprintf(path, "self/task/%ld/attr/current", sys_gettid()); lsmfd = sys_openat(procfd, path, O_WRONLY, 0); if (lsmfd < 0) { @@ -1087,9 +1088,9 @@ long __export_restore_task(struct task_restore_args *args) ksigaddset(&to_block, SIGCHLD); ret = sys_sigprocmask(SIG_UNBLOCK, &to_block, NULL, sizeof(k_rtsigset_t)); - log_set_fd(args->logfd); - log_set_loglevel(args->loglevel); - log_set_start(&args->logstart); + std_log_set_fd(args->logfd); + std_log_set_loglevel(args->loglevel); + std_log_set_start(&args->logstart); pr_info("Switched to the restorer %d\n", my_pid); @@ -1357,7 +1358,7 @@ long __export_restore_task(struct task_restore_args *args) continue; new_sp = restorer_stack(thread_args[i].mz); - last_pid_len = vprint_num(last_pid_buf, sizeof(last_pid_buf), thread_args[i].pid - 1, &s); + last_pid_len = std_vprint_num(last_pid_buf, sizeof(last_pid_buf), thread_args[i].pid - 1, &s); sys_lseek(fd, 0, SEEK_SET); ret = sys_write(fd, s, last_pid_len); if (ret < 0) { @@ -1470,7 +1471,7 @@ long __export_restore_task(struct task_restore_args *args) futex_wait_while_gt(&thread_inprogress, 1); sys_close(args->proc_fd); - log_set_fd(-1); + std_log_set_fd(-1); /* * The code that prepared the itimers makes shure the From a51068664bfb1b91432dc6f1bcae07b89c4fe226 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 16 Nov 2016 18:06:49 +0300 Subject: [PATCH 0222/4375] compel: plugins,std -- Move in log engine from criu pie travis-ci: success for compel: The final infect move and install target Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/Makefile | 1 + compel/plugins/include/uapi/std/log.h | 1 + criu/pie/log-simple.c => compel/plugins/std/log.c | 2 +- criu/include/criu-log.h | 1 - criu/pie/Makefile.library | 2 +- 5 files changed, 4 insertions(+), 3 deletions(-) rename criu/pie/log-simple.c => compel/plugins/std/log.c (99%) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 4cfeced4c..ccd74d515 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -48,6 +48,7 @@ shmem-obj-y += shmem/shmem.o # STD plugin target += std std-obj-y += std/std.o +std-obj-y += std/log.o std-obj-y += std/string.o include ./$(PLUGIN_ARCH_DIR)/std/syscalls/Makefile.syscalls diff --git a/compel/plugins/include/uapi/std/log.h b/compel/plugins/include/uapi/std/log.h index 4b2bf8afa..3a3d88992 100644 --- a/compel/plugins/include/uapi/std/log.h +++ b/compel/plugins/include/uapi/std/log.h @@ -5,6 +5,7 @@ extern void std_log_set_fd(int fd); extern void std_log_set_loglevel(unsigned int level); +extern void std_log_set_start(struct timeval *tv); extern int std_vprint_num(char *buf, int blen, int num, char **ps); extern void std_sprintf(char output[STD_LOG_SIMPLE_CHUNK], const char *format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); diff --git a/criu/pie/log-simple.c b/compel/plugins/std/log.c similarity index 99% rename from criu/pie/log-simple.c rename to compel/plugins/std/log.c index e324a871a..28d2259f1 100644 --- a/criu/pie/log-simple.c +++ b/compel/plugins/std/log.c @@ -124,7 +124,7 @@ void std_log_set_loglevel(unsigned int level) cur_loglevel = level; } -void log_set_start(struct timeval *s) +void std_log_set_start(struct timeval *s) { start = *s; } diff --git a/criu/include/criu-log.h b/criu/include/criu-log.h index 437e23784..ce6018860 100644 --- a/criu/include/criu-log.h +++ b/criu/include/criu-log.h @@ -35,7 +35,6 @@ extern int log_get_fd(void); extern void log_set_loglevel(unsigned int loglevel); extern unsigned int log_get_loglevel(void); extern void log_get_logstart(struct timeval *); -extern void log_set_start(struct timeval *s); extern int write_pidfile(int pid); diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index a76ee4b35..19168048b 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -17,7 +17,7 @@ ifeq ($(ARCH),x86) OBJS += ./$(ARCH_DIR)/memcpy.o endif -OBJS += log-simple.o util-fd.o util.o string.o +OBJS += util-fd.o util.o string.o ifeq ($(VDSO),y) OBJS += util-vdso.o parasite-vdso.o ./$(ARCH_DIR)/vdso-pie.o From 51458d45189a09a242c4b86d51d09c69b00ba1f1 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 16 Nov 2016 18:06:50 +0300 Subject: [PATCH 0223/4375] compel: plugins,std -- Move in infect code Providing infect functionality inside std plugin doesn't look suite for me: the restorer has to define dummy parasite_daemon_cmd/parasite_trap_cmd/parasite_cleanup just to be able to compile with it. So we have to define weak stubs right here in near future. travis-ci: success for compel: The final infect move and install target Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .../arch/aarch64/plugins/std}/parasite-head.S | 0 .../arch/arm/plugins/std}/parasite-head.S | 0 .../arch/ppc64/plugins/std}/parasite-head.S | 0 .../x86/plugins/std/parasite-head-compat.S | 0 .../arch/x86/plugins/std/parasite-head.S | 0 compel/plugins/Makefile | 2 + compel/plugins/include/uapi/plugin-std.h | 1 + compel/plugins/include/uapi/std/infect.h | 20 +++++++++ {criu/pie => compel/plugins/std}/infect.c | 43 ++++++++----------- compel/src/lib/infect.c | 2 - criu/Makefile | 2 +- criu/pie/Makefile | 19 +++----- criu/pie/compat/infect-compat.c | 1 - criu/pie/restorer.c | 17 ++++++++ 14 files changed, 65 insertions(+), 42 deletions(-) rename {criu/arch/aarch64 => compel/arch/aarch64/plugins/std}/parasite-head.S (100%) rename {criu/arch/arm => compel/arch/arm/plugins/std}/parasite-head.S (100%) rename {criu/arch/ppc64 => compel/arch/ppc64/plugins/std}/parasite-head.S (100%) rename criu/arch/x86/parasite-head-32.S => compel/arch/x86/plugins/std/parasite-head-compat.S (100%) rename criu/arch/x86/parasite-head-64.S => compel/arch/x86/plugins/std/parasite-head.S (100%) create mode 100644 compel/plugins/include/uapi/std/infect.h rename {criu/pie => compel/plugins/std}/infect.c (82%) delete mode 120000 criu/pie/compat/infect-compat.c diff --git a/criu/arch/aarch64/parasite-head.S b/compel/arch/aarch64/plugins/std/parasite-head.S similarity index 100% rename from criu/arch/aarch64/parasite-head.S rename to compel/arch/aarch64/plugins/std/parasite-head.S diff --git a/criu/arch/arm/parasite-head.S b/compel/arch/arm/plugins/std/parasite-head.S similarity index 100% rename from criu/arch/arm/parasite-head.S rename to compel/arch/arm/plugins/std/parasite-head.S diff --git a/criu/arch/ppc64/parasite-head.S b/compel/arch/ppc64/plugins/std/parasite-head.S similarity index 100% rename from criu/arch/ppc64/parasite-head.S rename to compel/arch/ppc64/plugins/std/parasite-head.S diff --git a/criu/arch/x86/parasite-head-32.S b/compel/arch/x86/plugins/std/parasite-head-compat.S similarity index 100% rename from criu/arch/x86/parasite-head-32.S rename to compel/arch/x86/plugins/std/parasite-head-compat.S diff --git a/criu/arch/x86/parasite-head-64.S b/compel/arch/x86/plugins/std/parasite-head.S similarity index 100% rename from criu/arch/x86/parasite-head-64.S rename to compel/arch/x86/plugins/std/parasite-head.S diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index ccd74d515..9e66c74bb 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -50,6 +50,8 @@ target += std std-obj-y += std/std.o std-obj-y += std/log.o std-obj-y += std/string.o +std-obj-y += std/infect.o +std-obj-y += ./$(PLUGIN_ARCH_DIR)/std/parasite-head.o include ./$(PLUGIN_ARCH_DIR)/std/syscalls/Makefile.syscalls diff --git a/compel/plugins/include/uapi/plugin-std.h b/compel/plugins/include/uapi/plugin-std.h index f91e2acbd..29e6c1b11 100644 --- a/compel/plugins/include/uapi/plugin-std.h +++ b/compel/plugins/include/uapi/plugin-std.h @@ -4,5 +4,6 @@ #include #include #include +#include #endif /* COMPEL_PLUGIN_STD_STD_H__ */ diff --git a/compel/plugins/include/uapi/std/infect.h b/compel/plugins/include/uapi/std/infect.h new file mode 100644 index 000000000..800df2509 --- /dev/null +++ b/compel/plugins/include/uapi/std/infect.h @@ -0,0 +1,20 @@ +#ifndef COMPEL_PLUGIN_STD_INFECT_H__ +#define COMPEL_PLUGIN_STD_INFECT_H__ + +extern int parasite_get_rpc_sock(void); +extern int parasite_service(unsigned int cmd, void *args); + +/* + * Must be supplied by user plugins. + */ +extern int parasite_daemon_cmd(int cmd, void *args); +extern int parasite_trap_cmd(int cmd, void *args); +extern void parasite_cleanup(void); + +/* + * FIXME: Should be supplied by log module. + */ +extern void log_set_fd(int fd); +extern void log_set_loglevel(unsigned int level); + +#endif /* COMPEL_PLUGIN_STD_INFECT_H__ */ diff --git a/criu/pie/infect.c b/compel/plugins/std/infect.c similarity index 82% rename from criu/pie/infect.c rename to compel/plugins/std/infect.c index b75900755..844bbb6f7 100644 --- a/criu/pie/infect.c +++ b/compel/plugins/std/infect.c @@ -1,15 +1,24 @@ +#include +#include + +#include "common/scm.h" +#include "uapi/compel/plugins/plugin-fds.h" +#include "uapi/compel/plugins/std/string.h" +#include "uapi/compel/plugins/std/log.h" + #include "common/compiler.h" #include "common/lock.h" -#include "int.h" -#include "util-pie.h" -#include -#include "criu-log.h" +#define pr_err(fmt, ...) print_on_level(1, fmt, ##__VA_ARGS__) +#define pr_info(fmt, ...) print_on_level(3, fmt, ##__VA_ARGS__) +#define pr_debug(fmt, ...) print_on_level(4, fmt, ##__VA_ARGS__) + #include "common/bug.h" -#include "sigframe.h" -#include "infect-rpc.h" -#include "infect-pie.h" -#include "compel/include/rpc-pie-priv.h" + +#include "uapi/compel/asm/sigframe.h" +#include "uapi/compel/infect-rpc.h" + +#include "rpc-pie-priv.h" static int tsock = -1; @@ -202,21 +211,3 @@ int __used __parasite_entry parasite_service(unsigned int cmd, void *args) return parasite_trap_cmd(cmd, args); } - -/* - * Mainally, -fstack-protector is disabled for parasite. - * But we share some object files, compiled for CRIU with parasite. - * Those files (like cpu.c) may be compiled with stack protector - * support. We can't use gcc-ld provided stackprotector callback, - * as Glibc is unmapped. Let's just try to cure application in - * case of stack smashing in parasite. - */ -void __stack_chk_fail(void) -{ - /* - * Smash didn't happen in printing part, as it's not shared - * with CRIU, therefore compiled with -fnostack-protector. - */ - pr_err("Stack smash detected in parasite\n"); - fini(); -} diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 78427591d..d09721ed6 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -32,8 +32,6 @@ #define __sys(foo) foo #define __memcpy memcpy -#define SCM_FDSET_HAS_OPTS - #include "common/scm.h" #include "common/scm-code.c" diff --git a/criu/Makefile b/criu/Makefile index 6c06029e7..f88f13a5a 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -59,7 +59,7 @@ criu/pie/native.lib.a: $(ARCH-LIB) # # PIE code blobs themseves. -pie: criu/pie/native.lib.a +pie: criu/pie/native.lib.a compel/plugins/std.built-in.o $(Q) $(MAKE) $(build)=criu/pie all .PHONY: pie diff --git a/criu/pie/Makefile b/criu/pie/Makefile index c010964a3..e58cc7502 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -8,11 +8,11 @@ endif compel_pack_lds-native := $(SRC_DIR)/compel/arch/$(ARCH)/scripts/compel-pack.lds.S compel_pack_lds-compat := $(SRC_DIR)/compel/arch/$(ARCH)/scripts/compel-pack-compat.lds.S +compel_std-native := $(SRC_DIR)/compel/plugins/std.built-in.o +compel_std-compat := $(SRC_DIR)/compel/plugins/std-compat.built-in.o native-obj-y += parasite.o -native-obj-y += infect.o compat-obj-y += compat/parasite-compat.o -compat-obj-y += compat/infect-compat.o restorer-obj-y += restorer.o restorer-obj-y += ./$(ARCH_DIR)/restorer.o @@ -25,18 +25,9 @@ ifeq ($(ARCH),x86) restorer-obj-y += ./$(ARCH_DIR)/sigaction_compat_pie.o endif - native-obj-y += ./$(ARCH_DIR)/parasite-head-64.o native-obj-e += ./compel/plugins/std.built-in.o - compat-obj-y += ./$(ARCH_DIR)/parasite-head-32.o - compat-obj-e += ./compel/plugins/std-32.built-in.o - - AFLAGS_parasite-head-64.o += -fpie -DCONFIG_X86_64 - AFLAGS_parasite-head-64.d += -fpie -DCONFIG_X86_64 - - AFLAGS_parasite-head-32.o += -fno-pic -m32 -DCONFIG_X86_32 - AFLAGS_parasite-head-32.d += -fno-pic -m32 -DCONFIG_X86_32 + compat-obj-e += ./compel/plugins/std-compat.built-in.o else - native-obj-y += ./$(ARCH_DIR)/parasite-head.o native-obj-e += ./compel/plugins/std.built-in.o restorer-obj-e += ./compel/plugins/std.built-in.o endif @@ -114,6 +105,7 @@ ifeq ($(strip $(V)),) piegen_stdout := >/dev/null endif +$(obj)/restorer.built-in.o: $(compel_std-native) $(obj)/restorer.built-in.bin.o: $(obj)/restorer.built-in.o \ $(obj)/native.lib.a $(compel_pack_lds-native) $(call msg-gen, $@) @@ -121,6 +113,7 @@ $(obj)/restorer.built-in.bin.o: $(obj)/restorer.built-in.o \ # $1 - binary mode: native/compat define gen-rule-built-in.bin.o +$(obj)/$(1).built-in.o: $(compel_std-$(1)) $(obj)/parasite-$(1).built-in.bin.o: $(obj)/$(1).built-in.o \ $(obj)/$(1).lib.a $(compel_pack_lds-$(1)) $$(call msg-gen, $$@) @@ -147,6 +140,7 @@ ifeq ($(filter arm aarch64,$(ARCH)),) endif define gen-rule-built-in.bin.o +$(obj)/$(1).built-in.o: $(compel_std-$(1)) $(obj)/parasite-$(1).built-in.bin.o: $(obj)/$(1).built-in.o \ $(compel_pack_lds-$(1)) $(obj)/native.lib.a $$(call msg-gen, $$@) @@ -155,6 +149,7 @@ endef $(eval $(call map,gen-rule-built-in.bin.o,$(parasite_target))) +$(obj)/restorer.built-in.o: $(compel_std-native) $(obj)/restorer.built-in.bin.o: $(obj)/restorer.built-in.o \ $(compel_pack_lds-native) $(obj)/native.lib.a $(call msg-gen, $@) diff --git a/criu/pie/compat/infect-compat.c b/criu/pie/compat/infect-compat.c deleted file mode 120000 index 87c7722b6..000000000 --- a/criu/pie/compat/infect-compat.c +++ /dev/null @@ -1 +0,0 @@ -../infect.c \ No newline at end of file diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index be1840c9e..6dbe01ece 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -63,11 +63,28 @@ static int n_helpers; static pid_t *zombies; static int n_zombies; +/* + * These are stubs for std compel plugin. + */ int compel_main(void *arg_p, unsigned int arg_s) { return 0; } +int parasite_daemon_cmd(int cmd, void *args) +{ + return 0; +} + +int parasite_trap_cmd(int cmd, void *args) +{ + return 0; +} + +void parasite_cleanup(void) +{ +} + extern void cr_restore_rt (void) asm ("__cr_restore_rt") __attribute__ ((visibility ("hidden"))); From aa72d8872b1c4d58ace897885ea8ee7b12401749 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 18 Nov 2016 04:23:00 +0300 Subject: [PATCH 0224/4375] compel: check whether a parasite socket is prepared each time Currently we prepare a parasite socket only once and save it in a static variable. It's bad idea to use a static variable in a library. In addition, it doesn't work if we have processes in different network namespaces. In this case, we have to have a separate socket for each namespace. v2: fix compilation on Alpine convert *p_sock into sock travis-ci: success for compel: check whether a parasite socket is prepared each time (rev2) Signed-off-by: Andrei Vagin Signed-off-by: Pavel Emelyanov --- compel/include/uapi/infect.h | 2 +- compel/src/lib/infect.c | 21 ++++++++++++++------- criu/parasite-syscall.c | 2 +- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 75fc4a7a9..adc40f2d9 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -96,7 +96,7 @@ typedef int (*open_proc_fn)(int pid, int mode, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); struct infect_ctx { - int *p_sock; + int sock; /* * Regs manipulation context. diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index d09721ed6..3ba34cdc6 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -320,20 +320,27 @@ static int gen_parasite_saddr(struct sockaddr_un *saddr, int key) static int prepare_tsock(struct parasite_ctl *ctl, pid_t pid, struct parasite_init_args *args) { - static int ssock = -1; + int ssock = -1; + socklen_t sk_len; + struct sockaddr_un addr; pr_info("Putting tsock into pid %d\n", pid); args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid()); + ssock = ctl->ictx.sock; + sk_len = sizeof(addr); + if (ssock == -1) { - ssock = *ctl->ictx.p_sock; - if (ssock == -1) { - pr_err("No socket in ictx\n"); - goto err; - } + pr_err("No socket in ictx\n"); + goto err; + } - *ctl->ictx.p_sock = -1; + if (getsockname(ssock, (struct sockaddr *) &addr, &sk_len) < 0) { + pr_perror("Unable to get name for a socket"); + return -1; + } + if (sk_len == sizeof(addr.sun_family)) { if (bind(ssock, (struct sockaddr *)&args->h_addr, args->h_addr_len) < 0) { pr_perror("Can't bind socket"); goto err; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index be93b319e..77fc6238c 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -581,7 +581,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ictx->open_proc = do_open_proc; ictx->child_handler = sigchld_handler; - ictx->p_sock = &dmpi(item)->netns->net.seqsk; + ictx->sock = dmpi(item)->netns->net.seqsk; ictx->save_regs = save_task_regs; ictx->make_sigframe = make_sigframe; ictx->regs_arg = item->core[0]; From 964a501b164333ccc2d4a7d05fa24df5ab2d85c6 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 10 Nov 2016 16:32:28 -0800 Subject: [PATCH 0225/4375] criu/pie/Makefile: disable FORTIFY_SOURCE This is highly controversial, but fixes the following compilation problem with Alpine Linux (i.e. musl libc) caused by the previous commit (""): > gcc -c -O2 -g -Wall -Wformat-security -Werror -D_FILE_OFFSET_BITS=64 > -D_GNU_SOURCE -iquote include/ -iquote /criu/compel/include -iquote > /criu/criu/arch/x86/include -iquote /criu/criu/include -iquote > /criu/include -iquote /criu -fno-strict-aliasing -iquote > /criu/criu/include -iquote /criu/include -iquote /criu/images -iquote > /criu/criu/pie -iquote /criu/criu/arch/x86 -iquote > /criu/criu/arch/x86/include -iquote /criu/ -I/usr/include/libnl3 -iquote > compel/plugins/include -iquote compel/include -iquote > compel/arch/x86/plugins/std -iquote /criu/compel/plugins/include -iquote > /criu/compel/include -DCR_NOGLIBC -Wstrict-prototypes > -fno-stack-protector -nostdlib -fomit-frame-pointer -fpie > -DCONFIG_X86_64 criu/pie/parasite.c -o criu/pie/parasite.o > In file included from /criu/criu/include/util.h:10:0, > from /criu/criu/include/restorer.h:13, > from criu/pie/parasite.c:23: > /usr/include/fortify/string.h:37:27: error: redefinition of 'memcpy' > _FORTIFY_FN(memcpy) void *memcpy(void *__od, const void *__os, size_t > __n) > ^ > In file included from > compel/plugins/include/uapi/std/syscall-types.h:13:0, > from compel/plugins/include/uapi/std/syscall-64.h:5, > from compel/plugins/include/uapi/std/syscall.h:8, > from criu/pie/parasite.c:11: > /usr/include/sched.h:72:7: note: previous definition of 'memcpy' was > here > void *memcpy(void *__restrict, const void *__restrict, size_t); > ^ > In file included from /criu/criu/include/util.h:10:0, > from /criu/criu/include/restorer.h:13, > from criu/pie/parasite.c:23: > /usr/include/fortify/string.h:64:27: error: redefinition of 'memset' > _FORTIFY_FN(memset) void *memset(void *__d, int __c, size_t __n) > ^ > In file included from /usr/include/fortify/string.h:20:0, > from /criu/criu/include/util.h:10, > from /criu/criu/include/restorer.h:13, > from criu/pie/parasite.c:23: > /usr/include/string.h:27:7: note: previous definition of 'memset' was > here > void *memset (void *, int, size_t); > ^ > /criu/scripts/nmk/scripts/build.mk:103: recipe for target > 'criu/pie/parasite.o' failed > https://travis-ci.org/kolyshkin/criu/builds/174634847 Signed-off-by: Kir Kolyshkin Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index e58cc7502..cec463281 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -52,6 +52,7 @@ CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 ccflags-y += -I compel/include/uapi ccflags-y += -I compel/plugins/include/uapi ccflags-y += -DCR_NOGLIBC +ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) NATIVE_CFLAGS := $(shell $(SRC_DIR)/compel/compel-host --arch=$(ARCH) cflags) ifeq ($(ARCH),x86) From 5f0695e650ccfe4cd406891b2a45c0136eff79b1 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 18 Nov 2016 18:21:00 +0300 Subject: [PATCH 0226/4375] criu: Drop dangling symlink PIE logger already in compel. Forgot to remove. travis-ci: success for criu: Drop dangling symlink Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/compat/log-simple-compat.c | 1 - 1 file changed, 1 deletion(-) delete mode 120000 criu/pie/compat/log-simple-compat.c diff --git a/criu/pie/compat/log-simple-compat.c b/criu/pie/compat/log-simple-compat.c deleted file mode 120000 index fd4c4bae2..000000000 --- a/criu/pie/compat/log-simple-compat.c +++ /dev/null @@ -1 +0,0 @@ -../log-simple.c \ No newline at end of file From fd26c6fcd68d6c799debd228e539aa3dddbf12d1 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 18 Nov 2016 19:44:52 +0300 Subject: [PATCH 0227/4375] compel: Drop common/page.h from UAPI headers This one is needed only for task_size() on some arches and it is simpler to keep this routine in compel .c rather than messing with common/page.h installation. https://travis-ci.org/xemul/criu/builds/177585567 Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .../src/lib/include/uapi/asm/infect-types.h | 21 ------------------ compel/arch/aarch64/src/lib/infect.c | 22 +++++++++++++++++++ .../src/lib/include/uapi/asm/infect-types.h | 21 ------------------ compel/arch/arm/src/lib/infect.c | 22 +++++++++++++++++++ .../src/lib/include/uapi/asm/infect-types.h | 10 --------- compel/arch/ppc64/src/lib/infect.c | 10 +++++++++ .../src/lib/include/uapi/asm/infect-types.h | 17 +++----------- compel/arch/x86/src/lib/infect.c | 12 ++++++++++ compel/include/uapi/infect.h | 2 ++ criu/kerndat.c | 3 ++- 10 files changed, 73 insertions(+), 67 deletions(-) diff --git a/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h b/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h index 714881c57..eabf1f22f 100644 --- a/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h @@ -5,7 +5,6 @@ #include #include #include -#include "common/page.h" #define SIGMAX 64 #define SIGMAX_OLD 31 @@ -25,26 +24,6 @@ typedef struct user_fpsimd_state user_fpregs_struct_t; #define user_regs_native(pregs) true -/* - * Range for task size calculated from the following Linux kernel files: - * arch/arm64/include/asm/memory.h - * arch/arm64/Kconfig - * - * TODO: handle 32 bit tasks - */ -#define TASK_SIZE_MIN (1UL << 39) -#define TASK_SIZE_MAX (1UL << 48) - -static inline unsigned long task_size(void) -{ - unsigned long task_size; - - for (task_size = TASK_SIZE_MIN; task_size < TASK_SIZE_MAX; task_size <<= 1) - if (munmap((void *)task_size, page_size())) - break; - return task_size; -} - #define AT_VECTOR_SIZE 40 typedef uint64_t auxv_t; diff --git a/compel/arch/aarch64/src/lib/infect.c b/compel/arch/aarch64/src/lib/infect.c index 95d6fc592..0fc639a1e 100644 --- a/compel/arch/aarch64/src/lib/infect.c +++ b/compel/arch/aarch64/src/lib/infect.c @@ -3,6 +3,7 @@ #include #include #include +#include "common/page.h" #include "uapi/compel/asm/infect-types.h" #include "log.h" #include "errno.h" @@ -109,3 +110,24 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) */ return true; } + +/* + * Range for task size calculated from the following Linux kernel files: + * arch/arm64/include/asm/memory.h + * arch/arm64/Kconfig + * + * TODO: handle 32 bit tasks + */ +#define TASK_SIZE_MIN (1UL << 39) +#define TASK_SIZE_MAX (1UL << 48) + +unsigned long compel_task_size(void) +{ + unsigned long task_size; + + for (task_size = TASK_SIZE_MIN; task_size < TASK_SIZE_MAX; task_size <<= 1) + if (munmap((void *)task_size, page_size())) + break; + return task_size; +} + diff --git a/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h b/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h index 9c2092e5d..b532c7dd9 100644 --- a/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h @@ -3,7 +3,6 @@ #include #include -#include "common/page.h" #define SIGMAX 64 #define SIGMAX_OLD 31 @@ -59,26 +58,6 @@ struct user_vfp_exc { #define user_regs_native(pregs) true -/* - * Range for task size calculated from the following Linux kernel files: - * arch/arm/include/asm/memory.h - * arch/arm/Kconfig (PAGE_OFFSET values in Memory split section) - */ -#define TASK_SIZE_MIN 0x3f000000 -#define TASK_SIZE_MAX 0xbf000000 -#define SZ_1G 0x40000000 - -static inline unsigned long task_size(void) -{ - unsigned long task_size; - - for (task_size = TASK_SIZE_MIN; task_size < TASK_SIZE_MAX; task_size += SZ_1G) - if (munmap((void *)task_size, page_size())) - break; - - return task_size; -} - #define AT_VECTOR_SIZE 40 typedef uint32_t auxv_t; diff --git a/compel/arch/arm/src/lib/infect.c b/compel/arch/arm/src/lib/infect.c index b45239211..7d9a23024 100644 --- a/compel/arch/arm/src/lib/infect.c +++ b/compel/arch/arm/src/lib/infect.c @@ -2,6 +2,7 @@ #include #include #include +#include "common/page.h" #include "uapi/compel/asm/infect-types.h" #include "log.h" #include "errno.h" @@ -120,3 +121,24 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) */ return true; } + +/* + * Range for task size calculated from the following Linux kernel files: + * arch/arm/include/asm/memory.h + * arch/arm/Kconfig (PAGE_OFFSET values in Memory split section) + */ +#define TASK_SIZE_MIN 0x3f000000 +#define TASK_SIZE_MAX 0xbf000000 +#define SZ_1G 0x40000000 + +unsigned long compel_task_size(void) +{ + unsigned long task_size; + + for (task_size = TASK_SIZE_MIN; task_size < TASK_SIZE_MAX; task_size += SZ_1G) + if (munmap((void *)task_size, page_size())) + break; + + return task_size; +} + diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h b/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h index f243def73..ecf643d68 100644 --- a/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h @@ -93,16 +93,6 @@ typedef uint64_t auxv_t; /* Not used but the structure parasite_dump_thread needs a tls_t field */ typedef uint64_t tls_t; -/* - * Copied for the Linux kernel arch/powerpc/include/asm/processor.h - * - * NOTE: 32bit tasks are not supported. - */ -#define TASK_SIZE_USER64 (0x0000400000000000UL) -#define TASK_SIZE TASK_SIZE_USER64 - -static inline unsigned long task_size(void) { return TASK_SIZE; } - #define ARCH_SI_TRAP TRAP_BRKPT #define __NR(syscall, compat) __NR_##syscall diff --git a/compel/arch/ppc64/src/lib/infect.c b/compel/arch/ppc64/src/lib/infect.c index b208f3dbb..1f1437414 100644 --- a/compel/arch/ppc64/src/lib/infect.c +++ b/compel/arch/ppc64/src/lib/infect.c @@ -316,3 +316,13 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) */ return true; } + +/* + * Copied for the Linux kernel arch/powerpc/include/asm/processor.h + * + * NOTE: 32bit tasks are not supported. + */ +#define TASK_SIZE_USER64 (0x0000400000000000UL) +#define TASK_SIZE TASK_SIZE_USER64 + +unsigned long compel_task_size(void) { return TASK_SIZE; } diff --git a/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h b/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h index bbc6bcf22..cb12ff00f 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h @@ -4,9 +4,6 @@ #include #include #include -#include "log.h" -#include "common/bug.h" -#include "common/page.h" #include #define SIGMAX 64 @@ -123,17 +120,9 @@ typedef struct { typedef struct xsave_struct user_fpregs_struct_t; -#ifdef CONFIG_X86_64 -# define TASK_SIZE ((1UL << 47) - PAGE_SIZE) -#else -/* - * Task size may be limited to 3G but we need a - * higher limit, because it's backward compatible. - */ -# define TASK_SIZE (0xffffe000) -#endif - -static inline unsigned long task_size(void) { return TASK_SIZE; } +#define REG_RES(regs) get_user_reg(®s, ax) +#define REG_IP(regs) get_user_reg(®s, ip) +#define REG_SYSCALL_NR(regs) get_user_reg(®s, orig_ax) typedef uint64_t auxv_t; diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index af46c6526..a9a0556aa 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -349,3 +349,15 @@ int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs) } return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov); } + +#ifdef CONFIG_X86_64 +# define TASK_SIZE ((1UL << 47) - PAGE_SIZE) +#else +/* + * Task size may be limited to 3G but we need a + * higher limit, because it's backward compatible. + */ +# define TASK_SIZE (0xffffe000) +#endif + +unsigned long compel_task_size(void) { return TASK_SIZE; } diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index adc40f2d9..c8a6d9f6e 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -141,4 +141,6 @@ extern int compel_get_thread_regs(struct parasite_thread_ctl *, save_regs_t, voi extern void compel_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *elf_relocs, size_t nr_relocs); +extern unsigned long compel_task_size(void); + #endif diff --git a/criu/kerndat.c b/criu/kerndat.c index 9f7eb0fd7..414e9c414 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -28,6 +28,7 @@ #include "config.h" #include "sk-inet.h" #include +#include struct kerndat_s kdat = { }; @@ -386,7 +387,7 @@ static bool kerndat_has_memfd_create(void) static int get_task_size(void) { - kdat.task_size = task_size(); + kdat.task_size = compel_task_size(); pr_debug("Found task size of %lx\n", kdat.task_size); return 0; } From 5be5424047b88edc68ca649e57c03065f0c09639 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 21 Nov 2016 11:48:27 +0300 Subject: [PATCH 0228/4375] compel: Split cpu.h heander into uapi and priv parts https://travis-ci.org/xemul/criu/builds/177585567 Signed-off-by: Pavel Emelyanov Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/cpu.c | 2 +- compel/arch/aarch64/src/lib/include/cpu.h | 0 compel/arch/arm/src/lib/cpu.c | 2 +- compel/arch/arm/src/lib/include/cpu.h | 0 compel/arch/ppc64/src/lib/cpu.c | 2 +- compel/arch/ppc64/src/lib/include/cpu.h | 0 compel/arch/x86/src/lib/cpu.c | 3 +- compel/arch/x86/src/lib/include/cpu.h | 59 +++++++++++++++++++ .../arch/x86/src/lib/include/uapi/asm/cpu.h | 55 ----------------- compel/include/compel-cpu.h | 11 ++++ compel/include/uapi/cpu.h | 3 - 11 files changed, 74 insertions(+), 63 deletions(-) create mode 100644 compel/arch/aarch64/src/lib/include/cpu.h create mode 100644 compel/arch/arm/src/lib/include/cpu.h create mode 100644 compel/arch/ppc64/src/lib/include/cpu.h create mode 100644 compel/arch/x86/src/lib/include/cpu.h create mode 100644 compel/include/compel-cpu.h diff --git a/compel/arch/aarch64/src/lib/cpu.c b/compel/arch/aarch64/src/lib/cpu.c index 9e5d0d7fe..3fa544639 100644 --- a/compel/arch/aarch64/src/lib/cpu.c +++ b/compel/arch/aarch64/src/lib/cpu.c @@ -1,7 +1,7 @@ #include #include -#include "uapi/compel/cpu.h" +#include "compel-cpu.h" #include "common/bitops.h" diff --git a/compel/arch/aarch64/src/lib/include/cpu.h b/compel/arch/aarch64/src/lib/include/cpu.h new file mode 100644 index 000000000..e69de29bb diff --git a/compel/arch/arm/src/lib/cpu.c b/compel/arch/arm/src/lib/cpu.c index 9e5d0d7fe..3fa544639 100644 --- a/compel/arch/arm/src/lib/cpu.c +++ b/compel/arch/arm/src/lib/cpu.c @@ -1,7 +1,7 @@ #include #include -#include "uapi/compel/cpu.h" +#include "compel-cpu.h" #include "common/bitops.h" diff --git a/compel/arch/arm/src/lib/include/cpu.h b/compel/arch/arm/src/lib/include/cpu.h new file mode 100644 index 000000000..e69de29bb diff --git a/compel/arch/ppc64/src/lib/cpu.c b/compel/arch/ppc64/src/lib/cpu.c index e324b80f9..00a02ea2a 100644 --- a/compel/arch/ppc64/src/lib/cpu.c +++ b/compel/arch/ppc64/src/lib/cpu.c @@ -3,7 +3,7 @@ #include #include -#include "uapi/compel/cpu.h" +#include "compel-cpu.h" #include "common/bitops.h" diff --git a/compel/arch/ppc64/src/lib/include/cpu.h b/compel/arch/ppc64/src/lib/include/cpu.h new file mode 100644 index 000000000..e69de29bb diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c index 7962a61c6..88df9f200 100644 --- a/compel/arch/x86/src/lib/cpu.c +++ b/compel/arch/x86/src/lib/cpu.c @@ -1,8 +1,7 @@ #include #include -#include "uapi/compel/cpu.h" - +#include "compel-cpu.h" #include "common/bitops.h" #include "common/compiler.h" diff --git a/compel/arch/x86/src/lib/include/cpu.h b/compel/arch/x86/src/lib/include/cpu.h new file mode 100644 index 000000000..396fcfdbe --- /dev/null +++ b/compel/arch/x86/src/lib/include/cpu.h @@ -0,0 +1,59 @@ +#ifndef __COMPEL_ASM_CPU_H__ +#define __COMPEL_ASM_CPU_H__ + +static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + /* ecx is often an input as well as an output. */ + asm volatile("cpuid" + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx) + : "memory"); +} + +static inline void cpuid(unsigned int op, + unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + *eax = op; + *ecx = 0; + native_cpuid(eax, ebx, ecx, edx); +} + +static inline void cpuid_count(unsigned int op, int count, + unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + *eax = op; + *ecx = count; + native_cpuid(eax, ebx, ecx, edx); +} + +static inline unsigned int cpuid_eax(unsigned int op) +{ + unsigned int eax, ebx, ecx, edx; + + cpuid(op, &eax, &ebx, &ecx, &edx); + return eax; +} + +static inline unsigned int cpuid_ecx(unsigned int op) +{ + unsigned int eax, ebx, ecx, edx; + + cpuid(op, &eax, &ebx, &ecx, &edx); + return ecx; +} + +static inline unsigned int cpuid_edx(unsigned int op) +{ + unsigned int eax, ebx, ecx, edx; + + cpuid(op, &eax, &ebx, &ecx, &edx); + return edx; +} + +#endif diff --git a/compel/arch/x86/src/lib/include/uapi/asm/cpu.h b/compel/arch/x86/src/lib/include/uapi/asm/cpu.h index f79ace1fc..90d777080 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/cpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/cpu.h @@ -121,61 +121,6 @@ */ #define X86_FEATURE_PREFETCHWT1 (11*32+0) /* The PREFETCHWT1 instruction */ -static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, - unsigned int *ecx, unsigned int *edx) -{ - /* ecx is often an input as well as an output. */ - asm volatile("cpuid" - : "=a" (*eax), - "=b" (*ebx), - "=c" (*ecx), - "=d" (*edx) - : "0" (*eax), "2" (*ecx) - : "memory"); -} - -static inline void cpuid(unsigned int op, - unsigned int *eax, unsigned int *ebx, - unsigned int *ecx, unsigned int *edx) -{ - *eax = op; - *ecx = 0; - native_cpuid(eax, ebx, ecx, edx); -} - -static inline void cpuid_count(unsigned int op, int count, - unsigned int *eax, unsigned int *ebx, - unsigned int *ecx, unsigned int *edx) -{ - *eax = op; - *ecx = count; - native_cpuid(eax, ebx, ecx, edx); -} - -static inline unsigned int cpuid_eax(unsigned int op) -{ - unsigned int eax, ebx, ecx, edx; - - cpuid(op, &eax, &ebx, &ecx, &edx); - return eax; -} - -static inline unsigned int cpuid_ecx(unsigned int op) -{ - unsigned int eax, ebx, ecx, edx; - - cpuid(op, &eax, &ebx, &ecx, &edx); - return ecx; -} - -static inline unsigned int cpuid_edx(unsigned int op) -{ - unsigned int eax, ebx, ecx, edx; - - cpuid(op, &eax, &ebx, &ecx, &edx); - return edx; -} - enum { X86_VENDOR_INTEL = 0, X86_VENDOR_AMD = 1, diff --git a/compel/include/compel-cpu.h b/compel/include/compel-cpu.h new file mode 100644 index 000000000..a06b2de2e --- /dev/null +++ b/compel/include/compel-cpu.h @@ -0,0 +1,11 @@ +#ifndef __COMPEL_CPU_H__ +#define __COMPEL_CPU_H__ + +#include +#include "asm/cpu.h" + +extern void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); +extern void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); +extern int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); + +#endif diff --git a/compel/include/uapi/cpu.h b/compel/include/uapi/cpu.h index 662883bc9..23438da4d 100644 --- a/compel/include/uapi/cpu.h +++ b/compel/include/uapi/cpu.h @@ -5,9 +5,6 @@ #include -extern void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); -extern void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); -extern int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); extern int compel_cpuid(compel_cpuinfo_t *info); extern bool cpu_has_feature(unsigned int feature); From c0836c20521a32fc8cbbb00d5f8b70a933096fec Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 21 Nov 2016 21:26:13 +0300 Subject: [PATCH 0229/4375] compel: Add compel_prepare_noctx The original compel_prepare() also initializes the infect_ctx with values suitable for simple usage. As a starting point the task_size value is set. The compel_prepare_noctx() allocates ctx-less handler that is to be filled by the caller (CRIU). travis-ci: success for compel: Contrinue improving library Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 1 + compel/src/lib/infect.c | 17 ++++++++++++++++- criu/cr-restore.c | 2 +- criu/parasite-syscall.c | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index c8a6d9f6e..f28e5580f 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -40,6 +40,7 @@ struct parasite_ctl; struct parasite_thread_ctl; extern struct parasite_ctl *compel_prepare(int pid); +extern struct parasite_ctl *compel_prepare_noctx(int pid); extern int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size); extern struct parasite_thread_ctl *compel_prepare_thread(struct parasite_ctl *ctl, int pid); extern void compel_release_thread(struct parasite_thread_ctl *); diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 3ba34cdc6..f924e8683 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -894,7 +894,7 @@ void compel_release_thread(struct parasite_thread_ctl *tctl) xfree(tctl); } -struct parasite_ctl *compel_prepare(int pid) +struct parasite_ctl *compel_prepare_noctx(int pid) { struct parasite_ctl *ctl = NULL; @@ -924,6 +924,21 @@ err: return NULL; } +struct parasite_ctl *compel_prepare(int pid) +{ + struct parasite_ctl *ctl; + struct infect_ctx *ictx; + + ctl = compel_prepare_noctx(pid); + if (ctl == NULL) + goto out; + + ictx = &ctl->ictx; + ictx->task_size = compel_task_size(); +out: + return ctl; +} + static bool task_in_parasite(struct parasite_ctl *ctl, user_regs_struct_t *regs) { void *addr = (void *) REG_IP(*regs); diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 2448360c9..bbb499339 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1657,7 +1657,7 @@ static void finalize_restore(void) continue; /* Unmap the restorer blob */ - ctl = compel_prepare(pid); + ctl = compel_prepare_noctx(pid); if (ctl == NULL) continue; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 77fc6238c..dc510ba66 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -573,7 +573,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, return NULL; } - ctl = compel_prepare(pid); + ctl = compel_prepare_noctx(pid); if (!ctl) return NULL; From b0dfd996ed5e2e6dca965edbce983b58f4c5cdfb Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 21 Nov 2016 21:26:14 +0300 Subject: [PATCH 0230/4375] compel: Get syscall injection point in compel The ictx->syscall_ip is the address of any x-able VMA. CRIU knows this as it parses the smaps file (heavily). For others compel just parses /proc/pid/maps file. travis-ci: success for compel: Contrinue improving library Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/lib/infect.c | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index f924e8683..d699e2006 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -924,6 +924,41 @@ err: return NULL; } +/* + * Find first executable VMA that would fit the initial + * syscall injection. + */ +static unsigned long find_executable_area(int pid) +{ + char aux[128]; + FILE *f; + unsigned long ret = (unsigned long)MAP_FAILED; + + sprintf(aux, "/proc/%d/maps", pid); + f = fopen(aux, "r"); + if (!f) + goto out; + + while (fgets(aux, sizeof(aux), f)) { + unsigned long start, end; + char *f; + + start = strtoul(aux, &f, 16); + end = strtoul(f + 1, &f, 16); + + /* f now points at " rwx" (yes, with space) part */ + if (f[3] == 'x') { + BUG_ON(end - start < PARASITE_START_AREA_MIN); + ret = start; + break; + } + } + + fclose(f); +out: + return ret; +} + struct parasite_ctl *compel_prepare(int pid) { struct parasite_ctl *ctl; @@ -935,8 +970,16 @@ struct parasite_ctl *compel_prepare(int pid) ictx = &ctl->ictx; ictx->task_size = compel_task_size(); + ictx->syscall_ip = find_executable_area(pid); + if (ictx->syscall_ip == (unsigned long)MAP_FAILED) + goto err; + out: return ctl; + +err: + free(ctl); + goto out; } static bool task_in_parasite(struct parasite_ctl *ctl, user_regs_struct_t *regs) From e50235b6560062fe0cb4428aa88f7933ab851066 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 21 Nov 2016 21:26:15 +0300 Subject: [PATCH 0231/4375] compel: Routine to open proc files Yet again -- CRIU has an optimized openat()-based engine that is slightly faster for opening "/proc" files rather than plain open(). The latter is provided by default by compel. travis-ci: success for compel: Contrinue improving library Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/lib/infect.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index d699e2006..979173cdf 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -959,6 +959,21 @@ out: return ret; } +static int simple_open_proc(int pid, int mode, const char *fmt, ...) +{ + int l; + char path[128]; + va_list args; + + l = sprintf(path, "/proc/%d/", pid); + + va_start(args, fmt); + vsnprintf(path + l, sizeof(path) - l, fmt, args); + va_end(args); + + return open(path, mode); +} + struct parasite_ctl *compel_prepare(int pid) { struct parasite_ctl *ctl; @@ -970,6 +985,7 @@ struct parasite_ctl *compel_prepare(int pid) ictx = &ctl->ictx; ictx->task_size = compel_task_size(); + ictx->open_proc = simple_open_proc; ictx->syscall_ip = find_executable_area(pid); if (ictx->syscall_ip == (unsigned long)MAP_FAILED) goto err; From 74d1725ca0463e1637ccd73a8154dd4e88504acf Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 21 Nov 2016 21:26:16 +0300 Subject: [PATCH 0232/4375] compel: Create socket for pid Compel needs a socket that lives in victim's net namespace. CRIU creates this socket once for all the processes it works with. For pure compel case the socket is created for each new ctl. travis-ci: success for compel: Contrinue improving library Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/lib/infect.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 979173cdf..2be67f12a 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -959,6 +959,39 @@ out: return ret; } +/* + * This routine is to create PF_UNIX/SOCK_SEQPACKET socket + * in the target net namespace + */ +static int make_sock_for(int pid) +{ + int ret = -1; + int mfd, fd; + char p[32]; + + sprintf(p, "/proc/%d/ns/net", pid); + fd = open(p, O_RDONLY); + if (fd < 0) + goto out; + + mfd = open("/proc/self/ns/net", O_RDONLY); + if (mfd < 0) + goto out_c; + + if (setns(fd, CLONE_NEWNET)) + goto out_cm; + + ret = socket(PF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK, 0); + + setns(mfd, CLONE_NEWNET); +out_cm: + close(mfd); +out_c: + close(fd); +out: + return ret; +} + static int simple_open_proc(int pid, int mode, const char *fmt, ...) { int l; @@ -989,6 +1022,9 @@ struct parasite_ctl *compel_prepare(int pid) ictx->syscall_ip = find_executable_area(pid); if (ictx->syscall_ip == (unsigned long)MAP_FAILED) goto err; + ictx->sock = make_sock_for(pid); + if (ictx->sock < 0) + goto err; out: return ctl; From 3e7627c6ac306b12e82c1e47b4cfe79c1cfe5460 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 21 Nov 2016 21:26:17 +0300 Subject: [PATCH 0233/4375] compel: Handle sigchilds in compel CRIU sets up a child hander to get errors from tasks it infects. For compel we'd have the same problem, so there's a way to request for custom child handler, but compel should provide some default by himself. And it's not clear atm how this should look like, so here's a plain stub to move forward. travis-ci: success for compel: Contrinue improving library Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 1 + compel/src/lib/infect.c | 24 ++++++++++++++---------- criu/parasite-syscall.c | 4 ++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index f28e5580f..a253e0d73 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -111,6 +111,7 @@ struct infect_ctx { unsigned long flags; /* fine-tune (e.g. faults) */ void (*child_handler)(int, siginfo_t *, void *); /* hander for SIGCHLD deaths */ + struct sigaction orig_handler; open_proc_fn open_proc; diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 2be67f12a..942cef877 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -384,16 +384,9 @@ static int setup_child_handler(struct parasite_ctl *ctl) return 0; } -static int restore_child_handler() +static int restore_child_handler(struct parasite_ctl *ctl) { - struct sigaction sa = { - .sa_handler = SIG_DFL, /* XXX -- should be original? */ - .sa_flags = SA_SIGINFO | SA_RESTART, - }; - - sigemptyset(&sa.sa_mask); - sigaddset(&sa.sa_mask, SIGCHLD); - if (sigaction(SIGCHLD, &sa, NULL)) { + if (sigaction(SIGCHLD, &ctl->ictx.orig_handler, NULL)) { pr_perror("Unable to setup SIGCHLD handler"); return -1; } @@ -1007,6 +1000,14 @@ static int simple_open_proc(int pid, int mode, const char *fmt, ...) return open(path, mode); } +static void handle_sigchld(int signal, siginfo_t *siginfo, void *data) +{ + int status; + + waitpid(-1, &status, WNOHANG); + /* FIXME -- what to do here? */ +} + struct parasite_ctl *compel_prepare(int pid) { struct parasite_ctl *ctl; @@ -1020,6 +1021,9 @@ struct parasite_ctl *compel_prepare(int pid) ictx->task_size = compel_task_size(); ictx->open_proc = simple_open_proc; ictx->syscall_ip = find_executable_area(pid); + ictx->child_handler = handle_sigchld; + sigaction(SIGCHLD, NULL, &ictx->orig_handler); + if (ictx->syscall_ip == (unsigned long)MAP_FAILED) goto err; ictx->sock = make_sock_for(pid); @@ -1049,7 +1053,7 @@ static int parasite_fini_seized(struct parasite_ctl *ctl) enum trace_flags flag; /* stop getting chld from parasite -- we're about to step-by-step it */ - if (restore_child_handler()) + if (restore_child_handler(ctl)) return -1; /* Start to trace syscalls for each thread */ diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index dc510ba66..8002546f9 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -581,6 +581,10 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ictx->open_proc = do_open_proc; ictx->child_handler = sigchld_handler; + ictx->orig_handler.sa_handler = SIG_DFL; + ictx->orig_handler.sa_flags = SA_SIGINFO | SA_RESTART; + sigemptyset(&ictx->orig_handler.sa_mask); + sigaddset(&ictx->orig_handler.sa_mask, SIGCHLD); ictx->sock = dmpi(item)->netns->net.seqsk; ictx->save_regs = save_task_regs; ictx->make_sigframe = make_sigframe; From c7a717c1d135cd9f3a2aa4ade0ff7cd149c1aaaa Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 21 Nov 2016 21:26:18 +0300 Subject: [PATCH 0234/4375] compel: Save and restore regs inside compel by default CRIU keeps all registers on CoreEntry and makes sigframe from them as well, which means anyone using the compel library have to provide own handlers, which is inconvenient. So now it's possible to leave this task for libcompel itself: it will save the regs and prerare sigframe on its own. travis-ci: success for compel: Contrinue improving library Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 1 + compel/arch/aarch64/src/lib/infect.c | 29 +++++++ compel/arch/arm/src/lib/infect.c | 38 ++++++++ compel/arch/ppc64/src/lib/infect.c | 125 +++++++++++++++++++++++++++ compel/arch/x86/src/lib/infect.c | 81 +++++++++++++++++ compel/include/infect-priv.h | 6 +- compel/src/lib/infect.c | 59 +++++++++++++ criu/arch/ppc64/crtools.c | 2 +- 8 files changed, 339 insertions(+), 2 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index 27ef59c52..ad0315566 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -7,6 +7,7 @@ COMPEL_SO_VERSION_CODE := $(shell expr $(COMPEL_SO_VERSION_MAJOR) \* 65536 \+ $( ccflags-y += -iquote compel/arch/$(ARCH)/src/lib/include ccflags-y += -iquote compel/include ccflags-y += -iquote compel/plugins/include +ccflags-y += -fno-strict-aliasing ccflags-y += -fPIC # diff --git a/compel/arch/aarch64/src/lib/infect.c b/compel/arch/aarch64/src/lib/infect.c index 0fc639a1e..ee1ec7c20 100644 --- a/compel/arch/aarch64/src/lib/infect.c +++ b/compel/arch/aarch64/src/lib/infect.c @@ -27,6 +27,35 @@ static inline void __always_unused __check_code_syscall(void) BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); } +int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, + user_regs_struct_t *regs, + user_fpregs_struct_t *fpregs) +{ + struct fpsimd_context *fpsimd = RT_SIGFRAME_FPU(sigframe); + + memcpy(sigframe->uc.uc_mcontext.regs, regs->regs, sizeof(regs->regs)); + + sigframe->uc.uc_mcontext.sp = regs->sp; + sigframe->uc.uc_mcontext.pc = regs->pc; + sigframe->uc.uc_mcontext.pstate = regs->pstate; + + memcpy(fpsimd->vregs, fpregs->vregs, 32 * sizeof(__uint128_t)); + + fpsimd->fpsr = fpregs->fpsr; + fpsimd->fpcr = fpregs->fpcr; + + fpsimd->head.magic = FPSIMD_MAGIC; + fpsimd->head.size = sizeof(*fpsimd); + + return 0; +} + +int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, + struct rt_sigframe *rsigframe) +{ + return 0; +} + int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) { struct iovec iov; diff --git a/compel/arch/arm/src/lib/infect.c b/compel/arch/arm/src/lib/infect.c index 7d9a23024..61377691a 100644 --- a/compel/arch/arm/src/lib/infect.c +++ b/compel/arch/arm/src/lib/infect.c @@ -26,6 +26,44 @@ static inline __always_unused void __check_code_syscall(void) BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); } +int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, + user_regs_struct_t *regs, + user_fpregs_struct_t *fpregs) +{ + struct aux_sigframe *aux = (struct aux_sigframe *)(void *)&sigframe->sig.uc.uc_regspace; + + sigframe->sig.uc.uc_mcontext.arm_r0 = regs->ARM_r0; + sigframe->sig.uc.uc_mcontext.arm_r1 = regs->ARM_r1; + sigframe->sig.uc.uc_mcontext.arm_r2 = regs->ARM_r2; + sigframe->sig.uc.uc_mcontext.arm_r3 = regs->ARM_r3; + sigframe->sig.uc.uc_mcontext.arm_r4 = regs->ARM_r4; + sigframe->sig.uc.uc_mcontext.arm_r5 = regs->ARM_r5; + sigframe->sig.uc.uc_mcontext.arm_r6 = regs->ARM_r6; + sigframe->sig.uc.uc_mcontext.arm_r7 = regs->ARM_r7; + sigframe->sig.uc.uc_mcontext.arm_r8 = regs->ARM_r8; + sigframe->sig.uc.uc_mcontext.arm_r9 = regs->ARM_r9; + sigframe->sig.uc.uc_mcontext.arm_r10 = regs->ARM_r10; + sigframe->sig.uc.uc_mcontext.arm_fp = regs->ARM_fp; + sigframe->sig.uc.uc_mcontext.arm_ip = regs->ARM_ip; + sigframe->sig.uc.uc_mcontext.arm_sp = regs->ARM_sp; + sigframe->sig.uc.uc_mcontext.arm_lr = regs->ARM_lr; + sigframe->sig.uc.uc_mcontext.arm_pc = regs->ARM_pc; + sigframe->sig.uc.uc_mcontext.arm_cpsr = regs->ARM_cpsr; + + memcpy(&aux->vfp.ufp.fpregs, &fpregs->fpregs, sizeof(aux->vfp.ufp.fpregs)); + aux->vfp.ufp.fpscr = fpregs->fpscr; + aux->vfp.magic = VFP_MAGIC; + aux->vfp.size = VFP_STORAGE_SIZE; + + return 0; +} + +int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, + struct rt_sigframe *rsigframe) +{ + return 0; +} + #define PTRACE_GETVFPREGS 27 int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) { diff --git a/compel/arch/ppc64/src/lib/infect.c b/compel/arch/ppc64/src/lib/infect.c index 1f1437414..637c3654e 100644 --- a/compel/arch/ppc64/src/lib/infect.c +++ b/compel/arch/ppc64/src/lib/infect.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,130 @@ static inline void __check_code_syscall(void) BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); } +static void prep_gp_regs(mcontext_t *dst, user_regs_struct_t *regs) +{ + memcpy(dst->gp_regs, regs->gpr, sizeof(regs->gpr)); + + dst->gp_regs[PT_NIP] = regs->nip; + dst->gp_regs[PT_MSR] = regs->msr; + dst->gp_regs[PT_ORIG_R3] = regs->orig_gpr3; + dst->gp_regs[PT_CTR] = regs->ctr; + dst->gp_regs[PT_LNK] = regs->link; + dst->gp_regs[PT_XER] = regs->xer; + dst->gp_regs[PT_CCR] = regs->ccr; + dst->gp_regs[PT_TRAP] = regs->trap; +} + +static void put_fpu_regs(mcontext_t *mc, uint64_t *fpregs) +{ + uint64_t *mcfp = (uint64_t *)mc->fp_regs; + + memcpy(mcfp, fpregs, sizeof(*fpregs) * NFPREG); +} + +static void put_altivec_regs(mcontext_t *mc, __vector128 *vrregs) +{ + vrregset_t *v_regs = (vrregset_t *)(((unsigned long)mc->vmx_reserve + 15) & ~0xful); + + memcpy(&v_regs->vrregs[0][0], vrregs, sizeof(uint64_t) * 2 * (NVRREG - 1)); + v_regs->vrsave = *((uint32_t *)&vrregs[NVRREG - 1]); + mc->v_regs = v_regs; +} + +static void put_vsx_regs(mcontext_t *mc, uint64_t *vsxregs) +{ + memcpy((uint64_t *)(mc->v_regs + 1), vsxregs, sizeof(*vsxregs) * NVSXREG); +} + +int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, + user_regs_struct_t *regs, + user_fpregs_struct_t *fpregs) +{ + mcontext_t *dst_tc = &sigframe->uc_transact.uc_mcontext; + mcontext_t *dst = &sigframe->uc.uc_mcontext; + + if (fpregs->flags & USER_FPREGS_FL_TM) { + prep_gp_regs(&sigframe->uc_transact.uc_mcontext, &fpregs->tm.regs); + prep_gp_regs(&sigframe->uc.uc_mcontext, &fpregs->tm.regs); + } else { + prep_gp_regs(&sigframe->uc.uc_mcontext, regs); + } + + if (fpregs->flags & USER_FPREGS_FL_TM) + sigframe->uc.uc_link = &sigframe->uc_transact; + + if (fpregs->flags & USER_FPREGS_FL_FP) { + if (fpregs->flags & USER_FPREGS_FL_TM) { + put_fpu_regs(&sigframe->uc_transact.uc_mcontext, fpregs->tm.fpregs); + put_fpu_regs(&sigframe->uc.uc_mcontext, fpregs->tm.fpregs); + } else { + put_fpu_regs(&sigframe->uc.uc_mcontext, fpregs->fpregs); + } + } + + if (fpregs->flags & USER_FPREGS_FL_ALTIVEC) { + if (fpregs->flags & USER_FPREGS_FL_TM) { + put_altivec_regs(&sigframe->uc_transact.uc_mcontext, fpregs->tm.vrregs); + put_altivec_regs(&sigframe->uc.uc_mcontext, fpregs->tm.vrregs); + + dst_tc->gp_regs[PT_MSR] |= MSR_VEC; + } else { + put_altivec_regs(&sigframe->uc.uc_mcontext, fpregs->vrregs); + } + + dst->gp_regs[PT_MSR] |= MSR_VEC; + + if (fpregs->flags & USER_FPREGS_FL_VSX) { + if (fpregs->flags & USER_FPREGS_FL_TM) { + put_vsx_regs(&sigframe->uc_transact.uc_mcontext, fpregs->tm.vsxregs); + put_vsx_regs(&sigframe->uc.uc_mcontext, fpregs->tm.vsxregs); + + dst_tc->gp_regs[PT_MSR] |= MSR_VSX; + } else { + put_vsx_regs(&sigframe->uc.uc_mcontext, fpregs->vsxregs); + } + dst->gp_regs[PT_MSR] |= MSR_VSX; + } + } + + return 0; +} + +static void update_vregs(mcontext_t *lcontext, mcontext_t *rcontext) +{ + if (lcontext->v_regs) { + uint64_t offset = (uint64_t)(lcontext->v_regs) - (uint64_t)lcontext; + lcontext->v_regs = (vrregset_t *)((uint64_t)rcontext + offset); + + pr_debug("Updated v_regs:%llx (rcontext:%llx)\n", + (unsigned long long)lcontext->v_regs, + (unsigned long long)rcontext); + } +} + +int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *frame, + struct rt_sigframe *rframe) +{ + uint64_t msr = frame->uc.uc_mcontext.gp_regs[PT_MSR]; + + update_vregs(&frame->uc.uc_mcontext, &rframe->uc.uc_mcontext); + + /* Sanity check: If TM so uc_link should be set, otherwise not */ + if (MSR_TM_ACTIVE(msr) ^ (!!(frame->uc.uc_link))) { + BUG(); + return -1; + } + + /* Updating the transactional state address if any */ + if (frame->uc.uc_link) { + update_vregs(&frame->uc_transact.uc_mcontext, + &rframe->uc_transact.uc_mcontext); + frame->uc.uc_link = &rframe->uc_transact; + } + + return 0; +} + /* This is the layout of the POWER7 VSX registers and the way they * overlap with the existing FPR and VMX registers. * diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index a9a0556aa..be0439917 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -47,6 +47,87 @@ static inline __always_unused void __check_code_syscall(void) BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); } +int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, + user_regs_struct_t *regs, + user_fpregs_struct_t *fpregs) +{ + bool is_native = user_regs_native(regs); + fpu_state_t *fpu_state = is_native ? + &sigframe->native.fpu_state : + &sigframe->compat.fpu_state; + if (is_native) { +#define cpreg64_native(d, s) sigframe->native.uc.uc_mcontext.d = regs->native.s + cpreg64_native(rdi, di); + cpreg64_native(rsi, si); + cpreg64_native(rbp, bp); + cpreg64_native(rsp, sp); + cpreg64_native(rbx, bx); + cpreg64_native(rdx, dx); + cpreg64_native(rcx, cx); + cpreg64_native(rip, ip); + cpreg64_native(rax, ax); + cpreg64_native(r8, r8); + cpreg64_native(r9, r9); + cpreg64_native(r10, r10); + cpreg64_native(r11, r11); + cpreg64_native(r12, r12); + cpreg64_native(r13, r13); + cpreg64_native(r14, r14); + cpreg64_native(r15, r15); + cpreg64_native(cs, cs); + cpreg64_native(eflags, flags); + + sigframe->is_native = true; +#undef cpreg64_native + } else { +#define cpreg32_compat(d) sigframe->compat.uc.uc_mcontext.d = regs->compat.d + cpreg32_compat(gs); + cpreg32_compat(fs); + cpreg32_compat(es); + cpreg32_compat(ds); + cpreg32_compat(di); + cpreg32_compat(si); + cpreg32_compat(bp); + cpreg32_compat(sp); + cpreg32_compat(bx); + cpreg32_compat(dx); + cpreg32_compat(cx); + cpreg32_compat(ip); + cpreg32_compat(ax); + cpreg32_compat(cs); + cpreg32_compat(ss); + cpreg32_compat(flags); +#undef cpreg32_compat + sigframe->is_native = false; + } + + fpu_state->has_fpu = true; + memcpy(&fpu_state->xsave, fpregs, sizeof(*fpregs)); + + return 0; +} + +int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, + struct rt_sigframe *rsigframe) +{ + fpu_state_t *fpu_state = (sigframe->is_native) ? + &rsigframe->native.fpu_state : + &rsigframe->compat.fpu_state; + unsigned long addr = (unsigned long)(void *)&fpu_state->xsave; + + if (sigframe->is_native && (addr % 64ul) == 0ul) { + sigframe->native.uc.uc_mcontext.fpstate = &fpu_state->xsave; + } else if (!sigframe->is_native && (addr % 32ul) == 0ul) { + sigframe->compat.uc.uc_mcontext.fpstate = (uint32_t)addr; + } else { + pr_err("Unaligned address passed: %lx (native %d)\n", + addr, sigframe->is_native); + return -1; + } + + return 0; +} + #define get_signed_user_reg(pregs, name) \ ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \ (int32_t)((pregs)->compat.name)) diff --git a/compel/include/infect-priv.h b/compel/include/infect-priv.h index 4eda1acdd..fde5548b7 100644 --- a/compel/include/infect-priv.h +++ b/compel/include/infect-priv.h @@ -67,5 +67,9 @@ extern void *remote_mmap(struct parasite_ctl *ctl, int flags, int fd, off_t offset); extern bool arch_can_dump_task(struct parasite_ctl *ctl); extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg); - +extern int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, + user_regs_struct_t *regs, + user_fpregs_struct_t *fpregs); +extern int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, + struct rt_sigframe *rsigframe); #endif diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 942cef877..4f5de2fb1 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -1008,6 +1008,58 @@ static void handle_sigchld(int signal, siginfo_t *siginfo, void *data) /* FIXME -- what to do here? */ } +struct plain_regs_struct { + user_regs_struct_t regs; + user_fpregs_struct_t fpregs; +}; + +static int save_regs_plain(void *to, user_regs_struct_t *r, user_fpregs_struct_t *f) +{ + struct plain_regs_struct *prs = to; + + prs->regs = *r; + prs->fpregs = *f; + + return 0; +} + +#ifndef RT_SIGFRAME_UC_SIGMASK +#define RT_SIGFRAME_UC_SIGMASK(sigframe) \ + (k_rtsigset_t*)&RT_SIGFRAME_UC(sigframe)->uc_sigmask +#endif + +static int make_sigframe_plain(void *from, struct rt_sigframe *f, struct rt_sigframe *rtf, k_rtsigset_t *b) +{ + struct plain_regs_struct *prs = from; + k_rtsigset_t *blk_sigset; + + /* + * Make sure it's zeroified. + */ + memset(f, 0, sizeof(*f)); + + if (sigreturn_prep_regs_plain(f, &prs->regs, &prs->fpregs)) + return -1; + + blk_sigset = RT_SIGFRAME_UC_SIGMASK(f); + if (b) + memcpy(blk_sigset, b, sizeof(k_rtsigset_t)); + else + memset(blk_sigset, 0, sizeof(k_rtsigset_t)); + + if (RT_SIGFRAME_HAS_FPU(f)) { + if (sigreturn_prep_fpu_frame_plain(f, rtf)) + return -1; + } + + /* + * FIXME What about sas? + * setup_sas(sigframe, core->thread_core->sas); + */ + + return 0; +} + struct parasite_ctl *compel_prepare(int pid) { struct parasite_ctl *ctl; @@ -1024,6 +1076,12 @@ struct parasite_ctl *compel_prepare(int pid) ictx->child_handler = handle_sigchld; sigaction(SIGCHLD, NULL, &ictx->orig_handler); + ictx->save_regs = save_regs_plain; + ictx->make_sigframe = make_sigframe_plain; + ictx->regs_arg = xmalloc(sizeof(struct plain_regs_struct)); + if (ictx->regs_arg == NULL) + goto err; + if (ictx->syscall_ip == (unsigned long)MAP_FAILED) goto err; ictx->sock = make_sock_for(pid); @@ -1034,6 +1092,7 @@ out: return ctl; err: + free(ictx->regs_arg); free(ctl); goto out; } diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index 074490956..c4f0df790 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -49,8 +49,8 @@ static UserPpc64FpstateEntry *copy_fp_regs(uint64_t *fpregs) static void put_fpu_regs(mcontext_t *mc, UserPpc64FpstateEntry *fpe) { - int i; uint64_t *mcfp = (uint64_t *)mc->fp_regs; + size_t i; for (i = 0; i < fpe->n_fpregs; i++) mcfp[i] = fpe->fpregs[i]; From f09ec0c24b6ccda6161ec5abe5c4ac10b8d8c259 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 21 Nov 2016 21:26:19 +0300 Subject: [PATCH 0235/4375] compel: Handier API for stopping tasks for infection Now we have two routines one of which needs a callback for proc parsing. This is complex, but needed by CRIU. For others let's have a single "stop" call that would to everything. travis-ci: success for compel: Contrinue improving library Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 2 +- compel/src/lib/infect.c | 59 ++++++++++++++++++++++++++++++++++++ criu/cr-exec.c | 2 +- criu/seize.c | 8 ++--- 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index a253e0d73..ffcc1c8c9 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -12,7 +12,7 @@ #define PARASITE_START_AREA_MIN (4096) -extern int compel_stop_task(int pid); +extern int compel_interrupt_task(int pid); struct seize_task_status { char state; diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 4f5de2fb1..b4db68069 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -62,7 +62,66 @@ static inline void close_safe(int *pfd) } } +static int parse_pid_status(int pid, struct seize_task_status *ss) +{ + char aux[128]; + FILE *f; + + sprintf(aux, "/proc/%d/status", pid); + f = fopen(aux, "r"); + if (!f) + return -1; + + ss->ppid = -1; /* Not needed at this point */ + ss->seccomp_mode = SECCOMP_MODE_DISABLED; + + while (fgets(aux, sizeof(aux), f)) { + if (!strncmp(aux, "State:", 6)) { + ss->state = aux[7]; + continue; + } + + if (!strncmp(aux, "Seccomp:", 8)) { + if (sscanf(aux + 9, "%d", &ss->seccomp_mode) != 1) + goto err_parse; + + continue; + } + + if (!strncmp(aux, "ShdPnd:", 7)) { + if (sscanf(aux + 7, "%llx", &ss->shdpnd) != 1) + goto err_parse; + + continue; + } + if (!strncmp(aux, "SigPnd:", 7)) { + if (sscanf(aux + 7, "%llx", &ss->sigpnd) != 1) + goto err_parse; + + continue; + } + } + + fclose(f); + return 0; + +err_parse: + fclose(f); + return -1; +} + int compel_stop_task(int pid) +{ + int ret; + struct seize_task_status ss; + + ret = compel_interrupt_task(pid); + if (ret == 0) + ret = compel_wait_task(pid, -1, parse_pid_status, &ss); + return ret; +} + +int compel_interrupt_task(int pid) { int ret; diff --git a/criu/cr-exec.c b/criu/cr-exec.c index b39c77238..538ebec86 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -137,7 +137,7 @@ int cr_exec(int pid, char **opt) goto out; } - if (compel_stop_task(pid)) + if (compel_interrupt_task(pid)) goto out; /* diff --git a/criu/seize.c b/criu/seize.c index 263f5a928..1fb7fd17d 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -130,7 +130,7 @@ static int seize_cgroup_tree(char *root_path, const char *state) return -1; } - if (!compel_stop_task(pid)) { + if (!compel_interrupt_task(pid)) { pr_debug("SEIZE %d: success\n", pid); processes_to_wait++; } else if (state == frozen) { @@ -482,7 +482,7 @@ static int collect_children(struct pstree_item *item) if (!opts.freeze_cgroup) /* fails when meets a zombie */ - compel_stop_task(pid); + compel_interrupt_task(pid); creds = xzalloc(sizeof(*creds)); if (!creds) { @@ -713,7 +713,7 @@ static int collect_threads(struct pstree_item *item) pr_info("\tSeizing %d's %d thread\n", item->pid->real, pid); - if (!opts.freeze_cgroup && compel_stop_task(pid)) + if (!opts.freeze_cgroup && compel_interrupt_task(pid)) continue; ret = compel_wait_task(pid, item_ppid(item), parse_pid_status, &t_creds.s); @@ -846,7 +846,7 @@ int collect_pstree(void) if (opts.freeze_cgroup && freeze_processes()) goto err; - if (!opts.freeze_cgroup && compel_stop_task(pid)) { + if (!opts.freeze_cgroup && compel_interrupt_task(pid)) { set_cr_errno(ESRCH); goto err; } From 0723c8a6f110c9d35a77d5b2b09916abc91fd392 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 22 Nov 2016 14:42:17 +0300 Subject: [PATCH 0236/4375] compel/uapi: remove compat_sigset_t type Remove compatible sigset structure: as it has the same size for both 32-bit and 64-bit, I didn't use it across the code, only for a size check. The check is removed as we use now only k_rtsigset_t. Wordsize for sigset is changed to 64-bit - as it's written in comment for possible 32-bit native building. If we ever going to support compat mode for other archs, we will need to re-introduce compat_sigset_t type if it has for those archs different sizes for compat/native builds. But for a while, let's simplify this. travis-ci: success for Compel/compat cleanups Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .../x86/plugins/include/asm/syscall-types.h | 12 ++++++------ .../x86/src/lib/include/uapi/asm/sigframe.h | 18 ++---------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/compel/arch/x86/plugins/include/asm/syscall-types.h b/compel/arch/x86/plugins/include/asm/syscall-types.h index b22b6d795..9874fd0be 100644 --- a/compel/arch/x86/plugins/include/asm/syscall-types.h +++ b/compel/arch/x86/plugins/include/asm/syscall-types.h @@ -11,17 +11,17 @@ typedef rt_restorefn_t *rt_sigrestore_t; #define SA_RESTORER 0x04000000 #define _KNSIG 64 - -#ifndef CONFIG_COMPAT #define _NSIG_BPW 64 -#else -#define _NSIG_BPW 32 -#endif #define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) +/* + * Note: as k_rtsigset_t is the same size for 32-bit and 64-bit, + * sig defined as uint64_t rather than (unsigned long) - for the + * purpose if we ever going to support native 32-bit compilation. + */ typedef struct { - unsigned long sig[_KNSIG_WORDS]; + uint64_t sig[_KNSIG_WORDS]; } k_rtsigset_t; typedef struct { diff --git a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h index 3caed449c..75eb76eda 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h @@ -73,17 +73,8 @@ struct rt_sigcontext_32 { * when (if) other architectures will support compatible C/R */ -typedef u32 compat_uptr_t; -typedef u32 compat_size_t; -typedef u32 compat_sigset_word; - -#define _COMPAT_NSIG 64 -#define _COMPAT_NSIG_BPW 32 -#define _COMPAT_NSIG_WORDS (_COMPAT_NSIG / _COMPAT_NSIG_BPW) - -typedef struct { - compat_sigset_word sig[_COMPAT_NSIG_WORDS]; -} compat_sigset_t; +typedef uint32_t compat_uptr_t; +typedef uint32_t compat_size_t; typedef struct compat_siginfo { int si_signo; @@ -92,11 +83,6 @@ typedef struct compat_siginfo { int _pad[128/sizeof(int) - 3]; } compat_siginfo_t; -static inline void __always_unused __check_compat_sigset_t(void) -{ - BUILD_BUG_ON(sizeof(compat_sigset_t) != sizeof(k_rtsigset_t)); -} - #ifdef CONFIG_X86_32 #define rt_sigframe_ia32 rt_sigframe #endif From 8ec112b721643fdc68c5ab43d19be8ad314c62ff Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 22 Nov 2016 14:42:18 +0300 Subject: [PATCH 0237/4375] make: drop syscalls_lib from criu - it's in compel now Libcompel is now responsible for system calls - criu already depends on building of compel, this code is commented-out... Drop it! travis-ci: success for Compel/compat cleanups Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/Makefile | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/criu/Makefile b/criu/Makefile index f88f13a5a..c88fe0918 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -34,22 +34,10 @@ include $(__nmk_dir)msg.mk # Needed libraries checks include $(SRC_DIR)/criu/Makefile.packages -## -## System calls library. -#ifeq ($(ARCH),x86) -## Do not need 32-bit compatible syscall lib compiled in criu -#SYSCALL-LIB := $(ARCH_DIR)/syscalls-64.built-in.o -#else -#SYSCALL-LIB := $(ARCH_DIR)/syscalls.built-in.o -#endif -#syscalls_lib: -# $(Q) $(MAKE) $(call build-as,Makefile.syscalls,$(ARCH_DIR)) all -.PHONY: syscalls_lib - # # Architecture dependent part. ARCH-LIB := $(ARCH_DIR)/crtools.built-in.o -$(ARCH-LIB): syscalls_lib +$(ARCH-LIB): $(Q) $(MAKE) $(build)=$(ARCH_DIR) all # From 2e39767a41734d16bbbbae98806923d8167a4f9c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 22 Nov 2016 14:42:00 +0300 Subject: [PATCH 0238/4375] uapi/compel/criu: move auxv_t, tls_t back to CRIU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need them in libcompel for PIE - only needed for C/R. Fixes (with compat enabled back): CC criu/arch/x86/sigaction_compat.o In file included from criu/arch/x86/sigaction_compat.c:1:0: /home/japdoll/tools/criu/criu/arch/x86/include/asm/restorer.h:15:25: error: unknown type name ‘tls_t’ extern void restore_tls(tls_t *ptls); ^~~~~ travis-ci: success for Compel/compat cleanups Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .../src/lib/include/uapi/asm/infect-types.h | 5 ---- .../src/lib/include/uapi/asm/infect-types.h | 5 ---- .../src/lib/include/uapi/asm/infect-types.h | 15 ------------ .../src/lib/include/uapi/asm/infect-types.h | 23 +++++-------------- criu/arch/aarch64/include/asm/types.h | 4 ++++ criu/arch/arm/include/asm/types.h | 4 ++++ criu/arch/ppc64/include/asm/types.h | 15 ++++++++++++ criu/arch/x86/include/asm/types.h | 16 +++++++++++++ 8 files changed, 45 insertions(+), 42 deletions(-) diff --git a/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h b/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h index eabf1f22f..eeb68be69 100644 --- a/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h @@ -24,11 +24,6 @@ typedef struct user_fpsimd_state user_fpregs_struct_t; #define user_regs_native(pregs) true -#define AT_VECTOR_SIZE 40 - -typedef uint64_t auxv_t; -typedef uint64_t tls_t; - #define ARCH_SI_TRAP TRAP_BRKPT #define __NR(syscall, compat) __NR_##syscall diff --git a/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h b/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h index b532c7dd9..03442ee2b 100644 --- a/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h @@ -58,11 +58,6 @@ struct user_vfp_exc { #define user_regs_native(pregs) true -#define AT_VECTOR_SIZE 40 - -typedef uint32_t auxv_t; -typedef uint32_t tls_t; - #define ARCH_SI_TRAP TRAP_BRKPT #define __NR(syscall, compat) __NR_##syscall diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h b/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h index ecf643d68..4b8a20055 100644 --- a/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h @@ -78,21 +78,6 @@ typedef struct { #define user_regs_native(pregs) true -/* - * Copied from the following kernel header files : - * include/linux/auxvec.h - * arch/powerpc/include/uapi/asm/auxvec.h - * include/linux/mm_types.h - */ -#define AT_VECTOR_SIZE_BASE 20 -#define AT_VECTOR_SIZE_ARCH 6 -#define AT_VECTOR_SIZE (2*(AT_VECTOR_SIZE_ARCH + AT_VECTOR_SIZE_BASE + 1)) - -typedef uint64_t auxv_t; - -/* Not used but the structure parasite_dump_thread needs a tls_t field */ -typedef uint64_t tls_t; - #define ARCH_SI_TRAP TRAP_BRKPT #define __NR(syscall, compat) __NR_##syscall diff --git a/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h b/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h index cb12ff00f..55fcd8106 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h @@ -124,25 +124,14 @@ typedef struct xsave_struct user_fpregs_struct_t; #define REG_IP(regs) get_user_reg(®s, ip) #define REG_SYSCALL_NR(regs) get_user_reg(®s, orig_ax) -typedef uint64_t auxv_t; +#define __NR(syscall, compat) ((compat) ? __NR32_##syscall : __NR_##syscall) /* - * Linux preserves three TLS segments in GDT. - * Offsets in GDT differ between 32-bit and 64-bit machines. - * For 64-bit x86 those GDT offsets are the same - * for native and compat tasks. + * For x86_32 __NR_mmap inside the kernel represents old_mmap system + * call, but since we didn't use it yet lets go further and simply + * define own alias for __NR_mmap2 which would allow us to unify code + * between 32 and 64 bits version. */ -#define GDT_ENTRY_TLS_MIN 12 -#define GDT_ENTRY_TLS_MAX 14 -#define GDT_ENTRY_TLS_NUM 3 -typedef struct { - user_desc_t desc[GDT_ENTRY_TLS_NUM]; -} tls_t; - -#define REG_RES(regs) get_user_reg(®s, ax) -#define REG_IP(regs) get_user_reg(®s, ip) -#define REG_SYSCALL_NR(regs) get_user_reg(®s, orig_ax) - -#define AT_VECTOR_SIZE 44 +#define __NR32_mmap __NR32_mmap2 #endif /* UAPI_COMPEL_ASM_TYPES_H__ */ diff --git a/criu/arch/aarch64/include/asm/types.h b/criu/arch/aarch64/include/asm/types.h index a84aea18e..e79f86698 100644 --- a/criu/arch/aarch64/include/asm/types.h +++ b/criu/arch/aarch64/include/asm/types.h @@ -25,4 +25,8 @@ typedef UserAarch64RegsEntry UserRegsEntry; static inline void *decode_pointer(uint64_t v) { return (void*)v; } static inline uint64_t encode_pointer(void *p) { return (uint64_t)p; } +#define AT_VECTOR_SIZE 40 +typedef uint64_t auxv_t; +typedef uint64_t tls_t; + #endif /* __CR_ASM_TYPES_H__ */ diff --git a/criu/arch/arm/include/asm/types.h b/criu/arch/arm/include/asm/types.h index 99543fa9e..32612a692 100644 --- a/criu/arch/arm/include/asm/types.h +++ b/criu/arch/arm/include/asm/types.h @@ -24,4 +24,8 @@ typedef UserArmRegsEntry UserRegsEntry; static inline void *decode_pointer(u64 v) { return (void*)(u32)v; } static inline u64 encode_pointer(void *p) { return (u32)p; } +#define AT_VECTOR_SIZE 40 +typedef uint32_t auxv_t; +typedef uint32_t tls_t; + #endif /* __CR_ASM_TYPES_H__ */ diff --git a/criu/arch/ppc64/include/asm/types.h b/criu/arch/ppc64/include/asm/types.h index a23d50035..a82bc71a8 100644 --- a/criu/arch/ppc64/include/asm/types.h +++ b/criu/arch/ppc64/include/asm/types.h @@ -22,4 +22,19 @@ typedef UserPpc64RegsEntry UserRegsEntry; static inline void *decode_pointer(uint64_t v) { return (void*)v; } static inline uint64_t encode_pointer(void *p) { return (uint64_t)p; } +/* + * Copied from the following kernel header files : + * include/linux/auxvec.h + * arch/powerpc/include/uapi/asm/auxvec.h + * include/linux/mm_types.h + */ +#define AT_VECTOR_SIZE_BASE 20 +#define AT_VECTOR_SIZE_ARCH 6 +#define AT_VECTOR_SIZE (2*(AT_VECTOR_SIZE_ARCH + AT_VECTOR_SIZE_BASE + 1)) + +typedef uint64_t auxv_t; + +/* Not used but the structure parasite_dump_thread needs a tls_t field */ +typedef uint64_t tls_t; + #endif /* __CR_ASM_TYPES_H__ */ diff --git a/criu/arch/x86/include/asm/types.h b/criu/arch/x86/include/asm/types.h index dbf284035..4a93ffdeb 100644 --- a/criu/arch/x86/include/asm/types.h +++ b/criu/arch/x86/include/asm/types.h @@ -37,4 +37,20 @@ typedef UserX86RegsEntry UserRegsEntry; static inline u64 encode_pointer(void *p) { return (u64)(long)p; } static inline void *decode_pointer(u64 v) { return (void*)(long)v; } +#define AT_VECTOR_SIZE 44 +typedef uint64_t auxv_t; + +/* + * Linux preserves three TLS segments in GDT. + * Offsets in GDT differ between 32-bit and 64-bit machines. + * For 64-bit x86 those GDT offsets are the same + * for native and compat tasks. + */ +#define GDT_ENTRY_TLS_MIN 12 +#define GDT_ENTRY_TLS_MAX 14 +#define GDT_ENTRY_TLS_NUM 3 +typedef struct { + user_desc_t desc[GDT_ENTRY_TLS_NUM]; +} tls_t; + #endif /* __CR_ASM_TYPES_H__ */ From 71eb7d8795e084a2ff30def4c255e2c91fbe049c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 22 Nov 2016 14:42:20 +0300 Subject: [PATCH 0239/4375] x86/compat: provide optimized memcpy_x86 Implementation for PIE's builtin_memcpy located at criu/arch/x86/include/asm/string.h travis-ci: success for Compel/compat cleanups Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/compat/memcpy-compat.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 criu/arch/x86/compat/memcpy-compat.c diff --git a/criu/arch/x86/compat/memcpy-compat.c b/criu/arch/x86/compat/memcpy-compat.c new file mode 100644 index 000000000..793c27dca --- /dev/null +++ b/criu/arch/x86/compat/memcpy-compat.c @@ -0,0 +1,25 @@ +#include + +/* + * This provides an optimized implementation of memcpy, and a simplified + * implementation of memset and memmove. These are used here because the + * standard kernel runtime versions are not yet available and we don't + * trust the gcc built-in implementations as they may do unexpected things + * (e.g. FPU ops) in the minimal decompression stub execution environment. + * + * From Linux kernel boot helpers: arch/x86/boot/compressed/string.c + */ + +void *memcpy_x86(void *dest, const void *src, size_t n) +{ + int d0, d1, d2; + asm volatile( + "rep ; movsl\n\t" + "movl %4,%%ecx\n\t" + "rep ; movsb\n\t" + : "=&c" (d0), "=&D" (d1), "=&S" (d2) + : "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src) + : "memory"); + + return dest; +} From 50219defcf24eea1ed9d58ef2c46b346c85441fc Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 23 Nov 2016 18:33:55 +0300 Subject: [PATCH 0240/4375] compel: plugins,fds -- Don't include log.h It's libcompel's helper. We need to address this problem later. travis-ci: success for compel: A few fixes and example Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/fds/fds.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compel/plugins/fds/fds.c b/compel/plugins/fds/fds.c index a19c66287..28f1db748 100644 --- a/compel/plugins/fds/fds.c +++ b/compel/plugins/fds/fds.c @@ -4,10 +4,12 @@ #include "uapi/std/syscall.h" #include "uapi/std/string.h" +#include "uapi/std/log.h" #include "uapi/plugin-fds.h" #include "std-priv.h" -#include "log.h" + +#define pr_err(fmt, ...) #include "common/compiler.h" #include "common/bug.h" From 61769b466b18ca46eb73f181d0a0ed68014fd7e4 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 23 Nov 2016 18:33:56 +0300 Subject: [PATCH 0241/4375] compel: Improve infect - extend handle_sigchld - fix garbage return in compel_prepare - handle errors in make_sock_for travis-ci: success for compel: A few fixes and example Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/lib/infect.c | 57 +++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index b4db68069..434186ed3 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -1017,31 +1017,46 @@ out: */ static int make_sock_for(int pid) { - int ret = -1; - int mfd, fd; + int ret, mfd, fd, sk = -1; char p[32]; + pr_debug("Preparing seqsk for %d\n", pid); + sprintf(p, "/proc/%d/ns/net", pid); fd = open(p, O_RDONLY); - if (fd < 0) + if (fd < 0) { + pr_perror("Can't open %p", p); goto out; + } mfd = open("/proc/self/ns/net", O_RDONLY); - if (mfd < 0) + if (mfd < 0) { + pr_perror("Can't open self netns"); goto out_c; + } - if (setns(fd, CLONE_NEWNET)) + if (setns(fd, CLONE_NEWNET)) { + pr_perror("Can't setup target netns"); goto out_cm; + } - ret = socket(PF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK, 0); + sk = socket(PF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK, 0); + if (sk < 0) + pr_perror("Can't create seqsk"); - setns(mfd, CLONE_NEWNET); + ret = setns(mfd, CLONE_NEWNET); + if (ret) { + pr_perror("Can't restore former netns"); + if (sk >= 0) + close(sk); + sk = -1; + } out_cm: close(mfd); out_c: close(fd); out: - return ret; + return sk; } static int simple_open_proc(int pid, int mode, const char *fmt, ...) @@ -1061,10 +1076,25 @@ static int simple_open_proc(int pid, int mode, const char *fmt, ...) static void handle_sigchld(int signal, siginfo_t *siginfo, void *data) { - int status; + int pid, status; - waitpid(-1, &status, WNOHANG); - /* FIXME -- what to do here? */ + pid = waitpid(-1, &status, WNOHANG); + if (pid <= 0) + return; + + pr_err("si_code=%d si_pid=%d si_status=%d\n", + siginfo->si_code, siginfo->si_pid, siginfo->si_status); + + if (WIFEXITED(status)) + pr_err("%d exited with %d unexpectedly\n", pid, WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + pr_err("%d was killed by %d unexpectedly: %s\n", + pid, WTERMSIG(status), strsignal(WTERMSIG(status))); + else if (WIFSTOPPED(status)) + pr_err("%d was stopped by %d unexpectedly\n", pid, WSTOPSIG(status)); + + /* FIXME Should we exit? */ + /* exit(1); */ } struct plain_regs_struct { @@ -1151,8 +1181,9 @@ out: return ctl; err: - free(ictx->regs_arg); - free(ctl); + xfree(ictx->regs_arg); + xfree(ctl); + ctl = NULL; goto out; } From 0af11b421abb15ee70dfcf5728416aa9b05bf79d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 23 Nov 2016 18:42:00 +0300 Subject: [PATCH 0242/4375] compel: Rename 'piegen' action into 'hgen' Where hgen stands for "header generator". travis-ci: success for compel: Rename 'piegen' action into 'hgen' Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 4 ++-- criu/pie/Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index 643b6a96c..b9d02d718 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -212,7 +212,7 @@ int main(int argc, char *argv[]) return 0; } - if (!strcmp(action, "piegen")) { + if (!strcmp(action, "hgen")) { if (!opts.input_filename) goto usage; compel_log_init(&cli_log, log_level); @@ -223,6 +223,6 @@ usage: printf("Usage:\n"); printf(" compel --arch=(x86|ia32|aarch64|arm|ppc64) cflags\n"); printf(" compel --arch=(x86|ia32|aarch64|arm|ppc64) ldflags\n"); - printf(" compel -f filename piegen\n"); + printf(" compel -f filename hgen\n"); return 1; } diff --git a/criu/pie/Makefile b/criu/pie/Makefile index cec463281..32b73b1f8 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -124,7 +124,7 @@ $(eval $(call map,gen-rule-built-in.bin.o,$(parasite_target))) $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host $(call msg-gen, $@) - $(Q) $(SRC_DIR)/compel/compel-host piegen -f $< \ + $(Q) $(SRC_DIR)/compel/compel-host hgen -f $< \ -l 4 \ -v $(call target-name,$@)_relocs \ -p $(call target-name,$@)_blob_offset__ \ From 658206f269ee12a63605d401d14e98e300c349f6 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 24 Nov 2016 15:21:00 +0300 Subject: [PATCH 0243/4375] compel: Prepare for several ways to load blob into libcompel Right now we load blob into libcompel by providing values from .h file which was generated by "compel hgen" command. In the future we'd like to provide other ways (e.g. by pusing mmap()-ed memory with .o file, or by .o file path), so prepare for such future. travis-ci: success for compel: Prepare for several ways to load blob into libcompel Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 28 ++++++++++++++++++++-------- compel/src/lib/infect.c | 19 +++++++++++-------- criu/parasite-syscall.c | 18 ++++++++++-------- 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index ffcc1c8c9..c5a85b9fb 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -125,15 +125,27 @@ extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *); #define INFECT_NO_BREAKPOINTS 0x4 /* no breakpoints in pie tracking */ #define INFECT_HAS_COMPAT_SIGRETURN 0x8 +/* + * There are several ways to describe a blob to compel + * library. The simplest one derived from criu is to + * provide it from .h files. + */ +#define COMPEL_BLOB_CHEADER 0x1 + struct parasite_blob_desc { - const void *mem; - size_t bsize; /* size of the blob */ - size_t size; /* size of the blob with relocs */ - unsigned long parasite_ip_off; - unsigned long addr_cmd_off; - unsigned long addr_arg_off; - compel_reloc_t *relocs; - unsigned int nr_relocs; + unsigned parasite_type; + union { + struct { + const void *mem; + size_t bsize; /* size of the blob */ + size_t size; /* size of the blob with relocs */ + unsigned long parasite_ip_off; + unsigned long addr_cmd_off; + unsigned long addr_arg_off; + compel_reloc_t *relocs; + unsigned int nr_relocs; + } hdr; + }; }; extern struct parasite_blob_desc *compel_parasite_blob_desc(struct parasite_ctl *); diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 434186ed3..11f3e3edb 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -843,6 +843,9 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l int ret; unsigned long p, map_exchange_size, parasite_size = 0; + if (ctl->pblob.parasite_type != COMPEL_BLOB_CHEADER) + goto err; + if (ctl->ictx.log_fd < 0) goto err; @@ -856,7 +859,7 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l * without using ptrace at all. */ - parasite_size = ctl->pblob.size; + parasite_size = ctl->pblob.hdr.size; ctl->args_size = round_up(args_size, PAGE_SIZE); parasite_size += ctl->args_size; @@ -872,14 +875,14 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map); - ctl->parasite_ip = (unsigned long)(ctl->remote_map + ctl->pblob.parasite_ip_off); - ctl->addr_cmd = ctl->local_map + ctl->pblob.addr_cmd_off; - ctl->addr_args = ctl->local_map + ctl->pblob.addr_arg_off; + ctl->parasite_ip = (unsigned long)(ctl->remote_map + ctl->pblob.hdr.parasite_ip_off); + ctl->addr_cmd = ctl->local_map + ctl->pblob.hdr.addr_cmd_off; + ctl->addr_args = ctl->local_map + ctl->pblob.hdr.addr_arg_off; - memcpy(ctl->local_map, ctl->pblob.mem, ctl->pblob.size); - if (ctl->pblob.nr_relocs) - compel_relocs_apply(ctl->local_map, ctl->remote_map, ctl->pblob.bsize, - ctl->pblob.relocs, ctl->pblob.nr_relocs); + memcpy(ctl->local_map, ctl->pblob.hdr.mem, ctl->pblob.hdr.size); + if (ctl->pblob.hdr.nr_relocs) + compel_relocs_apply(ctl->local_map, ctl->remote_map, ctl->pblob.hdr.bsize, + ctl->pblob.hdr.relocs, ctl->pblob.hdr.nr_relocs); p = parasite_size; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 8002546f9..445df2725 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -539,21 +539,21 @@ static int make_sigframe(void *arg, struct rt_sigframe *sf, struct rt_sigframe * #ifdef CONFIG_PIEGEN #define init_blob_relocs(bdesc, blob_type) \ do { \ - bdesc->relocs = parasite_##blob_type##_relocs; \ - bdesc->nr_relocs = ARRAY_SIZE(parasite_##blob_type##_relocs); \ + bdesc->hdr.relocs = parasite_##blob_type##_relocs; \ + bdesc->hdr.nr_relocs = ARRAY_SIZE(parasite_##blob_type##_relocs); \ } while (0) #else #define init_blob_relocs(bdesc, blob_type) #endif #define init_blob_desc(bdesc, blob_type) do { \ - pbd->size = pie_size(parasite_##blob_type); \ - bdesc->mem = parasite_##blob_type##_blob; \ - bdesc->bsize = sizeof(parasite_##blob_type##_blob); \ + bdesc->hdr.size = pie_size(parasite_##blob_type); \ + bdesc->hdr.mem = parasite_##blob_type##_blob; \ + bdesc->hdr.bsize = sizeof(parasite_##blob_type##_blob); \ /* Setup the rest of a control block */ \ - bdesc->parasite_ip_off = pblob_offset(blob_type, __export_parasite_head_start); \ - bdesc->addr_cmd_off = pblob_offset(blob_type, __export_parasite_cmd); \ - bdesc->addr_arg_off = pblob_offset(blob_type, __export_parasite_args); \ + bdesc->hdr.parasite_ip_off = pblob_offset(blob_type, __export_parasite_head_start);\ + bdesc->hdr.addr_cmd_off = pblob_offset(blob_type, __export_parasite_cmd); \ + bdesc->hdr.addr_arg_off = pblob_offset(blob_type, __export_parasite_args); \ init_blob_relocs(bdesc, blob_type); \ } while (0) @@ -605,6 +605,8 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ictx->log_fd = log_get_fd(); pbd = compel_parasite_blob_desc(ctl); + pbd->parasite_type = COMPEL_BLOB_CHEADER; + if (compel_mode_native(ctl)) init_blob_desc(pbd, native); #ifdef CONFIG_COMPAT From d6798cb3a4665da6efabcc321c4299666d63ef3c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 25 Nov 2016 18:11:51 +0300 Subject: [PATCH 0244/4375] compel: uapi -- Add common symlink Because we build compel from toplevel directory inclusion of "common/" doesn't cause any problem but will in future (especially when our headers start using it). Thus add symlink immediately and it will be a notice for installer that common directory in needed in uapi. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/common | 1 + 1 file changed, 1 insertion(+) create mode 120000 compel/include/uapi/common diff --git a/compel/include/uapi/common b/compel/include/uapi/common new file mode 120000 index 000000000..33f00f44a --- /dev/null +++ b/compel/include/uapi/common @@ -0,0 +1 @@ +../../../include/common \ No newline at end of file From 5a7c137bb77fcdb6ad15450c6a0e0266f1b2c336 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 25 Nov 2016 18:11:52 +0300 Subject: [PATCH 0245/4375] compel: Prepare to ship common headers into compel Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/include/uapi/asm/fpu.h | 2 +- compel/plugins/include/uapi/plugin-fds.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h index 90071a144..7525f153a 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h @@ -5,7 +5,7 @@ #include #include -#include "common/compiler.h" +#include #define FP_MIN_ALIGN_BYTES 64 diff --git a/compel/plugins/include/uapi/plugin-fds.h b/compel/plugins/include/uapi/plugin-fds.h index 4d2feedb3..fbf5313a8 100644 --- a/compel/plugins/include/uapi/plugin-fds.h +++ b/compel/plugins/include/uapi/plugin-fds.h @@ -7,6 +7,6 @@ #include -#include "common/scm.h" +#include #endif /* __COMPEL_PLUGIN_FDS_H__ */ From 474289f04006e2c138a9e754c0b00df4e19ed09a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 25 Nov 2016 18:11:54 +0300 Subject: [PATCH 0246/4375] compel: Add installation To ship plugins, libs and dev headers. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile.compel | 13 ++++++++++--- Makefile.install | 9 ++++++++- compel/Makefile | 42 ++++++++++++++++++++++++++++++++++++++++- compel/plugins/Makefile | 27 ++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/Makefile.compel b/Makefile.compel index 42d05bc41..d15b26763 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -35,6 +35,10 @@ compel-deps += $(COMPEL_VERSION_HEADER) compel-deps += $(CONFIG_HEADER) compel-deps += include/common/asm +LIBCOMPEL_SO := libcompel.so +LIBCOMPEL_A := libcompel.a +export LIBCOMPEL_SO LIBCOMPEL_A + # # Compel itself. compel/%: $(compel-deps) compel/plugins/std.built-in.o .FORCE @@ -58,14 +62,17 @@ compel/plugins/shmem.built-in.o: $(compel-deps) .FORCE compel/plugins/fds.built-in.o: $(compel-deps) .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ -compel/compel: compel/built-in.o compel/libcompel.a | $(compel-deps) +compel/compel: compel/built-in.o compel/$(LIBCOMPEL_A) | $(compel-deps) $(call msg-link, $@) $(Q) $(CC) $(CFLAGS) $^ $(WRAPFLAGS) $(LDFLAGS) -rdynamic -o $@ # # And compel library. -LIBCOMPEL_SO := libcompel.so LIBCOMPEL_SO_CFLAGS += $(CFLAGS) -rdynamic -Wl,-soname,$(LIBCOMPEL_SO).$(COMPEL_SO_VERSION_MAJOR) -compel/$(LIBCOMPEL_SO): compel/libcompel.a +compel/$(LIBCOMPEL_SO): compel/$(LIBCOMPEL_A) $(call msg-link, $@) $(Q) $(CC) -shared $(LIBCOMPEL_SO_CFLAGS) -o $@ -Wl,--whole-archive $^ -Wl,--no-whole-archive $(LDFLAGS) + +compel-install-targets += compel/$(LIBCOMPEL_SO) +compel-install-targets += compel/compel +compel-install-targets += compel/plugins/std.built-in.o diff --git a/Makefile.install b/Makefile.install index 7c3da2027..9e78367a3 100644 --- a/Makefile.install +++ b/Makefile.install @@ -36,7 +36,12 @@ install-criu: criu $(Q) $(MAKE) $(build)=criu install .PHONY: install-criu -install: install-man install-lib install-criu +install-compel: $(compel-install-targets) + $(Q) $(MAKE) $(build)=compel install + $(Q) $(MAKE) $(build)=compel/plugins install +.PHONY: install-compel + +install: install-man install-lib install-criu install-compel @true .PHONY: install @@ -44,4 +49,6 @@ uninstall: $(Q) $(MAKE) -C Documentation $@ $(Q) $(MAKE) $(build)=lib $@ $(Q) $(MAKE) $(build)=criu $@ + $(Q) $(MAKE) $(build)=compel $@ + $(Q) $(MAKE) $(build)=compel/plugins $@ .PHONY: uninstall diff --git a/compel/Makefile b/compel/Makefile index ad0315566..8c580fdf3 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -15,7 +15,7 @@ ccflags-y += -fPIC ccflags-y += -I compel/include/uapi ccflags-y += -I compel/plugins/include/uapi -lib-name := libcompel.a +lib-name := $(LIBCOMPEL_A) lib-y += src/lib/log.o host-lib-y += src/lib/log.o @@ -52,3 +52,43 @@ endif cleanup-y += compel/compel cleanup-y += compel/compel-host cleanup-y += compel/libcompel.so + +install: compel/compel compel/$(LIBCOMPEL_SO) compel/$(LIBCOMPEL_A) + $(E) " INSTALL " compel + $(Q) mkdir -p $(DESTDIR)$(SBINDIR) + $(Q) install -m 755 compel/compel $(DESTDIR)$(SBINDIR) + $(E) " INSTALL " $(LIBCOMPEL_SO) + $(Q) mkdir -p $(DESTDIR)$(LIBDIR) + $(Q) install -m 0644 compel/$(LIBCOMPEL_SO) $(DESTDIR)$(LIBDIR) + $(Q) install -m 755 compel/$(LIBCOMPEL_SO) $(DESTDIR)$(LIBDIR)/$(LIBCOMPEL_SO).$(COMPEL_SO_VERSION_MAJOR).$(COMPEL_SO_VERSION_MINOR) + $(Q) ln -fns $(LIBCOMPEL_SO).$(COMPEL_SO_VERSION_MAJOR).$(COMPEL_SO_VERSION_MINOR) $(DESTDIR)$(LIBDIR)/$(LIBCOMPEL_SO).$(COMPEL_SO_VERSION_MAJOR) + $(Q) ln -fns $(LIBCOMPEL_SO).$(COMPEL_SO_VERSION_MAJOR).$(COMPEL_SO_VERSION_MINOR) $(DESTDIR)$(LIBDIR)/$(LIBCOMPEL_SO) + $(E) " INSTALL " $(LIBCOMPEL_A) + $(Q) install -m 0644 compel/$(LIBCOMPEL_A) $(DESTDIR)$(LIBDIR) + $(E) " INSTALL " compel uapi + $(Q) mkdir -p $(DESTDIR)$(LIBEXECDIR)/compel/ + $(Q) mkdir -p $(DESTDIR)$(INCLUDEDIR)/compel/asm + $(Q) cp -fr compel/include/uapi/compel/*.h $(DESTDIR)$(INCLUDEDIR)/compel + $(Q) cp -fr compel/include/uapi/compel/asm/*.h $(DESTDIR)$(INCLUDEDIR)/compel/asm + $(Q) mkdir -p $(DESTDIR)$(INCLUDEDIR)/compel/common/asm + $(Q) cp -fr include/common/compiler.h $(DESTDIR)$(INCLUDEDIR)/compel/common/ +.PHONY: install + +uninstall: + $(E) " UNINSTALL" compel + $(Q) $(RM) $(addprefix $(DESTDIR)$(SBINDIR)/,compel) + $(E) " UNINSTALL" $(LIBCOMPEL_SO) + $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBDIR)/,$(LIBCOMPEL_SO)) + $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBDIR)/,$(LIBCOMPEL_SO).$(COMPEL_SO_VERSION_MAJOR)) + $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBDIR)/,$(LIBCOMPEL_SO).$(COMPEL_SO_VERSION_MAJOR).$(COMPEL_SO_VERSION_MINOR)) + $(E) " UNINSTALL" $(LIBCOMPEL_A) + $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBDIR)/,$(LIBCOMPEL_A)) + $(E) " UNINSTALL" compel uapi + $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/*.h) + $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/asm/*.h) + $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/asm/) + $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/common/*.h) + $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/common/asm/*.h) + $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/common/asm/) + $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/common/) +.PHONY: uninstall diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 9e66c74bb..320f55853 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -67,3 +67,30 @@ endef # and definitions so we have to order their # generation manually. $(foreach t,$(target),$(eval $(call syscall-priority,$(t)-obj-y,std-headers-deps))) + +# +# FIXME syscall-types.h should be setup earlier +# +install: compel/plugins/std.built-in.o compel/plugins/fds.built-in.o + $(E) " INSTALL " compel plugins + $(Q) mkdir -p $(DESTDIR)$(LIBEXECDIR)/compel/ + $(Q) install -m 0644 compel/plugins/std.built-in.o $(DESTDIR)$(LIBEXECDIR)/compel/ + $(Q) install -m 0644 compel/plugins/fds.built-in.o $(DESTDIR)$(LIBEXECDIR)/compel/ + $(Q) mkdir -p $(DESTDIR)$(LIBEXECDIR)/compel/scripts + $(Q) install -m 0644 compel/arch/$(ARCH)/scripts/compel-pack.lds.S $(DESTDIR)$(LIBEXECDIR)/compel/scripts + $(E) " INSTALL " compel plugins uapi + $(Q) mkdir -p $(DESTDIR)$(INCLUDEDIR)/compel/plugins/std/asm + $(Q) cp -fr compel/include/uapi/compel/plugins/plugin-std.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins + $(Q) cp -fr compel/include/uapi/compel/plugins/std/*.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins/std + $(Q) cp -fr compel/arch/$(ARCH)/plugins/include/asm/syscall-types.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins/std/asm + $(Q) cp -fr compel/include/uapi/compel/plugins/plugin-fds.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins +.PHONY: install + +uninstall: + $(E) " UNINSTALL" compel plugins + $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBEXECDIR)/compel/,std.built-in.o) + $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBEXECDIR)/compel/,fds.built-in.o) + $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBEXECDIR)/compel/scripts,compel-pack.lds.S) + $(E) " UNINSTALL" compel and plugins uapi + $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/plugins) +.PHONY: uninstall From a9a7bf7b4975c074a3e05a1e348612f4f5e01d93 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 25 Nov 2016 18:11:55 +0300 Subject: [PATCH 0247/4375] compel: cli -- Fix typo in options parsing Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/src/main.c b/compel/src/main.c index b9d02d718..3d18d7441 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -179,8 +179,8 @@ int main(int argc, char *argv[]) opts.nrgotpcrel_name = optarg; break; case 'l': - break; log_level = atoi(optarg); + break; case 'h': goto usage; case 'V': From fe0413ef9eb122cd0ede99808ed9e460416a5bba Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 25 Nov 2016 19:44:13 +0300 Subject: [PATCH 0248/4375] compel: plugins -- Merge fds plugin into std We use fds helpers in std plugin anyway so just merge it in. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/Makefile | 11 ++--------- compel/plugins/include/uapi/plugin-fds.h | 12 ------------ compel/plugins/include/uapi/plugin-std.h | 1 + compel/plugins/include/uapi/std/fds.h | 7 +++++++ compel/plugins/{fds => std}/fds.c | 4 +--- compel/plugins/std/infect.c | 2 +- compel/src/lib/infect-util.c | 2 +- 7 files changed, 13 insertions(+), 26 deletions(-) delete mode 100644 compel/plugins/include/uapi/plugin-fds.h create mode 100644 compel/plugins/include/uapi/std/fds.h rename compel/plugins/{fds => std}/fds.c (85%) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 320f55853..80735558c 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -34,11 +34,6 @@ asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer asflags-y += -fno-stack-protector ldflags-y += -z noexecstack -# -# Fds plugin -target += fds -fds-obj-y += fds/fds.o - # # Shmem plugin target += shmem @@ -48,6 +43,7 @@ shmem-obj-y += shmem/shmem.o # STD plugin target += std std-obj-y += std/std.o +std-obj-y += std/fds.o std-obj-y += std/log.o std-obj-y += std/string.o std-obj-y += std/infect.o @@ -71,11 +67,10 @@ $(foreach t,$(target),$(eval $(call syscall-priority,$(t)-obj-y,std-headers-deps # # FIXME syscall-types.h should be setup earlier # -install: compel/plugins/std.built-in.o compel/plugins/fds.built-in.o +install: compel/plugins/std.built-in.o $(E) " INSTALL " compel plugins $(Q) mkdir -p $(DESTDIR)$(LIBEXECDIR)/compel/ $(Q) install -m 0644 compel/plugins/std.built-in.o $(DESTDIR)$(LIBEXECDIR)/compel/ - $(Q) install -m 0644 compel/plugins/fds.built-in.o $(DESTDIR)$(LIBEXECDIR)/compel/ $(Q) mkdir -p $(DESTDIR)$(LIBEXECDIR)/compel/scripts $(Q) install -m 0644 compel/arch/$(ARCH)/scripts/compel-pack.lds.S $(DESTDIR)$(LIBEXECDIR)/compel/scripts $(E) " INSTALL " compel plugins uapi @@ -83,13 +78,11 @@ install: compel/plugins/std.built-in.o compel/plugins/fds.built-in.o $(Q) cp -fr compel/include/uapi/compel/plugins/plugin-std.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins $(Q) cp -fr compel/include/uapi/compel/plugins/std/*.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins/std $(Q) cp -fr compel/arch/$(ARCH)/plugins/include/asm/syscall-types.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins/std/asm - $(Q) cp -fr compel/include/uapi/compel/plugins/plugin-fds.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins .PHONY: install uninstall: $(E) " UNINSTALL" compel plugins $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBEXECDIR)/compel/,std.built-in.o) - $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBEXECDIR)/compel/,fds.built-in.o) $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBEXECDIR)/compel/scripts,compel-pack.lds.S) $(E) " UNINSTALL" compel and plugins uapi $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/plugins) diff --git a/compel/plugins/include/uapi/plugin-fds.h b/compel/plugins/include/uapi/plugin-fds.h deleted file mode 100644 index fbf5313a8..000000000 --- a/compel/plugins/include/uapi/plugin-fds.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * plugin-fds.h -- API for fds compel plugin - */ - -#ifndef __COMPEL_PLUGIN_FDS_H__ -#define __COMPEL_PLUGIN_FDS_H__ - -#include - -#include - -#endif /* __COMPEL_PLUGIN_FDS_H__ */ diff --git a/compel/plugins/include/uapi/plugin-std.h b/compel/plugins/include/uapi/plugin-std.h index 29e6c1b11..78619ecd7 100644 --- a/compel/plugins/include/uapi/plugin-std.h +++ b/compel/plugins/include/uapi/plugin-std.h @@ -5,5 +5,6 @@ #include #include #include +#include #endif /* COMPEL_PLUGIN_STD_STD_H__ */ diff --git a/compel/plugins/include/uapi/std/fds.h b/compel/plugins/include/uapi/std/fds.h new file mode 100644 index 000000000..ed695ee87 --- /dev/null +++ b/compel/plugins/include/uapi/std/fds.h @@ -0,0 +1,7 @@ +#ifndef COMPEL_PLUGIN_STD_FDS_H__ +#define COMPEL_PLUGIN_STD_FDS_H__ + +#include +#include + +#endif /* COMPEL_PLUGIN_STD_FDS_H__ */ diff --git a/compel/plugins/fds/fds.c b/compel/plugins/std/fds.c similarity index 85% rename from compel/plugins/fds/fds.c rename to compel/plugins/std/fds.c index 28f1db748..8cfe6d288 100644 --- a/compel/plugins/fds/fds.c +++ b/compel/plugins/std/fds.c @@ -5,7 +5,7 @@ #include "uapi/std/syscall.h" #include "uapi/std/string.h" #include "uapi/std/log.h" -#include "uapi/plugin-fds.h" +#include "uapi/std/fds.h" #include "std-priv.h" @@ -18,5 +18,3 @@ #define __memcpy std_memcpy #include "common/scm-code.c" - -PLUGIN_REGISTER_DUMMY(fds) diff --git a/compel/plugins/std/infect.c b/compel/plugins/std/infect.c index 844bbb6f7..7fb3db8b8 100644 --- a/compel/plugins/std/infect.c +++ b/compel/plugins/std/infect.c @@ -2,7 +2,7 @@ #include #include "common/scm.h" -#include "uapi/compel/plugins/plugin-fds.h" +#include "uapi/compel/plugins/std/fds.h" #include "uapi/compel/plugins/std/string.h" #include "uapi/compel/plugins/std/log.h" diff --git a/compel/src/lib/infect-util.c b/compel/src/lib/infect-util.c index 99dbee062..b8f20bf01 100644 --- a/compel/src/lib/infect-util.c +++ b/compel/src/lib/infect-util.c @@ -2,7 +2,7 @@ #include "common/bug.h" #include "common/lock.h" -#include "uapi/compel/plugins/plugin-fds.h" +#include "uapi/compel/plugins/std/fds.h" #include "infect-rpc.h" #include "infect-util.h" From 167d28bd9e0eacaa260806bc9438782bd6e88846 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 25 Nov 2016 16:20:31 +0300 Subject: [PATCH 0249/4375] compel: Add compel_stop_task() to UAPI headers The routine itself is in library, just forgot to putt the declaration into UAPI header. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index c5a85b9fb..8d823c14d 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -25,6 +25,8 @@ struct seize_task_status { extern int compel_wait_task(int pid, int ppid, int (*get_status)(int pid, struct seize_task_status *), struct seize_task_status *st); + +extern int compel_stop_task(int pid); extern int compel_unseize_task(pid_t pid, int orig_state, int state); /* From d6b9f74266b2421cb5fe6cd5ac8f1fb334f8efc8 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 25 Nov 2016 16:20:45 +0300 Subject: [PATCH 0250/4375] compel: Rename compel_unseize_task into _resume_ To be symmetrical with compel_stop_task() one. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 2 +- compel/src/lib/infect.c | 2 +- criu/cr-exec.c | 2 +- criu/seize.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 8d823c14d..746026c19 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -27,7 +27,7 @@ extern int compel_wait_task(int pid, int ppid, struct seize_task_status *st); extern int compel_stop_task(int pid); -extern int compel_unseize_task(pid_t pid, int orig_state, int state); +extern int compel_resume_task(pid_t pid, int orig_state, int state); /* * FIXME -- these should be mapped to pid.h's diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 11f3e3edb..bbb373a91 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -327,7 +327,7 @@ err: return -1; } -int compel_unseize_task(pid_t pid, int orig_st, int st) +int compel_resume_task(pid_t pid, int orig_st, int st) { pr_debug("\tUnseizing %d into %d\n", pid, st); diff --git a/criu/cr-exec.c b/criu/cr-exec.c index 538ebec86..ca764667c 100644 --- a/criu/cr-exec.c +++ b/criu/cr-exec.c @@ -192,7 +192,7 @@ int cr_exec(int pid, char **opt) out_cure: compel_cure(ctl); out_unseize: - compel_unseize_task(pid, prev_state, prev_state); + compel_resume_task(pid, prev_state, prev_state); out: return exit_code; } diff --git a/criu/seize.c b/criu/seize.c index 1fb7fd17d..d5079ca6c 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -538,7 +538,7 @@ static void unseize_task_and_threads(const struct pstree_item *item, int st) * the item->state is the state task was in when we seized one. */ - compel_unseize_task(item->pid->real, item->pid->state, st); + compel_resume_task(item->pid->real, item->pid->state, st); if (st == TASK_DEAD) return; From bf24eecdf677364e3b2b2af543f64780cfe1a265 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 25 Nov 2016 16:20:58 +0300 Subject: [PATCH 0251/4375] compel: Add helpers for hgen bdesc filling These names are generated by compel hgen, so there's no need in making callers know them. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/handle-elf.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compel/include/uapi/handle-elf.h b/compel/include/uapi/handle-elf.h index ddeecb0d5..013e2e43c 100644 --- a/compel/include/uapi/handle-elf.h +++ b/compel/include/uapi/handle-elf.h @@ -12,4 +12,12 @@ typedef struct { long value; } compel_reloc_t; +/* + * Helpers for compel hgen command results. The pref should match + * the -p|--sym-prefix argument value. + */ +#define COMPEL_H_PARASITE_HEAD(pref) pref##__export_parasite_head_start +#define COMPEL_H_PARASITE_CMD(pref) pref##__export_parasite_cmd +#define COMPEL_H_PARASITE_ARGS(pref) pref##__export_parasite_args + #endif From 7dbf89c4d07284a3a8530e81fa556698b9e44ee2 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 25 Nov 2016 16:21:12 +0300 Subject: [PATCH 0252/4375] compel: Remove size/bsize from blob desc The size value should be page_size() aligned, which is inconvenient for callers, and also differs from the bsize only a little bit, so it's nicer to have the nr_gotpcrel value which is anyway generated by compel hgen. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 4 ++-- compel/src/lib/infect.c | 11 ++++++++--- criu/parasite-syscall.c | 2 +- criu/pie/pie-relocs.h | 2 ++ 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 746026c19..142bef6fe 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -139,8 +139,8 @@ struct parasite_blob_desc { union { struct { const void *mem; - size_t bsize; /* size of the blob */ - size_t size; /* size of the blob with relocs */ + size_t bsize; + size_t nr_gotpcrel; unsigned long parasite_ip_off; unsigned long addr_cmd_off; unsigned long addr_arg_off; diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index bbb373a91..6674dc0f6 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -838,10 +838,15 @@ int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size) return ret; } +static inline unsigned long total_pie_size(size_t blob_size, size_t nr_gp) +{ + return round_up(blob_size + nr_gp * sizeof(long), page_size()); +} + int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size) { int ret; - unsigned long p, map_exchange_size, parasite_size = 0; + unsigned long p, map_exchange_size, pie_size, parasite_size = 0; if (ctl->pblob.parasite_type != COMPEL_BLOB_CHEADER) goto err; @@ -859,7 +864,7 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l * without using ptrace at all. */ - parasite_size = ctl->pblob.hdr.size; + pie_size = parasite_size = total_pie_size(ctl->pblob.hdr.bsize, ctl->pblob.hdr.nr_gotpcrel); ctl->args_size = round_up(args_size, PAGE_SIZE); parasite_size += ctl->args_size; @@ -879,7 +884,7 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l ctl->addr_cmd = ctl->local_map + ctl->pblob.hdr.addr_cmd_off; ctl->addr_args = ctl->local_map + ctl->pblob.hdr.addr_arg_off; - memcpy(ctl->local_map, ctl->pblob.hdr.mem, ctl->pblob.hdr.size); + memcpy(ctl->local_map, ctl->pblob.hdr.mem, pie_size); if (ctl->pblob.hdr.nr_relocs) compel_relocs_apply(ctl->local_map, ctl->remote_map, ctl->pblob.hdr.bsize, ctl->pblob.hdr.relocs, ctl->pblob.hdr.nr_relocs); diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 445df2725..9dd253007 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -547,9 +547,9 @@ static int make_sigframe(void *arg, struct rt_sigframe *sf, struct rt_sigframe * #endif #define init_blob_desc(bdesc, blob_type) do { \ - bdesc->hdr.size = pie_size(parasite_##blob_type); \ bdesc->hdr.mem = parasite_##blob_type##_blob; \ bdesc->hdr.bsize = sizeof(parasite_##blob_type##_blob); \ + bdesc->hdr.nr_gotpcrel = pie_nr_gotpcrel(parasite_##blob_type); \ /* Setup the rest of a control block */ \ bdesc->hdr.parasite_ip_off = pblob_offset(blob_type, __export_parasite_head_start);\ bdesc->hdr.addr_cmd_off = pblob_offset(blob_type, __export_parasite_cmd); \ diff --git a/criu/pie/pie-relocs.h b/criu/pie/pie-relocs.h index 442e70d13..a96150a26 100644 --- a/criu/pie/pie-relocs.h +++ b/criu/pie/pie-relocs.h @@ -10,6 +10,7 @@ #define pie_size(__pie_name) (round_up(sizeof(__pie_name##_blob) + \ __pie_name ## _nr_gotpcrel * sizeof(long), page_size())) +#define pie_nr_gotpcrel(__pie_name) (__pie_name ## _nr_gotpcrel) #define ELF_RELOCS_APPLY(__pie_name, __mem, __vbase) \ compel_relocs_apply(__mem, __vbase, sizeof(__pie_name##_blob), \ __pie_name##_relocs, ARRAY_SIZE(__pie_name##_relocs)) @@ -17,6 +18,7 @@ #else #define pie_size(__pie_name) (round_up(sizeof(__pie_name##_blob), page_size())) +#define pie_nr_gotpcrel(__pie_name) (0) #define ELF_RELOCS_APPLY(__pie_name, __mem, __vbase) #endif From 16080b7f6fa3f7d48e38476608cfcce37c7ee674 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 25 Nov 2016 16:45:31 +0300 Subject: [PATCH 0253/4375] compel: Hide compel_execute_syscall() from uapi It uses regs caller doesn't always know and is actually a core routine under the API compel_syscall() one. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/infect-priv.h | 2 ++ compel/include/uapi/infect.h | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/compel/include/infect-priv.h b/compel/include/infect-priv.h index fde5548b7..8e7443b85 100644 --- a/compel/include/infect-priv.h +++ b/compel/include/infect-priv.h @@ -72,4 +72,6 @@ extern int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, user_fpregs_struct_t *fpregs); extern int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, struct rt_sigframe *rsigframe); +extern int compel_execute_syscall(struct parasite_ctl *ctl, + user_regs_struct_t *regs, const char *code_syscall); #endif diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 142bef6fe..174c197bb 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -65,8 +65,13 @@ extern int compel_cure(struct parasite_ctl *ctl); extern void *compel_parasite_args_p(struct parasite_ctl *ctl); extern void *compel_parasite_args_s(struct parasite_ctl *ctl, int args_size); -extern int compel_execute_syscall(struct parasite_ctl *ctl, - user_regs_struct_t *regs, const char *code_syscall); +extern int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5, + unsigned long arg6); extern int compel_run_in_thread(struct parasite_thread_ctl *tctl, unsigned int cmd); /* From dd4d5aeddadf7c1b745e2f0756ca69b5971190d3 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 25 Nov 2016 16:21:52 +0300 Subject: [PATCH 0254/4375] compel: Simple infection test And, at the same time, an example of how to work with compel. Based on titanic preliminary work of Cyrill :) Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/test/infect/.gitignore | 4 + compel/test/infect/Makefile | 41 ++++++++ compel/test/infect/parasite.c | 37 +++++++ compel/test/infect/spy.c | 183 ++++++++++++++++++++++++++++++++++ compel/test/infect/victim.c | 15 +++ 5 files changed, 280 insertions(+) create mode 100644 compel/test/infect/.gitignore create mode 100644 compel/test/infect/Makefile create mode 100644 compel/test/infect/parasite.c create mode 100644 compel/test/infect/spy.c create mode 100644 compel/test/infect/victim.c diff --git a/compel/test/infect/.gitignore b/compel/test/infect/.gitignore new file mode 100644 index 000000000..0a554758d --- /dev/null +++ b/compel/test/infect/.gitignore @@ -0,0 +1,4 @@ +parasite.h +parasite.po +spy +victim diff --git a/compel/test/infect/Makefile b/compel/test/infect/Makefile new file mode 100644 index 000000000..2e27a09b1 --- /dev/null +++ b/compel/test/infect/Makefile @@ -0,0 +1,41 @@ +ifeq ($(ARCH),) + ARCH := x86 +endif + +# FIXME -- generate common symlink in compel/uapi +COMMON_IDIR := ../../../include +COMPEL := ../../../compel/compel-host +COMPEL_IDIR := ../../../compel/include/uapi +COMPEL_PACK_LDS := ../../../compel/arch/$(ARCH)/scripts/compel-pack.lds.S +COMPEL_PLUGINS := ../../../compel/plugins +COMPEL_LIBRARY := ../../../compel/libcompel.a + +all: victim spy + +clean: + rm -f victim + rm -f spy + rm -f parasite.h + rm -f parasite.po + rm -f parasite.o + +victim: victim.c + gcc -o $@ $^ + +spy: spy.c parasite.h $(COMPEL_LIBRARY) + gcc -Werror -I$(COMPEL_IDIR) -I$(COMMON_IDIR) -o $@ $^ + +parasite.h: parasite.po + $(COMPEL) hgen -f $^ -l 4 \ + -v parasite_relocs \ + -p parasite_sym \ + -s parasite_blob \ + -r parasite_nr_gotpcrel \ + -u $(COMPEL_IDIR) \ + -o $@ + +parasite.po: parasite.o $(COMPEL_PLUGINS)/std.built-in.o + ld -r -T $(COMPEL_PACK_LDS) -o $@ $^ + +parasite.o: parasite.c + gcc -c $(shell $(COMPEL) --arch=$(ARCH) cflags) -I$(COMPEL_IDIR) -o $@ $^ diff --git a/compel/test/infect/parasite.c b/compel/test/infect/parasite.c new file mode 100644 index 000000000..baecc0e3b --- /dev/null +++ b/compel/test/infect/parasite.c @@ -0,0 +1,37 @@ +#include + +#include +#include +#include + +#include + +/* + * Stubs for std compel plugin. + */ +int compel_main(void *arg_p, unsigned int arg_s) { return 0; } +int parasite_trap_cmd(int cmd, void *args) { return 0; } +void parasite_cleanup(void) { } + +#define PARASITE_CMD_INC PARASITE_USER_CMDS +#define PARASITE_CMD_DEC PARASITE_USER_CMDS + 1 + +int parasite_daemon_cmd(int cmd, void *args) +{ + int v; + + switch (cmd) { + case PARASITE_CMD_INC: + v = (*(int *)args) + 1; + break; + case PARASITE_CMD_DEC: + v = (*(int *)args) - 1; + break; + default: + v = -1; + break; + } + + sys_write(1, &v, sizeof(int)); + return 0; +} diff --git a/compel/test/infect/spy.c b/compel/test/infect/spy.c new file mode 100644 index 000000000..90428b16a --- /dev/null +++ b/compel/test/infect/spy.c @@ -0,0 +1,183 @@ +#include +#include +#include +#include + +#include +#include "parasite.h" + +#define PARASITE_CMD_INC PARASITE_USER_CMDS +#define PARASITE_CMD_DEC PARASITE_USER_CMDS + 1 + +static void print_vmsg(unsigned int lvl, const char *fmt, va_list parms) +{ + printf("\tLC%u: ", lvl); + vprintf(fmt, parms); +} + +static int do_infection(int pid) +{ +#define err_and_ret(msg) do { fprintf(stderr, msg); return -1; } while (0) + + int state; + struct parasite_ctl *ctl; + struct infect_ctx *ictx; + struct parasite_blob_desc *pbd; + int *arg; + + compel_log_init(print_vmsg, LOG_DEBUG); + + printf("Stopping task\n"); + state = compel_stop_task(pid); + if (state < 0) + err_and_ret("Can't stop task"); + + printf("Preparing parasite ctl\n"); + ctl = compel_prepare(pid); + if (!ctl) + err_and_ret("Can't prepare for infection"); + + printf("Configuring contexts\n"); + + /* + * First -- the infection context. Most of the stuff + * is already filled by compel_prepare(), just set the + * log descriptor for parasite side, library cannot + * live w/o it. + */ + ictx = compel_infect_ctx(ctl); + ictx->log_fd = STDERR_FILENO; + + /* + * Next the blob descriptor. We've requested for hgen + * in Makefile, so prepare this type of blob with the + * values from parasite.h. + */ + pbd = compel_parasite_blob_desc(ctl); + pbd->parasite_type = COMPEL_BLOB_CHEADER; + pbd->hdr.mem = parasite_blob; + pbd->hdr.bsize = sizeof(parasite_blob); + pbd->hdr.nr_gotpcrel = parasite_nr_gotpcrel; + pbd->hdr.parasite_ip_off = COMPEL_H_PARASITE_HEAD(parasite_sym); + pbd->hdr.addr_cmd_off = COMPEL_H_PARASITE_CMD(parasite_sym); + pbd->hdr.addr_arg_off = COMPEL_H_PARASITE_ARGS(parasite_sym); + pbd->hdr.relocs = parasite_relocs; + pbd->hdr.nr_relocs = sizeof(parasite_relocs) / sizeof(parasite_relocs[0]); + + printf("Infecting\n"); + if (compel_infect(ctl, 1, sizeof(int))) + err_and_ret("Can't infect victim"); + + /* + * Now get the area with arguments and run two + * commands one by one. + */ + arg = compel_parasite_args(ctl, int); + + printf("Running cmd 1\n"); + *arg = 137; + if (compel_rpc_call_sync(PARASITE_CMD_INC, ctl)) + err_and_ret("Can't run parasite command 1"); + + printf("Running cmd 2\n"); + *arg = 404; + if (compel_rpc_call_sync(PARASITE_CMD_DEC, ctl)) + err_and_ret("Can't run parasite command 2"); + + /* + * Done. Cure and resume the task. + */ + printf("Curing\n"); + if (compel_cure(ctl)) + err_and_ret("Can't cure victim"); + + if (compel_resume_task(pid, state, state)) + err_and_ret("Can't unseize task"); + + printf("Done\n"); + return 0; +} + +static inline int chk(int fd, int val) +{ + int v = 0; + + read(fd, &v, sizeof(v)); + printf("%d, want %d\n", v, val); + return v == val; +} + +int main(int argc, char **argv) +{ + int p_in[2], p_out[2], p_err[2], pid, i, pass = 1; + + /* + * Prepare IO-s and fork the victim binary + */ + if (pipe(p_in) || pipe(p_out) || pipe(p_err)) { + perror("Can't make pipe"); + return -1; + } + + pid = vfork(); + if (pid == 0) { + close(p_in[1]); dup2(p_in[0], 0); close(p_in[0]); + close(p_out[0]); dup2(p_out[1], 1); close(p_out[1]); + close(p_err[0]); dup2(p_err[1], 2); close(p_err[1]); + execl("./victim", "victim", NULL); + exit(1); + } + + close(p_in[0]); close(p_out[1]); close(p_err[1]); + + /* + * Tell the little guy some numbers + */ + i = 1; write(p_in[1], &i, sizeof(i)); + i = 42; write(p_in[1], &i, sizeof(i)); + + printf("Checking the victim alive\n"); + pass = chk(p_out[0], 1); + pass = chk(p_out[0], 42); + if (!pass) + return 1; + + /* + * Now do the infection with parasite.c + */ + + printf("Infecting the victim\n"); + if (do_infection(pid)) + return 1; + + /* + * Tell the victim some more stuff to check it's alive + */ + i = 1234; write(p_in[1], &i, sizeof(i)); + i = 4096; write(p_in[1], &i, sizeof(i)); + + /* + * Stop the victim and check the infection went well + */ + printf("Closing victim stdin\n"); + close(p_in[1]); + printf("Waiting for victim to die\n"); + wait(NULL); + + printf("Checking the result\n"); + + /* These two came from parasite */ + pass = chk(p_out[0], 138); + pass = chk(p_out[0], 403); + + /* These two came from post-infect */ + pass = chk(p_out[0], 1234); + pass = chk(p_out[0], 4096); + + if (pass) + printf("All OK\n"); + else + printf("Something went WRONG\n"); + + return 0; +} diff --git a/compel/test/infect/victim.c b/compel/test/infect/victim.c new file mode 100644 index 000000000..b37688b84 --- /dev/null +++ b/compel/test/infect/victim.c @@ -0,0 +1,15 @@ +#include + +int main(int argc, char **argv) +{ + int i; + + while (1) { + if (read(0, &i, sizeof(i)) != sizeof(i)) + break; + + write(1, &i, sizeof(i)); + } + + return 0; +} From 483f3e886b2a37cd27ac62b595a20d4aae2e5391 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 25 Nov 2016 16:45:47 +0300 Subject: [PATCH 0255/4375] compel: Test for remote syscall execution The library can be used not only to run infection blobs, but also just to execute syscalls remotely and here's an example of how to do this. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/test/rsys/.gitignore | 2 + compel/test/rsys/Makefile | 20 ++++++ compel/test/rsys/spy.c | 136 ++++++++++++++++++++++++++++++++++++ compel/test/rsys/victim.c | 16 +++++ 4 files changed, 174 insertions(+) create mode 100644 compel/test/rsys/.gitignore create mode 100644 compel/test/rsys/Makefile create mode 100644 compel/test/rsys/spy.c create mode 100644 compel/test/rsys/victim.c diff --git a/compel/test/rsys/.gitignore b/compel/test/rsys/.gitignore new file mode 100644 index 000000000..e3e9602c2 --- /dev/null +++ b/compel/test/rsys/.gitignore @@ -0,0 +1,2 @@ +spy +victim diff --git a/compel/test/rsys/Makefile b/compel/test/rsys/Makefile new file mode 100644 index 000000000..cd664884a --- /dev/null +++ b/compel/test/rsys/Makefile @@ -0,0 +1,20 @@ +ifeq ($(ARCH),) + ARCH := x86 +endif + +# FIXME -- generate common symlink in compel/uapi +COMMON_IDIR := ../../../include +COMPEL_IDIR := ../../../compel/include/uapi +COMPEL_LIBRARY := ../../../compel/libcompel.a + +all: victim spy + +clean: + rm -f victim + rm -f spy + +victim: victim.c + gcc -o $@ $^ + +spy: spy.c $(COMPEL_LIBRARY) + gcc -Werror -I$(COMPEL_IDIR) -I$(COMMON_IDIR) -o $@ $^ diff --git a/compel/test/rsys/spy.c b/compel/test/rsys/spy.c new file mode 100644 index 000000000..82c9725d7 --- /dev/null +++ b/compel/test/rsys/spy.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include + +#include + +static void print_vmsg(unsigned int lvl, const char *fmt, va_list parms) +{ + printf("\tLC%u: ", lvl); + vprintf(fmt, parms); +} + +static int do_rsetsid(int pid) +{ +#define err_and_ret(msg) do { fprintf(stderr, msg); return -1; } while (0) + + int state; + long ret; + struct parasite_ctl *ctl; + + compel_log_init(print_vmsg, LOG_DEBUG); + + printf("Stopping task\n"); + state = compel_stop_task(pid); + if (state < 0) + err_and_ret("Can't stop task"); + + printf("Preparing parasite ctl\n"); + ctl = compel_prepare(pid); + if (!ctl) + err_and_ret("Can't prepare for infection"); + + ret = -1000; + if (compel_syscall(ctl, __NR_getpid, &ret, 0, 0, 0, 0, 0, 0) < 0) + err_and_ret("Can't run rgetpid"); + + printf("Remote getpid returned %ld\n", ret); + if (ret != pid) + err_and_ret("Pid mismatch!"); + + ret = -1000; + if (compel_syscall(ctl, __NR_setsid, &ret, 0, 0, 0, 0, 0, 0) < 0) + err_and_ret("Can't run rsetsid"); + printf("Remote setsid returned %ld\n", ret); + + /* + * Done. Cure and resume the task. + */ + printf("Curing\n"); + if (compel_cure(ctl)) + err_and_ret("Can't cure victim"); + + if (compel_resume_task(pid, state, state)) + err_and_ret("Can't unseize task"); + + printf("Done\n"); + return 0; +} + +static inline int chk(int fd, int val) +{ + int v = 0; + + read(fd, &v, sizeof(v)); + printf("%d, want %d\n", v, val); + return v == val; +} + +int main(int argc, char **argv) +{ + int p_in[2], p_out[2], p_err[2], pid, i, pass = 1, sid; + + /* + * Prepare IO-s and fork the victim binary + */ + if (pipe(p_in) || pipe(p_out) || pipe(p_err)) { + perror("Can't make pipe"); + return -1; + } + + pid = vfork(); + if (pid == 0) { + close(p_in[1]); dup2(p_in[0], 0); close(p_in[0]); + close(p_out[0]); dup2(p_out[1], 1); close(p_out[1]); + close(p_err[0]); dup2(p_err[1], 2); close(p_err[1]); + execl("./victim", "victim", NULL); + exit(1); + } + + close(p_in[0]); close(p_out[1]); close(p_err[1]); + sid = getsid(0); + + /* + * Kick the victim once + */ + i = 0; + write(p_in[1], &i, sizeof(i)); + + printf("Checking the victim session to be %d\n", sid); + pass = chk(p_out[0], sid); + if (!pass) + return 1; + + /* + * Now do the infection with parasite.c + */ + + printf("Setsid() the victim\n"); + if (do_rsetsid(pid)) + return 1; + + /* + * Kick the victim again so it tells new session + */ + write(p_in[1], &i, sizeof(i)); + + /* + * Stop the victim and check the intrusion went well + */ + printf("Closing victim stdin\n"); + close(p_in[1]); + printf("Waiting for victim to die\n"); + wait(NULL); + + printf("Checking the new session to be %d\n", pid); + pass = chk(p_out[0], pid); + + if (pass) + printf("All OK\n"); + else + printf("Something went WRONG\n"); + + return 0; +} diff --git a/compel/test/rsys/victim.c b/compel/test/rsys/victim.c new file mode 100644 index 000000000..2f1943d0c --- /dev/null +++ b/compel/test/rsys/victim.c @@ -0,0 +1,16 @@ +#include + +int main(int argc, char **argv) +{ + int i; + + while (1) { + if (read(0, &i, sizeof(i)) != sizeof(i)) + break; + + i = getsid(0); + write(1, &i, sizeof(i)); + } + + return 0; +} From d4c02f2eb181197a70234b47be73f21824ff5ce5 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 25 Nov 2016 15:51:00 +0300 Subject: [PATCH 0256/4375] compel: kill self-unmap in parasite Why should we have self-unmapping code in parasite? It looks like, we can drop this code using simple sys_unmap() injection (like that I did for `criu exec` action and for cases where we failed to insert parasite by some reason, but still need to unmap remotes). It's an RFC, so just a suggestion - maybe I miss something you have in mind - please, describe that/those things. My motivation is: - less code, defined commands for PIE, one BUG() less, one jump to PIE less - I'm making one 64-bit parasite on x86 instead of two 32 and 64 bit. It works (branch 32-one-parasite) with long-jump in the beginning to 64-bit code from 32-bit task. On parasite curing it sig-returns from 64-bit parasite to 32-bit task, this point we're trapping in CRIU. After that we command parasite to unmap itself, so it long-jumps again to parasite 64-bit code, unmaps, we caught task after sys_unmap and the task is with 64-bit CS. We can't set 32-bit registers after this - kernel checks that registers set is the same on PTRACE_SETREGSET: > > static int ptrace_regset(struct task_struct *task, int req, unsigned int type, > > struct iovec *kiov) ... > > if (!regset || (kiov->iov_len % regset->size) != 0) > > return -EINVAL; So, to return again to 32-bit task I need sigreturn() again or add long-jump with 32-bit CS. I've disable that for 32-bit testing with (in compel_cure_remote): - if (ctl->addr_cmd) { + if (ctl->addr_cmd && user_regs_native(&ctl->orig.regs)) { And it works. It also works for native tasks, so why should we keep it? travis-ci: success for compel: kill self-unmap in parasite Cc: Cyrill Gorcunov Cc: Pavel Emelyanov Cc: Andrei Vagin Signed-off-by: Dmitry Safonov Acked-by: Andrei Vagin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/rpc-pie-priv.h | 1 - compel/plugins/std/infect.c | 20 +------------------- compel/src/lib/infect.c | 31 +++++++++---------------------- 3 files changed, 10 insertions(+), 42 deletions(-) diff --git a/compel/include/rpc-pie-priv.h b/compel/include/rpc-pie-priv.h index 3d9091159..f25ca89eb 100644 --- a/compel/include/rpc-pie-priv.h +++ b/compel/include/rpc-pie-priv.h @@ -22,7 +22,6 @@ enum { PARASITE_CMD_ACK, PARASITE_CMD_INIT_DAEMON, - PARASITE_CMD_UNMAP, /* * This must be greater than INITs. diff --git a/compel/plugins/std/infect.c b/compel/plugins/std/infect.c index 7fb3db8b8..a9553c8d0 100644 --- a/compel/plugins/std/infect.c +++ b/compel/plugins/std/infect.c @@ -140,20 +140,6 @@ out: return 0; } -static noinline int unmap_itself(void *data) -{ - struct parasite_unmap_args *args = data; - - sys_munmap(args->parasite_start, args->parasite_len); - /* - * This call to sys_munmap must never return. Instead, the controlling - * process must trap us on the exit from munmap. - */ - - BUG(); - return -1; -} - static noinline __used int parasite_init_daemon(void *data) { struct parasite_init_args *args = data; @@ -202,12 +188,8 @@ int __used __parasite_entry parasite_service(unsigned int cmd, void *args) { pr_info("Parasite cmd %d/%x process\n", cmd, cmd); - switch (cmd) { - case PARASITE_CMD_INIT_DAEMON: + if (cmd == PARASITE_CMD_INIT_DAEMON) return parasite_init_daemon(args); - case PARASITE_CMD_UNMAP: - return unmap_itself(args); - } return parasite_trap_cmd(cmd, args); } diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 6674dc0f6..adef4db9e 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -1292,34 +1292,21 @@ int compel_stop_daemon(struct parasite_ctl *ctl) int compel_cure_remote(struct parasite_ctl *ctl) { + unsigned long ret; + if (compel_stop_daemon(ctl)) return -1; if (!ctl->remote_map) return 0; - /* Unseizing task with parasite -- it does it himself */ - if (ctl->addr_cmd) { - struct parasite_unmap_args *args; - - *ctl->addr_cmd = PARASITE_CMD_UNMAP; - - args = compel_parasite_args(ctl, struct parasite_unmap_args); - args->parasite_start = ctl->remote_map; - args->parasite_len = ctl->map_length; - if (compel_unmap(ctl, ctl->parasite_ip)) - return -1; - } else { - unsigned long ret; - - compel_syscall(ctl, __NR(munmap, !compel_mode_native(ctl)), &ret, - (unsigned long)ctl->remote_map, ctl->map_length, - 0, 0, 0, 0); - if (ret) { - pr_err("munmap for remote map %p, %lu returned %lu\n", - ctl->remote_map, ctl->map_length, ret); - return -1; - } + compel_syscall(ctl, __NR(munmap, !compel_mode_native(ctl)), &ret, + (unsigned long)ctl->remote_map, ctl->map_length, + 0, 0, 0, 0); + if (ret) { + pr_err("munmap for remote map %p, %lu returned %lu\n", + ctl->remote_map, ctl->map_length, ret); + return -1; } return 0; From 403c96ad17929fa787ae1f50928d17cb34e909cc Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 6 Dec 2016 00:15:00 +0300 Subject: [PATCH 0257/4375] compel: Add compel_run_at helper Simply run tracee from specfied IP assuming it's arelady have trapping instruction in stream. It's unsafe low-level function use with caution. travis-ci: success for compel: A fix and new helper Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 1 + compel/src/lib/infect.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 174c197bb..7b88a5634 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -73,6 +73,7 @@ extern int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, unsigned long arg5, unsigned long arg6); extern int compel_run_in_thread(struct parasite_thread_ctl *tctl, unsigned int cmd); +extern int compel_run_at(struct parasite_ctl *ctl, unsigned long ip, user_regs_struct_t *ret_regs); /* * The PTRACE_SYSCALL will trap task twice -- on diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index adef4db9e..3dba438ef 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -590,6 +590,17 @@ int compel_execute_syscall(struct parasite_ctl *ctl, return err; } +int compel_run_at(struct parasite_ctl *ctl, unsigned long ip, user_regs_struct_t *ret_regs) +{ + user_regs_struct_t regs = ctl->orig.regs; + int ret; + + ret = parasite_run(ctl->rpid, PTRACE_CONT, ip, 0, ®s, &ctl->orig); + if (!ret) + ret = parasite_trap(ctl, ctl->rpid, ret_regs ? ret_regs : ®s, &ctl->orig); + return ret; +} + static int accept_tsock(struct parasite_ctl *ctl) { int sock; From b8474f294bbf0dbab9b30f72acd8136533a76ea7 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 07:00:00 +0300 Subject: [PATCH 0258/4375] compel handle_elf(): fix strings sect bounds check Got this when using compel hgen on arm 32-bit: Error (compel/src/lib/handle-elf-host.c:115): String section header @0xf66e11ec is out of [0xf66e1174, 0xf66e1264) Looking at this, it does not make sense. For the reference, sizeof(Elf_Shdr) is 0x28, so end position is also well within bounds. Apparently, the check for string section header bounds is wrong as the last argument of __ptr_struct_oob() is supposed to be a region size, not the region end address as it is. This always worked before because the check was too relaxed, and compel was never used on 32-bit ARM. This time it didn't work because of a 32-bit overflow, which helped to find this bug. This is a fix to commit 6402f03 ("compel: separate get_strings_section from __handle_elf"). Cc: Dmitry Safonov Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/lib/handle-elf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index ec41771db..c1318d512 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -110,7 +110,7 @@ static const char *get_strings_section(Elf_Ehdr *hdr, uintptr_t mem, size_t size */ addr = sec_table + ((size_t) hdr->e_shentsize) * hdr->e_shstrndx; if (__ptr_struct_oob(addr, sizeof(Elf_Shdr), - sec_table, sec_table + sec_table_size)) { + sec_table, sec_table_size)) { pr_err("String section header @%#zx is out of [%#zx, %#zx)\n", addr, sec_table, sec_table + sec_table_size); return NULL; From 4072e2d2c1a0a1f6f93b4a1df7b75395583aca49 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:14 -0800 Subject: [PATCH 0259/4375] compel: remove unneeded argc check Checks for a number of arguments are to be done after option parsing. With this patch, compel -V now works. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index 3d18d7441..a54aba7e8 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -137,9 +137,6 @@ int main(int argc, char *argv[]) { }, }; - if (argc < 3) - goto usage; - while (1) { idx = -1; opt = getopt_long(argc, argv, short_opts, long_opts, &idx); From ac2c9999f44c13d887e91961e8ebd25efc35be4a Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:15 -0800 Subject: [PATCH 0260/4375] compel: separate usage() to a function It will be easier to modify that way. This also fixes incorrect exit code from compel -h. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index a54aba7e8..2a2ba3b37 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -90,6 +90,17 @@ static void cli_log(unsigned int lvl, const char *fmt, va_list parms) vprintf(fmt, parms); } +static int usage(int rc) { + printf( +"Usage:\n" +" compel --arch=(x86|ia32|aarch64|arm|ppc64) cflags\n" +" compel --arch=(x86|ia32|aarch64|arm|ppc64) ldflags\n" +" compel -f filename hgen\n" +); + + return rc; +} + int main(int argc, char *argv[]) { const char *current_cflags = NULL; @@ -150,9 +161,9 @@ int main(int argc, char *argv[]) break; } } - - if (!current_cflags) - goto usage; + if (!current_cflags) { + return usage(1); + } break; case 'f': opts.input_filename = optarg; @@ -179,7 +190,7 @@ int main(int argc, char *argv[]) log_level = atoi(optarg); break; case 'h': - goto usage; + return usage(0); case 'V': printf("Version: %d.%d.%d\n", COMPEL_SO_VERSION_MAJOR, @@ -192,14 +203,15 @@ int main(int argc, char *argv[]) } } - if (optind >= argc) - goto usage; - + if (optind >= argc) { + return usage(1); + } action = argv[optind++]; if (!strcmp(action, "cflags")) { - if (!current_cflags) - goto usage; + if (!current_cflags) { + return usage(1); + } printf("%s", current_cflags); return 0; } @@ -210,16 +222,12 @@ int main(int argc, char *argv[]) } if (!strcmp(action, "hgen")) { - if (!opts.input_filename) - goto usage; + if (!opts.input_filename) { + return usage(1); + } compel_log_init(&cli_log, log_level); return piegen(); } -usage: - printf("Usage:\n"); - printf(" compel --arch=(x86|ia32|aarch64|arm|ppc64) cflags\n"); - printf(" compel --arch=(x86|ia32|aarch64|arm|ppc64) ldflags\n"); - printf(" compel -f filename hgen\n"); - return 1; + return usage(1); } From b73feb98db066951b1a1e17a27edae4781afa996 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:16 -0800 Subject: [PATCH 0261/4375] compel hgen: option -o is required Without this check, if -o is not given, compel will fail with the following error: Can't open (null) It's non-trivial to figure out that it means -o is required. While at it, initialize the corresponding field. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compel/src/main.c b/compel/src/main.c index 2a2ba3b37..8a2df00ab 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -29,6 +29,7 @@ piegen_opt_t opts = { .input_filename = NULL, + .output_filename = NULL, .uapi_dir = "piegen/uapi", .stream_name = "stream", .prefix_name = "__", @@ -225,6 +226,9 @@ int main(int argc, char *argv[]) if (!opts.input_filename) { return usage(1); } + if (!opts.output_filename) { + return usage(1); + } compel_log_init(&cli_log, log_level); return piegen(); } From 9fa2cda2cd3bebc0e37c57519cd454dcc9f2f2c5 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:17 -0800 Subject: [PATCH 0262/4375] compel: tell user what's wrong with usage In case our command line is not good, it's not enough to just show usage info -- it is much better to explicitly say what's wrong. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compel/src/main.c b/compel/src/main.c index 8a2df00ab..a2e9a56ff 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -163,6 +163,8 @@ int main(int argc, char *argv[]) } } if (!current_cflags) { + fprintf(stderr, "Error: unknown arch '%s'\n", + optarg); return usage(1); } break; @@ -205,12 +207,14 @@ int main(int argc, char *argv[]) } if (optind >= argc) { + fprintf(stderr, "Error: action argument required\n"); return usage(1); } action = argv[optind++]; if (!strcmp(action, "cflags")) { if (!current_cflags) { + fprintf(stderr, "Error: option --arch required\n"); return usage(1); } printf("%s", current_cflags); @@ -224,14 +228,17 @@ int main(int argc, char *argv[]) if (!strcmp(action, "hgen")) { if (!opts.input_filename) { + fprintf(stderr, "Error: option --file required\n"); return usage(1); } if (!opts.output_filename) { + fprintf(stderr, "Error: option --output required\n"); return usage(1); } compel_log_init(&cli_log, log_level); return piegen(); } + fprintf(stderr, "Error: unknown action '%s'\n", action); return usage(1); } From 904b6066f67c49aa75bcf236c84e2bf977a2c531 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:18 -0800 Subject: [PATCH 0263/4375] compel: error out on unknown opt or missing arg getopt_long() prints an error message and returns '?' in cases - an unknown option is given - a required option argument is missing In such cases, we need to show usage and exit with an error. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compel/src/main.c b/compel/src/main.c index a2e9a56ff..7fa4d7c28 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -201,7 +201,9 @@ int main(int argc, char *argv[]) COMPEL_SO_VERSION_SUBLEVEL); exit(0); break; - default: + default: // '?' + // error message already printed by getopt_long() + return usage(1); break; } } From 98fddd50268c9590c11b1da2d1225383c31a716a Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:19 -0800 Subject: [PATCH 0264/4375] compel --help: fix This: $ ./compel/compel-host --help ./compel/compel-host: option '--help' requires an argument Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/src/main.c b/compel/src/main.c index 7fa4d7c28..b7d83bf10 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -143,7 +143,7 @@ int main(int argc, char *argv[]) { "sym-prefix", required_argument, 0, 'p' }, { "variable", required_argument, 0, 'v' }, { "pcrelocs", required_argument, 0, 'r' }, - { "help", required_argument, 0, 'h' }, + { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'V' }, { "log-level", required_argument, 0, 'l' }, { }, From 6b584033c5abaccc86e08b6a215fab2b608a83f3 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:20 -0800 Subject: [PATCH 0265/4375] compel --help: don't hardcode arch list Instead of hardcoding list of architectures to usage(), let's generate it from the data. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 66 ++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index b7d83bf10..6005f9e55 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -27,6 +27,30 @@ #define COMPEL_LDFLAGS_DEFAULT "-r -z noexecstack" +typedef struct { + const char *arch; + const char *cflags; +} compel_cflags_t; + +static const compel_cflags_t compel_cflags[] = { + { + .arch = "x86", + .cflags = COMPEL_CFLAGS_PIE, + }, { + .arch = "ia32", + .cflags = COMPEL_CFLAGS_NOPIC, + }, { + .arch = "aarch64", + .cflags = COMPEL_CFLAGS_PIE, + }, { + .arch = "arm", + .cflags = COMPEL_CFLAGS_PIE, + }, { + .arch = "ppc64", + .cflags = COMPEL_CFLAGS_PIE, + }, +}; + piegen_opt_t opts = { .input_filename = NULL, .output_filename = NULL, @@ -92,10 +116,24 @@ static void cli_log(unsigned int lvl, const char *fmt, va_list parms) } static int usage(int rc) { + int i = 0; printf( "Usage:\n" -" compel --arch=(x86|ia32|aarch64|arm|ppc64) cflags\n" -" compel --arch=(x86|ia32|aarch64|arm|ppc64) ldflags\n" +" compel --arch=ARCH cflags\n" +" compel --arch=ARCH ldflags\n" +" ARCH := { " +); + + /* Print list of known arches */ + while (1) { + printf("%s", compel_cflags[i++].arch); + if (i == ARRAY_SIZE(compel_cflags)) + break; + printf(" | "); + } + + printf( +" }\n" " compel -f filename hgen\n" ); @@ -109,30 +147,6 @@ int main(int argc, char *argv[]) int opt, idx, i; char *action; - typedef struct { - const char *arch; - const char *cflags; - } compel_cflags_t; - - static const compel_cflags_t compel_cflags[] = { - { - .arch = "x86", - .cflags = COMPEL_CFLAGS_PIE, - }, { - .arch = "ia32", - .cflags = COMPEL_CFLAGS_NOPIC, - }, { - .arch = "aarch64", - .cflags = COMPEL_CFLAGS_PIE, - }, { - .arch = "arm", - .cflags = COMPEL_CFLAGS_PIE, - }, { - .arch = "ppc64", - .cflags = COMPEL_CFLAGS_PIE, - }, - }; - static const char short_opts[] = "a:f:o:s:p:v:r:u:hVl:"; static struct option long_opts[] = { { "arch", required_argument, 0, 'a' }, From 66bdd95347ece546956a3a0a3483d37480576e0e Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:21 -0800 Subject: [PATCH 0266/4375] compel --help: describe required parameters TODO: describe optional ones. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compel/src/main.c b/compel/src/main.c index 6005f9e55..e2aabcc60 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -134,7 +134,9 @@ static int usage(int rc) { printf( " }\n" -" compel -f filename hgen\n" +" compel -f FILE -o FILE [...] hgen\n" +" -f, --file FILE input (parasite object) file name\n" +" -o, --output FILE output (header) file name\n" ); return rc; From bd22ff2aa6048987387b0d83b49717c6c9ea59f4 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:22 -0800 Subject: [PATCH 0267/4375] __handle_elf: rm duplicated code Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/lib/handle-elf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index c1318d512..bc1a42d4a 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -577,8 +577,7 @@ int __handle_elf(void *mem, size_t size) } } pr_out("};\n"); - free(sec_hdrs); - return 0; + ret = 0; err: free(sec_hdrs); return ret; From 2d15cd077ef9fb3529b5ec8a3e0e844e0d869cd5 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:23 -0800 Subject: [PATCH 0268/4375] compel handle-elf.c: better align generated output This is purely cosmetical, no functional change. 1. Make sure relocs table is well aligned. 2. printf("%#02x", 1) prints 0x01, but for 0 it prints 0, not 0x00 as one would expect, so output is somewhat ugly. Use "0x%02x" format instead to make it more uniform and well aligned. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/lib/handle-elf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index bc1a42d4a..52aae3f60 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -488,7 +488,7 @@ int __handle_elf(void *mem, size_t size) case R_X86_64_32: /* Symbol + Addend (4 bytes) */ case R_X86_64_32S: /* Symbol + Addend (4 bytes) */ pr_debug("\t\t\t\tR_X86_64_32 at 0x%-4lx val 0x%x\n", place, value32); - pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_INT, " + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_INT, " ".addend = %-8d, .value = 0x%-16x, }, /* R_X86_64_32 */\n", (unsigned int)place, addend32, value32); break; @@ -524,7 +524,7 @@ int __handle_elf(void *mem, size_t size) #ifdef ELF_X86_32 case R_386_32: /* Symbol + Addend */ pr_debug("\t\t\t\tR_386_32 at 0x%-4lx val 0x%x\n", place, value32 + addend32); - pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_INT, " + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_INT, " ".addend = %-4d, .value = 0x%x, },\n", (unsigned int)place, addend32, value32); break; @@ -573,7 +573,7 @@ int __handle_elf(void *mem, size_t size) for (j = 0; j < sh->sh_size; j++, k++) { if (k && (k % 8) == 0) pr_out("\n\t"); - pr_out("%#02x,", shdata[j]); + pr_out("0x%02x,", shdata[j]); } } pr_out("};\n"); From 8ea542f78ecf028f0652164a5a66bba315b4b7a8 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:24 -0800 Subject: [PATCH 0269/4375] compel: simplify usage wrt ids Currently, some compel internals are exposed to user API (both C and CLI), making its usage more complicated than it can be. In particular, compel user have to specify a number of parameters (names for various data) on the command line, and when in C code assign a struc piegen_opt_t fields using the same names, without using those identifiers anywhere else in the code. It makes sense to hide this complexity from a user, which is what this commit does. First, remove the ability to specify individual names for data, instead introducing a prefix that is prepended to all the names. Second, generate a function %PREFIX%_setup_c_header() which does all the needed assignments. Third, convert users (criu/pie and compel test) to the new API. NOTE that this patch breaks ARM, as compel hgen is not used for ARM. This is to be fixed by a later patch in the series. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/piegen.h | 5 +---- compel/src/lib/handle-elf.c | 35 ++++++++++++++++++++++++++++++----- compel/src/main.c | 22 +++------------------- compel/test/infect/Makefile | 5 +---- compel/test/infect/spy.c | 16 +--------------- criu/include/restorer.h | 5 ++--- criu/parasite-syscall.c | 33 ++------------------------------- criu/pie/Makefile | 5 +---- scripts/gen-offsets.sh | 4 ++-- 9 files changed, 43 insertions(+), 87 deletions(-) diff --git a/compel/include/piegen.h b/compel/include/piegen.h index d240cd642..3dd62e62c 100644 --- a/compel/include/piegen.h +++ b/compel/include/piegen.h @@ -12,10 +12,7 @@ typedef struct { char *input_filename; char *output_filename; char *uapi_dir; - char *stream_name; - char *prefix_name; - char *var_name; - char *nrgotpcrel_name; + char *prefix; FILE *fout; } piegen_opt_t; diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index 52aae3f60..e7bfab6af 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -257,15 +257,15 @@ int __handle_elf(void *mem, size_t size) sh_src = sec_hdrs[sym->st_shndx]; ptr_func_exit(sh_src); } - pr_out("#define %s%s 0x%lx\n", - opts.prefix_name, name, + pr_out("#define %s_sym%s 0x%lx\n", + opts.prefix, name, (unsigned long)(sym->st_value + (sh_src ? sh_src->sh_addr : 0))); } } } - pr_out("static __maybe_unused compel_reloc_t %s[] = {\n", opts.var_name); + pr_out("static __maybe_unused compel_reloc_t %s_relocs[] = {\n", opts.prefix); pr_debug("Relocations\n"); pr_debug("------------\n"); @@ -545,9 +545,9 @@ int __handle_elf(void *mem, size_t size) } } pr_out("};\n"); - pr_out("static __maybe_unused size_t %s = %zd;\n", opts.nrgotpcrel_name, nr_gotpcrel); + pr_out("static __maybe_unused size_t %s_nr_gotpcrel = %zd;\n", opts.prefix, nr_gotpcrel); - pr_out("static __maybe_unused const char %s[] = {\n\t", opts.stream_name); + pr_out("static __maybe_unused const char %s_blob[] = {\n\t", opts.prefix); for (i = 0, k = 0; i < hdr->e_shnum; i++) { Elf_Shdr *sh = sec_hdrs[i]; @@ -577,6 +577,31 @@ int __handle_elf(void *mem, size_t size) } } pr_out("};\n"); + pr_out("\n"); + pr_out("static void __maybe_unused %s_setup_c_header(struct parasite_ctl *ctl)\n", + opts.prefix); + pr_out( +"{\n" +" struct parasite_blob_desc *pbd;\n" +"\n" +" pbd = compel_parasite_blob_desc(ctl);\n" +" pbd->parasite_type = COMPEL_BLOB_CHEADER;\n" +); + pr_out("\tpbd->hdr.mem = %s_blob;\n", opts.prefix); + pr_out("\tpbd->hdr.bsize = sizeof(%s_blob);\n", + opts.prefix); + pr_out("\tpbd->hdr.nr_gotpcrel = %s_nr_gotpcrel;\n", opts.prefix); + pr_out("\tpbd->hdr.parasite_ip_off = " + "COMPEL_H_PARASITE_HEAD(%s_sym);\n", opts.prefix); + pr_out("\tpbd->hdr.addr_cmd_off = " + "COMPEL_H_PARASITE_CMD(%s_sym);\n", opts.prefix); + pr_out("\tpbd->hdr.addr_arg_off = " + "COMPEL_H_PARASITE_ARGS(%s_sym);\n", opts.prefix); + pr_out("\tpbd->hdr.relocs = %s_relocs;\n", opts.prefix); + pr_out("\tpbd->hdr.nr_relocs = " + "sizeof(%s_relocs) / sizeof(%s_relocs[0]);\n", + opts.prefix, opts.prefix); + pr_out("}\n"); ret = 0; err: free(sec_hdrs); diff --git a/compel/src/main.c b/compel/src/main.c index e2aabcc60..30920677e 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -55,10 +55,6 @@ piegen_opt_t opts = { .input_filename = NULL, .output_filename = NULL, .uapi_dir = "piegen/uapi", - .stream_name = "stream", - .prefix_name = "__", - .var_name = "elf_relocs", - .nrgotpcrel_name = "nr_gotpcrel", .fout = NULL, }; @@ -149,16 +145,13 @@ int main(int argc, char *argv[]) int opt, idx, i; char *action; - static const char short_opts[] = "a:f:o:s:p:v:r:u:hVl:"; + static const char short_opts[] = "a:f:o:u:p:hVl:"; static struct option long_opts[] = { { "arch", required_argument, 0, 'a' }, { "file", required_argument, 0, 'f' }, { "output", required_argument, 0, 'o' }, - { "stream", required_argument, 0, 's' }, { "uapi-dir", required_argument, 0, 'u' }, - { "sym-prefix", required_argument, 0, 'p' }, - { "variable", required_argument, 0, 'v' }, - { "pcrelocs", required_argument, 0, 'r' }, + { "prefix", required_argument, 0, 'p' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'V' }, { "log-level", required_argument, 0, 'l' }, @@ -193,17 +186,8 @@ int main(int argc, char *argv[]) case 'u': opts.uapi_dir = optarg; break; - case 's': - opts.stream_name = optarg; - break; case 'p': - opts.prefix_name = optarg; - break; - case 'v': - opts.var_name = optarg; - break; - case 'r': - opts.nrgotpcrel_name = optarg; + opts.prefix = optarg; break; case 'l': log_level = atoi(optarg); diff --git a/compel/test/infect/Makefile b/compel/test/infect/Makefile index 2e27a09b1..b9f08206f 100644 --- a/compel/test/infect/Makefile +++ b/compel/test/infect/Makefile @@ -27,10 +27,7 @@ spy: spy.c parasite.h $(COMPEL_LIBRARY) parasite.h: parasite.po $(COMPEL) hgen -f $^ -l 4 \ - -v parasite_relocs \ - -p parasite_sym \ - -s parasite_blob \ - -r parasite_nr_gotpcrel \ + -p parasite \ -u $(COMPEL_IDIR) \ -o $@ diff --git a/compel/test/infect/spy.c b/compel/test/infect/spy.c index 90428b16a..b56b2b71f 100644 --- a/compel/test/infect/spy.c +++ b/compel/test/infect/spy.c @@ -48,21 +48,7 @@ static int do_infection(int pid) ictx = compel_infect_ctx(ctl); ictx->log_fd = STDERR_FILENO; - /* - * Next the blob descriptor. We've requested for hgen - * in Makefile, so prepare this type of blob with the - * values from parasite.h. - */ - pbd = compel_parasite_blob_desc(ctl); - pbd->parasite_type = COMPEL_BLOB_CHEADER; - pbd->hdr.mem = parasite_blob; - pbd->hdr.bsize = sizeof(parasite_blob); - pbd->hdr.nr_gotpcrel = parasite_nr_gotpcrel; - pbd->hdr.parasite_ip_off = COMPEL_H_PARASITE_HEAD(parasite_sym); - pbd->hdr.addr_cmd_off = COMPEL_H_PARASITE_CMD(parasite_sym); - pbd->hdr.addr_arg_off = COMPEL_H_PARASITE_ARGS(parasite_sym); - pbd->hdr.relocs = parasite_relocs; - pbd->hdr.nr_relocs = sizeof(parasite_relocs) / sizeof(parasite_relocs[0]); + parasite_setup_c_header(ctl); printf("Infecting\n"); if (compel_infect(ctl, 1, sizeof(int))) diff --git a/criu/include/restorer.h b/criu/include/restorer.h index c5cb97b45..fb7d89e49 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -225,8 +225,7 @@ enum { }) -/* the restorer_blob_offset__ prefix is added by gen_offsets.sh */ -#define __blob_offset(name) restorer_blob_offset__ ## name -#define restorer_sym(rblob, name) (void*)(rblob + __blob_offset(name)) +#define __r_sym(name) restorer_sym ## name +#define restorer_sym(rblob, name) (void*)(rblob + __r_sym(name)) #endif /* __CR_RESTORER_H__ */ diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 9dd253007..c93881b58 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -532,37 +532,11 @@ static int make_sigframe(void *arg, struct rt_sigframe *sf, struct rt_sigframe * return construct_sigframe(sf, rtsf, bs, (CoreEntry *)arg); } -/* the parasite prefix is added by gen_offsets.sh */ -#define pblob_offset(ptype, symbol) \ - parasite_ ## ptype ## _blob_offset__ ## symbol - -#ifdef CONFIG_PIEGEN -#define init_blob_relocs(bdesc, blob_type) \ - do { \ - bdesc->hdr.relocs = parasite_##blob_type##_relocs; \ - bdesc->hdr.nr_relocs = ARRAY_SIZE(parasite_##blob_type##_relocs); \ - } while (0) -#else -#define init_blob_relocs(bdesc, blob_type) -#endif - -#define init_blob_desc(bdesc, blob_type) do { \ - bdesc->hdr.mem = parasite_##blob_type##_blob; \ - bdesc->hdr.bsize = sizeof(parasite_##blob_type##_blob); \ - bdesc->hdr.nr_gotpcrel = pie_nr_gotpcrel(parasite_##blob_type); \ - /* Setup the rest of a control block */ \ - bdesc->hdr.parasite_ip_off = pblob_offset(blob_type, __export_parasite_head_start);\ - bdesc->hdr.addr_cmd_off = pblob_offset(blob_type, __export_parasite_cmd); \ - bdesc->hdr.addr_arg_off = pblob_offset(blob_type, __export_parasite_args); \ - init_blob_relocs(bdesc, blob_type); \ - } while (0) - struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, struct vm_area_list *vma_area_list) { struct parasite_ctl *ctl; struct infect_ctx *ictx; - struct parasite_blob_desc *pbd; unsigned long p; BUG_ON(item->threads[0].real != pid); @@ -604,14 +578,11 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ictx->log_fd = log_get_fd(); - pbd = compel_parasite_blob_desc(ctl); - pbd->parasite_type = COMPEL_BLOB_CHEADER; - if (compel_mode_native(ctl)) - init_blob_desc(pbd, native); + parasite_native_setup_c_header(ctl); #ifdef CONFIG_COMPAT else - init_blob_desc(pbd, compat); + parasite_compat_setup_c_header(ctl); #endif parasite_ensure_args_size(dump_pages_args_size(vma_area_list)); diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 32b73b1f8..38f166b87 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -126,10 +126,7 @@ $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host $(call msg-gen, $@) $(Q) $(SRC_DIR)/compel/compel-host hgen -f $< \ -l 4 \ - -v $(call target-name,$@)_relocs \ - -p $(call target-name,$@)_blob_offset__ \ - -s $(call target-name,$@)_blob \ - -r $(call target-name,$@)_nr_gotpcrel \ + -p $(call target-name,$@) \ -u $(SRC_DIR)/compel/include/uapi \ -o $@ $(piegen_stdout) diff --git a/scripts/gen-offsets.sh b/scripts/gen-offsets.sh index f5e3df290..16a03942e 100644 --- a/scripts/gen-offsets.sh +++ b/scripts/gen-offsets.sh @@ -13,12 +13,12 @@ CROSS_COMPILE= fi INC_GUARD=__${NAME}_h__ -PREFIX=${NAME}_blob_offset__ +SYM=${NAME}_sym BLOB=${NAME}_blob OBJNAME=${FILE}.built-in.bin.o BINARY=${FILE}.built-in.bin -AWK_CMD='$2 ~ /^[tTA]$/ { print "#define '$PREFIX'" $3 " 0x" $1; }' +AWK_CMD='$2 ~ /^[tTA]$/ { print "#define '$SYM'" $3 " 0x" $1; }' cat << EOF /* Autogenerated by $0, do not edit */ From 4dd92a5bf67728c580554a5937cb9d4e5c90421d Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:25 -0800 Subject: [PATCH 0270/4375] compel: rm COMPEL_H_PARASITE_* macros They are no longer needed. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/handle-elf.h | 8 -------- compel/src/lib/handle-elf.c | 6 +++--- criu/pie/pie-relocs.h | 2 -- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/compel/include/uapi/handle-elf.h b/compel/include/uapi/handle-elf.h index 013e2e43c..ddeecb0d5 100644 --- a/compel/include/uapi/handle-elf.h +++ b/compel/include/uapi/handle-elf.h @@ -12,12 +12,4 @@ typedef struct { long value; } compel_reloc_t; -/* - * Helpers for compel hgen command results. The pref should match - * the -p|--sym-prefix argument value. - */ -#define COMPEL_H_PARASITE_HEAD(pref) pref##__export_parasite_head_start -#define COMPEL_H_PARASITE_CMD(pref) pref##__export_parasite_cmd -#define COMPEL_H_PARASITE_ARGS(pref) pref##__export_parasite_args - #endif diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index e7bfab6af..e3e57c6f3 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -592,11 +592,11 @@ int __handle_elf(void *mem, size_t size) opts.prefix); pr_out("\tpbd->hdr.nr_gotpcrel = %s_nr_gotpcrel;\n", opts.prefix); pr_out("\tpbd->hdr.parasite_ip_off = " - "COMPEL_H_PARASITE_HEAD(%s_sym);\n", opts.prefix); + "%s_sym__export_parasite_head_start;\n", opts.prefix); pr_out("\tpbd->hdr.addr_cmd_off = " - "COMPEL_H_PARASITE_CMD(%s_sym);\n", opts.prefix); + "%s_sym__export_parasite_cmd;\n", opts.prefix); pr_out("\tpbd->hdr.addr_arg_off = " - "COMPEL_H_PARASITE_ARGS(%s_sym);\n", opts.prefix); + "%s_sym__export_parasite_args;\n", opts.prefix); pr_out("\tpbd->hdr.relocs = %s_relocs;\n", opts.prefix); pr_out("\tpbd->hdr.nr_relocs = " "sizeof(%s_relocs) / sizeof(%s_relocs[0]);\n", diff --git a/criu/pie/pie-relocs.h b/criu/pie/pie-relocs.h index a96150a26..442e70d13 100644 --- a/criu/pie/pie-relocs.h +++ b/criu/pie/pie-relocs.h @@ -10,7 +10,6 @@ #define pie_size(__pie_name) (round_up(sizeof(__pie_name##_blob) + \ __pie_name ## _nr_gotpcrel * sizeof(long), page_size())) -#define pie_nr_gotpcrel(__pie_name) (__pie_name ## _nr_gotpcrel) #define ELF_RELOCS_APPLY(__pie_name, __mem, __vbase) \ compel_relocs_apply(__mem, __vbase, sizeof(__pie_name##_blob), \ __pie_name##_relocs, ARRAY_SIZE(__pie_name##_relocs)) @@ -18,7 +17,6 @@ #else #define pie_size(__pie_name) (round_up(sizeof(__pie_name##_blob), page_size())) -#define pie_nr_gotpcrel(__pie_name) (0) #define ELF_RELOCS_APPLY(__pie_name, __mem, __vbase) #endif From 06953ea4db98e04b8bb6c9a9383ffda5d5f059f5 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:26 -0800 Subject: [PATCH 0271/4375] compel handle_elf(): use continue This is just to avoid a level of code block nesting/indentation that can easily be avoided. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/lib/handle-elf.c | 51 +++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index e3e57c6f3..148410022 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -233,35 +233,36 @@ int __handle_elf(void *mem, size_t size) name = &symstrings[sym->st_name]; ptr_func_exit(name); - if (*name) { - pr_debug("\ttype 0x%-2x bind 0x%-2x shndx 0x%-4x value 0x%-2lx name %s\n", - (unsigned)ELF_ST_TYPE(sym->st_info), (unsigned)ELF_ST_BIND(sym->st_info), - (unsigned)sym->st_shndx, (unsigned long)sym->st_value, name); + if (!*name) + continue; + + pr_debug("\ttype 0x%-2x bind 0x%-2x shndx 0x%-4x value 0x%-2lx name %s\n", + (unsigned)ELF_ST_TYPE(sym->st_info), (unsigned)ELF_ST_BIND(sym->st_info), + (unsigned)sym->st_shndx, (unsigned long)sym->st_value, name); #ifdef ELF_PPC64 - if (!sym->st_value && !strncmp(name, ".TOC.", 6)) { - if (!toc_offset) { - pr_err("No TOC pointer\n"); - goto err; - } - sym->st_value = toc_offset; - continue; + if (!sym->st_value && !strncmp(name, ".TOC.", 6)) { + if (!toc_offset) { + pr_err("No TOC pointer\n"); + goto err; } + sym->st_value = toc_offset; + continue; + } #endif - if (strncmp(name, "__export", 8)) - continue; - if ((sym->st_shndx && sym->st_shndx < hdr->e_shnum) || - sym->st_shndx == SHN_ABS) { - if (sym->st_shndx == SHN_ABS) { - sh_src = NULL; - } else { - sh_src = sec_hdrs[sym->st_shndx]; - ptr_func_exit(sh_src); - } - pr_out("#define %s_sym%s 0x%lx\n", - opts.prefix, name, - (unsigned long)(sym->st_value + - (sh_src ? sh_src->sh_addr : 0))); + if (strncmp(name, "__export", 8)) + continue; + if ((sym->st_shndx && sym->st_shndx < hdr->e_shnum) || + sym->st_shndx == SHN_ABS) { + if (sym->st_shndx == SHN_ABS) { + sh_src = NULL; + } else { + sh_src = sec_hdrs[sym->st_shndx]; + ptr_func_exit(sh_src); } + pr_out("#define %s_sym%s 0x%lx\n", + opts.prefix, name, + (unsigned long)(sym->st_value + + (sh_src ? sh_src->sh_addr : 0))); } } From 2a1db9c2c1e022bccc7b1090444c9ce5c95aa365 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:27 -0800 Subject: [PATCH 0272/4375] compel/test/infect/Makefile: don't add .h to sources The way the Makefile is written, parasite.h is added to gcc command line, like this: gcc -o spy spy.c libcompel.a parasite.h Surely this is not what we want, as parasite.h is included to spy.c The fix is to use "order-only prerequisite", as described by https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/test/infect/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/test/infect/Makefile b/compel/test/infect/Makefile index b9f08206f..d5187495e 100644 --- a/compel/test/infect/Makefile +++ b/compel/test/infect/Makefile @@ -22,7 +22,7 @@ clean: victim: victim.c gcc -o $@ $^ -spy: spy.c parasite.h $(COMPEL_LIBRARY) +spy: spy.c $(COMPEL_LIBRARY) | parasite.h gcc -Werror -I$(COMPEL_IDIR) -I$(COMMON_IDIR) -o $@ $^ parasite.h: parasite.po From 7cd6ad5e7ea50933eab6c48e9a071eb834353098 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:28 -0800 Subject: [PATCH 0273/4375] compel hgen: drop -u option This -u option always looked wrong to me, I mean, how the hell a user is supposed to know where the hell those headers are? It took quite a while to figure out what to do with it, but the end result is -- this option is not needed at all and can easily be dropped. For finding paths to includes, there is a -I compiler option, there's no need to specify something to compel. In fact, it should know by itself where its own headers are kept (and emit -I... to cflags if needed), but that's another story which is to be told when we'll decide to pack compel as a standalone tool. For now, just add "#include " and be done. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/piegen.h | 1 - compel/src/lib/handle-elf.c | 2 +- compel/src/main.c | 7 +------ compel/test/infect/Makefile | 1 - criu/pie/Makefile | 1 - 5 files changed, 2 insertions(+), 10 deletions(-) diff --git a/compel/include/piegen.h b/compel/include/piegen.h index 3dd62e62c..fd72f9c22 100644 --- a/compel/include/piegen.h +++ b/compel/include/piegen.h @@ -11,7 +11,6 @@ typedef struct { char *input_filename; char *output_filename; - char *uapi_dir; char *prefix; FILE *fout; } piegen_opt_t; diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index 148410022..b28830195 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -222,7 +222,7 @@ int __handle_elf(void *mem, size_t size) } pr_out("/* Autogenerated from %s */\n", opts.input_filename); - pr_out("#include \"%s/compel.h\"\n", opts.uapi_dir); + pr_out("#include \n"); for (i = 0; i < symtab_hdr->sh_size / symtab_hdr->sh_entsize; i++) { Elf_Sym *sym = &symbols[i]; diff --git a/compel/src/main.c b/compel/src/main.c index 30920677e..b75c04085 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -54,7 +54,6 @@ static const compel_cflags_t compel_cflags[] = { piegen_opt_t opts = { .input_filename = NULL, .output_filename = NULL, - .uapi_dir = "piegen/uapi", .fout = NULL, }; @@ -145,12 +144,11 @@ int main(int argc, char *argv[]) int opt, idx, i; char *action; - static const char short_opts[] = "a:f:o:u:p:hVl:"; + static const char short_opts[] = "a:f:o:p:hVl:"; static struct option long_opts[] = { { "arch", required_argument, 0, 'a' }, { "file", required_argument, 0, 'f' }, { "output", required_argument, 0, 'o' }, - { "uapi-dir", required_argument, 0, 'u' }, { "prefix", required_argument, 0, 'p' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'V' }, @@ -183,9 +181,6 @@ int main(int argc, char *argv[]) case 'o': opts.output_filename = optarg; break; - case 'u': - opts.uapi_dir = optarg; - break; case 'p': opts.prefix = optarg; break; diff --git a/compel/test/infect/Makefile b/compel/test/infect/Makefile index d5187495e..65c17280f 100644 --- a/compel/test/infect/Makefile +++ b/compel/test/infect/Makefile @@ -28,7 +28,6 @@ spy: spy.c $(COMPEL_LIBRARY) | parasite.h parasite.h: parasite.po $(COMPEL) hgen -f $^ -l 4 \ -p parasite \ - -u $(COMPEL_IDIR) \ -o $@ parasite.po: parasite.o $(COMPEL_PLUGINS)/std.built-in.o diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 38f166b87..05c1b08da 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -127,7 +127,6 @@ $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host $(Q) $(SRC_DIR)/compel/compel-host hgen -f $< \ -l 4 \ -p $(call target-name,$@) \ - -u $(SRC_DIR)/compel/include/uapi \ -o $@ $(piegen_stdout) else # !piegen-y From 9d6228630bf20434ed01fc490b839efbe1e80fd1 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:29 -0800 Subject: [PATCH 0274/4375] compel hgen: use for ARM, kill gen-offsets.sh I am not quite sure how that happened, but compel hgen was not used for ARM/ARM64, instead there's a simple version of it, called gen-offsets.sh. The main difference is, shell script doesn't handle ELF relocations, which apparently is not (currently?) needed for ARM. It's bad to maintain two tools for the same functionality, so this patch kills gen-offsets.sh and related stuff, making compel hgen working on ARM. ELF relocations are still not handled, this code is #ifdef-ed out for now and can be fixed to work on ARM later. This patch also kills some macros and defines that seem obsoleted now. For example, compel_relocs_apply() is now called unconditionally, as it handles the trivial case of 0 relocs just fine. Now, I checked that the blob headers generated by compel hgen and gen-offsets.h are similar (i.e. generated blob code and values defined are the same), but haven't done much above that. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 10 --------- Makefile.config | 4 ---- compel/Makefile | 6 ++++++ compel/src/lib/handle-elf.c | 3 ++- criu/cr-restore.c | 4 +++- criu/pie/Makefile | 37 ------------------------------- criu/pie/pie-relocs.h | 12 ----------- scripts/gen-offsets.sh | 43 ------------------------------------- 8 files changed, 11 insertions(+), 108 deletions(-) delete mode 100644 scripts/gen-offsets.sh diff --git a/Makefile b/Makefile index ea76a1246..a8cc9de7e 100644 --- a/Makefile +++ b/Makefile @@ -176,16 +176,6 @@ include/common/asm: include/common/arch/$(ARCH)/asm $(Q) ln -s ./arch/$(ARCH)/asm $@ $(VERSION_HEADER): include/common/asm -# -# piegen tool might be disabled by hands. Don't use it until -# you know what you're doing. -ifneq ($(filter ia32 x86 ppc64,$(ARCH)),) - ifneq ($(PIEGEN),no) - piegen-y := y - export piegen-y - endif -endif - # # Configure variables. export CONFIG_HEADER := criu/include/config.h diff --git a/Makefile.config b/Makefile.config index 6ff42fe3f..ad9953323 100644 --- a/Makefile.config +++ b/Makefile.config @@ -54,10 +54,6 @@ $(call map,gen-feature-test,$(FEATURES_LIST)) ifeq ($$(VDSO),y) $(Q) @echo '#define CONFIG_VDSO' >> $$@ $(Q) @echo '' >> $$@ -endif -ifeq ($$(piegen-y),y) - $(Q) @echo '#define CONFIG_PIEGEN' >> $$@ - $(Q) @echo '' >> $$@ endif $(Q) @echo '#endif /* __CR_CONFIG_H__ */' >> $$@ endef diff --git a/compel/Makefile b/compel/Makefile index 8c580fdf3..65426d812 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -26,6 +26,12 @@ lib-y += src/lib/infect-util.o lib-y += src/lib/infect.o lib-y += src/lib/ptrace.o +# handle_elf() has no support of ELF relocations on ARM (yet?) +ifneq ($(filter arm aarch64,$(ARCH)),) +CFLAGS += -DNO_RELOCS +HOSTCFLAGS += -DNO_RELOCS +endif + ifeq ($(ARCH),x86) obj-y += src/lib/handle-elf-32.o endif diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index b28830195..035cd0dda 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -267,7 +267,7 @@ int __handle_elf(void *mem, size_t size) } pr_out("static __maybe_unused compel_reloc_t %s_relocs[] = {\n", opts.prefix); - +#ifndef NO_RELOCS pr_debug("Relocations\n"); pr_debug("------------\n"); for (i = 0; i < hdr->e_shnum; i++) { @@ -545,6 +545,7 @@ int __handle_elf(void *mem, size_t size) } } } +#endif /* !NO_RELOCS */ pr_out("};\n"); pr_out("static __maybe_unused size_t %s_nr_gotpcrel = %zd;\n", opts.prefix, nr_gotpcrel); diff --git a/criu/cr-restore.c b/criu/cr-restore.c index bbb499339..f2e5c5ea7 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2459,7 +2459,9 @@ static int remap_restorer_blob(void *addr) return -1; } - ELF_RELOCS_APPLY(restorer, addr, addr); + compel_relocs_apply(addr, addr, sizeof(restorer_blob), + restorer_relocs, ARRAY_SIZE(restorer_relocs)); + return 0; } diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 05c1b08da..cb5bcdecf 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -87,8 +87,6 @@ endif asflags-y += -D__ASSEMBLY__ -GEN-OFFSETS := $(obj)/../../scripts/gen-offsets.sh - BLOBS += $(obj)/restorer-blob.h define gen-pields-blobs-var @@ -101,7 +99,6 @@ $(eval $(call map,gen-pields-blobs-var,$(parasite_target))) # for C files, we need "parasite-native" to be "parasite_native" target-name = $(patsubst criu/pie/%_blob.h,%,$(subst -,_,$(1))) -ifeq ($(piegen-y),y) ifeq ($(strip $(V)),) piegen_stdout := >/dev/null endif @@ -129,40 +126,6 @@ $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host -p $(call target-name,$@) \ -o $@ $(piegen_stdout) -else # !piegen-y - -# ld on arm doesn't like -pie and -r options together -ifeq ($(filter arm aarch64,$(ARCH)),) - LD_R := -r -endif - -define gen-rule-built-in.bin.o -$(obj)/$(1).built-in.o: $(compel_std-$(1)) -$(obj)/parasite-$(1).built-in.bin.o: $(obj)/$(1).built-in.o \ - $(compel_pack_lds-$(1)) $(obj)/native.lib.a - $$(call msg-gen, $$@) - $(Q) $(LD) $(LD_R) -T $(compel_pack_lds-$(1)) -o $$@ $$< $(obj)/native.lib.a -endef - -$(eval $(call map,gen-rule-built-in.bin.o,$(parasite_target))) - -$(obj)/restorer.built-in.o: $(compel_std-native) -$(obj)/restorer.built-in.bin.o: $(obj)/restorer.built-in.o \ - $(compel_pack_lds-native) $(obj)/native.lib.a - $(call msg-gen, $@) - $(Q) $(LD) $(LD_R) -T $(compel_pack_lds-native) -o $@ $< $(obj)/native.lib.a - -$(obj)/%.built-in.bin: $(obj)/%.built-in.bin.o - $(call msg-gen, $@) - $(Q) $(OBJCOPY) -O binary $^ $@ - -$(obj)/%-blob.h: $(obj)/%.built-in.bin $(GEN-OFFSETS) - $(call msg-gen, $@) - $(Q) $(SH) $(GEN-OFFSETS) $(@:-blob.h=) $(call target-name,$@) $(CROSS_COMPILE) > $@ - - -endif # !piegen-y - all-y += $(BLOBS) # blobs and pields are in cleanup, rather than in mrproper because # we want them to be re-generated after `make clean && make` diff --git a/criu/pie/pie-relocs.h b/criu/pie/pie-relocs.h index 442e70d13..5a18d8c9d 100644 --- a/criu/pie/pie-relocs.h +++ b/criu/pie/pie-relocs.h @@ -6,19 +6,7 @@ #include "common/compiler.h" #include "config.h" -#ifdef CONFIG_PIEGEN - #define pie_size(__pie_name) (round_up(sizeof(__pie_name##_blob) + \ __pie_name ## _nr_gotpcrel * sizeof(long), page_size())) -#define ELF_RELOCS_APPLY(__pie_name, __mem, __vbase) \ - compel_relocs_apply(__mem, __vbase, sizeof(__pie_name##_blob), \ - __pie_name##_relocs, ARRAY_SIZE(__pie_name##_relocs)) - -#else - -#define pie_size(__pie_name) (round_up(sizeof(__pie_name##_blob), page_size())) -#define ELF_RELOCS_APPLY(__pie_name, __mem, __vbase) - -#endif #endif /* __PIE_RELOCS_H__ */ diff --git a/scripts/gen-offsets.sh b/scripts/gen-offsets.sh deleted file mode 100644 index 16a03942e..000000000 --- a/scripts/gen-offsets.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh - -set -e -set -u - -FILE=$1 -NAME=$2 - -if test $# -ge 3; then -CROSS_COMPILE=$3 -else -CROSS_COMPILE= -fi - -INC_GUARD=__${NAME}_h__ -SYM=${NAME}_sym -BLOB=${NAME}_blob -OBJNAME=${FILE}.built-in.bin.o -BINARY=${FILE}.built-in.bin - -AWK_CMD='$2 ~ /^[tTA]$/ { print "#define '$SYM'" $3 " 0x" $1; }' - -cat << EOF -/* Autogenerated by $0, do not edit */ -#ifndef $INC_GUARD -#define $INC_GUARD - -EOF - -${CROSS_COMPILE}nm $OBJNAME | grep "__export_" | tr . _ | awk "$AWK_CMD" - -cat << EOF - -static char $BLOB[] = { -EOF - -hexdump -v -e '"\t" 8/1 "0x%02x, " "\n"' $BINARY - -cat << EOF -}; - -#endif /* $INC_GUARD */ -EOF From ee07e4252e19743706e56576a38f35a7895af025 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:31 -0800 Subject: [PATCH 0275/4375] compel: print errors to stderr After seeing a bunch of silent build failures, like this: > GEN criu/pie/parasite-native-blob.h > criu/pie/Makefile:121: recipe for target 'criu/pie/parasite-native-blob.h' failed I finally took a look at why are they silent, only to discover that compel prints errors to stdout, and of course its stdout is silenced in criu/pie/Makefile (unless you run make with V=1, in which case it prints tons and tons of very useful information). I am so shocked by this evil plan! Anyway, let's print errors to stderr like all sane programs do. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index b75c04085..a26b2e196 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -106,8 +106,15 @@ err: static void cli_log(unsigned int lvl, const char *fmt, va_list parms) { - if (!pr_quelled(lvl)) - vprintf(fmt, parms); + FILE *f = stdout; + + if (pr_quelled(lvl)) + return; + + if ((lvl == LOG_ERROR) || (lvl == LOG_WARN)) + f = stderr; + + vfprintf(f, fmt, parms); } static int usage(int rc) { From ab7bf8207c0d15e20d1ca0824bd6275d9e275d72 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:32 -0800 Subject: [PATCH 0276/4375] compel hgen: --prefix is required Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compel/src/main.c b/compel/src/main.c index a26b2e196..ce1ee5dbe 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -239,6 +239,10 @@ int main(int argc, char *argv[]) fprintf(stderr, "Error: option --output required\n"); return usage(1); } + if (!opts.prefix) { + fprintf(stderr, "Error: option --prefix required\n"); + return usage(1); + } compel_log_init(&cli_log, log_level); return piegen(); } From 365b29ae3847c264716ba409d8127ffadeb71ad7 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Dec 2016 01:44:33 -0800 Subject: [PATCH 0277/4375] compel --help: complete Now, when many useless options were dropped, it's easy to provide a complete description of CLI in usage(). Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compel/src/main.c b/compel/src/main.c index ce1ee5dbe..8eaf375fd 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -136,9 +136,14 @@ static int usage(int rc) { printf( " }\n" -" compel -f FILE -o FILE [...] hgen\n" +" compel -f FILE -o FILE -p NAME [-l N] hgen\n" " -f, --file FILE input (parasite object) file name\n" " -o, --output FILE output (header) file name\n" +" -p, --prefix NAME prefix for var names\n" +" -l, --log-level NUM log level (default: %d)\n" +" compel -h|--help\n" +" compel -V|--version\n" +, DEFAULT_LOGLEVEL ); return rc; From 8c1d8b74d03bef1b55ef7eb92bd55d1507f9b0a1 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:27 +0300 Subject: [PATCH 0278/4375] x86/asm: move user code selector values to common I'll need them in parasite head and in exit. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/call32.S | 3 --- include/common/arch/x86/asm/linkage.h | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/arch/x86/call32.S b/criu/arch/x86/call32.S index 48d28e2f1..dbed5dec3 100644 --- a/criu/arch/x86/call32.S +++ b/criu/arch/x86/call32.S @@ -18,9 +18,6 @@ #include "common/asm/linkage.h" -#define __USER32_CS 0x23 -#define __USER_CS 0x33 - .text /* diff --git a/include/common/arch/x86/asm/linkage.h b/include/common/arch/x86/asm/linkage.h index 5e0948f07..5eaf450db 100644 --- a/include/common/arch/x86/asm/linkage.h +++ b/include/common/arch/x86/asm/linkage.h @@ -21,4 +21,7 @@ #endif /* __ASSEMBLY__ */ +#define __USER32_CS 0x23 +#define __USER_CS 0x33 + #endif /* __CR_LINKAGE_H__ */ From 1c452384c6de2aba8e378a223e53dddbf163f27e Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:28 +0300 Subject: [PATCH 0279/4375] x86/parasite-head: add 32-bit parasite entry To drop the second parasite blob, create another entry in 64-bit parasite. Didn't remove parasite-head-compat.S - it we gonna support native 32-bit buids, we gonna need it. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/x86/plugins/std/parasite-head.S | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/compel/arch/x86/plugins/std/parasite-head.S b/compel/arch/x86/plugins/std/parasite-head.S index 9622af1ee..2757828cf 100644 --- a/compel/arch/x86/plugins/std/parasite-head.S +++ b/compel/arch/x86/plugins/std/parasite-head.S @@ -6,6 +6,16 @@ # error 64-bit parasite should compile with CONFIG_X86_64 #endif +#ifdef CONFIG_COMPAT +.code32 +ENTRY(__export_parasite_head_start_compat) + /* A long jump to 64-bit parasite. */ + jmp $__USER_CS,$__export_parasite_head_start + int $0x03 +END(__export_parasite_head_start_compat) +.code64 +#endif + ENTRY(__export_parasite_head_start) subq $16, %rsp andq $~15, %rsp @@ -15,7 +25,8 @@ ENTRY(__export_parasite_head_start) leaq __export_parasite_args(%rip), %rsi call parasite_service int $0x03 - .align 8 -__export_parasite_cmd: - .long 0 END(__export_parasite_head_start) + +.align 8 +GLOBAL(__export_parasite_cmd) + .long 0 From 3586421060a359a6f468c844f144f19b2f2cec63 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:29 +0300 Subject: [PATCH 0280/4375] criu/pie/vdso: change CONFIG_{X86_32 => VDSO_32} It's needed for ELF magic, not for platform. Will help to simplify Makefile.library (the very next patch). travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/util-vdso.h | 4 ++-- criu/pie/Makefile.library | 2 +- criu/pie/util-vdso.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/criu/include/util-vdso.h b/criu/include/util-vdso.h index 63bc70d79..f4ee7fef6 100644 --- a/criu/include/util-vdso.h +++ b/criu/include/util-vdso.h @@ -49,7 +49,7 @@ struct vdso_symtable { }, \ } -#ifdef CONFIG_X86_32 +#if defined(CONFIG_X86_32) || defined(CONFIG_VDSO_32) #define Ehdr_t Elf32_Ehdr #define Sym_t Elf32_Sym @@ -88,7 +88,7 @@ static inline unsigned long vvar_vma_size(struct vdso_symtable *t) return t->vvar_end - t->vvar_start; } -#if defined(CONFIG_X86_32) +#if defined(CONFIG_VDSO_32) # define vdso_fill_symtable vdso_fill_symtable_compat #endif diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 19168048b..e8a080abd 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -13,7 +13,7 @@ ifeq ($(ARCH),x86) endif CFLAGS_native += -DCONFIG_X86_64 CFLAGS_compat += -fno-pic -m32 -DCONFIG_X86_32 - CFLAGS_util-vdso-elf32.o += -DCONFIG_X86_32 + CFLAGS_util-vdso-elf32.o += -DCONFIG_VDSO_32 OBJS += ./$(ARCH_DIR)/memcpy.o endif diff --git a/criu/pie/util-vdso.c b/criu/pie/util-vdso.c index b55739a9e..1aab3e52a 100644 --- a/criu/pie/util-vdso.c +++ b/criu/pie/util-vdso.c @@ -74,7 +74,7 @@ static int has_elf_identity(Ehdr_t *ehdr) /* * See Elf specification for this magic values. */ -#if defined(CONFIG_X86_32) +#if defined(CONFIG_VDSO_32) static const char elf_ident[] = { 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, From 44641325eb3b3ec1d7bae38a45643ddc166d2346 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:30 +0300 Subject: [PATCH 0281/4375] criu/pie: rename native.lib.a into pie.lib.a As we have only one pie lib - no need to name it {native,compat}. The next patch cleans Makefile. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/Makefile | 6 +++--- criu/pie/Makefile | 8 ++++---- criu/pie/Makefile.library | 16 ++++++++-------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/criu/Makefile b/criu/Makefile index c88fe0918..160f1e9dc 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -42,12 +42,12 @@ $(ARCH-LIB): # # PIE library code. -criu/pie/native.lib.a: $(ARCH-LIB) +criu/pie/pie.lib.a: $(ARCH-LIB) $(Q) $(MAKE) $(call build-as,Makefile.library,criu/pie) all # # PIE code blobs themseves. -pie: criu/pie/native.lib.a compel/plugins/std.built-in.o +pie: criu/pie/pie.lib.a compel/plugins/std.built-in.o $(Q) $(MAKE) $(build)=criu/pie all .PHONY: pie @@ -56,7 +56,7 @@ criu/pie/%: pie # # CRIU executable -PROGRAM-BUILTINS += criu/pie/native.lib.a +PROGRAM-BUILTINS += criu/pie/pie.lib.a PROGRAM-BUILTINS += images/built-in.o PROGRAM-BUILTINS += $(obj)/built-in.o PROGRAM-BUILTINS += $(ARCH-LIB) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index cb5bcdecf..de6cf6436 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -105,17 +105,17 @@ endif $(obj)/restorer.built-in.o: $(compel_std-native) $(obj)/restorer.built-in.bin.o: $(obj)/restorer.built-in.o \ - $(obj)/native.lib.a $(compel_pack_lds-native) + $(obj)/pie.lib.a $(compel_pack_lds-native) $(call msg-gen, $@) - $(Q) $(LD) -r -T $(compel_pack_lds-native) -o $@ $< $(obj)/native.lib.a + $(Q) $(LD) -r -T $(compel_pack_lds-native) -o $@ $< $(obj)/pie.lib.a # $1 - binary mode: native/compat define gen-rule-built-in.bin.o $(obj)/$(1).built-in.o: $(compel_std-$(1)) $(obj)/parasite-$(1).built-in.bin.o: $(obj)/$(1).built-in.o \ - $(obj)/$(1).lib.a $(compel_pack_lds-$(1)) + $(obj)/pie.lib.a $(compel_pack_lds-$(1)) $$(call msg-gen, $$@) - $(Q) $(LD) -r -T $(compel_pack_lds-$(1)) -o $$@ $$< $(obj)/$(1).lib.a + $(Q) $(LD) -r -T $(compel_pack_lds-$(1)) -o $$@ $$< $(obj)/pie.lib.a endef $(eval $(call map,gen-rule-built-in.bin.o,$(parasite_target))) diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index e8a080abd..8b931463b 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -1,17 +1,17 @@ -target := native +target := pie CFLAGS := $(filter-out -DCONFIG_X86_64,$(CFLAGS)) CFLAGS += -fno-stack-protector -DCR_NOGLIBC LDFLAGS += -z noexecstack -CFLAGS_native += -fpie +CFLAGS_pie += -fpie ifeq ($(ARCH),x86) ifeq ($(CONFIG_COMPAT),y) target += compat - native-lib-y += util-vdso-elf32.o + pie-lib-y += util-vdso-elf32.o endif - CFLAGS_native += -DCONFIG_X86_64 + CFLAGS_pie += -DCONFIG_X86_64 CFLAGS_compat += -fno-pic -m32 -DCONFIG_X86_32 CFLAGS_util-vdso-elf32.o += -DCONFIG_VDSO_32 OBJS += ./$(ARCH_DIR)/memcpy.o @@ -36,9 +36,9 @@ ifeq ($(SRCARCH),ppc64) ./$(ARCH_DIR)/memcmp_64.o ./$(ARCH_DIR)/misc.o endif -define gen-native-objs -native-lib-y += $(1) -CFLAGS_$(1) := $(CFLAGS_native) +define gen-pie-objs +pie-lib-y += $(1) +CFLAGS_$(1) := $(CFLAGS_pie) endef compat-obj = $(basename $(notdir $(1)))-compat.o @@ -47,7 +47,7 @@ compat-lib-y += $(dir ./$(call objectify,$(1)))compat/$(compat-obj) CFLAGS_$(compat-obj) := $(CFLAGS_compat) endef -$(eval $(call map,gen-native-objs,$(OBJS))) +$(eval $(call map,gen-pie-objs,$(OBJS))) $(eval $(call map,gen-compat-objs,$(OBJS))) # From 82382beabf1b1c5dd1e1db9bfe7c913c08d9d55c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:31 +0300 Subject: [PATCH 0282/4375] pie.lib: drop second compat lib No need in two libraries if we have only one parasite blob. With left hand I write code - with right I erase it. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/Makefile.library | 47 ++++++++++++--------------------------- 1 file changed, 14 insertions(+), 33 deletions(-) diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 8b931463b..91b742c41 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -1,54 +1,35 @@ -target := pie +lib-name := pie.lib.a -CFLAGS := $(filter-out -DCONFIG_X86_64,$(CFLAGS)) -CFLAGS += -fno-stack-protector -DCR_NOGLIBC +CFLAGS += -fno-stack-protector -DCR_NOGLIBC -fpie LDFLAGS += -z noexecstack -CFLAGS_pie += -fpie - -ifeq ($(ARCH),x86) - ifeq ($(CONFIG_COMPAT),y) - target += compat - pie-lib-y += util-vdso-elf32.o - endif - CFLAGS_pie += -DCONFIG_X86_64 - CFLAGS_compat += -fno-pic -m32 -DCONFIG_X86_32 - CFLAGS_util-vdso-elf32.o += -DCONFIG_VDSO_32 - OBJS += ./$(ARCH_DIR)/memcpy.o -endif - -OBJS += util-fd.o util.o string.o +lib-y += util-fd.o util.o string.o ifeq ($(VDSO),y) - OBJS += util-vdso.o parasite-vdso.o ./$(ARCH_DIR)/vdso-pie.o + lib-y += util-vdso.o parasite-vdso.o ./$(ARCH_DIR)/vdso-pie.o ifeq ($(SRCARCH),aarch64) - OBJS += ./$(ARCH_DIR)/intraprocedure.o + lib-y += ./$(ARCH_DIR)/intraprocedure.o endif ifeq ($(SRCARCH),ppc64) - OBJS += ./$(ARCH_DIR)/vdso-trampoline.o + lib-y += ./$(ARCH_DIR)/vdso-trampoline.o endif endif ifeq ($(SRCARCH),ppc64) - OBJS += ./$(ARCH_DIR)/memcpy_power7.o \ + lib-y += ./$(ARCH_DIR)/memcpy_power7.o \ ./$(ARCH_DIR)/memcmp_64.o ./$(ARCH_DIR)/misc.o endif -define gen-pie-objs -pie-lib-y += $(1) -CFLAGS_$(1) := $(CFLAGS_pie) -endef +ifeq ($(SRCARCH),x86) + ifeq ($(CONFIG_COMPAT),y) + lib-y += util-vdso-elf32.o + endif + CFLAGS_util-vdso-elf32.o += -DCONFIG_VDSO_32 -compat-obj = $(basename $(notdir $(1)))-compat.o -define gen-compat-objs -compat-lib-y += $(dir ./$(call objectify,$(1)))compat/$(compat-obj) -CFLAGS_$(compat-obj) := $(CFLAGS_compat) -endef - -$(eval $(call map,gen-pie-objs,$(OBJS))) -$(eval $(call map,gen-compat-objs,$(OBJS))) + lib-y += ./$(ARCH_DIR)/memcpy.o +endif # # We can't provide proper mount implementation From a3e31595a49b6e4e826d61d6dee89d3f2d898650 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:32 +0300 Subject: [PATCH 0283/4375] criu/pie: drop second compat parasite Let's try having one with two entries/exits. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .gitignore | 2 +- criu/parasite-syscall.c | 7 +-- criu/pie/Makefile | 115 ++++++++++----------------------------- criu/pie/parasite-blob.h | 5 -- 4 files changed, 31 insertions(+), 98 deletions(-) delete mode 100644 criu/pie/parasite-blob.h diff --git a/.gitignore b/.gitignore index 48ea4fb13..c3f82939d 100644 --- a/.gitignore +++ b/.gitignore @@ -34,7 +34,7 @@ criu/include/syscall*.h soccr/config.h criu/include/version.h criu/pie/restorer-blob.h -criu/pie/parasite-*-blob.h +criu/pie/parasite-blob.h criu/pie/pie.lds*.S criu/protobuf-desc-gen.h lib/build/ diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index c93881b58..690713066 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -578,12 +578,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ictx->log_fd = log_get_fd(); - if (compel_mode_native(ctl)) - parasite_native_setup_c_header(ctl); -#ifdef CONFIG_COMPAT - else - parasite_compat_setup_c_header(ctl); -#endif + parasite_setup_c_header(ctl); parasite_ensure_args_size(dump_pages_args_size(vma_area_list)); parasite_ensure_args_size(aio_rings_args_size(vma_area_list)); diff --git a/criu/pie/Makefile b/criu/pie/Makefile index de6cf6436..e05bb0bbc 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -1,123 +1,66 @@ -# native/compat target names are _only_ for parasite -# restorer is always native (64-bit) -parasite_target := native +target += parasite restorer -ifeq ($(CONFIG_COMPAT),y) - parasite_target += compat -endif +compel_lds := $(SRC_DIR)/compel/arch/$(ARCH)/scripts/compel-pack.lds.S +compel_std := $(SRC_DIR)/compel/plugins/std.built-in.o +parasite-obj-e += ./compel/plugins/std.built-in.o +restorer-obj-e += ./compel/plugins/std.built-in.o -compel_pack_lds-native := $(SRC_DIR)/compel/arch/$(ARCH)/scripts/compel-pack.lds.S -compel_pack_lds-compat := $(SRC_DIR)/compel/arch/$(ARCH)/scripts/compel-pack-compat.lds.S -compel_std-native := $(SRC_DIR)/compel/plugins/std.built-in.o -compel_std-compat := $(SRC_DIR)/compel/plugins/std-compat.built-in.o - -native-obj-y += parasite.o -compat-obj-y += compat/parasite-compat.o - -restorer-obj-y += restorer.o -restorer-obj-y += ./$(ARCH_DIR)/restorer.o +parasite-obj-y += parasite.o +restorer-obj-y += restorer.o +restorer-obj-y += ./$(ARCH_DIR)/restorer.o ifeq ($(ARCH),x86) - restorer-obj-e += ./compel/plugins/std.built-in.o - ifeq ($(CONFIG_COMPAT),y) restorer-obj-y += ./$(ARCH_DIR)/call32.o restorer-obj-y += ./$(ARCH_DIR)/sigaction_compat_pie.o endif - - native-obj-e += ./compel/plugins/std.built-in.o - compat-obj-e += ./compel/plugins/std-compat.built-in.o -else - native-obj-e += ./compel/plugins/std.built-in.o - restorer-obj-e += ./compel/plugins/std.built-in.o endif -target += $(parasite_target) restorer - # # We can't provide proper mount implementation # in parasite code -- it requires run-time rellocation # applications, which is not the target of the # project. # -CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) -CFLAGS := $(filter-out -DCONFIG_X86_64,$(CFLAGS)) -CFLAGS += -iquote $(SRC_DIR)/criu/arch/$(ARCH)/include -CFLAGS += -iquote $(SRC_DIR)/criu/include -CFLAGS += -iquote $(SRC_DIR)/include -CFLAGS += -iquote $(SRC_DIR) -CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 +CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) +CFLAGS += -iquote $(SRC_DIR)/criu/arch/$(ARCH)/include +CFLAGS += -iquote $(SRC_DIR)/criu/include +CFLAGS += -iquote $(SRC_DIR)/include +CFLAGS += -iquote $(SRC_DIR) +CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 +CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 + +ccflags-y += -I compel/include/uapi +ccflags-y += -I compel/plugins/include/uapi +ccflags-y += -DCR_NOGLIBC +ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 +ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 -ccflags-y += -I compel/include/uapi -ccflags-y += -I compel/plugins/include/uapi -ccflags-y += -DCR_NOGLIBC -ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) -NATIVE_CFLAGS := $(shell $(SRC_DIR)/compel/compel-host --arch=$(ARCH) cflags) -ifeq ($(ARCH),x86) - COMPAT_CFLAGS := $(shell $(SRC_DIR)/compel/compel-host --arch=ia32 cflags) + CFLAGS += $(shell $(SRC_DIR)/compel/compel-host --arch=$(ARCH) cflags) endif -endif - -ifeq ($(ARCH),x86) - NATIVE_CFLAGS += -DCONFIG_X86_64 - COMPAT_CFLAGS += -m32 -DCONFIG_X86_32 - COMPAT_LDFLAGS += -m elf_i386 -endif - -CFLAGS_restorer.o += $(NATIVE_CFLAGS) -# $1 - object name -define obj-export-native-flags - CFLAGS_$(notdir $(1)) := $(NATIVE_CFLAGS) -endef -# $1 - object name -define obj-export-compat-flags - CFLAGS_$(notdir $(1)) := $(COMPAT_CFLAGS) - LDFLAGS_$(notdir $(1)) := $(COMPAT_LDFLAGS) -endef - -$(eval $(call map,obj-export-native-flags,$(restorer-obj-y))) -$(eval $(call map,obj-export-native-flags,$(native-obj-y) native)) -$(eval $(call map,obj-export-compat-flags,$(compat-obj-y) compat)) ifeq ($(SRCARCH),arm) ccflags-y += -marm endif -asflags-y += -D__ASSEMBLY__ +asflags-y += -D__ASSEMBLY__ -BLOBS += $(obj)/restorer-blob.h - -define gen-pields-blobs-var -BLOBS += $(obj)/parasite-$(1)-blob.h -endef -$(eval $(call map,gen-pields-blobs-var,$(parasite_target))) +BLOBS += $(obj)/restorer-blob.h $(obj)/parasite-blob.h .SECONDARY: -# for C files, we need "parasite-native" to be "parasite_native" -target-name = $(patsubst criu/pie/%_blob.h,%,$(subst -,_,$(1))) +target-name = $(patsubst criu/pie/%-blob.h,%,$(1)) ifeq ($(strip $(V)),) piegen_stdout := >/dev/null endif -$(obj)/restorer.built-in.o: $(compel_std-native) -$(obj)/restorer.built-in.bin.o: $(obj)/restorer.built-in.o \ - $(obj)/pie.lib.a $(compel_pack_lds-native) +$(obj)/restorer.built-in.o: $(compel_std) +$(obj)/parasite.built-in.o: $(compel_std) +$(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/pie.lib.a $(compel_lds) $(call msg-gen, $@) - $(Q) $(LD) -r -T $(compel_pack_lds-native) -o $@ $< $(obj)/pie.lib.a - -# $1 - binary mode: native/compat -define gen-rule-built-in.bin.o -$(obj)/$(1).built-in.o: $(compel_std-$(1)) -$(obj)/parasite-$(1).built-in.bin.o: $(obj)/$(1).built-in.o \ - $(obj)/pie.lib.a $(compel_pack_lds-$(1)) - $$(call msg-gen, $$@) - $(Q) $(LD) -r -T $(compel_pack_lds-$(1)) -o $$@ $$< $(obj)/pie.lib.a -endef -$(eval $(call map,gen-rule-built-in.bin.o,$(parasite_target))) + $(Q) $(LD) -r -T $(compel_lds) -o $@ $< $(obj)/pie.lib.a $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host $(call msg-gen, $@) diff --git a/criu/pie/parasite-blob.h b/criu/pie/parasite-blob.h deleted file mode 100644 index ddafd05f5..000000000 --- a/criu/pie/parasite-blob.h +++ /dev/null @@ -1,5 +0,0 @@ -#include "parasite-native-blob.h" - -#ifdef CONFIG_COMPAT -# include "parasite-compat-blob.h" -#endif From cb0a7ba3fd0cbfa6bf599a41ff881d4880861f04 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:33 +0300 Subject: [PATCH 0284/4375] page-pipe/page-xfer: remove PP_COMPAT (compatible iovs) Parasite transfers pages in the same iovec format now: drop compatible format (yay!). travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/page-pipe.h | 7 ------ criu/mem.c | 2 -- criu/page-pipe.c | 49 ++++++++-------------------------------- criu/page-xfer.c | 20 ++-------------- 4 files changed, 12 insertions(+), 66 deletions(-) diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h index 38c38968f..b8fdfdeb7 100644 --- a/criu/include/page-pipe.h +++ b/criu/include/page-pipe.h @@ -116,15 +116,8 @@ struct page_pipe { #define PP_CHUNK_MODE 0x1 /* Restrict the maximum buffer size of pipes and dump memory for a few iterations */ -#define PP_COMPAT 0x2 /* Use compatible iovs (struct compat_iovec) */ #define PP_OWN_IOVS 0x4 /* create_page_pipe allocated IOVs memory */ -/* XXX: move to arch-depended file, when non-x86 add support for compat mode */ -struct iovec_compat { - u32 iov_base; - u32 iov_len; -}; - struct page_pipe *create_page_pipe(unsigned int nr_segs, struct iovec *iovs, unsigned flags); extern void destroy_page_pipe(struct page_pipe *p); extern int page_pipe_add_page(struct page_pipe *p, unsigned long addr); diff --git a/criu/mem.c b/criu/mem.c index 26c370ac9..1c993b2fc 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -305,8 +305,6 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, * use, i.e. on non-lazy non-predump. */ cpp_flags |= PP_CHUNK_MODE; - if (!compel_mode_native(ctl)) - cpp_flags |= PP_COMPAT; pp = create_page_pipe(vma_area_list->priv_size, pargs_iovs(args), cpp_flags); if (!pp) diff --git a/criu/page-pipe.c b/criu/page-pipe.c index bdf72fb24..c80f73236 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -81,15 +81,10 @@ static int ppb_resize_pipe(struct page_pipe_buf *ppb, unsigned long new_size) return 0; } -static inline void iov_init_compat(struct iovec_compat *iov, unsigned long addr) -{ - iov->iov_base = (u32)addr; - iov->iov_len = PAGE_SIZE; -} - static int page_pipe_grow(struct page_pipe *pp) { struct page_pipe_buf *ppb; + struct iovec *free_iov; pr_debug("Will grow page pipe (iov off is %u)\n", pp->free_iov); @@ -107,7 +102,8 @@ static int page_pipe_grow(struct page_pipe *pp) return -1; out: - ppb_init(ppb, 0, 0, &pp->iovs[pp->free_iov]); + free_iov = &pp->iovs[pp->free_iov]; + ppb_init(ppb, 0, 0, free_iov); return 0; } @@ -214,13 +210,7 @@ static inline int try_add_page_to(struct page_pipe *pp, struct page_pipe_buf *pp pr_debug("Add iov to page pipe (%u iovs, %u/%u total)\n", ppb->nr_segs, pp->free_iov, pp->nr_iovs); - if (pp->flags & PP_COMPAT) { - struct iovec_compat *iovs = (void *)ppb->iov; - - iov_init_compat(&iovs[ppb->nr_segs++], addr); - } else { - iov_init(&ppb->iov[ppb->nr_segs++], addr); - } + iov_init(&ppb->iov[ppb->nr_segs++], addr); pp->free_iov++; BUG_ON(pp->free_iov > pp->nr_iovs); out: @@ -268,13 +258,8 @@ int page_pipe_add_hole(struct page_pipe *pp, unsigned long addr) iov_grow_page(&pp->holes[pp->free_hole - 1], addr)) goto out; - if (pp->flags & PP_COMPAT) { - struct iovec_compat *iovs = (void *)pp->holes; + iov_init(&pp->holes[pp->free_hole++], addr); - iov_init_compat(&iovs[pp->free_hole++], addr); - } else { - iov_init(&pp->holes[pp->free_hole++], addr); - } out: return 0; } @@ -284,7 +269,6 @@ void debug_show_page_pipe(struct page_pipe *pp) struct page_pipe_buf *ppb; int i; struct iovec *iov; - struct iovec_compat *iov_c; if (pr_quelled(LOG_DEBUG)) return; @@ -296,28 +280,15 @@ void debug_show_page_pipe(struct page_pipe *pp) pr_debug("\tbuf %u pages, %u iovs:\n", ppb->pages_in, ppb->nr_segs); for (i = 0; i < ppb->nr_segs; i++) { - if (pp->flags & PP_COMPAT) { - iov_c = (void *)ppb->iov; - pr_debug("\t\t%x %lu\n", iov_c[i].iov_base, - (unsigned long) iov_c[i].iov_len / PAGE_SIZE); - } else { - iov = &ppb->iov[i]; - pr_debug("\t\t%p %lu\n", iov->iov_base, - (unsigned long) iov->iov_len / PAGE_SIZE); - } + iov = &ppb->iov[i]; + pr_debug("\t\t%p %lu\n", iov->iov_base, + iov->iov_len / PAGE_SIZE); } } pr_debug("* %u holes:\n", pp->free_hole); for (i = 0; i < pp->free_hole; i++) { - if (pp->flags & PP_COMPAT) { - iov_c = (void *)pp->holes; - pr_debug("\t%x %lu\n", iov_c[i].iov_base, - (unsigned long) iov_c[i].iov_len / PAGE_SIZE); - } else { - iov = &pp->holes[i]; - pr_debug("\t%p %lu\n", iov->iov_base, - (unsigned long) iov->iov_len / PAGE_SIZE); - } + iov = &pp->holes[i]; + pr_debug("\t%p %lu\n", iov->iov_base, iov->iov_len / PAGE_SIZE); } } diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 8ec0998a4..71aee0d6b 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -341,29 +341,13 @@ static int page_xfer_dump_hole(struct page_xfer *xfer, return 0; } -static struct iovec get_iov(struct iovec *iovs, unsigned int n, bool compat) -{ - if (likely(!compat)) { - return iovs[n]; - } else { - struct iovec ret; - struct iovec_compat *tmp = (struct iovec_compat*)(void *)iovs; - - tmp += n; - ret.iov_base = (void *)(uintptr_t)tmp->iov_base; - ret.iov_len = tmp->iov_len; - return ret; - } -} - static int dump_holes(struct page_xfer *xfer, struct page_pipe *pp, unsigned int *cur_hole, void *limit, unsigned long off) { int ret; for (; *cur_hole < pp->free_hole ; (*cur_hole)++) { - struct iovec hole = get_iov(pp->holes, *cur_hole, - pp->flags & PP_COMPAT); + struct iovec hole = pp->holes[*cur_hole]; if (limit && hole.iov_base >= limit) break; @@ -391,7 +375,7 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, pr_debug("\tbuf %d/%d\n", ppb->pages_in, ppb->nr_segs); for (i = 0; i < ppb->nr_segs; i++) { - struct iovec iov = get_iov(ppb->iov, i, pp->flags & PP_COMPAT); + struct iovec iov = ppb->iov[i]; ret = dump_holes(xfer, pp, &cur_hole, iov.iov_base, off); if (ret) From 69070b13f614c216b74cdb10dc1c9a185b3594bf Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:34 +0300 Subject: [PATCH 0285/4375] criu/compat: remove serialization of parasite's answers Oh, thanks god - those silly crippy macro are gone! The best part of removing second parasite, I think. This is partial revert to commit 8c3b3bc2efa0 ("parasite-syscall: deserialize compat parasite's answers"). travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 35 +++----- criu/include/parasite-syscall.h | 4 +- criu/parasite-syscall.c | 151 +++++++++----------------------- 3 files changed, 53 insertions(+), 137 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index afb5a51b8..588e37f4d 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -667,7 +667,8 @@ static int dump_task_ids(struct pstree_item *item, const struct cr_imgset *cr_im return pb_write_one(img_from_set(cr_imgset, CR_FD_IDS), item->ids, PB_IDS); } -int dump_thread_core(int pid, CoreEntry *core, bool native, const void *dump_thread) +int dump_thread_core(int pid, CoreEntry *core, const struct parasite_dump_thread *ti) + { int ret; ThreadCoreEntry *tc = core->thread_core; @@ -678,30 +679,14 @@ int dump_thread_core(int pid, CoreEntry *core, bool native, const void *dump_thr if (!ret) ret = dump_sched_info(pid, tc); if (!ret) { - if (native) { - const struct parasite_dump_thread *ti = dump_thread; - - core_put_tls(core, ti->tls); - CORE_THREAD_ARCH_INFO(core)->clear_tid_addr = - encode_pointer(ti->tid_addr); - BUG_ON(!tc->sas); - copy_sas(tc->sas, &ti->sas); - if (ti->pdeath_sig) { - tc->has_pdeath_sig = true; - tc->pdeath_sig = ti->pdeath_sig; - } - } else { - const struct parasite_dump_thread_compat *ti = dump_thread; - - core_put_tls(core, (tls_t)ti->tls); - CORE_THREAD_ARCH_INFO(core)->clear_tid_addr = - encode_pointer((void*)(uintptr_t)ti->tid_addr); - BUG_ON(!tc->sas); - copy_sas_compat(tc->sas, &ti->sas); - if (ti->pdeath_sig) { - tc->has_pdeath_sig = true; - tc->pdeath_sig = ti->pdeath_sig; - } + core_put_tls(core, ti->tls); + CORE_THREAD_ARCH_INFO(core)->clear_tid_addr = + encode_pointer(ti->tid_addr); + BUG_ON(!tc->sas); + copy_sas(tc->sas, &ti->sas); + if (ti->pdeath_sig) { + tc->has_pdeath_sig = true; + tc->pdeath_sig = ti->pdeath_sig; } } diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 88318916b..3887446d6 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -34,8 +34,8 @@ extern int parasite_dump_creds(struct parasite_ctl *ctl, struct _CredsEntry *ce) extern int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, struct _CoreEntry *core); extern int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, struct pid *tid, struct _CoreEntry *core); -extern int dump_thread_core(int pid, CoreEntry *core, bool native, - const void *dump_thread); +extern int dump_thread_core(int pid, CoreEntry *core, + const struct parasite_dump_thread *dt); extern int parasite_drain_fds_seized(struct parasite_ctl *ctl, struct parasite_drain_fd *dfds, int nr_fds, int off, diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 690713066..a7a26adf4 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -141,19 +141,13 @@ static int alloc_groups_copy_creds(CredsEntry *ce, struct parasite_dump_creds *c int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEntry *core) { ThreadCoreEntry *tc = core->thread_core; - struct parasite_dump_thread *args = NULL; - struct parasite_dump_thread_compat *args_c = NULL; + struct parasite_dump_thread *args; struct parasite_dump_creds *pc; int ret; - if (compel_mode_native(ctl)) { - args = compel_parasite_args(ctl, struct parasite_dump_thread); - pc = args->creds; - } else { - args_c = compel_parasite_args(ctl, struct parasite_dump_thread_compat); - pc = args_c->creds; - } + args = compel_parasite_args(ctl, struct parasite_dump_thread); + pc = args->creds; pc->cap_last_cap = kdat.last_cap; ret = compel_rpc_call_sync(PARASITE_CMD_DUMP_THREAD, ctl); @@ -166,17 +160,13 @@ int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEn return -1; } - if (compel_mode_native(ctl)) - return dump_thread_core(pid, core, true, args); - else - return dump_thread_core(pid, core, false, args_c); + return dump_thread_core(pid, core, args); } int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, struct pid *tid, CoreEntry *core) { - struct parasite_dump_thread *args = NULL; - struct parasite_dump_thread_compat *args_c = NULL; + struct parasite_dump_thread *args; pid_t pid = tid->real; ThreadCoreEntry *tc = core->thread_core; CredsEntry *creds = tc->creds; @@ -186,14 +176,9 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, BUG_ON(id == 0); /* Leader is dumped in dump_task_core_all */ - if (compel_mode_native(ctl)) { - args = compel_parasite_args(ctl, struct parasite_dump_thread); - pc = args->creds; - } else { - args_c = compel_parasite_args(ctl, struct parasite_dump_thread_compat); - pc = args_c->creds; - } + args = compel_parasite_args(ctl, struct parasite_dump_thread); + pc = args->creds; pc->cap_last_cap = kdat.last_cap; tctl = compel_prepare_thread(ctl, pid); @@ -223,42 +208,22 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, compel_release_thread(tctl); - if (compel_mode_native(ctl)) { - tid->ns[0].virt = args->tid; - return dump_thread_core(pid, core, true, args); - } else { - tid->ns[0].virt = args_c->tid; - return dump_thread_core(pid, core, false, args_c); - } + tid->ns[0].virt = args->tid; + return dump_thread_core(pid, core, args); err_rth: compel_release_thread(tctl); return -1; } -#define ASSIGN_SAS(se, args) \ -do { \ - ASSIGN_TYPED(se.sigaction, encode_pointer( \ - (void*)(uintptr_t)args->sas[i].rt_sa_handler)); \ - ASSIGN_TYPED(se.flags, args->sas[i].rt_sa_flags); \ - ASSIGN_TYPED(se.restorer, encode_pointer( \ - (void*)(uintptr_t)args->sas[i].rt_sa_restorer));\ - BUILD_BUG_ON(sizeof(se.mask) != sizeof(args->sas[0].rt_sa_mask.sig)); \ - memcpy(&se.mask, args->sas[i].rt_sa_mask.sig, sizeof(se.mask)); \ -} while(0) int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_imgset) { - struct parasite_dump_sa_args *args = NULL; - struct parasite_dump_sa_args_compat *args_c = NULL; + struct parasite_dump_sa_args *args; int ret, sig; struct cr_img *img; SaEntry se = SA_ENTRY__INIT; - bool native_task = compel_mode_native(ctl); - if (native_task) - args = compel_parasite_args(ctl, struct parasite_dump_sa_args); - else - args_c = compel_parasite_args(ctl, struct parasite_dump_sa_args_compat); + args = compel_parasite_args(ctl, struct parasite_dump_sa_args); ret = compel_rpc_call_sync(PARASITE_CMD_DUMP_SIGACTS, ctl); if (ret < 0) @@ -272,12 +237,13 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_ if (sig == SIGSTOP || sig == SIGKILL) continue; - if (native_task) - ASSIGN_SAS(se, args); - else - ASSIGN_SAS(se, args_c); + ASSIGN_TYPED(se.sigaction, encode_pointer(args->sas[i].rt_sa_handler)); + ASSIGN_TYPED(se.flags, args->sas[i].rt_sa_flags); + ASSIGN_TYPED(se.restorer, encode_pointer(args->sas[i].rt_sa_restorer)); + BUILD_BUG_ON(sizeof(se.mask) != sizeof(args->sas[0].rt_sa_mask.sig)); + memcpy(&se.mask, args->sas[i].rt_sa_mask.sig, sizeof(se.mask)); se.has_compat_sigaction = true; - se.compat_sigaction = !native_task; + se.compat_sigaction = !compel_mode_native(ctl); if (pb_write_one(img, &se, PB_SIGACT) < 0) return -1; @@ -286,40 +252,29 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_ return 0; } -#define encode_itimer(v, ie) \ -do { \ - ie->isec = v->it_interval.tv_sec; \ - ie->iusec = v->it_interval.tv_usec; \ - ie->vsec = v->it_value.tv_sec; \ - ie->vusec = v->it_value.tv_usec; \ -} while(0) \ +static void encode_itimer(struct itimerval *v, ItimerEntry *ie) +{ + ie->isec = v->it_interval.tv_sec; + ie->iusec = v->it_interval.tv_usec; + ie->vsec = v->it_value.tv_sec; + ie->vusec = v->it_value.tv_usec; +} -#define ASSIGN_ITIMER(args) \ -do { \ - encode_itimer((&args->real), (core->tc->timers->real)); \ - encode_itimer((&args->virt), (core->tc->timers->virt)); \ - encode_itimer((&args->prof), (core->tc->timers->prof)); \ -} while(0) int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct pstree_item *item) { CoreEntry *core = item->core[0]; - struct parasite_dump_itimers_args *args = NULL; - struct parasite_dump_itimers_args_compat *args_c = NULL; + struct parasite_dump_itimers_args *args; int ret; - if (compel_mode_native(ctl)) - args = compel_parasite_args(ctl, struct parasite_dump_itimers_args); - else - args_c = compel_parasite_args(ctl, struct parasite_dump_itimers_args_compat); + args = compel_parasite_args(ctl, struct parasite_dump_itimers_args); ret = compel_rpc_call_sync(PARASITE_CMD_DUMP_ITIMERS, ctl); if (ret < 0) return ret; - if (compel_mode_native(ctl)) - ASSIGN_ITIMER(args); - else - ASSIGN_ITIMER(args_c); + encode_itimer((&args->real), (core->tc->timers->real)); \ + encode_itimer((&args->virt), (core->tc->timers->virt)); \ + encode_itimer((&args->prof), (core->tc->timers->prof)); \ return 0; } @@ -343,28 +298,8 @@ static int core_alloc_posix_timers(TaskTimersEntry *tte, int n, return 0; } -#define set_posix_timer_arg(args, ctl, m, val) \ -do { \ - if (compel_mode_native(ctl)) \ - ASSIGN_TYPED( \ - ((struct parasite_dump_posix_timers_args*)args)->m, val); \ - else \ - ASSIGN_TYPED( \ - ((struct parasite_dump_posix_timers_args_compat*)args)->m, val);\ -} while (0) - -#define get_posix_timer_arg(out, m) \ -do { \ - if (compel_mode_native(ctl)) \ - ASSIGN_TYPED( \ - out, ((struct parasite_dump_posix_timers_args*)args)->m); \ - else \ - ASSIGN_TYPED( \ - out, ((struct parasite_dump_posix_timers_args_compat*)args)->m);\ -} while (0) - -static void encode_posix_timer(void *args, struct parasite_ctl *ctl, - struct proc_posix_timer *vp, PosixTimerEntry *pte, int i) +static void encode_posix_timer(struct posix_timer *v, + struct proc_posix_timer *vp, PosixTimerEntry *pte) { pte->it_id = vp->spt.it_id; pte->clock_id = vp->spt.clock_id; @@ -372,12 +307,12 @@ static void encode_posix_timer(void *args, struct parasite_ctl *ctl, pte->it_sigev_notify = vp->spt.it_sigev_notify; pte->sival_ptr = encode_pointer(vp->spt.sival_ptr); - get_posix_timer_arg(pte->overrun, timer[i].overrun); + pte->overrun = v->overrun; - get_posix_timer_arg(pte->isec, timer[i].val.it_interval.tv_sec); - get_posix_timer_arg(pte->insec, timer[i].val.it_interval.tv_nsec); - get_posix_timer_arg(pte->vsec, timer[i].val.it_value.tv_sec); - get_posix_timer_arg(pte->vnsec, timer[i].val.it_value.tv_nsec); + pte->isec = v->val.it_interval.tv_sec; + pte->insec = v->val.it_interval.tv_nsec; + pte->vsec = v->val.it_value.tv_sec; + pte->vnsec = v->val.it_value.tv_nsec; } int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, @@ -387,7 +322,7 @@ int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, TaskTimersEntry *tte = core->tc->timers; PosixTimerEntry *pte; struct proc_posix_timer *temp; - void *args = NULL; + struct parasite_dump_posix_timers_args *args; int args_size; int ret = 0; int i; @@ -395,17 +330,13 @@ int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, if (core_alloc_posix_timers(tte, proc_args->timer_n, &pte)) return -1; - if (compel_mode_native(ctl)) - args_size = posix_timers_dump_size(proc_args->timer_n); - else - args_size = posix_timers_compat_dump_size(proc_args->timer_n); + args_size = posix_timers_dump_size(proc_args->timer_n); args = compel_parasite_args_s(ctl, args_size); - - set_posix_timer_arg(args, ctl, timer_n, proc_args->timer_n); + args->timer_n = proc_args->timer_n; i = 0; list_for_each_entry(temp, &proc_args->timers, list) { - set_posix_timer_arg(args, ctl, timer[i].it_id, temp->spt.it_id); + args->timer[i].it_id = temp->spt.it_id; i++; } @@ -416,7 +347,7 @@ int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, i = 0; list_for_each_entry(temp, &proc_args->timers, list) { posix_timer_entry__init(&pte[i]); - encode_posix_timer(args, ctl, temp, &pte[i], i); + encode_posix_timer(&args->timer[i], temp, &pte[i]); tte->posix[i] = &pte[i]; i++; } From 3cd00d04ba9cf73047616c9c9a54c0f498f100b1 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:36 +0300 Subject: [PATCH 0286/4375] compat: check arch_prctl() return code for ARCH_MAP_VDSO_32 On first versions of x86 compat patches it returned 0 or err. In merged version it returns error < 0 or vDSO blob's size. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/parasite-vdso.h | 2 +- criu/pie/parasite-vdso.c | 16 +++++++++++----- criu/pie/restorer.c | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index 025396319..85db6e826 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -80,7 +80,7 @@ static inline bool is_vdso_mark(void *addr) } extern int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned long park_size); -extern int vdso_map_compat(unsigned long map_at, unsigned long park_size, +extern int vdso_map_compat(unsigned long map_at, unsigned long *park_size, struct vdso_symtable *sym_rt); extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, size_t index, diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 601c37f68..a05645f87 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -75,7 +75,7 @@ int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned l extern int vdso_fill_symtable_compat(uintptr_t mem, size_t size, struct vdso_symtable *t); -int vdso_map_compat(unsigned long map_at, unsigned long park_size, +int vdso_map_compat(unsigned long map_at, unsigned long *park_size, struct vdso_symtable *sym_rt) { unsigned long search_vdso; @@ -84,18 +84,22 @@ int vdso_map_compat(unsigned long map_at, unsigned long park_size, pr_debug("Mapping compatible vDSO at %lx\n", map_at); ret = sys_arch_prctl(ARCH_MAP_VDSO_32, map_at); - if (ret) + if (ret < 0) return ret; + *park_size = (unsigned long)ret; /* * We could map VVAR firstly, or VDSO. * Try to find VDSO pages in this couple of parking pages. + * XXX: Please, FIXME - compat vdso/vvar sizes should be counted + * at CRIU start time by parsing /proc/<...>/maps then by searching + * ELF magic. */ - for (search_vdso = map_at; search_vdso < map_at + park_size; + for (search_vdso = map_at; search_vdso < map_at + *park_size; search_vdso += PAGE_SIZE) { ret = vdso_fill_symtable_compat(search_vdso, - map_at + park_size - search_vdso, sym_rt); + map_at + *park_size - search_vdso, sym_rt); if (!ret) return 0; } @@ -113,9 +117,11 @@ int __vdso_fill_symtable(uintptr_t mem, size_t size, } #else int vdso_map_compat(unsigned long __always_unused map_at, - unsigned long __always_unused park_size, + unsigned long __always_unused *park_size, struct vdso_symtable __always_unused *sym_rt) { + /* shouldn't be called on !CONFIG_COMPAT */ + BUG(); return 0; } int __vdso_fill_symtable(uintptr_t mem, size_t size, diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 6dbe01ece..44ce8671c 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1125,7 +1125,7 @@ long __export_restore_task(struct task_restore_args *args) if (args->compatible_mode) { /* Map compatible vdso */ if (vdso_map_compat(args->vdso_rt_parked_at, - vdso_rt_size, &args->vdso_sym_rt)) + &vdso_rt_size, &args->vdso_sym_rt)) goto core_restore_end; } From f7b966b4ae4142c32355552d6b7763dc1d1f76d6 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:37 +0300 Subject: [PATCH 0287/4375] vdso: separate vdso_parse_maps() from vdso_fill_self_symtable() We need to know compatible vdso/vvar sizes, so add pid argument to parse another process - it's needed to fork(), remap vdso and parse child's vdso/vvar in CRIU. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/vdso.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index dbbf84e09..47f0ff498 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -222,15 +222,15 @@ err: return exit_code; } -static int vdso_fill_self_symtable(struct vdso_symtable *s) +static int vdso_parse_maps(pid_t pid, struct vdso_symtable *s) { + int exit_code = -1; char buf[512]; - int ret, exit_code = -1; FILE *maps; *s = (struct vdso_symtable)VDSO_SYMTABLE_INIT; - maps = fopen_proc(PROC_SELF, "maps"); + maps = fopen_proc(pid, "maps"); if (!maps) return -1; @@ -247,8 +247,7 @@ static int vdso_fill_self_symtable(struct vdso_symtable *s) if (!has_vdso && !has_vvar) continue; - ret = sscanf(buf, "%lx-%lx", &start, &end); - if (ret != 2) { + if (sscanf(buf, "%lx-%lx", &start, &end) != 2) { pr_err("Can't find vDSO/VVAR bounds\n"); goto err; } @@ -260,10 +259,6 @@ static int vdso_fill_self_symtable(struct vdso_symtable *s) } s->vma_start = start; s->vma_end = end; - - ret = vdso_fill_symtable(start, end - start, s); - if (ret) - goto err; } else { if (s->vvar_start != VVAR_BAD_ADDR) { pr_err("Got second VVAR entry\n"); @@ -274,6 +269,21 @@ static int vdso_fill_self_symtable(struct vdso_symtable *s) } } + exit_code = 0; +err: + fclose(maps); + return exit_code; +} + +static int vdso_fill_self_symtable(struct vdso_symtable *s) +{ + + if (vdso_parse_maps(PROC_SELF, s)) + return -1; + + if (vdso_fill_symtable(s->vma_start, s->vma_end - s->vma_start, s)) + return -1; + /* * Validate its structure -- for new vDSO format the * structure must be like @@ -292,22 +302,19 @@ static int vdso_fill_self_symtable(struct vdso_symtable *s) if (s->vma_end != s->vvar_start && s->vvar_end != s->vma_start) { pr_err("Unexpected rt vDSO area bounds\n"); - goto err; + return -1; } } } else { pr_err("Can't find rt vDSO\n"); - goto err; + return -1; } pr_debug("rt [vdso] %lx-%lx [vvar] %lx-%lx\n", s->vma_start, s->vma_end, s->vvar_start, s->vvar_end); - exit_code = 0; -err: - fclose(maps); - return exit_code; + return 0; } int vdso_init(void) From 598aceb643987dc84b55e6b60587dc6e811fb659 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:38 +0300 Subject: [PATCH 0288/4375] vdso: separate validation from vdso_fill_self_symtable() I'll need to validate compat vdso/vvar positioning in the same way. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/vdso.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index 47f0ff498..232c2045e 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -275,15 +275,8 @@ err: return exit_code; } -static int vdso_fill_self_symtable(struct vdso_symtable *s) +static int validate_vdso_addr(struct vdso_symtable *s) { - - if (vdso_parse_maps(PROC_SELF, s)) - return -1; - - if (vdso_fill_symtable(s->vma_start, s->vma_end - s->vma_start, s)) - return -1; - /* * Validate its structure -- for new vDSO format the * structure must be like @@ -310,6 +303,21 @@ static int vdso_fill_self_symtable(struct vdso_symtable *s) return -1; } + return 0; +} + +static int vdso_fill_self_symtable(struct vdso_symtable *s) +{ + + if (vdso_parse_maps(PROC_SELF, s)) + return -1; + + if (vdso_fill_symtable(s->vma_start, s->vma_end - s->vma_start, s)) + return -1; + + if (validate_vdso_addr(s)) + return -1; + pr_debug("rt [vdso] %lx-%lx [vvar] %lx-%lx\n", s->vma_start, s->vma_end, s->vvar_start, s->vvar_end); From 001b9033b0303d6e96f3a14e340106f769347c12 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:39 +0300 Subject: [PATCH 0289/4375] vdso: fill compat symtab in CRIU The next patch will remove filling in restorer rt symtable for compat tasks. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/Makefile.crtools | 2 ++ criu/include/util-vdso.h | 7 ++++ criu/pie-util-vdso-elf32.c | 1 + criu/pie/parasite-vdso.c | 6 ---- criu/vdso.c | 66 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 6 deletions(-) create mode 120000 criu/pie-util-vdso-elf32.c diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index dabb1baa8..791205960 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -84,6 +84,8 @@ obj-y += fdstore.o ifeq ($(VDSO),y) obj-y += pie-util-vdso.o obj-y += vdso.o +obj-y += pie-util-vdso-elf32.o +CFLAGS_pie-util-vdso-elf32.o += -DCONFIG_VDSO_32 endif PROTOBUF_GEN := $(SRC_DIR)/scripts/protobuf-gen.sh diff --git a/criu/include/util-vdso.h b/criu/include/util-vdso.h index f4ee7fef6..642cee737 100644 --- a/criu/include/util-vdso.h +++ b/criu/include/util-vdso.h @@ -93,5 +93,12 @@ static inline unsigned long vvar_vma_size(struct vdso_symtable *t) #endif extern int vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t); +#if defined(CONFIG_X86_64) && defined(CONFIG_COMPAT) +#ifndef ARCH_MAP_VDSO_32 +# define ARCH_MAP_VDSO_32 0x2002 +#endif +extern int vdso_fill_symtable_compat(uintptr_t mem, size_t size, + struct vdso_symtable *t); +#endif #endif /* __CR_UTIL_VDSO_H__ */ diff --git a/criu/pie-util-vdso-elf32.c b/criu/pie-util-vdso-elf32.c new file mode 120000 index 000000000..961bb1d37 --- /dev/null +++ b/criu/pie-util-vdso-elf32.c @@ -0,0 +1 @@ +pie/util-vdso-elf32.c \ No newline at end of file diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index a05645f87..a88018da0 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -69,12 +69,6 @@ int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned l } #if defined(CONFIG_X86_64) && defined(CONFIG_COMPAT) -#ifndef ARCH_MAP_VDSO_32 -# define ARCH_MAP_VDSO_32 0x2002 -#endif -extern int vdso_fill_symtable_compat(uintptr_t mem, size_t size, - struct vdso_symtable *t); - int vdso_map_compat(unsigned long map_at, unsigned long *park_size, struct vdso_symtable *sym_rt) { diff --git a/criu/vdso.c b/criu/vdso.c index 232c2045e..014d48c28 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "types.h" #include "parasite-syscall.h" @@ -20,6 +21,7 @@ #include "mem.h" #include "vma.h" #include +#include #ifdef LOG_PREFIX # undef LOG_PREFIX @@ -28,6 +30,7 @@ struct vdso_symtable vdso_sym_rt = VDSO_SYMTABLE_INIT; u64 vdso_pfn = VDSO_BAD_PFN; +struct vdso_symtable vdso_compat_rt = VDSO_SYMTABLE_INIT; /* * The VMAs list might have proxy vdso/vvar areas left * from previous dump/restore cycle so we need to detect @@ -325,10 +328,73 @@ static int vdso_fill_self_symtable(struct vdso_symtable *s) return 0; } +static int vdso_fill_compat_symtable(struct vdso_symtable *native, + struct vdso_symtable *compat) +{ +#ifdef CONFIG_COMPAT + pid_t pid; + int status, ret = -1; + + pid = fork(); + if (pid == 0) { + size_t vma_size = native->vma_end - native->vma_start; + + if (syscall(__NR_munmap, native->vma_start, vma_size)) + syscall(__NR_exit, 1); + vma_size = native->vvar_end - native->vvar_start; + if (syscall(__NR_munmap, native->vvar_start, vma_size)) + syscall(__NR_exit, 2); + + if (syscall(__NR_arch_prctl, ARCH_MAP_VDSO_32, native->vma_start) < 0) + syscall(__NR_exit, 3); + + syscall(__NR_kill, syscall(__NR_getpid), SIGSTOP); + /* this helper should be killed at this point */ + BUG(); + } + + waitpid(pid, &status, WUNTRACED); + + if (WIFEXITED(status)) { + pr_err("Compat vdso helper exited with %d\n", + WEXITSTATUS(status)); + goto out_kill; + } + + if (!WIFSTOPPED(status)) { + pr_err("Compat vdso helper isn't stopped\n"); + goto out_kill; + } + + if (vdso_parse_maps(pid, compat)) + goto out_kill; + + if (vdso_fill_symtable_compat(compat->vma_start, + compat->vma_end - compat->vma_start, compat)) + goto out_kill; + + if (validate_vdso_addr(compat)) + goto out_kill; + + pr_debug("compat [vdso] %lx-%lx [vvar] %lx-%lx\n", + compat->vma_start, compat->vma_end, + compat->vvar_start, compat->vvar_end); + ret = 0; + +out_kill: + kill(pid, SIGKILL); + return ret; +#else + return 0; +#endif +} + int vdso_init(void) { if (vdso_fill_self_symtable(&vdso_sym_rt)) return -1; + if (vdso_fill_compat_symtable(&vdso_sym_rt, &vdso_compat_rt)) + return -1; if (kdat.pmap != PM_FULL) pr_info("VDSO detection turned off\n"); From b6eb6f16f866db0c801e0000169c3e1bccca3696 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:40 +0300 Subject: [PATCH 0290/4375] vdso/compat: parse compat vdso at vdso_init() Adds a helper to parse compatible vdso blob at time of vdso_init(). The following patches will remove parsing vdso in restorer. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/vdso.c | 146 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 122 insertions(+), 24 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index 014d48c28..af4431f40 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -328,31 +328,74 @@ static int vdso_fill_self_symtable(struct vdso_symtable *s) return 0; } -static int vdso_fill_compat_symtable(struct vdso_symtable *native, - struct vdso_symtable *compat) -{ #ifdef CONFIG_COMPAT +/* + * The helper runs under fork() - it remaps vdso/vvar blobs to compatible. + * After that it copies them into shared with parent mmaped vma so that + * parent could parse compat vdso's symbols and blob sizes into vdso_compat_rt. + * All system calls should be as light as possible after unmapping vdso. + * If we call something clever through Glibc here - the child will blow up. + */ +static void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd, + void *vdso_buf, size_t buf_size) +{ + size_t vma_size; + void *vdso_addr; + long vdso_size; + + vma_size = native->vma_end - native->vma_start; + if (syscall(__NR_munmap, native->vma_start, vma_size)) + syscall(__NR_exit, 2); + + vma_size = native->vvar_end - native->vvar_start; + if (syscall(__NR_munmap, native->vvar_start, vma_size)) + syscall(__NR_exit, 3); + + vdso_size = syscall(__NR_arch_prctl, + ARCH_MAP_VDSO_32, native->vma_start); + if (vdso_size < 0) + syscall(__NR_exit, 4); + if (vdso_size > buf_size) + syscall(__NR_exit, 5); + + syscall(__NR_kill, syscall(__NR_getpid), SIGSTOP); + + if (syscall(__NR_read, pipe_fd, &vdso_addr, sizeof(void *)) != sizeof(void *)) + syscall(__NR_exit, 6); + + memcpy(vdso_buf, vdso_addr, vdso_size); + + syscall(__NR_exit, 0); +} + +static int vdso_mmap_compat(struct vdso_symtable *native, + struct vdso_symtable *compat, void *vdso_buf, size_t buf_size) +{ pid_t pid; int status, ret = -1; + int fds[2]; + + if (pipe(fds)) { + pr_perror("Failed to open pipe"); + return -1; + } pid = fork(); if (pid == 0) { - size_t vma_size = native->vma_end - native->vma_start; - - if (syscall(__NR_munmap, native->vma_start, vma_size)) + if (close(fds[1])) { + pr_perror("Failed to close pipe"); syscall(__NR_exit, 1); - vma_size = native->vvar_end - native->vvar_start; - if (syscall(__NR_munmap, native->vvar_start, vma_size)) - syscall(__NR_exit, 2); + } - if (syscall(__NR_arch_prctl, ARCH_MAP_VDSO_32, native->vma_start) < 0) - syscall(__NR_exit, 3); + compat_vdso_helper(native, fds[0], vdso_buf, buf_size); - syscall(__NR_kill, syscall(__NR_getpid), SIGSTOP); - /* this helper should be killed at this point */ BUG(); } + if (close(fds[0])) { + pr_perror("Failed to close pipe"); + goto out_kill; + } waitpid(pid, &status, WUNTRACED); if (WIFEXITED(status)) { @@ -369,32 +412,87 @@ static int vdso_fill_compat_symtable(struct vdso_symtable *native, if (vdso_parse_maps(pid, compat)) goto out_kill; - if (vdso_fill_symtable_compat(compat->vma_start, - compat->vma_end - compat->vma_start, compat)) - goto out_kill; - if (validate_vdso_addr(compat)) goto out_kill; + if (kill(pid, SIGCONT)) { + pr_perror("Failed to kill(SIGCONT) for compat vdso helper\n"); + goto out_kill; + } + if (write(fds[1], &compat->vma_start, sizeof(void *)) != + sizeof(compat->vma_start)) { + pr_perror("Failed write to pipe\n"); + goto out_kill; + } + waitpid(pid, &status, WUNTRACED); + + if (!WIFEXITED(status) || WEXITSTATUS(status)) + pr_err("Compat vdso helper failed\n"); + else + ret = 0; + +out_kill: + kill(pid, SIGKILL); + if (close(fds[1])) + pr_perror("Failed to close pipe"); + return ret; +} + +#define COMPAT_VDSO_BUF_SZ (PAGE_SIZE*2) +static int vdso_fill_compat_symtable(struct vdso_symtable *native, + struct vdso_symtable *compat) +{ + void *vdso_mmap; + int ret = -1; + + vdso_mmap = mmap(NULL, COMPAT_VDSO_BUF_SZ, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANON, -1, 0); + if (vdso_mmap == MAP_FAILED) { + pr_perror("Failed to mmap buf for compat vdso"); + return -1; + } + + if (vdso_mmap_compat(native, compat, vdso_mmap, COMPAT_VDSO_BUF_SZ)) { + pr_err("Failed to mmap compatible vdso with helper process\n"); + goto out_unmap; + } + + if (vdso_fill_symtable_compat((uintptr_t)vdso_mmap, + compat->vma_end - compat->vma_start, compat)) { + pr_err("Failed to parse mmaped compatible vdso blob\n"); + goto out_unmap; + } + pr_debug("compat [vdso] %lx-%lx [vvar] %lx-%lx\n", compat->vma_start, compat->vma_end, compat->vvar_start, compat->vvar_end); ret = 0; -out_kill: - kill(pid, SIGKILL); +out_unmap: + if (munmap(vdso_mmap, COMPAT_VDSO_BUF_SZ)) + pr_perror("Failed to unmap buf for compat vdso"); return ret; -#else - return 0; -#endif } +#else +static int vdso_fill_compat_symtable(struct vdso_symtable *native, + struct vdso_symtable *compat) +{ + return 0; +} +#endif + int vdso_init(void) { - if (vdso_fill_self_symtable(&vdso_sym_rt)) + if (vdso_fill_self_symtable(&vdso_sym_rt)) { + pr_err("Failed to fill self vdso symtable\n"); return -1; - if (vdso_fill_compat_symtable(&vdso_sym_rt, &vdso_compat_rt)) + } + if (kdat.has_compat_sigreturn && + vdso_fill_compat_symtable(&vdso_sym_rt, &vdso_compat_rt)) { + pr_err("Failed to fill compat vdso symtable\n"); return -1; + } if (kdat.pmap != PM_FULL) pr_info("VDSO detection turned off\n"); From 3755e414ec6a3b93a471f81a36b951ddb124c9dc Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:41 +0300 Subject: [PATCH 0291/4375] restorer/vdso: use compat vdso symtab in restorer No need to fill symtab at restorer - previous commit add vdso filling at startup: on vdso_init(). Now it's possible just to use the symtab and sizes if we need them. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 13 +++++++++---- criu/include/parasite-vdso.h | 5 ++--- criu/include/vdso.h | 1 + criu/pie/parasite-vdso.c | 28 +++------------------------- criu/pie/restorer.c | 9 +++------ 5 files changed, 18 insertions(+), 38 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index f2e5c5ea7..e4334c4e8 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2892,6 +2892,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns struct restore_mem_zone *mz; #ifdef CONFIG_VDSO + struct vdso_symtable vdso_symtab_rt; unsigned long vdso_rt_size = 0; #endif @@ -2936,12 +2937,16 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns current->nr_threads, KBYTES(task_args->bootstrap_len)); #ifdef CONFIG_VDSO + if (core_is_compat(core)) + vdso_symtab_rt = vdso_compat_rt; + else + vdso_symtab_rt = vdso_sym_rt; /* * Figure out how much memory runtime vdso and vvar will need. */ - vdso_rt_size = vdso_vma_size(&vdso_sym_rt); - if (vdso_rt_size && vvar_vma_size(&vdso_sym_rt)) - vdso_rt_size += ALIGN(vvar_vma_size(&vdso_sym_rt), PAGE_SIZE); + vdso_rt_size = vdso_vma_size(&vdso_symtab_rt); + if (vdso_rt_size && vvar_vma_size(&vdso_symtab_rt)) + vdso_rt_size += ALIGN(vvar_vma_size(&vdso_symtab_rt), PAGE_SIZE); task_args->bootstrap_len += vdso_rt_size; #endif @@ -3163,7 +3168,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns */ mem += rst_mem_size; task_args->vdso_rt_parked_at = (unsigned long)mem; - task_args->vdso_sym_rt = vdso_sym_rt; + task_args->vdso_sym_rt = vdso_symtab_rt; task_args->vdso_rt_size = vdso_rt_size; #endif diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index 85db6e826..efb282a60 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -80,15 +80,14 @@ static inline bool is_vdso_mark(void *addr) } extern int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned long park_size); -extern int vdso_map_compat(unsigned long map_at, unsigned long *park_size, - struct vdso_symtable *sym_rt); +extern int vdso_map_compat(unsigned long map_at); extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, size_t index, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso); #else /* CONFIG_VDSO */ #define vdso_do_park(sym_rt, park_at, park_size) (0) -#define vdso_map_compat(map_at, park_size, sym_rt) (0) +#define vdso_map_compat(map_at) (0) #endif /* CONFIG_VDSO */ diff --git a/criu/include/vdso.h b/criu/include/vdso.h index ea6bfabbf..9b6010c03 100644 --- a/criu/include/vdso.h +++ b/criu/include/vdso.h @@ -11,6 +11,7 @@ #include "util-vdso.h" extern struct vdso_symtable vdso_sym_rt; +extern struct vdso_symtable vdso_compat_rt; extern int vdso_init(void); diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index a88018da0..cb1fdd3f2 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -69,10 +69,8 @@ int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned l } #if defined(CONFIG_X86_64) && defined(CONFIG_COMPAT) -int vdso_map_compat(unsigned long map_at, unsigned long *park_size, - struct vdso_symtable *sym_rt) +int vdso_map_compat(unsigned long map_at) { - unsigned long search_vdso; int ret; pr_debug("Mapping compatible vDSO at %lx\n", map_at); @@ -80,25 +78,7 @@ int vdso_map_compat(unsigned long map_at, unsigned long *park_size, ret = sys_arch_prctl(ARCH_MAP_VDSO_32, map_at); if (ret < 0) return ret; - *park_size = (unsigned long)ret; - - /* - * We could map VVAR firstly, or VDSO. - * Try to find VDSO pages in this couple of parking pages. - * XXX: Please, FIXME - compat vdso/vvar sizes should be counted - * at CRIU start time by parsing /proc/<...>/maps then by searching - * ELF magic. - */ - for (search_vdso = map_at; search_vdso < map_at + *park_size; - search_vdso += PAGE_SIZE) - { - ret = vdso_fill_symtable_compat(search_vdso, - map_at + *park_size - search_vdso, sym_rt); - if (!ret) - return 0; - } - pr_err("Failed to parse a arch_prctl-mapped vDSO %d\n", ret); - return ret; + return 0; } int __vdso_fill_symtable(uintptr_t mem, size_t size, @@ -110,9 +90,7 @@ int __vdso_fill_symtable(uintptr_t mem, size_t size, return vdso_fill_symtable(mem, size, t); } #else -int vdso_map_compat(unsigned long __always_unused map_at, - unsigned long __always_unused *park_size, - struct vdso_symtable __always_unused *sym_rt) +int vdso_map_compat(unsigned long __always_unused map_at) { /* shouldn't be called on !CONFIG_COMPAT */ BUG(); diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 44ce8671c..54a216b14 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1122,12 +1122,9 @@ long __export_restore_task(struct task_restore_args *args) bootstrap_start, bootstrap_len, args->task_size)) goto core_restore_end; - if (args->compatible_mode) { - /* Map compatible vdso */ - if (vdso_map_compat(args->vdso_rt_parked_at, - &vdso_rt_size, &args->vdso_sym_rt)) - goto core_restore_end; - } + /* Map compatible vdso */ + if (args->compatible_mode && vdso_map_compat(args->vdso_rt_parked_at)) + goto core_restore_end; /* Shift private vma-s to the left */ for (i = 0; i < args->vmas_n; i++) { From b7c4ca512f7ae473a33254a535a4eae35da0e8f1 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:43 +0300 Subject: [PATCH 0292/4375] vdso: do not try to fill symtable for compat tasks in parasite Parasite is 64-bit and if we want to check if vma is vDSO, we need to link parasite blob with util-vdso-elf32. But luckely, there is no need to do that: mremap() for compat vDSO works only after v4.8 kernel: commit b059a453b1cf ("x86/vdso: Add mremap hook to vm_special_mapping"). And in those kernels "[vdso]" is always reported in /proc/.../maps rightly - so no need to check that. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/vdso.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index af4431f40..d7066b189 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -104,12 +104,8 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, */ args->start = vma->e->start; args->len = vma_area_len(vma); - /* - * XXX: For compatible tasks, vDSO pfn is different from - * our native vdso_pfn. Check vma explicitly. - */ if (!compel_mode_native(ctl)) - args->try_fill_symtable = true; + args->try_fill_symtable = false; else args->try_fill_symtable = (fd < 0) ? true : false; args->is_vdso = false; @@ -172,7 +168,12 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, vma->e->status |= VMA_AREA_VDSO; } } else { - if (unlikely(vma_area_is(vma, VMA_AREA_VDSO))) { + /* + * Compat vDSO mremap support is only after v4.8, + * [vdso] vma name always stays after mremap. + */ + if (unlikely(vma_area_is(vma, VMA_AREA_VDSO)) && + compel_mode_native(ctl)) { pr_debug("Drop mishinted vDSO status at %lx\n", (long)vma->e->start); vma->e->status &= ~VMA_AREA_VDSO; From fa2e8f76be90e24082c7b3f93a7db013f89620cb Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:44 +0300 Subject: [PATCH 0293/4375] x86/restorer/tls: simplify restoring of TLS We can live here without 32-bit CS - this syscall doesn't depend on descriptor type. No functional changes expected, cleanup. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/restorer.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index 050241cca..9cc76fe17 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -33,22 +33,18 @@ int restore_nonsigframe_gpregs(UserX86RegsEntry *r) } #ifdef CONFIG_COMPAT -asm ( " .pushsection .text \n" - " .global restore_set_thread_area \n" - " .code32 \n" - "restore_set_thread_area: \n" - " movl $"__stringify(__NR32_set_thread_area)",%eax\n" - " int $0x80 \n" - " ret \n" - " .popsection \n" - " .code64"); -extern char restore_set_thread_area; - +/* + * We need here compatible stack, because 32-bit syscalls get + * 4-byte pointer and _usally_ restorer is also under 4Gb, but + * it can be upper and then pointers are messed up. + * (we lose high 4 bytes and... BUNG!) + * Nothing serious, but syscall will return -EFAULT - or if we're + * lucky and lower 4 bytes points on some writeable VMA - corruption). + */ static void *stack32; static int prepare_stack32(void) { - if (stack32) return 0; @@ -63,7 +59,7 @@ static int prepare_stack32(void) void restore_tls(tls_t *ptls) { - int i; + unsigned i; for (i = 0; i < GDT_ENTRY_TLS_NUM; i++) { user_desc_t *desc = &ptls->desc[i]; @@ -76,13 +72,17 @@ void restore_tls(tls_t *ptls) return; builtin_memcpy(stack32, desc, sizeof(user_desc_t)); + asm volatile ( + " mov %1,%%eax \n" + " mov %2,%%ebx \n" + " int $0x80 \n" + " mov %%eax,%0 \n" + : "=g"(ret) + : "r"(__NR32_set_thread_area), "r"((uint32_t)(uintptr_t)stack32) + : "eax", "ebx", "memory"); - /* user_desc parameter for set_thread_area syscall */ - asm volatile ("\t movl %%ebx,%%ebx\n" : :"b"(stack32)); - call32_from_64(stack32 + PAGE_SIZE, &restore_set_thread_area); - asm volatile ("\t movl %%eax,%0\n" : "=r"(ret)); if (ret) - pr_err("Failed to restore TLS descriptor %d in GDT ret %d\n", + pr_err("Failed to restore TLS descriptor %u in GDT: %d\n", desc->entry_number, ret); } From dfa1d636cd2275e7ac2c885deb8927a1b17114f2 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:45 +0300 Subject: [PATCH 0294/4375] kdat: check compat support by EEXIST error More reliable way to check support of mapping 32-bit blob. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index c59face98..b9ce6e7da 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -28,7 +28,6 @@ #include "images/creds.pb-c.h" #ifdef CONFIG_X86_64 -/* Remaps 64-bit vDSO on the same addr, where it already is */ int kdat_compat_sigreturn_test(void) { unsigned long auxval; @@ -41,14 +40,13 @@ int kdat_compat_sigreturn_test(void) return 0; } /* - * Mapping vDSO on very low unaligned address (1). - * We will get ENOMEM or EPERM if ARCH_MAP_VDSO_* exist, - * and ENOSYS if patches aren't in kernel. + * Mapping vDSO while have not unmap it yet: + * this is restricted by API if ARCH_MAP_VDSO_* is supported. */ ret = syscall(SYS_arch_prctl, ARCH_MAP_VDSO_32, 1); - if (ret == -1 && errno == ENOSYS) - return 0; - return 1; + if (ret == -1 && errno == EEXIST) + return 1; + return 0; } #endif /* CONFIG_X86_64 */ From fa46f917390c6c6b20f6d12cd8f61910350212c3 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:46 +0300 Subject: [PATCH 0295/4375] parasite/x86: always try to dump TLS As 64-bit parasite is now in 32-bit compat app and 64-bit applications can also have TLS in GDT - simplify and just always dump TLS with 32-bit syscall get_thread_area, it's 3 syscalls more - but that's a low cost for that. Note that entry point for sys_get_thread_area() is only for 32-bits, so we need to call raw int80 here with 32-bit syscall number. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/include/asm/parasite.h | 33 ++++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/criu/arch/x86/include/asm/parasite.h b/criu/arch/x86/include/asm/parasite.h index 7f9c16033..302b412af 100644 --- a/criu/arch/x86/include/asm/parasite.h +++ b/criu/arch/x86/include/asm/parasite.h @@ -2,21 +2,15 @@ #define __ASM_PARASITE_H__ #include "asm-generic/string.h" +#include #ifdef CONFIG_X86_32 # define __parasite_entry __attribute__((regparm(3))) #endif -#ifdef CONFIG_X86_32 -static void arch_get_user_desc(user_desc_t *desc) -{ - if (sys_get_thread_area(desc)) - pr_err("Failed to dump TLS descriptor #%d\n", - desc->entry_number); -} -#else /* !X86_32 */ static void arch_get_user_desc(user_desc_t *desc) { + int ret = __NR32_get_thread_area; /* * For 64-bit applications, TLS (fs_base for Glibc) is * in MSR, which are dumped with the help of arch_prctl(). @@ -35,14 +29,24 @@ static void arch_get_user_desc(user_desc_t *desc) * #endif * ... * }; - * - * For this mixed code we may want to call get_thread_area - * 32-bit syscall. But as additional three calls to kernel - * will slow dumping, I omit it here. */ - desc->seg_not_present = 1; + asm volatile ( + " mov %0,%%eax \n" + " mov %1,%%rbx \n" + " int $0x80 \n" + " mov %%eax,%0 \n" + : "+m"(ret) + : "m"(desc) + : "eax", "rbx", "memory"); + + /* + * Fixup for Travis: on missing GDT entry get_thread_area() + * retruns -EINTR then descriptor with seg_not_preset = 1 + */ + if (ret) + pr_err("Failed to dump TLS descriptor #%d: %d\n", + desc->entry_number, ret); } -#endif /* !X86_32 */ static void arch_get_tls(tls_t *ptls) { @@ -53,6 +57,7 @@ static void arch_get_tls(tls_t *ptls) user_desc_t *d = &ptls->desc[i]; builtin_memset(d, 0, sizeof(user_desc_t)); + d->seg_not_present = 1; d->entry_number = GDT_ENTRY_TLS_MIN + i; arch_get_user_desc(d); } From 4d68ca5c94f02129ee3c08e03efcd52e24ddec74 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:47 +0300 Subject: [PATCH 0296/4375] x86/parasite: call get_thread_area on 32-bit addr It's 32-bit syscall and the high-part of address is dropped, so call it only on 32-bit addr. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/include/asm/compat.h | 41 ++++++++++++++++++++++++++++ criu/arch/x86/include/asm/parasite.h | 23 ++++++++++++++-- criu/arch/x86/include/asm/restorer.h | 13 ++------- criu/arch/x86/sigaction_compat.c | 20 +------------- 4 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 criu/arch/x86/include/asm/compat.h diff --git a/criu/arch/x86/include/asm/compat.h b/criu/arch/x86/include/asm/compat.h new file mode 100644 index 000000000..8379af452 --- /dev/null +++ b/criu/arch/x86/include/asm/compat.h @@ -0,0 +1,41 @@ +#ifndef __CR_ASM_COMPAT_H__ +#define __CR_ASM_COMPAT_H__ + +#ifdef CR_NOGLIBC +# include +# include +#else +# define sys_mmap mmap +# define sys_munmap munmap +#endif + +#include + +static inline void *alloc_compat_syscall_stack(void) +{ + void *mem = (void*)sys_mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + + if (mem == MAP_FAILED) + return 0; + return mem; +} + +static inline void free_compat_syscall_stack(void *mem) +{ + long int ret = sys_munmap(mem, PAGE_SIZE); + + if (ret) + pr_err("munmap of compat addr %p failed with %ld", mem, ret); +} + +#ifdef CONFIG_COMPAT +extern unsigned long call32_from_64(void *stack, void *func); +#endif + +#ifndef CR_NOGLIBC +# undef sys_mmap +# undef sys_munmap +#endif + +#endif diff --git a/criu/arch/x86/include/asm/parasite.h b/criu/arch/x86/include/asm/parasite.h index 302b412af..2385ec16d 100644 --- a/criu/arch/x86/include/asm/parasite.h +++ b/criu/arch/x86/include/asm/parasite.h @@ -3,12 +3,13 @@ #include "asm-generic/string.h" #include +#include "asm/compat.h" #ifdef CONFIG_X86_32 # define __parasite_entry __attribute__((regparm(3))) #endif -static void arch_get_user_desc(user_desc_t *desc) +static int arch_get_user_desc(user_desc_t *desc) { int ret = __NR32_get_thread_area; /* @@ -46,21 +47,39 @@ static void arch_get_user_desc(user_desc_t *desc) if (ret) pr_err("Failed to dump TLS descriptor #%d: %d\n", desc->entry_number, ret); + return ret; } static void arch_get_tls(tls_t *ptls) { + void *syscall_mem; int i; + syscall_mem = alloc_compat_syscall_stack(); + if (!syscall_mem) { + pr_err("Failed to allocate memory <4Gb for compat syscall\n"); + + for (i = 0; i < GDT_ENTRY_TLS_NUM; i++) { + user_desc_t *d = &ptls->desc[i]; + + d->seg_not_present = 1; + d->entry_number = GDT_ENTRY_TLS_MIN + i; + } + return; + } + for (i = 0; i < GDT_ENTRY_TLS_NUM; i++) { - user_desc_t *d = &ptls->desc[i]; + user_desc_t *d = syscall_mem; builtin_memset(d, 0, sizeof(user_desc_t)); d->seg_not_present = 1; d->entry_number = GDT_ENTRY_TLS_MIN + i; arch_get_user_desc(d); + builtin_memcpy(&ptls->desc[i], d, sizeof(user_desc_t)); } + + free_compat_syscall_stack(syscall_mem); } #endif diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index e5636aef5..2dc4fe1b7 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -5,25 +5,18 @@ #include #include "images/core.pb-c.h" #include - #include +#include "asm/compat.h" #ifdef CONFIG_COMPAT -extern void *alloc_compat_syscall_stack(void); -extern void free_compat_syscall_stack(void *mem); -extern unsigned long call32_from_64(void *stack, void *func); extern void restore_tls(tls_t *ptls); - extern int arch_compat_rt_sigaction(void *stack32, int sig, rt_sigaction_t_compat *act); -#else -static inline void *alloc_compat_syscall_stack(void) { return NULL; } -static inline void free_compat_syscall_stack(void *stack32) { } +#else /* CONFIG_COMPAT */ static inline void restore_tls(tls_t *ptls) { } static inline int arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; } -#endif - +#endif /* !CONFIG_COMPAT */ #ifdef CONFIG_X86_64 #define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \ thread_args, clone_restore_fn) \ diff --git a/criu/arch/x86/sigaction_compat.c b/criu/arch/x86/sigaction_compat.c index 076c014ef..0e9e23bdd 100644 --- a/criu/arch/x86/sigaction_compat.c +++ b/criu/arch/x86/sigaction_compat.c @@ -1,14 +1,11 @@ #include "asm/restorer.h" #include #include "asm/string.h" - -#include +#include "asm/compat.h" #ifdef CR_NOGLIBC # include #else -# define sys_mmap mmap -# define sys_munmap munmap # ifndef __NR32_rt_sigaction # define __NR32_rt_sigaction 174 # endif @@ -16,21 +13,6 @@ #include "log.h" #include "cpu.h" -void *alloc_compat_syscall_stack(void) -{ - void *mem = (void*)sys_mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, - MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - - if (mem == MAP_FAILED) - return 0; - return mem; -} - -void free_compat_syscall_stack(void *mem) -{ - sys_munmap(mem, PAGE_SIZE); -} - asm ( " .pushsection .text \n" " .global restore_rt_sigaction \n" " .code32 \n" From dc633d867905cb6388d385a6bb1aaf9b4d66ef29 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:48 +0300 Subject: [PATCH 0297/4375] x86: enable compatible 32 C/R back Supported only from v4.9 kernel :) The following commits may be backported if needed: b059a453b ("x86/vdso: Add mremap hook to vm_special_mapping") e38447ee1 ("x86/vdso: Unmap vdso blob on vvar mapping failure") 576ebfefd ("x86/vdso: Replace calculate_addr in map_vdso() with addr") 2eefd8789 ("x86/arch_prctl/vdso: Add ARCH_MAP_VDSO_*") 90954e7b9 ("x86/coredump: Use pr_reg size, rather that TIF_IA32 flag") cc87324b3 ("x86/ptrace: Down with test_thread_flag(TIF_IA32)") 684635105 ("x86/signal: Add SA_{X32,IA32}_ABI sa_flags") ed1e7db33 ("x86/signal: Remove bogus user_64bit_mode() check from sigaction_compat_abi()") The required patches list may be checked also at https://criu.org/Upstream_kernel_commits travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile.config | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Makefile.config b/Makefile.config index ad9953323..0a04115b8 100644 --- a/Makefile.config +++ b/Makefile.config @@ -19,15 +19,13 @@ CONFIG_FILE = $(SRC_DIR)/.config $(CONFIG_FILE): touch $(CONFIG_FILE) -# -# FIXME Bring back once libcompel complete -#ifeq ($(SRCARCH),x86) -## CONFIG_COMPAT is only for x86 now, no need for compile-test other archs -#ifeq ($(call try-cc,$(FEATURE_TEST_X86_COMPAT),-m32),true) -# export CONFIG_COMPAT := y -# FEATURE_DEFINES += -DCONFIG_COMPAT -#endif -#endif +ifeq ($(SRCARCH),x86) +# CONFIG_COMPAT is only for x86 now, no need for compile-test other archs +ifeq ($(call try-cc,$(FEATURE_TEST_X86_COMPAT),-m32),true) + export CONFIG_COMPAT := y + FEATURE_DEFINES += -DCONFIG_COMPAT +endif +endif export DEFINES += $(FEATURE_DEFINES) export CFLAGS += $(FEATURE_DEFINES) From 574fe35699d9408194e7e033fcf713311e0ee34b Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 9 Dec 2016 21:19:49 +0300 Subject: [PATCH 0298/4375] compel/compat: fixup for head_start addr Resolves merge conflict with commit 71abfb84e158 ("compel: simplify usage wrt ids"). Sets start ip for parasite blob according to app mode: native/compat. travis-ci: success for Rectify 32-bit compatible C/R on x86 Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/lib/handle-elf.c | 10 ++++++++-- compel/test/infect/spy.c | 1 - 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index 035cd0dda..4b8b73dfa 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -593,8 +593,14 @@ int __handle_elf(void *mem, size_t size) pr_out("\tpbd->hdr.bsize = sizeof(%s_blob);\n", opts.prefix); pr_out("\tpbd->hdr.nr_gotpcrel = %s_nr_gotpcrel;\n", opts.prefix); - pr_out("\tpbd->hdr.parasite_ip_off = " - "%s_sym__export_parasite_head_start;\n", opts.prefix); + pr_out("\tif (compel_mode_native(ctl))\n"); + pr_out("\t\tpbd->hdr.parasite_ip_off = " + "%s_sym__export_parasite_head_start;\n", opts.prefix); + pr_out("#ifdef CONFIG_COMPAT\n"); + pr_out("\telse\n"); + pr_out("\t\tpbd->hdr.parasite_ip_off = " + "%s_sym__export_parasite_head_start_compat;\n", opts.prefix); + pr_out("#endif /* CONFIG_COMPAT */\n"); pr_out("\tpbd->hdr.addr_cmd_off = " "%s_sym__export_parasite_cmd;\n", opts.prefix); pr_out("\tpbd->hdr.addr_arg_off = " diff --git a/compel/test/infect/spy.c b/compel/test/infect/spy.c index b56b2b71f..c628a0f86 100644 --- a/compel/test/infect/spy.c +++ b/compel/test/infect/spy.c @@ -22,7 +22,6 @@ static int do_infection(int pid) int state; struct parasite_ctl *ctl; struct infect_ctx *ictx; - struct parasite_blob_desc *pbd; int *arg; compel_log_init(print_vmsg, LOG_DEBUG); From 5e87137e73d82aa2da6d0e162bc42ee35a1f4da9 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 13 Dec 2016 16:55:38 +0300 Subject: [PATCH 0299/4375] criu: Fix compilation after prev patch(es) Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 2 +- criu/arch/x86/sigaction_compat.c | 2 +- criu/sigframe.c | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index b9ce6e7da..ba0145b27 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -6,6 +6,7 @@ #include #include "types.h" +#include "log.h" #include "asm/parasite-syscall.h" #include "asm/restorer.h" #include @@ -16,7 +17,6 @@ #include "restorer.h" #include #include "parasite-syscall.h" -#include "log.h" #include "util.h" #include "cpu.h" #include diff --git a/criu/arch/x86/sigaction_compat.c b/criu/arch/x86/sigaction_compat.c index 0e9e23bdd..168d3ddb0 100644 --- a/criu/arch/x86/sigaction_compat.c +++ b/criu/arch/x86/sigaction_compat.c @@ -1,3 +1,4 @@ +#include "log.h" #include "asm/restorer.h" #include #include "asm/string.h" @@ -10,7 +11,6 @@ # define __NR32_rt_sigaction 174 # endif #endif -#include "log.h" #include "cpu.h" asm ( " .pushsection .text \n" diff --git a/criu/sigframe.c b/criu/sigframe.c index b2dd85add..2b5ae7658 100644 --- a/criu/sigframe.c +++ b/criu/sigframe.c @@ -1,5 +1,6 @@ #include #include +#include "log.h" #include "restore.h" #include "images/core.pb-c.h" From 4120f64d3d6c36ad284c05340eab96470c48819f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 14 Dec 2016 19:40:00 +0300 Subject: [PATCH 0300/4375] pie: fix clobber registers for int 0x80 I managed to forgot that kernel erases R8...R11 regitster prior returning to userspace from `int 0x80`: https://lkml.org/lkml/2009/10/1/164 That was the reason for hang on gcc v6.1 on Jenkins/elsewhere: https://ci.openvz.org/job/CRIU/job/CRIU-x86_64/branch/criu-dev/ Tested on gcc v6.1 locally, on Travis-CI: https://travis-ci.org/0x7f454c46/criu/builds/183976899 travis-ci: success for pie: fix clobber registers for int 0x80 (rev2) Signed-off-by: Dmitry Safonov Tested-by: Andrei Vagin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/include/uapi/asm/sigframe.h | 2 +- criu/arch/x86/include/asm/parasite.h | 6 +----- criu/arch/x86/restorer.c | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h index 75eb76eda..e9357002c 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h @@ -185,7 +185,7 @@ struct rt_sigframe { ".code64 \n" \ : \ : "rdi"(new_sp) \ - : "eax","esp","memory") + : "eax","esp", "r8", "r9", "r10", "r11", "memory") #define ARCH_RT_SIGRETURN(new_sp, rt_sigframe) \ do { \ diff --git a/criu/arch/x86/include/asm/parasite.h b/criu/arch/x86/include/asm/parasite.h index 2385ec16d..7b259d7a2 100644 --- a/criu/arch/x86/include/asm/parasite.h +++ b/criu/arch/x86/include/asm/parasite.h @@ -38,12 +38,8 @@ static int arch_get_user_desc(user_desc_t *desc) " mov %%eax,%0 \n" : "+m"(ret) : "m"(desc) - : "eax", "rbx", "memory"); + : "rax", "rbx", "r8", "r9", "r10", "r11", "memory"); - /* - * Fixup for Travis: on missing GDT entry get_thread_area() - * retruns -EINTR then descriptor with seg_not_preset = 1 - */ if (ret) pr_err("Failed to dump TLS descriptor #%d: %d\n", desc->entry_number, ret); diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index 9cc76fe17..377a9186e 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -79,7 +79,7 @@ void restore_tls(tls_t *ptls) " mov %%eax,%0 \n" : "=g"(ret) : "r"(__NR32_set_thread_area), "r"((uint32_t)(uintptr_t)stack32) - : "eax", "ebx", "memory"); + : "eax", "ebx", "r8", "r9", "r10", "r11", "memory"); if (ret) pr_err("Failed to restore TLS descriptor %u in GDT: %d\n", From 5254258604235c077a89e4bd27dda0aa59a2b685 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:21:54 -0800 Subject: [PATCH 0301/4375] compel --help: fix indentation travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/src/main.c b/compel/src/main.c index 8eaf375fd..b4afff9e1 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -140,7 +140,7 @@ static int usage(int rc) { " -f, --file FILE input (parasite object) file name\n" " -o, --output FILE output (header) file name\n" " -p, --prefix NAME prefix for var names\n" -" -l, --log-level NUM log level (default: %d)\n" +" -l, --log-level NUM log level (default: %d)\n" " compel -h|--help\n" " compel -V|--version\n" , DEFAULT_LOGLEVEL From 7d181cda7376a0ea97fecd9e5376aa09cd1e19ef Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:21:55 -0800 Subject: [PATCH 0302/4375] compel/test: Makefiles cleanup 1. Remove COMMON_IDIR -- there's no need for it, and it makes the build process look more complicated than it is. 2. Use standard CC and CFLAGS defines (so one can use say make CC=clang) 3. Drop the dependency on COMPEL_LIBRARY, as it's supposed to be an external file/tool. 4. Add -Wall to CFLAGS. 5. Simplify ARCH setting in infect test. 6. Drop ARCH from rsys test, as it's not used there. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/test/infect/Makefile | 16 +++++++--------- compel/test/rsys/Makefile | 13 +++++-------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/compel/test/infect/Makefile b/compel/test/infect/Makefile index 65c17280f..f244755f6 100644 --- a/compel/test/infect/Makefile +++ b/compel/test/infect/Makefile @@ -1,9 +1,7 @@ -ifeq ($(ARCH),) - ARCH := x86 -endif +CC := gcc +CFLAGS ?= -O2 -g -Wall -Werror +ARCH ?= x86 -# FIXME -- generate common symlink in compel/uapi -COMMON_IDIR := ../../../include COMPEL := ../../../compel/compel-host COMPEL_IDIR := ../../../compel/include/uapi COMPEL_PACK_LDS := ../../../compel/arch/$(ARCH)/scripts/compel-pack.lds.S @@ -20,10 +18,10 @@ clean: rm -f parasite.o victim: victim.c - gcc -o $@ $^ + $(CC) $(CFLAGS) -o $@ $^ -spy: spy.c $(COMPEL_LIBRARY) | parasite.h - gcc -Werror -I$(COMPEL_IDIR) -I$(COMMON_IDIR) -o $@ $^ +spy: spy.c | parasite.h + $(CC) $(CFLAGS) -I$(COMPEL_IDIR) -o $@ $^ $(COMPEL_LIBRARY) parasite.h: parasite.po $(COMPEL) hgen -f $^ -l 4 \ @@ -34,4 +32,4 @@ parasite.po: parasite.o $(COMPEL_PLUGINS)/std.built-in.o ld -r -T $(COMPEL_PACK_LDS) -o $@ $^ parasite.o: parasite.c - gcc -c $(shell $(COMPEL) --arch=$(ARCH) cflags) -I$(COMPEL_IDIR) -o $@ $^ + $(CC) $(CFLAGS) -c $(shell $(COMPEL) --arch=$(ARCH) cflags) -I$(COMPEL_IDIR) -o $@ $^ diff --git a/compel/test/rsys/Makefile b/compel/test/rsys/Makefile index cd664884a..a4fda54fa 100644 --- a/compel/test/rsys/Makefile +++ b/compel/test/rsys/Makefile @@ -1,9 +1,6 @@ -ifeq ($(ARCH),) - ARCH := x86 -endif +CC := gcc +CFLAGS ?= -O2 -g -Wall -Werror -# FIXME -- generate common symlink in compel/uapi -COMMON_IDIR := ../../../include COMPEL_IDIR := ../../../compel/include/uapi COMPEL_LIBRARY := ../../../compel/libcompel.a @@ -14,7 +11,7 @@ clean: rm -f spy victim: victim.c - gcc -o $@ $^ + $(CC) $(CFLAGS) -o $@ $^ -spy: spy.c $(COMPEL_LIBRARY) - gcc -Werror -I$(COMPEL_IDIR) -I$(COMMON_IDIR) -o $@ $^ +spy: spy.c + $(CC) $(CFLAGS) -I$(COMPEL_IDIR) -o $@ $^ $(COMPEL_LIBRARY) From 1be75af874aba6515167462b69741309dd1dd2a6 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:21:56 -0800 Subject: [PATCH 0303/4375] compel_syscall(): make ret argument signed I saw this line in the code unsigned long sret = -ENOSYS; and ended up with this patch. Note syscall(2) man page says return value is long -- who am I to disagree? travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/infect.c | 4 ++-- compel/arch/arm/src/lib/infect.c | 4 ++-- compel/arch/ppc64/src/lib/infect.c | 4 ++-- compel/arch/x86/src/lib/infect.c | 4 ++-- compel/include/infect-priv.h | 2 +- compel/include/uapi/infect.h | 2 +- compel/src/lib/infect.c | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compel/arch/aarch64/src/lib/infect.c b/compel/arch/aarch64/src/lib/infect.c index ee1ec7c20..4f5534b75 100644 --- a/compel/arch/aarch64/src/lib/infect.c +++ b/compel/arch/aarch64/src/lib/infect.c @@ -83,7 +83,7 @@ err: return ret; } -int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, +int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, unsigned long arg1, unsigned long arg2, unsigned long arg3, @@ -114,7 +114,7 @@ void *remote_mmap(struct parasite_ctl *ctl, void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - unsigned long map; + long map; int err; err = compel_syscall(ctl, __NR_mmap, &map, diff --git a/compel/arch/arm/src/lib/infect.c b/compel/arch/arm/src/lib/infect.c index 61377691a..ad085ff98 100644 --- a/compel/arch/arm/src/lib/infect.c +++ b/compel/arch/arm/src/lib/infect.c @@ -99,7 +99,7 @@ err: return ret; } -int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, +int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, unsigned long arg1, unsigned long arg2, unsigned long arg3, @@ -128,7 +128,7 @@ void *remote_mmap(struct parasite_ctl *ctl, void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - unsigned long map; + long map; int err; if (offset & ~PAGE_MASK) diff --git a/compel/arch/ppc64/src/lib/infect.c b/compel/arch/ppc64/src/lib/infect.c index 637c3654e..11154d658 100644 --- a/compel/arch/ppc64/src/lib/infect.c +++ b/compel/arch/ppc64/src/lib/infect.c @@ -381,7 +381,7 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *ar return save(arg, ®s, &fpregs); } -int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, +int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, unsigned long arg1, unsigned long arg2, unsigned long arg3, @@ -410,7 +410,7 @@ void *remote_mmap(struct parasite_ctl *ctl, void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - unsigned long map = 0; + long map = 0; int err; err = compel_syscall(ctl, __NR_mmap, &map, diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index be0439917..9a3b1fb75 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -195,7 +195,7 @@ err: return ret; } -int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, +int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, unsigned long arg1, unsigned long arg2, unsigned long arg3, @@ -240,7 +240,7 @@ void *remote_mmap(struct parasite_ctl *ctl, void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - unsigned long map; + long map; int err; bool compat_task = !user_regs_native(&ctl->orig.regs); diff --git a/compel/include/infect-priv.h b/compel/include/infect-priv.h index 8e7443b85..99f9adab6 100644 --- a/compel/include/infect-priv.h +++ b/compel/include/infect-priv.h @@ -55,7 +55,7 @@ int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m); /* XXX -- remove with cr-exec.c */ extern int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size); -extern int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, +extern int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6); diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 7b88a5634..9f08f3461 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -65,7 +65,7 @@ extern int compel_cure(struct parasite_ctl *ctl); extern void *compel_parasite_args_p(struct parasite_ctl *ctl); extern void *compel_parasite_args_s(struct parasite_ctl *ctl, int args_size); -extern int compel_syscall(struct parasite_ctl *ctl, int nr, unsigned long *ret, +extern int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, unsigned long arg1, unsigned long arg2, unsigned long arg3, diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 3dba438ef..599c37274 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -735,7 +735,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) void *where = (void *)ctl->ictx.syscall_ip + BUILTIN_SYSCALL_SIZE; uint8_t orig_code[MEMFD_FNAME_SZ] = MEMFD_FNAME; pid_t pid = ctl->rpid; - unsigned long sret = -ENOSYS; + long sret = -ENOSYS; int ret, fd, lfd; bool __maybe_unused compat_task = !compel_mode_native(ctl); @@ -1303,7 +1303,7 @@ int compel_stop_daemon(struct parasite_ctl *ctl) int compel_cure_remote(struct parasite_ctl *ctl) { - unsigned long ret; + long ret; if (compel_stop_daemon(ctl)) return -1; From 4b86502585f11d94a1162b0329fc7cb691ccf5f3 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:21:57 -0800 Subject: [PATCH 0304/4375] compel/Makefile: rm unused .FORCE thing travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index 65426d812..b2000386e 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -1,7 +1,5 @@ include $(SRC_DIR)/Makefile.versions -.PHONY: .FORCE - COMPEL_SO_VERSION := $(COMPEL_SO_VERSION_MAJOR)$(if $(COMPEL_SO_VERSION_MINOR),.$(COMPEL_SO_VERSION_MINOR))$(if $(COMPEL_SO_VERSION_SUBLEVEL),.$(COMPEL_SO_VERSION_SUBLEVEL)) COMPEL_SO_VERSION_CODE := $(shell expr $(COMPEL_SO_VERSION_MAJOR) \* 65536 \+ $(COMPEL_SO_VERSION_MINOR) \* 256 \+ $(COMPEL_SO_VERSION_SUBLEVEL)) ccflags-y += -iquote compel/arch/$(ARCH)/src/lib/include From a49d44d2b34ccb694134a4f4abe9ec995aa15f95 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:21:58 -0800 Subject: [PATCH 0305/4375] compel/src/main.c: rm useless init 1 Since all the fields are now initialized to zeroes, we can just say ={}; 2 Since this is static, it is initialized to zeroes anyway, but from my POV being explicit about it is better. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index b4afff9e1..4202b1210 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -51,11 +51,7 @@ static const compel_cflags_t compel_cflags[] = { }, }; -piegen_opt_t opts = { - .input_filename = NULL, - .output_filename = NULL, - .fout = NULL, -}; +piegen_opt_t opts = {}; static int piegen(void) { From dfee3232e60735c011e7fef9f6f9630f8b2be08c Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:21:59 -0800 Subject: [PATCH 0306/4375] compel cli: kill --arch option, add --compat There is no need to support all possible architectures for "compel cflags" action. In fact, "compel hgen" can only support the one it was compiled for (with the only exception of 32-bit mode for x86). It looks like if we can use a few #ifdefs, there is no need to specify --arch anymore, let's drop it! Still, for the x86 32-bit mode we need to introduce --compat option. Note that "compel hgen" autodetects 32-bit mode for x86 by looking into ELF header, but in case of "compel clfags" there are no files to look into, so we need this --compat specified explicitly. While at it, - Makefile: define CONFIG_AARCH64 if building for ARM64 - fail to compile on unsupported/unspecified ARCH - make "compel --help" output a bit more compact travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 4 ++ compel/src/main.c | 84 +++++++++++++------------------------ compel/test/infect/Makefile | 2 +- criu/pie/Makefile | 2 +- 4 files changed, 34 insertions(+), 58 deletions(-) diff --git a/Makefile b/Makefile index a8cc9de7e..e06731eec 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,10 @@ ifeq ($(ARCH),arm) PROTOUFIX := y endif +ifeq ($(ARCH),aarch64) + DEFINES := -DCONFIG_AARCH64 +endif + ifeq ($(ARCH),x86) DEFINES := -DCONFIG_X86_64 endif diff --git a/compel/src/main.c b/compel/src/main.c index 4202b1210..9be3c8b64 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -28,27 +28,23 @@ #define COMPEL_LDFLAGS_DEFAULT "-r -z noexecstack" typedef struct { - const char *arch; const char *cflags; -} compel_cflags_t; + const char *cflags_compat; +} flags_t; -static const compel_cflags_t compel_cflags[] = { - { - .arch = "x86", - .cflags = COMPEL_CFLAGS_PIE, - }, { - .arch = "ia32", - .cflags = COMPEL_CFLAGS_NOPIC, - }, { - .arch = "aarch64", - .cflags = COMPEL_CFLAGS_PIE, - }, { - .arch = "arm", - .cflags = COMPEL_CFLAGS_PIE, - }, { - .arch = "ppc64", - .cflags = COMPEL_CFLAGS_PIE, - }, +static const flags_t flags = { +#if defined CONFIG_X86_64 + .cflags = COMPEL_CFLAGS_PIE, + .cflags_compat = COMPEL_CFLAGS_NOPIC, +#elif defined CONFIG_AARCH64 + .cflags = COMPEL_CFLAGS_PIE, +#elif defined(CONFIG_ARMV6) || defined(CONFIG_ARMV7) + .cflags = COMPEL_CFLAGS_PIE, +#elif defined CONFIG_PPC64 + .cflags = COMPEL_CFLAGS_PIE, +#else +#error "CONFIG_ not defined, or unsupported ARCH" +#endif }; piegen_opt_t opts = {}; @@ -114,24 +110,9 @@ static void cli_log(unsigned int lvl, const char *fmt, va_list parms) } static int usage(int rc) { - int i = 0; printf( "Usage:\n" -" compel --arch=ARCH cflags\n" -" compel --arch=ARCH ldflags\n" -" ARCH := { " -); - - /* Print list of known arches */ - while (1) { - printf("%s", compel_cflags[i++].arch); - if (i == ARRAY_SIZE(compel_cflags)) - break; - printf(" | "); - } - - printf( -" }\n" +" compel [--compat] cflags | ldflags\n" " compel -f FILE -o FILE -p NAME [-l N] hgen\n" " -f, --file FILE input (parasite object) file name\n" " -o, --output FILE output (header) file name\n" @@ -145,16 +126,21 @@ static int usage(int rc) { return rc; } +static void print_cflags(bool compat) +{ + printf("%s\n", compat ? flags.cflags_compat : flags.cflags); +} + int main(int argc, char *argv[]) { - const char *current_cflags = NULL; int log_level = DEFAULT_LOGLEVEL; - int opt, idx, i; + bool compat = false; + int opt, idx; char *action; - static const char short_opts[] = "a:f:o:p:hVl:"; + static const char short_opts[] = "cf:o:p:hVl:"; static struct option long_opts[] = { - { "arch", required_argument, 0, 'a' }, + { "compat", no_argument, 0, 'c' }, { "file", required_argument, 0, 'f' }, { "output", required_argument, 0, 'o' }, { "prefix", required_argument, 0, 'p' }, @@ -170,18 +156,8 @@ int main(int argc, char *argv[]) if (opt == -1) break; switch (opt) { - case 'a': - for (i = 0; i < ARRAY_SIZE(compel_cflags); i++) { - if (!strcmp(optarg, compel_cflags[i].arch)) { - current_cflags = compel_cflags[i].cflags; - break; - } - } - if (!current_cflags) { - fprintf(stderr, "Error: unknown arch '%s'\n", - optarg); - return usage(1); - } + case 'c': + compat = true; break; case 'f': opts.input_filename = optarg; @@ -218,11 +194,7 @@ int main(int argc, char *argv[]) action = argv[optind++]; if (!strcmp(action, "cflags")) { - if (!current_cflags) { - fprintf(stderr, "Error: option --arch required\n"); - return usage(1); - } - printf("%s", current_cflags); + print_cflags(compat); return 0; } diff --git a/compel/test/infect/Makefile b/compel/test/infect/Makefile index f244755f6..ede9a474d 100644 --- a/compel/test/infect/Makefile +++ b/compel/test/infect/Makefile @@ -32,4 +32,4 @@ parasite.po: parasite.o $(COMPEL_PLUGINS)/std.built-in.o ld -r -T $(COMPEL_PACK_LDS) -o $@ $^ parasite.o: parasite.c - $(CC) $(CFLAGS) -c $(shell $(COMPEL) --arch=$(ARCH) cflags) -I$(COMPEL_IDIR) -o $@ $^ + $(CC) $(CFLAGS) -c $(shell $(COMPEL) cflags) -I$(COMPEL_IDIR) -o $@ $^ diff --git a/criu/pie/Makefile b/criu/pie/Makefile index e05bb0bbc..9ae488c89 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -37,7 +37,7 @@ ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) - CFLAGS += $(shell $(SRC_DIR)/compel/compel-host --arch=$(ARCH) cflags) + CFLAGS += $(shell $(SRC_DIR)/compel/compel-host cflags) endif ifeq ($(SRCARCH),arm) From f53189c520bf61dd40c91a0c09a145e5f53474ca Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:00 -0800 Subject: [PATCH 0307/4375] compel cli: print usage to stderr in case of error This is mainly dictated by the fact that we use stdout from "compel *flags" in a special way, so it should not be garbled by the usage info. Otherwise, for example, the following code in Makefile CFLAGS += $(shell compel --badopt cflags) will lead to the whole usage() output to be added to compiler flags, which looks really really weird. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compel/src/main.c b/compel/src/main.c index 9be3c8b64..c943febd1 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -110,7 +110,9 @@ static void cli_log(unsigned int lvl, const char *fmt, va_list parms) } static int usage(int rc) { - printf( + FILE *out = (rc == 0) ? stdout : stderr; + + fprintf(out, "Usage:\n" " compel [--compat] cflags | ldflags\n" " compel -f FILE -o FILE -p NAME [-l N] hgen\n" From 51c4569cd901f1af4278a81547d0a53d3330541c Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:02 -0800 Subject: [PATCH 0308/4375] compel cli: show includes 1. Add "compel includes" command, to be used for parasite *loading* code compilation. 2. Add includes to output of "compel cflags", which is used for parasite code compilation. Now, this patch looks big and complex, this is mostly because we want compel cli to work for both uninstalled (right from the source tree) and installed cases. The paths to be printed are quite different for these two cases, so I had to introduce a wrapper for a non-installed case. The wrapper sets an environment variable, which compel binary uses as a path to non-installed file. If this env var is not set, it means compel is installed so no tricks are needed. Note the wrapper is only provided for the compel-host binary, as compel (which differs from compel-host in case of cross-compiling) is not executed from within the source tree. Because of the wrapper, the original binary had to be renamed, thus the changes to Makefiles and .gitignore. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .gitignore | 2 +- Makefile | 4 ++-- compel/Makefile | 7 ++++--- compel/compel-host | 8 ++++++++ compel/src/main.c | 35 ++++++++++++++++++++++++++++++++++- compel/test/infect/Makefile | 5 ++--- compel/test/rsys/Makefile | 4 ++-- criu/pie/Makefile | 2 +- 8 files changed, 54 insertions(+), 13 deletions(-) create mode 100755 compel/compel-host diff --git a/.gitignore b/.gitignore index c3f82939d..f54248c6a 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,7 @@ tags TAGS Makefile.local compel/compel -compel/compel-host +compel/compel-host-bin images/*.c images/*.h images/google/protobuf/*.c diff --git a/Makefile b/Makefile index e06731eec..630b650af 100644 --- a/Makefile +++ b/Makefile @@ -222,9 +222,9 @@ $(SOCCR_A): |soccr/built-in.o # # But note that we're already included # the nmk so we can reuse it there. -criu/%: images/built-in.o compel/plugins/std.built-in.o compel/libcompel.a compel/compel-host $(VERSION_HEADER) .FORCE +criu/%: images/built-in.o compel/plugins/std.built-in.o compel/libcompel.a compel/compel-host-bin $(VERSION_HEADER) .FORCE $(Q) $(MAKE) $(build)=criu $@ -criu: images/built-in.o compel/plugins/std.built-in.o compel/libcompel.a compel/compel-host $(SOCCR_A) $(VERSION_HEADER) +criu: images/built-in.o compel/plugins/std.built-in.o compel/libcompel.a compel/compel-host-bin $(SOCCR_A) $(VERSION_HEADER) $(Q) $(MAKE) $(build)=criu all .PHONY: criu diff --git a/compel/Makefile b/compel/Makefile index b2000386e..ef932fe46 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -2,6 +2,7 @@ include $(SRC_DIR)/Makefile.versions COMPEL_SO_VERSION := $(COMPEL_SO_VERSION_MAJOR)$(if $(COMPEL_SO_VERSION_MINOR),.$(COMPEL_SO_VERSION_MINOR))$(if $(COMPEL_SO_VERSION_SUBLEVEL),.$(COMPEL_SO_VERSION_SUBLEVEL)) COMPEL_SO_VERSION_CODE := $(shell expr $(COMPEL_SO_VERSION_MAJOR) \* 65536 \+ $(COMPEL_SO_VERSION_MINOR) \* 256 \+ $(COMPEL_SO_VERSION_SUBLEVEL)) +ccflags-y += -DINCLUDEDIR=\"$(INCLUDEDIR)\" ccflags-y += -iquote compel/arch/$(ARCH)/src/lib/include ccflags-y += -iquote compel/include ccflags-y += -iquote compel/plugins/include @@ -45,8 +46,8 @@ endif host-ccflags-y += $(ccflags-y) -hostprogs-y += compel-host -compel-host-objs := $(patsubst %.o,%-host.o,$(obj-y) $(host-lib-y)) +hostprogs-y += compel-host-bin +compel-host-bin-objs := $(patsubst %.o,%-host.o,$(obj-y) $(host-lib-y)) ifeq ($(ARCH),x86) HOSTCFLAGS_handle-elf-32-host.o += -UCONFIG_X86_64 -DCONFIG_X86_32 @@ -54,7 +55,7 @@ HOSTCFLAGS_handle-elf-32-host.d += -UCONFIG_X86_64 -DCONFIG_X86_32 endif cleanup-y += compel/compel -cleanup-y += compel/compel-host +cleanup-y += compel/compel-host-bin cleanup-y += compel/libcompel.so install: compel/compel compel/$(LIBCOMPEL_SO) compel/$(LIBCOMPEL_A) diff --git a/compel/compel-host b/compel/compel-host new file mode 100755 index 000000000..bf78862bb --- /dev/null +++ b/compel/compel-host @@ -0,0 +1,8 @@ +#!/bin/sh +# +# A wrapper to use compel-host right from the source dir +# (i.e. when it is not yet installed). + +COMPEL_UNINSTALLED_ROOTDIR=$(dirname "$0") +export COMPEL_UNINSTALLED_ROOTDIR +exec "${COMPEL_UNINSTALLED_ROOTDIR}/compel-host-bin" "$@" diff --git a/compel/src/main.c b/compel/src/main.c index c943febd1..f91fe2729 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -48,6 +48,7 @@ static const flags_t flags = { }; piegen_opt_t opts = {}; +const char *uninst_root; static int piegen(void) { @@ -114,7 +115,7 @@ static int usage(int rc) { fprintf(out, "Usage:\n" -" compel [--compat] cflags | ldflags\n" +" compel [--compat] includes | cflags | ldflags\n" " compel -f FILE -o FILE -p NAME [-l N] hgen\n" " -f, --file FILE input (parasite object) file name\n" " -o, --output FILE output (header) file name\n" @@ -128,9 +129,35 @@ static int usage(int rc) { return rc; } +static void print_includes(void) +{ + int i; + /* list of standard include dirs (built into C preprocessor) */ + const char *standard_includes[] = { + "/usr/include", + "/usr/local/include", + }; + + /* I am not installed, called via a wrapper */ + if (uninst_root) { + printf("-I %s/include/uapi\n", uninst_root); + return; + } + + /* I am installed + * Make sure to not print banalities */ + for (i = 0; i < ARRAY_SIZE(standard_includes); i++) + if (strcmp(INCLUDEDIR, standard_includes[i]) == 0) + return; + + /* Finally, print our non-standard include path */ + printf("%s\n", "-I " INCLUDEDIR); +} + static void print_cflags(bool compat) { printf("%s\n", compat ? flags.cflags_compat : flags.cflags); + print_includes(); } int main(int argc, char *argv[]) @@ -152,6 +179,8 @@ int main(int argc, char *argv[]) { }, }; + uninst_root = getenv("COMPEL_UNINSTALLED_ROOTDIR"); + while (1) { idx = -1; opt = getopt_long(argc, argv, short_opts, long_opts, &idx); @@ -195,6 +224,10 @@ int main(int argc, char *argv[]) } action = argv[optind++]; + if (!strcmp(action, "includes")) { + print_includes(); + return 0; + } if (!strcmp(action, "cflags")) { print_cflags(compat); return 0; diff --git a/compel/test/infect/Makefile b/compel/test/infect/Makefile index ede9a474d..8d35c2967 100644 --- a/compel/test/infect/Makefile +++ b/compel/test/infect/Makefile @@ -3,7 +3,6 @@ CFLAGS ?= -O2 -g -Wall -Werror ARCH ?= x86 COMPEL := ../../../compel/compel-host -COMPEL_IDIR := ../../../compel/include/uapi COMPEL_PACK_LDS := ../../../compel/arch/$(ARCH)/scripts/compel-pack.lds.S COMPEL_PLUGINS := ../../../compel/plugins COMPEL_LIBRARY := ../../../compel/libcompel.a @@ -21,7 +20,7 @@ victim: victim.c $(CC) $(CFLAGS) -o $@ $^ spy: spy.c | parasite.h - $(CC) $(CFLAGS) -I$(COMPEL_IDIR) -o $@ $^ $(COMPEL_LIBRARY) + $(CC) $(CFLAGS) $(shell $(COMPEL) includes) -o $@ $^ $(COMPEL_LIBRARY) parasite.h: parasite.po $(COMPEL) hgen -f $^ -l 4 \ @@ -32,4 +31,4 @@ parasite.po: parasite.o $(COMPEL_PLUGINS)/std.built-in.o ld -r -T $(COMPEL_PACK_LDS) -o $@ $^ parasite.o: parasite.c - $(CC) $(CFLAGS) -c $(shell $(COMPEL) cflags) -I$(COMPEL_IDIR) -o $@ $^ + $(CC) $(CFLAGS) -c $(shell $(COMPEL) cflags) -o $@ $^ diff --git a/compel/test/rsys/Makefile b/compel/test/rsys/Makefile index a4fda54fa..3c5ef5bba 100644 --- a/compel/test/rsys/Makefile +++ b/compel/test/rsys/Makefile @@ -1,7 +1,7 @@ CC := gcc CFLAGS ?= -O2 -g -Wall -Werror -COMPEL_IDIR := ../../../compel/include/uapi +COMPEL := ../../../compel/compel-host COMPEL_LIBRARY := ../../../compel/libcompel.a all: victim spy @@ -14,4 +14,4 @@ victim: victim.c $(CC) $(CFLAGS) -o $@ $^ spy: spy.c - $(CC) $(CFLAGS) -I$(COMPEL_IDIR) -o $@ $^ $(COMPEL_LIBRARY) + $(CC) $(CFLAGS) $(shell $(COMPEL) includes) -o $@ $^ $(COMPEL_LIBRARY) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 9ae488c89..1649a2987 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -62,7 +62,7 @@ $(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/pie.lib.a $(compel_lds) $(call msg-gen, $@) $(Q) $(LD) -r -T $(compel_lds) -o $@ $< $(obj)/pie.lib.a -$(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host +$(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host-bin $(call msg-gen, $@) $(Q) $(SRC_DIR)/compel/compel-host hgen -f $< \ -l 4 \ From 545bac9b623805de0a83e35d68cbd35990211982 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:03 -0800 Subject: [PATCH 0309/4375] Makefiles: rm -I compel/plugins... from cflags I have noticed compel/plugins/include[/uapi] is not needed, not entirely sure why (added symlinks?) but everything compiles just fine without it. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 2 -- compel/plugins/Makefile | 2 -- criu/Makefile | 1 - criu/Makefile.crtools | 1 - criu/arch/aarch64/Makefile | 1 - criu/arch/arm/Makefile | 1 - criu/arch/ppc64/Makefile | 1 - criu/arch/x86/Makefile | 1 - criu/pie/Makefile | 1 - criu/pie/Makefile.library | 1 - 10 files changed, 12 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index ef932fe46..1d2230c26 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -5,14 +5,12 @@ COMPEL_SO_VERSION_CODE := $(shell expr $(COMPEL_SO_VERSION_MAJOR) \* 65536 \+ $( ccflags-y += -DINCLUDEDIR=\"$(INCLUDEDIR)\" ccflags-y += -iquote compel/arch/$(ARCH)/src/lib/include ccflags-y += -iquote compel/include -ccflags-y += -iquote compel/plugins/include ccflags-y += -fno-strict-aliasing ccflags-y += -fPIC # # UAPI inclusion, referred as ccflags-y += -I compel/include/uapi -ccflags-y += -I compel/plugins/include/uapi lib-name := $(LIBCOMPEL_A) lib-y += src/lib/log.o diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 80735558c..587324057 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -9,9 +9,7 @@ PLUGIN_ARCH_DIR := compel/arch/$(ARCH)/plugins # # UAPI inclusion, referred as ccflags-y += -I compel/include/uapi -ccflags-y += -I compel/plugins/include/uapi asflags-y += -I compel/include/uapi -asflags-y += -I compel/plugins/include/uapi # General compel includes ccflags-y += -iquote $(SRC_DIR)/compel/include diff --git a/criu/Makefile b/criu/Makefile index 160f1e9dc..89615e36e 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -18,7 +18,6 @@ ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR)/include ccflags-y += -iquote $(SRC_DIR)/ ccflags-y += -I/usr/include/libnl3 ccflags-y += -I compel/include/uapi -ccflags-y += -I compel/plugins/include/uapi export ccflags-y diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 791205960..f862afa9d 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -1,6 +1,5 @@ ccflags-y += -iquote criu/$(ARCH) ccflags-y += -I compel/include/uapi -ccflags-y += -I compel/plugins/include/uapi obj-y += action-scripts.o obj-y += external.o diff --git a/criu/arch/aarch64/Makefile b/criu/arch/aarch64/Makefile index 858e1a583..edc4eb446 100644 --- a/criu/arch/aarch64/Makefile +++ b/criu/arch/aarch64/Makefile @@ -4,7 +4,6 @@ ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) ccflags-y += -iquote $(obj)/include -iquote $(SRC_DIR)/criu/include ccflags-y += -iquote $(SRC_DIR)/include ccflags-y += -I compel/include/uapi -ccflags-y += -I compel/plugins/include/uapi asflags-y += -D__ASSEMBLY__ obj-y += cpu.o diff --git a/criu/arch/arm/Makefile b/criu/arch/arm/Makefile index ec32a9d6b..218b3a0f5 100644 --- a/criu/arch/arm/Makefile +++ b/criu/arch/arm/Makefile @@ -4,7 +4,6 @@ ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include ccflags-y += -I compel/include/uapi -ccflags-y += -I compel/plugins/include/uapi asflags-y += -D__ASSEMBLY__ diff --git a/criu/arch/ppc64/Makefile b/criu/arch/ppc64/Makefile index 12b8ad2e3..7f767bb47 100644 --- a/criu/arch/ppc64/Makefile +++ b/criu/arch/ppc64/Makefile @@ -3,7 +3,6 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include ccflags-y += -I compel/include/uapi -ccflags-y += -I compel/plugins/include/uapi obj-y += cpu.o obj-y += crtools.o diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index 6744f9a27..7217068e5 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -3,7 +3,6 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include ccflags-y += -I compel/include/uapi -ccflags-y += -I compel/plugins/include/uapi asflags-y += -Wstrict-prototypes -Wa,--noexecstack asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 1649a2987..d6bb9fd5b 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -31,7 +31,6 @@ CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 ccflags-y += -I compel/include/uapi -ccflags-y += -I compel/plugins/include/uapi ccflags-y += -DCR_NOGLIBC ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 91b742c41..1cef5158f 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -42,7 +42,6 @@ iquotes += -iquote $(SRC_DIR)/$(ARCH_DIR)/include iquotes += -iquote $(SRC_DIR) -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) $(iquotes) asflags-y := -D__ASSEMBLY__ $(iquotes) -ccflags-y += -I compel/plugins/include/uapi ccflags-y += -I compel/include/uapi ifeq ($(SRCARCH),arm) From 509d4205ae778d61a186b143734c893c063d740a Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:04 -0800 Subject: [PATCH 0310/4375] Makefiles: introduce/use COMPEL_BIN We call compel-host binary from a number of places, so let's add COMPEL_BIN variable and use it. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile.compel | 3 +++ criu/pie/Makefile | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Makefile.compel b/Makefile.compel index d15b26763..43d325556 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -1,3 +1,6 @@ +COMPEL_BIN := $(SRC_DIR)/compel/compel-host +export COMPEL_BIN + COMPEL_VERSION_HEADER := compel/include/version.h $(COMPEL_VERSION_HEADER): $(SRC_DIR)/Makefile.versions diff --git a/criu/pie/Makefile b/criu/pie/Makefile index d6bb9fd5b..7a909114e 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -36,7 +36,7 @@ ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) - CFLAGS += $(shell $(SRC_DIR)/compel/compel-host cflags) + CFLAGS += $(shell $(COMPEL_BIN) cflags) endif ifeq ($(SRCARCH),arm) @@ -63,9 +63,9 @@ $(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/pie.lib.a $(compel_lds) $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host-bin $(call msg-gen, $@) - $(Q) $(SRC_DIR)/compel/compel-host hgen -f $< \ - -l 4 \ - -p $(call target-name,$@) \ + $(Q) $(COMPEL_BIN) hgen -f $< \ + -l 4 \ + -p $(call target-name,$@) \ -o $@ $(piegen_stdout) all-y += $(BLOBS) From 597d40a022ad68a95c4e844094d6217f2e31e29a Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:05 -0800 Subject: [PATCH 0311/4375] Makefile.compel: rm fds plugin As of commit 3c16dc5 ("compel: plugins -- Merge fds plugin into std") fds plugin is no more. Remove this leftover. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile.compel | 3 --- 1 file changed, 3 deletions(-) diff --git a/Makefile.compel b/Makefile.compel index 43d325556..ca50a5810 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -62,9 +62,6 @@ compel/plugins/std.built-in.o: $(compel-deps) .FORCE compel/plugins/shmem.built-in.o: $(compel-deps) .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ -compel/plugins/fds.built-in.o: $(compel-deps) .FORCE - $(Q) $(MAKE) $(build)=compel/plugins $@ - compel/compel: compel/built-in.o compel/$(LIBCOMPEL_A) | $(compel-deps) $(call msg-link, $@) $(Q) $(CC) $(CFLAGS) $^ $(WRAPFLAGS) $(LDFLAGS) -rdynamic -o $@ From e0fcf550c6b77ebb801f0768827ff31e821c8740 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:06 -0800 Subject: [PATCH 0312/4375] compel: make include/uapi symlink permanent There is absolutely no need to create/remove this symlink from Makefiles, as it is constant. Just add the symlink to sources and save a few lines in Makefiles. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 1 - Makefile.compel | 6 ------ compel/include/uapi/compel | 1 + 3 files changed, 1 insertion(+), 7 deletions(-) create mode 120000 compel/include/uapi/compel diff --git a/Makefile b/Makefile index 630b650af..d4fee531e 100644 --- a/Makefile +++ b/Makefile @@ -266,7 +266,6 @@ mrproper: subclean $(Q) $(RM) $(VERSION_HEADER) $(Q) $(RM) $(COMPEL_VERSION_HEADER) $(Q) $(RM) include/common/asm - $(Q) $(RM) compel/include/uapi/compel $(Q) $(RM) compel/include/uapi/asm $(Q) $(RM) compel/include/asm $(Q) $(RM) cscope.* diff --git a/Makefile.compel b/Makefile.compel index ca50a5810..4fcc6eade 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -14,11 +14,6 @@ $(COMPEL_VERSION_HEADER): $(SRC_DIR)/Makefile.versions $(Q) echo "#define COMPEL_SO_VERSION_SUBLEVEL " $(COMPEL_SO_VERSION_SUBLEVEL) >> $(COMPEL_VERSION_HEADER) $(Q) echo "#endif /* COMPEL_SO_VERSION_H__ */" >> $(COMPEL_VERSION_HEADER) -$(SRC_DIR)/compel/include/uapi/compel: $(SRC_DIR)/compel/include/uapi - $(call msg-gen, $@) - $(Q) ln -s $^ $@ -$(COMPEL_VERSION_HEADER): $(SRC_DIR)/compel/include/uapi/compel - $(SRC_DIR)/compel/include/uapi/asm: $(SRC_DIR)/compel/arch/$(ARCH)/src/lib/include/uapi/asm $(call msg-gen, $@) $(Q) ln -s $^ $@ @@ -29,7 +24,6 @@ $(SRC_DIR)/compel/include/asm: $(SRC_DIR)/compel/arch/$(ARCH)/src/lib/include $(Q) ln -s $^ $@ $(COMPEL_VERSION_HEADER): $(SRC_DIR)/compel/include/asm -compel-uapi-links += $(SRC_DIR)/compel/include/uapi/compel compel-uapi-links += $(SRC_DIR)/compel/include/uapi/asm compel-uapi-links += $(SRC_DIR)/compel/include/asm diff --git a/compel/include/uapi/compel b/compel/include/uapi/compel new file mode 120000 index 000000000..945c9b46d --- /dev/null +++ b/compel/include/uapi/compel @@ -0,0 +1 @@ +. \ No newline at end of file From ea0cc75ab34d07da56a91aee62b7660c4eaa342b Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:07 -0800 Subject: [PATCH 0313/4375] compel: make include/uapi/asm symlink permanent Similar to the previous commit, there is absolutely no need to create/remove this symlink from Makefiles, as it can be made a constant one. Add the symlink to sources and save a few lines in Makefiles. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 1 - Makefile.compel | 10 +--------- compel/include/uapi/asm | 1 + 3 files changed, 2 insertions(+), 10 deletions(-) create mode 120000 compel/include/uapi/asm diff --git a/Makefile b/Makefile index d4fee531e..4374ef5af 100644 --- a/Makefile +++ b/Makefile @@ -266,7 +266,6 @@ mrproper: subclean $(Q) $(RM) $(VERSION_HEADER) $(Q) $(RM) $(COMPEL_VERSION_HEADER) $(Q) $(RM) include/common/asm - $(Q) $(RM) compel/include/uapi/asm $(Q) $(RM) compel/include/asm $(Q) $(RM) cscope.* $(Q) $(RM) tags TAGS diff --git a/Makefile.compel b/Makefile.compel index 4fcc6eade..301b5a822 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -14,20 +14,12 @@ $(COMPEL_VERSION_HEADER): $(SRC_DIR)/Makefile.versions $(Q) echo "#define COMPEL_SO_VERSION_SUBLEVEL " $(COMPEL_SO_VERSION_SUBLEVEL) >> $(COMPEL_VERSION_HEADER) $(Q) echo "#endif /* COMPEL_SO_VERSION_H__ */" >> $(COMPEL_VERSION_HEADER) -$(SRC_DIR)/compel/include/uapi/asm: $(SRC_DIR)/compel/arch/$(ARCH)/src/lib/include/uapi/asm - $(call msg-gen, $@) - $(Q) ln -s $^ $@ -$(COMPEL_VERSION_HEADER): $(SRC_DIR)/compel/include/uapi/asm - $(SRC_DIR)/compel/include/asm: $(SRC_DIR)/compel/arch/$(ARCH)/src/lib/include $(call msg-gen, $@) $(Q) ln -s $^ $@ $(COMPEL_VERSION_HEADER): $(SRC_DIR)/compel/include/asm -compel-uapi-links += $(SRC_DIR)/compel/include/uapi/asm -compel-uapi-links += $(SRC_DIR)/compel/include/asm - -compel-deps += $(compel-uapi-links) +compel-deps += $(SRC_DIR)/compel/include/asm compel-deps += $(COMPEL_VERSION_HEADER) compel-deps += $(CONFIG_HEADER) compel-deps += include/common/asm diff --git a/compel/include/uapi/asm b/compel/include/uapi/asm new file mode 120000 index 000000000..36f9e049d --- /dev/null +++ b/compel/include/uapi/asm @@ -0,0 +1 @@ +../asm/uapi/asm \ No newline at end of file From a502750a3d6163f41f67396e6228620b1dd846b3 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:08 -0800 Subject: [PATCH 0314/4375] Makefile.compel: simplify compel-deps Working on CRIU Makefilest feels like walking on a minefield. This is not an attempt to demine it, but to make some mines a bit easier to notice. OK, this is what we're trying to do here: 1. Drop the $(SRC_DIR)/ prefix from the target: as this is a top-level Makefile, we can just use paths relative to top-level source dir. 2. Drop the $(SRC_DIR) from the symlink, use relative one. Relative symlinks are always better -- say, if a source directory is moved, everything will still work. 3. The "compel/include/asm: compel/arch/$(ARCH)/src/lib/include" dependency is useless. Yes, the left side is created as a symlink to the right side, but that doesn't mean that "make" should compare the timestamps of both to decide whether to remake the target. 4. The "$(COMPEL_VERSION_HEADER): compel/include/asm" dependency is wrong, the compel/include/asm symlink is not needed for $(COMPEL_VERSION_HEADER) generation. Remove it. 5. Move compel/plugins/std.built-in.o prerequisite from the rule to compel-plugins variable, and use it. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile.compel | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile.compel b/Makefile.compel index 301b5a822..46a3b529f 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -14,15 +14,15 @@ $(COMPEL_VERSION_HEADER): $(SRC_DIR)/Makefile.versions $(Q) echo "#define COMPEL_SO_VERSION_SUBLEVEL " $(COMPEL_SO_VERSION_SUBLEVEL) >> $(COMPEL_VERSION_HEADER) $(Q) echo "#endif /* COMPEL_SO_VERSION_H__ */" >> $(COMPEL_VERSION_HEADER) -$(SRC_DIR)/compel/include/asm: $(SRC_DIR)/compel/arch/$(ARCH)/src/lib/include +compel/include/asm: $(call msg-gen, $@) - $(Q) ln -s $^ $@ -$(COMPEL_VERSION_HEADER): $(SRC_DIR)/compel/include/asm + $(Q) ln -s ../arch/$(ARCH)/src/lib/include $@ -compel-deps += $(SRC_DIR)/compel/include/asm +compel-deps += compel/include/asm compel-deps += $(COMPEL_VERSION_HEADER) compel-deps += $(CONFIG_HEADER) compel-deps += include/common/asm +compel-plugins += compel/plugins/std.built-in.o LIBCOMPEL_SO := libcompel.so LIBCOMPEL_A := libcompel.a @@ -30,7 +30,7 @@ export LIBCOMPEL_SO LIBCOMPEL_A # # Compel itself. -compel/%: $(compel-deps) compel/plugins/std.built-in.o .FORCE +compel/%: $(compel-deps) $(compel-plugins) .FORCE $(Q) $(MAKE) $(build)=compel $@ # @@ -61,4 +61,4 @@ compel/$(LIBCOMPEL_SO): compel/$(LIBCOMPEL_A) compel-install-targets += compel/$(LIBCOMPEL_SO) compel-install-targets += compel/compel -compel-install-targets += compel/plugins/std.built-in.o +compel-install-targets += $(compel-plugins) From 96f3f1b64f6a7aacff8f19bb2aaea2b68d017c69 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:09 -0800 Subject: [PATCH 0315/4375] Makefile: untangle criu deps Build of criu binary depends on many other things that needs to be built before it. Let's clean these deps a bit by using criu-deps variable. This also removes wrong "$(VERSION_HEADER): include/common/asm" dependency -- one can certainly succeed in generating criu/include/version.h file without creating include/common/asm symlink fist! travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile | 11 ++++++++--- Makefile.compel | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 4374ef5af..fdb25208b 100644 --- a/Makefile +++ b/Makefile @@ -173,12 +173,15 @@ endif $(Q) echo "#define CRIU_GITID \"$(GITID)\"" >> $@ $(Q) echo "#endif /* __CR_VERSION_H__ */" >> $@ +criu-deps += $(VERSION_HEADER) + # # Setup proper link for asm headers in common code. include/common/asm: include/common/arch/$(ARCH)/asm $(call msg-gen, $@) $(Q) ln -s ./arch/$(ARCH)/asm $@ -$(VERSION_HEADER): include/common/asm + +criu-deps += include/common/asm # # Configure variables. @@ -194,6 +197,7 @@ endif # Protobuf images first, they are not depending # on anything else. $(eval $(call gen-built-in,images)) +criu-deps += images/built-in.o .PHONY: .FORCE @@ -213,6 +217,7 @@ soccr/%: $(SOCCR_CONFIG) .FORCE soccr/built-in.o: $(SOCCR_CONFIG) .FORCE $(Q) $(MAKE) $(build)=soccr all $(SOCCR_A): |soccr/built-in.o +criu-deps += $(SOCCR_A) # # CRIU building done in own directory @@ -222,9 +227,9 @@ $(SOCCR_A): |soccr/built-in.o # # But note that we're already included # the nmk so we can reuse it there. -criu/%: images/built-in.o compel/plugins/std.built-in.o compel/libcompel.a compel/compel-host-bin $(VERSION_HEADER) .FORCE +criu/%: $(criu-deps) .FORCE $(Q) $(MAKE) $(build)=criu $@ -criu: images/built-in.o compel/plugins/std.built-in.o compel/libcompel.a compel/compel-host-bin $(SOCCR_A) $(VERSION_HEADER) +criu: $(criu-deps) $(Q) $(MAKE) $(build)=criu all .PHONY: criu diff --git a/Makefile.compel b/Makefile.compel index 46a3b529f..3e7a1742f 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -27,12 +27,15 @@ compel-plugins += compel/plugins/std.built-in.o LIBCOMPEL_SO := libcompel.so LIBCOMPEL_A := libcompel.a export LIBCOMPEL_SO LIBCOMPEL_A +criu-deps += compel/$(LIBCOMPEL_A) # # Compel itself. compel/%: $(compel-deps) $(compel-plugins) .FORCE $(Q) $(MAKE) $(build)=compel $@ +criu-deps += compel/compel-host-bin + # # Plugins compel/plugins/%: $(compel-deps) .FORCE From e3a9aefae4c1b45783f50e389f721478095e499e Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:10 -0800 Subject: [PATCH 0316/4375] criu Makefiles: use compel includes Instead of hardcoding the path to compel uapi includes, call compel tool to get one. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/Makefile | 7 ++++++- criu/Makefile.crtools | 2 +- criu/arch/aarch64/Makefile | 2 +- criu/arch/arm/Makefile | 2 +- criu/arch/ppc64/Makefile | 2 +- criu/arch/x86/Makefile | 2 +- criu/pie/Makefile | 2 +- criu/pie/Makefile.library | 2 +- 8 files changed, 13 insertions(+), 8 deletions(-) diff --git a/criu/Makefile b/criu/Makefile index 89615e36e..c44d3b0a2 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -6,6 +6,11 @@ ARCH_DIR := criu/arch/$(SRCARCH) PIE_DIR := criu/pie export ARCH_DIR PIE_DIR +ifeq ($(filter clean mrproper,$(MAKECMDGOALS)),) + COMPEL_UAPI_INCLUDES := $(shell $(COMPEL_BIN) includes) + export COMPEL_UAPI_INCLUDES +endif + # # General flags. ccflags-y += -fno-strict-aliasing @@ -17,7 +22,7 @@ ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR) ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR)/include ccflags-y += -iquote $(SRC_DIR)/ ccflags-y += -I/usr/include/libnl3 -ccflags-y += -I compel/include/uapi +ccflags-y += $(COMPEL_UAPI_INCLUDES) export ccflags-y diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index f862afa9d..7565895bf 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -1,5 +1,5 @@ ccflags-y += -iquote criu/$(ARCH) -ccflags-y += -I compel/include/uapi +ccflags-y += $(COMPEL_UAPI_INCLUDES) obj-y += action-scripts.o obj-y += external.o diff --git a/criu/arch/aarch64/Makefile b/criu/arch/aarch64/Makefile index edc4eb446..428e8081b 100644 --- a/criu/arch/aarch64/Makefile +++ b/criu/arch/aarch64/Makefile @@ -3,7 +3,7 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) ccflags-y += -iquote $(obj)/include -iquote $(SRC_DIR)/criu/include ccflags-y += -iquote $(SRC_DIR)/include -ccflags-y += -I compel/include/uapi +ccflags-y += $(COMPEL_UAPI_INCLUDES) asflags-y += -D__ASSEMBLY__ obj-y += cpu.o diff --git a/criu/arch/arm/Makefile b/criu/arch/arm/Makefile index 218b3a0f5..b64d1c9ff 100644 --- a/criu/arch/arm/Makefile +++ b/criu/arch/arm/Makefile @@ -3,7 +3,7 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include -ccflags-y += -I compel/include/uapi +ccflags-y += $(COMPEL_UAPI_INCLUDES) asflags-y += -D__ASSEMBLY__ diff --git a/criu/arch/ppc64/Makefile b/criu/arch/ppc64/Makefile index 7f767bb47..4859bf04a 100644 --- a/criu/arch/ppc64/Makefile +++ b/criu/arch/ppc64/Makefile @@ -2,7 +2,7 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include -ccflags-y += -I compel/include/uapi +ccflags-y += $(COMPEL_UAPI_INCLUDES) obj-y += cpu.o obj-y += crtools.o diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index 7217068e5..1d29cb943 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -2,7 +2,7 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include -ccflags-y += -I compel/include/uapi +ccflags-y += $(COMPEL_UAPI_INCLUDES) asflags-y += -Wstrict-prototypes -Wa,--noexecstack asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 7a909114e..f75d166fa 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -30,7 +30,7 @@ CFLAGS += -iquote $(SRC_DIR) CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 -ccflags-y += -I compel/include/uapi +ccflags-y += $(COMPEL_UAPI_INCLUDES) ccflags-y += -DCR_NOGLIBC ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 1cef5158f..7143050f4 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -42,7 +42,7 @@ iquotes += -iquote $(SRC_DIR)/$(ARCH_DIR)/include iquotes += -iquote $(SRC_DIR) -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) $(iquotes) asflags-y := -D__ASSEMBLY__ $(iquotes) -ccflags-y += -I compel/include/uapi +ccflags-y += $(COMPEL_UAPI_INCLUDES) ifeq ($(SRCARCH),arm) ccflags-y += -marm From 9f41af0325dade01d7fbf8aad4e96b70ecd3d664 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:11 -0800 Subject: [PATCH 0317/4375] compel cli: add linker script to ldflags / use it This commit adds -T path/to/linker_script to the output of "compel ldflags", so compel user does not have to specify one manually. This commit also makes use of this functionality in criu/pie and compel/test. NOTE this commit also drops the linker script dependency in criu/pie/Makefile, meaning if it will be changed that won't cause a rebuild. I hope it's not a big issue, and it is sort of inevitable as compel is becoming a separate tool. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 1 + compel/src/main.c | 26 ++++++++++++++++++++++++-- compel/test/infect/Makefile | 4 +--- criu/pie/Makefile | 5 ++--- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index 1d2230c26..670654e0e 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -3,6 +3,7 @@ include $(SRC_DIR)/Makefile.versions COMPEL_SO_VERSION := $(COMPEL_SO_VERSION_MAJOR)$(if $(COMPEL_SO_VERSION_MINOR),.$(COMPEL_SO_VERSION_MINOR))$(if $(COMPEL_SO_VERSION_SUBLEVEL),.$(COMPEL_SO_VERSION_SUBLEVEL)) COMPEL_SO_VERSION_CODE := $(shell expr $(COMPEL_SO_VERSION_MAJOR) \* 65536 \+ $(COMPEL_SO_VERSION_MINOR) \* 256 \+ $(COMPEL_SO_VERSION_SUBLEVEL)) ccflags-y += -DINCLUDEDIR=\"$(INCLUDEDIR)\" +ccflags-y += -DLIBEXECDIR=\"$(LIBEXECDIR)\" ccflags-y += -iquote compel/arch/$(ARCH)/src/lib/include ccflags-y += -iquote compel/include ccflags-y += -fno-strict-aliasing diff --git a/compel/src/main.c b/compel/src/main.c index f91fe2729..cd4753c1c 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -25,22 +25,27 @@ #define COMPEL_CFLAGS_PIE CFLAGS_DEFAULT_SET "-fpie" #define COMPEL_CFLAGS_NOPIC CFLAGS_DEFAULT_SET "-fno-pic" -#define COMPEL_LDFLAGS_DEFAULT "-r -z noexecstack" +#define COMPEL_LDFLAGS_COMMON "-r -z noexecstack -T " typedef struct { + const char *arch; // dir name under arch/ const char *cflags; const char *cflags_compat; } flags_t; static const flags_t flags = { #if defined CONFIG_X86_64 + .arch = "x86", .cflags = COMPEL_CFLAGS_PIE, .cflags_compat = COMPEL_CFLAGS_NOPIC, #elif defined CONFIG_AARCH64 + .arch = "aarch64", .cflags = COMPEL_CFLAGS_PIE, #elif defined(CONFIG_ARMV6) || defined(CONFIG_ARMV7) + .arch = "arm", .cflags = COMPEL_CFLAGS_PIE, #elif defined CONFIG_PPC64 + .arch = "ppc64", .cflags = COMPEL_CFLAGS_PIE, #else #error "CONFIG_ not defined, or unsupported ARCH" @@ -160,6 +165,23 @@ static void print_cflags(bool compat) print_includes(); } +static void print_ldflags(bool compat) +{ + const char *compat_str = (compat) ? "-compat" : ""; + + printf("%s", COMPEL_LDFLAGS_COMMON); + + if (uninst_root) { + printf("%s/arch/%s/scripts/compel-pack%s.lds.S\n", + uninst_root, flags.arch, compat_str); + } + else { + printf("%s/compel/scripts/compel-pack%s.lds.S\n", + LIBEXECDIR, compat_str); + + } +} + int main(int argc, char *argv[]) { int log_level = DEFAULT_LOGLEVEL; @@ -234,7 +256,7 @@ int main(int argc, char *argv[]) } if (!strcmp(action, "ldflags")) { - printf("%s", COMPEL_LDFLAGS_DEFAULT); + print_ldflags(compat); return 0; } diff --git a/compel/test/infect/Makefile b/compel/test/infect/Makefile index 8d35c2967..e08fa7941 100644 --- a/compel/test/infect/Makefile +++ b/compel/test/infect/Makefile @@ -1,9 +1,7 @@ CC := gcc CFLAGS ?= -O2 -g -Wall -Werror -ARCH ?= x86 COMPEL := ../../../compel/compel-host -COMPEL_PACK_LDS := ../../../compel/arch/$(ARCH)/scripts/compel-pack.lds.S COMPEL_PLUGINS := ../../../compel/plugins COMPEL_LIBRARY := ../../../compel/libcompel.a @@ -28,7 +26,7 @@ parasite.h: parasite.po -o $@ parasite.po: parasite.o $(COMPEL_PLUGINS)/std.built-in.o - ld -r -T $(COMPEL_PACK_LDS) -o $@ $^ + ld $(shell $(COMPEL) ldflags) -o $@ $^ parasite.o: parasite.c $(CC) $(CFLAGS) -c $(shell $(COMPEL) cflags) -o $@ $^ diff --git a/criu/pie/Makefile b/criu/pie/Makefile index f75d166fa..b5a08de5f 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -1,6 +1,5 @@ target += parasite restorer -compel_lds := $(SRC_DIR)/compel/arch/$(ARCH)/scripts/compel-pack.lds.S compel_std := $(SRC_DIR)/compel/plugins/std.built-in.o parasite-obj-e += ./compel/plugins/std.built-in.o restorer-obj-e += ./compel/plugins/std.built-in.o @@ -57,9 +56,9 @@ endif $(obj)/restorer.built-in.o: $(compel_std) $(obj)/parasite.built-in.o: $(compel_std) -$(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/pie.lib.a $(compel_lds) +$(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/pie.lib.a $(call msg-gen, $@) - $(Q) $(LD) -r -T $(compel_lds) -o $@ $< $(obj)/pie.lib.a + $(Q) $(LD) $(shell $(COMPEL_BIN) ldflags) -o $@ $< $(obj)/pie.lib.a $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host-bin $(call msg-gen, $@) From d4ddc01654035900f7d4dbbde1ec06ee15062f56 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:12 -0800 Subject: [PATCH 0318/4375] compel/Makefile: install to bin not sbin compel tool doesn't need to be run as root, so it makes no sense to install it to SBINDIR. Fix to use BINDIR. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index 670654e0e..8920281fb 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -59,8 +59,8 @@ cleanup-y += compel/libcompel.so install: compel/compel compel/$(LIBCOMPEL_SO) compel/$(LIBCOMPEL_A) $(E) " INSTALL " compel - $(Q) mkdir -p $(DESTDIR)$(SBINDIR) - $(Q) install -m 755 compel/compel $(DESTDIR)$(SBINDIR) + $(Q) mkdir -p $(DESTDIR)$(BINDIR) + $(Q) install -m 755 compel/compel $(DESTDIR)$(BINDIR) $(E) " INSTALL " $(LIBCOMPEL_SO) $(Q) mkdir -p $(DESTDIR)$(LIBDIR) $(Q) install -m 0644 compel/$(LIBCOMPEL_SO) $(DESTDIR)$(LIBDIR) @@ -80,7 +80,7 @@ install: compel/compel compel/$(LIBCOMPEL_SO) compel/$(LIBCOMPEL_A) uninstall: $(E) " UNINSTALL" compel - $(Q) $(RM) $(addprefix $(DESTDIR)$(SBINDIR)/,compel) + $(Q) $(RM) $(addprefix $(DESTDIR)$(BINDIR)/,compel) $(E) " UNINSTALL" $(LIBCOMPEL_SO) $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBDIR)/,$(LIBCOMPEL_SO)) $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBDIR)/,$(LIBCOMPEL_SO).$(COMPEL_SO_VERSION_MAJOR)) From 24aa5f4b0443d552c37edbde122463cabc8b81d8 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:13 -0800 Subject: [PATCH 0319/4375] criu/pie/Makefile: a nitpick Since commit 656710e the list of prerequisites are the same as the list of objects, so we can use $^ to avoid repetition. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index b5a08de5f..53acdcdc8 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -58,7 +58,7 @@ $(obj)/restorer.built-in.o: $(compel_std) $(obj)/parasite.built-in.o: $(compel_std) $(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/pie.lib.a $(call msg-gen, $@) - $(Q) $(LD) $(shell $(COMPEL_BIN) ldflags) -o $@ $< $(obj)/pie.lib.a + $(Q) $(LD) $(shell $(COMPEL_BIN) ldflags) -o $@ $^ $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host-bin $(call msg-gen, $@) From 616c6d172a0062bc9ef679e7c09a8025cb5f1410 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:14 -0800 Subject: [PATCH 0320/4375] compel/test/infect/Makefile: fix a dependency Commit 8173ea2 ("compel/test/infect/Makefile: don't add .h to sources") was a bad one as it removed dependency between parasite.h and spy binary. Fix it. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/test/infect/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/test/infect/Makefile b/compel/test/infect/Makefile index e08fa7941..4ad8fd010 100644 --- a/compel/test/infect/Makefile +++ b/compel/test/infect/Makefile @@ -17,8 +17,8 @@ clean: victim: victim.c $(CC) $(CFLAGS) -o $@ $^ -spy: spy.c | parasite.h - $(CC) $(CFLAGS) $(shell $(COMPEL) includes) -o $@ $^ $(COMPEL_LIBRARY) +spy: spy.c parasite.h + $(CC) $(CFLAGS) $(shell $(COMPEL) includes) -o $@ $< $(COMPEL_LIBRARY) parasite.h: parasite.po $(COMPEL) hgen -f $^ -l 4 \ From 7ad7ee4d6cd8fa3b5fc8057f85f0e3983cf6e97e Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:15 -0800 Subject: [PATCH 0321/4375] compel cli: add plugins cmd, use it A compel user should not be aware of compel internals, including the paths to various files. This commit introduces a command to get the plugin files (well, currently just one plugin, "std"). Example for uninstalled compel: $ cd compel/test/infect/ $ ../../../compel/compel-host plugins ../../../compel/plugins/std.built-in Example for installed compel: $ compel plugins /usr/libexec/compel/std.built-in.o The commit also makes use of this command by compel/test/infect and criu/pie. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 22 +++++++++++++++++++++- compel/test/infect/Makefile | 5 ++--- criu/pie/Makefile | 2 +- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index cd4753c1c..2d2351753 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -120,7 +120,7 @@ static int usage(int rc) { fprintf(out, "Usage:\n" -" compel [--compat] includes | cflags | ldflags\n" +" compel [--compat] includes | cflags | ldflags | plugins\n" " compel -f FILE -o FILE -p NAME [-l N] hgen\n" " -f, --file FILE input (parasite object) file name\n" " -o, --output FILE output (header) file name\n" @@ -182,12 +182,25 @@ static void print_ldflags(bool compat) } } +static void print_plugins(const char *list[]) +{ + while (*list != NULL) { + if (uninst_root) + printf("%s/plugins/%s.built-in.o\n", + uninst_root, *list); + else + printf("%s/compel/%s.built-in.o\n", LIBEXECDIR, *list); + list++; + } +} + int main(int argc, char *argv[]) { int log_level = DEFAULT_LOGLEVEL; bool compat = false; int opt, idx; char *action; + const char *plugins_list[] = { "std", NULL }; static const char short_opts[] = "cf:o:p:hVl:"; static struct option long_opts[] = { @@ -260,6 +273,13 @@ int main(int argc, char *argv[]) return 0; } + if (!strcmp(action, "plugins")) { + /* TODO: add option to specify additional plugins + * if/when we'll have any */ + print_plugins(plugins_list); + return 0; + } + if (!strcmp(action, "hgen")) { if (!opts.input_filename) { fprintf(stderr, "Error: option --file required\n"); diff --git a/compel/test/infect/Makefile b/compel/test/infect/Makefile index 4ad8fd010..e9b96ddfd 100644 --- a/compel/test/infect/Makefile +++ b/compel/test/infect/Makefile @@ -2,7 +2,6 @@ CC := gcc CFLAGS ?= -O2 -g -Wall -Werror COMPEL := ../../../compel/compel-host -COMPEL_PLUGINS := ../../../compel/plugins COMPEL_LIBRARY := ../../../compel/libcompel.a all: victim spy @@ -25,8 +24,8 @@ parasite.h: parasite.po -p parasite \ -o $@ -parasite.po: parasite.o $(COMPEL_PLUGINS)/std.built-in.o - ld $(shell $(COMPEL) ldflags) -o $@ $^ +parasite.po: parasite.o + ld $(shell $(COMPEL) ldflags) -o $@ $^ $(shell $(COMPEL) plugins) parasite.o: parasite.c $(CC) $(CFLAGS) -c $(shell $(COMPEL) cflags) -o $@ $^ diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 53acdcdc8..ca4f80d65 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -1,6 +1,5 @@ target += parasite restorer -compel_std := $(SRC_DIR)/compel/plugins/std.built-in.o parasite-obj-e += ./compel/plugins/std.built-in.o restorer-obj-e += ./compel/plugins/std.built-in.o @@ -36,6 +35,7 @@ ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) CFLAGS += $(shell $(COMPEL_BIN) cflags) + compel_std := $(shell $(COMPEL_BIN) plugins) endif ifeq ($(SRCARCH),arm) From ad2e322204d91af104eccbb1f0e6ea24afa6a5d3 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:16 -0800 Subject: [PATCH 0322/4375] compel cli: add libs command, use it Add "compel libs" that prints the list of libraries needed to link the parasite loader. Make compel/test/ and criu/ to use it. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/Makefile | 3 +++ compel/src/main.c | 30 +++++++++++++++++++++++++++++- compel/test/infect/Makefile | 3 +-- compel/test/rsys/Makefile | 3 +-- criu/Makefile | 3 ++- 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index 8920281fb..204e19f0c 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -4,6 +4,9 @@ COMPEL_SO_VERSION := $(COMPEL_SO_VERSION_MAJOR)$(if $(COMPEL_SO_VERSION_MINOR),. COMPEL_SO_VERSION_CODE := $(shell expr $(COMPEL_SO_VERSION_MAJOR) \* 65536 \+ $(COMPEL_SO_VERSION_MINOR) \* 256 \+ $(COMPEL_SO_VERSION_SUBLEVEL)) ccflags-y += -DINCLUDEDIR=\"$(INCLUDEDIR)\" ccflags-y += -DLIBEXECDIR=\"$(LIBEXECDIR)\" +ccflags-y += -DLIBDIR=\"$(LIBDIR)\" +ccflags-y += -DSTATIC_LIB=\"$(LIBCOMPEL_A)\" +ccflags-y += -DDYN_LIB=\"$(LIBCOMPEL_SO).$(COMPEL_SO_VERSION_MAJOR)\" ccflags-y += -iquote compel/arch/$(ARCH)/src/lib/include ccflags-y += -iquote compel/include ccflags-y += -fno-strict-aliasing diff --git a/compel/src/main.c b/compel/src/main.c index 2d2351753..2bfb37f8c 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -121,6 +121,7 @@ static int usage(int rc) { fprintf(out, "Usage:\n" " compel [--compat] includes | cflags | ldflags | plugins\n" +" compel [--compat] [--static] libs\n" " compel -f FILE -o FILE -p NAME [-l N] hgen\n" " -f, --file FILE input (parasite object) file name\n" " -o, --output FILE output (header) file name\n" @@ -194,17 +195,37 @@ static void print_plugins(const char *list[]) } } +static int print_libs(bool is_static) +{ + if (uninst_root) { + if (!is_static) { + fprintf(stderr, "Compel is not installed, can " + "only link with static libraries " + "(use --static)\n"); + return 1; + } + printf("%s/%s\n", uninst_root, STATIC_LIB); + } + else { + printf("%s/%s\n", LIBDIR, (is_static) ? STATIC_LIB : DYN_LIB); + } + + return 0; +} + int main(int argc, char *argv[]) { int log_level = DEFAULT_LOGLEVEL; bool compat = false; + bool is_static = false; int opt, idx; char *action; const char *plugins_list[] = { "std", NULL }; - static const char short_opts[] = "cf:o:p:hVl:"; + static const char short_opts[] = "csf:o:p:hVl:"; static struct option long_opts[] = { { "compat", no_argument, 0, 'c' }, + { "static", no_argument, 0, 's' }, { "file", required_argument, 0, 'f' }, { "output", required_argument, 0, 'o' }, { "prefix", required_argument, 0, 'p' }, @@ -225,6 +246,9 @@ int main(int argc, char *argv[]) case 'c': compat = true; break; + case 's': + is_static = true; + break; case 'f': opts.input_filename = optarg; break; @@ -280,6 +304,10 @@ int main(int argc, char *argv[]) return 0; } + if (!strcmp(action, "libs")) { + return print_libs(is_static); + } + if (!strcmp(action, "hgen")) { if (!opts.input_filename) { fprintf(stderr, "Error: option --file required\n"); diff --git a/compel/test/infect/Makefile b/compel/test/infect/Makefile index e9b96ddfd..fa966ac75 100644 --- a/compel/test/infect/Makefile +++ b/compel/test/infect/Makefile @@ -2,7 +2,6 @@ CC := gcc CFLAGS ?= -O2 -g -Wall -Werror COMPEL := ../../../compel/compel-host -COMPEL_LIBRARY := ../../../compel/libcompel.a all: victim spy @@ -17,7 +16,7 @@ victim: victim.c $(CC) $(CFLAGS) -o $@ $^ spy: spy.c parasite.h - $(CC) $(CFLAGS) $(shell $(COMPEL) includes) -o $@ $< $(COMPEL_LIBRARY) + $(CC) $(CFLAGS) $(shell $(COMPEL) includes) -o $@ $< $(shell $(COMPEL) --static libs) parasite.h: parasite.po $(COMPEL) hgen -f $^ -l 4 \ diff --git a/compel/test/rsys/Makefile b/compel/test/rsys/Makefile index 3c5ef5bba..3babda18f 100644 --- a/compel/test/rsys/Makefile +++ b/compel/test/rsys/Makefile @@ -2,7 +2,6 @@ CC := gcc CFLAGS ?= -O2 -g -Wall -Werror COMPEL := ../../../compel/compel-host -COMPEL_LIBRARY := ../../../compel/libcompel.a all: victim spy @@ -14,4 +13,4 @@ victim: victim.c $(CC) $(CFLAGS) -o $@ $^ spy: spy.c - $(CC) $(CFLAGS) $(shell $(COMPEL) includes) -o $@ $^ $(COMPEL_LIBRARY) + $(CC) $(CFLAGS) $(shell $(COMPEL) includes) -o $@ $^ $(shell $(COMPEL) --static libs) diff --git a/criu/Makefile b/criu/Makefile index c44d3b0a2..969716803 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -9,6 +9,7 @@ export ARCH_DIR PIE_DIR ifeq ($(filter clean mrproper,$(MAKECMDGOALS)),) COMPEL_UAPI_INCLUDES := $(shell $(COMPEL_BIN) includes) export COMPEL_UAPI_INCLUDES + COMPEL_LIBS := $(shell $(COMPEL_BIN) --static libs) endif # @@ -65,7 +66,7 @@ PROGRAM-BUILTINS += images/built-in.o PROGRAM-BUILTINS += $(obj)/built-in.o PROGRAM-BUILTINS += $(ARCH-LIB) PROGRAM-BUILTINS += soccr/libsoccr.a -PROGRAM-BUILTINS += compel/libcompel.a +PROGRAM-BUILTINS += $(COMPEL_LIBS) $(obj)/built-in.o: pie $(Q) $(MAKE) $(call build-as,Makefile.crtools,criu) all From 2e9ae927841bbd7debdb13a51ae3a379bd691309 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 17 Dec 2016 03:22:17 -0800 Subject: [PATCH 0323/4375] compel cli: make -p optional Yet another nail in the coffin of compel cli usage complexity. Since commit cd1c9d9 ("compel: simplify usage wrt ids") landed, it became obvious that the newly introduced -p option can be made optional. First, prefix value is not very important; second, it can be easily generated from the input (or output) file name. This is what this commit does, also trying to check that the resulting prefix is adeqate for using in C code. In case it is not (say, file names used are 1.po 1.h), an error is printed, suggesting to use --prefix. The commit also makes use of this functionality by removing -p option from compel/test/infect and criu/pie Makefiles. While at it, let's also remove -l 4 and the kludge of hiding it. If the output generated by this is ever needed, one can easily run "compel hgen -l4 ..." manually. travis-ci: success for More polishing for compel cli Signed-off-by: Kir Kolyshkin Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/main.c | 81 +++++++++++++++++++++++++++++++++++-- compel/test/infect/Makefile | 4 +- criu/pie/Makefile | 9 +---- 3 files changed, 80 insertions(+), 14 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index 2bfb37f8c..33dc2aa57 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -122,7 +123,7 @@ static int usage(int rc) { "Usage:\n" " compel [--compat] includes | cflags | ldflags | plugins\n" " compel [--compat] [--static] libs\n" -" compel -f FILE -o FILE -p NAME [-l N] hgen\n" +" compel -f FILE -o FILE [-p NAME] [-l N] hgen\n" " -f, --file FILE input (parasite object) file name\n" " -o, --output FILE output (header) file name\n" " -p, --prefix NAME prefix for var names\n" @@ -213,6 +214,73 @@ static int print_libs(bool is_static) return 0; } +/* Extracts the file name (removing directory path and suffix, + * and checks the result for being a valid C identifier + * (replacing - with _ along the way). + * + * If everything went fine, return the resulting string, + * otherwise NULL. + * + * Example: get_prefix("./some/path/to/file.c") ==> "file" + */ +static char *gen_prefix(const char *path) +{ + const char *p1 = NULL, *p2 = NULL; + size_t len; + int i; + char *p, *ret; + + len = strlen(path); + if (len == 0) + return NULL; + + // Find the last slash (p1) + // and the first dot after it (p2) + for (i = len - 1; i >= 0; i--) { + if (!p1 && path[i] == '.') { + p2 = path + i - 1; + } + else if (!p1 && path[i] == '/') { + p1 = path + i + 1; + break; + } + } + + if (!p1) // no slash in path + p1 = path; + if (!p2) // no dot (after slash) + p2 = path + len; + + len = p2 - p1 + 1; + if (len < 1) + return NULL; + + ret = strndup(p1, len); + + // Now, check if we got a valid C identifier. We don't need to care + // about C reserved keywords, as this is only used as a prefix. + for (p = ret; *p != '\0'; p++) { + if (isalpha(*p)) + continue; + // digit is fine, except the first character + if (isdigit(*p) && p > ret) + continue; + // only allowed special character is _ + if (*p == '_') + continue; + // as a courtesy, replace - with _ + if (*p == '-') { + *p = '_'; + continue; + } + // invalid character! + free(ret); + return NULL; + } + + return ret; +} + int main(int argc, char *argv[]) { int log_level = DEFAULT_LOGLEVEL; @@ -318,8 +386,15 @@ int main(int argc, char *argv[]) return usage(1); } if (!opts.prefix) { - fprintf(stderr, "Error: option --prefix required\n"); - return usage(1); + // prefix not provided, let's autogenerate + opts.prefix = gen_prefix(opts.input_filename); + if (!opts.prefix) + opts.prefix = gen_prefix(opts.output_filename); + if (!opts.prefix) { + fprintf(stderr, "Error: can't autogenerate " + "prefix (supply --prefix)"); + return 2; + } } compel_log_init(&cli_log, log_level); return piegen(); diff --git a/compel/test/infect/Makefile b/compel/test/infect/Makefile index fa966ac75..4dedf33c9 100644 --- a/compel/test/infect/Makefile +++ b/compel/test/infect/Makefile @@ -19,9 +19,7 @@ spy: spy.c parasite.h $(CC) $(CFLAGS) $(shell $(COMPEL) includes) -o $@ $< $(shell $(COMPEL) --static libs) parasite.h: parasite.po - $(COMPEL) hgen -f $^ -l 4 \ - -p parasite \ - -o $@ + $(COMPEL) hgen -o $@ -f $< parasite.po: parasite.o ld $(shell $(COMPEL) ldflags) -o $@ $^ $(shell $(COMPEL) plugins) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index ca4f80d65..320e70c90 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -50,10 +50,6 @@ BLOBS += $(obj)/restorer-blob.h $(obj)/parasite-blob.h target-name = $(patsubst criu/pie/%-blob.h,%,$(1)) -ifeq ($(strip $(V)),) - piegen_stdout := >/dev/null -endif - $(obj)/restorer.built-in.o: $(compel_std) $(obj)/parasite.built-in.o: $(compel_std) $(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/pie.lib.a @@ -62,10 +58,7 @@ $(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/pie.lib.a $(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host-bin $(call msg-gen, $@) - $(Q) $(COMPEL_BIN) hgen -f $< \ - -l 4 \ - -p $(call target-name,$@) \ - -o $@ $(piegen_stdout) + $(Q) $(COMPEL_BIN) hgen -f $< -o $@ all-y += $(BLOBS) # blobs and pields are in cleanup, rather than in mrproper because From 4464274c1f7c305fb2118f0f28726ed6c6966857 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 23 Dec 2016 12:05:00 +0300 Subject: [PATCH 0324/4375] .gitignore: Add compel and common asm symlinks travis-ci: success for .gitignore: Add compel and common asm symlinks Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index f54248c6a..3aaead18b 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,5 @@ lib/build/ lib/c/criu.pc scripts/build/qemu-user-static/* lib/.crit-setup.files +compel/include/asm +include/common/asm From 6e70d6941e15677d68ea94363ed2dbb38ee18893 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 7 Jan 2017 15:52:49 -0800 Subject: [PATCH 0325/4375] criu/Makefile: fix rebuilding criu/pie/pie.lib.a As reported by Andrei Vagin: touch criu/pie/parasite-vdso.c does not lead to rebuild pie.lib.a and its dependencies. This happened because the real dependencies of criu/pie/pie.lib.a are listed in criu/pie/Makefile.library, which is never included or called with sub-make, because the criu/Makefile says: criu/pie/pie.lib.a: $(ARCH-LIB) $(Q) $(MAKE) $(call build-as,Makefile.library,criu/pie) all essentially saying we only need to call a sub-make with Makefile.library if the target is absent, or $(ARCH-LIB) is newer than the target. A workaround is to use .FORCE so that the Makefile.library is always called and so the dependencies are checked. Note the above is also true for any target that involves calling a sub-make -- it should either be used with .FORCE or otherwise depend on a phony target. I haven't checked all the CRIU makefiles but suspect there might be more cases like this one. travis-ci: success for Makefiles: fix deps checking Cc: Cyrill Gorcunov Reported-by: Andrei Vagin Signed-off-by: Kir Kolyshkin Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/criu/Makefile b/criu/Makefile index 969716803..ccf77805e 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -1,3 +1,5 @@ +.PHONY: .FORCE + # here is a workaround for a bug in libnl-3: # 6a8d90f5fec4 "attr: Allow attribute type 0" WRAPFLAGS += -Wl,--wrap=nla_parse,--wrap=nlmsg_parse @@ -47,7 +49,7 @@ $(ARCH-LIB): # # PIE library code. -criu/pie/pie.lib.a: $(ARCH-LIB) +criu/pie/pie.lib.a: $(ARCH-LIB) .FORCE $(Q) $(MAKE) $(call build-as,Makefile.library,criu/pie) all # From 983ed43f516dc75c0d650deb4db5eed89acd0d60 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 7 Jan 2017 15:52:50 -0800 Subject: [PATCH 0326/4375] criu/Makefile: fix criu/arch/* rebuild Problem: if we do touch criu/arch/x86/cpu.c nothing is being rebuilt. For detailed analisys, see the previous commit ("criu/Makefile: fix rebuilding criu/pie/pie.lib.a"). Note there are other targets in criu/Makefile where one might want to add .FORCE to, but it's not needed as they all depend on another target which itself is marked as .PHONY. travis-ci: success for Makefiles: fix deps checking Signed-off-by: Kir Kolyshkin Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/Makefile b/criu/Makefile index ccf77805e..5c19d0af2 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -44,7 +44,7 @@ include $(SRC_DIR)/criu/Makefile.packages # # Architecture dependent part. ARCH-LIB := $(ARCH_DIR)/crtools.built-in.o -$(ARCH-LIB): +$(ARCH-LIB): .FORCE $(Q) $(MAKE) $(build)=$(ARCH_DIR) all # From e84d24d9f272748d28c4c725e155a9858e067bcf Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 9 Jan 2017 10:48:00 +0300 Subject: [PATCH 0327/4375] zdtm: handle COMPAT_TEST from Makefile.inc In this case it will work for any make commangs. For example: make COMPAT_TEST=y -C test/zdtm/lib travis-ci: success for zdtm: handle COMPAT_TEST from Makefile.inc Cc: Dmitry Safonov Signed-off-by: Andrei Vagin Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov --- test/zdtm/Makefile | 8 -------- test/zdtm/Makefile.inc | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/zdtm/Makefile b/test/zdtm/Makefile index 2566a925e..8abf2144d 100644 --- a/test/zdtm/Makefile +++ b/test/zdtm/Makefile @@ -1,13 +1,5 @@ SUBDIRS = lib static transition -ifeq ($(COMPAT_TEST),y) -ifeq ($(ARCH),x86) - export USERCFLAGS += -m32 - export CFLAGS += -m32 - export LDFLAGS += -m32 -endif -endif - default: all .PHONY: default lib static transition diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index 074e39bd8..ef7c1b81a 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -30,4 +30,12 @@ endif RM := rm -f --one-file-system +ifeq ($(COMPAT_TEST),y) +ifeq ($(ARCH),x86) + export USERCFLAGS += -m32 + export CFLAGS += -m32 + export LDFLAGS += -m32 +endif +endif + export E Q RM From dd6736bd247905484df37335108c7299959868e5 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 9 Jan 2017 20:19:06 +0300 Subject: [PATCH 0328/4375] compel/x86/compat: pack ucontext_ia32 As I've united k_rtsigset_t between native and compat ucontext's, it's 8-bytes aligned now. We don't care about align of this as we fill it always with memcpy()/memset(0). So after those changes, ucontext_ia32 has received new padding between uc_mcontext and uc_sigmask (4 bytes to align to 8-byte sized sigmask). Because of this, mask of blocked signals was restored with shift (wrongly). Fixes: signalfd00, file_attr tests. travis-ci: success for 32-bit tests fixes Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/include/uapi/asm/sigframe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h index e9357002c..a939bbee1 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h @@ -99,7 +99,7 @@ struct ucontext_ia32 { compat_stack_t uc_stack; struct rt_sigcontext_32 uc_mcontext; k_rtsigset_t uc_sigmask; /* mask last for extensibility */ -}; +} __packed; struct rt_sigframe_ia32 { uint32_t pretcode; From 08cbdefb020f4d575fd940865245ebdc5b33abcf Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 9 Jan 2017 20:19:07 +0300 Subject: [PATCH 0329/4375] x86/compat: don't set has_compat_sigreturn if !CONFIG_COMPAT We can be on v4.9 or newer kernel, but have no 32-bit multilib toolchain, which will result in !CONFIG_COMPAT but kdat_compat_sigreturn_test() will return true as we have new arch_prctls in kernel needed for compatible C/R. Fail compat test in this case. travis-ci: success for 32-bit tests fixes Reported-by: Andrei Vagin Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index ba0145b27..0c3851adc 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -30,6 +30,7 @@ #ifdef CONFIG_X86_64 int kdat_compat_sigreturn_test(void) { +#ifdef CONFIG_COMPAT unsigned long auxval; int ret; @@ -46,6 +47,7 @@ int kdat_compat_sigreturn_test(void) ret = syscall(SYS_arch_prctl, ARCH_MAP_VDSO_32, 1); if (ret == -1 && errno == EEXIST) return 1; +#endif return 0; } #endif /* CONFIG_X86_64 */ From be783a3768ca0082314b4f012e580fc4551619e4 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 9 Jan 2017 20:19:08 +0300 Subject: [PATCH 0330/4375] compel/x86: hang in 32-bit mode on sw-break for compat tasks Otherwise we'll try to set 32-bit register set to 64-bit task, which is not possible with ptrace - it uses register set size, according to processes mode. So we should set 32-bit regset only to tasks those are in 32-bit mode already. Please, see inline comment in the patch for more info. travis-ci: success for 32-bit tests fixes Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/x86/plugins/std/parasite-head.S | 42 +++++++++++++++------ 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/compel/arch/x86/plugins/std/parasite-head.S b/compel/arch/x86/plugins/std/parasite-head.S index 2757828cf..bdb56c877 100644 --- a/compel/arch/x86/plugins/std/parasite-head.S +++ b/compel/arch/x86/plugins/std/parasite-head.S @@ -6,17 +6,7 @@ # error 64-bit parasite should compile with CONFIG_X86_64 #endif -#ifdef CONFIG_COMPAT -.code32 -ENTRY(__export_parasite_head_start_compat) - /* A long jump to 64-bit parasite. */ - jmp $__USER_CS,$__export_parasite_head_start - int $0x03 -END(__export_parasite_head_start_compat) -.code64 -#endif - -ENTRY(__export_parasite_head_start) +.macro PARASITE_ENTRY subq $16, %rsp andq $~15, %rsp pushq $0 @@ -24,6 +14,36 @@ ENTRY(__export_parasite_head_start) movl __export_parasite_cmd(%rip), %edi leaq __export_parasite_args(%rip), %rsi call parasite_service +.endm + +#ifdef CONFIG_COMPAT +.code32 +ENTRY(__export_parasite_head_start_compat) + /* A long jump to 64-bit parasite. */ + jmp $__USER_CS,$1f +1: +.code64 + PARASITE_ENTRY + pushq $__USER32_CS + pushq $2f + lretq +2: +.code32 + /* + * parasite_service() can run commands in non-daemon mode + * with parasite_trap_cmd(): it waits that after return there + * is a software break. + * compel_run_in_thread() uses this and after hitting the break, + * it restores register set - that's the reason, why we should + * stop in 32-bit mode for compat tasks here. + */ + int $0x03 +END(__export_parasite_head_start_compat) +.code64 +#endif + +ENTRY(__export_parasite_head_start) + PARASITE_ENTRY int $0x03 END(__export_parasite_head_start) From cbde93e12e7029799a0cfc54a29d798f6a767be5 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 9 Jan 2017 20:19:09 +0300 Subject: [PATCH 0331/4375] compel/x86: clang-3.4 isn't a friend to numbers in macro It's a workaround to clang-3.4, which doesn't handle numbers in asm macros rightly: https://llvm.org/bugs/show_bug.cgi?id=21500 Which resulted in: CC compel/arch/x86/plugins/std/parasite-head.o :3:2: error: too few operands for instruction pushq ^ compel/arch/x86/plugins/std/parasite-head.S:26:2: note: while in macro instantiation PARASITE_ENTRY ^ Fixes: https://travis-ci.org/0x7f454c46/criu/jobs/186099057 travis-ci: success for 32-bit tests fixes Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/x86/plugins/std/parasite-head.S | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compel/arch/x86/plugins/std/parasite-head.S b/compel/arch/x86/plugins/std/parasite-head.S index bdb56c877..a988de9d4 100644 --- a/compel/arch/x86/plugins/std/parasite-head.S +++ b/compel/arch/x86/plugins/std/parasite-head.S @@ -6,10 +6,10 @@ # error 64-bit parasite should compile with CONFIG_X86_64 #endif -.macro PARASITE_ENTRY +.macro PARASITE_ENTRY num subq $16, %rsp andq $~15, %rsp - pushq $0 + pushq $\num movq %rsp, %rbp movl __export_parasite_cmd(%rip), %edi leaq __export_parasite_args(%rip), %rsi @@ -23,7 +23,7 @@ ENTRY(__export_parasite_head_start_compat) jmp $__USER_CS,$1f 1: .code64 - PARASITE_ENTRY + PARASITE_ENTRY 0 pushq $__USER32_CS pushq $2f lretq @@ -43,7 +43,7 @@ END(__export_parasite_head_start_compat) #endif ENTRY(__export_parasite_head_start) - PARASITE_ENTRY + PARASITE_ENTRY 0 int $0x03 END(__export_parasite_head_start) From 2775c8f810235c0cb1bea8213296bdcacde2056b Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 9 Jan 2017 20:19:11 +0300 Subject: [PATCH 0332/4375] x86/restorer/compat: let stack32 be per-thread As threads restore in parallel, stack32 may be reused concurrently leading to reusing others thread's data. So, let it lay on stack. It would still worth making 32-bit stack per-task reusing it in threads but at this moment introducing such complexity looks like premature optimization. It does not affect 64-bit C/R. Fixes: file_aio, sigaltstack, clone_fs, socket_aio, different_creds, futex travis-ci: success for 32-bit tests fixes Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/restorer.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index 377a9186e..45107045d 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -33,23 +33,14 @@ int restore_nonsigframe_gpregs(UserX86RegsEntry *r) } #ifdef CONFIG_COMPAT -/* - * We need here compatible stack, because 32-bit syscalls get - * 4-byte pointer and _usally_ restorer is also under 4Gb, but - * it can be upper and then pointers are messed up. - * (we lose high 4 bytes and... BUNG!) - * Nothing serious, but syscall will return -EFAULT - or if we're - * lucky and lower 4 bytes points on some writeable VMA - corruption). - */ -static void *stack32; -static int prepare_stack32(void) +static int prepare_stack32(void **stack32) { - if (stack32) + if (*stack32) return 0; - stack32 = alloc_compat_syscall_stack(); - if (!stack32) { + *stack32 = alloc_compat_syscall_stack(); + if (!*stack32) { pr_err("Failed to allocate stack for 32-bit TLS restore\n"); return -1; } @@ -59,6 +50,15 @@ static int prepare_stack32(void) void restore_tls(tls_t *ptls) { + /* + * We need here compatible stack, because 32-bit syscalls get + * 4-byte pointer and _usally_ restorer is also under 4Gb, but + * it can be upper and then pointers are messed up. + * (we lose high 4 bytes and... BANG!) + * Nothing serious, but syscall will return -EFAULT - or if we're + * lucky and lower 4 bytes points on some writeable VMA - corruption). + */ + void *stack32 = NULL; unsigned i; for (i = 0; i < GDT_ENTRY_TLS_NUM; i++) { @@ -68,7 +68,7 @@ void restore_tls(tls_t *ptls) if (desc->seg_not_present) continue; - if (prepare_stack32() < 0) + if (prepare_stack32(&stack32) < 0) return; builtin_memcpy(stack32, desc, sizeof(user_desc_t)); From f5cad87d5b49238116e493980c837a95f8708158 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 10 Jan 2017 17:32:00 +0300 Subject: [PATCH 0333/4375] cr-check: add compat_cr check Initialy, I thought to name it "compat_restore", but after I've dropped the second 32-bit parasite (which surely made compat code lesser and easier), our parasite works in 64-bit in 32-bit task and ptrace() for setting registers in this long-jumped situation will work correctly only after v4.9 kernel. Maybe it can be work-arounded if needed, but yet no compatible dump for pre-v4.9 kernels. Requested-by: Andrei Vagin Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-check.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/criu/cr-check.c b/criu/cr-check.c index fc0c2e99d..c7304af6d 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -49,6 +49,7 @@ #include "cr_options.h" #include "libnetlink.h" #include "net.h" +#include "restorer.h" static char *feature_name(int (*func)()); @@ -1058,6 +1059,14 @@ static int check_loginuid(void) return 0; } +static int check_compat_cr(void) +{ + if (kdat_compat_sigreturn_test()) + return 0; + pr_warn("compat_cr is not supported. Requires kernel >= v4.9\n"); + return -1; +} + static int (*chk_feature)(void); /* @@ -1168,6 +1177,7 @@ int cr_check(void) */ if (opts.check_experimental_features) { ret |= check_autofs(); + ret |= check_compat_cr(); } print_on_level(DEFAULT_LOGLEVEL, "%s\n", ret ? CHECK_MAYBE : CHECK_GOOD); @@ -1208,6 +1218,7 @@ static struct feature_list feature_list[] = { { "cgroupns", check_cgroupns }, { "autofs", check_autofs }, { "tcp_half_closed", check_tcp_halt_closed }, + { "compat_cr", check_compat_cr }, { NULL, NULL }, }; From 6cacaa69d676dba8f807a644152c95da75f982f8 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 18 Jan 2017 19:26:00 +0300 Subject: [PATCH 0334/4375] x86/compat: fix error-check for compat mmap() Raw sys_mmap() returns address or error like -ENOMEM. Don't check MAP_FAILED, check that result is aligned by page. travis-ci: success for x86/compat: fix error-check for compat mmap() Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/include/asm/compat.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/criu/arch/x86/include/asm/compat.h b/criu/arch/x86/include/asm/compat.h index 8379af452..119768db3 100644 --- a/criu/arch/x86/include/asm/compat.h +++ b/criu/arch/x86/include/asm/compat.h @@ -16,8 +16,12 @@ static inline void *alloc_compat_syscall_stack(void) void *mem = (void*)sys_mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (mem == MAP_FAILED) + if ((uintptr_t)mem % PAGE_SIZE) { + int err = (~(uint32_t)(uintptr_t)mem) + 1; + + pr_err("mmap() of compat syscall stack failed with %d\n", err); return 0; + } return mem; } @@ -26,7 +30,7 @@ static inline void free_compat_syscall_stack(void *mem) long int ret = sys_munmap(mem, PAGE_SIZE); if (ret) - pr_err("munmap of compat addr %p failed with %ld", mem, ret); + pr_err("munmap() of compat addr %p failed with %ld", mem, ret); } #ifdef CONFIG_COMPAT From 86f811eb5c33aa10666c5d5a22c6bc88cc2238d9 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 19 Jan 2017 15:11:00 +0300 Subject: [PATCH 0335/4375] test/zdtm: use flock64 instead of flock For 32-bit fcntl() Glibc function calls sys_fcntl64(), which needs struct flock64, otherwise the kernel gets a wrong struct. For 64-bit, it's all the same. Also unset errno before fcntl() and check return value of the call. Cc: Qiang Huang Cc: Begunkov Pavel Cc: Pavel Emelyanov travis-ci: success for test/zdtm: use flock64 instead of flock Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/zdtm/static/file_locks00.c | 34 ++++++++++++++++++++++--------- test/zdtm/static/file_locks06.c | 4 ++-- test/zdtm/static/file_locks07.c | 4 ++-- test/zdtm/static/file_locks08.c | 4 ++-- test/zdtm/static/ofd_file_locks.h | 12 +++++------ 5 files changed, 36 insertions(+), 22 deletions(-) diff --git a/test/zdtm/static/file_locks00.c b/test/zdtm/static/file_locks00.c index f701e00c0..82888709e 100644 --- a/test/zdtm/static/file_locks00.c +++ b/test/zdtm/static/file_locks00.c @@ -24,24 +24,25 @@ char file1[PATH_MAX]; static int lock_reg(int fd, int cmd, int type, int whence, off_t offset, off_t len) { - struct flock lock; + struct flock64 lock; lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */ lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */ lock.l_start = offset; /* byte offset, relative to l_whence */ lock.l_len = len; /* #bytes (0 means to EOF) */ + errno = 0; return fcntl(fd, cmd, &lock); } #define set_read_lock(fd, whence, offset, len) \ - lock_reg(fd, F_SETLK, F_RDLCK, whence, offset, len) + lock_reg(fd, F_SETLK64, F_RDLCK, whence, offset, len) #define set_write_lock(fd, whence, offset, len) \ - lock_reg(fd, F_SETLK, F_WRLCK, whence, offset, len) + lock_reg(fd, F_SETLK64, F_WRLCK, whence, offset, len) static int check_read_lock(int fd, int whence, off_t offset, off_t len) { - struct flock lock; + struct flock64 lock; int ret; lock.l_type = F_RDLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */ @@ -50,7 +51,8 @@ static int check_read_lock(int fd, int whence, off_t offset, off_t len) lock.l_len = len; /* #bytes (0 means to EOF) */ lock.l_pid = -1; - ret = fcntl(fd, F_GETLK, &lock); + errno = 0; + ret = fcntl(fd, F_GETLK64, &lock); if (ret == -1) { pr_perror("F_GETLK failed."); return -1; @@ -67,7 +69,7 @@ static int check_read_lock(int fd, int whence, off_t offset, off_t len) static int check_write_lock(int fd, int whence, off_t offset, off_t len) { - struct flock lock; + struct flock64 lock; int ret; pid_t ppid = getppid(); @@ -78,7 +80,8 @@ static int check_write_lock(int fd, int whence, off_t offset, off_t len) lock.l_len = len; /* #bytes (0 means to EOF) */ lock.l_pid = -1; - ret = fcntl(fd, F_GETLK, &lock); + errno = 0; + ret = fcntl(fd, F_GETLK64, &lock); if (ret == -1) { pr_perror("F_GETLK failed."); return -1; @@ -129,7 +132,7 @@ static int check_file_locks() int main(int argc, char **argv) { - int fd_0, fd_1; + int fd_0, fd_1, ret; pid_t pid; test_init(argc, argv); @@ -168,8 +171,19 @@ int main(int argc, char **argv) exit(0); } - set_read_lock(fd_0, SEEK_SET, 0, 0); - set_write_lock(fd_1, SEEK_SET, 0, 0); + ret = set_read_lock(fd_0, SEEK_SET, 0, 0); + if (ret == -1) { + pr_perror("Failed to set read lock"); + kill(pid, SIGTERM); + return -1; + } + + ret = set_write_lock(fd_1, SEEK_SET, 0, 0); + if (ret == -1) { + pr_perror("Failed to set write lock"); + kill(pid, SIGTERM); + return -1; + } test_daemon(); test_waitsig(); diff --git a/test/zdtm/static/file_locks06.c b/test/zdtm/static/file_locks06.c index 2e1ba4370..8eafa7c58 100644 --- a/test/zdtm/static/file_locks06.c +++ b/test/zdtm/static/file_locks06.c @@ -14,7 +14,7 @@ char *filename; TEST_OPTION(filename, string, "file name", 1); -int init_lock(int *fd, struct flock *lck) +int init_lock(int *fd, struct flock64 *lck) { *fd = open(filename, O_RDWR | O_CREAT, 0666); if (*fd < 0) { @@ -47,7 +47,7 @@ void cleanup(int *fd) int main(int argc, char **argv) { int fd; - struct flock lck; + struct flock64 lck; test_init(argc, argv); if (init_lock(&fd, &lck)) diff --git a/test/zdtm/static/file_locks07.c b/test/zdtm/static/file_locks07.c index 1f946254a..25051b925 100644 --- a/test/zdtm/static/file_locks07.c +++ b/test/zdtm/static/file_locks07.c @@ -16,12 +16,12 @@ TEST_OPTION(filename, string, "file name", 1); #define FILE_NUM 4 static int fds[FILE_NUM]; -static struct flock lcks[FILE_NUM]; +static struct flock64 lcks[FILE_NUM]; static short types[] = {F_RDLCK, F_RDLCK, F_RDLCK, F_RDLCK}; static off_t starts[] = {0, 10, 0, 70}; static off_t lens[] = {20, 30, 100, 200}; -void fill_lock(struct flock *lock, off_t start, off_t len, short int type) +void fill_lock(struct flock64 *lock, off_t start, off_t len, short int type) { lock->l_start = start; lock->l_len = len; diff --git a/test/zdtm/static/file_locks08.c b/test/zdtm/static/file_locks08.c index aa26d8cff..7963704da 100644 --- a/test/zdtm/static/file_locks08.c +++ b/test/zdtm/static/file_locks08.c @@ -16,7 +16,7 @@ char *filename; TEST_OPTION(filename, string, "file name", 1); -int init_file_lock(int *fd, struct flock *lck) +int init_file_lock(int *fd, struct flock64 *lck) { *fd = open(filename, O_RDWR | O_CREAT, 0666); if (*fd < 0) { @@ -53,7 +53,7 @@ int main(int argc, char **argv) int status; int ret = 0; task_waiter_t tw; - struct flock lck; + struct flock64 lck; test_init(argc, argv); if (init_file_lock(&fd, &lck)) diff --git a/test/zdtm/static/ofd_file_locks.h b/test/zdtm/static/ofd_file_locks.h index 049401a9c..b2c249a9b 100644 --- a/test/zdtm/static/ofd_file_locks.h +++ b/test/zdtm/static/ofd_file_locks.h @@ -20,7 +20,7 @@ * from procfs and checking them after restoring. */ -static int parse_ofd_lock(char *buf, struct flock *lck) +static int parse_ofd_lock(char *buf, struct flock64 *lck) { char fl_flag[10], fl_type[15], fl_option[10], fl_end[32]; long long start; @@ -61,7 +61,7 @@ static int parse_ofd_lock(char *buf, struct flock *lck) return 0; } -static int read_fd_ofd_lock(int pid, int fd, struct flock *lck) +static int read_fd_ofd_lock(int pid, int fd, struct flock64 *lck) { char path[PATH_MAX]; char buf[100]; @@ -90,7 +90,7 @@ static int read_fd_ofd_lock(int pid, int fd, struct flock *lck) return num; } -static int check_lock_exists(const char *filename, struct flock *lck) +static int check_lock_exists(const char *filename, struct flock64 *lck) { int ret = -1; int fd; @@ -129,16 +129,16 @@ out: return ret; } -static int check_file_locks_match(struct flock *orig_lck, struct flock *lck) +static int check_file_locks_match(struct flock64 *orig_lck, struct flock64 *lck) { return orig_lck->l_start == lck->l_start && orig_lck->l_len == lck->l_len && orig_lck->l_type == lck->l_type; } -static int check_file_lock_restored(int pid, int fd, struct flock *lck) +static int check_file_lock_restored(int pid, int fd, struct flock64 *lck) { - struct flock lck_restored; + struct flock64 lck_restored; if (read_fd_ofd_lock(pid, fd, &lck_restored)) return -1; From a84e65a63b156ff74207fcb70268d1147ab8c828 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 19 Jan 2017 19:24:00 +0300 Subject: [PATCH 0336/4375] zdtm/test/rtc: build 64-bit criu-rtc.so It's library plugin to CRIU - it needs to be 64-bit. travis-ci: success for zdtm/test/rtc: build 64-bit criu-rtc.so Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 11d6d9500..067c1e576 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -483,6 +483,6 @@ criu-rtc.pb-c.c: criu-rtc.proto protoc-c --proto_path=. --c_out=. criu-rtc.proto criu-rtc.so: criu-rtc.c criu-rtc.pb-c.c - $(CC) -g -Wall -shared -nostartfiles criu-rtc.c criu-rtc.pb-c.c -o criu-rtc.so -iquote ../../../criu/include -fPIC $(USERCFLAGS) + $(CC) -g -Wall -shared -nostartfiles criu-rtc.c criu-rtc.pb-c.c -o criu-rtc.so -iquote ../../../criu/include -fPIC $(filter-out -m32,$(USERCFLAGS)) .PHONY: force clean cleandep cleanout realclean start check_start stop wait_stop From 1aea2b98d82d95ae2d1465a19fa0c2b79e3ee62b Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 20 Jan 2017 18:49:00 +0300 Subject: [PATCH 0337/4375] zdtm/sigpending/32: check only 12 bytes of _si_fields The kernel does touch only relevant union member on x86_32. travis-ci: success for zdtm/sigpending/32: check only 12 bytes of _si_fields Cc: Andrei Vagin Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/zdtm/static/sigpending.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/test/zdtm/static/sigpending.c b/test/zdtm/static/sigpending.c index d1dbd251d..70c2580a1 100644 --- a/test/zdtm/static/sigpending.c +++ b/test/zdtm/static/sigpending.c @@ -29,6 +29,26 @@ static int thread_nr; # define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif +#ifdef __i386__ +/* + * On x86_32 kernel puts only relevant union member when signal arrives, + * leaving _si_fields to be filled with junk from stack. Check only + * first 12 bytes: + * // POSIX.1b signals. + * struct + * { + * __pid_t si_pid; // Sending process ID. + * __uid_t si_uid; // Real user ID of sending process. + * sigval_t si_sigval; // Signal value. + * } _rt; + * Look at __copy_siginfo_to_user32() for more information. + */ +# define _si_fields_sz 12 +#else +# define _si_fields_sz (sizeof(siginfo_t) - offsetof(siginfo_t, _sifields)) +#endif +#define siginfo_filled (offsetof(siginfo_t, _sifields) + _si_fields_sz) + static pthread_mutex_t exit_lock; static pthread_mutex_t init_lock; @@ -71,13 +91,12 @@ static void sig_handler(int signal, siginfo_t *info, void *data) } crc = ~0; - if (datachk((uint8_t *) &info->_sifields, - sizeof(siginfo_t) - offsetof(siginfo_t, _sifields), &crc)) { + if (datachk((uint8_t *) &info->_sifields, _si_fields_sz, &crc)) { fail("CRC mismatch\n"); return; } - if (memcmp(info, src, sizeof(siginfo_t))) { + if (memcmp(info, src, siginfo_filled)) { fail("Source and received info are differ\n"); return; } @@ -154,8 +173,7 @@ int send_siginfo(int signo, pid_t pid, pid_t tid, int group, siginfo_t *info) info->si_code = si_code; si_code--; info->si_signo = signo; - datagen((uint8_t *) &info->_sifields, - sizeof(siginfo_t) - offsetof(siginfo_t, _sifields), &crc); + datagen((uint8_t *) &info->_sifields, _si_fields_sz, &crc); sent_sigs++; From 95817e952eba5baf19f5c6ac93e4309f5ec696c6 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 25 Jan 2017 12:46:19 +0300 Subject: [PATCH 0338/4375] compel: Define __sys_err-s for scm stuff Signed-off-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/plugins/std/fds.c | 1 + compel/src/lib/infect.c | 1 + 2 files changed, 2 insertions(+) diff --git a/compel/plugins/std/fds.c b/compel/plugins/std/fds.c index 8cfe6d288..a61bbfd2c 100644 --- a/compel/plugins/std/fds.c +++ b/compel/plugins/std/fds.c @@ -15,6 +15,7 @@ #include "common/bug.h" #define __sys(foo) sys_##foo +#define __sys_err(ret) ret #define __memcpy std_memcpy #include "common/scm-code.c" diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 599c37274..b8997a40d 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -30,6 +30,7 @@ #include "infect-util.h" #define __sys(foo) foo +#define __sys_err(ret) (-errno) #define __memcpy memcpy #include "common/scm.h" From 253f53ac8a21dc1cc274d365c1cb0d451b6f2f62 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 27 Jan 2017 17:11:00 +0300 Subject: [PATCH 0339/4375] make: regenerate blobs on linker script (lds) change travis-ci: success for make: regenerate blobs on linker script (lds) change Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 320e70c90..8666a3048 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -45,6 +45,7 @@ endif asflags-y += -D__ASSEMBLY__ BLOBS += $(obj)/restorer-blob.h $(obj)/parasite-blob.h +LDS := $(SRC_DIR)/compel/arch/$(SRCARCH)/scripts/compel-pack.lds.S .SECONDARY: @@ -52,7 +53,7 @@ target-name = $(patsubst criu/pie/%-blob.h,%,$(1)) $(obj)/restorer.built-in.o: $(compel_std) $(obj)/parasite.built-in.o: $(compel_std) -$(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/pie.lib.a +$(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/pie.lib.a $(LDS) $(call msg-gen, $@) $(Q) $(LD) $(shell $(COMPEL_BIN) ldflags) -o $@ $^ From b4aa7a37bd846eea62a08e1f0085e77fe97b1dd6 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 27 Jan 2017 19:08:00 +0300 Subject: [PATCH 0340/4375] criu/arch/x86/Makefile: move -Wa out of asflags In a manner similar to one of commit 9303ed3 ("Makefiles: move -Wa,--noexecstack out of CFLAGS"), let's move this option from assembler to linker flags (see the abovementioned commit for reasoning). This fixes generating dependencies for criu/arch/x86/call32.S when using clang: DEP criu/arch/x86/call32.d clang-3.8: error: argument unused during compilation: '-Wa,--noexecstack' DEP criu/arch/x86/call32.d clang-3.8: error: argument unused during compilation: '-Wa,--noexecstack' travis-ci: success for criu/arch/x86/Makefile: move -Wa out of asflags (rev2) Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index 1d29cb943..6bd5ac9cc 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -4,9 +4,10 @@ ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include ccflags-y += $(COMPEL_UAPI_INCLUDES) -asflags-y += -Wstrict-prototypes -Wa,--noexecstack +asflags-y += -Wstrict-prototypes asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer asflags-y += -iquote $(obj)/include +ldflags-y += -z noexecstack obj-y += cpu.o obj-y += crtools.o From 165cd1ee61f5d581710c2bc9e9c1729962f62804 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 27 Jan 2017 20:11:00 +0300 Subject: [PATCH 0341/4375] criu/pie: kill util-fd.c The functions it provides, send_fds() and receive_fds(), are already provided by compel/plugins/std.built-in.o (compel/plugins/std/fds.c) which is linked into both parasite and restorer. This fixes the following issue (for some reason, reported on ARMv7, see https://travis-ci.org/kolyshkin/criu/jobs/195367825): LINK criu/pie/parasite.built-in.o GEN criu/pie/parasite.built-in.bin.o criu/pie/pie.lib.a(util-fd.o): In function `send_fds': /criu/include/common/scm-code.c:56: multiple definition of `send_fds' criu/pie/parasite.built-in.o:/criu/include/common/scm-code.c:56: first defined here criu/pie/pie.lib.a(util-fd.o): In function `recv_fds': /criu/include/common/scm-code.c:79: multiple definition of `recv_fds' criu/pie/parasite.built-in.o:/criu/include/common/scm-code.c:79: first defined here criu/pie/Makefile:53: recipe for target 'criu/pie/parasite.built-in.bin.o' failed make[2]: *** [criu/pie/parasite.built-in.bin.o] Error 1 travis-ci: success for criu/pie: kill util-fd.c Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pie/Makefile.library | 2 +- criu/pie/util-fd.c | 27 --------------------------- 2 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 criu/pie/util-fd.c diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 7143050f4..3996d137b 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -3,7 +3,7 @@ lib-name := pie.lib.a CFLAGS += -fno-stack-protector -DCR_NOGLIBC -fpie LDFLAGS += -z noexecstack -lib-y += util-fd.o util.o string.o +lib-y += util.o string.o ifeq ($(VDSO),y) lib-y += util-vdso.o parasite-vdso.o ./$(ARCH_DIR)/vdso-pie.o diff --git a/criu/pie/util-fd.c b/criu/pie/util-fd.c deleted file mode 100644 index df7daea6f..000000000 --- a/criu/pie/util-fd.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include -#include -#include - -#include "int.h" -#include "types.h" -#include "common/compiler.h" -#include "log.h" -#include "string.h" - -#ifdef CR_NOGLIBC -# include -# define __sys(foo) sys_##foo -# define __sys_err(ret) ret -#else -# define __sys(foo) foo -# define __sys_err(ret) (-errno) -#endif - -#include "util-pie.h" -#include "fcntl.h" - -#include "common/bug.h" - -#include "common/scm-code.c" From af73eda388a126c00ccdc2ec34881db059642d80 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 1 Feb 2017 16:48:00 +0300 Subject: [PATCH 0342/4375] x86/compat: clean symlinks left from second parasite Those symlinks were for building 32-bit objects with `-m32` to link them with 32-bit parasite. Since I have dropped second parasite, I cleaned Makefile rules for 32-bit parasite, but accidentally left those symlinks. Drop them now. travis-ci: success for x86/compat: clean symlinks left from second parasite Signed-off-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/compat/memcpy-compat.c | 25 ------------------------- criu/arch/x86/compat/vdso-pie-compat.c | 1 - criu/pie/compat/parasite-compat.c | 1 - criu/pie/compat/parasite-vdso-compat.c | 1 - criu/pie/compat/util-compat.c | 1 - criu/pie/compat/util-fd-compat.c | 1 - criu/pie/compat/util-vdso-compat.c | 1 - 7 files changed, 31 deletions(-) delete mode 100644 criu/arch/x86/compat/memcpy-compat.c delete mode 120000 criu/arch/x86/compat/vdso-pie-compat.c delete mode 120000 criu/pie/compat/parasite-compat.c delete mode 120000 criu/pie/compat/parasite-vdso-compat.c delete mode 120000 criu/pie/compat/util-compat.c delete mode 120000 criu/pie/compat/util-fd-compat.c delete mode 120000 criu/pie/compat/util-vdso-compat.c diff --git a/criu/arch/x86/compat/memcpy-compat.c b/criu/arch/x86/compat/memcpy-compat.c deleted file mode 100644 index 793c27dca..000000000 --- a/criu/arch/x86/compat/memcpy-compat.c +++ /dev/null @@ -1,25 +0,0 @@ -#include - -/* - * This provides an optimized implementation of memcpy, and a simplified - * implementation of memset and memmove. These are used here because the - * standard kernel runtime versions are not yet available and we don't - * trust the gcc built-in implementations as they may do unexpected things - * (e.g. FPU ops) in the minimal decompression stub execution environment. - * - * From Linux kernel boot helpers: arch/x86/boot/compressed/string.c - */ - -void *memcpy_x86(void *dest, const void *src, size_t n) -{ - int d0, d1, d2; - asm volatile( - "rep ; movsl\n\t" - "movl %4,%%ecx\n\t" - "rep ; movsb\n\t" - : "=&c" (d0), "=&D" (d1), "=&S" (d2) - : "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src) - : "memory"); - - return dest; -} diff --git a/criu/arch/x86/compat/vdso-pie-compat.c b/criu/arch/x86/compat/vdso-pie-compat.c deleted file mode 120000 index 98b1f39da..000000000 --- a/criu/arch/x86/compat/vdso-pie-compat.c +++ /dev/null @@ -1 +0,0 @@ -../vdso-pie.c \ No newline at end of file diff --git a/criu/pie/compat/parasite-compat.c b/criu/pie/compat/parasite-compat.c deleted file mode 120000 index bc5cbac9d..000000000 --- a/criu/pie/compat/parasite-compat.c +++ /dev/null @@ -1 +0,0 @@ -../parasite.c \ No newline at end of file diff --git a/criu/pie/compat/parasite-vdso-compat.c b/criu/pie/compat/parasite-vdso-compat.c deleted file mode 120000 index 95158832f..000000000 --- a/criu/pie/compat/parasite-vdso-compat.c +++ /dev/null @@ -1 +0,0 @@ -../parasite-vdso.c \ No newline at end of file diff --git a/criu/pie/compat/util-compat.c b/criu/pie/compat/util-compat.c deleted file mode 120000 index 39606ede1..000000000 --- a/criu/pie/compat/util-compat.c +++ /dev/null @@ -1 +0,0 @@ -../util.c \ No newline at end of file diff --git a/criu/pie/compat/util-fd-compat.c b/criu/pie/compat/util-fd-compat.c deleted file mode 120000 index 358f069dc..000000000 --- a/criu/pie/compat/util-fd-compat.c +++ /dev/null @@ -1 +0,0 @@ -../util-fd.c \ No newline at end of file diff --git a/criu/pie/compat/util-vdso-compat.c b/criu/pie/compat/util-vdso-compat.c deleted file mode 120000 index 4caac4510..000000000 --- a/criu/pie/compat/util-vdso-compat.c +++ /dev/null @@ -1 +0,0 @@ -../util-vdso.c \ No newline at end of file From beed3195500bf49b955d6d9585041745a328a907 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 6 Feb 2017 13:14:12 +0300 Subject: [PATCH 0343/4375] compel/infect: fix out-of-bounds parasite memcpy() We need to copy only parasite, do copy page-aligned size, which will copy part of CRIU binary, that follows parasite blob. That will cross red-zones and fire asan error. travis-ci: success for series starting with [1/6] compel/infect: fix out-of-bounds parasite memcpy() Signed-off-by: Dmitry Safonov Signed-off-by: Andrey Ryabinin Signed-off-by: Pavel Emelyanov --- compel/src/lib/infect.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index b8997a40d..7e1da8fa9 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -858,7 +858,7 @@ static inline unsigned long total_pie_size(size_t blob_size, size_t nr_gp) int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size) { int ret; - unsigned long p, map_exchange_size, pie_size, parasite_size = 0; + unsigned long p, map_exchange_size, parasite_size = 0; if (ctl->pblob.parasite_type != COMPEL_BLOB_CHEADER) goto err; @@ -876,7 +876,7 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l * without using ptrace at all. */ - pie_size = parasite_size = total_pie_size(ctl->pblob.hdr.bsize, ctl->pblob.hdr.nr_gotpcrel); + parasite_size = total_pie_size(ctl->pblob.hdr.bsize, ctl->pblob.hdr.nr_gotpcrel); ctl->args_size = round_up(args_size, PAGE_SIZE); parasite_size += ctl->args_size; @@ -896,7 +896,7 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l ctl->addr_cmd = ctl->local_map + ctl->pblob.hdr.addr_cmd_off; ctl->addr_args = ctl->local_map + ctl->pblob.hdr.addr_arg_off; - memcpy(ctl->local_map, ctl->pblob.hdr.mem, pie_size); + memcpy(ctl->local_map, ctl->pblob.hdr.mem, ctl->pblob.hdr.bsize); if (ctl->pblob.hdr.nr_relocs) compel_relocs_apply(ctl->local_map, ctl->remote_map, ctl->pblob.hdr.bsize, ctl->pblob.hdr.relocs, ctl->pblob.hdr.nr_relocs); From 311463469829a559d0d3bcfb1c17b6cc3a4bf4b2 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 6 Feb 2017 13:14:13 +0300 Subject: [PATCH 0344/4375] compel/infect: don't copy gotpcrel with parasite's blob We don't need gotpcrel inside parasite's blob: we handle relocations over remote map in compel library, reading them from parasite's blob header. travis-ci: success for series starting with [1/6] compel/infect: fix out-of-bounds parasite memcpy() Signed-off-by: Dmitry Safonov Signed-off-by: Andrey Ryabinin Signed-off-by: Pavel Emelyanov --- compel/src/lib/infect.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 7e1da8fa9..2ffd2de63 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -850,9 +850,9 @@ int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size) return ret; } -static inline unsigned long total_pie_size(size_t blob_size, size_t nr_gp) +static inline unsigned long total_pie_size(size_t blob_size) { - return round_up(blob_size + nr_gp * sizeof(long), page_size()); + return round_up(blob_size, page_size()); } int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size) @@ -876,7 +876,7 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l * without using ptrace at all. */ - parasite_size = total_pie_size(ctl->pblob.hdr.bsize, ctl->pblob.hdr.nr_gotpcrel); + parasite_size = total_pie_size(ctl->pblob.hdr.bsize); ctl->args_size = round_up(args_size, PAGE_SIZE); parasite_size += ctl->args_size; From abec5dabe34ed8cfebda2008c581fdec48a95f57 Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Mon, 6 Feb 2017 13:14:14 +0300 Subject: [PATCH 0345/4375] Makefile: Introduce per-file CFLAGS removal. This adds the reverse of CFLAGS_obj.o with CFLAGS_REMOVE_obj.o. This allows to prevent certain CFLAGS from being used to compile files. travis-ci: success for series starting with [1/6] compel/infect: fix out-of-bounds parasite memcpy() Signed-off-by: Andrey Ryabinin Cc: Dmitry Safonov Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov --- scripts/nmk/scripts/build.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nmk/scripts/build.mk b/scripts/nmk/scripts/build.mk index e5706afa1..46d15fab9 100644 --- a/scripts/nmk/scripts/build.mk +++ b/scripts/nmk/scripts/build.mk @@ -43,7 +43,7 @@ LDFLAGS := $(filter-out $(LDFLAGS-MASK),$(LDFLAGS)) # # Accumulate common flags. define nmk-ccflags - $(CFLAGS) $(ccflags-y) $(CFLAGS_$(@F)) + $(filter-out $(CFLAGS_REMOVE_$(@F)), $(CFLAGS) $(ccflags-y) $(CFLAGS_$(@F))) endef define nmk-asflags From 706c05529f599ec8dfdedf9c0b6c51daaa81ab2f Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Mon, 6 Feb 2017 13:14:15 +0300 Subject: [PATCH 0346/4375] Makefile: add AddressSanitizer to CFLAGS This allows to build criu with AddressSanitizer enabled: make ASAN=1 -j travis-ci: success for series starting with [1/6] compel/infect: fix out-of-bounds parasite memcpy() Signed-off-by: Andrey Ryabinin Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov --- Makefile | 6 ++++++ compel/plugins/Makefile | 1 + criu/pie/Makefile | 1 + criu/pie/Makefile.library | 2 ++ 4 files changed, 10 insertions(+) diff --git a/Makefile b/Makefile index fdb25208b..d3a830630 100644 --- a/Makefile +++ b/Makefile @@ -111,6 +111,12 @@ ifneq ($(GCOV),) CFLAGS += $(CFLAGS-GCOV) endif +ifeq ($(ASAN),1) + CFLAGS-ASAN := -fsanitize=address + export CFLAGS-ASAN + CFLAGS += $(CFLAGS-ASAN) +endif + ifneq ($(WERROR),0) WARNINGS += -Werror endif diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 587324057..611d440d4 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -1,6 +1,7 @@ .PHONY: .FORCE CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) -DCR_NOGLIBC +CFLAGS := $(filter-out $(CFLAGS-ASAN),$(CFLAGS)) PLUGIN_ARCH_DIR := compel/arch/$(ARCH)/plugins # diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 8666a3048..845f9fa94 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -21,6 +21,7 @@ endif # project. # CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) +CFLAGS := $(filter-out $(CFLAGS-ASAN),$(CFLAGS)) CFLAGS += -iquote $(SRC_DIR)/criu/arch/$(ARCH)/include CFLAGS += -iquote $(SRC_DIR)/criu/include CFLAGS += -iquote $(SRC_DIR)/include diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 3996d137b..62f248208 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -41,6 +41,8 @@ iquotes := -iquote $(SRC_DIR)/$(PIE_DIR)/piegen iquotes += -iquote $(SRC_DIR)/$(ARCH_DIR)/include iquotes += -iquote $(SRC_DIR) -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) $(iquotes) +CFLAGS := $(filter-out $(CFLAGS-ASAN),$(CFLAGS)) + asflags-y := -D__ASSEMBLY__ $(iquotes) ccflags-y += $(COMPEL_UAPI_INCLUDES) From 148929d6d92e919d42d4b079a46ff9f2eae5e694 Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Mon, 6 Feb 2017 13:14:16 +0300 Subject: [PATCH 0347/4375] restorer: Workaround ASan false-positives after clone(). ASan doesn't play nicely with clone if we use current stack for child task. ASan puts local variables on the fake stack to catch use-after-return bug: https://github.com/google/sanitizers/wiki/AddressSanitizerUseAfterReturn#algorithm So it's become easy to overflow this fake stack frame in cloned child. We need a real stack for clone(). To workaround this we add clone_noasan() not-instrumented wrapper for clone(). Unfortunately we can't use __attrbute__((no_sanitize_addresss)) for this because of bug in GCC > 6: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69863 So the only way is to put this wrapper in separate non-instrumented file. travis-ci: success for series starting with [1/6] compel/infect: fix out-of-bounds parasite memcpy() Signed-off-by: Andrey Ryabinin Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov --- criu/Makefile.crtools | 2 ++ criu/clone-noasan.c | 33 +++++++++++++++++++++++++++++++++ criu/cr-restore.c | 12 +++--------- criu/include/clone-noasan.h | 6 ++++++ 4 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 criu/clone-noasan.c create mode 100644 criu/include/clone-noasan.h diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 7565895bf..04d96e82e 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -1,5 +1,6 @@ ccflags-y += -iquote criu/$(ARCH) ccflags-y += $(COMPEL_UAPI_INCLUDES) +CFLAGS_REMOVE_clone-noasan.o += $(CFLAGS-ASAN) obj-y += action-scripts.o obj-y += external.o @@ -8,6 +9,7 @@ obj-y += bfd.o obj-y += bitmap.o obj-y += cgroup.o obj-y += cgroup-props.o +obj-y += clone-noasan.o obj-y += cr-check.o obj-y += cr-dedup.o obj-y += cr-dump.o diff --git a/criu/clone-noasan.c b/criu/clone-noasan.c new file mode 100644 index 000000000..c5171b11f --- /dev/null +++ b/criu/clone-noasan.c @@ -0,0 +1,33 @@ +#include +#include "common/compiler.h" + +/* + * ASan doesn't play nicely with clone if we use current stack for + * child task. ASan puts local variables on the fake stack + * to catch use-after-return bug: + * https://github.com/google/sanitizers/wiki/AddressSanitizerUseAfterReturn#algorithm + * + * So it's become easy to overflow this fake stack frame in cloned child. + * We need a real stack for clone(). + * + * To workaround this we add clone_noasan() not-instrumented wrapper for + * clone(). Unfortunately we can't use __attrbute__((no_sanitize_addresss)) + * for this because of bug in GCC > 6: + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69863 + * + * So the only way is to put this wrapper in separate non-instrumented file + */ +int clone_noasan(int (*fn)(void *), int flags, void *arg) +{ + /* + * Reserve some space for clone() to locate arguments + * and retcode in this place + */ + char stack[128] __stack_aligned__; + char *stack_ptr = &stack[sizeof(stack)]; + int ret; + + ret = clone(fn, stack_ptr, flags, arg); + return ret; +} + diff --git a/criu/cr-restore.c b/criu/cr-restore.c index e4334c4e8..d0dd6371a 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -27,6 +27,7 @@ #include #include "common/compiler.h" +#include "clone-noasan.h" #include "cr_options.h" #include "servicefd.h" #include "image.h" @@ -909,12 +910,6 @@ static int restore_one_task(int pid, CoreEntry *core) /* All arguments should be above stack, because it grows down */ struct cr_clone_arg { - /* - * Reserve some space for clone() to locate arguments - * and retcode in this place - */ - char stack[128] __stack_aligned__; - char stack_ptr[0]; struct pstree_item *item; unsigned long clone_flags; int fd; @@ -1037,9 +1032,8 @@ static inline int fork_with_pid(struct pstree_item *item) * The cgroup namespace is also unshared explicitly in the * move_in_cgroup(), so drop this flag here as well. */ - ret = clone(restore_task_with_children, ca.stack_ptr, - (ca.clone_flags & ~(CLONE_NEWNET | CLONE_NEWCGROUP)) | SIGCHLD, &ca); - + ret = clone_noasan(restore_task_with_children, + (ca.clone_flags & ~(CLONE_NEWNET | CLONE_NEWCGROUP)) | SIGCHLD, &ca); if (ret < 0) { pr_perror("Can't fork for %d", pid); goto err_unlock; diff --git a/criu/include/clone-noasan.h b/criu/include/clone-noasan.h new file mode 100644 index 000000000..8ef75fa73 --- /dev/null +++ b/criu/include/clone-noasan.h @@ -0,0 +1,6 @@ +#ifndef __CR_CLONE_NOASAN_H__ +#define __CR_CLONE_NOASAN_H__ + +int clone_noasan(int (*fn)(void *), int flags, void *arg); + +#endif /* __CR_CLONE_NOASAN_H__ */ From e23c1d4ed942b9cd970d523a81e52dc5750af86d Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Mon, 6 Feb 2017 13:14:17 +0300 Subject: [PATCH 0348/4375] zdtm.py: run tests with ASAN_OPTIONS To run CRIU with ASan we have to use some non-default options: - detect_leaks=0 - We have to many leaks for know. Let's disable until fixed. - disable_coredump=0 - without this ASan library changes RLIMIT_CORE which break rlmimits00 tests. - log_path=asan.log - For some reason default output to stderr sometimes doesn't work in CRIU. So error log will be stored in asan.log. file instead. travis-ci: success for series starting with [1/6] compel/infect: fix out-of-bounds parasite memcpy() Signed-off-by: Andrey Ryabinin Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov --- test/zdtm.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index a8daa1863..5468d418f 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -676,10 +676,12 @@ join_ns_file = '/run/netns/zdtm_netns' class criu_cli: @staticmethod def run(action, args, fault = None, strace = [], preexec = None, nowait = False): - env = None + env = dict(os.environ, ASAN_OPTIONS = "log_path=asan.log:disable_coredump=0:detect_leaks=0") + if fault: print "Forcing %s fault" % fault - env = dict(os.environ, CRIU_FAULT = fault) + env['CRIU_FAULT'] = fault + cr = subprocess.Popen(strace + [criu_bin, action] + args, env = env, preexec_fn = preexec) if nowait: return cr From adaa7979be6feabbd356d11fafba4766a225a4fc Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 8 Feb 2017 06:36:10 -0800 Subject: [PATCH 0349/4375] compel: split sanitize ptrace.h We have ptrace defines and functions that are part of UAPI, and we have some internal stuff not to be exposed. Split ptrace.h into two files accordingly. While at it, do some cleanups: - add ptrace_ prefix to some functions and macros - remove (duplicated) PTRACE_* defines from .c files - rename ptrace_seccomp(), remove its duplicate - remove unused ptrace defines - remove unneeded (ptrace-related) includes travis-ci: success for compel uapi cleanups Signed-off-by: Kir Kolyshkin Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/infect.c | 8 +---- compel/include/ptrace.h | 17 ++++++++++ compel/include/uapi/ptrace.h | 53 ++++++++++++-------------------- compel/src/lib/infect.c | 26 ++-------------- compel/src/lib/ptrace.c | 5 ++- criu/arch/x86/crtools.c | 1 - criu/cr-dump.c | 1 - criu/cr-restore.c | 2 +- criu/include/ptrace-compat.h | 4 +-- criu/parasite-syscall.c | 1 - 10 files changed, 45 insertions(+), 73 deletions(-) create mode 100644 compel/include/ptrace.h diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index 9a3b1fb75..2c6b6e191 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -14,10 +13,9 @@ #include "errno.h" #include #include -#include "asm/ptrace.h" #include "common/err.h" #include "asm/infect-types.h" -#include "uapi/compel/ptrace.h" +#include "ptrace.h" #include "infect.h" #include "infect-priv.h" #include "log.h" @@ -159,10 +157,6 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *ar } } -#ifndef PTRACE_GETREGSET -# define PTRACE_GETREGSET 0x4204 -#endif - if (!cpu_has_feature(X86_FEATURE_FPU)) goto out; diff --git a/compel/include/ptrace.h b/compel/include/ptrace.h new file mode 100644 index 000000000..30dc74441 --- /dev/null +++ b/compel/include/ptrace.h @@ -0,0 +1,17 @@ +#ifndef COMPEL_PTRACE_H__ +#define COMPEL_PTRACE_H__ + +#include +#include +#include + +#define PTRACE_SI_EVENT(_si_code) (((_si_code) & 0xFFFF) >> 8) + +extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes); +extern int ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes); +extern int ptrace_swap_area(pid_t pid, void *dst, void *src, long bytes); + +extern int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs); +extern int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs); + +#endif /* COMPEL_PTRACE_H__ */ diff --git a/compel/include/uapi/ptrace.h b/compel/include/uapi/ptrace.h index 2ab9e1c76..d249bd99f 100644 --- a/compel/include/uapi/ptrace.h +++ b/compel/include/uapi/ptrace.h @@ -1,13 +1,21 @@ #ifndef UAPI_COMPEL_PTRACE_H__ #define UAPI_COMPEL_PTRACE_H__ -#include +/* + * We'd want to include both sys/ptrace.h and linux/ptrace.h, + * hoping that most definitions come from either one or another. + * Alas, on Alpine/musl both files declare struct ptrace_peeksiginfo_args, + * so there is no way they can be used together. Let's rely on libc one. + */ #include -#include #include -/* some constants for ptrace */ +/* + * Some constants for ptrace that might be missing from the + * standard library includes due to being (relatively) new. + */ + #ifndef PTRACE_SEIZE # define PTRACE_SEIZE 0x4206 #endif @@ -20,10 +28,6 @@ # define PTRACE_INTERRUPT 0x4207 #endif -#ifndef PTRACE_LISTEN -#define PTRACE_LISTEN 0x4208 -#endif - #ifndef PTRACE_PEEKSIGINFO #define PTRACE_PEEKSIGINFO 0x4209 @@ -45,32 +49,15 @@ #define PTRACE_SECCOMP_GET_FILTER 0x420c #endif -#define PTRACE_SEIZE_DEVEL 0x80000000 +#ifdef PTRACE_EVENT_STOP +# if PTRACE_EVENT_STOP == 7 /* Bad value from Linux 3.1-3.3, fixed in 3.4 */ +# undef PTRACE_EVENT_STOP +# endif +#endif +#ifndef PTRACE_EVENT_STOP +# define PTRACE_EVENT_STOP 128 +#endif -#define PTRACE_EVENT_FORK 1 -#define PTRACE_EVENT_VFORK 2 -#define PTRACE_EVENT_CLONE 3 -#define PTRACE_EVENT_EXEC 4 -#define PTRACE_EVENT_VFORK_DONE 5 -#define PTRACE_EVENT_EXIT 6 -#define PTRACE_EVENT_STOP 128 - -#define PTRACE_O_TRACESYSGOOD 0x00000001 -#define PTRACE_O_TRACEFORK 0x00000002 -#define PTRACE_O_TRACEVFORK 0x00000004 -#define PTRACE_O_TRACECLONE 0x00000008 -#define PTRACE_O_TRACEEXEC 0x00000010 -#define PTRACE_O_TRACEVFORKDONE 0x00000020 -#define PTRACE_O_TRACEEXIT 0x00000040 - -#define SI_EVENT(_si_code) (((_si_code) & 0xFFFF) >> 8) - -extern int suspend_seccomp(pid_t pid); -extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes); -extern int ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes); -extern int ptrace_swap_area(pid_t pid, void *dst, void *src, long bytes); - -extern int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs); -extern int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs); +extern int ptrace_suspend_seccomp(pid_t pid); #endif /* UAPI_COMPEL_PTRACE_H__ */ diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 2ffd2de63..5a45a1a09 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -17,12 +16,11 @@ #include #include -#include "asm/ptrace.h" #include "uapi/compel/plugins/std/syscall.h" #include "asm/infect-types.h" #include "asm/sigframe.h" #include "infect.h" -#include "uapi/compel/ptrace.h" +#include "ptrace.h" #include "infect-rpc.h" #include "infect-priv.h" #include "infect-util.h" @@ -41,18 +39,10 @@ #define PARASITE_STACK_SIZE (16 << 10) -#define PTRACE_EVENT_STOP 128 - #ifndef SECCOMP_MODE_DISABLED #define SECCOMP_MODE_DISABLED 0 #endif -#ifndef PTRACE_O_SUSPEND_SECCOMP -# define PTRACE_O_SUSPEND_SECCOMP (1 << 21) -#endif - -#define SI_EVENT(_si_code) (((_si_code) & 0xFFFF) >> 8) - static int prepare_thread(int pid, struct thread_ctx *ctx); static inline void close_safe(int *pfd) @@ -195,16 +185,6 @@ static int skip_sigstop(int pid, int nr_signals) return 0; } -static int do_suspend_seccomp(pid_t pid) -{ - if (ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_SUSPEND_SECCOMP) < 0) { - pr_perror("suspending seccomp failed"); - return -1; - } - - return 0; -} - /* * This routine seizes task putting it into a special * state where we can manipulate the task via ptrace @@ -278,7 +258,7 @@ try_again: goto err; } - if (SI_EVENT(si.si_code) != PTRACE_EVENT_STOP) { + if (PTRACE_SI_EVENT(si.si_code) != PTRACE_EVENT_STOP) { /* * Kernel notifies us about the task being seized received some * event other than the STOP, i.e. -- a signal. Let the task @@ -295,7 +275,7 @@ try_again: goto try_again; } - if (ss->seccomp_mode != SECCOMP_MODE_DISABLED && do_suspend_seccomp(pid) < 0) + if (ss->seccomp_mode != SECCOMP_MODE_DISABLED && ptrace_suspend_seccomp(pid) < 0) goto err; nr_sigstop = 0; diff --git a/compel/src/lib/ptrace.c b/compel/src/lib/ptrace.c index c2991b5d8..9142bac42 100644 --- a/compel/src/lib/ptrace.c +++ b/compel/src/lib/ptrace.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -18,11 +17,11 @@ #include "common/compiler.h" #include "uapi/compel/asm/infect-types.h" -#include "uapi/compel/ptrace.h" +#include "ptrace.h" #include "log.h" -int suspend_seccomp(pid_t pid) +int ptrace_suspend_seccomp(pid_t pid) { if (ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_SUSPEND_SECCOMP) < 0) { pr_perror("suspending seccomp failed"); diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 0c3851adc..e1cfb1952 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -15,7 +15,6 @@ #include "cr_options.h" #include "common/compiler.h" #include "restorer.h" -#include #include "parasite-syscall.h" #include "util.h" #include "cpu.h" diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 588e37f4d..d0639f398 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -42,7 +42,6 @@ #include "cr_options.h" #include "servicefd.h" #include "string.h" -#include #include "ptrace-compat.h" #include "util.h" #include "namespaces.h" diff --git a/criu/cr-restore.c b/criu/cr-restore.c index d0dd6371a..92964d7ee 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1572,7 +1572,7 @@ static int attach_to_tasks(bool root_seized) * doing an munmap in the process, which may be blocked by * seccomp and cause the task to be killed. */ - if (rsti(item)->has_seccomp && suspend_seccomp(pid) < 0) + if (rsti(item)->has_seccomp && ptrace_suspend_seccomp(pid) < 0) pr_err("failed to suspend seccomp, restore will probably fail...\n"); if (ptrace(PTRACE_CONT, pid, NULL, NULL) ) { diff --git a/criu/include/ptrace-compat.h b/criu/include/ptrace-compat.h index 295fb01c6..b23df2dfd 100644 --- a/criu/include/ptrace-compat.h +++ b/criu/include/ptrace-compat.h @@ -1,10 +1,8 @@ #ifndef __CR_PTRACE_H__ #define __CR_PTRACE_H__ +#include #include -#include - -#include "types.h" #include "config.h" #ifndef CONFIG_HAS_PTRACE_PEEKSIGINFO diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index a7a26adf4..fef902de9 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -15,7 +15,6 @@ #include "images/pagemap.pb-c.h" #include "imgset.h" -#include #include "parasite-syscall.h" #include "parasite.h" #include "crtools.h" From c18aa3e7fb8d4c7d76120b1a4b246581902552fb Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 8 Feb 2017 06:36:11 -0800 Subject: [PATCH 0350/4375] compel: add compel_ prefix to cpu_has_feature travis-ci: success for compel uapi cleanups Signed-off-by: Kir Kolyshkin Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/cpu.c | 2 +- compel/arch/arm/src/lib/cpu.c | 2 +- compel/arch/ppc64/src/lib/cpu.c | 2 +- compel/arch/x86/src/lib/cpu.c | 2 +- compel/arch/x86/src/lib/infect.c | 4 ++-- compel/include/uapi/cpu.h | 2 +- criu/arch/x86/cpu.c | 12 ++++++------ criu/arch/x86/crtools.c | 10 +++++----- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/compel/arch/aarch64/src/lib/cpu.c b/compel/arch/aarch64/src/lib/cpu.c index 3fa544639..30263b377 100644 --- a/compel/arch/aarch64/src/lib/cpu.c +++ b/compel/arch/aarch64/src/lib/cpu.c @@ -18,7 +18,7 @@ void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } int compel_cpuid(compel_cpuinfo_t *info) { return 0; } -bool cpu_has_feature(unsigned int feature) +bool compel_cpu_has_feature(unsigned int feature) { if (!rt_info_done) { compel_cpuid(&rt_info); diff --git a/compel/arch/arm/src/lib/cpu.c b/compel/arch/arm/src/lib/cpu.c index 3fa544639..30263b377 100644 --- a/compel/arch/arm/src/lib/cpu.c +++ b/compel/arch/arm/src/lib/cpu.c @@ -18,7 +18,7 @@ void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } int compel_cpuid(compel_cpuinfo_t *info) { return 0; } -bool cpu_has_feature(unsigned int feature) +bool compel_cpu_has_feature(unsigned int feature) { if (!rt_info_done) { compel_cpuid(&rt_info); diff --git a/compel/arch/ppc64/src/lib/cpu.c b/compel/arch/ppc64/src/lib/cpu.c index 00a02ea2a..d2a7552a1 100644 --- a/compel/arch/ppc64/src/lib/cpu.c +++ b/compel/arch/ppc64/src/lib/cpu.c @@ -32,7 +32,7 @@ int compel_cpuid(compel_cpuinfo_t *info) return 0; } -bool cpu_has_feature(unsigned int feature) +bool compel_cpu_has_feature(unsigned int feature) { if (!rt_info_done) { compel_cpuid(&rt_info); diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c index 88df9f200..dbd3136f0 100644 --- a/compel/arch/x86/src/lib/cpu.c +++ b/compel/arch/x86/src/lib/cpu.c @@ -178,7 +178,7 @@ int compel_cpuid(compel_cpuinfo_t *c) return 0; } -bool cpu_has_feature(unsigned int feature) +bool compel_cpu_has_feature(unsigned int feature) { if (!rt_info_done) { compel_cpuid(&rt_info); diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index 2c6b6e191..53f29cfbf 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -157,7 +157,7 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *ar } } - if (!cpu_has_feature(X86_FEATURE_FPU)) + if (!compel_cpu_has_feature(X86_FEATURE_FPU)) goto out; /* @@ -167,7 +167,7 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *ar pr_info("Dumping GP/FPU registers for %d\n", pid); - if (cpu_has_feature(X86_FEATURE_OSXSAVE)) { + if (compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) { iov.iov_base = &xsave; iov.iov_len = sizeof(xsave); diff --git a/compel/include/uapi/cpu.h b/compel/include/uapi/cpu.h index 23438da4d..4268b6c4f 100644 --- a/compel/include/uapi/cpu.h +++ b/compel/include/uapi/cpu.h @@ -6,6 +6,6 @@ #include extern int compel_cpuid(compel_cpuinfo_t *info); -extern bool cpu_has_feature(unsigned int feature); +extern bool compel_cpu_has_feature(unsigned int feature); #endif /* UAPI_COMPEL_CPU_H__ */ diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index 9f8083db0..5e95d25d8 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -41,17 +41,17 @@ int cpu_init(void) * Make sure that at least FPU is onboard * and fxsave is supported. */ - if (cpu_has_feature(X86_FEATURE_FPU)) { - if (!cpu_has_feature(X86_FEATURE_FXSR)) { + if (compel_cpu_has_feature(X86_FEATURE_FPU)) { + if (!compel_cpu_has_feature(X86_FEATURE_FXSR)) { pr_err("missing support fxsave/restore insns\n"); return -1; } } pr_debug("fpu:%d fxsr:%d xsave:%d\n", - !!cpu_has_feature(X86_FEATURE_FPU), - !!cpu_has_feature(X86_FEATURE_FXSR), - !!cpu_has_feature(X86_FEATURE_OSXSAVE)); + !!compel_cpu_has_feature(X86_FEATURE_FPU), + !!compel_cpu_has_feature(X86_FEATURE_FXSR), + !!compel_cpu_has_feature(X86_FEATURE_OSXSAVE)); return 0; } @@ -222,7 +222,7 @@ static int cpu_validate_features(CpuinfoX86Entry *img_x86_entry) #define __mismatch_fpu_bit(__bit) \ (test_bit(__bit, (void *)img_x86_entry->capability) && \ - !cpu_has_feature(__bit)) + !compel_cpu_has_feature(__bit)) if (__mismatch_fpu_bit(X86_FEATURE_FPU) || __mismatch_fpu_bit(X86_FEATURE_FXSR) || __mismatch_fpu_bit(X86_FEATURE_OSXSAVE)) { diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index e1cfb1952..99a0786c8 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -129,7 +129,7 @@ int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpre assign_array(core->thread_info->fpregs, fpregs->i387, st_space); assign_array(core->thread_info->fpregs, fpregs->i387, xmm_space); - if (cpu_has_feature(X86_FEATURE_OSXSAVE)) { + if (compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) { BUG_ON(core->thread_info->fpregs->xsave->n_ymmh_space != ARRAY_SIZE(fpregs->ymmh.ymmh_space)); assign_reg(core->thread_info->fpregs->xsave, fpregs->xsave_hdr, xstate_bv); @@ -162,14 +162,14 @@ int arch_alloc_thread_info(CoreEntry *core) ThreadInfoX86 *ti = NULL; - with_fpu = cpu_has_feature(X86_FEATURE_FPU); + with_fpu = compel_cpu_has_feature(X86_FEATURE_FPU); sz = sizeof(ThreadInfoX86) + sizeof(UserX86RegsEntry) + GDT_ENTRY_TLS_NUM*sizeof(UserDescT) + GDT_ENTRY_TLS_NUM*sizeof(UserDescT*); if (with_fpu) { sz += sizeof(UserX86FpregsEntry); - with_xsave = cpu_has_feature(X86_FEATURE_OSXSAVE); + with_xsave = compel_cpu_has_feature(X86_FEATURE_OSXSAVE); if (with_xsave) sz += sizeof(UserX86XsaveEntry); } @@ -250,7 +250,7 @@ static bool valid_xsave_frame(CoreEntry *core) return false; } - if (cpu_has_feature(X86_FEATURE_OSXSAVE)) { + if (compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) { if (core->thread_info->fpregs->xsave && core->thread_info->fpregs->xsave->n_ymmh_space < ARRAY_SIZE(x->ymmh.ymmh_space)) { pr_err("Corruption in FPU ymmh_space area " @@ -336,7 +336,7 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) assign_array(x->i387, core->thread_info->fpregs, st_space); assign_array(x->i387, core->thread_info->fpregs, xmm_space); - if (cpu_has_feature(X86_FEATURE_OSXSAVE)) { + if (compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) { struct fpx_sw_bytes *fpx_sw = (void *)&x->i387.sw_reserved; void *magic2; From 99e27b1dbc6ca23491df52ad44dfd010d3a6790d Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 8 Feb 2017 06:36:12 -0800 Subject: [PATCH 0351/4375] compel/include/uapi/infect.h: no circular inclusion infect.h includes compel.h, and compel.h includes infect.h. Surely, due to include guards it will be sorted out, but we'd rather just include what we need. travis-ci: success for compel uapi cleanups Signed-off-by: Kir Kolyshkin Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 9f08f3461..5c475555a 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include "common/compiler.h" From 735ffc1d7ef2c4d1eac17dfd10ca7250fca5b862 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 10 Feb 2017 01:03:00 +0300 Subject: [PATCH 0352/4375] Sanitize TASK_ values First, TASK_* defines provided by compel should be prefixed with COMPEL_. The complication is, same constants are also used by CRIU, some are even writted into images (meaning we should not change their values). One way to solve this would be to untie compel values from CRIU ones, using some mapping between the two sets when needed (i.e. in calls to compel_wait_task() and compel_resume_task()). Fortunately, we can avoid implementing this mapping by separating the ranges used by compel and criu. With this patch, compel is using values in range 0x01..0x7f, and criu is reusing those, plus adding more values in range 0x80..0xff for its own purposes. Note tha the values that are used inside images are not changed (as, luckily, they were all used by compel). travis-ci: success for compel uapi cleanups (rev2) Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 10 +--------- compel/include/uapi/task-state.h | 19 +++++++++++++++++++ compel/src/lib/infect.c | 20 ++++++++++---------- criu/include/pid.h | 26 ++++++++++++++++++-------- criu/pstree.c | 1 + 5 files changed, 49 insertions(+), 27 deletions(-) create mode 100644 compel/include/uapi/task-state.h diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 5c475555a..da0ca3a69 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "common/compiler.h" @@ -29,15 +30,6 @@ extern int compel_wait_task(int pid, int ppid, extern int compel_stop_task(int pid); extern int compel_resume_task(pid_t pid, int orig_state, int state); -/* - * FIXME -- these should be mapped to pid.h's - */ - -#define TASK_ALIVE 0x1 -#define TASK_DEAD 0x2 -#define TASK_STOPPED 0x3 -#define TASK_ZOMBIE 0x6 - struct parasite_ctl; struct parasite_thread_ctl; diff --git a/compel/include/uapi/task-state.h b/compel/include/uapi/task-state.h new file mode 100644 index 000000000..84a2a0ba5 --- /dev/null +++ b/compel/include/uapi/task-state.h @@ -0,0 +1,19 @@ +#ifndef __COMPEL_UAPI_TASK_STATE_H__ +#define __COMPEL_UAPI_TASK_STATE_H__ + +/* + * Task state, as returned by compel_wait_task() + * and used in arguments to compel_resume_task(). + */ +enum __compel_task_state +{ + COMPEL_TASK_ALIVE = 0x01, + COMPEL_TASK_DEAD = 0x02, + COMPEL_TASK_STOPPED = 0x03, + COMPEL_TASK_ZOMBIE = 0x06, + /* Don't ever change the above values, they are used by CRIU! */ + + COMPEL_TASK_MAX = 0x7f +}; + +#endif /* __COMPEL_UAPI_TASK_STATE_H__ */ diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 5a45a1a09..7cf577b3d 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -236,9 +236,9 @@ try_again: } if (ret < 0) - return TASK_ZOMBIE; + return COMPEL_TASK_ZOMBIE; else - return TASK_DEAD; + return COMPEL_TASK_DEAD; } if ((ppid != -1) && (ss->ppid != ppid)) { @@ -290,11 +290,11 @@ try_again: if (skip_sigstop(pid, nr_sigstop)) goto err_stop; - return TASK_STOPPED; + return COMPEL_TASK_STOPPED; } if (si.si_signo == SIGTRAP) - return TASK_ALIVE; + return COMPEL_TASK_ALIVE; else { pr_err("SEIZE %d: unsupported stop signal %d\n", pid, si.si_signo); goto err; @@ -312,25 +312,25 @@ int compel_resume_task(pid_t pid, int orig_st, int st) { pr_debug("\tUnseizing %d into %d\n", pid, st); - if (st == TASK_DEAD) { + if (st == COMPEL_TASK_DEAD) { kill(pid, SIGKILL); return 0; - } else if (st == TASK_STOPPED) { + } else if (st == COMPEL_TASK_STOPPED) { /* * Task might have had STOP in queue. We detected such - * guy as TASK_STOPPED, but cleared signal to run the - * parasite code. hus after detach the task will become + * guy as COMPEL_TASK_STOPPED, but cleared signal to run + * the parasite code. Thus after detach the task will become * running. That said -- STOP everyone regardless of * the initial state. */ kill(pid, SIGSTOP); - } else if (st == TASK_ALIVE) { + } else if (st == COMPEL_TASK_ALIVE) { /* * Same as in the comment above -- there might be a * task with STOP in queue that would get lost after * detach, so stop it again. */ - if (orig_st == TASK_STOPPED) + if (orig_st == COMPEL_TASK_STOPPED) kill(pid, SIGSTOP); } else pr_err("Unknown final state %d\n", st); diff --git a/criu/include/pid.h b/criu/include/pid.h index 9ac583ffb..81786ec4a 100644 --- a/criu/include/pid.h +++ b/criu/include/pid.h @@ -1,9 +1,27 @@ #ifndef __CR_PID_H__ #define __CR_PID_H__ +#include #include "stdbool.h" #include "rbtree.h" +/* + * Task states, used in e.g. struct pid's state. + */ +enum __criu_task_state +{ + /* Values shared with compel */ + TASK_ALIVE = COMPEL_TASK_ALIVE, + TASK_DEAD = COMPEL_TASK_DEAD, + TASK_STOPPED = COMPEL_TASK_STOPPED, + TASK_ZOMBIE = COMPEL_TASK_ZOMBIE, + /* Own internal states */ + TASK_HELPER = COMPEL_TASK_MAX + 1, + TASK_THREAD, + /* new values are to be added before this line */ + TASK_UNDEF = 0xff +}; + struct pid { struct pstree_item *item; /* @@ -26,14 +44,6 @@ struct pid { } ns[1]; /* Must be at the end of struct pid */ }; -#define TASK_UNDEF 0x0 -#define TASK_ALIVE 0x1 -#define TASK_DEAD 0x2 -#define TASK_STOPPED 0x3 -#define TASK_HELPER 0x4 -#define TASK_THREAD 0x5 -#define TASK_ZOMBIE 0x6 - /* * When we have to restore a shared resource, we mush select which * task should do it, and make other(s) wait for it. In order to diff --git a/criu/pstree.c b/criu/pstree.c index 3838070f2..7d92a3ef8 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -217,6 +217,7 @@ struct pstree_item *__alloc_pstree_item(bool rst) item->pid->ns[0].virt = -1; item->pid->real = -1; + item->pid->state = TASK_UNDEF; item->born_sid = -1; item->pid->item = item; futex_init(&item->task_st); From f233b86a02de369837098f069e0bc35c178d32da Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Mon, 13 Feb 2017 13:00:33 +0300 Subject: [PATCH 0353/4375] compel: Move memcpy/memcpy/etc stuff in This is the difference between two commits criu-dev/b0f6f293/Unify own memcpy/memset/memcmp master/0367a1fe/Drop prefix from own memcpy/memset/memcmp that makes criu-dev after rebase on master with latter commit be the same as it was with former commit before rebase. Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- .../arch/aarch64/plugins/include/features.h | 4 ++ compel/arch/arm/plugins/include/features.h | 4 ++ compel/arch/ppc64/plugins/include/features.h | 7 +++ .../arch/ppc64/plugins/std/memcmp.S | 0 .../arch/ppc64/plugins/std/memcpy.S | 0 compel/arch/x86/plugins/include/features.h | 6 ++ .../arch/x86/plugins/std}/memcpy.S | 0 compel/plugins/Makefile | 13 +++- compel/plugins/include/uapi/std/string.h | 7 ++- compel/plugins/std/fds.c | 1 - compel/plugins/std/log.c | 2 +- compel/plugins/std/string.c | 59 ++++++++++++++--- compel/src/lib/infect.c | 1 - criu/arch/aarch64/include/features.h | 4 -- criu/arch/arm/include/features.h | 4 -- criu/arch/ppc64/include/features.h | 7 --- criu/arch/ppc64/vdso-pie.c | 2 +- criu/arch/x86/include/asm/parasite.h | 6 +- criu/arch/x86/include/features.h | 6 -- criu/arch/x86/restorer.c | 4 +- criu/arch/x86/sigaction_compat.c | 4 +- criu/arch/x86/vdso-pie.c | 2 +- criu/include/string.h | 3 - criu/pie/Makefile | 2 - criu/pie/Makefile.library | 16 +---- criu/pie/restorer.c | 1 - criu/pie/string.c | 63 ------------------- criu/pie/util-vdso.c | 7 +-- 28 files changed, 105 insertions(+), 130 deletions(-) create mode 100644 compel/arch/aarch64/plugins/include/features.h create mode 100644 compel/arch/arm/plugins/include/features.h create mode 100644 compel/arch/ppc64/plugins/include/features.h rename criu/arch/ppc64/memcmp_64.S => compel/arch/ppc64/plugins/std/memcmp.S (100%) rename criu/arch/ppc64/memcpy_power7.S => compel/arch/ppc64/plugins/std/memcpy.S (100%) create mode 100644 compel/arch/x86/plugins/include/features.h rename {criu/arch/x86 => compel/arch/x86/plugins/std}/memcpy.S (100%) delete mode 100644 criu/arch/aarch64/include/features.h delete mode 100644 criu/arch/arm/include/features.h delete mode 100644 criu/arch/ppc64/include/features.h delete mode 100644 criu/arch/x86/include/features.h delete mode 100644 criu/pie/string.c diff --git a/compel/arch/aarch64/plugins/include/features.h b/compel/arch/aarch64/plugins/include/features.h new file mode 100644 index 000000000..b4a3cded2 --- /dev/null +++ b/compel/arch/aarch64/plugins/include/features.h @@ -0,0 +1,4 @@ +#ifndef __COMPEL_ARCH_FEATURES_H +#define __COMPEL_ARCH_FEATURES_H + +#endif /* __COMPEL_ARCH_FEATURES_H */ diff --git a/compel/arch/arm/plugins/include/features.h b/compel/arch/arm/plugins/include/features.h new file mode 100644 index 000000000..b4a3cded2 --- /dev/null +++ b/compel/arch/arm/plugins/include/features.h @@ -0,0 +1,4 @@ +#ifndef __COMPEL_ARCH_FEATURES_H +#define __COMPEL_ARCH_FEATURES_H + +#endif /* __COMPEL_ARCH_FEATURES_H */ diff --git a/compel/arch/ppc64/plugins/include/features.h b/compel/arch/ppc64/plugins/include/features.h new file mode 100644 index 000000000..d7dd5072d --- /dev/null +++ b/compel/arch/ppc64/plugins/include/features.h @@ -0,0 +1,7 @@ +#ifndef __COMPEL_ARCH_FEATURES_H +#define __COMPEL_ARCH_FEATURES_H + +#define ARCH_HAS_MEMCPY +#define ARCH_HAS_MEMCMP + +#endif /* __COMPEL_ARCH_FEATURES_H */ diff --git a/criu/arch/ppc64/memcmp_64.S b/compel/arch/ppc64/plugins/std/memcmp.S similarity index 100% rename from criu/arch/ppc64/memcmp_64.S rename to compel/arch/ppc64/plugins/std/memcmp.S diff --git a/criu/arch/ppc64/memcpy_power7.S b/compel/arch/ppc64/plugins/std/memcpy.S similarity index 100% rename from criu/arch/ppc64/memcpy_power7.S rename to compel/arch/ppc64/plugins/std/memcpy.S diff --git a/compel/arch/x86/plugins/include/features.h b/compel/arch/x86/plugins/include/features.h new file mode 100644 index 000000000..0f35725fa --- /dev/null +++ b/compel/arch/x86/plugins/include/features.h @@ -0,0 +1,6 @@ +#ifndef __COMPEL_ARCH_FEATURES_H +#define __COMPEL_ARCH_FEATURES_H + +#define ARCH_HAS_MEMCPY + +#endif /* __COMPEL_ARCH_FEATURES_H */ diff --git a/criu/arch/x86/memcpy.S b/compel/arch/x86/plugins/std/memcpy.S similarity index 100% rename from criu/arch/x86/memcpy.S rename to compel/arch/x86/plugins/std/memcpy.S diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 611d440d4..cea312508 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -1,6 +1,8 @@ .PHONY: .FORCE -CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) -DCR_NOGLIBC +CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) +CFLAGS += -DCR_NOGLIBC -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 +CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 CFLAGS := $(filter-out $(CFLAGS-ASAN),$(CFLAGS)) PLUGIN_ARCH_DIR := compel/arch/$(ARCH)/plugins @@ -48,6 +50,15 @@ std-obj-y += std/string.o std-obj-y += std/infect.o std-obj-y += ./$(PLUGIN_ARCH_DIR)/std/parasite-head.o +ifeq ($(SRCARCH),x86) + std-obj-y += ./$(PLUGIN_ARCH_DIR)/std/memcpy.o +endif + +ifeq ($(SRCARCH),ppc64) + std-obj-y += ./$(PLUGIN_ARCH_DIR)/std/memcpy.o + std-obj-y += ./$(PLUGIN_ARCH_DIR)/std/memcmp.o +endif + include ./$(PLUGIN_ARCH_DIR)/std/syscalls/Makefile.syscalls define syscall-priority diff --git a/compel/plugins/include/uapi/std/string.h b/compel/plugins/include/uapi/std/string.h index 8aec886bd..ddc1ea3cf 100644 --- a/compel/plugins/include/uapi/std/string.h +++ b/compel/plugins/include/uapi/std/string.h @@ -21,8 +21,11 @@ extern void __std_printf(int fd, const char *format, ...); #define std_putchar(c) __std_putc(STDOUT_FILENO, c) extern unsigned long std_strtoul(const char *nptr, char **endptr, int base); -extern void *std_memcpy(void *to, const void *from, unsigned int n); -extern int std_memcmp(const void *cs, const void *ct, size_t count); extern int std_strcmp(const char *cs, const char *ct); +extern int std_strncmp(const char *cs, const char *ct, size_t n); + +extern void *memcpy(void *dest, const void *src, size_t n); +extern int memcmp(const void *s1, const void *s2, size_t n); +extern void *memset(void *s, int c, size_t n); #endif /* COMPEL_PLUGIN_STD_STRING_H__ */ diff --git a/compel/plugins/std/fds.c b/compel/plugins/std/fds.c index a61bbfd2c..c947a30f0 100644 --- a/compel/plugins/std/fds.c +++ b/compel/plugins/std/fds.c @@ -16,6 +16,5 @@ #define __sys(foo) sys_##foo #define __sys_err(ret) ret -#define __memcpy std_memcpy #include "common/scm-code.c" diff --git a/compel/plugins/std/log.c b/compel/plugins/std/log.c index 28d2259f1..52a3f1a30 100644 --- a/compel/plugins/std/log.c +++ b/compel/plugins/std/log.c @@ -1,8 +1,8 @@ #include -#include "string.h" #include "common/bitsperlong.h" #include +#include "uapi/std/string.h" #include #include diff --git a/compel/plugins/std/string.c b/compel/plugins/std/string.c index e987e408e..177d7e653 100644 --- a/compel/plugins/std/string.c +++ b/compel/plugins/std/string.c @@ -5,6 +5,8 @@ #include "uapi/std/syscall.h" #include "uapi/std/string.h" +#include "features.h" + static const char conv_tab[] = "0123456789abcdefghijklmnopqrstuvwxyz"; void __std_putc(int fd, char c) @@ -220,17 +222,33 @@ fin: return neg ? (unsigned long)-num : (unsigned long)num; } -void *std_memcpy(void *to, const void *from, unsigned int n) -{ - char *tmp = to; - const char *s = from; - while (n--) - *tmp++ = *s++; +/* + * C compiler is free to insert implicit calls to memcmp, memset, + * memcpy and memmove, assuming they are available during linking. + * As the parasite code is not linked with libc, it must provide + * our own implementations of the above functions. + * Surely, these functions can also be called explicitly. + * + * Note: for now, not having memmove() seems OK for both gcc and clang. + */ + +#ifndef ARCH_HAS_MEMCPY +void *memcpy(void *to, const void *from, size_t n) +{ + size_t i; + unsigned char *cto = to; + const unsigned char *cfrom = from; + + for (i = 0; i < n; ++i, ++cto, ++cfrom) + *cto = *cfrom; + return to; } +#endif -int std_memcmp(const void *cs, const void *ct, size_t count) +#ifndef ARCH_HAS_MEMCMP +int memcmp(const void *cs, const void *ct, size_t count) { const unsigned char *su1, *su2; int res = 0; @@ -240,6 +258,20 @@ int std_memcmp(const void *cs, const void *ct, size_t count) break; return res; } +#endif + +#ifndef ARCH_HAS_MEMSET +void *memset(void *s, const int c, size_t count) +{ + volatile char *dest = s; + size_t i = 0; + + while (i < count) + dest[i++] = (char) c; + + return s; +} +#endif int std_strcmp(const char *cs, const char *ct) { @@ -255,3 +287,16 @@ int std_strcmp(const char *cs, const char *ct) } return 0; } + +int std_strncmp(const char *cs, const char *ct, size_t count) +{ + size_t i; + + for (i = 0; i < count; i++) { + if (cs[i] != ct[i]) + return cs[i] < ct[i] ? -1 : 1; + if (!cs[i]) + break; + } + return 0; +} diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 7cf577b3d..fea7e6b55 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -29,7 +29,6 @@ #define __sys(foo) foo #define __sys_err(ret) (-errno) -#define __memcpy memcpy #include "common/scm.h" #include "common/scm-code.c" diff --git a/criu/arch/aarch64/include/features.h b/criu/arch/aarch64/include/features.h deleted file mode 100644 index 5b51d1892..000000000 --- a/criu/arch/aarch64/include/features.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef __CRIU_ARCH_FEATURES_H -#define __CRIU_ARCH_FEATURES_H - -#endif /* __CRIU_ARCH_FEATURES_H */ diff --git a/criu/arch/arm/include/features.h b/criu/arch/arm/include/features.h deleted file mode 100644 index 5b51d1892..000000000 --- a/criu/arch/arm/include/features.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef __CRIU_ARCH_FEATURES_H -#define __CRIU_ARCH_FEATURES_H - -#endif /* __CRIU_ARCH_FEATURES_H */ diff --git a/criu/arch/ppc64/include/features.h b/criu/arch/ppc64/include/features.h deleted file mode 100644 index 5b720f8f3..000000000 --- a/criu/arch/ppc64/include/features.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __CRIU_ARCH_FEATURES_H -#define __CRIU_ARCH_FEATURES_H - -#define ARCH_HAS_MEMCPY -#define ARCH_HAS_MEMCMP - -#endif /* __CRIU_ARCH_FEATURES_H */ diff --git a/criu/arch/ppc64/vdso-pie.c b/criu/arch/ppc64/vdso-pie.c index 2c46c1613..f13ea4a88 100644 --- a/criu/arch/ppc64/vdso-pie.c +++ b/criu/arch/ppc64/vdso-pie.c @@ -1,8 +1,8 @@ #include -#include #include "asm/types.h" +#include #include #include "parasite-vdso.h" #include "log.h" diff --git a/criu/arch/x86/include/asm/parasite.h b/criu/arch/x86/include/asm/parasite.h index 7b259d7a2..68fad095c 100644 --- a/criu/arch/x86/include/asm/parasite.h +++ b/criu/arch/x86/include/asm/parasite.h @@ -1,7 +1,7 @@ #ifndef __ASM_PARASITE_H__ #define __ASM_PARASITE_H__ -#include "asm-generic/string.h" +#include #include #include "asm/compat.h" @@ -68,11 +68,11 @@ static void arch_get_tls(tls_t *ptls) { user_desc_t *d = syscall_mem; - builtin_memset(d, 0, sizeof(user_desc_t)); + memset(d, 0, sizeof(user_desc_t)); d->seg_not_present = 1; d->entry_number = GDT_ENTRY_TLS_MIN + i; arch_get_user_desc(d); - builtin_memcpy(&ptls->desc[i], d, sizeof(user_desc_t)); + memcpy(&ptls->desc[i], d, sizeof(user_desc_t)); } free_compat_syscall_stack(syscall_mem); diff --git a/criu/arch/x86/include/features.h b/criu/arch/x86/include/features.h deleted file mode 100644 index d357e99ad..000000000 --- a/criu/arch/x86/include/features.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __CRIU_ARCH_FEATURES_H -#define __CRIU_ARCH_FEATURES_H - -#define ARCH_HAS_MEMCPY - -#endif /* __CRIU_ARCH_FEATURES_H */ diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index 45107045d..a4ddee543 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -5,8 +5,8 @@ #include "restorer.h" #include "asm/restorer.h" #include -#include "asm/string.h" +#include #include #include "log.h" #include "cpu.h" @@ -71,7 +71,7 @@ void restore_tls(tls_t *ptls) if (prepare_stack32(&stack32) < 0) return; - builtin_memcpy(stack32, desc, sizeof(user_desc_t)); + memcpy(stack32, desc, sizeof(user_desc_t)); asm volatile ( " mov %1,%%eax \n" " mov %2,%%ebx \n" diff --git a/criu/arch/x86/sigaction_compat.c b/criu/arch/x86/sigaction_compat.c index 168d3ddb0..52f22a4f9 100644 --- a/criu/arch/x86/sigaction_compat.c +++ b/criu/arch/x86/sigaction_compat.c @@ -1,11 +1,11 @@ #include "log.h" #include "asm/restorer.h" #include -#include "asm/string.h" #include "asm/compat.h" #ifdef CR_NOGLIBC # include +# include #else # ifndef __NR32_rt_sigaction # define __NR32_rt_sigaction 174 @@ -38,7 +38,7 @@ int arch_compat_rt_sigaction(void *stack32, int sig, rt_sigaction_t_compat *act) * To be sure, that sigaction pointer lies under 4G, * coping it on the bottom of the stack. */ - builtin_memcpy(stack32, act, sizeof(rt_sigaction_t_compat)); + memcpy(stack32, act, sizeof(rt_sigaction_t_compat)); asm volatile ("\t movl %%ebx,%%ebx\n" : :"b"(sig)); /* signum */ asm volatile ("\t movl %%ecx,%%ecx\n" : :"c"(stack32)); /* act */ diff --git a/criu/arch/x86/vdso-pie.c b/criu/arch/x86/vdso-pie.c index 990a2771f..24d44965b 100644 --- a/criu/arch/x86/vdso-pie.c +++ b/criu/arch/x86/vdso-pie.c @@ -1,8 +1,8 @@ #include -#include "string.h" #include "asm/types.h" +#include #include #include "parasite-vdso.h" #include "log.h" diff --git a/criu/include/string.h b/criu/include/string.h index 3a87e85ea..f9b4a3828 100644 --- a/criu/include/string.h +++ b/criu/include/string.h @@ -2,7 +2,6 @@ #define __CR_STRING_H__ #include -#include #ifdef CONFIG_HAS_LIBBSD # include @@ -18,6 +17,4 @@ extern size_t strlcpy(char *dest, const char *src, size_t size); extern size_t strlcat(char *dest, const char *src, size_t count); #endif -extern int builtin_strncmp(const char *cs, const char *ct, size_t count); - #endif /* __CR_STRING_H__ */ diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 845f9fa94..45adbc10b 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -26,8 +26,6 @@ CFLAGS += -iquote $(SRC_DIR)/criu/arch/$(ARCH)/include CFLAGS += -iquote $(SRC_DIR)/criu/include CFLAGS += -iquote $(SRC_DIR)/include CFLAGS += -iquote $(SRC_DIR) -CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 ccflags-y += $(COMPEL_UAPI_INCLUDES) ccflags-y += -DCR_NOGLIBC diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 62f248208..e84058c67 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -3,7 +3,7 @@ lib-name := pie.lib.a CFLAGS += -fno-stack-protector -DCR_NOGLIBC -fpie LDFLAGS += -z noexecstack -lib-y += util.o string.o +lib-y += util.o ifeq ($(VDSO),y) lib-y += util-vdso.o parasite-vdso.o ./$(ARCH_DIR)/vdso-pie.o @@ -18,8 +18,7 @@ ifeq ($(VDSO),y) endif ifeq ($(SRCARCH),ppc64) - lib-y += ./$(ARCH_DIR)/memcpy_power7.o \ - ./$(ARCH_DIR)/memcmp_64.o ./$(ARCH_DIR)/misc.o + lib-y += ./$(ARCH_DIR)/misc.o endif ifeq ($(SRCARCH),x86) @@ -27,8 +26,6 @@ ifeq ($(SRCARCH),x86) lib-y += util-vdso-elf32.o endif CFLAGS_util-vdso-elf32.o += -DCONFIG_VDSO_32 - - lib-y += ./$(ARCH_DIR)/memcpy.o endif # @@ -49,12 +46,3 @@ ccflags-y += $(COMPEL_UAPI_INCLUDES) ifeq ($(SRCARCH),arm) ccflags-y += -marm endif - -ifneq ($(filter-out ia32,$(ARCH)),) - ccflags-y += -DCR_NOGLIBC -fpie -Wa,--noexecstack -fno-stack-protector -else - ccflags-y += -DCR_NOGLIBC -fno-pic -Wa,--noexecstack -fno-stack-protector -endif - -ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 54a216b14..ccf9dabe5 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -20,7 +20,6 @@ #include "int.h" #include "types.h" #include "common/compiler.h" -#include "string.h" #include #include #include diff --git a/criu/pie/string.c b/criu/pie/string.c deleted file mode 100644 index d15419295..000000000 --- a/criu/pie/string.c +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include "features.h" - -/* C compiler may generate calls to memcmp, memset, memcpy and memmove, - * so it relies on those to be available during linking. - * In case we are not linking our code against glibc, we set CR_NOGLIBC - * and have to provide our own implementations of mem*() functions. - * - * For now, not having memmove() seems OK for both gcc and clang. - */ - -#ifndef ARCH_HAS_MEMCPY -void *memcpy(void *to, const void *from, size_t n) -{ - size_t i; - unsigned char *cto = to; - const unsigned char *cfrom = from; - - for (i = 0; i < n; ++i, ++cto, ++cfrom) - *cto = *cfrom; - - return to; -} -#endif - -#ifndef ARCH_HAS_MEMCMP -int memcmp(const void *cs, const void *ct, size_t count) -{ - const unsigned char *su1, *su2; - int res = 0; - - for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) - if ((res = *su1 - *su2) != 0) - break; - return res; -} -#endif - -int builtin_strncmp(const char *cs, const char *ct, size_t count) -{ - size_t i; - - for (i = 0; i < count; i++) { - if (cs[i] != ct[i]) - return cs[i] < ct[i] ? -1 : 1; - if (!cs[i]) - break; - } - return 0; -} - -#ifndef ARCH_HAS_MEMSET -void *memset(void *s, const int c, size_t count) -{ - char *dest = s; - size_t i = 0; - - while (i < count) - dest[i++] = (char) c; - - return s; -} -#endif diff --git a/criu/pie/util-vdso.c b/criu/pie/util-vdso.c index 1aab3e52a..ef87f07d5 100644 --- a/criu/pie/util-vdso.c +++ b/criu/pie/util-vdso.c @@ -17,13 +17,12 @@ #include "common/bug.h" #ifdef CR_NOGLIBC -# include "string.h" +# include #else # include -# define builtin_strncmp strncmp +# define std_strncmp strncmp #endif - #ifdef LOG_PREFIX # undef LOG_PREFIX #endif @@ -246,7 +245,7 @@ static void parse_elf_symbols(uintptr_t mem, size_t size, Phdr_t *load, continue; name = (void *)addr; - if (builtin_strncmp(name, symbol, vdso_symbol_length)) + if (std_strncmp(name, symbol, vdso_symbol_length)) continue; memcpy(t->symbols[i].name, name, vdso_symbol_length); From e73434cc4cd5a5773c3014c6e358d32f4917050d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 10 Feb 2017 19:48:00 +0300 Subject: [PATCH 0354/4375] criu: Kill syscall-types.h header Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cgroup.c | 2 +- criu/include/syscall-types.h | 56 ------------------------------------ 2 files changed, 1 insertion(+), 57 deletions(-) delete mode 100644 criu/include/syscall-types.h diff --git a/criu/cgroup.c b/criu/cgroup.c index 5036be430..c4eea8dcc 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "common/list.h" #include "xmalloc.h" #include "cgroup.h" @@ -19,7 +20,6 @@ #include "util-pie.h" #include "namespaces.h" #include "seize.h" -#include "syscall-types.h" #include "protobuf.h" #include "images/core.pb-c.h" #include "images/cgroup.pb-c.h" diff --git a/criu/include/syscall-types.h b/criu/include/syscall-types.h deleted file mode 100644 index fb036717f..000000000 --- a/criu/include/syscall-types.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Please add here type definitions if - * syscall prototypes need them. - * - * Anything else should go to plain type.h - */ - -#ifndef __CR_SYSCALL_TYPES_H__ -#define __CR_SYSCALL_TYPES_H__ - -#include -#include -#include -#include -#include -#include "int.h" - -struct cap_header { - u32 version; - int pid; -}; - -struct cap_data { - u32 eff; - u32 prm; - u32 inh; -}; - -struct sockaddr; -struct msghdr; -struct rusage; -struct file_handle; -struct robust_list_head; -struct io_event; -struct iocb; -struct timespec; - -typedef unsigned long aio_context_t; - -struct itimerspec; - -#ifndef F_GETFD -#define F_GETFD 1 -#endif - -struct krlimit { - unsigned long rlim_cur; - unsigned long rlim_max; -}; - -struct siginfo; - -/* Type of timers in the kernel. */ -typedef int kernel_timer_t; - -#endif /* __CR_SYSCALL_TYPES_H__ */ From 909590a3558560655c1ce5b72215efbb325999ca Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 10 Feb 2017 13:27:00 +0300 Subject: [PATCH 0355/4375] Remove criu exec code It's now obsoleted by compel library. Maybe-TODO: Add compel tool exec action? Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/infect-priv.h | 8 -- compel/src/lib/infect.c | 2 +- criu/Makefile.crtools | 1 - criu/cr-exec.c | 198 ----------------------------------- criu/crtools.c | 20 ++-- 5 files changed, 7 insertions(+), 222 deletions(-) delete mode 100644 criu/cr-exec.c diff --git a/compel/include/infect-priv.h b/compel/include/infect-priv.h index 99f9adab6..cf0ce3a92 100644 --- a/compel/include/infect-priv.h +++ b/compel/include/infect-priv.h @@ -53,14 +53,6 @@ struct parasite_thread_ctl { struct ctl_msg; int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m); -/* XXX -- remove with cr-exec.c */ -extern int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size); -extern int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, - unsigned long arg1, unsigned long arg2, - unsigned long arg3, unsigned long arg4, - unsigned long arg5, unsigned long arg6); - - extern void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs); extern void *remote_mmap(struct parasite_ctl *ctl, void *addr, size_t length, int prot, diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index fea7e6b55..78c9655ef 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -817,7 +817,7 @@ void compel_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *el } } -int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size) +static int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size) { int ret; diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 04d96e82e..ea0e81521 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -14,7 +14,6 @@ obj-y += cr-check.o obj-y += cr-dedup.o obj-y += cr-dump.o obj-y += cr-errno.o -#obj-y += cr-exec.o obj-y += cr-restore.o obj-y += cr-service.o obj-y += crtools.o diff --git a/criu/cr-exec.c b/criu/cr-exec.c deleted file mode 100644 index ca764667c..000000000 --- a/criu/cr-exec.c +++ /dev/null @@ -1,198 +0,0 @@ -#include -#include -#include -#include "int.h" -#include "types.h" -#include "crtools.h" -#include "parasite-syscall.h" -#include "proc_parse.h" -#include "ptrace.h" -#include "pstree.h" -#include "vma.h" -#include "log.h" -#include "util.h" -#include "kerndat.h" -#include - -struct syscall_exec_desc { - char *name; - unsigned nr; -}; - -#define SYSCALL(__name, __nr) { .name = #__name, .nr = __nr, }, -#include "sys-exec-tbl.c" -#undef SYSCALL - -#ifndef ARCH_HAS_FIND_SYSCALL -struct syscall_exec_desc * -find_syscall(char *name, struct parasite_ctl __always_unused *ctl) -{ - int i; - - for (i = 0; sc_exec_table[i].name != NULL; i++) - if (!strcmp(sc_exec_table[i].name, name)) - return &sc_exec_table[i]; - - return NULL; -} -#endif - -#define MAX_ARGS 6 - -static int execute_syscall(struct parasite_ctl *ctl, - struct syscall_exec_desc *scd, char **opt) -{ - int i, err; - unsigned long args[MAX_ARGS] = {}, ret, r_mem_size = 0; - unsigned int ret_args[MAX_ARGS] = {}; - void *r_mem = NULL; - - for (i = 0; i < MAX_ARGS; i++) { - if (opt[i] == NULL) - break; - - /* - * &foo -- argument string "foo" - * @ -- ret-arg of size - */ - - if ((opt[i][0] == '&') || (opt[i][0] == '@')) { - int len; - - if (!r_mem) { - err = compel_map_exchange(ctl, PAGE_SIZE); - if (err) - return err; - - r_mem_size = PAGE_SIZE; - r_mem = ctl->local_map; - } - - if (opt[i][0] == '&') { - len = strlen(opt[i]); - if (r_mem_size < len) { - pr_err("Arg size overflow\n"); - return -1; - } - - memcpy(r_mem, opt[i] + 1, len); - } else { - len = strtol(opt[i] + 1, NULL, 0); - if (!len || (r_mem_size < len)) { - pr_err("Bad argument size %d\n", len); - return -1; - } - - ret_args[i] = len; - } - - args[i] = (unsigned long)ctl->remote_map + (r_mem - ctl->local_map); - pr_info("Pushing %c mem arg [%s]\n", opt[i][0], (char *)r_mem); - r_mem_size -= len; - r_mem += len; - } else - args[i] = strtol(opt[i], NULL, 0); - } - - pr_info("Calling %d with %lu %lu %lu %lu %lu %lu\n", scd->nr, - args[0], args[1], args[2], args[3], args[4], args[5]); - - err = compel_syscall(ctl, scd->nr, &ret, - args[0], args[1], args[2], args[3], args[4], args[5]); - if (err) - return err; - - pr_msg("Syscall returned %lx(%d)\n", ret, (int)ret); - for (i = 0; i < MAX_ARGS; i++) { - unsigned long addr; - - if (!ret_args[i]) - continue; - - pr_msg("Argument %d returns:\n", i); - addr = (unsigned long)ctl->local_map + (args[i] - (unsigned long)ctl->remote_map); - print_data(0, (unsigned char *)addr, ret_args[i]); - } - - return 0; -} - -int cr_exec(int pid, char **opt) -{ - char *sys_name = opt[0]; - struct syscall_exec_desc *si; - struct parasite_ctl *ctl; - struct vm_area_list vmas; - int ret, prev_state, exit_code = -1; - struct proc_status_creds creds; - unsigned long p_start; - - if (!sys_name) { - pr_err("Syscall name required\n"); - goto out; - } - - if (kerndat_init_cr_exec()) { - pr_err("Failed to init kerndat\n"); - goto out; - } - - if (compel_interrupt_task(pid)) - goto out; - - /* - * We don't seize a task's threads here, so there is no reason to - * mess with creds in this use case anyway. - */ - - prev_state = ret = compel_wait_task(pid, -1, parse_pid_status, &creds.s); - if (ret < 0) { - pr_err("Can't seize task %d\n", pid); - goto out; - } - - if (!is_alive_state(prev_state)) { - pr_err("Only can exec on running/stopped tasks\n"); - goto out; - } - - ret = collect_mappings(pid, &vmas, NULL); - if (ret) { - pr_err("Can't collect vmas for %d\n", pid); - goto out_unseize; - } - - p_start = get_exec_start(&vmas); - if (!p_start) { - pr_err("No suitable VM are found\n"); - goto out_unseize; - } - - ctl = compel_prepare(pid); - if (!ctl) { - pr_err("Can't prep ctl %d\n", pid); - goto out_unseize; - } - - ctl->ictx.syscall_ip = p_start; - - si = find_syscall(sys_name, ctl); - if (!si) { - pr_err("Unknown syscall [%s]\n", sys_name); - goto out_cure; - } - - ret = execute_syscall(ctl, si, opt + 1); - if (ret < 0) { - pr_err("Can't execute syscall remotely\n"); - goto out_cure; - } - - exit_code = 0; -out_cure: - compel_cure(ctl); -out_unseize: - compel_resume_task(pid, prev_state, prev_state); -out: - return exit_code; -} diff --git a/criu/crtools.c b/criu/crtools.c index 3c761a557..785c78b41 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -646,6 +646,11 @@ int main(int argc, char *argv[], char *envp[]) goto usage; } + if (!strcmp(argv[optind], "exec")) { + pr_msg("The \"exec\" action is deprecated by the Compel library.\n"); + return -1; + } + has_sub_command = (argc - optind) > 1; if (has_exec_cmd) { @@ -671,8 +676,7 @@ int main(int argc, char *argv[], char *envp[]) opts.exec_cmd[argc - optind - 1] = NULL; } else { /* No subcommands except for cpuinfo and restore --exec-cmd */ - if ((strcmp(argv[optind], "cpuinfo") && strcmp(argv[optind], "exec")) - && has_sub_command) { + if (strcmp(argv[optind], "cpuinfo") && has_sub_command) { pr_msg("Error: excessive parameter%s for command %s\n", (argc - optind) > 2 ? "s" : "", argv[optind]); goto usage; @@ -765,16 +769,6 @@ int main(int argc, char *argv[], char *envp[]) if (!strcmp(argv[optind], "check")) return cr_check() != 0; -#if 0 - if (!strcmp(argv[optind], "exec")) { - if (!pid) - pid = tree_id; /* old usage */ - if (!pid) - goto opt_pid_missing; - return cr_exec(pid, argv + optind + 1) != 0; - } -#endif - if (!strcmp(argv[optind], "page-server")) return cr_page_server(opts.daemon_mode, -1) != 0; @@ -802,7 +796,6 @@ usage: " criu dump|pre-dump -t PID []\n" " criu restore []\n" " criu check [--feature FEAT]\n" -" criu exec -p PID \n" " criu page-server\n" " criu service []\n" " criu dedup\n" @@ -812,7 +805,6 @@ usage: " pre-dump pre-dump task(s) minimizing their frozen time\n" " restore restore a process/tree\n" " check checks whether the kernel support is up-to-date\n" -" exec execute a system call by other task\n" " page-server launch page server\n" " service launch service\n" " dedup remove duplicates in memory dump\n" From b729c187d51f1dffef10ea719c75b66b5772000b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 15 Feb 2017 01:30:06 +0300 Subject: [PATCH 0356/4375] compel: arch,x86 -- Drop native ia32 pieces It was never functional neither we plan to support native ia32 mode, so drop these incomplete code pieces out. - Presumably we will need TASK_SIZE for compat mode so I provide TASK_SIZE_IA32 for this sake - 32 bit syscalls are remaining for a while Acked-by: Dmitry Safonov Acked-by: Pavel Emelyanov Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/Makefile | 14 ---------- .../x86/plugins/std/parasite-head-compat.S | 23 ---------------- compel/arch/x86/src/lib/handle-elf.c | 10 +------ compel/arch/x86/src/lib/include/handle-elf.h | 13 --------- .../src/lib/include/uapi/asm/infect-types.h | 11 -------- .../x86/src/lib/include/uapi/asm/sigframe.h | 27 ------------------- compel/arch/x86/src/lib/infect.c | 7 ++--- compel/src/lib/handle-elf-32-host.c | 1 - compel/src/lib/handle-elf-32.c | 1 - 9 files changed, 3 insertions(+), 104 deletions(-) delete mode 100644 compel/arch/x86/plugins/std/parasite-head-compat.S delete mode 120000 compel/src/lib/handle-elf-32-host.c delete mode 120000 compel/src/lib/handle-elf-32.c diff --git a/compel/Makefile b/compel/Makefile index 204e19f0c..159a3e1cc 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -33,29 +33,15 @@ CFLAGS += -DNO_RELOCS HOSTCFLAGS += -DNO_RELOCS endif -ifeq ($(ARCH),x86) -obj-y += src/lib/handle-elf-32.o -endif - obj-y += src/main.o obj-y += arch/$(ARCH)/src/lib/handle-elf.o obj-y += src/lib/handle-elf.o -ifeq ($(ARCH),x86) -CFLAGS_handle-elf-32.o += -UCONFIG_X86_64 -DCONFIG_X86_32 -CFLAGS_handle-elf-32.d += -UCONFIG_X86_64 -DCONFIG_X86_32 -endif - host-ccflags-y += $(ccflags-y) hostprogs-y += compel-host-bin compel-host-bin-objs := $(patsubst %.o,%-host.o,$(obj-y) $(host-lib-y)) -ifeq ($(ARCH),x86) -HOSTCFLAGS_handle-elf-32-host.o += -UCONFIG_X86_64 -DCONFIG_X86_32 -HOSTCFLAGS_handle-elf-32-host.d += -UCONFIG_X86_64 -DCONFIG_X86_32 -endif - cleanup-y += compel/compel cleanup-y += compel/compel-host-bin cleanup-y += compel/libcompel.so diff --git a/compel/arch/x86/plugins/std/parasite-head-compat.S b/compel/arch/x86/plugins/std/parasite-head-compat.S deleted file mode 100644 index f08cc1c3c..000000000 --- a/compel/arch/x86/plugins/std/parasite-head-compat.S +++ /dev/null @@ -1,23 +0,0 @@ -#include "common/asm/linkage.h" - - .section .head.text, "ax" - -#ifndef CONFIG_X86_32 -# error 32-bit parasite should compile with CONFIG_X86_32 -#endif - -ENTRY(__export_parasite_head_start) - subl $16, %esp - andl $~15, %esp - pushl $0 - movl %esp, %ebp - call 1f -1: popl %ecx - movl (__export_parasite_cmd-1b)(%ecx), %eax - leal (__export_parasite_args-1b)(%ecx), %edx - call parasite_service - int $0x03 - .align 8 -GLOBAL(__export_parasite_cmd) - .long 0 -END(__export_parasite_head_start) diff --git a/compel/arch/x86/src/lib/handle-elf.c b/compel/arch/x86/src/lib/handle-elf.c index 38e27abd3..62fb28f49 100644 --- a/compel/arch/x86/src/lib/handle-elf.c +++ b/compel/arch/x86/src/lib/handle-elf.c @@ -12,17 +12,9 @@ elf_ident_64_le[EI_NIDENT] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static const unsigned char __maybe_unused -elf_ident_32[EI_NIDENT] = { - 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - int handle_binary(void *mem, size_t size) { - if (memcmp(mem, elf_ident_32, sizeof(elf_ident_32)) == 0) - return handle_elf_x86_32(mem, size); - else if (memcmp(mem, elf_ident_64_le, sizeof(elf_ident_64_le)) == 0) + if (memcmp(mem, elf_ident_64_le, sizeof(elf_ident_64_le)) == 0) return handle_elf_x86_64(mem, size); pr_err("Unsupported Elf format detected\n"); diff --git a/compel/arch/x86/src/lib/include/handle-elf.h b/compel/arch/x86/src/lib/include/handle-elf.h index bfc935a4e..08de8363f 100644 --- a/compel/arch/x86/src/lib/include/handle-elf.h +++ b/compel/arch/x86/src/lib/include/handle-elf.h @@ -1,17 +1,6 @@ #ifndef COMPEL_HANDLE_ELF_H__ #define COMPEL_HANDLE_ELF_H__ -#ifdef CONFIG_X86_32 - -#include "elf32-types.h" - -#define ELF_X86_32 - -#define __handle_elf handle_elf_x86_32 -#define arch_is_machine_supported(e_machine) (e_machine == EM_386) - -#else /* CONFIG_X86_64 */ - #include "elf64-types.h" #define ELF_X86_64 @@ -19,8 +8,6 @@ #define __handle_elf handle_elf_x86_64 #define arch_is_machine_supported(e_machine) (e_machine == EM_X86_64) -#endif - extern int handle_elf_x86_32(void *mem, size_t size); extern int handle_elf_x86_64(void *mem, size_t size); diff --git a/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h b/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h index 55fcd8106..af42461ae 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h @@ -59,7 +59,6 @@ typedef struct { uint32_t ss; } user_regs_struct32; -#ifdef CONFIG_X86_64 /* * To be sure that we rely on inited reg->__is_native, this member * is (short int) instead of initial (bool). The right way to @@ -90,16 +89,6 @@ static inline bool user_regs_native(user_regs_struct_t *pregs) ((user_regs_native(pregs)) ? \ ((pregs)->native.name = (val)) : \ ((pregs)->compat.name = (val))) -#else -typedef struct { - union { - user_regs_struct32 native; - }; -} user_regs_struct_t; -#define user_regs_native(pregs) true -#define get_user_reg(pregs, name) ((pregs)->native.name) -#define set_user_reg(pregs, name, val) ((pregs)->native.name = val) -#endif #if 0 typedef struct { diff --git a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h index a939bbee1..21cd341c0 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h @@ -83,10 +83,6 @@ typedef struct compat_siginfo { int _pad[128/sizeof(int) - 3]; } compat_siginfo_t; -#ifdef CONFIG_X86_32 -#define rt_sigframe_ia32 rt_sigframe -#endif - typedef struct compat_sigaltstack { compat_uptr_t ss_sp; int ss_flags; @@ -106,11 +102,7 @@ struct rt_sigframe_ia32 { int32_t sig; uint32_t pinfo; uint32_t puc; -#ifdef CONFIG_X86_64 compat_siginfo_t info; -#else - struct rt_siginfo info; -#endif struct ucontext_ia32 uc; char retcode[8]; @@ -118,7 +110,6 @@ struct rt_sigframe_ia32 { fpu_state_t fpu_state; }; -#ifdef CONFIG_X86_64 struct rt_sigframe_64 { char *pretcode; struct rt_ucontext uc; @@ -194,24 +185,6 @@ do { \ else \ ARCH_RT_SIGRETURN_COMPAT(new_sp); \ } while (0) -#else /* CONFIG_X86_64 */ -#define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->uc) -#define RT_SIGFRAME_OFFSET(rt_sigframe) 4 -#define RT_SIGFRAME_REGIP(rt_sigframe) \ - (unsigned long)(rt_sigframe)->uc.uc_mcontext.ip -#define RT_SIGFRAME_FPU(rt_sigframe) (&(rt_sigframe)->fpu_state) -#define RT_SIGFRAME_HAS_FPU(rt_sigframe) (RT_SIGFRAME_FPU(rt_sigframe)->has_fpu) - -#define ARCH_RT_SIGRETURN(new_sp, rt_sigframe) \ - asm volatile( \ - "movl %0, %%eax \n" \ - "movl %%eax, %%esp \n" \ - "movl $"__stringify(__NR_rt_sigreturn)", %%eax \n" \ - "int $0x80 \n" \ - : \ - : "r"(new_sp) \ - : "eax","esp","memory") -#endif /* CONFIG_X86_64 */ int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, struct rt_sigframe *rsigframe); diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index 53f29cfbf..d86e0a811 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -425,14 +425,11 @@ int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs) return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov); } -#ifdef CONFIG_X86_64 -# define TASK_SIZE ((1UL << 47) - PAGE_SIZE) -#else +#define TASK_SIZE ((1UL << 47) - PAGE_SIZE) /* * Task size may be limited to 3G but we need a * higher limit, because it's backward compatible. */ -# define TASK_SIZE (0xffffe000) -#endif +#define TASK_SIZE_IA32 (0xffffe000) unsigned long compel_task_size(void) { return TASK_SIZE; } diff --git a/compel/src/lib/handle-elf-32-host.c b/compel/src/lib/handle-elf-32-host.c deleted file mode 120000 index 126cd5984..000000000 --- a/compel/src/lib/handle-elf-32-host.c +++ /dev/null @@ -1 +0,0 @@ -handle-elf-32.c \ No newline at end of file diff --git a/compel/src/lib/handle-elf-32.c b/compel/src/lib/handle-elf-32.c deleted file mode 120000 index fe4611886..000000000 --- a/compel/src/lib/handle-elf-32.c +++ /dev/null @@ -1 +0,0 @@ -handle-elf.c \ No newline at end of file From c58e1bbc2fe0078c841a2d859fd3333ead5f4fc2 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 15 Feb 2017 01:30:07 +0300 Subject: [PATCH 0357/4375] criu: arch,x86 -- Drop native ia32 pieces Acked-by: Dmitry Safonov Acked-by: Pavel Emelyanov Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 17 ----------------- criu/arch/x86/include/asm/parasite.h | 4 ---- criu/arch/x86/include/asm/restore.h | 9 --------- criu/arch/x86/include/asm/restorer.h | 27 +-------------------------- criu/arch/x86/include/asm/types.h | 4 ---- criu/include/util-vdso.h | 6 +++--- 6 files changed, 4 insertions(+), 63 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 99a0786c8..684955349 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -26,7 +26,6 @@ #include "images/core.pb-c.h" #include "images/creds.pb-c.h" -#ifdef CONFIG_X86_64 int kdat_compat_sigreturn_test(void) { #ifdef CONFIG_COMPAT @@ -49,7 +48,6 @@ int kdat_compat_sigreturn_test(void) #endif return 0; } -#endif /* CONFIG_X86_64 */ int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) { @@ -369,11 +367,7 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) return 0; } -#ifdef CONFIG_X86_64 #define CPREG32(d) f->compat.uc.uc_mcontext.d = r->d -#else -#define CPREG32(d) f->uc.uc_mcontext.d = r->d -#endif static void restore_compat_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) { CPREG32(gs); @@ -387,13 +381,10 @@ static void restore_compat_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) CPREG32(ss); CPREG32(flags); -#ifdef CONFIG_X86_64 f->is_native = false; -#endif } #undef CPREG32 -#ifdef CONFIG_X86_64 #define CPREG64(d, s) f->native.uc.uc_mcontext.d = r->s static void restore_native_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) { @@ -439,11 +430,3 @@ int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) } return 0; } -#else /* !CONFIG_X86_64 */ -int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) -{ - restore_compat_gpregs(f, r); - return 0; -} -#endif - diff --git a/criu/arch/x86/include/asm/parasite.h b/criu/arch/x86/include/asm/parasite.h index 68fad095c..0ef1d9a86 100644 --- a/criu/arch/x86/include/asm/parasite.h +++ b/criu/arch/x86/include/asm/parasite.h @@ -5,10 +5,6 @@ #include #include "asm/compat.h" -#ifdef CONFIG_X86_32 -# define __parasite_entry __attribute__((regparm(3))) -#endif - static int arch_get_user_desc(user_desc_t *desc) { int ret = __NR32_get_thread_area; diff --git a/criu/arch/x86/include/asm/restore.h b/criu/arch/x86/include/asm/restore.h index 7959e686b..a3e7af92f 100644 --- a/criu/arch/x86/include/asm/restore.h +++ b/criu/arch/x86/include/asm/restore.h @@ -5,7 +5,6 @@ #include "images/core.pb-c.h" -#ifdef CONFIG_X86_64 #define JUMP_TO_RESTORER_BLOB(new_sp, restore_task_exec_start, \ task_args) \ asm volatile( \ @@ -19,14 +18,6 @@ "g"(restore_task_exec_start), \ "g"(task_args) \ : "rsp", "rdi", "rsi", "rbx", "rax", "memory") -#else /* CONFIG_X86_64 */ -#define JUMP_TO_RESTORER_BLOB(new_sp, restore_task_exec_start, \ - task_args) \ - (void)new_sp; \ - (void)restore_task_exec_start; \ - (void)task_args; \ - ; -#endif /* CONFIG_X86_64 */ static inline void core_get_tls(CoreEntry *pcore, tls_t *ptls) { diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index 2dc4fe1b7..e8a619620 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -17,7 +17,7 @@ static inline void restore_tls(tls_t *ptls) { } static inline int arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; } #endif /* !CONFIG_COMPAT */ -#ifdef CONFIG_X86_64 + #define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \ thread_args, clone_restore_fn) \ asm volatile( \ @@ -70,27 +70,6 @@ arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; } #endif extern int kdat_compat_sigreturn_test(void); -#else /* CONFIG_X86_64 */ -#define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \ - thread_args, clone_restore_fn) \ - (void)ret; \ - (void)clone_flags; \ - (void)new_sp; \ - (void)parent_tid; \ - (void)thread_args; \ - (void)clone_restore_fn; \ - ; -#define ARCH_FAIL_CORE_RESTORE \ - asm volatile( \ - "movl %0, %%esp \n" \ - "xorl %%eax, %%eax \n" \ - "jmp *%%eax \n" \ - : \ - : "r"(ret) \ - : "memory") - -#define kdat_compat_sigreturn_test() 0 -#endif /* CONFIG_X86_64 */ static inline void __setup_sas_compat(struct ucontext_ia32* uc, ThreadSasEntry *sas) @@ -103,7 +82,6 @@ __setup_sas_compat(struct ucontext_ia32* uc, ThreadSasEntry *sas) static inline void __setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas) { -#ifdef CONFIG_X86_64 if (sigframe->is_native) { struct rt_ucontext *uc = &sigframe->native.uc; @@ -113,9 +91,6 @@ __setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas) } else { __setup_sas_compat(&sigframe->compat.uc, sas); } -#else - __setup_sas_compat(&sigframe->uc, sas); -#endif } static inline void _setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas) diff --git a/criu/arch/x86/include/asm/types.h b/criu/arch/x86/include/asm/types.h index 4a93ffdeb..3ff7fc630 100644 --- a/criu/arch/x86/include/asm/types.h +++ b/criu/arch/x86/include/asm/types.h @@ -12,7 +12,6 @@ #include "images/core.pb-c.h" -#ifdef CONFIG_X86_64 static inline int core_is_compat(CoreEntry *c) { switch (c->thread_info->gpregs->mode) { @@ -24,9 +23,6 @@ static inline int core_is_compat(CoreEntry *c) return -1; } } -#else /* CONFIG_X86_64 */ -static inline int core_is_compat(CoreEntry *c) { return 0; } -#endif /* CONFIG_X86_64 */ #define CORE_ENTRY__MARCH CORE_ENTRY__MARCH__X86_64 diff --git a/criu/include/util-vdso.h b/criu/include/util-vdso.h index 642cee737..ad4a48eb2 100644 --- a/criu/include/util-vdso.h +++ b/criu/include/util-vdso.h @@ -49,7 +49,7 @@ struct vdso_symtable { }, \ } -#if defined(CONFIG_X86_32) || defined(CONFIG_VDSO_32) +#ifdef CONFIG_VDSO_32 #define Ehdr_t Elf32_Ehdr #define Sym_t Elf32_Sym @@ -60,7 +60,7 @@ struct vdso_symtable { #define ELF_ST_TYPE ELF32_ST_TYPE #define ELF_ST_BIND ELF32_ST_BIND -#else /* !CONFIG_X86_32 */ +#else /* CONFIG_VDSO_32 */ #define Ehdr_t Elf64_Ehdr #define Sym_t Elf64_Sym @@ -75,7 +75,7 @@ struct vdso_symtable { #define ELF_ST_BIND ELF64_ST_BIND #endif -#endif /* !CONFIG_X86_32 */ +#endif /* CONFIG_VDSO_32 */ /* Size of VMA associated with vdso */ static inline unsigned long vdso_vma_size(struct vdso_symtable *t) From 9f6edce06c3d8a2a21b14c8a196097122f4a6c2d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 15 Feb 2017 01:30:08 +0300 Subject: [PATCH 0358/4375] criu: arch, x86 -- Don't require alignment on compat frame In compat mode the fpu frame won't be aligned on 32 bit due to kernel specifics. Acked-by: Dmitry Safonov Acked-by: Pavel Emelyanov Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/arch/x86/sigframe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/arch/x86/sigframe.c b/criu/arch/x86/sigframe.c index 7faed892a..755439fcf 100644 --- a/criu/arch/x86/sigframe.c +++ b/criu/arch/x86/sigframe.c @@ -20,7 +20,7 @@ int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, if (sigframe->is_native && (addr % 64ul) == 0ul) { sigframe->native.uc.uc_mcontext.fpstate = &fpu_state->xsave; - } else if (!sigframe->is_native && (addr % 32ul) == 0ul) { + } else if (!sigframe->is_native) { sigframe->compat.uc.uc_mcontext.fpstate = (uint32_t)addr; } else { pr_err("Unaligned address passed: %lx (native %d)\n", From 88014eb029f450c11c28f1e9f9aaf29f239334f6 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 15 Feb 2017 01:30:09 +0300 Subject: [PATCH 0359/4375] compel: arch, x86 -- Don't require compat frame alignment Acked-by: Dmitry Safonov Acked-by: Pavel Emelyanov Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/infect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index d86e0a811..76e116db1 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -115,7 +115,7 @@ int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, if (sigframe->is_native && (addr % 64ul) == 0ul) { sigframe->native.uc.uc_mcontext.fpstate = &fpu_state->xsave; - } else if (!sigframe->is_native && (addr % 32ul) == 0ul) { + } else if (!sigframe->is_native) { sigframe->compat.uc.uc_mcontext.fpstate = (uint32_t)addr; } else { pr_err("Unaligned address passed: %lx (native %d)\n", From 51b10d686401129c7e1c08503295f2c0ec3f77be Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 15 Feb 2017 01:30:10 +0300 Subject: [PATCH 0360/4375] compel: arch, x86 -- Add support of FPU restore in ia32 compat mode To support ia32 compat mode on x86-64 we need to things - extend fpu_state_t type to carry ia32 specifics - fill up additional members in fpu_state_ia32_t type before calling sigreturn (this also requires the uc_mcontext::fpstate won't be aligned on 32 bytes) Because we touches base types in compel the criu has been updated accordingly. Acked-by: Dmitry Safonov Acked-by: Pavel Emelyanov Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- .../arch/x86/src/lib/include/uapi/asm/fpu.h | 48 +++++++- compel/arch/x86/src/lib/infect.c | 113 ++++++++++++++++-- criu/arch/x86/crtools.c | 10 +- criu/arch/x86/sigframe.c | 20 ++-- 4 files changed, 169 insertions(+), 22 deletions(-) diff --git a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h index 7525f153a..f60112b9b 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h @@ -82,9 +82,12 @@ struct xsave_struct { struct ymmh_struct ymmh; } __aligned(FP_MIN_ALIGN_BYTES) __packed; -/* - * This one is used in restorer. - */ +struct xsave_struct_ia32 { + struct i387_fxsave_struct i387; + struct xsave_hdr_struct xsave_hdr; + struct ymmh_struct ymmh; +} __packed; + typedef struct { /* * The FPU xsave area must be continious and FP_MIN_ALIGN_BYTES @@ -96,7 +99,46 @@ typedef struct { uint8_t __pad[sizeof(struct xsave_struct) + FP_XSTATE_MAGIC2_SIZE]; }; + uint8_t has_fpu; +} fpu_state_64_t; + +struct user_i387_ia32_struct { + uint32_t cwd; /* FPU Control Word */ + uint32_t swd; /* FPU Status Word */ + uint32_t twd; /* FPU Tag Word */ + uint32_t fip; /* FPU IP Offset */ + uint32_t fcs; /* FPU IP Selector */ + uint32_t foo; /* FPU Operand Pointer Offset */ + uint32_t fos; /* FPU Operand Pointer Selector */ + uint32_t st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ +} __packed; + +typedef struct { + struct { + struct user_i387_ia32_struct i387_ia32; + + /* Software status information [not touched by FSAVE]: */ + uint32_t status; + } __packed fregs_state; + union { + struct xsave_struct_ia32 xsave; + uint8_t __pad[sizeof(struct xsave_struct) + FP_XSTATE_MAGIC2_SIZE]; + } __packed; +} __packed fpu_state_ia32_t; + +/* + * This one is used in restorer. + */ +typedef struct { + union { + fpu_state_64_t fpu_state_64; + fpu_state_ia32_t fpu_state_ia32; + }; + uint8_t has_fpu; } fpu_state_t; +extern void compel_convert_from_fxsr(struct user_i387_ia32_struct *env, + struct i387_fxsave_struct *fxsave); + #endif /* __CR_ASM_FPU_H__ */ diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index 76e116db1..f1b216650 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -45,6 +45,91 @@ static inline __always_unused void __check_code_syscall(void) BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); } +/* 10-byte legacy floating point register */ +struct fpreg { + uint16_t significand[4]; + uint16_t exponent; +}; + +/* 16-byte floating point register */ +struct fpxreg { + uint16_t significand[4]; + uint16_t exponent; + uint16_t padding[3]; +}; + +#define FPREG_ADDR(f, n) ((void *)&(f)->st_space + (n) * 16) +#define FP_EXP_TAG_VALID 0 +#define FP_EXP_TAG_ZERO 1 +#define FP_EXP_TAG_SPECIAL 2 +#define FP_EXP_TAG_EMPTY 3 + +static inline uint32_t twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave) +{ + struct fpxreg *st; + uint32_t tos = (fxsave->swd >> 11) & 7; + uint32_t twd = (unsigned long)fxsave->twd; + uint32_t tag; + uint32_t ret = 0xffff0000u; + int i; + + for (i = 0; i < 8; i++, twd >>= 1) { + if (twd & 0x1) { + st = FPREG_ADDR(fxsave, (i - tos) & 7); + + switch (st->exponent & 0x7fff) { + case 0x7fff: + tag = FP_EXP_TAG_SPECIAL; + break; + case 0x0000: + if (!st->significand[0] && + !st->significand[1] && + !st->significand[2] && + !st->significand[3]) + tag = FP_EXP_TAG_ZERO; + else + tag = FP_EXP_TAG_SPECIAL; + break; + default: + if (st->significand[3] & 0x8000) + tag = FP_EXP_TAG_VALID; + else + tag = FP_EXP_TAG_SPECIAL; + break; + } + } else { + tag = FP_EXP_TAG_EMPTY; + } + ret |= tag << (2 * i); + } + return ret; +} + +void compel_convert_from_fxsr(struct user_i387_ia32_struct *env, + struct i387_fxsave_struct *fxsave) +{ + struct fpxreg *from = (struct fpxreg *)&fxsave->st_space[0]; + struct fpreg *to = (struct fpreg *)&env->st_space[0]; + int i; + + env->cwd = fxsave->cwd | 0xffff0000u; + env->swd = fxsave->swd | 0xffff0000u; + env->twd = twd_fxsr_to_i387(fxsave); + + env->fip = fxsave->rip; + env->foo = fxsave->rdp; + /* + * should be actually ds/cs at fpu exception time, but + * that information is not available in 64bit mode. + */ + env->fcs = 0x23; /* __USER32_CS */ + env->fos = 0x2b; /* __USER32_DS */ + env->fos |= 0xffff0000; + + for (i = 0; i < 8; ++i) + memcpy(&to[i], &from[i], sizeof(to[0])); +} + int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) @@ -100,7 +185,13 @@ int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, } fpu_state->has_fpu = true; - memcpy(&fpu_state->xsave, fpregs, sizeof(*fpregs)); + if (is_native) { + memcpy(&fpu_state->fpu_state_64.xsave, fpregs, sizeof(*fpregs)); + } else { + memcpy(&fpu_state->fpu_state_ia32.xsave, fpregs, sizeof(*fpregs)); + compel_convert_from_fxsr(&fpu_state->fpu_state_ia32.fregs_state.i387_ia32, + &fpu_state->fpu_state_ia32.xsave.i387); + } return 0; } @@ -111,16 +202,20 @@ int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, fpu_state_t *fpu_state = (sigframe->is_native) ? &rsigframe->native.fpu_state : &rsigframe->compat.fpu_state; - unsigned long addr = (unsigned long)(void *)&fpu_state->xsave; - if (sigframe->is_native && (addr % 64ul) == 0ul) { - sigframe->native.uc.uc_mcontext.fpstate = &fpu_state->xsave; + if (sigframe->is_native) { + unsigned long addr = (unsigned long)(void *)&fpu_state->fpu_state_64.xsave; + + if ((addr % 64ul)) { + pr_err("Unaligned address passed: %lx (native %d)\n", + addr, sigframe->is_native); + return -1; + } + + sigframe->native.uc.uc_mcontext.fpstate = (void *)addr; } else if (!sigframe->is_native) { - sigframe->compat.uc.uc_mcontext.fpstate = (uint32_t)addr; - } else { - pr_err("Unaligned address passed: %lx (native %d)\n", - addr, sigframe->is_native); - return -1; + sigframe->compat.uc.uc_mcontext.fpstate = + (uint32_t)(unsigned long)(void *)&fpu_state->fpu_state_ia32; } return 0; diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 684955349..bce19aa6e 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -302,7 +302,9 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) fpu_state_t *fpu_state = core_is_compat(core) ? &sigframe->compat.fpu_state : &sigframe->native.fpu_state; - struct xsave_struct *x = &fpu_state->xsave; + struct xsave_struct *x = core_is_compat(core) ? + (void *)&fpu_state->fpu_state_ia32.xsave : + (void *)&fpu_state->fpu_state_64.xsave; /* * If no FPU information provided -- we're restoring @@ -334,6 +336,10 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) assign_array(x->i387, core->thread_info->fpregs, st_space); assign_array(x->i387, core->thread_info->fpregs, xmm_space); + if (core_is_compat(core)) + compel_convert_from_fxsr(&fpu_state->fpu_state_ia32.fregs_state.i387_ia32, + &fpu_state->fpu_state_ia32.xsave.i387); + if (compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) { struct fpx_sw_bytes *fpx_sw = (void *)&x->i387.sw_reserved; void *magic2; @@ -355,7 +361,7 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) /* * This should be at the end of xsave frame. */ - magic2 = fpu_state->__pad + sizeof(struct xsave_struct); + magic2 = (void *)x + sizeof(struct xsave_struct); *(u32 *)magic2 = FP_XSTATE_MAGIC2; } diff --git a/criu/arch/x86/sigframe.c b/criu/arch/x86/sigframe.c index 755439fcf..89bfa4a0b 100644 --- a/criu/arch/x86/sigframe.c +++ b/criu/arch/x86/sigframe.c @@ -16,16 +16,20 @@ int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, fpu_state_t *fpu_state = (sigframe->is_native) ? &rsigframe->native.fpu_state : &rsigframe->compat.fpu_state; - unsigned long addr = (unsigned long)(void *)&fpu_state->xsave; - if (sigframe->is_native && (addr % 64ul) == 0ul) { - sigframe->native.uc.uc_mcontext.fpstate = &fpu_state->xsave; + if (sigframe->is_native) { + unsigned long addr = (unsigned long)(void *)&fpu_state->fpu_state_64.xsave; + + if ((addr % 64ul)) { + pr_err("Unaligned address passed: %lx (native %d)\n", + addr, sigframe->is_native); + return -1; + } + + sigframe->native.uc.uc_mcontext.fpstate = (void *)addr; } else if (!sigframe->is_native) { - sigframe->compat.uc.uc_mcontext.fpstate = (uint32_t)addr; - } else { - pr_err("Unaligned address passed: %lx (native %d)\n", - addr, sigframe->is_native); - return -1; + sigframe->compat.uc.uc_mcontext.fpstate = + (uint32_t)(unsigned long)(void *)&fpu_state->fpu_state_ia32; } return 0; From 2b90a35bfc40afbb59a8bb74f33df98e6260a7cc Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 15 Feb 2017 01:30:11 +0300 Subject: [PATCH 0361/4375] test: fpu01 -- Allow running in compat mode We support compat mode now (at least partially) so the test should be allowed. Acked-by: Dmitry Safonov Acked-by: Pavel Emelyanov Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/fpu01.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/fpu01.c b/test/zdtm/static/fpu01.c index c8e6ca19e..bc41b6977 100644 --- a/test/zdtm/static/fpu01.c +++ b/test/zdtm/static/fpu01.c @@ -6,7 +6,7 @@ #include "zdtmtst.h" -#if defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) #include "cpuid.h" From c1d4832d80085b88887f08c86a268458991fc731 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Mon, 13 Feb 2017 16:59:35 -0800 Subject: [PATCH 0362/4375] compel/include/log.h: whitespace cleanup Those macros look twice as long as they should be on my 80-columns terminal. As there is nothing here to justify such width, go ahead and remove the extra tabs, keeping the code within 80 cols. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/include/log.h | 57 ++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/compel/include/log.h b/compel/include/log.h index 4619e8ab4..5423cb84f 100644 --- a/compel/include/log.h +++ b/compel/include/log.h @@ -13,49 +13,50 @@ static inline int pr_quelled(unsigned int loglevel) return compel_log_get_loglevel() < loglevel && loglevel != LOG_MSG; } -extern void compel_print_on_level(unsigned int loglevel, const char *format, ...); +extern void compel_print_on_level(unsigned int loglevel, + const char *format, ...); -#define pr_msg(fmt, ...) \ - compel_print_on_level(LOG_MSG, \ +#define pr_msg(fmt, ...) \ + compel_print_on_level(LOG_MSG, \ fmt, ##__VA_ARGS__) -#define pr_info(fmt, ...) \ - compel_print_on_level(LOG_INFO, \ +#define pr_info(fmt, ...) \ + compel_print_on_level(LOG_INFO, \ LOG_PREFIX fmt, ##__VA_ARGS__) -#define pr_err(fmt, ...) \ - compel_print_on_level(LOG_ERROR, \ - "Error (%s:%d): " LOG_PREFIX fmt, \ +#define pr_err(fmt, ...) \ + compel_print_on_level(LOG_ERROR, \ + "Error (%s:%d): " LOG_PREFIX fmt, \ __FILE__, __LINE__, ##__VA_ARGS__) -#define pr_err_once(fmt, ...) \ - do { \ - static bool __printed; \ - if (!__printed) { \ - pr_err(fmt, ##__VA_ARGS__); \ - __printed = 1; \ - } \ +#define pr_err_once(fmt, ...) \ + do { \ + static bool __printed; \ + if (!__printed) { \ + pr_err(fmt, ##__VA_ARGS__); \ + __printed = 1; \ + } \ } while (0) -#define pr_warn(fmt, ...) \ - compel_print_on_level(LOG_WARN, \ - "Warn (%s:%d): " LOG_PREFIX fmt, \ +#define pr_warn(fmt, ...) \ + compel_print_on_level(LOG_WARN, \ + "Warn (%s:%d): " LOG_PREFIX fmt, \ __FILE__, __LINE__, ##__VA_ARGS__) -#define pr_warn_once(fmt, ...) \ - do { \ - static bool __printed; \ - if (!__printed) { \ - pr_warn(fmt, ##__VA_ARGS__); \ - __printed = 1; \ - } \ +#define pr_warn_once(fmt, ...) \ + do { \ + static bool __printed; \ + if (!__printed) { \ + pr_warn(fmt, ##__VA_ARGS__); \ + __printed = 1; \ + } \ } while (0) -#define pr_debug(fmt, ...) \ - compel_print_on_level(LOG_DEBUG, \ +#define pr_debug(fmt, ...) \ + compel_print_on_level(LOG_DEBUG, \ LOG_PREFIX fmt, ##__VA_ARGS__) -#define pr_perror(fmt, ...) \ +#define pr_perror(fmt, ...) \ pr_err(fmt ": %m\n", ##__VA_ARGS__) #endif /* COMPEL_LOG_H__ */ From b1245247e2490a5bf3587c42e81d028879daaa01 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Mon, 13 Feb 2017 16:59:36 -0800 Subject: [PATCH 0363/4375] compel/uapi: add prefix to log levels These are part of compel UAPI so should be prefixed with COMPEL_ in order to not pollute the namespace. While at it, move from set of defines to an enum, which looks a bit cleaner. Also, kill LOG_UNDEF as it's not used anywhere. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/include/log.h | 13 +++++++------ compel/include/uapi/log.h | 4 ++++ compel/include/uapi/loglevels.h | 21 ++++++++++++++------- compel/plugins/std/log.c | 4 ++-- compel/src/lib/log.c | 2 +- compel/src/main.c | 6 +++--- compel/test/infect/spy.c | 2 +- compel/test/rsys/spy.c | 2 +- 8 files changed, 33 insertions(+), 21 deletions(-) diff --git a/compel/include/log.h b/compel/include/log.h index 5423cb84f..1f0442b78 100644 --- a/compel/include/log.h +++ b/compel/include/log.h @@ -10,22 +10,23 @@ static inline int pr_quelled(unsigned int loglevel) { - return compel_log_get_loglevel() < loglevel && loglevel != LOG_MSG; + return compel_log_get_loglevel() < loglevel + && loglevel != COMPEL_LOG_MSG; } extern void compel_print_on_level(unsigned int loglevel, const char *format, ...); #define pr_msg(fmt, ...) \ - compel_print_on_level(LOG_MSG, \ + compel_print_on_level(COMPEL_LOG_MSG, \ fmt, ##__VA_ARGS__) #define pr_info(fmt, ...) \ - compel_print_on_level(LOG_INFO, \ + compel_print_on_level(COMPEL_LOG_INFO, \ LOG_PREFIX fmt, ##__VA_ARGS__) #define pr_err(fmt, ...) \ - compel_print_on_level(LOG_ERROR, \ + compel_print_on_level(COMPEL_LOG_ERROR, \ "Error (%s:%d): " LOG_PREFIX fmt, \ __FILE__, __LINE__, ##__VA_ARGS__) @@ -39,7 +40,7 @@ extern void compel_print_on_level(unsigned int loglevel, } while (0) #define pr_warn(fmt, ...) \ - compel_print_on_level(LOG_WARN, \ + compel_print_on_level(COMPEL_LOG_WARN, \ "Warn (%s:%d): " LOG_PREFIX fmt, \ __FILE__, __LINE__, ##__VA_ARGS__) @@ -53,7 +54,7 @@ extern void compel_print_on_level(unsigned int loglevel, } while (0) #define pr_debug(fmt, ...) \ - compel_print_on_level(LOG_DEBUG, \ + compel_print_on_level(COMPEL_LOG_DEBUG, \ LOG_PREFIX fmt, ##__VA_ARGS__) #define pr_perror(fmt, ...) \ diff --git a/compel/include/uapi/log.h b/compel/include/uapi/log.h index cd3bf2aff..79dd1f4d5 100644 --- a/compel/include/uapi/log.h +++ b/compel/include/uapi/log.h @@ -1,7 +1,11 @@ #ifndef __COMPEL_UAPI_LOG_H__ #define __COMPEL_UAPI_LOG_H__ + +#include #include + typedef void (*compel_log_fn)(unsigned int lvl, const char *fmt, va_list parms); extern void compel_log_init(compel_log_fn log_fn, unsigned int level); extern unsigned int compel_log_get_loglevel(void); + #endif diff --git a/compel/include/uapi/loglevels.h b/compel/include/uapi/loglevels.h index f7cdcc448..7bf88475d 100644 --- a/compel/include/uapi/loglevels.h +++ b/compel/include/uapi/loglevels.h @@ -1,13 +1,20 @@ #ifndef UAPI_COMPEL_LOGLEVELS_H__ #define UAPI_COMPEL_LOGLEVELS_H__ -#define LOG_UNSET (-1) -#define LOG_MSG (0) /* Print message regardless of log level */ -#define LOG_ERROR (1) /* Errors only, when we're in trouble */ -#define LOG_WARN (2) /* Warnings, dazen and confused but trying to continue */ -#define LOG_INFO (3) /* Informative, everything is fine */ -#define LOG_DEBUG (4) /* Debug only */ +/* + * Log levels used by compel itself (see compel_log_init()), + * also by log functions in the std plugin. + */ -#define DEFAULT_LOGLEVEL LOG_WARN +enum __compel_log_levels +{ + COMPEL_LOG_MSG, /* Print message regardless of log level */ + COMPEL_LOG_ERROR, /* Errors only, when we're in trouble */ + COMPEL_LOG_WARN, /* Warnings */ + COMPEL_LOG_INFO, /* Informative, everything is fine */ + COMPEL_LOG_DEBUG, /* Debug only */ + + COMPEL_DEFAULT_LOGLEVEL = COMPEL_LOG_WARN +}; #endif /* UAPI_COMPEL_LOGLEVELS_H__ */ diff --git a/compel/plugins/std/log.c b/compel/plugins/std/log.c index 52a3f1a30..2d622d658 100644 --- a/compel/plugins/std/log.c +++ b/compel/plugins/std/log.c @@ -2,7 +2,7 @@ #include "common/bitsperlong.h" #include -#include "uapi/std/string.h" +#include #include #include @@ -14,7 +14,7 @@ struct simple_buf { }; static int logfd = -1; -static int cur_loglevel = DEFAULT_LOGLEVEL; +static int cur_loglevel = COMPEL_DEFAULT_LOGLEVEL; static struct timeval start; static void sbuf_log_flush(struct simple_buf *b); diff --git a/compel/src/lib/log.c b/compel/src/lib/log.c index 4c98407c6..d195343e4 100644 --- a/compel/src/lib/log.c +++ b/compel/src/lib/log.c @@ -11,7 +11,7 @@ #include "log.h" -static unsigned int current_loglevel = DEFAULT_LOGLEVEL; +static unsigned int current_loglevel = COMPEL_DEFAULT_LOGLEVEL; static compel_log_fn logfn; void compel_log_init(compel_log_fn log_fn, unsigned int level) diff --git a/compel/src/main.c b/compel/src/main.c index 33dc2aa57..ea3da89a5 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -110,7 +110,7 @@ static void cli_log(unsigned int lvl, const char *fmt, va_list parms) if (pr_quelled(lvl)) return; - if ((lvl == LOG_ERROR) || (lvl == LOG_WARN)) + if ((lvl == COMPEL_LOG_ERROR) || (lvl == COMPEL_LOG_WARN)) f = stderr; vfprintf(f, fmt, parms); @@ -130,7 +130,7 @@ static int usage(int rc) { " -l, --log-level NUM log level (default: %d)\n" " compel -h|--help\n" " compel -V|--version\n" -, DEFAULT_LOGLEVEL +, COMPEL_DEFAULT_LOGLEVEL ); return rc; @@ -283,7 +283,7 @@ static char *gen_prefix(const char *path) int main(int argc, char *argv[]) { - int log_level = DEFAULT_LOGLEVEL; + int log_level = COMPEL_DEFAULT_LOGLEVEL; bool compat = false; bool is_static = false; int opt, idx; diff --git a/compel/test/infect/spy.c b/compel/test/infect/spy.c index c628a0f86..b8a65c345 100644 --- a/compel/test/infect/spy.c +++ b/compel/test/infect/spy.c @@ -24,7 +24,7 @@ static int do_infection(int pid) struct infect_ctx *ictx; int *arg; - compel_log_init(print_vmsg, LOG_DEBUG); + compel_log_init(print_vmsg, COMPEL_LOG_DEBUG); printf("Stopping task\n"); state = compel_stop_task(pid); diff --git a/compel/test/rsys/spy.c b/compel/test/rsys/spy.c index 82c9725d7..f5c999d5a 100644 --- a/compel/test/rsys/spy.c +++ b/compel/test/rsys/spy.c @@ -20,7 +20,7 @@ static int do_rsetsid(int pid) long ret; struct parasite_ctl *ctl; - compel_log_init(print_vmsg, LOG_DEBUG); + compel_log_init(print_vmsg, COMPEL_LOG_DEBUG); printf("Stopping task\n"); state = compel_stop_task(pid); From 6b5b2996d4859206fb57f92ca56453046135cab6 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Mon, 13 Feb 2017 16:59:37 -0800 Subject: [PATCH 0364/4375] compel_print_on_level(): annotate with printf This function works like printf, and it helps the compiler to know that, so it can check whether arguments fit the format string. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/include/log.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compel/include/log.h b/compel/include/log.h index 1f0442b78..559f909ce 100644 --- a/compel/include/log.h +++ b/compel/include/log.h @@ -15,7 +15,8 @@ static inline int pr_quelled(unsigned int loglevel) } extern void compel_print_on_level(unsigned int loglevel, - const char *format, ...); + const char *format, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); #define pr_msg(fmt, ...) \ compel_print_on_level(COMPEL_LOG_MSG, \ From 026968f63ae50840ca8e3e6968ab65324eaac6ea Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Mon, 13 Feb 2017 16:59:38 -0800 Subject: [PATCH 0365/4375] compel std_printf: annotate with printf This function works like printf, and it helps the compiler to know that, so it can check whether arguments fit the format string. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/plugins/include/uapi/std/string.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compel/plugins/include/uapi/std/string.h b/compel/plugins/include/uapi/std/string.h index ddc1ea3cf..5129017d2 100644 --- a/compel/plugins/include/uapi/std/string.h +++ b/compel/plugins/include/uapi/std/string.h @@ -14,7 +14,9 @@ extern void __std_putc(int fd, char c); extern void __std_puts(int fd, const char *s); extern void __std_printk(int fd, const char *format, va_list args); -extern void __std_printf(int fd, const char *format, ...); +extern void __std_printf(int fd, const char *format, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); + #define std_printf(fmt, ...) __std_printf(STDOUT_FILENO, fmt, ##__VA_ARGS__) #define std_puts(s) __std_puts(STDOUT_FILENO, s) From 8b745876da31352e0921bab542a13f6df4c71231 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Mon, 13 Feb 2017 16:59:39 -0800 Subject: [PATCH 0366/4375] compel std: rename printing functions Let's rename the printing functions so their names look more like the standard ones. 1. putc/puts with a file descriptor. __std_putc -> std_dputc __std_puts -> std_dputs There are no standard putc/puts that accept fd as an argument, but the libc convention is to use d prefix for such. Therefore: NOTE we keep the order of the arguments intact, to be in line with the rest of the functions. 2. *printf __std_printk -> std_vdprintf __std_printf -> std_dprintf The reason is, these are the names of libc functions with similar functionality/arguments. Cc: Dmitry Safonov Cc: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/plugins/include/uapi/std/string.h | 15 +++++++-------- compel/plugins/std/string.c | 20 ++++++++++---------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/compel/plugins/include/uapi/std/string.h b/compel/plugins/include/uapi/std/string.h index 5129017d2..c2e4b9345 100644 --- a/compel/plugins/include/uapi/std/string.h +++ b/compel/plugins/include/uapi/std/string.h @@ -11,16 +11,15 @@ #define STDERR_FILENO 2 /* Standard error output. */ -extern void __std_putc(int fd, char c); -extern void __std_puts(int fd, const char *s); -extern void __std_printk(int fd, const char *format, va_list args); -extern void __std_printf(int fd, const char *format, ...) +extern void std_dputc(int fd, char c); +extern void std_dputs(int fd, const char *s); +extern void std_vdprintf(int fd, const char *format, va_list args); +extern void std_dprintf(int fd, const char *format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); - -#define std_printf(fmt, ...) __std_printf(STDOUT_FILENO, fmt, ##__VA_ARGS__) -#define std_puts(s) __std_puts(STDOUT_FILENO, s) -#define std_putchar(c) __std_putc(STDOUT_FILENO, c) +#define std_printf(fmt, ...) std_dprintf(STDOUT_FILENO, fmt, ##__VA_ARGS__) +#define std_puts(s) std_dputs(STDOUT_FILENO, s) +#define std_putchar(c) std_dputc(STDOUT_FILENO, c) extern unsigned long std_strtoul(const char *nptr, char **endptr, int base); extern int std_strcmp(const char *cs, const char *ct); diff --git a/compel/plugins/std/string.c b/compel/plugins/std/string.c index 177d7e653..43db1e34c 100644 --- a/compel/plugins/std/string.c +++ b/compel/plugins/std/string.c @@ -9,15 +9,15 @@ static const char conv_tab[] = "0123456789abcdefghijklmnopqrstuvwxyz"; -void __std_putc(int fd, char c) +void std_dputc(int fd, char c) { sys_write(fd, &c, 1); } -void __std_puts(int fd, const char *s) +void std_dputs(int fd, const char *s) { for (; *s; s++) - __std_putc(fd, *s); + std_dputc(fd, *s); } static size_t __std_vprint_long_hex(char *buf, size_t blen, unsigned long num, char **ps) @@ -74,7 +74,7 @@ done: return blen - (s - buf); } -void __std_printk(int fd, const char *format, va_list args) +void std_vdprintf(int fd, const char *format, va_list args) { const char *s = format; @@ -83,7 +83,7 @@ void __std_printk(int fd, const char *format, va_list args) int along = 0; if (*s != '%') { - __std_putc(fd, *s); + std_dputc(fd, *s); continue; } @@ -97,7 +97,7 @@ void __std_printk(int fd, const char *format, va_list args) switch (*s) { case 's': - __std_puts(fd, va_arg(args, char *)); + std_dputs(fd, va_arg(args, char *)); break; case 'd': __std_vprint_long(buf, sizeof(buf), @@ -105,7 +105,7 @@ void __std_printk(int fd, const char *format, va_list args) va_arg(args, long) : (long)va_arg(args, int), &t); - __std_puts(fd, t); + std_dputs(fd, t); break; case 'x': __std_vprint_long_hex(buf, sizeof(buf), @@ -113,18 +113,18 @@ void __std_printk(int fd, const char *format, va_list args) va_arg(args, long) : (long)va_arg(args, int), &t); - __std_puts(fd, t); + std_dputs(fd, t); break; } } } -void __std_printf(int fd, const char *format, ...) +void std_dprintf(int fd, const char *format, ...) { va_list args; va_start(args, format); - __std_printk(fd, format, args); + std_vdprintf(fd, format, args); va_end(args); } From 63ccf14e22b9168a1a0908faf9d3c7b8b6ed0326 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 9 Feb 2017 20:01:33 -0800 Subject: [PATCH 0367/4375] criu/include/util.h: rm unused macro This macro is not in use since mid-2012 (commit 4806e13 "protobuf: Convert vma_entry to PB format v3"), so I guess it is about time to retire it. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/include/util.h | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/include/util.h b/criu/include/util.h index eee9d4562..277edc142 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -40,7 +40,6 @@ struct list_head; extern void pr_vma(unsigned int loglevel, const struct vma_area *vma_area); #define pr_info_vma(vma_area) pr_vma(LOG_INFO, vma_area) -#define pr_msg_vma(vma_area) pr_vma(LOG_MSG, vma_area) #define pr_vma_list(level, head) \ do { \ From eaa79ea266a2b998c9bdf5a9eec75c3ad11a33e0 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 16 Feb 2017 19:20:36 +0300 Subject: [PATCH 0368/4375] ia32/vdso: pretify helper for mmaping 32bit vDSO Forward CRIU's log fd into helper, so it can actually print errors. This will help to debug troubles with helper, like #273. Log fd can be safely written to, as it's opened in CRIU with O_APPEND or it's line-buffered (stdout) or not buffered (stderr) stream. Anyway, it's double safe, as there is simple synchronization between helper and CRIU, so only one of them will log at a time. Also expanded the comment about a helper. Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/vdso.c | 76 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index d7066b189..770853514 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -17,7 +17,7 @@ #include "kerndat.h" #include "vdso.h" #include "util.h" -#include "log.h" +#include "criu-log.h" #include "mem.h" #include "vma.h" #include @@ -330,39 +330,62 @@ static int vdso_fill_self_symtable(struct vdso_symtable *s) } #ifdef CONFIG_COMPAT +static void exit_on(int ret, int err_fd, char *reason) +{ + if (ret) { + syscall(__NR_write, err_fd, reason, strlen(reason)); + syscall(__NR_exit, ret); + } +} /* - * The helper runs under fork() - it remaps vdso/vvar blobs to compatible. - * After that it copies them into shared with parent mmaped vma so that - * parent could parse compat vdso's symbols and blob sizes into vdso_compat_rt. - * All system calls should be as light as possible after unmapping vdso. - * If we call something clever through Glibc here - the child will blow up. + * Because of restrictions of ARCH_MAP_VDSO_* API, new vDSO blob + * can be mapped only if there is no vDSO blob present for a process. + * This is a helper process, it unmaps 64-bit vDSO and maps 32-bit vDSO. + * Then it copies vDSO blob to shared with CRIU mapping. + * + * The purpose is to fill compat vdso's symtable (vdso_compat_rt). + * It's an optimization to fill symtable only once at CRIU restore + * for all restored tasks. + * + * @native - 64-bit vDSO blob (for easy unmap) + * @pipe_fd - to get size of compat blob from /proc/.../maps + * @err_fd - to print error messages + * @vdso_buf, buf_size - shared with CRIU buffer + * + * WARN: This helper shouldn't call pr_err() or any syscall with + * Glibc's wrapper function - it may very likely blow up. */ static void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd, - void *vdso_buf, size_t buf_size) + int err_fd, void *vdso_buf, size_t buf_size) { size_t vma_size; void *vdso_addr; long vdso_size; + long ret; vma_size = native->vma_end - native->vma_start; - if (syscall(__NR_munmap, native->vma_start, vma_size)) - syscall(__NR_exit, 2); + ret = syscall(__NR_munmap, native->vma_start, vma_size); + exit_on(ret, err_fd, "Error: Failed to unmap native vdso\n"); vma_size = native->vvar_end - native->vvar_start; - if (syscall(__NR_munmap, native->vvar_start, vma_size)) - syscall(__NR_exit, 3); + ret = syscall(__NR_munmap, native->vvar_start, vma_size); + exit_on(ret, err_fd, "Error: Failed to unmap native vvar\n"); - vdso_size = syscall(__NR_arch_prctl, - ARCH_MAP_VDSO_32, native->vma_start); - if (vdso_size < 0) - syscall(__NR_exit, 4); + ret = syscall(__NR_arch_prctl, ARCH_MAP_VDSO_32, native->vma_start); + if (ret < 0) + exit_on(ret, err_fd, "Error: ARCH_MAP_VDSO failed\n"); + + vdso_size = ret; if (vdso_size > buf_size) - syscall(__NR_exit, 5); + exit_on(-1, err_fd, "Error: Compatible vdso's size is bigger than reserved buf\n"); - syscall(__NR_kill, syscall(__NR_getpid), SIGSTOP); + /* Stop so CRIU could parse smaps to find 32-bit vdso's size */ + ret = syscall(__NR_kill, syscall(__NR_getpid), SIGSTOP); + exit_on(ret, err_fd, "Error: Can't stop myself with SIGSTOP (having a good time)\n"); - if (syscall(__NR_read, pipe_fd, &vdso_addr, sizeof(void *)) != sizeof(void *)) - syscall(__NR_exit, 6); + ret = syscall(__NR_read, pipe_fd, &vdso_addr, sizeof(void *)); + if (ret != sizeof(void *)) + exit_on(-1, err_fd, "Error: Can't read size of mmaped vdso from pipe\n"); memcpy(vdso_buf, vdso_addr, vdso_size); @@ -388,7 +411,8 @@ static int vdso_mmap_compat(struct vdso_symtable *native, syscall(__NR_exit, 1); } - compat_vdso_helper(native, fds[0], vdso_buf, buf_size); + compat_vdso_helper(native, fds[0], log_get_fd(), + vdso_buf, buf_size); BUG(); } @@ -427,13 +451,17 @@ static int vdso_mmap_compat(struct vdso_symtable *native, } waitpid(pid, &status, WUNTRACED); - if (!WIFEXITED(status) || WEXITSTATUS(status)) - pr_err("Compat vdso helper failed\n"); - else - ret = 0; + if (WIFEXITED(status)) { + ret = WEXITSTATUS(status); + if (ret) + pr_err("Helper for mmaping compat vdso failed with %d\n", ret); + goto out_close; + } + pr_err("Compat vDSO helper didn't exit, status: %d\n", status); out_kill: kill(pid, SIGKILL); +out_close: if (close(fds[1])) pr_perror("Failed to close pipe"); return ret; From 0f4b1220db486a27a460ac3e35d47a73ab08edf1 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 16 Feb 2017 19:20:37 +0300 Subject: [PATCH 0369/4375] x86/vdso: add ia32 vdso symbols For 32-bit at this moment there are follwing entries: o __vdso_clock_gettime o __vdso_gettimeofday o __vdso_time o __kernel_vsyscall o __kernel_sigreturn o __kernel_rt_sigreturn So, there isn't __vdso_getcpu(), which is present in 64-bit vDSO, and 64-bit vDSO doesn't have those __kernel_*. This is fine as two vdso blobs with the same not present symbols are considered to be the same in comparison. I didn't introduce ARCH_VDSO_SYMBOLS_32, as it would have different size and that will result in quite painful conversion of struct vdso_symtable (it's fixed size and e.g., inside parasite's parameters) Which is not needed by the described behavior of vdso blobs comparison. Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/include/asm/vdso.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/criu/arch/x86/include/asm/vdso.h b/criu/arch/x86/include/asm/vdso.h index a1cc9bb97..37296f96a 100644 --- a/criu/arch/x86/include/asm/vdso.h +++ b/criu/arch/x86/include/asm/vdso.h @@ -12,13 +12,16 @@ * This is a minimal amount of symbols * we should support at the moment. */ -#define VDSO_SYMBOL_MAX 4 +#define VDSO_SYMBOL_MAX 7 #define ARCH_VDSO_SYMBOLS \ "__vdso_clock_gettime", \ "__vdso_getcpu", \ "__vdso_gettimeofday", \ - "__vdso_time" + "__vdso_time", \ + "__kernel_vsyscall", \ + "__kernel_sigreturn", \ + "__kernel_rt_sigreturn" struct vdso_symtable; From a206326396d5cf77fa6640d039e4f8d6f325a0b4 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 16 Feb 2017 19:20:38 +0300 Subject: [PATCH 0370/4375] zdtm/vdso01: separate handlers calling traversal Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/vdso01.c | 58 +++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/test/zdtm/static/vdso01.c b/test/zdtm/static/vdso01.c index fe52d1947..9572c174c 100644 --- a/test/zdtm/static/vdso01.c +++ b/test/zdtm/static/vdso01.c @@ -359,19 +359,37 @@ static int vdso_time_handler(void *func) return 0; } -int main(int argc, char *argv[]) +static int call_handlers(struct vdso_symtable *symtable) { typedef int (handler_t)(void *func); - - struct vdso_symtable symtable; - size_t i; - handler_t *handlers[VDSO_SYMBOL_MAX] = { [VDSO_SYMBOL_CLOCK_GETTIME] = vdso_clock_gettime_handler, [VDSO_SYMBOL_GETCPU] = vdso_getcpu_handler, [VDSO_SYMBOL_GETTIMEOFDAY] = vdso_gettimeofday_handler, [VDSO_SYMBOL_TIME] = vdso_time_handler, }; + size_t i; + + for (i = 0; i < ARRAY_SIZE(symtable->symbols); i++) { + struct vdso_symbol *s = &symtable->symbols[i]; + handler_t *func; + + if (vdso_symbol_empty(s) || i > ARRAY_SIZE(handlers)) + continue; + func = handlers[i]; + + if (func((void *)(s->offset + symtable->vma_start))) { + pr_perror("Handler error"); + return -1; + } + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + struct vdso_symtable symtable; test_init(argc, argv); @@ -380,19 +398,8 @@ int main(int argc, char *argv[]) return -1; } - for (i = 0; i < ARRAY_SIZE(symtable.symbols); i++) { - struct vdso_symbol *s = &symtable.symbols[i]; - handler_t *func; - - if (vdso_symbol_empty(s) || i > ARRAY_SIZE(handlers)) - continue; - func = handlers[i]; - - if (func((void *)(s->offset + symtable.vma_start))) { - pr_perror("Handler error"); - return -1; - } - } + if (call_handlers(&symtable)) + return -1; test_daemon(); test_waitsig(); @@ -400,18 +407,9 @@ int main(int argc, char *argv[]) /* * After restore the vDSO must remain in old place. */ - for (i = 0; i < ARRAY_SIZE(symtable.symbols); i++) { - struct vdso_symbol *s = &symtable.symbols[i]; - handler_t *func; - - if (vdso_symbol_empty(s) || i > ARRAY_SIZE(handlers)) - continue; - func = handlers[i]; - - if (func((void *)(s->offset + symtable.vma_start))) { - fail("Handler error"); - return -1; - } + if (call_handlers(&symtable)) { + fail("Failed to call vdso handlers from symtable after C/R"); + return -1; } pass(); From 6ae6cbdf46a9a94e95f0c775816c3e3810a0dc81 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 16 Feb 2017 19:20:39 +0300 Subject: [PATCH 0371/4375] zdtm/vdso01: move vdso_symbols upper Remove not needed VDSO_SYMBOL_*_NAME defines. Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/vdso01.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/test/zdtm/static/vdso01.c b/test/zdtm/static/vdso01.c index 9572c174c..d4ff920ad 100644 --- a/test/zdtm/static/vdso01.c +++ b/test/zdtm/static/vdso01.c @@ -51,10 +51,12 @@ enum { VDSO_SYMBOL_MAX }; -#define VDSO_SYMBOL_CLOCK_GETTIME_NAME "__vdso_clock_gettime" -#define VDSO_SYMBOL_GETCPU_NAME "__vdso_getcpu" -#define VDSO_SYMBOL_GETTIMEOFDAY_NAME "__vdso_gettimeofday" -#define VDSO_SYMBOL_TIME_NAME "__vdso_time" +const char *vdso_symbols[VDSO_SYMBOL_MAX] = { + [VDSO_SYMBOL_CLOCK_GETTIME] = "__vdso_clock_gettime", + [VDSO_SYMBOL_GETCPU] = "__vdso_getcpu", + [VDSO_SYMBOL_GETTIMEOFDAY] = "__vdso_gettimeofday", + [VDSO_SYMBOL_TIME] = "__vdso_time", +}; struct vdso_symtable { unsigned long vma_start; @@ -116,13 +118,6 @@ static int vdso_fill_symtable(char *mem, size_t size, struct vdso_symtable *t) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; - const char *vdso_symbols[VDSO_SYMBOL_MAX] = { - [VDSO_SYMBOL_CLOCK_GETTIME] = VDSO_SYMBOL_CLOCK_GETTIME_NAME, - [VDSO_SYMBOL_GETCPU] = VDSO_SYMBOL_GETCPU_NAME, - [VDSO_SYMBOL_GETTIMEOFDAY] = VDSO_SYMBOL_GETTIMEOFDAY_NAME, - [VDSO_SYMBOL_TIME] = VDSO_SYMBOL_TIME_NAME, - }; - char *dynsymbol_names; unsigned int i, j, k; From fcd18783bb5858211db58cd4a48ed4ecb75d12e8 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 16 Feb 2017 19:20:40 +0300 Subject: [PATCH 0372/4375] zdtm/vdso01/ia32: add ia32 test version Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/vdso01.c | 79 +++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/test/zdtm/static/vdso01.c b/test/zdtm/static/vdso01.c index d4ff920ad..f571a87a8 100644 --- a/test/zdtm/static/vdso01.c +++ b/test/zdtm/static/vdso01.c @@ -18,6 +18,47 @@ const char *test_doc = "Check if we can use vDSO using direct vDSO calls\n"; const char *test_author = "Cyrill Gorcunov d_un.d_ptr - load->p_vaddr]; + Sym_t *sym = (void *)&mem[dyn_symtab->d_un.d_ptr - load->p_vaddr]; char *name; sym = &sym[j]; if (__ptr_oob(sym, mem, size)) continue; - if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC && - ELF64_ST_BIND(sym->st_info) != STB_GLOBAL) + if (ELF_ST_TYPE(sym->st_info) != STT_FUNC && + ELF_ST_BIND(sym->st_info) != STB_GLOBAL) continue; name = &dynsymbol_names[sym->st_name]; From 2c34d08055f81f9bff17b37cf56cc6269a2e4b00 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 16 Feb 2017 19:20:41 +0300 Subject: [PATCH 0373/4375] vdso: correct remap messages We should log whom we're remapping, but ~5 lines upper or so we've unmapped dumpee vdso and vvar. Here we're mremapping runtime host-provided vdso/vvar blobs to the dumpee position. Correct the messages to reflect that we've remapped rt-vdso/vvar, having the same naming as in vdso_do_park(). Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/parasite-vdso.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index cb1fdd3f2..df1a985ea 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -209,16 +209,16 @@ int vdso_proxify(char *who, struct vdso_symtable *sym_rt, } if (vma_vdso->start < vma_vvar->start) { - ret = vdso_remap(who, vdso_rt_parked_at, vma_vdso->start, vdso_vma_size(sym_rt)); + ret = vdso_remap("rt-vdso", vdso_rt_parked_at, vma_vdso->start, vdso_vma_size(sym_rt)); vdso_rt_parked_at += vdso_vma_size(sym_rt); - ret |= vdso_remap(who, vdso_rt_parked_at, vma_vvar->start, vvar_vma_size(sym_rt)); + ret |= vdso_remap("rt-vvar", vdso_rt_parked_at, vma_vvar->start, vvar_vma_size(sym_rt)); } else { - ret = vdso_remap(who, vdso_rt_parked_at, vma_vvar->start, vvar_vma_size(sym_rt)); + ret = vdso_remap("rt-vvar", vdso_rt_parked_at, vma_vvar->start, vvar_vma_size(sym_rt)); vdso_rt_parked_at += vvar_vma_size(sym_rt); - ret |= vdso_remap(who, vdso_rt_parked_at, vma_vdso->start, vdso_vma_size(sym_rt)); + ret |= vdso_remap("rt-vdso", vdso_rt_parked_at, vma_vdso->start, vdso_vma_size(sym_rt)); } } else - ret = vdso_remap(who, vdso_rt_parked_at, vma_vdso->start, vdso_vma_size(sym_rt)); + ret = vdso_remap("rt-vdso", vdso_rt_parked_at, vma_vdso->start, vdso_vma_size(sym_rt)); return ret; } From 2261748e418e55ec77375fa7fc719574a6c7de5c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 16 Feb 2017 19:20:42 +0300 Subject: [PATCH 0374/4375] vdso: drop excessive parameter who from vdso_proxify It's always "dumpee" and is used in two pr_err() messages, put it right there. Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/parasite-vdso.h | 2 +- criu/pie/parasite-vdso.c | 6 +++--- criu/pie/restorer.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index efb282a60..8f7aaf9e0 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -81,7 +81,7 @@ static inline bool is_vdso_mark(void *addr) extern int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned long park_size); extern int vdso_map_compat(unsigned long map_at); -extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, +extern int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, size_t index, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso); diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index df1a985ea..e55c23a07 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -103,7 +103,7 @@ int __vdso_fill_symtable(uintptr_t mem, size_t size, } #endif -int vdso_proxify(char *who, struct vdso_symtable *sym_rt, +int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, size_t index, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso) { @@ -197,14 +197,14 @@ int vdso_proxify(char *who, struct vdso_symtable *sym_rt, if (sys_munmap((void *)(uintptr_t)vma_vdso->start, vma_entry_len(vma_vdso))) { - pr_err("Failed to unmap %s\n", who); + pr_err("Failed to unmap dumpee\n"); return -1; } if (vma_vvar) { if (sys_munmap((void *)(uintptr_t)vma_vvar->start, vma_entry_len(vma_vvar))) { - pr_err("Failed to unmap %s\n", who); + pr_err("Failed to unmap dumpee\n"); return -1; } diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index ccf9dabe5..9ead57199 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1188,7 +1188,7 @@ long __export_restore_task(struct task_restore_args *args) for (i = 0; i < args->vmas_n; i++) { if (vma_entry_is(&args->vmas[i], VMA_AREA_VDSO) || vma_entry_is(&args->vmas[i], VMA_AREA_VVAR)) { - if (vdso_proxify("dumpee", &args->vdso_sym_rt, + if (vdso_proxify(&args->vdso_sym_rt, args->vdso_rt_parked_at, i, args->vmas, args->vmas_n, args->compatible_mode)) From 9062e59e5ef54aec2018e669c8e221415504f0be Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 16 Feb 2017 19:20:43 +0300 Subject: [PATCH 0375/4375] vdso: move VMAs traverse cycle in vdso_proxify() Reduce __export_restore_task(), which is fat and too long, drop needless parameter from vdso_proxify() and drop also that find-tuple logic, which isn't needed really. Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/parasite-vdso.h | 2 +- criu/pie/parasite-vdso.c | 29 ++++++++++++++++------------- criu/pie/restorer.c | 14 +++----------- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index 8f7aaf9e0..11a4135e0 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -82,7 +82,7 @@ static inline bool is_vdso_mark(void *addr) extern int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned long park_size); extern int vdso_map_compat(unsigned long map_at); extern int vdso_proxify(struct vdso_symtable *sym_rt, - unsigned long vdso_rt_parked_at, size_t index, + unsigned long vdso_rt_parked_at, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso); #else /* CONFIG_VDSO */ diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index e55c23a07..dc4d03376 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -104,26 +104,29 @@ int __vdso_fill_symtable(uintptr_t mem, size_t size, #endif int vdso_proxify(struct vdso_symtable *sym_rt, - unsigned long vdso_rt_parked_at, size_t index, + unsigned long vdso_rt_parked_at, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso) { VmaEntry *vma_vdso = NULL, *vma_vvar = NULL; struct vdso_symtable s = VDSO_SYMTABLE_INIT; bool remap_rt = false; + unsigned int i; - /* - * Figure out which kind of vdso tuple we get. - */ - if (vma_entry_is(&vmas[index], VMA_AREA_VDSO)) - vma_vdso = &vmas[index]; - else if (vma_entry_is(&vmas[index], VMA_AREA_VVAR)) - vma_vvar = &vmas[index]; + for (i = 0; i < nr_vmas; i++) { + if (vma_entry_is(&vmas[i], VMA_AREA_VDSO)) + vma_vdso = &vmas[i]; + else if (vma_entry_is(&vmas[i], VMA_AREA_VVAR)) + vma_vvar = &vmas[i]; + } - if (index < (nr_vmas - 1)) { - if (vma_entry_is(&vmas[index + 1], VMA_AREA_VDSO)) - vma_vdso = &vmas[index + 1]; - else if (vma_entry_is(&vmas[index + 1], VMA_AREA_VVAR)) - vma_vvar = &vmas[index + 1]; + if (!vma_vdso && !vma_vvar) { + pr_info("No VVAR, no vDSO in image\n"); + /* + * We don't have to unmap rt-vdso, rt-vvar as they will + * be unmapped with restorer blob in the end, + * see __export_unmap() + */ + return 0; } if (!vma_vdso) { diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 9ead57199..929c478b7 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1185,17 +1185,9 @@ long __export_restore_task(struct task_restore_args *args) /* * Proxify vDSO. */ - for (i = 0; i < args->vmas_n; i++) { - if (vma_entry_is(&args->vmas[i], VMA_AREA_VDSO) || - vma_entry_is(&args->vmas[i], VMA_AREA_VVAR)) { - if (vdso_proxify(&args->vdso_sym_rt, - args->vdso_rt_parked_at, - i, args->vmas, args->vmas_n, - args->compatible_mode)) - goto core_restore_end; - break; - } - } + if (vdso_proxify(&args->vdso_sym_rt, args->vdso_rt_parked_at, + args->vmas, args->vmas_n, args->compatible_mode)) + goto core_restore_end; #endif /* From d4a60bb201cd647ae5d682dc92665f26dcc20187 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 16 Feb 2017 19:20:44 +0300 Subject: [PATCH 0376/4375] restorer/fault: add fault-injection into restorer Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 1 + criu/include/fault-injection.h | 19 +++++++++++++++---- criu/include/restorer.h | 3 +++ criu/pie/restorer.c | 7 +++++++ 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 92964d7ee..c87cc44b5 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3035,6 +3035,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns } task_args->breakpoint = &rsti(current)->breakpoint; + task_args->fault_strategy = fi_strategy; sigemptyset(&blockmask); sigaddset(&blockmask, SIGCHLD); diff --git a/criu/include/fault-injection.h b/criu/include/fault-injection.h index 2b23f54bd..5b3313667 100644 --- a/criu/include/fault-injection.h +++ b/criu/include/fault-injection.h @@ -18,10 +18,7 @@ enum faults { FI_MAX, }; -extern enum faults fi_strategy; -extern int fault_injection_init(void); - -static inline bool fault_injected(enum faults f) +static inline bool __fault_injected(enum faults f, enum faults fi_strategy) { /* * Temporary workaround for Xen guests. Breakpoints degrade @@ -33,4 +30,18 @@ static inline bool fault_injected(enum faults f) return fi_strategy == f; } + +#ifndef CR_NOGLIBC + +extern enum faults fi_strategy; +#define fault_injected(f) __fault_injected(f, fi_strategy) + +extern int fault_injection_init(void); + +#else /* CR_NOGLIBC */ + +extern bool fault_injected(enum faults f); + +#endif + #endif diff --git a/criu/include/restorer.h b/criu/include/restorer.h index fb7d89e49..d0f786d94 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -18,6 +18,7 @@ #include "timerfd.h" #include "shmem.h" #include "parasite-vdso.h" +#include "fault-injection.h" #include @@ -182,6 +183,8 @@ struct task_restore_args { unsigned long vdso_rt_parked_at; /* safe place to keep vdso */ #endif void **breakpoint; + + enum faults fault_strategy; } __aligned(64); /* diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 929c478b7..0d6e3b9da 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -61,6 +61,11 @@ static pid_t *helpers; static int n_helpers; static pid_t *zombies; static int n_zombies; +static enum faults fi_strategy; +bool fault_injected(enum faults f) +{ + return __fault_injected(f, fi_strategy); +} /* * These are stubs for std compel plugin. @@ -1087,6 +1092,8 @@ long __export_restore_task(struct task_restore_args *args) vdso_rt_size = args->vdso_rt_size; #endif + fi_strategy = args->fault_strategy; + task_entries_local = args->task_entries; helpers = args->helpers; n_helpers = args->helpers_n; From a90c07d6ddcb2df31fdf40ddc6ed7a94237cf452 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 16 Feb 2017 19:20:45 +0300 Subject: [PATCH 0377/4375] fault/vdso/restorer: add force-injection of trampolines To check that jump trampolines to rt-vdso works. Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/fault-injection.h | 1 + criu/include/parasite-vdso.h | 3 ++- criu/pie/parasite-vdso.c | 8 ++++---- criu/pie/restorer.c | 3 ++- test/jenkins/criu-fault.sh | 1 + 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/criu/include/fault-injection.h b/criu/include/fault-injection.h index 5b3313667..46a5f71b0 100644 --- a/criu/include/fault-injection.h +++ b/criu/include/fault-injection.h @@ -11,6 +11,7 @@ enum faults { FI_PARASITE_CONNECT, FI_POST_RESTORE, /* not fatal */ + FI_VDSO_TRAMPOLINES = 127, FI_CHECK_OPEN_HANDLE = 128, FI_NO_MEMFD = 129, FI_NO_BREAKPOINTS = 130, diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index 11a4135e0..ae9584512 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -83,7 +83,8 @@ extern int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, uns extern int vdso_map_compat(unsigned long map_at); extern int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, - VmaEntry *vmas, size_t nr_vmas, bool compat_vdso); + VmaEntry *vmas, size_t nr_vmas, + bool compat_vdso, bool force_trampolines); #else /* CONFIG_VDSO */ #define vdso_do_park(sym_rt, park_at, park_size) (0) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index dc4d03376..fb37f9f38 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -103,9 +103,9 @@ int __vdso_fill_symtable(uintptr_t mem, size_t size, } #endif -int vdso_proxify(struct vdso_symtable *sym_rt, - unsigned long vdso_rt_parked_at, - VmaEntry *vmas, size_t nr_vmas, bool compat_vdso) +int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, + VmaEntry *vmas, size_t nr_vmas, + bool compat_vdso, bool force_trampolines) { VmaEntry *vma_vdso = NULL, *vma_vvar = NULL; struct vdso_symtable s = VDSO_SYMTABLE_INIT; @@ -193,7 +193,7 @@ int vdso_proxify(struct vdso_symtable *sym_rt, * by a caller code. So drop VMA_AREA_REGULAR from it and caller would * not touch it anymore. */ - if (remap_rt) { + if (remap_rt && !force_trampolines) { int ret = 0; pr_info("Runtime vdso/vvar matches dumpee, remap inplace\n"); diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 0d6e3b9da..c91c6b5dd 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1193,7 +1193,8 @@ long __export_restore_task(struct task_restore_args *args) * Proxify vDSO. */ if (vdso_proxify(&args->vdso_sym_rt, args->vdso_rt_parked_at, - args->vmas, args->vmas_n, args->compatible_mode)) + args->vmas, args->vmas_n, args->compatible_mode, + fault_injected(FI_VDSO_TRAMPOLINES))) goto core_restore_end; #endif diff --git a/test/jenkins/criu-fault.sh b/test/jenkins/criu-fault.sh index 7ed26802b..b7879116d 100755 --- a/test/jenkins/criu-fault.sh +++ b/test/jenkins/criu-fault.sh @@ -9,6 +9,7 @@ prep ./test/zdtm.py run -t zdtm/static/inotify_irmap --fault 128 --keep-going --pre 2 -f uns || fail ./test/zdtm.py run -t zdtm/static/env00 --fault 129 -f uns || fail ./test/zdtm.py run -t zdtm/transition/fork --fault 130 -f h || fail +./test/zdtm.py run -t zdtm/static/vdso01 --fault 127 || fail ./test/zdtm.py run -t zdtm/static/mntns_ghost --fault 2 --keep-going --report report || fail ./test/zdtm.py run -t zdtm/static/mntns_ghost --fault 4 --keep-going --report report || fail From 67b7c98ef908fac710c1319bba5acf8c05e02930 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 22 Feb 2017 15:15:41 -0800 Subject: [PATCH 0378/4375] criu Makefiles: rm old compel leftovers As compel is an external tool now, let's treat it as such -- remove the hardcoded paths to compel files, they are now provided via compel CLI. Details: 1. The compel std plugin dependency is dropped from the intermediate criu/Makefile. It was there in order to make sure plugin is built before pie, but the top level Makefile and Makefile.compel take care about it. 2. The compel std plugin logic is simplified in criu/pie/Makefile. 3. The compel linker script dependency is kept as-is for now (except the linker script file name no longer appears in the list of objects to link). 4. Linking of compel std plugin is moved to a second linking stage in order to simplify the Makefile. Side note: we can actually avoid running the linker twice! 5. The compel binary dependency is dropped from criu/pie/Makefile as this is already there in top-level Makefile (look for criu-deps). [v2: reworked after dsafonov@ comments; keep most compel deps] Signed-off-by: Kir Kolyshkin Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/Makefile | 2 +- criu/pie/Makefile | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/criu/Makefile b/criu/Makefile index 5c19d0af2..e5fdde92a 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -54,7 +54,7 @@ criu/pie/pie.lib.a: $(ARCH-LIB) .FORCE # # PIE code blobs themseves. -pie: criu/pie/pie.lib.a compel/plugins/std.built-in.o +pie: criu/pie/pie.lib.a $(Q) $(MAKE) $(build)=criu/pie all .PHONY: pie diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 45adbc10b..9b43af901 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -1,8 +1,5 @@ target += parasite restorer -parasite-obj-e += ./compel/plugins/std.built-in.o -restorer-obj-e += ./compel/plugins/std.built-in.o - parasite-obj-y += parasite.o restorer-obj-y += restorer.o restorer-obj-y += ./$(ARCH_DIR)/restorer.o @@ -50,13 +47,12 @@ LDS := $(SRC_DIR)/compel/arch/$(SRCARCH)/scripts/compel-pack.lds.S target-name = $(patsubst criu/pie/%-blob.h,%,$(1)) -$(obj)/restorer.built-in.o: $(compel_std) -$(obj)/parasite.built-in.o: $(compel_std) -$(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/pie.lib.a $(LDS) +$(obj)/%.build-in.bin.o: $(LDS) +$(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/pie.lib.a $(compel_std) $(call msg-gen, $@) $(Q) $(LD) $(shell $(COMPEL_BIN) ldflags) -o $@ $^ -$(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(SRC_DIR)/compel/compel-host-bin +$(obj)/%-blob.h: $(obj)/%.built-in.bin.o $(call msg-gen, $@) $(Q) $(COMPEL_BIN) hgen -f $< -o $@ From 0f453c18ab0c19ac8a63298e1c82957516fe5208 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 22 Feb 2017 15:15:42 -0800 Subject: [PATCH 0379/4375] lib Makefiles: integrate Our whole system of Makefiles are integrated from top to bottom, meaning: 1. The paths in sub-makefiles are relative to the top source dir. 2. Sub-makefiles are executed via make $(build)= For some reason, makefiles under lib/ are the exclusion. Let's fix it. Side effect: you can now build any individual target under lib/, for example, "make lib/c/libcriu.so" works. [v2: use the .FORCE, thanks to dsafonov@] Signed-off-by: Kir Kolyshkin Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index d3a830630..a9930e917 100644 --- a/Makefile +++ b/Makefile @@ -262,6 +262,7 @@ clean: subclean $(Q) $(MAKE) $(build)=lib $@ $(Q) $(MAKE) $(build)=compel $@ $(Q) $(MAKE) $(build)=compel/plugins $@ + $(Q) $(MAKE) $(build)=lib $@ .PHONY: clean # mrproper depends on clean in nmk From 85b04c8bfd89d9e077cbe1d3ada9d112149a0a0b Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 22 Feb 2017 15:15:45 -0800 Subject: [PATCH 0380/4375] Makefiles: nuke $(SRC_DIR) As all builds are done from top source dir, there is no need to have SRC_DIR. Reviewed-by: Dmitry Safonov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- Makefile | 12 ++++-------- Makefile.compel | 4 ++-- Makefile.config | 6 +++--- compel/Makefile | 2 +- compel/plugins/Makefile | 2 +- criu/Makefile | 22 +++++++++++----------- criu/Makefile.crtools | 2 +- criu/arch/aarch64/Makefile | 6 +++--- criu/arch/arm/Makefile | 5 ++--- criu/arch/ppc64/Makefile | 4 ++-- criu/arch/x86/Makefile | 4 ++-- criu/pie/Makefile | 7 +++---- criu/pie/Makefile.library | 5 ++--- lib/Makefile | 1 + lib/c/Makefile | 8 ++++---- lib/py/Makefile | 2 +- lib/py/images/Makefile | 6 +++--- 17 files changed, 46 insertions(+), 52 deletions(-) diff --git a/Makefile b/Makefile index a9930e917..3fe23b9aa 100644 --- a/Makefile +++ b/Makefile @@ -12,11 +12,6 @@ export CFLAGS HOSTCFLAGS ?= $(CFLAGS) export HOSTCFLAGS -# -# Where we live. -SRC_DIR := $(CURDIR) -export SRC_DIR - # # Architecture specific options. ifneq ($(filter-out x86 arm arm64 ppc64,$(ARCH)),) @@ -144,7 +139,7 @@ all: criu lib # Version headers. include Makefile.versions -VERSION_HEADER := $(SRC_DIR)/criu/include/version.h +VERSION_HEADER := criu/include/version.h GITID_FILE := .gitid GITID := $(shell if [ -d ".git" ]; then git describe --always; fi) @@ -193,7 +188,7 @@ criu-deps += include/common/asm # Configure variables. export CONFIG_HEADER := criu/include/config.h ifeq ($(filter clean mrproper,$(MAKECMDGOALS)),) -include $(SRC_DIR)/Makefile.config +include Makefile.config else # To clean all files, enable make/build options here export CONFIG_COMPAT := y @@ -215,7 +210,7 @@ include Makefile.compel # Next the socket CR library # SOCCR_A := soccr/libsoccr.a -SOCCR_CONFIG := $(SRC_DIR)/soccr/config.h +SOCCR_CONFIG := soccr/config.h $(SOCCR_CONFIG): $(CONFIG_HEADER) $(Q) test -f $@ || ln -s ../$(CONFIG_HEADER) $@ soccr/%: $(SOCCR_CONFIG) .FORCE @@ -273,6 +268,7 @@ mrproper: subclean $(Q) $(MAKE) $(build)=lib $@ $(Q) $(MAKE) $(build)=compel $@ $(Q) $(MAKE) $(build)=compel/plugins $@ + $(Q) $(MAKE) $(build)=lib $@ $(Q) $(RM) $(CONFIG_HEADER) $(Q) $(RM) $(SOCCR_CONFIG) $(Q) $(RM) $(VERSION_HEADER) diff --git a/Makefile.compel b/Makefile.compel index 3e7a1742f..7586ef3ac 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -1,9 +1,9 @@ -COMPEL_BIN := $(SRC_DIR)/compel/compel-host +COMPEL_BIN := compel/compel-host export COMPEL_BIN COMPEL_VERSION_HEADER := compel/include/version.h -$(COMPEL_VERSION_HEADER): $(SRC_DIR)/Makefile.versions +$(COMPEL_VERSION_HEADER): Makefile.versions $(call msg-gen, $(COMPEL_VERSION_HEADER)) $(Q) echo "/* Autogenerated, do not edit */" > $(COMPEL_VERSION_HEADER) $(Q) echo "#ifndef COMPEL_SO_VERSION_H__" >> $(COMPEL_VERSION_HEADER) diff --git a/Makefile.config b/Makefile.config index 0a04115b8..50516109a 100644 --- a/Makefile.config +++ b/Makefile.config @@ -1,6 +1,6 @@ include $(__nmk_dir)utils.mk include $(__nmk_dir)msg.mk -include $(SRC_DIR)/scripts/feature-tests.mak +include scripts/feature-tests.mak ifeq ($(call try-cc,$(FEATURE_TEST_LIBBSD_DEV),-lbsd),true) LIBS_FEATURES += -lbsd @@ -14,7 +14,7 @@ endif export LIBS += $(LIBS_FEATURES) -CONFIG_FILE = $(SRC_DIR)/.config +CONFIG_FILE = .config $(CONFIG_FILE): touch $(CONFIG_FILE) @@ -42,7 +42,7 @@ endif endef define config-header-rule -$(CONFIG_HEADER): $(SRC_DIR)/scripts/feature-tests.mak $(CONFIG_FILE) +$(CONFIG_HEADER): scripts/feature-tests.mak $(CONFIG_FILE) $$(call msg-gen, $$@) $(Q) @echo '#ifndef __CR_CONFIG_H__' > $$@ $(Q) @echo '#define __CR_CONFIG_H__' >> $$@ diff --git a/compel/Makefile b/compel/Makefile index 159a3e1cc..983b1a441 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -1,4 +1,4 @@ -include $(SRC_DIR)/Makefile.versions +include Makefile.versions COMPEL_SO_VERSION := $(COMPEL_SO_VERSION_MAJOR)$(if $(COMPEL_SO_VERSION_MINOR),.$(COMPEL_SO_VERSION_MINOR))$(if $(COMPEL_SO_VERSION_SUBLEVEL),.$(COMPEL_SO_VERSION_SUBLEVEL)) COMPEL_SO_VERSION_CODE := $(shell expr $(COMPEL_SO_VERSION_MAJOR) \* 65536 \+ $(COMPEL_SO_VERSION_MINOR) \* 256 \+ $(COMPEL_SO_VERSION_SUBLEVEL)) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index cea312508..b65055dad 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -15,7 +15,7 @@ ccflags-y += -I compel/include/uapi asflags-y += -I compel/include/uapi # General compel includes -ccflags-y += -iquote $(SRC_DIR)/compel/include +ccflags-y += -iquote compel/include ccflags-y += -fpie -fno-stack-protector # General compel/plugins includes diff --git a/criu/Makefile b/criu/Makefile index e5fdde92a..c67b9b2cf 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -17,13 +17,13 @@ endif # # General flags. ccflags-y += -fno-strict-aliasing -ccflags-y += -iquote $(SRC_DIR)/criu/include -ccflags-y += -iquote $(SRC_DIR)/include -ccflags-y += -iquote $(SRC_DIR)/images -ccflags-y += -iquote $(SRC_DIR)/criu/pie -ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR) -ccflags-y += -iquote $(SRC_DIR)/$(ARCH_DIR)/include -ccflags-y += -iquote $(SRC_DIR)/ +ccflags-y += -iquote criu/include +ccflags-y += -iquote include +ccflags-y += -iquote images +ccflags-y += -iquote criu/pie +ccflags-y += -iquote $(ARCH_DIR) +ccflags-y += -iquote $(ARCH_DIR)/include +ccflags-y += -iquote . ccflags-y += -I/usr/include/libnl3 ccflags-y += $(COMPEL_UAPI_INCLUDES) @@ -39,7 +39,7 @@ include $(__nmk_dir)msg.mk # # Needed libraries checks -include $(SRC_DIR)/criu/Makefile.packages +include criu/Makefile.packages # # Architecture dependent part. @@ -108,8 +108,8 @@ subproper: .PHONY: subproper mrproper: subproper -UAPI_HEADERS := $(SRC_DIR)/criu/include/criu-plugin.h -UAPI_HEADERS += $(SRC_DIR)/criu/include/criu-log.h +UAPI_HEADERS := criu/include/criu-plugin.h +UAPI_HEADERS += criu/include/criu-log.h install: $(obj)/criu $(E) " INSTALL " $(obj)/criu @@ -118,7 +118,7 @@ install: $(obj)/criu $(Q) mkdir -p $(DESTDIR)$(INCLUDEDIR)/criu/ $(Q) install -m 644 $(UAPI_HEADERS) $(DESTDIR)$(INCLUDEDIR)/criu/ $(Q) mkdir -p $(DESTDIR)$(LIBEXECDIR)/criu/scripts - $(Q) install -m 755 $(SRC_DIR)/scripts/systemd-autofs-restart.sh $(DESTDIR)$(LIBEXECDIR)/criu/scripts + $(Q) install -m 755 scripts/systemd-autofs-restart.sh $(DESTDIR)$(LIBEXECDIR)/criu/scripts .PHONY: install uninstall: diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index ea0e81521..c6b202108 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -88,7 +88,7 @@ obj-y += pie-util-vdso-elf32.o CFLAGS_pie-util-vdso-elf32.o += -DCONFIG_VDSO_32 endif -PROTOBUF_GEN := $(SRC_DIR)/scripts/protobuf-gen.sh +PROTOBUF_GEN := scripts/protobuf-gen.sh $(obj)/protobuf-desc.d: $(obj)/protobuf-desc-gen.h diff --git a/criu/arch/aarch64/Makefile b/criu/arch/aarch64/Makefile index 428e8081b..4203e3de7 100644 --- a/criu/arch/aarch64/Makefile +++ b/criu/arch/aarch64/Makefile @@ -1,8 +1,8 @@ builtin-name := crtools.built-in.o -ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -ccflags-y += -iquote $(obj)/include -iquote $(SRC_DIR)/criu/include -ccflags-y += -iquote $(SRC_DIR)/include +ccflags-y += -iquote $(obj) +ccflags-y += -iquote $(obj)/include -iquote criu/include +ccflags-y += -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) asflags-y += -D__ASSEMBLY__ diff --git a/criu/arch/arm/Makefile b/criu/arch/arm/Makefile index b64d1c9ff..07daec7d8 100644 --- a/criu/arch/arm/Makefile +++ b/criu/arch/arm/Makefile @@ -1,8 +1,7 @@ builtin-name := crtools.built-in.o -ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include -ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include - +ccflags-y += -iquote $(obj) -iquote $(obj)/include +ccflags-y += -iquote criu/include -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) asflags-y += -D__ASSEMBLY__ diff --git a/criu/arch/ppc64/Makefile b/criu/arch/ppc64/Makefile index 4859bf04a..177ea3156 100644 --- a/criu/arch/ppc64/Makefile +++ b/criu/arch/ppc64/Makefile @@ -1,7 +1,7 @@ builtin-name := crtools.built-in.o -ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include -ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include +ccflags-y += -iquote $(obj) -iquote $(obj)/include +ccflags-y += -iquote criu/include -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) obj-y += cpu.o diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index 6bd5ac9cc..0e1717c1d 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -1,7 +1,7 @@ builtin-name := crtools.built-in.o -ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include -ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include +ccflags-y += -iquote $(obj) -iquote . -iquote $(obj)/include +ccflags-y += -iquote criu/include -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) asflags-y += -Wstrict-prototypes diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 9b43af901..ffaaf4c41 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -19,10 +19,9 @@ endif # CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) CFLAGS := $(filter-out $(CFLAGS-ASAN),$(CFLAGS)) -CFLAGS += -iquote $(SRC_DIR)/criu/arch/$(ARCH)/include -CFLAGS += -iquote $(SRC_DIR)/criu/include -CFLAGS += -iquote $(SRC_DIR)/include -CFLAGS += -iquote $(SRC_DIR) +CFLAGS += -iquote criu/arch/$(ARCH)/include +CFLAGS += -iquote criu/include +CFLAGS += -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) ccflags-y += -DCR_NOGLIBC diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index e84058c67..7fe25965c 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -34,9 +34,8 @@ endif # applications, which is not the target of the # project. # -iquotes := -iquote $(SRC_DIR)/$(PIE_DIR)/piegen -iquotes += -iquote $(SRC_DIR)/$(ARCH_DIR)/include -iquotes += -iquote $(SRC_DIR) -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include +iquotes += -iquote $(ARCH_DIR)/include +iquotes += -iquote criu/include -iquote include CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) $(iquotes) CFLAGS := $(filter-out $(CFLAGS-ASAN),$(CFLAGS)) diff --git a/lib/Makefile b/lib/Makefile index 589e7251d..4bc865a45 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -40,6 +40,7 @@ clean-lib: .PHONY: clean-lib clean: clean-lib cleanup-y += lib/c/$(CRIU_SO) lib/c/criu.pc +mrproper: clean install: lib-c lib-py crit/crit lib/c/criu.pc.in $(E) " INSTALL " lib diff --git a/lib/c/Makefile b/lib/c/Makefile index 68cf2b9ce..79a8e69a6 100644 --- a/lib/c/Makefile +++ b/lib/c/Makefile @@ -1,8 +1,8 @@ obj-y += criu.o -obj-y += $(SRC_DIR)/images/rpc.pb-c.o +obj-y += ./images/rpc.pb-c.o -ccflags-y += -iquote $(SRC_DIR)/criu/$(ARCH_DIR)/include -ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(obj)/.. -ccflags-y += -iquote $(SRC_DIR)/images +ccflags-y += -iquote criu/$(ARCH_DIR)/include +ccflags-y += -iquote criu/include +ccflags-y += -iquote images ccflags-y += -fPIC -fno-stack-protector ldflags-y += -z noexecstack diff --git a/lib/py/Makefile b/lib/py/Makefile index 960529244..413b3da55 100644 --- a/lib/py/Makefile +++ b/lib/py/Makefile @@ -10,7 +10,7 @@ libpy-images: .PHONY: libpy-images rpc_pb2.py: - $(Q) protoc -I=$(SRC_DIR)/images/ --python_out=$(obj) $(SRC_DIR)/images/$(@:_pb2.py=.proto) + $(Q) protoc -I=images/ --python_out=$(obj) images/$(@:_pb2.py=.proto) cleanup-y += $(addprefix $(obj)/,rpc_pb2.py *.pyc) diff --git a/lib/py/images/Makefile b/lib/py/images/Makefile index a5990c4ca..a95f6120b 100644 --- a/lib/py/images/Makefile +++ b/lib/py/images/Makefile @@ -1,16 +1,16 @@ all-y += images magic.py pb.py -proto := $(filter-out $(SRC_DIR)/images/rpc.proto, $(sort $(wildcard $(SRC_DIR)/images/*.proto))) +proto := $(filter-out images/rpc.proto, $(sort $(wildcard images/*.proto))) proto-py-modules := $(foreach m,$(proto),$(subst -,_,$(notdir $(m:.proto=_pb2)))) # We don't need rpc_pb2.py here, as it is not related to the images. # Unfortunately, we can't drop ugly _pb2 suffixes here, because # some _pb2 files depend on others _pb2 files. images: - $(Q) protoc -I=$(SRC_DIR)/images -I=/usr/include/ --python_out=$(obj) $(proto) + $(Q) protoc -I=images/ -I=/usr/include/ --python_out=$(obj) $(proto) .PHONY: images -magic.py: $(SRC_DIR)/scripts/magic-gen.py $(SRC_DIR)/criu/include/magic.h +magic.py: scripts/magic-gen.py criu/include/magic.h $(call msg-gen, $@) $(Q) python $^ $(obj)/$@ From c30a793bece5e389721c758e0a23209b2466c87d Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 22 Feb 2017 15:15:46 -0800 Subject: [PATCH 0381/4375] Makefiles: get rid of extra includes Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/Makefile | 1 - criu/arch/aarch64/Makefile | 1 - criu/arch/arm/Makefile | 2 +- criu/arch/ppc64/Makefile | 2 +- criu/arch/x86/Makefile | 2 +- criu/pie/Makefile | 3 --- criu/pie/Makefile.library | 2 -- 7 files changed, 3 insertions(+), 10 deletions(-) diff --git a/criu/Makefile b/criu/Makefile index c67b9b2cf..48688d8c1 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -21,7 +21,6 @@ ccflags-y += -iquote criu/include ccflags-y += -iquote include ccflags-y += -iquote images ccflags-y += -iquote criu/pie -ccflags-y += -iquote $(ARCH_DIR) ccflags-y += -iquote $(ARCH_DIR)/include ccflags-y += -iquote . ccflags-y += -I/usr/include/libnl3 diff --git a/criu/arch/aarch64/Makefile b/criu/arch/aarch64/Makefile index 4203e3de7..0dc635096 100644 --- a/criu/arch/aarch64/Makefile +++ b/criu/arch/aarch64/Makefile @@ -1,6 +1,5 @@ builtin-name := crtools.built-in.o -ccflags-y += -iquote $(obj) ccflags-y += -iquote $(obj)/include -iquote criu/include ccflags-y += -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) diff --git a/criu/arch/arm/Makefile b/criu/arch/arm/Makefile index 07daec7d8..1b0bc56cb 100644 --- a/criu/arch/arm/Makefile +++ b/criu/arch/arm/Makefile @@ -1,6 +1,6 @@ builtin-name := crtools.built-in.o -ccflags-y += -iquote $(obj) -iquote $(obj)/include +ccflags-y += -iquote $(obj)/include ccflags-y += -iquote criu/include -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) diff --git a/criu/arch/ppc64/Makefile b/criu/arch/ppc64/Makefile index 177ea3156..8148dc943 100644 --- a/criu/arch/ppc64/Makefile +++ b/criu/arch/ppc64/Makefile @@ -1,6 +1,6 @@ builtin-name := crtools.built-in.o -ccflags-y += -iquote $(obj) -iquote $(obj)/include +ccflags-y += -iquote $(obj)/include ccflags-y += -iquote criu/include -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index 0e1717c1d..9ff59942a 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -1,6 +1,6 @@ builtin-name := crtools.built-in.o -ccflags-y += -iquote $(obj) -iquote . -iquote $(obj)/include +ccflags-y += -iquote $(obj)/include ccflags-y += -iquote criu/include -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index ffaaf4c41..d8b3fbff8 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -19,9 +19,6 @@ endif # CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) CFLAGS := $(filter-out $(CFLAGS-ASAN),$(CFLAGS)) -CFLAGS += -iquote criu/arch/$(ARCH)/include -CFLAGS += -iquote criu/include -CFLAGS += -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) ccflags-y += -DCR_NOGLIBC diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 7fe25965c..78da25de2 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -34,8 +34,6 @@ endif # applications, which is not the target of the # project. # -iquotes += -iquote $(ARCH_DIR)/include -iquotes += -iquote criu/include -iquote include CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) $(iquotes) CFLAGS := $(filter-out $(CFLAGS-ASAN),$(CFLAGS)) From f5ccecbdf2bba92600bf5443acbcf5927fc52c69 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 22 Feb 2017 15:15:47 -0800 Subject: [PATCH 0382/4375] Makefile: reorg top-level clean/mrproper Mostly this is done in order to not repeat the recursive clean lines twice. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- Makefile | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index 3fe23b9aa..a47ac405f 100644 --- a/Makefile +++ b/Makefile @@ -244,31 +244,25 @@ lib: criu $(Q) $(MAKE) $(build)=lib all .PHONY: lib -subclean: +clean mrproper: + $(Q) $(MAKE) $(build)=images $@ + $(Q) $(MAKE) $(build)=criu $@ + $(Q) $(MAKE) $(build)=soccr $@ + $(Q) $(MAKE) $(build)=lib $@ + $(Q) $(MAKE) $(build)=compel $@ + $(Q) $(MAKE) $(build)=compel/plugins $@ + $(Q) $(MAKE) $(build)=lib $@ +.PHONY: clean mrproper + +clean-top: $(Q) $(MAKE) -C Documentation clean $(Q) $(MAKE) $(build)=test/compel clean $(Q) $(RM) .gitid -.PHONY: subclean +.PHONY: clean-top -clean: subclean - $(Q) $(MAKE) $(build)=images $@ - $(Q) $(MAKE) $(build)=criu $@ - $(Q) $(MAKE) $(build)=soccr $@ - $(Q) $(MAKE) $(build)=lib $@ - $(Q) $(MAKE) $(build)=compel $@ - $(Q) $(MAKE) $(build)=compel/plugins $@ - $(Q) $(MAKE) $(build)=lib $@ -.PHONY: clean +clean: clean-top -# mrproper depends on clean in nmk -mrproper: subclean - $(Q) $(MAKE) $(build)=images $@ - $(Q) $(MAKE) $(build)=criu $@ - $(Q) $(MAKE) $(build)=soccr $@ - $(Q) $(MAKE) $(build)=lib $@ - $(Q) $(MAKE) $(build)=compel $@ - $(Q) $(MAKE) $(build)=compel/plugins $@ - $(Q) $(MAKE) $(build)=lib $@ +mrproper-top: clean-top $(Q) $(RM) $(CONFIG_HEADER) $(Q) $(RM) $(SOCCR_CONFIG) $(Q) $(RM) $(VERSION_HEADER) @@ -277,7 +271,9 @@ mrproper: subclean $(Q) $(RM) compel/include/asm $(Q) $(RM) cscope.* $(Q) $(RM) tags TAGS -.PHONY: mrproper +.PHONY: mrproper-top + +mrproper: mrproper-top # # Non-CRIU stuff. From 15a757f6be76511b2816fb461f3ff060561af6f9 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 22 Feb 2017 15:15:48 -0800 Subject: [PATCH 0383/4375] Makefiles: remove @true Apparently @true was used as a rule for any target which should have a non-empty rule doing nothing. For this, there's a ": ;" syntax, let's use this and eliminate an unnecessary fork/exec :) Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- Makefile | 3 +-- Makefile.install | 3 +-- criu/Makefile | 3 +-- scripts/nmk/Makefile | 3 +-- scripts/nmk/scripts/build.mk | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index a47ac405f..4a6bbd4a1 100644 --- a/Makefile +++ b/Makefile @@ -311,8 +311,7 @@ endif tar-name := $(shell echo $(head-name) | sed -e 's/^v//g') criu-$(tar-name).tar.bz2: git archive --format tar --prefix 'criu-$(tar-name)/' $(head-name) | bzip2 > $@ -dist tar: criu-$(tar-name).tar.bz2 - @true +dist tar: criu-$(tar-name).tar.bz2 ; .PHONY: dist tar tags: diff --git a/Makefile.install b/Makefile.install index 9e78367a3..f1e541500 100644 --- a/Makefile.install +++ b/Makefile.install @@ -41,8 +41,7 @@ install-compel: $(compel-install-targets) $(Q) $(MAKE) $(build)=compel/plugins install .PHONY: install-compel -install: install-man install-lib install-criu install-compel - @true +install: install-man install-lib install-criu install-compel ; .PHONY: install uninstall: diff --git a/criu/Makefile b/criu/Makefile index 48688d8c1..ada75af3a 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -57,8 +57,7 @@ pie: criu/pie/pie.lib.a $(Q) $(MAKE) $(build)=criu/pie all .PHONY: pie -criu/pie/%: pie - @true +criu/pie/%: pie ; # # CRIU executable diff --git a/scripts/nmk/Makefile b/scripts/nmk/Makefile index d9885c23a..f05e5c5c8 100644 --- a/scripts/nmk/Makefile +++ b/scripts/nmk/Makefile @@ -29,8 +29,7 @@ install: @cp scripts/tools.mk $(dir) @cp scripts/utils.mk $(dir) -all: - @true +all: ; clean: $(call msg-clean, "nmk") diff --git a/scripts/nmk/scripts/build.mk b/scripts/nmk/scripts/build.mk index 46d15fab9..907967cd7 100644 --- a/scripts/nmk/scripts/build.mk +++ b/scripts/nmk/scripts/build.mk @@ -281,8 +281,7 @@ endif # # Main phony rule. -all: $(all-y) - @true +all: $(all-y) ; .PHONY: all # From ab90777ca1bca9414fdbe72a8e99d2ed9213279a Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 22 Feb 2017 15:15:49 -0800 Subject: [PATCH 0384/4375] Makefiles: protect from % rules, don't rebuild GNU make tries to rebuild any makefiles it uses. While in general it's a good idea (and it is used e.g. in autoconf-based builds), in our case it is not necessary, as all the makefiles are static. More to say, as we have a few "match anything" rules for subdirectories, Makefiles in these subdirs are also matching these rules, which leads to excessive (re)building while a particular makefile is needed. Protect such Makefiles with explicit (or pattern) rules, so make knows it should do nothing to rebuild those. Signed-off-by: Kir Kolyshkin Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 16 ++++++++++++++-- Makefile.compel | 2 ++ criu/Makefile | 8 ++++++-- lib/Makefile | 3 ++- lib/py/Makefile | 1 + 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 4a6bbd4a1..d70a413c0 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,15 @@ -# -# Import the build engine first __nmk_dir=$(CURDIR)/scripts/nmk/scripts/ export __nmk_dir +# +# No need to try to remake our Makefiles +Makefile: ; +Makefile.%: ; +scripts/%.mak: ; +$(__nmk_dir)%.mk: ; + +# +# Import the build engine include $(__nmk_dir)include.mk include $(__nmk_dir)macro.mk @@ -213,6 +220,7 @@ SOCCR_A := soccr/libsoccr.a SOCCR_CONFIG := soccr/config.h $(SOCCR_CONFIG): $(CONFIG_HEADER) $(Q) test -f $@ || ln -s ../$(CONFIG_HEADER) $@ +soccr/Makefile: ; soccr/%: $(SOCCR_CONFIG) .FORCE $(Q) $(MAKE) $(build)=soccr $@ soccr/built-in.o: $(SOCCR_CONFIG) .FORCE @@ -228,6 +236,9 @@ criu-deps += $(SOCCR_A) # # But note that we're already included # the nmk so we can reuse it there. +criu/Makefile: ; +criu/Makefile.packages: ; +criu/Makefile.crtools: ; criu/%: $(criu-deps) .FORCE $(Q) $(MAKE) $(build)=criu $@ criu: $(criu-deps) @@ -238,6 +249,7 @@ criu: $(criu-deps) # Libraries next once criu it ready # (we might generate headers and such # when building criu itself). +lib/Makefile: ; lib/%: criu .FORCE $(Q) $(MAKE) $(build)=lib $@ lib: criu diff --git a/Makefile.compel b/Makefile.compel index 7586ef3ac..408f0a701 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -31,6 +31,7 @@ criu-deps += compel/$(LIBCOMPEL_A) # # Compel itself. +compel/Makefile: ; compel/%: $(compel-deps) $(compel-plugins) .FORCE $(Q) $(MAKE) $(build)=compel $@ @@ -38,6 +39,7 @@ criu-deps += compel/compel-host-bin # # Plugins +compel/plugins/Makefile: ; compel/plugins/%: $(compel-deps) .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ diff --git a/criu/Makefile b/criu/Makefile index ada75af3a..735890e0f 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -57,6 +57,8 @@ pie: criu/pie/pie.lib.a $(Q) $(MAKE) $(build)=criu/pie all .PHONY: pie +criu/pie/Makefile: ; +criu/pie/Makefile.library: ; criu/pie/%: pie ; # @@ -71,8 +73,10 @@ PROGRAM-BUILTINS += $(COMPEL_LIBS) $(obj)/built-in.o: pie $(Q) $(MAKE) $(call build-as,Makefile.crtools,criu) all -$(obj)/Makefile: - @true + +$(obj)/Makefile: ; +$(obj)/Makefile.crtools: ; +$(obj)/Makefile.packages: ; $(obj)/%: pie $(Q) $(MAKE) $(call build-as,Makefile.crtools,criu) $@ diff --git a/lib/Makefile b/lib/Makefile index 4bc865a45..a8647ce7a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -12,8 +12,8 @@ all-y += lib-c lib-py # # C language bindings. +lib/c/Makefile: ; lib/c/%: .FORCE - $(call msg-gen, $@) $(Q) $(MAKE) $(build)=lib/c $@ cflags-so += $(CFLAGS) -rdynamic -Wl,-soname,$(CRIU_SO).$(CRIU_SO_VERSION_MAJOR) @@ -27,6 +27,7 @@ lib-c: lib/c/$(CRIU_SO) # # Python bindings. +lib/py/Makefile: ; lib/py/%: .FORCE $(call msg-gen, $@) $(Q) $(MAKE) $(build)=lib/py $@ diff --git a/lib/py/Makefile b/lib/py/Makefile index 413b3da55..5eb77d40e 100644 --- a/lib/py/Makefile +++ b/lib/py/Makefile @@ -2,6 +2,7 @@ all-y += libpy-images rpc_pb2.py .PHONY: .FORCE +$(obj)/images/Makefile: ; $(obj)/images/%: .FORCE $(Q) $(MAKE) $(build)=$(obj)/images $@ From aa39838c32dba125fd2935b55e73bfbc3cbab9af Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 24 Feb 2017 11:06:22 -0800 Subject: [PATCH 0385/4375] compel: fix uninstall A slash after a directory was missing in a number of places, that resulted in "make uninstall" leaving a number of files behind. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/Makefile | 14 +++++++------- compel/plugins/Makefile | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index 983b1a441..d09aa7739 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -77,11 +77,11 @@ uninstall: $(E) " UNINSTALL" $(LIBCOMPEL_A) $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBDIR)/,$(LIBCOMPEL_A)) $(E) " UNINSTALL" compel uapi - $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/*.h) - $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/asm/*.h) - $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/asm/) - $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/common/*.h) - $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/common/asm/*.h) - $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/common/asm/) - $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/common/) + $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/*.h) + $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/asm/*.h) + $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/asm/) + $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/common/*.h) + $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/common/asm/*.h) + $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/common/asm/) + $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/common/) .PHONY: uninstall diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index b65055dad..0305c8961 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -93,7 +93,7 @@ install: compel/plugins/std.built-in.o uninstall: $(E) " UNINSTALL" compel plugins $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBEXECDIR)/compel/,std.built-in.o) - $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBEXECDIR)/compel/scripts,compel-pack.lds.S) + $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBEXECDIR)/compel/scripts/,compel-pack.lds.S) $(E) " UNINSTALL" compel and plugins uapi - $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR),compel/plugins) + $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/plugins) .PHONY: uninstall From 31eab3e36dfcdd3255aaf6254254a75766719784 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 4 Mar 2017 21:42:47 -0800 Subject: [PATCH 0386/4375] compel: nuke compel_main() It is not used anywhere, so unless someone has any plans, let's kill it. Reviewed-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Acked-by: Pavel Emelyanov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/plugins/std/std.c | 5 ----- compel/test/infect/parasite.c | 1 - criu/pie/parasite.c | 5 ----- criu/pie/restorer.c | 5 ----- 4 files changed, 16 deletions(-) diff --git a/compel/plugins/std/std.c b/compel/plugins/std/std.c index 705629f47..e326ef726 100644 --- a/compel/plugins/std/std.c +++ b/compel/plugins/std/std.c @@ -5,8 +5,6 @@ #include "asm/prologue.h" -extern int compel_main(void *arg_p, unsigned int arg_s); - static struct prologue_init_args *init_args; static int ctl_socket = -1; @@ -73,9 +71,6 @@ int __export_std_compel_start(struct prologue_init_args *args, } } - if (!ret) - ret = compel_main(args->arg_p, args->arg_s); - for (; i > 0; i--) { const plugin_init_t *d = init_array[i - 1]; diff --git a/compel/test/infect/parasite.c b/compel/test/infect/parasite.c index baecc0e3b..68bf1f7c3 100644 --- a/compel/test/infect/parasite.c +++ b/compel/test/infect/parasite.c @@ -9,7 +9,6 @@ /* * Stubs for std compel plugin. */ -int compel_main(void *arg_p, unsigned int arg_s) { return 0; } int parasite_trap_cmd(int cmd, void *args) { return 0; } void parasite_cleanup(void) { } diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index e84d63405..fe08e7252 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -24,11 +24,6 @@ #include "restorer.h" #include "infect-pie.h" -int compel_main(void *arg_p, unsigned int arg_s) -{ - return 0; -} - /* * PARASITE_CMD_DUMPPAGES is called many times and the parasite args contains * an array of VMAs at this time, so VMAs can be unprotected in any moment diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index c91c6b5dd..5250969ce 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -70,11 +70,6 @@ bool fault_injected(enum faults f) /* * These are stubs for std compel plugin. */ -int compel_main(void *arg_p, unsigned int arg_s) -{ - return 0; -} - int parasite_daemon_cmd(int cmd, void *args) { return 0; From ef849f2df851a76eb34421fadd4b8229ec025c75 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 4 Mar 2017 21:42:48 -0800 Subject: [PATCH 0387/4375] compel Makefiles: simplify headers [un]install * install 'cp' can copy recursively, create directories, and even dereference symlinks. Everything we have in uapi/ is to be installed. NOTE we can't use -r for compel includes, as there is some extra stuff in there we don't want to take with us (in particular, plugins/ and 'compel -> .' symlinks). * uninstall rm -rf everything under compel includedir While at it, fix some minor things here and there. Reviewed-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Acked-by: Pavel Emelyanov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/Makefile | 13 +++---------- compel/plugins/Makefile | 6 ++---- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index d09aa7739..fee12121b 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -59,10 +59,9 @@ install: compel/compel compel/$(LIBCOMPEL_SO) compel/$(LIBCOMPEL_A) $(E) " INSTALL " $(LIBCOMPEL_A) $(Q) install -m 0644 compel/$(LIBCOMPEL_A) $(DESTDIR)$(LIBDIR) $(E) " INSTALL " compel uapi - $(Q) mkdir -p $(DESTDIR)$(LIBEXECDIR)/compel/ $(Q) mkdir -p $(DESTDIR)$(INCLUDEDIR)/compel/asm - $(Q) cp -fr compel/include/uapi/compel/*.h $(DESTDIR)$(INCLUDEDIR)/compel - $(Q) cp -fr compel/include/uapi/compel/asm/*.h $(DESTDIR)$(INCLUDEDIR)/compel/asm + $(Q) cp -fr compel/include/uapi/*.h $(DESTDIR)$(INCLUDEDIR)/compel/ + $(Q) cp -fr compel/include/uapi/asm/*.h $(DESTDIR)$(INCLUDEDIR)/compel/asm/ $(Q) mkdir -p $(DESTDIR)$(INCLUDEDIR)/compel/common/asm $(Q) cp -fr include/common/compiler.h $(DESTDIR)$(INCLUDEDIR)/compel/common/ .PHONY: install @@ -77,11 +76,5 @@ uninstall: $(E) " UNINSTALL" $(LIBCOMPEL_A) $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBDIR)/,$(LIBCOMPEL_A)) $(E) " UNINSTALL" compel uapi - $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/*.h) - $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/asm/*.h) - $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/asm/) - $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/common/*.h) - $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/common/asm/*.h) - $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/common/asm/) - $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/common/) + $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/*) .PHONY: uninstall diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 0305c8961..b4b84960b 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -84,10 +84,8 @@ install: compel/plugins/std.built-in.o $(Q) mkdir -p $(DESTDIR)$(LIBEXECDIR)/compel/scripts $(Q) install -m 0644 compel/arch/$(ARCH)/scripts/compel-pack.lds.S $(DESTDIR)$(LIBEXECDIR)/compel/scripts $(E) " INSTALL " compel plugins uapi - $(Q) mkdir -p $(DESTDIR)$(INCLUDEDIR)/compel/plugins/std/asm - $(Q) cp -fr compel/include/uapi/compel/plugins/plugin-std.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins - $(Q) cp -fr compel/include/uapi/compel/plugins/std/*.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins/std - $(Q) cp -fr compel/arch/$(ARCH)/plugins/include/asm/syscall-types.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins/std/asm + $(Q) mkdir -p $(DESTDIR)$(INCLUDEDIR)/compel/plugins + $(Q) cp -frL compel/plugins/include/uapi/* $(DESTDIR)$(INCLUDEDIR)/compel/plugins/ .PHONY: install uninstall: From 9067c5c18f0b179dfe852dc9f5095271c2764d0f Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 4 Mar 2017 21:42:49 -0800 Subject: [PATCH 0388/4375] compel/plugin-std.h: include log.h This header should have everything we have in std/ Reviewed-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Acked-by: Pavel Emelyanov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/plugins/include/uapi/plugin-std.h | 1 + 1 file changed, 1 insertion(+) diff --git a/compel/plugins/include/uapi/plugin-std.h b/compel/plugins/include/uapi/plugin-std.h index 78619ecd7..d05fc9494 100644 --- a/compel/plugins/include/uapi/plugin-std.h +++ b/compel/plugins/include/uapi/plugin-std.h @@ -6,5 +6,6 @@ #include #include #include +#include #endif /* COMPEL_PLUGIN_STD_STD_H__ */ From 485a47babce4e91a5ed8497b354209009ada19b9 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 4 Mar 2017 21:42:50 -0800 Subject: [PATCH 0389/4375] compel/plugins: simplify #includes First, for building compel plugins, we already have "-I compel/include/uapi" in ccflags and asflags, so there is no need to add "-iquote include/uapi". Second, let's refer to compel plugin uapi includes in a uniform way, choosing the same way the external code does, i.e. #include . Third, in a few cases simplify #include statements by including compel/plugins/plugin-std.h instead of a number of plugins/std/*.h files. Reviewed-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Acked-by: Pavel Emelyanov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/plugins/Makefile | 2 -- compel/plugins/shmem/shmem.c | 6 +++--- compel/plugins/std/fds.c | 8 ++------ compel/plugins/std/infect.c | 7 +------ compel/plugins/std/std.c | 4 ++-- compel/plugins/std/string.c | 4 ++-- compel/test/infect/parasite.c | 6 +----- 7 files changed, 11 insertions(+), 26 deletions(-) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index b4b84960b..f26081f55 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -20,9 +20,7 @@ ccflags-y += -fpie -fno-stack-protector # General compel/plugins includes ccflags-y += -iquote $(obj)/include -ccflags-y += -iquote $(obj)/include/uapi asflags-y += -iquote $(obj)/include -asflags-y += -iquote $(obj)/include/uapi # Arch compel/plugins includes ccflags-y += -iquote $(PLUGIN_ARCH_DIR)/include diff --git a/compel/plugins/shmem/shmem.c b/compel/plugins/shmem/shmem.c index 9ded93fb3..1489df68e 100644 --- a/compel/plugins/shmem/shmem.c +++ b/compel/plugins/shmem/shmem.c @@ -1,8 +1,8 @@ #include -#include "uapi/plugins.h" -#include "uapi/plugin-shmem.h" -#include "uapi/std/syscall.h" +#include +#include +#include #include "shmem.h" #include "std-priv.h" diff --git a/compel/plugins/std/fds.c b/compel/plugins/std/fds.c index c947a30f0..eaa12713f 100644 --- a/compel/plugins/std/fds.c +++ b/compel/plugins/std/fds.c @@ -1,11 +1,7 @@ #include -#include "uapi/plugins.h" - -#include "uapi/std/syscall.h" -#include "uapi/std/string.h" -#include "uapi/std/log.h" -#include "uapi/std/fds.h" +#include +#include #include "std-priv.h" diff --git a/compel/plugins/std/infect.c b/compel/plugins/std/infect.c index a9553c8d0..5f195f19c 100644 --- a/compel/plugins/std/infect.c +++ b/compel/plugins/std/infect.c @@ -1,11 +1,6 @@ -#include -#include +#include #include "common/scm.h" -#include "uapi/compel/plugins/std/fds.h" -#include "uapi/compel/plugins/std/string.h" -#include "uapi/compel/plugins/std/log.h" - #include "common/compiler.h" #include "common/lock.h" diff --git a/compel/plugins/std/std.c b/compel/plugins/std/std.c index e326ef726..ec04665a3 100644 --- a/compel/plugins/std/std.c +++ b/compel/plugins/std/std.c @@ -1,7 +1,7 @@ #include -#include "uapi/plugins.h" -#include "uapi/plugin-std.h" +#include +#include #include "asm/prologue.h" diff --git a/compel/plugins/std/string.c b/compel/plugins/std/string.c index 43db1e34c..85bede803 100644 --- a/compel/plugins/std/string.c +++ b/compel/plugins/std/string.c @@ -2,8 +2,8 @@ #include #include -#include "uapi/std/syscall.h" -#include "uapi/std/string.h" +#include +#include #include "features.h" diff --git a/compel/test/infect/parasite.c b/compel/test/infect/parasite.c index 68bf1f7c3..17bf3d621 100644 --- a/compel/test/infect/parasite.c +++ b/compel/test/infect/parasite.c @@ -1,10 +1,6 @@ #include -#include -#include -#include - -#include +#include /* * Stubs for std compel plugin. From eebfeb925b577651f44e1cfc14a7b027baab6129 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sat, 4 Mar 2017 21:42:51 -0800 Subject: [PATCH 0390/4375] compel plugins uapi: rename includes The statement like #include looks a bit tautological. I think the single "plugins" word is enough: #include Reviewed-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Acked-by: Pavel Emelyanov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/plugins/include/uapi/{plugin-shmem.h => shmem.h} | 0 compel/plugins/include/uapi/{plugin-std.h => std.h} | 0 compel/plugins/shmem/shmem.c | 2 +- compel/plugins/std/fds.c | 2 +- compel/plugins/std/infect.c | 2 +- compel/plugins/std/std.c | 2 +- compel/test/infect/parasite.c | 2 +- 7 files changed, 5 insertions(+), 5 deletions(-) rename compel/plugins/include/uapi/{plugin-shmem.h => shmem.h} (100%) rename compel/plugins/include/uapi/{plugin-std.h => std.h} (100%) diff --git a/compel/plugins/include/uapi/plugin-shmem.h b/compel/plugins/include/uapi/shmem.h similarity index 100% rename from compel/plugins/include/uapi/plugin-shmem.h rename to compel/plugins/include/uapi/shmem.h diff --git a/compel/plugins/include/uapi/plugin-std.h b/compel/plugins/include/uapi/std.h similarity index 100% rename from compel/plugins/include/uapi/plugin-std.h rename to compel/plugins/include/uapi/std.h diff --git a/compel/plugins/shmem/shmem.c b/compel/plugins/shmem/shmem.c index 1489df68e..c2d56c270 100644 --- a/compel/plugins/shmem/shmem.c +++ b/compel/plugins/shmem/shmem.c @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include "shmem.h" #include "std-priv.h" diff --git a/compel/plugins/std/fds.c b/compel/plugins/std/fds.c index eaa12713f..499102788 100644 --- a/compel/plugins/std/fds.c +++ b/compel/plugins/std/fds.c @@ -1,7 +1,7 @@ #include #include -#include +#include #include "std-priv.h" diff --git a/compel/plugins/std/infect.c b/compel/plugins/std/infect.c index 5f195f19c..2d3aa3df8 100644 --- a/compel/plugins/std/infect.c +++ b/compel/plugins/std/infect.c @@ -1,4 +1,4 @@ -#include +#include #include "common/scm.h" #include "common/compiler.h" diff --git a/compel/plugins/std/std.c b/compel/plugins/std/std.c index ec04665a3..82f51eac4 100644 --- a/compel/plugins/std/std.c +++ b/compel/plugins/std/std.c @@ -1,7 +1,7 @@ #include #include -#include +#include #include "asm/prologue.h" diff --git a/compel/test/infect/parasite.c b/compel/test/infect/parasite.c index 17bf3d621..bdbe72229 100644 --- a/compel/test/infect/parasite.c +++ b/compel/test/infect/parasite.c @@ -1,6 +1,6 @@ #include -#include +#include /* * Stubs for std compel plugin. From cda7d6b2f9e44704c18989f56166086800604d9d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 7 Mar 2017 22:37:16 +0300 Subject: [PATCH 0391/4375] restorer: unblock only SIGCHLD previously blocked in criu The purpose is to unblock previously blocked SIGCHLD, not all the signals. IIRC, this block-unblock dancing is about a race where SIGCHLD may come during switching to restorer blob, where CRIU handler function is already unmapped - which will result in segmentation violation if SIGCHLD wasn't blocked. Fixes:3a61c38a5832 ("restore: block sigchld to remap task_entries") Cc: Andrei Vagin Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 5250969ce..1b91a7806 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1102,7 +1102,7 @@ long __export_restore_task(struct task_restore_args *args) act.rt_sa_restorer = cr_restore_rt; sys_sigaction(SIGCHLD, &act, NULL, sizeof(k_rtsigset_t)); - ksigfillset(&to_block); + ksigemptyset(&to_block); ksigaddset(&to_block, SIGCHLD); ret = sys_sigprocmask(SIG_UNBLOCK, &to_block, NULL, sizeof(k_rtsigset_t)); From 72557edb1506fcab56a6c1390070c3fbee4cdeb6 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 7 Mar 2017 22:37:17 +0300 Subject: [PATCH 0392/4375] compel/ksigset: fix ksigaddset() UB and flushing mask Found by Coverity error: > CID 172193 (#1 of 1): Bad bit shift operation (BAD_SHIFT) > 1. large_shift: In expression 1 << sig % 64, left shifting > by more than 31 bits has undefined behavior. The shift amount, > sig % 64, is as much as 63. That is: 1. yes, UB 2. while adding a signal to mask, this has flushed all other signals from mask. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/include/uapi/ksigset.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/include/uapi/ksigset.h b/compel/include/uapi/ksigset.h index ed6950a33..f6b124bf3 100644 --- a/compel/include/uapi/ksigset.h +++ b/compel/include/uapi/ksigset.h @@ -20,6 +20,6 @@ static inline void ksigemptyset(k_rtsigset_t *set) static inline void ksigaddset(k_rtsigset_t *set, int _sig) { int sig = _sig - 1; - set->sig[sig / _NSIG_BPW] = 1 << (sig % _NSIG_BPW); + set->sig[sig / _NSIG_BPW] |= 1UL << (sig % _NSIG_BPW); } #endif From b502d7fd6b14ab8c006d650398264c8196d44787 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 7 Mar 2017 15:55:29 +0300 Subject: [PATCH 0393/4375] compel: pass regs by pointer in get_task_regs() CID 73371 (#1 of 1): Big parameter passed by value (PASS_BY_VALUE) pass_by_value: Passing parameter regs of type user_regs_struct_t (size 224 bytes) by value. Suggesting to do this until compel is released and API is cut in stone. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/infect.c | 6 +++--- compel/arch/arm/src/lib/infect.c | 16 ++++++++-------- compel/arch/ppc64/src/lib/infect.c | 6 +++--- compel/arch/x86/src/lib/infect.c | 16 ++++++++-------- compel/include/infect-priv.h | 2 +- compel/src/lib/infect.c | 4 ++-- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/compel/arch/aarch64/src/lib/infect.c b/compel/arch/aarch64/src/lib/infect.c index 4f5534b75..41600e091 100644 --- a/compel/arch/aarch64/src/lib/infect.c +++ b/compel/arch/aarch64/src/lib/infect.c @@ -56,7 +56,7 @@ int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, return 0; } -int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) +int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, void *arg) { struct iovec iov; user_fpregs_struct_t fpsimd; @@ -64,7 +64,7 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *ar pr_info("Dumping GP/FPU registers for %d\n", pid); - iov.iov_base = ®s; + iov.iov_base = regs; iov.iov_len = sizeof(user_regs_struct_t); if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov))) { pr_perror("Failed to obtain CPU registers for %d", pid); @@ -78,7 +78,7 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *ar goto err; } - ret = save(arg, ®s, &fpsimd); + ret = save(arg, regs, &fpsimd); err: return ret; } diff --git a/compel/arch/arm/src/lib/infect.c b/compel/arch/arm/src/lib/infect.c index ad085ff98..a78108dff 100644 --- a/compel/arch/arm/src/lib/infect.c +++ b/compel/arch/arm/src/lib/infect.c @@ -65,7 +65,7 @@ int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, } #define PTRACE_GETVFPREGS 27 -int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) +int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, void *arg) { user_fpregs_struct_t vfp; int ret = -1; @@ -78,23 +78,23 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *ar } /* Did we come from a system call? */ - if ((int)regs.ARM_ORIG_r0 >= 0) { + if ((int)regs->ARM_ORIG_r0 >= 0) { /* Restart the system call */ - switch ((long)(int)regs.ARM_r0) { + switch ((long)(int)regs->ARM_r0) { case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: - regs.ARM_r0 = regs.ARM_ORIG_r0; - regs.ARM_pc -= 4; + regs->ARM_r0 = regs->ARM_ORIG_r0; + regs->ARM_pc -= 4; break; case -ERESTART_RESTARTBLOCK: - regs.ARM_r0 = __NR_restart_syscall; - regs.ARM_pc -= 4; + regs->ARM_r0 = __NR_restart_syscall; + regs->ARM_pc -= 4; break; } } - ret = save(arg, ®s, &vfp); + ret = save(arg, regs, &vfp); err: return ret; } diff --git a/compel/arch/ppc64/src/lib/infect.c b/compel/arch/ppc64/src/lib/infect.c index 11154d658..f3f1aacec 100644 --- a/compel/arch/ppc64/src/lib/infect.c +++ b/compel/arch/ppc64/src/lib/infect.c @@ -369,16 +369,16 @@ static int __get_task_regs(pid_t pid, user_regs_struct_t *regs, return 0; } -int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) +int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, void *arg) { user_fpregs_struct_t fpregs; int ret; - ret = __get_task_regs(pid, ®s, &fpregs); + ret = __get_task_regs(pid, regs, &fpregs); if (ret) return ret; - return save(arg, ®s, &fpregs); + return save(arg, regs, &fpregs); } int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index f1b216650..84ff21b15 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -225,7 +225,7 @@ int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \ (int32_t)((pregs)->compat.name)) -int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) +int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, void *arg) { user_fpregs_struct_t xsave = { }, *xs = NULL; @@ -233,21 +233,21 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *ar int ret = -1; pr_info("Dumping general registers for %d in %s mode\n", pid, - user_regs_native(®s) ? "native" : "compat"); + user_regs_native(regs) ? "native" : "compat"); /* Did we come from a system call? */ - if (get_signed_user_reg(®s, orig_ax) >= 0) { + if (get_signed_user_reg(regs, orig_ax) >= 0) { /* Restart the system call */ - switch (get_signed_user_reg(®s, ax)) { + switch (get_signed_user_reg(regs, ax)) { case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: - set_user_reg(®s, ax, get_user_reg(®s, orig_ax)); - set_user_reg(®s, ip, get_user_reg(®s, ip) - 2); + set_user_reg(regs, ax, get_user_reg(regs, orig_ax)); + set_user_reg(regs, ip, get_user_reg(regs, ip) - 2); break; case -ERESTART_RESTARTBLOCK: pr_warn("Will restore %d with interrupted system call\n", pid); - set_user_reg(®s, ax, -EINTR); + set_user_reg(regs, ax, -EINTR); break; } } @@ -279,7 +279,7 @@ int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *ar xs = &xsave; out: - ret = save(arg, ®s, xs); + ret = save(arg, regs, xs); err: return ret; } diff --git a/compel/include/infect-priv.h b/compel/include/infect-priv.h index cf0ce3a92..0f80895a7 100644 --- a/compel/include/infect-priv.h +++ b/compel/include/infect-priv.h @@ -58,7 +58,7 @@ extern void *remote_mmap(struct parasite_ctl *ctl, void *addr, size_t length, int prot, int flags, int fd, off_t offset); extern bool arch_can_dump_task(struct parasite_ctl *ctl); -extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg); +extern int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, void *arg); extern int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs); diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 78c9655ef..c02425036 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -664,7 +664,7 @@ static int parasite_start_daemon(struct parasite_ctl *ctl) * while in daemon it is not such. */ - if (get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) { + if (get_task_regs(pid, &ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) { pr_err("Can't obtain regs for thread %d\n", pid); return -1; } @@ -1556,7 +1556,7 @@ k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl) int compel_get_thread_regs(struct parasite_thread_ctl *tctl, save_regs_t save, void * arg) { - return get_task_regs(tctl->tid, tctl->th.regs, save, arg); + return get_task_regs(tctl->tid, &tctl->th.regs, save, arg); } struct infect_ctx *compel_infect_ctx(struct parasite_ctl *ctl) From 6794c8c2a9e94f0de19da306f586589c3c9809cf Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 6 Mar 2017 21:38:17 +0300 Subject: [PATCH 0394/4375] compel: Add fds plugin (v2) This is just export by reasonable name of the existing code, that sends and receives FDs via compel RPC socket. v2: Rebase on recent criu-dev Fix parallel build Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile.compel | 7 +++++-- compel/plugins/Makefile | 5 +++++ compel/plugins/fds/fds.c | 25 ++++++++++++++++++++++++ compel/plugins/include/uapi/plugin-fds.h | 7 +++++++ 4 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 compel/plugins/fds/fds.c create mode 100644 compel/plugins/include/uapi/plugin-fds.h diff --git a/Makefile.compel b/Makefile.compel index 408f0a701..ab479f79d 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -22,7 +22,7 @@ compel-deps += compel/include/asm compel-deps += $(COMPEL_VERSION_HEADER) compel-deps += $(CONFIG_HEADER) compel-deps += include/common/asm -compel-plugins += compel/plugins/std.built-in.o +compel-plugins += compel/plugins/std.built-in.o compel/plugins/fds.built-in.o LIBCOMPEL_SO := libcompel.so LIBCOMPEL_A := libcompel.a @@ -50,7 +50,10 @@ compel/plugins/%: $(compel-deps) .FORCE compel/plugins/std.built-in.o: $(compel-deps) .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ -compel/plugins/shmem.built-in.o: $(compel-deps) .FORCE +compel/plugins/shmem.built-in.o: $(compel-deps) compel/plugins/std.built-in.o .FORCE + $(Q) $(MAKE) $(build)=compel/plugins $@ + +compel/plugins/fds.built-in.o: $(compel-deps) compel/plugins/std.built-in.o .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ compel/compel: compel/built-in.o compel/$(LIBCOMPEL_A) | $(compel-deps) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index f26081f55..79ed21dce 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -48,6 +48,11 @@ std-obj-y += std/string.o std-obj-y += std/infect.o std-obj-y += ./$(PLUGIN_ARCH_DIR)/std/parasite-head.o +# +# FDS plugin +target += fds +fds-obj-y += fds/fds.o + ifeq ($(SRCARCH),x86) std-obj-y += ./$(PLUGIN_ARCH_DIR)/std/memcpy.o endif diff --git a/compel/plugins/fds/fds.c b/compel/plugins/fds/fds.c new file mode 100644 index 000000000..7ed94509d --- /dev/null +++ b/compel/plugins/fds/fds.c @@ -0,0 +1,25 @@ +#include + +#include "uapi/plugins.h" +#include "uapi/plugins/std.h" +#include + +#define pr_err(fmt, ...) + +#include "common/compiler.h" +#include "common/bug.h" + +#define __sys(foo) sys_##foo +#define __sys_err(ret) ret + +#include "common/scm.h" + +int fds_send_fd(int fd) +{ + return send_fd(parasite_get_rpc_sock(), NULL, 0, fd); +} + +int fds_recv_fd(void) +{ + return recv_fd(parasite_get_rpc_sock()); +} diff --git a/compel/plugins/include/uapi/plugin-fds.h b/compel/plugins/include/uapi/plugin-fds.h new file mode 100644 index 000000000..cececb21d --- /dev/null +++ b/compel/plugins/include/uapi/plugin-fds.h @@ -0,0 +1,7 @@ +#ifndef COMPEL_PLUGIN_STD_STD_H__ +#define COMPEL_PLUGIN_STD_STD_H__ + +extern int fds_send_fd(int fd); +extern int fds_recv_fd(void); + +#endif /* COMPEL_PLUGIN_STD_STD_H__ */ From a5752133c7327a9889092d45f485848471ed5bad Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 6 Mar 2017 21:38:29 +0300 Subject: [PATCH 0395/4375] compel: Add recv fd helper The same for libcompel.so user. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect-util.h | 1 + compel/src/lib/infect-util.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/compel/include/uapi/infect-util.h b/compel/include/uapi/infect-util.h index bd2010c3b..7307ba57a 100644 --- a/compel/include/uapi/infect-util.h +++ b/compel/include/uapi/infect-util.h @@ -2,4 +2,5 @@ #define __COMPEL_INFECT_UTIL_H__ struct parasite_ctl; extern int compel_util_send_fd(struct parasite_ctl *ctl, int fd); +extern int compel_util_recv_fd(struct parasite_ctl *ctl, int *pfd); #endif diff --git a/compel/src/lib/infect-util.c b/compel/src/lib/infect-util.c index b8f20bf01..5d6d0ddd8 100644 --- a/compel/src/lib/infect-util.c +++ b/compel/src/lib/infect-util.c @@ -19,3 +19,14 @@ int compel_util_send_fd(struct parasite_ctl *ctl, int fd) return 0; } +int compel_util_recv_fd(struct parasite_ctl *ctl, int *pfd) +{ + int sk; + + sk = compel_rpc_sock(ctl); + if ((*pfd = recv_fd(sk)) < 0) { + pr_perror("Can't send file descriptor"); + return -1; + } + return 0; +} From 36ebce8d9cf1b05cec691c642fc63fc8bfe44918 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 6 Mar 2017 21:38:45 +0300 Subject: [PATCH 0396/4375] compel: Test for FDs stealing An example, that steals stderr descriptor from victim task. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/test/fdspy/.gitignore | 4 + compel/test/fdspy/Makefile | 28 ++++++ compel/test/fdspy/parasite.c | 20 +++++ compel/test/fdspy/spy.c | 169 +++++++++++++++++++++++++++++++++++ compel/test/fdspy/victim.c | 12 +++ 5 files changed, 233 insertions(+) create mode 100644 compel/test/fdspy/.gitignore create mode 100644 compel/test/fdspy/Makefile create mode 100644 compel/test/fdspy/parasite.c create mode 100644 compel/test/fdspy/spy.c create mode 100644 compel/test/fdspy/victim.c diff --git a/compel/test/fdspy/.gitignore b/compel/test/fdspy/.gitignore new file mode 100644 index 000000000..0a554758d --- /dev/null +++ b/compel/test/fdspy/.gitignore @@ -0,0 +1,4 @@ +parasite.h +parasite.po +spy +victim diff --git a/compel/test/fdspy/Makefile b/compel/test/fdspy/Makefile new file mode 100644 index 000000000..4fed7912e --- /dev/null +++ b/compel/test/fdspy/Makefile @@ -0,0 +1,28 @@ +CC := gcc +CFLAGS ?= -O2 -g -Wall -Werror + +COMPEL := ../../../compel/compel-host + +all: victim spy + +clean: + rm -f victim + rm -f spy + rm -f parasite.h + rm -f parasite.po + rm -f parasite.o + +victim: victim.c + $(CC) $(CFLAGS) -o $@ $^ + +spy: spy.c parasite.h + $(CC) $(CFLAGS) $(shell $(COMPEL) includes) -o $@ $< $(shell $(COMPEL) --static libs) + +parasite.h: parasite.po + $(COMPEL) hgen -o $@ -f $< + +parasite.po: parasite.o + ld $(shell $(COMPEL) ldflags) -o $@ $^ $(shell $(COMPEL) plugins) ../../plugins/fds.built-in.o + +parasite.o: parasite.c + $(CC) $(CFLAGS) -c $(shell $(COMPEL) cflags) -o $@ $^ diff --git a/compel/test/fdspy/parasite.c b/compel/test/fdspy/parasite.c new file mode 100644 index 000000000..c14064b36 --- /dev/null +++ b/compel/test/fdspy/parasite.c @@ -0,0 +1,20 @@ +#include + +#include +#include + +/* + * Stubs for std compel plugin. + */ +int compel_main(void *arg_p, unsigned int arg_s) { return 0; } +int parasite_trap_cmd(int cmd, void *args) { return 0; } +void parasite_cleanup(void) { } + +#define PARASITE_CMD_GETFD PARASITE_USER_CMDS + +int parasite_daemon_cmd(int cmd, void *args) +{ + if (cmd == PARASITE_CMD_GETFD) + fds_send_fd(2); + return 0; +} diff --git a/compel/test/fdspy/spy.c b/compel/test/fdspy/spy.c new file mode 100644 index 000000000..258e3ab75 --- /dev/null +++ b/compel/test/fdspy/spy.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include +#include + +#include +#include "parasite.h" + +#define PARASITE_CMD_GETFD PARASITE_USER_CMDS + +static void print_vmsg(unsigned int lvl, const char *fmt, va_list parms) +{ + printf("\tLC%u: ", lvl); + vprintf(fmt, parms); +} + +static int do_infection(int pid, int *stolen_fd) +{ +#define err_and_ret(msg) do { fprintf(stderr, msg); return -1; } while (0) + + int state; + struct parasite_ctl *ctl; + struct infect_ctx *ictx; + + compel_log_init(print_vmsg, COMPEL_LOG_DEBUG); + + printf("Stopping task\n"); + state = compel_stop_task(pid); + if (state < 0) + err_and_ret("Can't stop task"); + + printf("Preparing parasite ctl\n"); + ctl = compel_prepare(pid); + if (!ctl) + err_and_ret("Can't prepare for infection"); + + printf("Configuring contexts\n"); + + /* + * First -- the infection context. Most of the stuff + * is already filled by compel_prepare(), just set the + * log descriptor for parasite side, library cannot + * live w/o it. + */ + ictx = compel_infect_ctx(ctl); + ictx->log_fd = STDERR_FILENO; + + parasite_setup_c_header(ctl); + + printf("Infecting\n"); + if (compel_infect(ctl, 1, sizeof(int))) + err_and_ret("Can't infect victim"); + + printf("Stealing fd\n"); + if (compel_rpc_call(PARASITE_CMD_GETFD, ctl)) + err_and_ret("Can't run cmd"); + + if (compel_util_recv_fd(ctl, stolen_fd)) + err_and_ret("Can't recv fd"); + + if (compel_rpc_sync(PARASITE_CMD_GETFD, ctl)) + err_and_ret("Con't finalize cmd"); + + printf("Stole %d fd\n", *stolen_fd); + + /* + * Done. Cure and resume the task. + */ + printf("Curing\n"); + if (compel_cure(ctl)) + err_and_ret("Can't cure victim"); + + if (compel_resume_task(pid, state, state)) + err_and_ret("Can't unseize task"); + + printf("Done\n"); + return 0; +} + +static int check_pipe_ends(int wfd, int rfd) +{ + struct stat r, w; + char aux[4] = "0000"; + + printf("Check pipe ends are at hands\n"); + if (fstat(wfd, &w) < 0) { + perror("Can't stat wfd"); + return 0; + } + + if (fstat(rfd, &r) < 0) { + perror("Can't stat rfd"); + return 0; + } + + if (w.st_dev != r.st_dev || w.st_ino != r.st_ino) { + perror("Pipe's not the same"); + return 0; + } + + printf("Check pipe ends are connected\n"); + write(wfd, "1", 2); + read(rfd, aux, sizeof(aux)); + if (aux[0] != '1' || aux[1] != '\0') { + fprintf(stderr, "Pipe connectivity lost\n"); + return 0; + } + + return 1; +} + +int main(int argc, char **argv) +{ + int p_in[2], p_out[2], p_err[2], pid, pass = 1, stolen_fd = -1; + + /* + * Prepare IO-s and fork the victim binary + */ + if (pipe(p_in) || pipe(p_out) || pipe(p_err)) { + perror("Can't make pipe"); + return -1; + } + + printf("Run the victim\n"); + pid = vfork(); + if (pid == 0) { + close(p_in[1]); dup2(p_in[0], 0); close(p_in[0]); + close(p_out[0]); dup2(p_out[1], 1); close(p_out[1]); + close(p_err[0]); dup2(p_err[1], 2); close(p_err[1]); + execl("./victim", "victim", NULL); + exit(1); + } + + close(p_in[0]); close(p_out[1]); close(p_err[1]); + + /* + * Now do the infection with parasite.c + */ + + printf("Infecting the victim\n"); + if (do_infection(pid, &stolen_fd)) + return 1; + + /* + * Stop the victim and check the infection went well + */ + printf("Closing victim stdin\n"); + close(p_in[1]); + printf("Waiting for victim to die\n"); + wait(NULL); + + printf("Checking the result\n"); + /* + * Stolen fd is the stderr of the task + * Check these are the ends of the same pipe + * and message passing works OK + */ + + pass = check_pipe_ends(stolen_fd, p_err[0]); + + if (pass) + printf("All OK\n"); + else + printf("Something went WRONG\n"); + + return 0; +} diff --git a/compel/test/fdspy/victim.c b/compel/test/fdspy/victim.c new file mode 100644 index 000000000..3dbd274e3 --- /dev/null +++ b/compel/test/fdspy/victim.c @@ -0,0 +1,12 @@ +#include + +int main(int argc, char **argv) +{ + int i, aux; + + do { + i = read(0, &aux, 1); + } while (i > 0); + + return 0; +} From ceaa66034c6d49e06f3c6bd503de39d22f2936f9 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 23 Mar 2017 08:09:29 +0300 Subject: [PATCH 0397/4375] mount: don't collect mounts when they are not required Currently we collect mounts to clean up a mount namespace, but it isn't required when we are going to call pivot_root. https://github.com/docker/docker/issues/31663 Signed-off-by: Andrei Vagin --- criu/mount.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 2973d27b8..736eaf456 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2901,7 +2901,6 @@ void cleanup_mnt_ns(void) int prepare_mnt_ns(void) { int ret = -1, rst = -1; - struct mount_info *old; struct ns_id ns = { .type = NS_CRIU, .ns_pid = PROC_SELF, .nd = &mnt_ns_desc }; struct ns_id *nsid; @@ -2910,27 +2909,30 @@ int prepare_mnt_ns(void) pr_info("Restoring mount namespace\n"); - old = collect_mntinfo(&ns, false); - if (old == NULL) - return -1; - if (!opts.root) { + struct mount_info *old; + if (chdir("/")) { pr_perror("chdir(\"/\") failed"); return -1; } + old = collect_mntinfo(&ns, false); + if (old == NULL) + return -1; /* * The new mount namespace is filled with the mountpoint * clones from the original one. We have to umount them * prior to recreating new ones. */ pr_info("Cleaning mount namespace\n"); - if (mnt_tree_for_each_reverse(ns.mnt.mntinfo_tree, do_umount_one)) + if (mnt_tree_for_each_reverse(ns.mnt.mntinfo_tree, do_umount_one)) { + free_mntinfo(old); return -1; - } + } - free_mntinfo(old); + free_mntinfo(old); + } ret = populate_mnt_ns(); if (ret) From d29b00d820481e71bfa201c13bb286ad9f82ca3a Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 23 Mar 2017 08:12:12 +0300 Subject: [PATCH 0398/4375] mount: don't dump content for external mounts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit External mounts are provided by an user and CRIU doesn't need to restore their content. https://github.com/xemul/criu/issues/299 Reported-by: Stéphane Graber Signed-off-by: Andrei Vagin --- criu/mount.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 736eaf456..e04893b66 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1263,13 +1263,14 @@ static int dump_one_mountpoint(struct mount_info *pm, struct cr_img *img) if (me.fstype == FSTYPE__AUTO) me.fsname = pm->fsname; + if (!pm->external) { + if (!pm->dumped && dump_one_fs(pm)) + return -1; - if (!pm->dumped && dump_one_fs(pm)) - return -1; - - if (!fsroot_mounted(pm) && - pm->fstype->check_bindmount && pm->fstype->check_bindmount(pm)) - return -1; + if (!fsroot_mounted(pm) && + pm->fstype->check_bindmount && pm->fstype->check_bindmount(pm)) + return -1; + } if (pm->mnt_id == CRTIME_MNT_ID) { pr_info("Skip dumping cr-time mountpoint: %s\n", pm->mountpoint); From 4f3927a638fac38e00d8f36db3356d42de03a066 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 9 Mar 2017 11:38:29 +0300 Subject: [PATCH 0399/4375] fsnotify: skip non-direcory mounts To restore fsnotify's watches on files we need to find paths for each of them using handle we have in /proc//fdinfo/. These handle is valid to open the file with open_by_handle_at if you have mount fd where the file lays. So we try open_by_handle_at for all possible mount fds we have. But we can not do so for 'file' bind-mounts, as the way we open mount fd opens file instead and can hang on fifos or fail on sockets. (see check_open_handle->open_handle->open_mount code path, imagine lookup_mnt_sdev() found 'file' bind-mount, open_mount() failed(hanged) in __open_mountpoint() and if irmap_lookup() also was not successful the whole dump fails too) So if we have file bindmount of fifo file, and we restore some inotify on other file on other mount with same s_dev, we hang forever on open. So just skip non-directory mounts from inotify search we will find path for them on other mount(e.g. non-bindmount) with same s_dev. v2: remove isdir hashing, improve commit message v3: make lookup_mnt_sdev handle only nondir mounts, add comment, move more expensive notdir_mountpoint check after s_dev v4: inverse notdir_mountpoint to be mnt_is_dir, now on error in mnt_is_dir mount is also skipped Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/fsnotify.c | 2 ++ criu/include/mount.h | 1 + criu/mount.c | 27 ++++++++++++++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 0dcb07c7c..65833caeb 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -132,6 +132,8 @@ static char *alloc_openable(unsigned int s_dev, unsigned long i_ino, FhEntry *f_ if (m->s_dev != s_dev) continue; + if (!mnt_is_dir(m)) + continue; mntfd = __open_mountpoint(m, -1); pr_debug("\t\tTrying via mntid %d root %s ns_mountpoint @%s (%d)\n", diff --git a/criu/include/mount.h b/criu/include/mount.h index a692b550b..e60dd348f 100644 --- a/criu/include/mount.h +++ b/criu/include/mount.h @@ -87,6 +87,7 @@ extern struct ns_id *lookup_nsid_by_mnt_id(int mnt_id); extern int open_mount(unsigned int s_dev); extern int __open_mountpoint(struct mount_info *pm, int mnt_fd); +extern int mnt_is_dir(struct mount_info *pm); extern int open_mountpoint(struct mount_info *pm); extern struct mount_info *collect_mntinfo(struct ns_id *ns, bool for_dump); diff --git a/criu/mount.c b/criu/mount.c index e04893b66..50c4d9378 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -228,7 +228,11 @@ struct mount_info *lookup_mnt_sdev(unsigned int s_dev) struct mount_info *m; for (m = mntinfo; m != NULL; m = m->next) - if (m->s_dev == s_dev) + /* + * We should not provide notdir bindmounts to open_mount as + * opening them can fail/hang for binds of unix sockets/fifos + */ + if (m->s_dev == s_dev && mnt_is_dir(m)) return m; return NULL; @@ -957,6 +961,27 @@ static struct mount_info *mnt_build_tree(struct mount_info *list, return tree; } +int mnt_is_dir(struct mount_info *pm) +{ + int mntns_root; + struct stat st; + + mntns_root = mntns_get_root_fd(pm->nsid); + if (mntns_root < 0) { + pr_perror("Can't get root fd of mntns for %d", pm->mnt_id); + return 0; + } + + if (fstatat(mntns_root, pm->ns_mountpoint, &st, 0)) { + pr_perror("Can't fstatat on %s", pm->ns_mountpoint); + return 0; + } + + if (S_ISDIR(st.st_mode)) + return 1; + return 0; +} + /* * mnt_fd is a file descriptor on the mountpoint, which is closed in an error case. * If mnt_fd is -1, the mountpoint will be opened by this function. From a155afda0b462529a19a901e2b49b99bc3fc6cf3 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 3 Mar 2017 18:39:15 +0300 Subject: [PATCH 0400/4375] sk-inet: Add support for shutdown'ed UDP/UDPlite sockets Supporting shutdown for dgram sockets (udp and udplite) is simple -- just fetch the state from diag module and record it in the image, then upon socket creation restore this state. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 20 ++++++++++++++------ images/sk-inet.proto | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 8e0050282..fb3939267 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -122,12 +122,6 @@ static int can_dump_inet_sk(const struct inet_sk_desc *sk) BUG_ON((sk->sd.family != AF_INET) && (sk->sd.family != AF_INET6)); if (sk->type == SOCK_DGRAM) { - if (sk->shutdown) { - pr_err("Can't dump shutdown inet socket %x\n", - sk->sd.ino); - return 0; - } - if (sk->wqlen != 0) { pr_err("Can't dump corked dgram socket %x\n", sk->sd.ino); @@ -414,6 +408,10 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa case IPPROTO_TCP: err = dump_one_tcp(lfd, sk); break; + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + sk_encode_shutdown(&ie, sk->shutdown); + /* Fallthrough! */ default: err = 0; break; @@ -704,6 +702,16 @@ done: if (restore_socket_opts(sk, ie->opts)) goto err; + if (ie->has_shutdown && + (ie->proto == IPPROTO_UDP || + ie->proto == IPPROTO_UDPLITE)) { + if (shutdown(sk, sk_decode_shutdown(ie->shutdown))) { + pr_perror("Can't shutdown socket into %d", + sk_decode_shutdown(ie->shutdown)); + goto err; + } + } + *new_fd = sk; return 1; err: diff --git a/images/sk-inet.proto b/images/sk-inet.proto index 01dda875a..177f83fca 100644 --- a/images/sk-inet.proto +++ b/images/sk-inet.proto @@ -39,4 +39,5 @@ message inet_sk_entry { /* for ipv6, we need to send the ifindex to bind(); we keep the ifname * here and convert it on restore */ optional string ifname = 17; + optional sk_shutdown shutdown = 19; } From e4d1ae344640478a2f48e8d116262c8ad03822df Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 3 Mar 2017 18:39:16 +0300 Subject: [PATCH 0401/4375] test: Add shutdown'ed UDP socket test Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/socket_udp_shutdown.c | 128 +++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 test/zdtm/static/socket_udp_shutdown.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 067c1e576..ccd2a6080 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -32,6 +32,7 @@ TST_NOFILE := \ socket_listen6 \ socket_udp \ socket6_udp \ + socket_udp_shutdown \ sk-freebind \ sk-freebind-false \ socket_udplite \ diff --git a/test/zdtm/static/socket_udp_shutdown.c b/test/zdtm/static/socket_udp_shutdown.c new file mode 100644 index 000000000..4e2834af9 --- /dev/null +++ b/test/zdtm/static/socket_udp_shutdown.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for sockaddr_in and inet_ntoa() */ +#include + +#include "zdtmtst.h" + +const char *test_doc = "static test for UDP shutdown'ed socket"; +const char *test_author = "Cyrill Gorcunov "; + +static int port = 8881; + +#define MSG1 "msg1" + +int main(int argc, char **argv) +{ + socklen_t len = sizeof(struct sockaddr_in); + struct sockaddr_in addr1, addr2, addr; + int ret, sk1, sk2; + char buf[512]; + + test_init(argc, argv); + + sk1 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + sk2 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sk1 < 0 || sk2 < 0) { + pr_err("Can't create socket"); + exit(1); + return 1; + } + + memset(&addr1, 0, sizeof(addr1)); + memset(&addr2, 0, sizeof(addr1)); + + addr1.sin_family = AF_INET; + addr1.sin_addr.s_addr = inet_addr("127.0.0.10"); + addr1.sin_port = htons(port); + + addr2.sin_family = AF_INET; + addr2.sin_addr.s_addr = inet_addr("127.0.0.10"); + addr2.sin_port = htons(port + 1); + + if (bind(sk1, (struct sockaddr *)&addr1, len) < 0 || + bind(sk2, (struct sockaddr *)&addr2, len) < 0) { + pr_err("Can't bind socket"); + return 1; + } + + if (connect(sk1, (struct sockaddr *)&addr2, len) || + connect(sk2, (struct sockaddr *)&addr1, len)) { + pr_err("Can't connect"); + return 1; + } + + if (shutdown(sk1, SHUT_WR) || + shutdown(sk2, SHUT_RD)) { + pr_err("Can't shutdown\n"); + return 1; + } + + ret = sendto(sk2, MSG1, sizeof(MSG1), 0, + (struct sockaddr *)&addr1, len); + if (ret < 0) { + pr_perror("Can't send"); + return 1; + } + + ret = recvfrom(sk1, buf, sizeof(buf), 0, + (struct sockaddr *)&addr, &len); + if (ret <= 0) { + pr_err("Can't receive data"); + return 1; + } + + if (len != sizeof(struct sockaddr_in) || memcmp(&addr2, &addr, len)) { + pr_err("Data received from wrong peer"); + return 1; + } + + if (ret != sizeof(MSG1) || memcmp(buf, MSG1, ret)) { + pr_err("Wrong message received"); + return 1; + } + + test_daemon(); + test_waitsig(); + + ret = sendto(sk2, MSG1, sizeof(MSG1), 0, + (struct sockaddr *)&addr1, len); + if (ret < 0) { + pr_perror("Can't send"); + return 1; + } + + ret = recvfrom(sk1, buf, sizeof(buf), 0, + (struct sockaddr *)&addr, &len); + if (ret <= 0) { + pr_err("Can't receive data"); + return 1; + } + + if (len != sizeof(struct sockaddr_in) || memcmp(&addr2, &addr, len)) { + pr_err("Data received from wrong peer"); + return 1; + } + + if (ret != sizeof(MSG1) || memcmp(buf, MSG1, ret)) { + pr_err("Wrong message received"); + return 1; + } + + ret = sendto(sk1, MSG1, sizeof(MSG1), 0, + (struct sockaddr *)&addr2, len); + if (ret >= 0) { + fail("Sent to write-shutdown'ed socket"); + return 1; + } + + pass(); + return 0; +} From 4d1cacec3c71c31afacad8e748bc571a66ee1688 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 10 Mar 2017 13:58:02 +0300 Subject: [PATCH 0402/4375] mem: Use long for memory size When checkpointing applications with really big memory slab (like in our vz7 test with 920G of memory) the int type get cutted, we should use long int instead, just like we do in other code pieces. Otherwise get (on vz7's criu, which s sharing the code) | pie: 756: Daemon waits for command | (01.193097) Wait for ack 12 on daemon socket | (01.193112) Fetched ack: 12 12 0 | (01.193164) 988065 fdinfo 0: pos: 0 flags: 100002/0 | (01.193201) fdinfo: type: 0xb flags: 0100002/0 pos: 0 fd: 0 | (01.193279) 988065 fdinfo 1: pos: 0 flags: 100002/0 | (01.193307) fdinfo: type: 0xb flags: 0100002/0 pos: 0 fd: 1 | (01.193341) 988065 fdinfo 2: pos: 0 flags: 100002/0 | (01.193365) fdinfo: type: 0xb flags: 0100002/0 pos: 0 fd: 2 | (01.193375) ---------------------------------------- | (01.193405) Error (criu/parasite-syscall.c:243): BUG at criu/parasite-syscall.c:243 | pie: 756: Error (criu/pie/parasite.c:676): Trimmed message received (1> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/mem.h | 2 +- criu/mem.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/include/mem.h b/criu/include/mem.h index bc10ab9a3..c6c5ca373 100644 --- a/criu/include/mem.h +++ b/criu/include/mem.h @@ -17,7 +17,7 @@ struct mem_dump_ctl { extern bool page_in_parent(bool dirty); extern int prepare_mm_pid(struct pstree_item *i); extern int do_task_reset_dirty_track(int pid); -extern unsigned int dump_pages_args_size(struct vm_area_list *vmas); +extern unsigned long dump_pages_args_size(struct vm_area_list *vmas); extern int parasite_dump_pages_seized(struct pstree_item *item, struct vm_area_list *vma_area_list, struct mem_dump_ctl *mdc, diff --git a/criu/mem.c b/criu/mem.c index 1c993b2fc..eeaedeef6 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -72,7 +72,7 @@ int do_task_reset_dirty_track(int pid) return ret; } -unsigned int dump_pages_args_size(struct vm_area_list *vmas) +unsigned long dump_pages_args_size(struct vm_area_list *vmas) { /* In the worst case I need one iovec for each page */ return sizeof(struct parasite_dump_pages_args) + From e56c642e3f816026a77928c7e09fda70a20d71c9 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 10 Mar 2017 16:35:23 +0300 Subject: [PATCH 0403/4375] vdso: remove per-arch declaration for vdso_redirect_calls It's the same on all archs (as it's called from generic code), no need to redeclare it. is included in all per-arch headers. Drop vdso_symtable forward declaration as includes header which defines the structure. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/include/asm/vdso.h | 6 ------ criu/arch/ppc64/include/asm/vdso.h | 6 ------ criu/arch/x86/include/asm/vdso.h | 6 ------ criu/include/parasite-vdso.h | 2 ++ 4 files changed, 2 insertions(+), 18 deletions(-) diff --git a/criu/arch/aarch64/include/asm/vdso.h b/criu/arch/aarch64/include/asm/vdso.h index 26dcf8b88..34d723f6c 100644 --- a/criu/arch/aarch64/include/asm/vdso.h +++ b/criu/arch/aarch64/include/asm/vdso.h @@ -25,12 +25,6 @@ static const char* __maybe_unused aarch_vdso_symbol4 = "__kernel_rt_sigreturn"; aarch_vdso_symbol3, \ aarch_vdso_symbol4 - -struct vdso_symtable; -extern int vdso_redirect_calls(unsigned long base_to, - unsigned long base_from, - struct vdso_symtable *to, - struct vdso_symtable *from); extern void write_intraprocedure_branch(unsigned long to, unsigned long from); #endif /* __CR_ASM_VDSO_H__ */ diff --git a/criu/arch/ppc64/include/asm/vdso.h b/criu/arch/ppc64/include/asm/vdso.h index ed94e4cf0..9546e2460 100644 --- a/criu/arch/ppc64/include/asm/vdso.h +++ b/criu/arch/ppc64/include/asm/vdso.h @@ -25,10 +25,4 @@ "__kernel_sync_dicache_p5", \ "__kernel_time" -struct vdso_symtable; -extern int vdso_redirect_calls(unsigned long base_to, - unsigned long base_from, - struct vdso_symtable *to, - struct vdso_symtable *from); - #endif /* __CR_ASM_VDSO_H__ */ diff --git a/criu/arch/x86/include/asm/vdso.h b/criu/arch/x86/include/asm/vdso.h index 37296f96a..d6c2f1b8c 100644 --- a/criu/arch/x86/include/asm/vdso.h +++ b/criu/arch/x86/include/asm/vdso.h @@ -24,10 +24,4 @@ "__kernel_rt_sigreturn" -struct vdso_symtable; -extern int vdso_redirect_calls(unsigned long base_to, - unsigned long base_from, - struct vdso_symtable *to, - struct vdso_symtable *from); - #endif /* __CR_ASM_VDSO_H__ */ diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index ae9584512..7d19efd12 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -85,6 +85,8 @@ extern int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso, bool force_trampolines); +extern int vdso_redirect_calls(unsigned long base_to, unsigned long base_from, + struct vdso_symtable *to, struct vdso_symtable *from); #else /* CONFIG_VDSO */ #define vdso_do_park(sym_rt, park_at, park_size) (0) From 684dbef1c8858aa6f45a73c6cfd0e5459432749d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 10 Mar 2017 16:35:24 +0300 Subject: [PATCH 0404/4375] x86/32: rectify compatible jump trampolines Reworked this code a little and it becomes more readable. Drop those macroses under CONFIG_X86_64 define and just use boolean `compat_vdso' to check whether insert 64 or 32-bit jmp. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/vdso-pie.c | 4 +- criu/arch/ppc64/vdso-pie.c | 7 ++-- criu/arch/x86/vdso-pie.c | 80 ++++++++++++++++++++---------------- criu/include/parasite-vdso.h | 3 +- criu/pie/parasite-vdso.c | 2 +- 5 files changed, 53 insertions(+), 43 deletions(-) diff --git a/criu/arch/aarch64/vdso-pie.c b/criu/arch/aarch64/vdso-pie.c index 55de8cb08..53d83cbe7 100644 --- a/criu/arch/aarch64/vdso-pie.c +++ b/criu/arch/aarch64/vdso-pie.c @@ -13,8 +13,8 @@ #define LOG_PREFIX "vdso: " int vdso_redirect_calls(unsigned long base_to, unsigned long base_from, - struct vdso_symtable *to, - struct vdso_symtable *from) + struct vdso_symtable *to, struct vdso_symtable *from, + bool __always_unused compat_vdso) { unsigned int i; diff --git a/criu/arch/ppc64/vdso-pie.c b/criu/arch/ppc64/vdso-pie.c index f13ea4a88..2dd3030dc 100644 --- a/criu/arch/ppc64/vdso-pie.c +++ b/criu/arch/ppc64/vdso-pie.c @@ -125,10 +125,9 @@ static inline void put_trampoline_call(unsigned long at, unsigned long to, invalidate_caches(at); } -int vdso_redirect_calls(unsigned long base_to, - unsigned long base_from, - struct vdso_symtable *to, - struct vdso_symtable *from) +int vdso_redirect_calls(unsigned long base_to, unsigned long base_from, + struct vdso_symtable *to, struct vdso_symtable *from, + bool __always_unused compat_vdso) { unsigned int i; unsigned long trampoline; diff --git a/criu/arch/x86/vdso-pie.c b/criu/arch/x86/vdso-pie.c index 24d44965b..988cf0869 100644 --- a/criu/arch/x86/vdso-pie.c +++ b/criu/arch/x86/vdso-pie.c @@ -13,53 +13,63 @@ #endif #define LOG_PREFIX "vdso: " -#ifdef CONFIG_X86_64 -typedef struct { - u16 movabs; - u64 imm64; - u16 jmp_rax; - u32 guards; -} __packed jmp_t; -#define IMMEDIATE(j) (j.imm64) +static void insert_trampoline32(uintptr_t from, uintptr_t to) +{ + struct { + u8 movl; + u32 imm32; + u16 jmp_eax; + u32 guards; + } __packed jmp = { + .movl = 0xb8, + .imm32 = (uint32_t)to, + .jmp_eax = 0xe0ff, + .guards = 0xcccccccc, + }; -jmp_t jmp = { - .movabs = 0xb848, - .jmp_rax = 0xe0ff, - .guards = 0xcccccccc, -}; + memcpy((void *)from, &jmp, sizeof(jmp)); +} -#else /* CONFIG_X86_64 */ -typedef struct { - u8 movl; - u32 imm32; - u16 jmp_eax; - u32 guards; -} __packed jmp_t; -#define IMMEDIATE(j) (j.imm32) +static void insert_trampoline64(uintptr_t from, uintptr_t to) +{ + struct { + u16 movabs; + u64 imm64; + u16 jmp_rax; + u32 guards; + } __packed jmp = { + .movabs = 0xb848, + .imm64 = to, + .jmp_rax = 0xe0ff, + .guards = 0xcccccccc, + }; -jmp_t jmp = { - .movl = 0xb8, - .jmp_eax = 0xe0ff, - .guards = 0xcccccccc, -}; -#endif /* CONFIG_X86_64 */ + memcpy((void *)from, &jmp, sizeof(jmp)); +} int vdso_redirect_calls(unsigned long base_to, unsigned long base_from, - struct vdso_symtable *to, - struct vdso_symtable *from) + struct vdso_symtable *sto, struct vdso_symtable *sfrom, + bool compat_vdso) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(to->symbols); i++) { - if (vdso_symbol_empty(&from->symbols[i])) + for (i = 0; i < ARRAY_SIZE(sto->symbols); i++) { + uintptr_t from, to; + + if (vdso_symbol_empty(&sfrom->symbols[i])) continue; pr_debug("jmp: %lx/%lx -> %lx/%lx (index %d)\n", - base_from, from->symbols[i].offset, - base_to, to->symbols[i].offset, i); + base_from, sfrom->symbols[i].offset, + base_to, sto->symbols[i].offset, i); - IMMEDIATE(jmp) = base_to + to->symbols[i].offset; - memcpy((void *)(base_from + from->symbols[i].offset), &jmp, sizeof(jmp)); + from = base_from + sfrom->symbols[i].offset; + to = base_to + sto->symbols[i].offset; + + if (!compat_vdso) + insert_trampoline64(from, to); + else + insert_trampoline32(from, to); } return 0; diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index 7d19efd12..3dad9404d 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -86,7 +86,8 @@ extern int vdso_proxify(struct vdso_symtable *sym_rt, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso, bool force_trampolines); extern int vdso_redirect_calls(unsigned long base_to, unsigned long base_from, - struct vdso_symtable *to, struct vdso_symtable *from); + struct vdso_symtable *to, struct vdso_symtable *from, + bool compat_vdso); #else /* CONFIG_VDSO */ #define vdso_do_park(sym_rt, park_at, park_size) (0) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index fb37f9f38..b0d531baf 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -242,7 +242,7 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, if (vdso_redirect_calls(vdso_rt_parked_at, vma_vdso->start, - sym_rt, &s)) { + sym_rt, &s, compat_vdso)) { pr_err("Failed to proxify dumpee contents\n"); return -1; } From e5de8986675a1870498742591be0b3cbcc2829b1 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 10 Mar 2017 16:35:25 +0300 Subject: [PATCH 0405/4375] x86/32: don't unmap vdso_rt after redirecting calls there We need to leave this part of restorer in restored task in case of inserted redirected calls. Jump trampolines from old vdso lead here - it would be painful to land nowhere. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 1b91a7806..51bf8c880 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -935,6 +935,7 @@ asm ( " .code32\n" " mov bootstrap_start, %ebx\n" " mov bootstrap_len, %ecx\n" + " sub vdso_rt_size, %ecx\n" " movl $"__stringify(__NR32_munmap)", %eax\n" " int $0x80\n" " .code64\n" From 6e4d05853d75d4e8a5cb41381eeb266ba62249e6 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 20 Feb 2017 11:33:42 +0300 Subject: [PATCH 0406/4375] compel: infect -- Don't forget to fetch sas early When infecting victim we construct sigframe to be able to self-rectore it in case if something goes wrong. But in case is a targer been using alternative stack for signal handling it will be missed in sigframe since we don't fetch it. Thus add fetching sas on infection stage and put it into signal frame early. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/infect.c | 11 +++++++++++ compel/arch/arm/src/lib/infect.c | 11 +++++++++++ compel/arch/ppc64/src/lib/infect.c | 11 +++++++++++ compel/arch/x86/src/lib/infect.c | 15 +++++++++++++++ compel/include/infect-priv.h | 1 + compel/src/lib/infect.c | 7 +++++++ 6 files changed, 56 insertions(+) diff --git a/compel/arch/aarch64/src/lib/infect.c b/compel/arch/aarch64/src/lib/infect.c index 41600e091..166ec2363 100644 --- a/compel/arch/aarch64/src/lib/infect.c +++ b/compel/arch/aarch64/src/lib/infect.c @@ -140,6 +140,17 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) return true; } +int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s) +{ + long ret; + int err; + + err = compel_syscall(ctl, __NR_sigaltstack, + &ret, 0, (unsigned long)&s->uc.uc_stack, + 0, 0, 0, 0); + return err ? err : ret; +} + /* * Range for task size calculated from the following Linux kernel files: * arch/arm64/include/asm/memory.h diff --git a/compel/arch/arm/src/lib/infect.c b/compel/arch/arm/src/lib/infect.c index a78108dff..27d258bc3 100644 --- a/compel/arch/arm/src/lib/infect.c +++ b/compel/arch/arm/src/lib/infect.c @@ -160,6 +160,17 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) return true; } +int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s) +{ + long ret; + int err; + + err = compel_syscall(ctl, __NR_sigaltstack, + &ret, 0, (unsigned long)&s->sig.uc.uc_stack, + 0, 0, 0, 0); + return err ? err : ret; +} + /* * Range for task size calculated from the following Linux kernel files: * arch/arm/include/asm/memory.h diff --git a/compel/arch/ppc64/src/lib/infect.c b/compel/arch/ppc64/src/lib/infect.c index f3f1aacec..32175174b 100644 --- a/compel/arch/ppc64/src/lib/infect.c +++ b/compel/arch/ppc64/src/lib/infect.c @@ -442,6 +442,17 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) return true; } +int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s) +{ + long ret; + int err; + + err = compel_syscall(ctl, __NR_sigaltstack, + &ret, 0, (unsigned long)&s->uc.uc_stack, + 0, 0, 0, 0); + return err ? err : ret; +} + /* * Copied for the Linux kernel arch/powerpc/include/asm/processor.h * diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index 84ff21b15..23a96df86 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -419,6 +419,21 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) return true; } +int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s) +{ + int native = compel_mode_native(ctl); + void *where = native ? + (void *)&s->native.uc.uc_stack : + (void *)&s->compat.uc.uc_stack; + long ret; + int err; + + err = compel_syscall(ctl, __NR(sigaltstack, !native), + &ret, 0, (unsigned long)where, + 0, 0, 0, 0); + return err ? err : ret; +} + /* Copied from the gdb header gdb/nat/x86-dregs.h */ /* Debug registers' indices. */ diff --git a/compel/include/infect-priv.h b/compel/include/infect-priv.h index 0f80895a7..00671e71f 100644 --- a/compel/include/infect-priv.h +++ b/compel/include/infect-priv.h @@ -59,6 +59,7 @@ extern void *remote_mmap(struct parasite_ctl *ctl, int flags, int fd, off_t offset); extern bool arch_can_dump_task(struct parasite_ctl *ctl); extern int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, void *arg); +extern int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s); extern int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs); diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index c02425036..c34452fd6 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -894,6 +894,13 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l ctl->r_thread_stack = ctl->remote_map + p; } + ret = arch_fetch_sas(ctl, ctl->rsigframe); + if (ret) { + pr_err("Can't fetch sigaltstack for task %d (ret %d)", + ctl->rpid, ret); + goto err; + } + if (parasite_start_daemon(ctl)) goto err; From 3edd0576f4cd1653a505c3ec13066830760a66ae Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 16 Mar 2017 17:38:17 +0100 Subject: [PATCH 0407/4375] zdtm: fix decode_flav() decode_flav() was doing 'if i in flavors:' where 'i' was an integer but the keys from the flavors dict are strings 'h', 'ns' and 'uns'. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/zdtm.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 5468d418f..46100c8b6 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -291,10 +291,10 @@ def encode_flav(f): def decode_flav(i): - i = i - 128 - if i in flavors: + try: return flavors.keys()[i - 128] - return "unknown" + except: + return "unknown" def tail(path): From 905c4084cf434d639dc5e91b0bce43d72df1390b Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 16 Mar 2017 17:38:18 +0100 Subject: [PATCH 0408/4375] zdtm: print test case summary also if all test cases pass If using the '--keep-going' option, zdtm prints out an overview how many tests were run, failed and skipped. This would also be useful to know if it did not fail. This patch changes the output like this: ################## ALL TEST(S) PASSED (TOTAL 297/SKIPPED 36) ################### or in the case of a failure it is unchanged: ################### 2 TEST(S) FAILED (TOTAL 297/SKIPPED 34) #################### * zdtm/static/sched_policy00(ns) * zdtm/static/cgroup02(h) ##################################### FAIL ##################################### Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/zdtm.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 46100c8b6..2026bf605 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1481,12 +1481,18 @@ class launcher: self.__fail = True if self.__file_report: self.__file_report.close() - if self.__fail: - if opts['keep_going']: + + if opts['keep_going']: + if self.__fail: print_sep("%d TEST(S) FAILED (TOTAL %d/SKIPPED %d)" % (len(self.__failed), self.__total, self.__nr_skip), "#") for failed in self.__failed: print " * %s(%s)" % (failed[0], failed[1]) + else: + print_sep("ALL TEST(S) PASSED (TOTAL %d/SKIPPED %d)" + % (self.__total, self.__nr_skip), "#") + + if self.__fail: print_sep("FAIL", "#") sys.exit(1) From 81a424aee433ab82d77f16a053f747b0ebedd429 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 15 Mar 2017 16:17:18 -0700 Subject: [PATCH 0409/4375] criu/arch/arm/bitops.S: fix clang compile clang-3.8 complains: > criu/arch/arm/bitops.S:5:2: error: invalid instruction > strneb r1, [ip] @ assert word-aligned > ^ Apparently (see [1]) this is some old asm syntax, which, I guess, was deliberately dropped from clang. [1] https://sourceware.org/ml/libc-ports/2013-03/msg00095.html Cc: Kirill Tkhai Signed-off-by: Kir Kolyshkin Reviewed-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/arch/arm/bitops.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/criu/arch/arm/bitops.S b/criu/arch/arm/bitops.S index db8360f51..51939118b 100644 --- a/criu/arch/arm/bitops.S +++ b/criu/arch/arm/bitops.S @@ -1,8 +1,10 @@ #include "common/asm/linkage.h" +.syntax unified + ENTRY(test_and_set_bit) ands ip, r1, #3 - strneb r1, [ip] @ assert word-aligned + strbne r1, [ip] @ assert word-aligned mov r2, #1 and r3, r0, #31 @ Get bit offset mov r0, r0, lsr #5 From a6ed6964a2a1d467c1201c54e52e357f3012d95c Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 15 Mar 2017 16:17:19 -0700 Subject: [PATCH 0410/4375] compel ppc64 infect.c: fix clang compilation This is generated by clang-3.8: > compel/arch/ppc64/src/lib/infect.c:31:20: error: unused function > '__check_code_syscall' [-Werror,-Wunused-function] > static inline void __check_code_syscall(void) > ^ The fix is the same as in commit 3ea2fd7. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/arch/ppc64/src/lib/infect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/arch/ppc64/src/lib/infect.c b/compel/arch/ppc64/src/lib/infect.c index 32175174b..81125885d 100644 --- a/compel/arch/ppc64/src/lib/infect.c +++ b/compel/arch/ppc64/src/lib/infect.c @@ -28,7 +28,7 @@ const uint32_t code_syscall[] = { 0x0fe00000 /* twi 31,0,0 */ }; -static inline void __check_code_syscall(void) +static inline __always_unused void __check_code_syscall(void) { BUILD_BUG_ON(sizeof(code_syscall) != BUILTIN_SYSCALL_SIZE); BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); From 6866fd2e248880a5b493a90879f7f30ab767e89d Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 15 Mar 2017 16:17:20 -0700 Subject: [PATCH 0411/4375] travis: fix clang builds As pointed out by Andrey, arch clang tests are using gcc regardless of CLANG=1 set in travis environment. Frankly, I do not understand how it worked before (while being pretty sure it worked!), but here is a way to fix it. Reported-by: Andrey Vagin Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- scripts/travis/Makefile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index 37721aa8f..0dadd65f7 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -6,9 +6,15 @@ after_success: ./travis-after_success .PHONY: after_success +target-suffix = +ifdef CLANG + target-suffix = -clang +endif + alpine: - $(MAKE) -C ../build alpine + $(MAKE) -C ../build $@$(target-suffix) docker run --rm -it --privileged -v /lib/modules:/lib/modules criu-alpine ./test/zdtm.py run -t zdtm/static/env00 + %: - $(MAKE) -C ../build $@ + $(MAKE) -C ../build $@$(target-suffix) From c903ddfcf1c7802d55caedd0a5991d9b1da01868 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 15 Mar 2017 16:17:21 -0700 Subject: [PATCH 0412/4375] scripts/build/Makefile: fix Unify alpine and non-alpine builds. The only difference is foreign arch builds need some preparation -- separate that to a dependency. Unfortunately we can't use wildcard targets ("%: ") as non-wildcard ones are prevaling. Therefore, a somewhat ugly hack to generate $arch: Dockerfile.$arch dependency is added. While at it: - rename DB_ARGS to DB_CC - mark clean as phony - make "all" really run all the builds we can Nice side effect: autocompletion ("make -C scripts/build ") now works! Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- scripts/build/Makefile | 43 +++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/scripts/build/Makefile b/scripts/build/Makefile index dc00bfbef..fc8317b41 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -1,5 +1,16 @@ -ARCHES ?= armv7hf aarch64 ppc64le # x86_64 -all: $(ARCHES) +QEMU_ARCHES := armv7hf aarch64 ppc64le # require qemu +ARCHES := $(QEMU_ARCHES) x86_64 +TARGETS := $(ARCHES) alpine +TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) + +all: $(TARGETS) $(TARGETS_CLANG) +.PHONY: all + +# A build for each architecture requires appropriate Dockerfile +define ARCH_DEP +$(1): Dockerfile.$(1) +endef +$(foreach arch,$(ARCHES),$(eval $(call ARCH_DEP,$(arch)))) Dockerfile.%: Dockerfile.%.hdr Dockerfile.tmpl cat $^ > $@ @@ -11,21 +22,22 @@ binfmt_misc: ./binfmt_misc .PHONY: binfmt_misc -alpine: - docker build -t criu-$@ -f Dockerfile.alpine $(DB_ARGS) ../.. +$(QEMU_ARCHES): qemu-user-static binfmt_misc -%: Dockerfile.% qemu-user-static binfmt_misc - docker build -t criu-$@ -f $< $(DB_ARGS) ../.. +$(TARGETS): + docker build -t criu-$@ -f Dockerfile.$@ $(DB_CC) ../.. +.PHONY: $(TARGETS) -%-clang: DB_ARGS=--build-arg CC=clang-3.8 -alpine-clang: DB_ARGS=--build-arg CC=clang -alpine-clang: alpine -armv7hf-clang: armv7hf -aarch64-clang: DB_ARGS=--build-arg CC=clang-3.6 -aarch64-clang: aarch64 -ppc64le-clang: ppc64le -x86_64-clang: x86_64 -.PHONY: alpine-clang armv7hf-clang aarch64-clang ppc64le-clang x86_64-clang +# Clang builds add some Docker build env +define CLANG_DEP +$(1)-clang: $(1) +endef +$(foreach t,$(TARGETS),$(eval $(call CLANG_DEP,$(t)))) + +%-clang: DB_CC=--build-arg CC=clang-3.8 +alpine-clang: DB_CC=--build-arg CC=clang +aarch64-clang: DB_CC=--build-arg CC=clang-3.6 +.PHONY: $(TARGETS_CLANG) clean: rm -rf qemu-user-static @@ -34,3 +46,4 @@ clean: test -f $$FILE && echo -1 > $$FILE; \ rm -f Dockerfile.$$ARCH; \ done +.PHONY: clean From 29f9e6e2f1669dc2a48b20239765342ebfa02854 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 15 Mar 2017 16:17:22 -0700 Subject: [PATCH 0413/4375] travis: enable ccache for local builds For now, it's done for local builds only (i.e. no per-arch Docker builds yet). The reason is, it's easier to play with ccache when the compiles are (relatively) fast. Performance: there is 2x to 3x improvement in build speeds for ideal cases (same code, hot cache), but the absolute savings are negligible (example: 7 seconds instead of 23). Note that ccache is not compatible with gcov, so we only enable it for non-gcov build (which happens to be the one with clang). Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- .travis.yml | 4 +++- scripts/travis/travis-tests | 27 +++++++++++++++++++++------ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 70d666d8f..a5dfb9f18 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: c sudo: required dist: trusty +cache: ccache services: - docker env: @@ -16,6 +17,7 @@ env: - TR_ARCH=ppc64le CLANG=1 - TR_ARCH=alpine CLANG=1 script: - - sudo make -C scripts/travis $TR_ARCH + - sudo make CCACHE=1 -C scripts/travis $TR_ARCH after_success: + - ccache -s - make -C scripts/travis after_success diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 75d15f5d6..ec730019b 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -13,12 +13,25 @@ travis_prep () { service apport stop + CC=gcc + # clang support + if [ "$CLANG" = "1" ]; then + TRAVIS_PKGS="$TRAVIS_PKGS clang" + CC=clang + fi + + # ccache support, only enable for non-GCOV case + if [ "$CCACHE" = "1" -a -z "$GCOV" ]; then + # ccache is installed by default, need to set it up + export CCACHE_DIR=$HOME/.ccache + [ "$CC" = "clang" ] && export CCACHE_CPP2=yes + # uncomment the following to get detailed ccache logs + #export CCACHE_LOGFILE=$HOME/ccache.log + CC="ccache $CC" + fi + apt-get update -qq apt-get install -qq $TRAVIS_PKGS - if [ "$CLANG" = "1" ]; then - apt-get install -qq clang - MAKE_VARS=CC=clang - fi chmod a+x $HOME } @@ -28,8 +41,10 @@ ulimit -c unlimited echo "|`pwd`/test/abrt.sh %P %p %s %e" > /proc/sys/kernel/core_pattern export GCOV -make ${MAKE_VARS} -make ${MAKE_VARS} -C test/zdtm +time make CC="$CC" -j4 +time make CC="$CC" -j4 -C test/zdtm + +[ -f "$CCACHE_LOGFILE" ] && cat $CCACHE_LOGFILE ./criu/criu check ./criu/criu check --all || echo $? From 5204a193e7ce23dd13726368419f68364db1a18f Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 15 Mar 2017 16:17:23 -0700 Subject: [PATCH 0414/4375] test/zdtm: use separate compile/link For compatibility with ccache (so it can cache the compilation results), let's compile and link separately. For this, we have to - disable the implicit make rules - write the explicit ones While at it, do use the "silent make" stuff that is already here FIXME: figure out if it helps to speed up ccache build Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 15 +++++++++++---- test/zdtm/transition/Makefile | 15 +++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index ccd2a6080..785d303f4 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -1,4 +1,5 @@ include ../Makefile.inc +.SUFFIXES: # No implicit rules LIBDIR = ../lib LIB = $(LIBDIR)/libzdtmtst.a @@ -313,9 +314,15 @@ OUT = $(TST:%=%.out) STATE = $(TST_STATE:%=%.state) STATE_OUT = $(TST_STATE:%=%.out) -%: %.c - $(Q)echo $@ >> .gitignore - $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(LOADLIBES) $^ $(LDLIBS) -o $@ +%.o: %.c + @echo $@ >> .gitignore + $(E) " CC " $@ + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +%: %.o + @echo $@ >> .gitignore + $(E) " LINK " $@ + $(Q)$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ all: $(TST) criu-rtc.so install: all @@ -390,7 +397,7 @@ wait_stop: i=`expr $$i + 1`; \ done -$(TST): $(LIB) +$(TST): | $(LIB) aio00: override LDLIBS += -laio different_creds: override LDLIBS += -lcap diff --git a/test/zdtm/transition/Makefile b/test/zdtm/transition/Makefile index a5ca99fa2..4466333c7 100644 --- a/test/zdtm/transition/Makefile +++ b/test/zdtm/transition/Makefile @@ -1,4 +1,5 @@ include ../Makefile.inc +.SUFFIXES: # No implicit rules LIBDIR = ../lib LIB = $(LIBDIR)/libzdtmtst.a @@ -40,9 +41,15 @@ DEP = $(SRC:%.c=%.d) PID = $(TST:%=%.pid) OUT = $(TST:%=%.out) -%: %.c - $(Q)echo $@ >> .gitignore - $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(LOADLIBES) $^ $(LDLIBS) -o $@ +%.o: %.c + @echo $@ >> .gitignore + $(E) " CC " $@ + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +%: %.o + @echo $@ >> .gitignore + $(E) " LINK " $@ + $(Q)$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ all: $(TST) install: all @@ -74,7 +81,7 @@ wait_stop: sleep 1; \ done -$(TST): $(LIB) +$(TST): | $(LIB) file_aio: override LDLIBS += -lrt -pthread socket-tcp: override CFLAGS += -D STREAM From 7290de590251eb260b0e57056b34d70f5c7a7dae Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 16 Mar 2017 14:27:36 -0700 Subject: [PATCH 0415/4375] travis: enable ccache for docker/qemu builds As we compile-test non-x86_64 architectures under qemu emulation, it works pretty slow. Dmitry Safonov suggested, and Andrey Vagin initially implemented supporting ccache for such builds. This patch is based heavily on Andrey's work -- all the bugs added are purely mine though. Performance results: in an ideal environment (two builds of the same code, one with cold (empty) ccache, another with the hot one) I saw compile time improvements of 4x to 5x, and total test run time improvement up to 2x to 2.5x. In layman terms, the complete test run that was taking more than 50 minutes now takes about 25! Notes on handling .ccache directory: 1. Before running docker build, .ccache directory (saved in between runs by Travis) is moved to criu source code root, from where it is copied by docker together with criu sources. 2. In Dockerfile, .ccache gets moved to /tmp, and CCACHE_DIR is set accordingly. 3. After running docker build, .ccache is copied out from docker container back to the host (from where it is saved by Travis). Ccache envorinment notes: 1. CCACHE_NOCOMPRESS is needed because otherwise tons of time is spent on compression/decompression (big performance hit under qemu). 2. CCACHE_CPP2 is required with clang, see detailed explanation at http://petereisentraut.blogspot.com/2011/09/ccache-and-clang-part-2.html The logic of setting CCACHE_CPP2 in Dockerfile is somewhat fancy; unfortunately I was not able to come up with a simpler approach. Misc: 1. Travis runs "ccache -s" after the build is completed. A call to "ccache -s" is called to Dockerfile before make, so one can compare before/after numbers. 2. make invocations are surrounded by "date" calls so one can get the compilation times. Changes in v2: - consolidate Dockerfile statements (ENV, RUN) - single object make test is no longer commented out - simplify "make mrproper" test Signed-off-by: Kir Kolyshkin Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.alpine | 16 ++++++++++------ scripts/build/Dockerfile.tmpl | 23 +++++++++++++++++------ scripts/build/Makefile | 6 +++++- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index 86738a748..26c39ac25 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -1,5 +1,7 @@ FROM alpine:3.5 ARG CC=gcc +ARG ENV1=FOOBAR + RUN apk update && apk add \ build-base \ coreutils \ @@ -12,18 +14,20 @@ RUN apk update && apk add \ libnl3-dev \ pkgconfig \ libnet-dev \ + ccache \ $CC COPY . /criu WORKDIR /criu -RUN make mrproper && make -j $(nproc) CC=$CC +ENV CC="ccache $CC" CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes +RUN mv .ccache /tmp; make mrproper; ccache -s; \ + date; make -j $(nproc) CC="$CC"; date -# to run tests +# Run a test RUN apk add py-yaml \ py-pip \ ip6tables \ iptables \ - iproute2 - -RUN pip install protobuf -RUN make -C test/zdtm/static env00 + iproute2 \ + && pip install protobuf \ + && make -C test/zdtm/static env00 diff --git a/scripts/build/Dockerfile.tmpl b/scripts/build/Dockerfile.tmpl index 6e35f87b6..60e0e4591 100644 --- a/scripts/build/Dockerfile.tmpl +++ b/scripts/build/Dockerfile.tmpl @@ -1,4 +1,5 @@ ARG CC=gcc +ARG ENV1=FOOBAR RUN apt-get update && apt-get install -y \ build-essential \ @@ -16,15 +17,25 @@ RUN apt-get update && apt-get install -y \ pkg-config \ git-core \ libnet-dev \ + ccache \ $CC COPY . /criu WORKDIR /criu +ENV CC="ccache $CC" CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes + +RUN mv .ccache /tmp && make mrproper; ccache -s; \ + date; \ +# Check single object build + make -j $(nproc) CC="$CC" criu/parasite-syscall.o; \ +# Compile criu + make -j $(nproc) CC="$CC"; \ + date; \ +# Check that "make mrproper" works + make mrproper && ! git clean -ndx --exclude=scripts/build \ + --exclude=.config --exclude=test | grep . + +# Compile tests +RUN date; make -j $(nproc) CC="$CC" -C test/zdtm; date -RUN make mrproper -RUN make -j $(nproc) CC=$CC V=1 criu/parasite-syscall.o -RUN make -j $(nproc) CC=$CC V=1 -RUN make mrproper -RUN bash -c 'CLEAN="$(git clean -ndx --exclude=scripts/build --exclude=.config)"; echo "${CLEAN}"; test -z "${CLEAN}"; exit $?' -RUN make -j $(nproc) CC=$CC -C test/zdtm #RUN make test/compel/handle_binary && ./test/compel/handle_binary diff --git a/scripts/build/Makefile b/scripts/build/Makefile index fc8317b41..b17bf10f5 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -25,7 +25,10 @@ binfmt_misc: $(QEMU_ARCHES): qemu-user-static binfmt_misc $(TARGETS): - docker build -t criu-$@ -f Dockerfile.$@ $(DB_CC) ../.. + mkdir -p $(HOME)/.ccache + mv $(HOME)/.ccache ../../ + docker build -t criu-$@ -f Dockerfile.$@ $(DB_CC) $(DB_ENV) ../.. + docker run criu-$@ tar c -C /tmp .ccache | tar x -C $(HOME) .PHONY: $(TARGETS) # Clang builds add some Docker build env @@ -35,6 +38,7 @@ endef $(foreach t,$(TARGETS),$(eval $(call CLANG_DEP,$(t)))) %-clang: DB_CC=--build-arg CC=clang-3.8 +%-clang: DB_ENV=--build-arg ENV1=CCACHE_CPP2 alpine-clang: DB_CC=--build-arg CC=clang aarch64-clang: DB_CC=--build-arg CC=clang-3.6 .PHONY: $(TARGETS_CLANG) From e3f0c52596ac569e86424664a398284aa469c88d Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Mon, 27 Feb 2017 22:58:35 -0800 Subject: [PATCH 0416/4375] travis: add "make uninstall" test "make uninstall" is supposed to remove all the files that "make install" (with the same arguments) have created. This is a test to check that. PS ideally, "make uninstall" should also remove any empty directories, but let's not care about it for now. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 3 ++- test/others/make/Makefile | 5 +++++ test/others/make/uninstall.sh | 22 ++++++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 test/others/make/Makefile create mode 100755 test/others/make/uninstall.sh diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index ec730019b..50a51ff35 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -4,7 +4,7 @@ set -x -e TRAVIS_PKGS="protobuf-c-compiler libprotobuf-c0-dev libaio-dev libprotobuf-dev protobuf-compiler python-ipaddr libcap-dev libnl-3-dev gcc-multilib libc6-dev-i386 gdb bash python-protobuf - libnet-dev util-linux" + libnet-dev util-linux asciidoc" travis_prep () { [ -n "$SKIP_TRAVIS_PREP" ] && return @@ -70,6 +70,7 @@ bash ./test/jenkins/criu-inhfd.sh make -C test/others/mnt-ext-dev/ run #make -C test/others/exec/ run +make -C test/others/make/ run ./test/zdtm.py run -t zdtm/static/env00 --sibling diff --git a/test/others/make/Makefile b/test/others/make/Makefile new file mode 100644 index 000000000..b77b8259e --- /dev/null +++ b/test/others/make/Makefile @@ -0,0 +1,5 @@ +# Tests for the build system + +run: + ./uninstall.sh +.PHONY: run diff --git a/test/others/make/uninstall.sh b/test/others/make/uninstall.sh new file mode 100755 index 000000000..ec5a74d2d --- /dev/null +++ b/test/others/make/uninstall.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# A test to make sure "make uninstall" works as intended. + +set -e +SELFDIR=$(dirname $(readlink -f $0)) +DESTDIR=$SELFDIR/test.install-$$ +cd $SELFDIR/../../.. + +set -x +make install DESTDIR=$DESTDIR +make uninstall DESTDIR=$DESTDIR +set +x + +# There should be no files left (directories are OK for now) +if [ $(find $DESTDIR -type f | wc -l) -gt 0 ]; then + echo "Files left after uninstall:" + find $DESTDIR -type f + echo "FAIL" + exit 1 +fi + +echo PASS From 1f942ca84ad9769cfc1f8311ef4d347e82f2c82d Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 20 Mar 2017 12:45:40 +0300 Subject: [PATCH 0417/4375] mount: fix confusing naming s/find_widest_shared/find_wider_shared/ Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 50c4d9378..0227cd40b 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -509,7 +509,7 @@ static int try_resolve_ext_mount(struct mount_info *info) return 0; } -static struct mount_info *find_widest_shared(struct mount_info *m) +static struct mount_info *find_wider_shared(struct mount_info *m) { struct mount_info *p; @@ -560,7 +560,7 @@ static int validate_shared(struct mount_info *m) * has the same set of children. */ - t = find_widest_shared(m); + t = find_wider_shared(m); if (!t) /* * The current mount is the widest one in its shared group, From 37887781e3fcf1313cfdaeebf8e3a47501389885 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 20 Mar 2017 12:45:41 +0300 Subject: [PATCH 0418/4375] mount: remove excess mi->external checks mi->external is always false in these places Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 0227cd40b..0f1f4db8e 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1774,7 +1774,7 @@ static int do_new_mount(struct mount_info *mi) goto out; } - if (!mi->is_ns_root && !mi->external && remount_ro) { + if (!mi->is_ns_root && remount_ro) { int fd; fd = open(mi->mountpoint, O_PATH); @@ -2071,7 +2071,7 @@ static bool can_mount_now(struct mount_info *mi) } } - if (!fsroot_mounted(mi) && (mi->bind == NULL && !mi->need_plugin && !mi->external)) + if (!fsroot_mounted(mi) && (mi->bind == NULL && !mi->need_plugin)) return false; shared: From 9b2acbe427fdf7e0ace351f7069a4149a1723626 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 21 Mar 2017 12:04:31 +0300 Subject: [PATCH 0419/4375] ns: Fix return collison in prepare_userns_creds() "return" and "exit" are mixed in this function, and this is wrong. Must be "return" only, because its callers don't want exit. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/namespaces.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/namespaces.c b/criu/namespaces.c index 92ae1d7db..13a6a3b93 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -1501,7 +1501,7 @@ int collect_namespaces(bool for_dump) return 0; } -static int prepare_userns_creds() +static int prepare_userns_creds(void) { /* UID and GID must be set after restoring /proc/PID/{uid,gid}_maps */ if (setuid(0) || setgid(0) || setgroups(0, NULL)) { @@ -1517,7 +1517,7 @@ static int prepare_userns_creds() */ if (prctl(PR_SET_DUMPABLE, 1, 0)) { pr_perror("Unable to set PR_SET_DUMPABLE"); - exit(1); + return -1; } return 0; From fded9a000c46ea0b417e53b2af281496860919be Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 22 Mar 2017 12:19:59 +0300 Subject: [PATCH 0420/4375] mount: save ext_real_root for external mounts need it to check if we can bindmount from external mount note: when migrating from criu with patch to criu without, external mount mapping won't work, we do not support it. v2: s/real_root/ext_real_root/ v4: add comment v5: use ext_key field for mapping, put NO_ROOT_MOUNT in root for old externals for which we do not have it. Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 32 +++++++++++++++++++++++--------- images/mnt.proto | 2 ++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 0f1f4db8e..b8e8598aa 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -35,6 +35,7 @@ * debugging. */ #define AUTODETECTED_MOUNT "CRIU:AUTOGENERATED" +#define NO_ROOT_MOUNT "CRIU:NO_ROOT" #define MS_PROPAGATE (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE | MS_SLAVE) #undef LOG_PREFIX @@ -1329,17 +1330,14 @@ static int dump_one_mountpoint(struct mount_info *pm, struct cr_img *img) me.internal_sharing = true; } - if (pm->external) { + if (pm->external) /* * For external mount points dump the mapping's - * value instead of root. See collect_mnt_from_image + * value, see collect_mnt_from_image -> get_mp_root * for reverse mapping details. */ - me.root = pm->external; - me.has_ext_mount = true; - me.ext_mount = true; - } else - me.root = pm->root; + me.ext_key = pm->external; + me.root = pm->root; if (pb_write_one(img, &me, PB_MNT)) return -1; @@ -2446,11 +2444,27 @@ static int get_mp_root(MntEntry *me, struct mount_info *mi) { char *ext = NULL; + BUG_ON(me->ext_mount && me->ext_key); + + /* Forward compatibility fixup */ + if (me->ext_mount) { + me->ext_key = me->root; + /* + * Puting the id of external mount which is provided by user, + * to ->root can confuse mnt_is_external and other functions + * which expect to see the path in the file system to the root + * of these mount (mounts_equal, mnt_build_ids_tree, + * find_wider_shared, find_fsroot_mount_for, + * find_best_external_match, etc.) + */ + me->root = NO_ROOT_MOUNT; + } + mi->root = xstrdup(me->root); if (!mi->root) return -1; - if (!me->ext_mount) + if (!me->ext_key) goto out; /* @@ -2458,7 +2472,7 @@ static int get_mp_root(MntEntry *me, struct mount_info *mi) * from the command line and put into root's place */ - ext = ext_mount_lookup(me->root); + ext = ext_mount_lookup(me->ext_key); if (!ext) { if (!opts.autodetect_ext_mounts) { pr_err("No mapping for %s mountpoint\n", me->mountpoint); diff --git a/images/mnt.proto b/images/mnt.proto index 50cd8afbb..4160acbf6 100644 --- a/images/mnt.proto +++ b/images/mnt.proto @@ -53,4 +53,6 @@ message mnt_entry { optional bool deleted = 16; optional uint32 sb_flags = 17 [(criu).hex = true]; + /* user defined mapping for external mount */ + optional string ext_key = 18; } From 742252a49ba2adf571791ba38758c83aa2d279a9 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 22 Mar 2017 12:20:00 +0300 Subject: [PATCH 0421/4375] mount: migrate bindmounts of external mounts If container has external bindmount given to criu through --ext-mount-map option by admin, container user can bindmount subdirs of these external bindmount to somewhere else inside container creating secondary external bindmounts. Criu we will fail to restore them as having unreachable sharing. But we can restore secondary external bindmounts bindmounting them from primary external bindmount. v2: s/external_bind/mnt_is_external/, make mnt_is_external bool, do mnt_is_external without recursion v3: add debug message on propagate_mount when bind is set v5: remove hunk of v4 which goes to previous patch, so same as v3 Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index b8e8598aa..700bb8fb2 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -645,6 +645,36 @@ static bool does_mnt_overmount(struct mount_info *m) return false; } +/* + * Say mount is external if it was explicitly specified as an + * external or it will be bind from such an explicit external + * mount, we set bind in propagate_mount and propagate_siblings + */ + +static bool mnt_is_external(struct mount_info *m) +{ + struct mount_info *t; + + while (m) { + if (m->external) + return 1; + + if (!list_empty(&m->mnt_share)) + list_for_each_entry(t, &m->mnt_share, mnt_share) + if (t->external) + return 1; + + if (m->master_id <= 0 && !list_empty(&m->mnt_bind)) + list_for_each_entry(t, &m->mnt_bind, mnt_bind) + if (issubpath(m->root, t->root) && t->external) + return 1; + + m = m->mnt_master; + } + + return 0; +} + static int validate_mounts(struct mount_info *info, bool for_dump) { struct mount_info *m, *t; @@ -657,7 +687,7 @@ static int validate_mounts(struct mount_info *info, bool for_dump) if (m->shared_id && validate_shared(m)) return -1; - if (m->external) + if (mnt_is_external(m)) goto skip_fstype; /* @@ -913,9 +943,9 @@ static int resolve_shared_mounts(struct mount_info *info, int root_master_id) /* * If we haven't already determined this mount is external, - * then we don't know where it came from. + * or bind of external, then we don't know where it came from. */ - if (need_master && m->parent && !m->external) { + if (need_master && m->parent && !mnt_is_external(m)) { pr_err("Mount %d %s (master_id: %d shared_id: %d) " "has unreachable sharing. Try --enable-external-masters.\n", m->mnt_id, m->mountpoint, m->master_id, m->shared_id); @@ -1248,7 +1278,7 @@ static int dump_one_fs(struct mount_info *mi) struct mount_info *t; bool first = true; - if (mi->is_ns_root || mi->need_plugin || mi->external || !mi->fstype->dump) + if (mi->is_ns_root || mi->need_plugin || mnt_is_external(mi) || !mi->fstype->dump) return 0; /* mnt_bind is a cycled list, so list_for_each can't be used here. */ @@ -1661,7 +1691,7 @@ skip_parent: * FIXME Currently non-root mounts can be restored * only if a proper root mount exists */ - if (fsroot_mounted(mi) || mi->parent == root_yard_mp) { + if (fsroot_mounted(mi) || mi->parent == root_yard_mp || mi->external) { list_for_each_entry(t, &mi->mnt_bind, mnt_bind) { if (t->mounted) continue; @@ -1669,6 +1699,9 @@ skip_parent: continue; if (t->master_id > 0) continue; + if (!issubpath(t->root, mi->root)) + continue; + pr_debug("\t\tBind private %s\n", t->mountpoint); t->bind = mi; t->s_dev_rt = mi->s_dev_rt; } From 983a762a0b3a67d763f957737d38627c666f4ba8 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 22 Mar 2017 12:20:01 +0300 Subject: [PATCH 0422/4375] zdtm/mnt_ext_auto: add different bind-mounts of external mount Before dump: 438 437 0:51 /mtest /zdtm/static/mnt_ext_manual.test rw,relatime - tmpfs zdtm_auto_ext_mnt rw 439 437 0:51 /mtest /zdtm/static/mnt_ext_manual_private_shared_bind.test rw,relatime shared:144 - tmpfs zdtm_auto_ext_mnt rw 440 437 0:51 /mtest /zdtm/static/mnt_ext_manual_bind.test rw,relatime shared:144 - tmpfs zdtm_auto_ext_mnt rw 441 437 0:51 /mtest /zdtm/static/mnt_ext_manual_slave_shared_bind.test rw,relatime shared:145 master:144 - tmpfs zdtm_auto_ext_mnt rw 442 437 0:51 /mtest /zdtm/static/mnt_ext_manual_slave_bind.test rw,relatime master:145 - tmpfs zdtm_auto_ext_mnt rw >From log: mount mnt_ext_manual_slave_bind is restored as slave of mnt_ext_manual_slave_shared_bind, which is restored as slave of mnt_ext_manual_private_shared_bind, which is restored as shared of mnt_ext_manual_bind, which is restored as private bind of external, that is exactly the same way mnt_is_external() looks for external. v2: fix test to cover all cases in mnt_is_external() Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm/static/mnt_ext_auto.c | 114 +++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/mnt_ext_auto.c b/test/zdtm/static/mnt_ext_auto.c index 44d774bf1..69d814939 100644 --- a/test/zdtm/static/mnt_ext_auto.c +++ b/test/zdtm/static/mnt_ext_auto.c @@ -16,9 +16,17 @@ const char *test_author = "Andrew Vagin "; #ifdef ZDTM_EXTMAP_MANUAL char *dirname = "mnt_ext_manual.test"; +char *dirname_private_shared_bind = "mnt_ext_manual_private_shared_bind.test"; +char *dirname_bind = "mnt_ext_manual_bind.test"; +char *dirname_slave_shared_bind = "mnt_ext_manual_slave_shared_bind.test"; +char *dirname_slave_bind = "mnt_ext_manual_slave_bind.test"; #define DDIR "mtest" #else char *dirname = "mnt_ext_auto.test"; +char *dirname_private_shared_bind = "mnt_ext_auto_private_shared_bind.test"; +char *dirname_bind = "mnt_ext_auto_bind.test"; +char *dirname_slave_shared_bind = "mnt_ext_auto_slave_shared_bind.test"; +char *dirname_slave_bind = "mnt_ext_auto_slave_bind.test"; #define DDIR "atest" #endif TEST_OPTION(dirname, string, "directory name", 1); @@ -26,8 +34,10 @@ TEST_OPTION(dirname, string, "directory name", 1); int main(int argc, char ** argv) { char src[PATH_MAX], dst[PATH_MAX], *root; + char dst_bind[PATH_MAX], dst_private_shared_bind[PATH_MAX], + dst_slave_shared_bind[PATH_MAX], dst_slave_bind[PATH_MAX]; char *dname = "/tmp/zdtm_ext_auto.XXXXXX"; - struct stat sta, stb; + struct stat sta, stb, bsta, bstb, ssbsta, sbsta, ssbstb, sbstb, psbsta, psbstb; char* zdtm_newns = getenv("ZDTM_NEWNS"); root = getenv("ZDTM_ROOT"); @@ -37,6 +47,10 @@ int main(int argc, char ** argv) } sprintf(dst, "%s/%s", get_current_dir_name(), dirname); + sprintf(dst_private_shared_bind, "%s/%s", get_current_dir_name(), dirname_private_shared_bind); + sprintf(dst_bind, "%s/%s", get_current_dir_name(), dirname_bind); + sprintf(dst_slave_shared_bind, "%s/%s", get_current_dir_name(), dirname_slave_shared_bind); + sprintf(dst_slave_bind, "%s/%s", get_current_dir_name(), dirname_slave_bind); if (!zdtm_newns) { pr_perror("ZDTM_NEWNS is not set"); @@ -59,6 +73,46 @@ int main(int argc, char ** argv) pr_perror("bind"); return 1; } + mkdir(dst_private_shared_bind, 755); + if (mount(dst, dst_private_shared_bind, NULL, MS_BIND, NULL)) { + pr_perror("bind"); + return 1; + } + if (mount("none", dst_private_shared_bind, NULL, MS_PRIVATE, NULL)) { + pr_perror("bind"); + return 1; + } + if (mount("none", dst_private_shared_bind, NULL, MS_SHARED, NULL)) { + pr_perror("bind"); + return 1; + } + mkdir(dst_bind, 755); + if (mount(dst_private_shared_bind, dst_bind, NULL, MS_BIND, NULL)) { + pr_perror("bind"); + return 1; + } + mkdir(dst_slave_shared_bind, 755); + if (mount(dst_bind, dst_slave_shared_bind, NULL, MS_BIND, NULL)) { + pr_perror("bind"); + return 1; + } + if (mount("none", dst_slave_shared_bind, NULL, MS_SLAVE, NULL)) { + pr_perror("bind"); + return 1; + } + if (mount("none", dst_slave_shared_bind, NULL, MS_SHARED, NULL)) { + pr_perror("bind"); + return 1; + } + mkdir(dst_slave_bind, 755); + if (mount(dst_slave_shared_bind, dst_slave_bind, NULL, MS_BIND, NULL)) { + pr_perror("bind"); + return 1; + } + if (mount("none", dst_slave_bind, NULL, MS_SLAVE, NULL)) { + pr_perror("bind"); + return 1; + } test: test_init(argc, argv); @@ -67,18 +121,76 @@ test: sleep(100); return 1; } + if (stat(dirname_private_shared_bind, &psbstb)) { + pr_perror("stat"); + sleep(100); + return 1; + } + if (stat(dirname_bind, &bstb)) { + pr_perror("stat"); + sleep(100); + return 1; + } + if (stat(dirname_slave_shared_bind, &ssbstb)) { + pr_perror("stat"); + sleep(100); + return 1; + } + if (stat(dirname_slave_bind, &sbstb)) { + pr_perror("stat"); + sleep(100); + return 1; + } test_daemon(); test_waitsig(); if (stat(dirname, &sta)) { pr_perror("stat"); + sleep(100); return 1; } + if (stat(dirname_private_shared_bind, &psbsta)) { + pr_perror("stat"); + sleep(100); + return 1; + } + if (stat(dirname_bind, &bsta)) { + pr_perror("stat"); + sleep(100); + return 1; + } + if (stat(dirname_slave_shared_bind, &ssbsta)) { + pr_perror("stat"); + sleep(100); + return 1; + } + if (stat(dirname_slave_bind, &sbsta)) { + pr_perror("stat"); + sleep(100); + return 1; + } + if (sta.st_dev != stb.st_dev) { fail(); return 1; } + if (psbsta.st_dev != psbstb.st_dev) { + fail(); + return 1; + } + if (bsta.st_dev != bstb.st_dev) { + fail(); + return 1; + } + if (ssbsta.st_dev != ssbstb.st_dev) { + fail(); + return 1; + } + if (sbsta.st_dev != sbstb.st_dev) { + fail(); + return 1; + } pass(); From 9301c5d6138f9cc21d677d0a20fb747e44926798 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsburskiy Date: Thu, 16 Mar 2017 15:45:39 +0300 Subject: [PATCH 0423/4375] compel: return ptrace area helpers back to uapi These helpers are valuable and can be used outside. Signed-off-by: Stanislav Kinsburskiy Signed-off-by: Andrei Vagin --- compel/include/ptrace.h | 4 ---- compel/include/uapi/ptrace.h | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compel/include/ptrace.h b/compel/include/ptrace.h index 30dc74441..01f55c45a 100644 --- a/compel/include/ptrace.h +++ b/compel/include/ptrace.h @@ -7,10 +7,6 @@ #define PTRACE_SI_EVENT(_si_code) (((_si_code) & 0xFFFF) >> 8) -extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes); -extern int ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes); -extern int ptrace_swap_area(pid_t pid, void *dst, void *src, long bytes); - extern int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs); extern int ptrace_set_regs(pid_t pid, user_regs_struct_t *regs); diff --git a/compel/include/uapi/ptrace.h b/compel/include/uapi/ptrace.h index d249bd99f..7024efef3 100644 --- a/compel/include/uapi/ptrace.h +++ b/compel/include/uapi/ptrace.h @@ -60,4 +60,8 @@ extern int ptrace_suspend_seccomp(pid_t pid); +extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes); +extern int ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes); +extern int ptrace_swap_area(pid_t pid, void *dst, void *src, long bytes); + #endif /* UAPI_COMPEL_PTRACE_H__ */ From 7ac8ba5560865dfa6de27feb25105dd38b574d2e Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 23 Mar 2017 15:02:00 -0700 Subject: [PATCH 0424/4375] prepare_pstree_ids(): improve an error message I guess this is a followup to commit 59e80d4. 1 s/determinate/figure out/ (there is no "determinate" verb in English) 2 moved 'with' to the end Cc: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/pstree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/pstree.c b/criu/pstree.c index 7d92a3ef8..d537e5831 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -710,8 +710,8 @@ static int prepare_pstree_ids(void) parent = item->parent; while (parent && vpid(parent) != item->sid) { if (parent->born_sid != -1 && parent->born_sid != item->sid) { - pr_err("Can't determinate with which sid (%d or %d)" - "the process %d was born\n", + pr_err("Can't figure out which sid (%d or %d)" + "the process %d was born with\n", parent->born_sid, item->sid, vpid(parent)); return -1; } From 132d0458eeeb0c1f4170c818ac9cb47c8d08bf37 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 23 Mar 2017 15:02:01 -0700 Subject: [PATCH 0425/4375] can_dump_inet_sk(): improve an error message Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index fb3939267..046d04be5 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -137,7 +137,7 @@ static int can_dump_inet_sk(const struct inet_sk_desc *sk) if (sk->type != SOCK_STREAM) { pr_err("Can't dump %d inet socket %x. " - "Only can stream and dgram.\n", + "Only stream and dgram are supported.\n", sk->type, sk->sd.ino); return 0; } From 55a140d48d792099f086d57a4f6568081e152821 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 23 Mar 2017 15:02:04 -0700 Subject: [PATCH 0426/4375] Correct an error message after waitpid Usually we print the PID we wait for, let's do the same here. Probably just a typo. Cc: Kirill Tkhai Reviewed-by: Kirill Tkhai Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/namespaces.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/namespaces.c b/criu/namespaces.c index 13a6a3b93..c4a75a620 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -896,7 +896,7 @@ static int check_user_ns(int pid) } if (waitpid(chld, &status, 0) != chld) { - pr_perror("Unable to wait the %d process", pid); + pr_perror("Unable to wait for PID %d", chld); return -1; } From 6d8f8399ef63f10b6350300acd311b70e9f1db18 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsburskiy Date: Fri, 17 Mar 2017 14:15:48 +0300 Subject: [PATCH 0427/4375] compel: wrap rt_sigframe with parentheses It can be passed as link to real object. Signed-off-by: Stanislav Kinsburskiy Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/include/uapi/asm/sigframe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h index 21cd341c0..2b51c3666 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h @@ -150,7 +150,7 @@ struct rt_sigframe { * - compatible is in sys32_rt_sigreturn at arch/x86/ia32/ia32_signal.c * - native is in sys_rt_sigreturn at arch/x86/kernel/signal.c */ -#define RT_SIGFRAME_OFFSET(rt_sigframe) ((rt_sigframe->is_native) ? 8 : 4 ) +#define RT_SIGFRAME_OFFSET(rt_sigframe) (((rt_sigframe)->is_native) ? 8 : 4 ) #define USER32_CS 0x23 From 28b3b60032225da90293979ebacda153851fd661 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 24 Mar 2017 15:07:38 -0700 Subject: [PATCH 0428/4375] criu/pie/Makefile: nuke SRC_DIR This is a missing hunk from commit 85b04c8 "Makefiles: nuke $(SRC_DIR)" which has somehow escaped from my attention. Acked-by: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index d8b3fbff8..711d83a60 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -37,7 +37,7 @@ endif asflags-y += -D__ASSEMBLY__ BLOBS += $(obj)/restorer-blob.h $(obj)/parasite-blob.h -LDS := $(SRC_DIR)/compel/arch/$(SRCARCH)/scripts/compel-pack.lds.S +LDS := compel/arch/$(SRCARCH)/scripts/compel-pack.lds.S .SECONDARY: From 75d0c5df9933443bb8828dd2b50df1fd81602165 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 24 Mar 2017 15:07:39 -0700 Subject: [PATCH 0429/4375] criu/Makefile: rm criu/pie from -iquote There are too many directories in the include path. Let's remove this one, and refer to the blobs with pie/ prefix. Acked-by: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/Makefile | 1 - criu/cr-restore.c | 2 +- criu/parasite-syscall.c | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/criu/Makefile b/criu/Makefile index 735890e0f..b2c663310 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -20,7 +20,6 @@ ccflags-y += -fno-strict-aliasing ccflags-y += -iquote criu/include ccflags-y += -iquote include ccflags-y += -iquote images -ccflags-y += -iquote criu/pie ccflags-y += -iquote $(ARCH_DIR)/include ccflags-y += -iquote . ccflags-y += -I/usr/include/libnl3 diff --git a/criu/cr-restore.c b/criu/cr-restore.c index c87cc44b5..95ad9ab65 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -47,7 +47,7 @@ #include "eventpoll.h" #include "signalfd.h" #include "proc_parse.h" -#include "restorer-blob.h" +#include "pie/restorer-blob.h" #include "crtools.h" #include "namespaces.h" #include "mem.h" diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index fef902de9..fdd20a06e 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -43,7 +43,7 @@ #include "infect.h" #include "infect-rpc.h" -#include "parasite-blob.h" +#include "pie/parasite-blob.h" #include From 76de67f9bd8eb91664db8ce53b042f2df16509eb Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 24 Mar 2017 15:07:40 -0700 Subject: [PATCH 0430/4375] .gitignore: remove a leftover This is an addition to commit 3a7e027 ("criu: pie -- Switch to use compel shipped lds scripts"). Acked-by: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3aaead18b..d1725af2d 100644 --- a/.gitignore +++ b/.gitignore @@ -35,7 +35,6 @@ soccr/config.h criu/include/version.h criu/pie/restorer-blob.h criu/pie/parasite-blob.h -criu/pie/pie.lds*.S criu/protobuf-desc-gen.h lib/build/ lib/c/criu.pc From 9cf884f02fe1c93ffa5fb5a52325e5beb0eaaf32 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 24 Mar 2017 15:07:41 -0700 Subject: [PATCH 0431/4375] criu/pie/Makefile.library: clean up 1. Remove useless LDFLAGS -- dynamic linker is not used here. 2. Remove $(iquotes) -- there are none defined here. 3. Consolidate filter-out statements into a single one. Acked-by: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/pie/Makefile.library | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 78da25de2..f58933313 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -1,7 +1,6 @@ lib-name := pie.lib.a CFLAGS += -fno-stack-protector -DCR_NOGLIBC -fpie -LDFLAGS += -z noexecstack lib-y += util.o @@ -34,10 +33,9 @@ endif # applications, which is not the target of the # project. # -CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) $(iquotes) -CFLAGS := $(filter-out $(CFLAGS-ASAN),$(CFLAGS)) +CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) -asflags-y := -D__ASSEMBLY__ $(iquotes) +asflags-y := -D__ASSEMBLY__ ccflags-y += $(COMPEL_UAPI_INCLUDES) ifeq ($(SRCARCH),arm) From 37904cc91a712f27a739319fd9bb99a8fcc819d7 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 24 Mar 2017 15:07:42 -0700 Subject: [PATCH 0432/4375] criu/pie/Makefile: simplify and fix The way criu/pie/Makefile is currently written, ld is run twice: 1. link $(NAME-obj-y) objects to NAME.built-in.o 2. link NAME.built-in.o, pie.lib.a, and compel plugins to NAME.built-in.bin.o (with compel ldflags and linker script) There is absolutely no need for such two-stage linking, but it was OK. It is not OK now, as "compel ldflags" for ARM doesn't need -r, and we can't run the first stage with -r and the second stage without it. So, let's simplify linking using a single ld invocation. This is my third attempt in doing it, I think I nailed it this time -- it is now clean and (relatively) simple. While at it: - fix compel linker script dependency (it was not working); - rearrange the Makefile so variables goes first, then rules; - remove a comment about mount implementation in restorer. NOTE that compel is called with ./ prefix so the file paths it prints are also prefixed with ./, which is needed for objectify macro to ignore those. Acked-by: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- Makefile.compel | 2 +- criu/pie/Makefile | 81 ++++++++++++++++++++--------------------------- 2 files changed, 35 insertions(+), 48 deletions(-) diff --git a/Makefile.compel b/Makefile.compel index ab479f79d..50124351d 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -1,4 +1,4 @@ -COMPEL_BIN := compel/compel-host +COMPEL_BIN := ./compel/compel-host export COMPEL_BIN COMPEL_VERSION_HEADER := compel/include/version.h diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 711d83a60..6a4fba9c1 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -1,7 +1,25 @@ -target += parasite restorer +target := parasite restorer + +CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) +ccflags-y += $(COMPEL_UAPI_INCLUDES) +ccflags-y += -DCR_NOGLIBC +ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 +ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 + +ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) + CFLAGS += $(shell $(COMPEL_BIN) cflags) + LDFLAGS += $(shell $(COMPEL_BIN) ldflags) + compel_plugins := $(shell $(COMPEL_BIN) plugins) +endif + +ifeq ($(SRCARCH),arm) + ccflags-y += -marm +endif + +asflags-y += -D__ASSEMBLY__ + +LDS := compel/arch/$(SRCARCH)/scripts/compel-pack.lds.S -parasite-obj-y += parasite.o -restorer-obj-y += restorer.o restorer-obj-y += ./$(ARCH_DIR)/restorer.o ifeq ($(ARCH),x86) @@ -11,51 +29,20 @@ ifeq ($(ARCH),x86) endif endif -# -# We can't provide proper mount implementation -# in parasite code -- it requires run-time rellocation -# applications, which is not the target of the -# project. -# -CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) -CFLAGS := $(filter-out $(CFLAGS-ASAN),$(CFLAGS)) +define gen-pie-rules +$(1)-obj-y += $(1).o +$(1)-obj-e += pie.lib.a +$(1)-obj-e += $$(compel_plugins) -ccflags-y += $(COMPEL_UAPI_INCLUDES) -ccflags-y += -DCR_NOGLIBC -ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 +# Dependency on compel linker script, to relink if it has changed +$$(obj)/$(1).built-in.o: $$(LDS) -ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) - CFLAGS += $(shell $(COMPEL_BIN) cflags) - compel_std := $(shell $(COMPEL_BIN) plugins) -endif +$$(obj)/$(1)-blob.h: $$(obj)/$(1).built-in.o + $$(call msg-gen, $$@) + $$(Q) $$(COMPEL_BIN) hgen -f $$< -o $$@ -ifeq ($(SRCARCH),arm) - ccflags-y += -marm -endif +all-y += $$(obj)/$(1)-blob.h +cleanup-y += $$(obj)/$(1)-blob.h +endef -asflags-y += -D__ASSEMBLY__ - -BLOBS += $(obj)/restorer-blob.h $(obj)/parasite-blob.h -LDS := compel/arch/$(SRCARCH)/scripts/compel-pack.lds.S - -.SECONDARY: - -target-name = $(patsubst criu/pie/%-blob.h,%,$(1)) - -$(obj)/%.build-in.bin.o: $(LDS) -$(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/pie.lib.a $(compel_std) - $(call msg-gen, $@) - $(Q) $(LD) $(shell $(COMPEL_BIN) ldflags) -o $@ $^ - -$(obj)/%-blob.h: $(obj)/%.built-in.bin.o - $(call msg-gen, $@) - $(Q) $(COMPEL_BIN) hgen -f $< -o $@ - -all-y += $(BLOBS) -# blobs and pields are in cleanup, rather than in mrproper because -# we want them to be re-generated after `make clean && make` -cleanup-y += $(BLOBS) -cleanup-y += $(obj)/*.bin -cleanup-y += $(obj)/*.built-in.bin.o -cleanup-y += $(obj)/*.built-in.bin +$(foreach t,$(target),$(eval $(call gen-pie-rules,$(t)))) From f3a1dc5cc9c91d916976eb795003e2ce25785890 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 24 Mar 2017 15:07:43 -0700 Subject: [PATCH 0433/4375] compel/plugins/Makefile: clean up 1. Remove .FORCE, it's not used. 2. Consolidate CFLAGS stripping into a single line. Acked-by: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/plugins/Makefile | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 79ed21dce..e834a05dc 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -1,9 +1,7 @@ -.PHONY: .FORCE +CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) +CFLAGS += -DCR_NOGLIBC -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 +CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 -CFLAGS := $(filter-out -pg $(CFLAGS-GCOV),$(CFLAGS)) -CFLAGS += -DCR_NOGLIBC -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 -CFLAGS := $(filter-out $(CFLAGS-ASAN),$(CFLAGS)) PLUGIN_ARCH_DIR := compel/arch/$(ARCH)/plugins # From af572b3cf5776b1367436dd7e82d13bb51252ab1 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 24 Mar 2017 15:07:44 -0700 Subject: [PATCH 0434/4375] nmk: do not sort lib-y objects When performing static linking, the order of objects is important (when the linker finds an undefined reference, it looks forward, never back). Therefore, sorting objects breaks things. Required for the next patch. Cc: Cyrill Gorcunov Acked-by: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/build.mk | 2 +- scripts/nmk/scripts/utils.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nmk/scripts/build.mk b/scripts/nmk/scripts/build.mk index 907967cd7..cd49acea0 100644 --- a/scripts/nmk/scripts/build.mk +++ b/scripts/nmk/scripts/build.mk @@ -89,7 +89,7 @@ endif # # Prepare the unique entries. obj-y := $(sort $(call uniq,$(obj-y))) -lib-y := $(filter-out $(obj-y),$(sort $(call uniq,$(lib-y)))) +lib-y := $(filter-out $(obj-y),$(lib-y)) # # Add subdir path diff --git a/scripts/nmk/scripts/utils.mk b/scripts/nmk/scripts/utils.mk index bf841417c..1736ada90 100644 --- a/scripts/nmk/scripts/utils.mk +++ b/scripts/nmk/scripts/utils.mk @@ -16,7 +16,7 @@ uniq = $(strip $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1), # # Add $(obj)/ for paths that are not relative -objectify = $(foreach o,$(sort $(call uniq,$(1))),$(if $(filter /% ./% ../%,$(o)),$(o),$(obj)/$(o))) +objectify = $(foreach o,$(1),$(if $(filter /% ./% ../%,$(o)),$(o),$(obj)/$(o))) # To cleanup entries. cleanify = $(foreach o,$(sort $(call uniq,$(1))),$(o) $(o:.o=.d) $(o:.o=.i) $(o:.o=.s) $(o:.o=.gcda) $(o:.o=.gcno)) From 8b99809a4ea991b66b2fd7c3d92e3278be15a926 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 24 Mar 2017 15:07:45 -0700 Subject: [PATCH 0435/4375] compel: make plugins .a archives The objective is to only do parasite code linking once -- when we link parasite objects with compel plugin(s). So, let's use ar (rather than ld) here. This way we'll have a single ld invocation with the proper flags (from compel ldflags) etc. There are two tricks in doing it: 1. The order of objects while linking is important. Therefore, compel plugins should be the last to add to ld command line. 2. Somehow ld doesn't want to include parasite-head.o in the output (probably because no one else references it), so we have to force it in with the modification to our linker scripts. NB: compel makefiles are still a big mess, but I'll get there. Acked-by: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- Makefile.compel | 8 ++--- compel/arch/aarch64/scripts/compel-pack.lds.S | 4 +++ .../plugins/std/syscalls/Makefile.syscalls | 2 +- compel/arch/arm/scripts/compel-pack.lds.S | 4 +++ .../plugins/std/syscalls/Makefile.syscalls | 2 +- compel/arch/ppc64/scripts/compel-pack.lds.S | 4 +++ .../plugins/std/syscalls/Makefile.syscalls | 2 +- .../arch/x86/scripts/compel-pack-compat.lds.S | 4 +++ compel/arch/x86/scripts/compel-pack.lds.S | 4 +++ compel/plugins/Makefile | 30 +++++++++---------- compel/src/main.c | 8 +++-- 11 files changed, 47 insertions(+), 25 deletions(-) diff --git a/Makefile.compel b/Makefile.compel index 50124351d..1ef7f8cb2 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -22,7 +22,7 @@ compel-deps += compel/include/asm compel-deps += $(COMPEL_VERSION_HEADER) compel-deps += $(CONFIG_HEADER) compel-deps += include/common/asm -compel-plugins += compel/plugins/std.built-in.o compel/plugins/fds.built-in.o +compel-plugins += compel/plugins/std.lib.a compel/plugins/fds.lib.a LIBCOMPEL_SO := libcompel.so LIBCOMPEL_A := libcompel.a @@ -47,13 +47,13 @@ compel/plugins/%: $(compel-deps) .FORCE # GNU make 4.x supports targets matching via wide # match targeting, where GNU make 3.x series (used on # Travis) is not, so we have to write them here explicitly. -compel/plugins/std.built-in.o: $(compel-deps) .FORCE +compel/plugins/std.lib.a: $(compel-deps) .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ -compel/plugins/shmem.built-in.o: $(compel-deps) compel/plugins/std.built-in.o .FORCE +compel/plugins/shmem.lib.a: $(compel-deps) compel/plugins/std.lib.a .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ -compel/plugins/fds.built-in.o: $(compel-deps) compel/plugins/std.built-in.o .FORCE +compel/plugins/fds.lib.a: $(compel-deps) compel/plugins/std.lib.a .FORCE $(Q) $(MAKE) $(build)=compel/plugins $@ compel/compel: compel/built-in.o compel/$(LIBCOMPEL_A) | $(compel-deps) diff --git a/compel/arch/aarch64/scripts/compel-pack.lds.S b/compel/arch/aarch64/scripts/compel-pack.lds.S index b07e68c1d..eba89cd5f 100644 --- a/compel/arch/aarch64/scripts/compel-pack.lds.S +++ b/compel/arch/aarch64/scripts/compel-pack.lds.S @@ -1,8 +1,12 @@ OUTPUT_ARCH(aarch64) +EXTERN(__export_parasite_head_start) + SECTIONS { .crblob 0x0 : { *(.head.text) + ASSERT(DEFINED(__export_parasite_head_start), + "Symbol __export_parasite_head_start is missing"); *(.text*) . = ALIGN(32); *(.data*) diff --git a/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls b/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls index 6be8cacbd..5695b86b9 100644 --- a/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls +++ b/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls @@ -15,7 +15,7 @@ sys-gen := $(PLUGIN_ARCH_DIR)/std/syscalls/gen-syscalls.pl sys-gen-tbl := $(PLUGIN_ARCH_DIR)/std/syscalls/gen-sys-exec-tbl.pl sys-asm := ./$(PLUGIN_ARCH_DIR)/std/syscalls/syscalls.S -std-obj-y += $(sys-asm:.S=).o +std-lib-y += $(sys-asm:.S=).o ifeq ($(ARCH),arm) arch_bits := 32 diff --git a/compel/arch/arm/scripts/compel-pack.lds.S b/compel/arch/arm/scripts/compel-pack.lds.S index fe402787f..f8a4739f3 100644 --- a/compel/arch/arm/scripts/compel-pack.lds.S +++ b/compel/arch/arm/scripts/compel-pack.lds.S @@ -1,8 +1,12 @@ OUTPUT_ARCH(arm) +EXTERN(__export_parasite_head_start) + SECTIONS { .crblob 0x0 : { *(.head.text) + ASSERT(DEFINED(__export_parasite_head_start), + "Symbol __export_parasite_head_start is missing"); *(.text*) . = ALIGN(32); *(.data*) diff --git a/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls b/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls index 3a0d172ae..c0c22bfbe 100644 --- a/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls +++ b/compel/arch/ppc64/plugins/std/syscalls/Makefile.syscalls @@ -12,7 +12,7 @@ sys-asm-types := $(obj)/include/uapi/std/asm/syscall-types.h sys-exec-tbl = $(PLUGIN_ARCH_DIR)/std/sys-exec-tbl.c sys-asm := ./$(PLUGIN_ARCH_DIR)/std/syscalls/syscalls.S -std-obj-y += $(sys-asm:.S=).o +std-lib-y += $(sys-asm:.S=).o $(sys-codes): $(sys-def) $(E) " GEN " $@ diff --git a/compel/arch/ppc64/scripts/compel-pack.lds.S b/compel/arch/ppc64/scripts/compel-pack.lds.S index 5da9a0846..e0f826d7d 100644 --- a/compel/arch/ppc64/scripts/compel-pack.lds.S +++ b/compel/arch/ppc64/scripts/compel-pack.lds.S @@ -1,8 +1,12 @@ OUTPUT_ARCH(powerpc:common64) +EXTERN(__export_parasite_head_start) + SECTIONS { .text : { *(.head.text) + ASSERT(DEFINED(__export_parasite_head_start), + "Symbol __export_parasite_head_start is missing"); *(.text*) *(.compel.exit) *(.compel.init) diff --git a/compel/arch/x86/plugins/std/syscalls/Makefile.syscalls b/compel/arch/x86/plugins/std/syscalls/Makefile.syscalls index 522ee89fd..4ba4b56c8 100644 --- a/compel/arch/x86/plugins/std/syscalls/Makefile.syscalls +++ b/compel/arch/x86/plugins/std/syscalls/Makefile.syscalls @@ -1,4 +1,4 @@ -std-obj-y += ./$(PLUGIN_ARCH_DIR)/std/syscalls-64.o +std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/syscalls-64.o sys-proto-types := $(obj)/include/uapi/std/syscall-types.h sys-proto-generic := $(obj)/include/uapi/std/syscall.h diff --git a/compel/arch/x86/scripts/compel-pack-compat.lds.S b/compel/arch/x86/scripts/compel-pack-compat.lds.S index 67adf96a0..ff9c2c6b2 100644 --- a/compel/arch/x86/scripts/compel-pack-compat.lds.S +++ b/compel/arch/x86/scripts/compel-pack-compat.lds.S @@ -1,9 +1,13 @@ OUTPUT_ARCH(i386) TARGET(elf32-i386) +EXTERN(__export_parasite_head_start) + SECTIONS { .text : { *(.head.text) + ASSERT(DEFINED(__export_parasite_head_start), + "Symbol __export_parasite_head_start is missing"); *(.text*) *(.compel.exit) *(.compel.init) diff --git a/compel/arch/x86/scripts/compel-pack.lds.S b/compel/arch/x86/scripts/compel-pack.lds.S index cd6584ffe..0c936f84d 100644 --- a/compel/arch/x86/scripts/compel-pack.lds.S +++ b/compel/arch/x86/scripts/compel-pack.lds.S @@ -1,9 +1,13 @@ OUTPUT_ARCH(i386:x86-64) TARGET(elf64-x86-64) +EXTERN(__export_parasite_head_start) + SECTIONS { .text : { *(.head.text) + ASSERT(DEFINED(__export_parasite_head_start), + "Symbol __export_parasite_head_start is missing"); *(.text*) *(.compel.exit) *(.compel.init) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index e834a05dc..7127425af 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -34,30 +34,30 @@ ldflags-y += -z noexecstack # # Shmem plugin target += shmem -shmem-obj-y += shmem/shmem.o +shmem-lib-y += shmem/shmem.o # # STD plugin target += std -std-obj-y += std/std.o -std-obj-y += std/fds.o -std-obj-y += std/log.o -std-obj-y += std/string.o -std-obj-y += std/infect.o -std-obj-y += ./$(PLUGIN_ARCH_DIR)/std/parasite-head.o +std-lib-y += std/std.o +std-lib-y += std/fds.o +std-lib-y += std/log.o +std-lib-y += std/string.o +std-lib-y += std/infect.o +std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/parasite-head.o # # FDS plugin target += fds -fds-obj-y += fds/fds.o +fds-lib-y += fds/fds.o ifeq ($(SRCARCH),x86) - std-obj-y += ./$(PLUGIN_ARCH_DIR)/std/memcpy.o + std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/memcpy.o endif ifeq ($(SRCARCH),ppc64) - std-obj-y += ./$(PLUGIN_ARCH_DIR)/std/memcpy.o - std-obj-y += ./$(PLUGIN_ARCH_DIR)/std/memcmp.o + std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/memcpy.o + std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/memcmp.o endif include ./$(PLUGIN_ARCH_DIR)/std/syscalls/Makefile.syscalls @@ -73,15 +73,15 @@ endef # Almost all plugins depen on syscall headers # and definitions so we have to order their # generation manually. -$(foreach t,$(target),$(eval $(call syscall-priority,$(t)-obj-y,std-headers-deps))) +$(foreach t,$(target),$(eval $(call syscall-priority,$(t)-lib-y,std-headers-deps))) # # FIXME syscall-types.h should be setup earlier # -install: compel/plugins/std.built-in.o +install: compel/plugins/std.lib.a compel/plugins/fds.lib.a $(E) " INSTALL " compel plugins $(Q) mkdir -p $(DESTDIR)$(LIBEXECDIR)/compel/ - $(Q) install -m 0644 compel/plugins/std.built-in.o $(DESTDIR)$(LIBEXECDIR)/compel/ + $(Q) install -m 0644 $^ $(DESTDIR)$(LIBEXECDIR)/compel/ $(Q) mkdir -p $(DESTDIR)$(LIBEXECDIR)/compel/scripts $(Q) install -m 0644 compel/arch/$(ARCH)/scripts/compel-pack.lds.S $(DESTDIR)$(LIBEXECDIR)/compel/scripts $(E) " INSTALL " compel plugins uapi @@ -91,7 +91,7 @@ install: compel/plugins/std.built-in.o uninstall: $(E) " UNINSTALL" compel plugins - $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBEXECDIR)/compel/,std.built-in.o) + $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBEXECDIR)/compel/,*.lib.a) $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBEXECDIR)/compel/scripts/,compel-pack.lds.S) $(E) " UNINSTALL" compel and plugins uapi $(Q) $(RM) -rf $(addprefix $(DESTDIR)$(INCLUDEDIR)/,compel/plugins) diff --git a/compel/src/main.c b/compel/src/main.c index ea3da89a5..e0dcb09ae 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -186,12 +186,14 @@ static void print_ldflags(bool compat) static void print_plugins(const char *list[]) { + const char suffix[] = ".lib.a"; + while (*list != NULL) { if (uninst_root) - printf("%s/plugins/%s.built-in.o\n", - uninst_root, *list); + printf("%s/plugins/%s%s\n", + uninst_root, *list, suffix); else - printf("%s/compel/%s.built-in.o\n", LIBEXECDIR, *list); + printf("%s/compel/%s%s\n", LIBEXECDIR, *list, suffix); list++; } } From f62818d9adaa240554311afc5575547c40d1b04d Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 24 Mar 2017 15:07:46 -0700 Subject: [PATCH 0436/4375] compel: no -r for ARM ldflags Commit d9486bd720 ("arm/pie/build: do not produce relocatable parasite object") removed -r from LDFLAGS used to compile criu pie. This functionality somehow never made it to criu-dev, and was also lost in master then compel was ported to it. Make it work with compel. Unfortunately it was not as simple as I initially thought, as -r flag to ld was built into nmk. This patch removes it, and adds it to all places that need intermediate linking. Cc: Dmitry Safonov Cc: Cyrill Gorcunov Acked-by: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/Makefile | 1 + compel/src/main.c | 4 ++++ criu/Makefile.crtools | 1 + criu/arch/aarch64/Makefile | 1 + criu/arch/arm/Makefile | 1 + criu/arch/ppc64/Makefile | 1 + criu/arch/x86/Makefile | 2 +- lib/c/Makefile | 2 +- scripts/nmk/scripts/build.mk | 2 +- 9 files changed, 12 insertions(+), 3 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index fee12121b..43d27f55d 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -11,6 +11,7 @@ ccflags-y += -iquote compel/arch/$(ARCH)/src/lib/include ccflags-y += -iquote compel/include ccflags-y += -fno-strict-aliasing ccflags-y += -fPIC +ldflags-y += -r # # UAPI inclusion, referred as diff --git a/compel/src/main.c b/compel/src/main.c index e0dcb09ae..4584ef915 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -26,7 +26,11 @@ #define COMPEL_CFLAGS_PIE CFLAGS_DEFAULT_SET "-fpie" #define COMPEL_CFLAGS_NOPIC CFLAGS_DEFAULT_SET "-fno-pic" +#ifdef NO_RELOCS +#define COMPEL_LDFLAGS_COMMON "-z noexecstack -T " +#else #define COMPEL_LDFLAGS_COMMON "-r -z noexecstack -T " +#endif typedef struct { const char *arch; // dir name under arch/ diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index c6b202108..51573cd43 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -1,6 +1,7 @@ ccflags-y += -iquote criu/$(ARCH) ccflags-y += $(COMPEL_UAPI_INCLUDES) CFLAGS_REMOVE_clone-noasan.o += $(CFLAGS-ASAN) +ldflags-y += -r obj-y += action-scripts.o obj-y += external.o diff --git a/criu/arch/aarch64/Makefile b/criu/arch/aarch64/Makefile index 0dc635096..49ef6a480 100644 --- a/criu/arch/aarch64/Makefile +++ b/criu/arch/aarch64/Makefile @@ -4,6 +4,7 @@ ccflags-y += -iquote $(obj)/include -iquote criu/include ccflags-y += -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) asflags-y += -D__ASSEMBLY__ +ldflags-y += -r obj-y += cpu.o obj-y += crtools.o diff --git a/criu/arch/arm/Makefile b/criu/arch/arm/Makefile index 1b0bc56cb..d79ab6238 100644 --- a/criu/arch/arm/Makefile +++ b/criu/arch/arm/Makefile @@ -5,6 +5,7 @@ ccflags-y += -iquote criu/include -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) asflags-y += -D__ASSEMBLY__ +ldflags-y += -r obj-y += cpu.o obj-y += crtools.o diff --git a/criu/arch/ppc64/Makefile b/criu/arch/ppc64/Makefile index 8148dc943..ff0a71207 100644 --- a/criu/arch/ppc64/Makefile +++ b/criu/arch/ppc64/Makefile @@ -3,6 +3,7 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj)/include ccflags-y += -iquote criu/include -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) +ldflags-y += -r obj-y += cpu.o obj-y += crtools.o diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index 9ff59942a..669dc073a 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -7,7 +7,7 @@ ccflags-y += $(COMPEL_UAPI_INCLUDES) asflags-y += -Wstrict-prototypes asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer asflags-y += -iquote $(obj)/include -ldflags-y += -z noexecstack +ldflags-y += -r -z noexecstack obj-y += cpu.o obj-y += crtools.o diff --git a/lib/c/Makefile b/lib/c/Makefile index 79a8e69a6..af01467d7 100644 --- a/lib/c/Makefile +++ b/lib/c/Makefile @@ -5,4 +5,4 @@ ccflags-y += -iquote criu/$(ARCH_DIR)/include ccflags-y += -iquote criu/include ccflags-y += -iquote images ccflags-y += -fPIC -fno-stack-protector -ldflags-y += -z noexecstack +ldflags-y += -r -z noexecstack diff --git a/scripts/nmk/scripts/build.mk b/scripts/nmk/scripts/build.mk index cd49acea0..a6bd47d52 100644 --- a/scripts/nmk/scripts/build.mk +++ b/scripts/nmk/scripts/build.mk @@ -142,7 +142,7 @@ endif define gen-ld-target-rule $(1): $(3) $$(call msg-link, $$@) - $$(Q) $$(LD) $(2) -r -o $$@ $(4) + $$(Q) $$(LD) $(2) -o $$@ $(4) endef define gen-ar-target-rule From e2c64a942c43c38551e104b8f4f1f9826d217314 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 26 Mar 2017 02:21:42 +0300 Subject: [PATCH 0437/4375] zdtm/static/autofs: stop children before c/r A static test has to be stopped, because zdtm.py compares file descriptors before and after c/r. Signed-off-by: Andrei Vagin --- test/zdtm/static/autofs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/zdtm/static/autofs.c b/test/zdtm/static/autofs.c index 1238e67d4..1644a6e10 100644 --- a/test/zdtm/static/autofs.c +++ b/test/zdtm/static/autofs.c @@ -34,6 +34,7 @@ TEST_OPTION(dirname, string, "directory name", 1); #define INDIRECT_MNT_DIR "mnt" int autofs_dev; +task_waiter_t t; static char *xvstrcat(char *str, const char *fmt, va_list args) { @@ -568,6 +569,7 @@ static int automountd(struct autofs_params *p, int control_fd) goto err; } close(control_fd); + task_waiter_complete(&t, getpid()); return automountd_loop(pipes[0], autofs_path, p); err: @@ -599,6 +601,7 @@ static int start_automounter(struct autofs_params *p) close(control_fd[0]); exit(automountd(p, control_fd[1])); } + task_waiter_wait4(&t, pid); p->pid = pid; close(control_fd[1]); @@ -877,6 +880,8 @@ int main(int argc, char **argv) test_init(argc, argv); + task_waiter_init(&t); + if (mkdir(dirname, 0777) < 0) { pr_perror("failed to create %s directory", dirname); return -1; From 61a3156e878b81a7a47d0fa2b0a2439c42325d64 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 28 Mar 2017 18:55:44 +0300 Subject: [PATCH 0438/4375] unix: Do pr_perror() before cleanup revert_unix_sk_cwd() may rewrite errno, so call pr_perror() firstly. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 4ab42f8df..c7441e588 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -956,8 +956,8 @@ static int post_open_unix_sk(struct file_desc *d, int fd) if (connect(fd, (struct sockaddr *)&addr, sizeof(addr.sun_family) + peer->ue->name.len) < 0) { - revert_unix_sk_cwd(&cwd_fd, &root_fd); pr_perror("Can't connect %#x socket", ui->ue->ino); + revert_unix_sk_cwd(&cwd_fd, &root_fd); return -1; } From bc93f12abdd7e72d48930a69433246c843b90215 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 29 Mar 2017 13:15:57 -0700 Subject: [PATCH 0439/4375] compel hgen: fix for 32-bit ARM Since commit 93db22b ("compel: no -r for ARM ldflags") and commit ce043d3 ("compel: make plugins .a archives") the generated parasite/restorer blobs for 32-bit ARM are no longer relocatable, and so their ELF header has e_type of ET_EXEC (rather than ET_REL). As a result, we have "Unsupported header detected" message and a failure from compel hgen. This commit allows e_type == ET_EXEC in case NO_RELOCS is defined. I am not sure if it's OK to still allow ET_REL -- maybe Dmitry can chime in on that. Cc: Dmitry Safonov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/src/lib/handle-elf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index 4b8b73dfa..41633e99c 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -86,7 +86,11 @@ static bool is_header_supported(Elf_Ehdr *hdr) { if (!arch_is_machine_supported(hdr->e_machine)) return false; - if (hdr->e_type != ET_REL || hdr->e_version != EV_CURRENT) + if ((hdr->e_type != ET_REL +#ifdef NO_RELOCS + && hdr->e_type != ET_EXEC +#endif + ) || hdr->e_version != EV_CURRENT) return false; return true; } From e4000c59a716f511644a9719a703610c54ebed92 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 29 Mar 2017 13:15:58 -0700 Subject: [PATCH 0440/4375] Dockerfiles: don't ignore make failures Commit 299e4b4 ("travis: enable ccache for docker/qemu builds") combined multiple RUN statements in Dockerfiles into a single one, which is good for performance (as there is an intermediate cache created after each statement). Unfortunately, it partially did so by combining statements with use of semicolons, meaning we are ignoring non-zero exit codes. As a result, failure from make are ignored and Travis builds are all green. To fix, replace all occurences of semicolon with &&. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.alpine | 4 ++-- scripts/build/Dockerfile.tmpl | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index 26c39ac25..1c4684922 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -20,8 +20,8 @@ RUN apk update && apk add \ COPY . /criu WORKDIR /criu ENV CC="ccache $CC" CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes -RUN mv .ccache /tmp; make mrproper; ccache -s; \ - date; make -j $(nproc) CC="$CC"; date +RUN mv .ccache /tmp && make mrproper && ccache -s && \ + date && make -j $(nproc) CC="$CC" && date # Run a test RUN apk add py-yaml \ diff --git a/scripts/build/Dockerfile.tmpl b/scripts/build/Dockerfile.tmpl index 60e0e4591..ec0242965 100644 --- a/scripts/build/Dockerfile.tmpl +++ b/scripts/build/Dockerfile.tmpl @@ -24,18 +24,18 @@ COPY . /criu WORKDIR /criu ENV CC="ccache $CC" CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes -RUN mv .ccache /tmp && make mrproper; ccache -s; \ - date; \ +RUN mv .ccache /tmp && make mrproper && ccache -s && \ + date && \ # Check single object build - make -j $(nproc) CC="$CC" criu/parasite-syscall.o; \ + make -j $(nproc) CC="$CC" criu/parasite-syscall.o && \ # Compile criu - make -j $(nproc) CC="$CC"; \ - date; \ + make -j $(nproc) CC="$CC" && \ + date && \ # Check that "make mrproper" works make mrproper && ! git clean -ndx --exclude=scripts/build \ --exclude=.config --exclude=test | grep . # Compile tests -RUN date; make -j $(nproc) CC="$CC" -C test/zdtm; date +RUN date && make -j $(nproc) CC="$CC" -C test/zdtm && date #RUN make test/compel/handle_binary && ./test/compel/handle_binary From 04db53367b2cf2e024e159e3c60cf3aa45044436 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 29 Mar 2017 15:21:12 -0700 Subject: [PATCH 0441/4375] test/zdtm/lib/Makefile: fix When optimizing our Travis runs, I noticed that test/zdtm/lib is built 3 times in a row -- first time the binaries, 2nd and 3rd time the deps, in parallel (sic!). I took a look at Makefile and found this, and some more problems, like: - dependencies are generated but not included - cleandep does not depend on clean - groups.c dependencies are not generated (or used) - "make all" does not make groups binary - overcomplicated and unused groups.{pid,out,cleanout} targets - extra -f flag to rm - etc. This patch (hopefully) fixes all of the above. In addition, it provides a few enhancements: - enables "silent make" rules, so now lib/ is in line with the rest of zdtm - adds "dep" target (not used, just for convenience) Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/lib/Makefile | 72 +++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/test/zdtm/lib/Makefile b/test/zdtm/lib/Makefile index 592d934d2..6b37e0ddd 100644 --- a/test/zdtm/lib/Makefile +++ b/test/zdtm/lib/Makefile @@ -1,52 +1,60 @@ +MAKEFLAGS += -r +LIBDIR := . include ../Makefile.inc -CFLAGS = -g -O2 -Wall -Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 +CFLAGS := -g -O2 -Wall -Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS += $(USERCFLAGS) -LIBDIR = . -LIB = libzdtmtst.a -GRPS = groups +LIB := libzdtmtst.a -LIBSRC = datagen.c msg.c parseargs.c test.c streamutil.c lock.c ns.c tcp.c fs.c -LIBOBJ = $(LIBSRC:%.c=%.o) -LIBDEP = $(LIBSRC:%.c=%.d) +LIBSRC := datagen.c msg.c parseargs.c test.c streamutil.c lock.c ns.c tcp.c fs.c +LIBOBJ := $(LIBSRC:%.c=%.o) + +BIN := groups +SRC := $(LIBSRC) groups.c +DEP := $(SRC:%.c=%.d) +OBJ := $(SRC:%.c=%.o) +LDLIBS := $(LIB) + +TARGETS := $(LIB) $(BIN) + +all: $(TARGETS) +.PHONY: all DEPEND.c = $(COMPILE.c) -MM -MP -%.d: %.c - $(DEPEND.c) $(OUTPUT_OPTION) $< +%.d: %.c + $(E) " DEP " $*.d + $(Q)$(DEPEND.c) $(OUTPUT_OPTION) $< -all: $(LIB) - @true -install: all -.PHONY: all install +%.o: %.c | %.d + $(E) " CC " $@ + $(Q)$(COMPILE.c) $(OUTPUT_OPTION) $< + +%: %.o $(LDLIBS) + $(E) " LINK " $@ + $(Q)$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ $(LIB): $(LIBOBJ) - $(Q) ar rv $@ $^ + $(E) " AR " $@ + $(Q)ar rcs $@ $^ + +dep: $(DEP) +.PHONY: dep clean: - $(RM) -f $(LIBOBJ) $(LIB) *~ + $(RM) $(OBJ) $(TARGETS) -cleandep: - $(RM) -f $(LIBDEP) +cleandep: clean + $(RM) $(DEP) -cleanout: - @true - -$(GRPS): $(LIB) - -$(GRPS:%=%.pid): $(GRPS) - $( Date: Wed, 29 Mar 2017 15:21:13 -0700 Subject: [PATCH 0442/4375] test/zdtm/Makefile: simplify Brevity is the soul of wit. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/Makefile | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/test/zdtm/Makefile b/test/zdtm/Makefile index 8abf2144d..24a33f2a6 100644 --- a/test/zdtm/Makefile +++ b/test/zdtm/Makefile @@ -1,18 +1,13 @@ -SUBDIRS = lib static transition +SUBDIRS := lib static transition -default: all -.PHONY: default lib static transition +all: $(SUBDIRS) +.PHONY: all $(SUBDIRS) -lib: - $(MAKE) -C lib all +$(SUBDIRS): + $(MAKE) -C $@ all static: lib - $(MAKE) -C static all - transition: lib - $(MAKE) -C transition all -all: lib static transition - @true %: set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done From 4dcceffe43afabdecf431220745dce72cee39d46 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 29 Mar 2017 15:21:14 -0700 Subject: [PATCH 0443/4375] test/zdtm Makefile: stop override abuse In GNU make, 'override' means change a variable even if it was set from the make command line (as in "make VAR=value"). As we do not intend to modify CFLAGS/LDFLAGS from the command line, 'override' can be dropped. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 126 +++++++++++++++++----------------- test/zdtm/transition/Makefile | 18 ++--- 2 files changed, 73 insertions(+), 71 deletions(-) diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 785d303f4..cb9478dbc 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -4,7 +4,7 @@ include ../Makefile.inc LIBDIR = ../lib LIB = $(LIBDIR)/libzdtmtst.a LDLIBS += $(LIBDIR)/libzdtmtst.a -override CPPFLAGS += -I$(LIBDIR) +CPPFLAGS += -I$(LIBDIR) CFLAGS = -g -O2 -Wall -Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS += $(USERCFLAGS) @@ -399,69 +399,71 @@ wait_stop: $(TST): | $(LIB) -aio00: override LDLIBS += -laio -different_creds: override LDLIBS += -lcap -futex.o: override CFLAGS += -pthread -futex: override LDFLAGS += -pthread -futex-rl.o: override CFLAGS += -pthread -futex-rl: override LDFLAGS += -pthread -jobctl00: override LDLIBS += -lutil -socket_listen: override LDLIBS += -lrt -pthread -socket_aio: override LDLIBS += -lrt -pthread -uptime_grow: override LDLIBS += -lrt -pthread -unlink_largefile: override CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -inotify_system_nodel: override CFLAGS += -DNODEL -pthread00: override LDLIBS += -pthread -pthread01: override LDLIBS += -pthread -pthread02: override LDLIBS += -pthread -different_creds: override LDLIBS += -pthread -sigpending: override LDLIBS += -pthread -sigaltstack: override LDLIBS += -pthread -seccomp_filter_tsync: override LDLIBS += -pthread -shm: override CFLAGS += -DNEW_IPC_NS -msgque: override CFLAGS += -DNEW_IPC_NS -sem: override CFLAGS += -DNEW_IPC_NS -posix_timers: override LDLIBS += -lrt -pthread -remap_dead_pid_root: override CFLAGS += -DREMAP_PID_ROOT -socket-tcp6: override CFLAGS += -D ZDTM_IPV6 -socket-tcpbuf6: override CFLAGS += -D ZDTM_IPV6 -socket-tcpbuf-local: override CFLAGS += -D ZDTM_TCP_LOCAL -socket-tcpbuf6-local: override CFLAGS += -D ZDTM_TCP_LOCAL -D ZDTM_IPV6 -socket-tcp6-local: override CFLAGS += -D ZDTM_TCP_LOCAL -D ZDTM_IPV6 -socket-tcp-local: override CFLAGS += -D ZDTM_TCP_LOCAL -socket-tcp-nfconntrack: override CFLAGS += -D ZDTM_TCP_LOCAL -DZDTM_CONNTRACK -socket_listen6: override CFLAGS += -D ZDTM_IPV6 -socket-tcp6-closed: override CFLAGS += -D ZDTM_IPV6 -socket-tcp-closed-last-ack: override CFLAGS += -D ZDTM_TCP_LAST_ACK -mnt_ext_manual: override CFLAGS += -D ZDTM_EXTMAP_MANUAL -sigpending: override LDLIBS += -lrt -vdso01: override LDLIBS += -lrt -mntns_link_remap: override CFLAGS += -DZDTM_LINK_REMAP -mntns_shared_bind02: override CFLAGS += -DSHARED_BIND02 -mntns_root_bind02: override CFLAGS += -DROOT_BIND02 -maps02: get_smaps_bits.o -mlock_setuid: get_smaps_bits.o -inotify01: override CFLAGS += -DINOTIFY01 -unlink_fstat01+: override CFLAGS += -DUNLINK_OVER -unlink_fstat04: override CFLAGS += -DUNLINK_FSTAT04 -sk-freebind-false: override CFLAGS += -DZDTM_FREEBIND_FALSE -stopped01: override CFLAGS += -DZDTM_STOPPED_KILL -stopped02: override CFLAGS += -DZDTM_STOPPED_TKILL -stopped12: override CFLAGS += -DZDTM_STOPPED_KILL -DZDTM_STOPPED_TKILL -clone_fs: override LDLIBS += -pthread +aio00: LDLIBS += -laio +different_creds: LDLIBS += -lcap +futex.o: CFLAGS += -pthread +futex: LDFLAGS += -pthread +futex-rl.o: CFLAGS += -pthread +futex-rl: LDFLAGS += -pthread +jobctl00: LDLIBS += -lutil +socket_listen: LDLIBS += -lrt -pthread +socket_aio: LDLIBS += -lrt -pthread +uptime_grow: LDLIBS += -lrt -pthread +unlink_largefile: CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE +inotify_system_nodel: CFLAGS += -DNODEL +pthread00: LDLIBS += -pthread +pthread01: LDLIBS += -pthread +pthread02: LDLIBS += -pthread +different_creds: LDLIBS += -pthread +sigpending: LDLIBS += -pthread +sigaltstack: LDLIBS += -pthread +seccomp_filter_tsync: LDLIBS += -pthread +shm: CFLAGS += -DNEW_IPC_NS +msgque: CFLAGS += -DNEW_IPC_NS +sem: CFLAGS += -DNEW_IPC_NS +posix_timers: LDLIBS += -lrt -pthread +remap_dead_pid_root: CFLAGS += -DREMAP_PID_ROOT +socket-tcp6: CFLAGS += -D ZDTM_IPV6 +socket-tcpbuf6: CFLAGS += -D ZDTM_IPV6 +socket-tcpbuf-local: CFLAGS += -D ZDTM_TCP_LOCAL +socket-tcpbuf6-local: CFLAGS += -D ZDTM_TCP_LOCAL -D ZDTM_IPV6 +socket-tcp6-local: CFLAGS += -D ZDTM_TCP_LOCAL -D ZDTM_IPV6 +socket-tcp-local: CFLAGS += -D ZDTM_TCP_LOCAL +socket-tcp-nfconntrack: CFLAGS += -D ZDTM_TCP_LOCAL -DZDTM_CONNTRACK +socket_listen6: CFLAGS += -D ZDTM_IPV6 +socket-tcp6-closed: CFLAGS += -D ZDTM_IPV6 +socket-tcp-closed-last-ack: CFLAGS += -D ZDTM_TCP_LAST_ACK +mnt_ext_manual: CFLAGS += -D ZDTM_EXTMAP_MANUAL +sigpending: LDLIBS += -lrt +vdso01: LDLIBS += -lrt +mntns_link_remap: CFLAGS += -DZDTM_LINK_REMAP +mntns_shared_bind02: CFLAGS += -DSHARED_BIND02 +mntns_root_bind02: CFLAGS += -DROOT_BIND02 +maps02: get_smaps_bits.o +mlock_setuid: get_smaps_bits.o +inotify01: CFLAGS += -DINOTIFY01 +unlink_fstat01+: CFLAGS += -DUNLINK_OVER +unlink_fstat04: CFLAGS += -DUNLINK_FSTAT04 +sk-freebind-false: CFLAGS += -DZDTM_FREEBIND_FALSE +stopped01: CFLAGS += -DZDTM_STOPPED_KILL +stopped02: CFLAGS += -DZDTM_STOPPED_TKILL +stopped12: CFLAGS += -DZDTM_STOPPED_KILL -DZDTM_STOPPED_TKILL +clone_fs: LDLIBS += -pthread +netns_sub_veth: CFLAGS += -I/usr/include/libnl3 +netns_sub_veth: LDLIBS += -lnl-3 -l nl-route-3 -socket-tcp-fin-wait1: override CFLAGS += -D ZDTM_TCP_FIN_WAIT1 -socket-tcp-fin-wait2: override CFLAGS += -D ZDTM_TCP_FIN_WAIT2 -socket-tcp6-fin-wait1: override CFLAGS += -D ZDTM_TCP_FIN_WAIT1 -D ZDTM_IPV6 -socket-tcp6-fin-wait2: override CFLAGS += -D ZDTM_TCP_FIN_WAIT2 -D ZDTM_IPV6 -socket-tcp-close-wait: override CFLAGS += -D ZDTM_TCP_CLOSE_WAIT -socket-tcp6-close-wait: override CFLAGS += -D ZDTM_TCP_CLOSE_WAIT -D ZDTM_IPV6 -socket-tcp-last-ack: override CFLAGS += -D ZDTM_TCP_LAST_ACK -socket-tcp6-last-ack: override CFLAGS += -D ZDTM_TCP_LAST_ACK -D ZDTM_IPV6 -socket-tcp6-closing: override CFLAGS += -D ZDTM_IPV6 -socket-tcp6-unconn: override CFLAGS += -D ZDTM_IPV6 +socket-tcp-fin-wait1: CFLAGS += -D ZDTM_TCP_FIN_WAIT1 +socket-tcp-fin-wait2: CFLAGS += -D ZDTM_TCP_FIN_WAIT2 +socket-tcp6-fin-wait1: CFLAGS += -D ZDTM_TCP_FIN_WAIT1 -D ZDTM_IPV6 +socket-tcp6-fin-wait2: CFLAGS += -D ZDTM_TCP_FIN_WAIT2 -D ZDTM_IPV6 +socket-tcp-close-wait: CFLAGS += -D ZDTM_TCP_CLOSE_WAIT +socket-tcp6-close-wait: CFLAGS += -D ZDTM_TCP_CLOSE_WAIT -D ZDTM_IPV6 +socket-tcp-last-ack: CFLAGS += -D ZDTM_TCP_LAST_ACK +socket-tcp6-last-ack: CFLAGS += -D ZDTM_TCP_LAST_ACK -D ZDTM_IPV6 +socket-tcp6-closing: CFLAGS += -D ZDTM_IPV6 +socket-tcp6-unconn: CFLAGS += -D ZDTM_IPV6 -pty-console: override CFLAGS += -D ZDTM_DEV_CONSOLE +pty-console: CFLAGS += -D ZDTM_DEV_CONSOLE $(LIB): force $(Q) $(MAKE) -C $(LIBDIR) diff --git a/test/zdtm/transition/Makefile b/test/zdtm/transition/Makefile index 4466333c7..d5efe5fad 100644 --- a/test/zdtm/transition/Makefile +++ b/test/zdtm/transition/Makefile @@ -4,7 +4,7 @@ include ../Makefile.inc LIBDIR = ../lib LIB = $(LIBDIR)/libzdtmtst.a LDLIBS += $(LIBDIR)/libzdtmtst.a -override CPPFLAGS += -I$(LIBDIR) +CPPFLAGS += -I$(LIBDIR) CFLAGS = -g -O2 -Wall -Werror -fno-strict-aliasing CFLAGS += $(USERCFLAGS) @@ -83,14 +83,14 @@ wait_stop: $(TST): | $(LIB) -file_aio: override LDLIBS += -lrt -pthread -socket-tcp: override CFLAGS += -D STREAM -socket-tcp6: override CFLAGS += -D ZDTM_IPV6 -D STREAM -ptrace.o: override CFLAGS += -pthread -ptrace: override LDFLAGS += -pthread -fork2: override CFLAGS += -D FORK2 -thread-bomb.o: override CFLAGS += -pthread -thread-bomb: override LDFLAGS += -pthread +file_aio: LDLIBS += -lrt -pthread +socket-tcp: CFLAGS += -D STREAM +socket-tcp6: CFLAGS += -D ZDTM_IPV6 -D STREAM +ptrace.o: CFLAGS += -pthread +ptrace: LDFLAGS += -pthread +fork2: CFLAGS += -D FORK2 +thread-bomb.o: CFLAGS += -pthread +thread-bomb: LDFLAGS += -pthread %: %.sh cp $< $@ From 50d799116820e41ec410eb0d565fd37f6a89fd59 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 29 Mar 2017 15:21:15 -0700 Subject: [PATCH 0444/4375] test/zdtm: unify common code This commit expands the success with lib/Makefile to the rest of ztdm/Makefiles. In particular, it moves the common part to Makefile.inc and let {lib,static,transition}/Makefile use it. This results in: - dependencies being handled properly; - reduction of makefiles length due to unification; - possibly more proper dependencies and builds. While at it, let's also: - make rules for criu-rtc.so silent; - set default CC=gcc; - remove duplicate -m32 from CFLAGS. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/.gitignore | 1 + test/zdtm/Makefile.inc | 56 +++++++++++++++++++++++++++++++++-- test/zdtm/lib/Makefile | 42 ++++---------------------- test/zdtm/static/Makefile | 53 ++++++++++----------------------- test/zdtm/transition/Makefile | 40 ++++--------------------- 5 files changed, 82 insertions(+), 110 deletions(-) diff --git a/test/zdtm/.gitignore b/test/zdtm/.gitignore index 5817013cc..64719439e 100644 --- a/test/zdtm/.gitignore +++ b/test/zdtm/.gitignore @@ -1,4 +1,5 @@ /lib/libzdtmtst.a +/lib/.gitignore /static/.gitignore /transition/.gitignore diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index ef7c1b81a..c7b40e763 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -1,3 +1,5 @@ +MAKEFLAGS += -r + ARCH ?= $(shell uname -m | sed \ -e s/i.86/x86/ \ -e s/x86_64/x86/ \ @@ -18,6 +20,9 @@ endif SRCARCH ?= $(ARCH) +CC := gcc +CFLAGS += -g -O2 -Wall -Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 +CFLAGS += $(USERCFLAGS) CPPFLAGS += -iquote $(LIBDIR)/arch/$(SRCARCH)/include ifeq ($(strip $(V)),) @@ -32,10 +37,57 @@ RM := rm -f --one-file-system ifeq ($(COMPAT_TEST),y) ifeq ($(ARCH),x86) - export USERCFLAGS += -m32 export CFLAGS += -m32 export LDFLAGS += -m32 endif endif -export E Q RM +DEPEND.c = $(COMPILE.c) -MM -MP +%.d: %.c + $(E) " DEP " $*.d + $(Q)$(DEPEND.c) $(OUTPUT_OPTION) $< + +%.o: %.c | %.d + $(E) " CC " $@ + $(Q)$(COMPILE.c) $(OUTPUT_OPTION) $< + +%: %.o $(LDLIBS) + @echo $@ >> .gitignore + $(E) " LINK " $@ + $(Q)$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +default: all +.PHONY: default + +gitignore-clean: + $(RM) .gitignore +.PHONY: gitignore-clean + +clean: gitignore-clean + $(RM) $(OBJ) $(TST) *~ +.PHONY: clean + +cleandep: clean + $(RM) $(DEP) +.PHONY: cleandep + +cleanout: + $(RM) -r *.pid *.out* *.test* *.state +.PHONY: cleanout + +%.cleanout: % + $(Q) $(RM) -r $<.pid* $<.out* *$<.test* $<.*.test $<.*.state $<.state chew_$<.test* + +realclean: cleandep cleanout +.PHONY: realclean + +dep: $(DEP) +.PHONY: dep + +no-deps-targets := clean cleandep cleanout realclean groups.cleanout + +ifeq ($(filter $(no-deps-targets), $(MAKECMDGOALS)),) +-include $(DEP) +endif + +.SECONDARY: diff --git a/test/zdtm/lib/Makefile b/test/zdtm/lib/Makefile index 6b37e0ddd..d2d9f1cc3 100644 --- a/test/zdtm/lib/Makefile +++ b/test/zdtm/lib/Makefile @@ -1,8 +1,5 @@ -MAKEFLAGS += -r LIBDIR := . -include ../Makefile.inc -CFLAGS := -g -O2 -Wall -Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS += $(USERCFLAGS) LIB := libzdtmtst.a @@ -18,43 +15,16 @@ LDLIBS := $(LIB) TARGETS := $(LIB) $(BIN) +include ../Makefile.inc + all: $(TARGETS) .PHONY: all -DEPEND.c = $(COMPILE.c) -MM -MP -%.d: %.c - $(E) " DEP " $*.d - $(Q)$(DEPEND.c) $(OUTPUT_OPTION) $< - -%.o: %.c | %.d - $(E) " CC " $@ - $(Q)$(COMPILE.c) $(OUTPUT_OPTION) $< - -%: %.o $(LDLIBS) - $(E) " LINK " $@ - $(Q)$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ +clean-more: + $(RM) $(TARGETS) +.PHONY: clean-more +clean: clean-more $(LIB): $(LIBOBJ) $(E) " AR " $@ $(Q)ar rcs $@ $^ - -dep: $(DEP) -.PHONY: dep - -clean: - $(RM) $(OBJ) $(TARGETS) - -cleandep: clean - $(RM) $(DEP) - -cleanout: clean ; - -realclean: clean cleandep - -.PHONY: clean cleandep cleanout realclean - -no-deps-targets := clean cleandep cleanout realclean - -ifeq ($(filter $(no-deps-targets), $(MAKECMDGOALS)),) --include $(DEP) -endif diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index cb9478dbc..92ea9c394 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -1,12 +1,7 @@ -include ../Makefile.inc -.SUFFIXES: # No implicit rules - -LIBDIR = ../lib -LIB = $(LIBDIR)/libzdtmtst.a -LDLIBS += $(LIBDIR)/libzdtmtst.a +LIBDIR := ../lib +LIB := $(LIBDIR)/libzdtmtst.a +LDLIBS += $(LIB) CPPFLAGS += -I$(LIBDIR) -CFLAGS = -g -O2 -Wall -Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -CFLAGS += $(USERCFLAGS) TST_NOFILE := \ busyloop00 \ @@ -314,15 +309,7 @@ OUT = $(TST:%=%.out) STATE = $(TST_STATE:%=%.state) STATE_OUT = $(TST_STATE:%=%.out) -%.o: %.c - @echo $@ >> .gitignore - $(E) " CC " $@ - $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< - -%: %.o - @echo $@ >> .gitignore - $(E) " LINK " $@ - $(Q)$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ +include ../Makefile.inc all: $(TST) criu-rtc.so install: all @@ -449,7 +436,9 @@ stopped01: CFLAGS += -DZDTM_STOPPED_KILL stopped02: CFLAGS += -DZDTM_STOPPED_TKILL stopped12: CFLAGS += -DZDTM_STOPPED_KILL -DZDTM_STOPPED_TKILL clone_fs: LDLIBS += -pthread -netns_sub_veth: CFLAGS += -I/usr/include/libnl3 +# As generating dependencies won't work without proper includes, +# we have to explicitly specify both .o and .d for this case: +netns_sub_veth.o netns_sub_veth.d: CPPFLAGS += -I/usr/include/libnl3 netns_sub_veth: LDLIBS += -lnl-3 -l nl-route-3 socket-tcp-fin-wait1: CFLAGS += -D ZDTM_TCP_FIN_WAIT1 @@ -468,31 +457,21 @@ pty-console: CFLAGS += -D ZDTM_DEV_CONSOLE $(LIB): force $(Q) $(MAKE) -C $(LIBDIR) -gitignore-clean: - $(RM) -f .gitignore - -clean: gitignore-clean - $(RM) -f $(OBJ) $(TST) *~ criu-rtc.so criu-rtc.pb-c.c criu-rtc.pb-c.h get_smaps_bits.o - -cleandep: clean - $(RM) -f $(DEP) - -cleanout: - $(RM) -f -r *.pid *.out* *.test* *.state - -%.cleanout: % - $(Q) $(RM) -f -r $<.pid* $<.out* *$<.test* $<.*.test $<.*.state $<.state - -realclean: cleandep cleanout +clean-more: + $(RM) criu-rtc.so criu-rtc.pb-c.c criu-rtc.pb-c.h get_smaps_bits.o +.PHONY: clean-more +clean: clean-more rtc.c: criu-rtc.so criu-rtc.pb-c.c: criu-rtc.proto $(Q)echo $@ >> .gitignore $(Q)echo $(@:%.c=%.h) >> .gitignore - protoc-c --proto_path=. --c_out=. criu-rtc.proto + $(E) " PBCC " $@ + $(Q)protoc-c --proto_path=. --c_out=. criu-rtc.proto criu-rtc.so: criu-rtc.c criu-rtc.pb-c.c - $(CC) -g -Wall -shared -nostartfiles criu-rtc.c criu-rtc.pb-c.c -o criu-rtc.so -iquote ../../../criu/include -fPIC $(filter-out -m32,$(USERCFLAGS)) + $(E) " LD " $@ + $(Q)$(CC) -g -Wall -shared -nostartfiles criu-rtc.c criu-rtc.pb-c.c -o criu-rtc.so -iquote ../../../criu/include -fPIC $(filter-out -m32,$(USERCFLAGS)) -.PHONY: force clean cleandep cleanout realclean start check_start stop wait_stop +.PHONY: force start check_start stop wait_stop diff --git a/test/zdtm/transition/Makefile b/test/zdtm/transition/Makefile index d5efe5fad..cd9892159 100644 --- a/test/zdtm/transition/Makefile +++ b/test/zdtm/transition/Makefile @@ -1,12 +1,7 @@ -include ../Makefile.inc -.SUFFIXES: # No implicit rules - -LIBDIR = ../lib -LIB = $(LIBDIR)/libzdtmtst.a -LDLIBS += $(LIBDIR)/libzdtmtst.a +LIBDIR := ../lib +LIB := $(LIBDIR)/libzdtmtst.a +LDLIBS += $(LIB) CPPFLAGS += -I$(LIBDIR) -CFLAGS = -g -O2 -Wall -Werror -fno-strict-aliasing -CFLAGS += $(USERCFLAGS) TST_NOFILE = \ ipc \ @@ -41,15 +36,7 @@ DEP = $(SRC:%.c=%.d) PID = $(TST:%=%.pid) OUT = $(TST:%=%.out) -%.o: %.c - @echo $@ >> .gitignore - $(E) " CC " $@ - $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< - -%: %.o - @echo $@ >> .gitignore - $(E) " LINK " $@ - $(Q)$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ +include ../Makefile.inc all: $(TST) install: all @@ -99,21 +86,4 @@ thread-bomb: LDFLAGS += -pthread $(LIB): force $(Q) $(MAKE) -C $(LIBDIR) -gitignore-clean: - $(RM) -f .gitignore - -clean: gitignore-clean - $(RM) -f $(OBJ) $(TST) *~ - -cleandep: clean - $(RM) -f $(DEP) - -%.cleanout: % - $(Q) $(RM) -f -r $<.pid* $<.out* $<.test* chew_$<.test* - -cleanout: - $(RM) -f *.pid *.out* *.test chew* - -realclean: cleandep cleanout - -.PHONY: force clean cleandep cleanout realclean start check_start stop wait_stop +.PHONY: force start check_start stop wait_stop From b02526f3469896617851ff34a5951c5894f4c471 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 29 Mar 2017 15:21:16 -0700 Subject: [PATCH 0445/4375] zdtm/static/Makefile: rm non-existent test This test name was added by commit 1ce1cca, but there is no test. We do not use these lists since zdtm.py was introduced, therefore the error went unnoticed. I found it while running "make dep". Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 92ea9c394..4169f7a98 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -60,7 +60,6 @@ TST_NOFILE := \ sockets02 \ sockets_spair \ socket_queues \ - socket_queues02 \ socket-tcp \ socket-tcp6 \ socket-tcp-local \ From d9664e83cd4a4945d365967e4465b4bf671774f7 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 29 Mar 2017 15:21:17 -0700 Subject: [PATCH 0446/4375] test/zdtm/static/Makefile: drop .o for flags Makefile knows that a binary depends on .o file, and the .o file depends on .c file, and adds the per-target variables even in the indirect case. Therefore, .o suffix is not needed here. Note that it not hurts to leave it as is, so this commit is done only for the sake of keeping things simple. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 4169f7a98..4f8c3ff78 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -387,9 +387,9 @@ $(TST): | $(LIB) aio00: LDLIBS += -laio different_creds: LDLIBS += -lcap -futex.o: CFLAGS += -pthread +futex: CFLAGS += -pthread futex: LDFLAGS += -pthread -futex-rl.o: CFLAGS += -pthread +futex-rl: CFLAGS += -pthread futex-rl: LDFLAGS += -pthread jobctl00: LDLIBS += -lutil socket_listen: LDLIBS += -lrt -pthread From ef8bf4922447443248998c81021effe0e7a9acd8 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 29 Mar 2017 15:21:18 -0700 Subject: [PATCH 0447/4375] test/zdtm/static/skip-me.c: generalize Make it possible to use a custom message telling why the test is skipped. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/static/seccomp_filter.c | 1 + test/zdtm/static/seccomp_filter_inheritance.c | 1 + test/zdtm/static/seccomp_filter_tsync.c | 1 + test/zdtm/static/seccomp_strict.c | 1 + test/zdtm/static/skip-me.c | 2 +- 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/seccomp_filter.c b/test/zdtm/static/seccomp_filter.c index 36295a21a..81d985132 100644 --- a/test/zdtm/static/seccomp_filter.c +++ b/test/zdtm/static/seccomp_filter.c @@ -194,6 +194,7 @@ err: #else /* __NR_seccomp */ +#define TEST_SKIP_REASON "incompatible kernel (no seccomp)" #include "skip-me.c" #endif /* __NR_seccomp */ diff --git a/test/zdtm/static/seccomp_filter_inheritance.c b/test/zdtm/static/seccomp_filter_inheritance.c index 36d183c40..840136c5c 100644 --- a/test/zdtm/static/seccomp_filter_inheritance.c +++ b/test/zdtm/static/seccomp_filter_inheritance.c @@ -184,6 +184,7 @@ err: #else /* __NR_seccomp */ +#define TEST_SKIP_REASON "incompatible kernel (no seccomp)" #include "skip-me.c" #endif /* __NR_seccomp */ diff --git a/test/zdtm/static/seccomp_filter_tsync.c b/test/zdtm/static/seccomp_filter_tsync.c index 8b85947b7..9b4742ba1 100644 --- a/test/zdtm/static/seccomp_filter_tsync.c +++ b/test/zdtm/static/seccomp_filter_tsync.c @@ -209,6 +209,7 @@ err: #else /* __NR_seccomp */ +#define TEST_SKIP_REASON "incompatible kernel (no seccomp)" #include "skip-me.c" #endif /* __NR_seccomp */ diff --git a/test/zdtm/static/seccomp_strict.c b/test/zdtm/static/seccomp_strict.c index 054d0d98f..ac95ac828 100644 --- a/test/zdtm/static/seccomp_strict.c +++ b/test/zdtm/static/seccomp_strict.c @@ -129,6 +129,7 @@ err: #else /* __NR_seccomp */ +#define TEST_SKIP_REASON "incompatible kernel (no seccomp)" #include "skip-me.c" #endif /* __NR_seccomp */ diff --git a/test/zdtm/static/skip-me.c b/test/zdtm/static/skip-me.c index 0cb53aaba..9a552761e 100644 --- a/test/zdtm/static/skip-me.c +++ b/test/zdtm/static/skip-me.c @@ -2,7 +2,7 @@ int main(int argc, char ** argv) { test_init(argc, argv); - test_msg("Skipping test on incompatible kernel"); + test_msg("Skipping test:" TEST_SKIP_REASON); test_daemon(); test_waitsig(); From a773d9c215be7b60413713b7cdcc26704ad4ec93 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 29 Mar 2017 15:21:19 -0700 Subject: [PATCH 0448/4375] zdtm/static/maps03: don't run for 32-bit When this test is compiled on ARMv7, we get this: > maps03.c: In function 'main': > maps03.c:15:31: error: result of '10l << 30' requires 35 bits > to represent, but 'long int' only has 32 bits [-Werror=shift-overflow=] > mem = (void *)mmap(NULL, (10L << 30), PROT_READ | PROT_WRITE, > ^~ Surely, the nature of the test looks like it needs 64-bit addressing. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/static/maps03.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/zdtm/static/maps03.c b/test/zdtm/static/maps03.c index c4aba196a..f2bf7957a 100644 --- a/test/zdtm/static/maps03.c +++ b/test/zdtm/static/maps03.c @@ -1,8 +1,16 @@ #include #include #include +#include #include "zdtmtst.h" +#if (LONG_MAX == 2147483647L) /* 32 bit */ + +#define TEST_SKIP_REASON "64-bit arch required" +#include "skip-me.c" + +#else + const char *test_doc = "Test for huge VMA area"; const char *test_author = "Cyrill Gorcunov "; @@ -36,3 +44,4 @@ int main(int argc, char **argv) return 0; } +#endif From afcbee3caa60a0e50ef75ba72f256671f9d03fde Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 29 Mar 2017 15:21:20 -0700 Subject: [PATCH 0449/4375] test/zdtm/static/socket-ext.c: don't use mktemp This is just to prevent a compiler warning. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/static/socket-ext.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/zdtm/static/socket-ext.c b/test/zdtm/static/socket-ext.c index 219eeec0f..46bf6c9ff 100644 --- a/test/zdtm/static/socket-ext.c +++ b/test/zdtm/static/socket-ext.c @@ -27,13 +27,19 @@ int main(int argc, char *argv[]) unsigned int addrlen; task_waiter_t lock; - char path[PATH_MAX] = "/tmp/zdtm.unix.sock.XXXXXX"; + char dir[] = "/tmp/zdtm.unix.sock.XXXXXX"; + char *path; pid_t pid; int ret, sk; - mktemp(path); + if (mkdtemp(dir) < 0) { + pr_perror("mkdtemp(%s) failed", dir); + return 1; + } addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, path, sizeof(addr.sun_path)); + snprintf(addr.sun_path, sizeof(addr.sun_path), + "%s/%s", dir, "sock"); + path = addr.sun_path; addrlen = sizeof(addr.sun_family) + strlen(path); task_waiter_init(&lock); @@ -56,6 +62,7 @@ int main(int argc, char *argv[]) pr_perror("Can't bind socket to %s", path); return 1; } + chmod(dir, 0777); chmod(path, 0777); test_msg("The external socket %s\n", path); task_waiter_complete(&lock, 1); @@ -88,6 +95,7 @@ int main(int argc, char *argv[]) test_waitsig(); unlink(path); + unlink(dir); ret = send(sk, "H", 1, 0); if (ret != 1) { From a2a07874d10c02f4f594c0ff265ecc9fd0b2342b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 31 Mar 2017 18:49:59 +0300 Subject: [PATCH 0450/4375] shm: Do not dump sysvshm twice The contents of sysvshm areas is sometimes dumped twice. First time it goes via cr_dump_shmem(), since each attachment of the segment is noted by the add_shmem_area() and thus gets into the list scanned by the former call(). Second time it is dumped by dump_ipc_shm_pages(). Another thing is that in the 1st dump memory gets into the standard pagemap/pages image pair, while in the 2nd time it's all written as plain byte array into ipcns-shm.img. At restore contents is read from the ipcns-shm.img (2nd). While the first way is preferred, let's (temporarily) eliminate it. Historically these segments were dumped and restored the 2nd way. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/shmem.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/criu/shmem.c b/criu/shmem.c index a0821413d..586352a53 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -585,6 +585,9 @@ int add_shmem_area(pid_t pid, VmaEntry *vma, u64 *map) struct shmem_info *si; unsigned long size = vma->pgoff + (vma->end - vma->start); + if (vma_entry_is(vma, VMA_AREA_SYSVIPC)) + pid = SYSVIPC_SHMEM_PID; + si = shmem_find(vma->shmid); if (si) { if (si->size < size) { @@ -745,6 +748,8 @@ int cr_dump_shmem(void) struct shmem_info *si; for_each_shmem(i, si) { + if (si->pid == SYSVIPC_SHMEM_PID) + continue; ret = dump_one_shmem(si); if (ret) goto out; From feff2efa9a45f1f0db9ec4247ce32bed2d6631d1 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 29 Mar 2017 23:15:00 +0300 Subject: [PATCH 0451/4375] zdtm/dumpable02: don't print a non-null terminated string Signed-off-by: Andrei Vagin --- test/zdtm/static/dumpable02.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/dumpable02.c b/test/zdtm/static/dumpable02.c index 3463deda7..bd632e13e 100644 --- a/test/zdtm/static/dumpable02.c +++ b/test/zdtm/static/dumpable02.c @@ -36,11 +36,12 @@ int get_dumpable_from_pipes(int pipe_input, int pipe_output) { /* input and output are from the child's point of view. */ write(pipe_input, "GET\n", 4); - len = read(pipe_output, buf, sizeof(buf)); + len = read(pipe_output, buf, sizeof(buf) - 1); if (len < 0) { pr_perror("error in parent reading from pipe"); return -1; } + buf[len] = 0; if (memcmp(buf, "DUMPABLE:", 9) != 0) { pr_perror("child returned [%s]", buf); From 88e5db749c94536e301a85d6690071f94246dd5b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 29 Mar 2017 10:03:05 +0300 Subject: [PATCH 0452/4375] zdtm: print 5 lines before an error It's very hard to understand an error without a context Signed-off-by: Andrei Vagin --- test/zdtm.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 2026bf605..fcbacbd2a 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1552,13 +1552,19 @@ def print_error(line): def grep_errors(fname): first = True print_next = False + before = [] for l in open(fname): + before.append(l) + if len(before) > 5: + before.pop(0) if "Error" in l: if first: print_fname(fname, 'log') print_sep("grep Error", "-", 60) first = False - print_next = print_error(l) + for i in before: + print_next = print_error(i) + before = [] else: if print_next: print_next = print_error(l) From 9e1bde4d571282aceb1a5350c79cdd09b8a7cd9a Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 23 Mar 2017 15:02:03 -0700 Subject: [PATCH 0453/4375] pr_err(): don't forget a newline Unlike pr_perror(), pr_err() does not append a newline. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/arch/ppc64/src/lib/cpu.c | 2 +- compel/arch/x86/src/lib/infect.c | 2 +- compel/src/lib/infect.c | 2 +- criu/arch/ppc64/cpu.c | 4 ++-- criu/arch/x86/include/asm/compat.h | 3 ++- criu/cgroup.c | 6 +++--- criu/cr-restore.c | 6 +++--- criu/crtools.c | 3 ++- criu/files-reg.c | 2 +- criu/filesystems.c | 2 +- criu/lsm.c | 4 ++-- criu/mount.c | 2 +- criu/tty.c | 5 +++-- 13 files changed, 23 insertions(+), 20 deletions(-) diff --git a/compel/arch/ppc64/src/lib/cpu.c b/compel/arch/ppc64/src/lib/cpu.c index d2a7552a1..24c3c0cc6 100644 --- a/compel/arch/ppc64/src/lib/cpu.c +++ b/compel/arch/ppc64/src/lib/cpu.c @@ -25,7 +25,7 @@ int compel_cpuid(compel_cpuinfo_t *info) info->hwcap[1] = getauxval(AT_HWCAP2); if (!info->hwcap[0] || !info->hwcap[1]) { - pr_err("Can't read the hardware capabilities"); + pr_err("Can't read the hardware capabilities\n"); return -1; } diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index 23a96df86..b64a55d97 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -515,7 +515,7 @@ int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs) return ret; } - pr_err("PTRACE_GETREGSET read %zu bytes for pid %d, but native/compat regs sizes are %zu/%zu bytes", + pr_err("PTRACE_GETREGSET read %zu bytes for pid %d, but native/compat regs sizes are %zu/%zu bytes\n", iov.iov_len, pid, sizeof(regs->native), sizeof(regs->compat)); return -1; diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index c34452fd6..c0b05e3d9 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -896,7 +896,7 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l ret = arch_fetch_sas(ctl, ctl->rsigframe); if (ret) { - pr_err("Can't fetch sigaltstack for task %d (ret %d)", + pr_err("Can't fetch sigaltstack for task %d (ret %d)\n", ctl->rpid, ret); goto err; } diff --git a/criu/arch/ppc64/cpu.c b/criu/arch/ppc64/cpu.c index aecba7801..f90f99713 100644 --- a/criu/arch/ppc64/cpu.c +++ b/criu/arch/ppc64/cpu.c @@ -68,13 +68,13 @@ int cpu_validate_cpuinfo(void) goto error; if (cpu_info->n_ppc64_entry != 1) { - pr_err("No PPC64 related entry in image"); + pr_err("No PPC64 related entry in image\n"); goto error; } cpu_ppc64_entry = cpu_info->ppc64_entry[0]; if (cpu_ppc64_entry->endian != CURRENT_ENDIANNESS) { - pr_err("Bad endianness"); + pr_err("Bad endianness\n"); goto error; } diff --git a/criu/arch/x86/include/asm/compat.h b/criu/arch/x86/include/asm/compat.h index 119768db3..6d20c93f6 100644 --- a/criu/arch/x86/include/asm/compat.h +++ b/criu/arch/x86/include/asm/compat.h @@ -30,7 +30,8 @@ static inline void free_compat_syscall_stack(void *mem) long int ret = sys_munmap(mem, PAGE_SIZE); if (ret) - pr_err("munmap() of compat addr %p failed with %ld", mem, ret); + pr_err("munmap() of compat addr %p failed with %ld\n", + mem, ret); } #ifdef CONFIG_COMPAT diff --git a/criu/cgroup.c b/criu/cgroup.c index c4eea8dcc..bb8523a40 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -422,12 +422,12 @@ static int add_cgroup_properties(const char *fpath, struct cgroup_dir *ncd, const cgp_t *cgp = cgp_get_props(controller->controllers[i]); if (dump_cg_props_array(fpath, ncd, cgp) < 0) { - pr_err("dumping known properties failed"); + pr_err("dumping known properties failed\n"); return -1; } if (dump_cg_props_array(fpath, ncd, &cgp_global) < 0) { - pr_err("dumping global properties failed"); + pr_err("dumping global properties failed\n"); return -1; } } @@ -1069,7 +1069,7 @@ static int move_in_cgroup(CgSetEntry *se, bool setup_cgns) pr_info("Move into %d\n", se->id); if (setup_cgns && prepare_cgns(se) < 0) { - pr_err("failed preparing cgns"); + pr_err("failed preparing cgns\n"); return -1; } diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 95ad9ab65..6c8692335 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -555,7 +555,7 @@ static int open_core(int pid, CoreEntry **pcore) img = open_image(CR_FD_CORE, O_RSTR, pid); if (!img) { - pr_err("Can't open core data for %d", pid); + pr_err("Can't open core data for %d\n", pid); return -1; } @@ -1717,7 +1717,7 @@ static int prepare_userns_hook(void) return -1; if (prepare_loginuid(INVALID_UID, LOG_ERROR) < 0) { - pr_err("Setting loginuid for CT init task failed, CAP_AUDIT_CONTROL?"); + pr_err("Setting loginuid for CT init task failed, CAP_AUDIT_CONTROL?\n"); return -1; } return 0; @@ -1730,7 +1730,7 @@ static void restore_origin_ns_hook(void) /* not critical: it does not affect CT in any way */ if (prepare_loginuid(saved_loginuid, LOG_ERROR) < 0) - pr_err("Restore original /proc/self/loginuid failed"); + pr_err("Restore original /proc/self/loginuid failed\n"); } static int write_restored_pid(void) diff --git a/criu/crtools.c b/criu/crtools.c index 785c78b41..20f8fa9f4 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -565,7 +565,8 @@ int main(int argc, char *argv[], char *envp[]) if (!strcmp("net", optarg)) opts.empty_ns |= CLONE_NEWNET; else { - pr_err("Unsupported empty namespace: %s", optarg); + pr_err("Unsupported empty namespace: %s\n", + optarg); return 1; } break; diff --git a/criu/files-reg.c b/criu/files-reg.c index 3b93bb9e4..451427589 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1323,7 +1323,7 @@ static int make_parent_dirs_if_need(int mntns_root, char *path) p = last_delim = strrchr(path, '/'); if (!p) { - pr_err("Path %s has no parent dir", path); + pr_err("Path %s has no parent dir\n", path); return -1; } *p = '\0'; diff --git a/criu/filesystems.c b/criu/filesystems.c index 5c8a0b743..8211e396a 100644 --- a/criu/filesystems.c +++ b/criu/filesystems.c @@ -613,7 +613,7 @@ static bool btrfs_sb_equal(struct mount_info *a, struct mount_info *b) bool equal; if (!posa || !posb) { - pr_err("invalid btrfs options, no subvol argument"); + pr_err("invalid btrfs options, no subvol argument\n"); return false; } diff --git a/criu/lsm.c b/criu/lsm.c index 27ca00428..8c014d432 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -192,7 +192,7 @@ int render_lsm_profile(char *profile, char **val) switch (lsmtype) { case LSMTYPE__APPARMOR: if (strcmp(profile, "unconfined") != 0 && asprintf(val, "changeprofile %s", profile) < 0) { - pr_err("allocating lsm profile failed"); + pr_err("allocating lsm profile failed\n"); *val = NULL; return -1; } @@ -219,7 +219,7 @@ int parse_lsm_arg(char *arg) aux = strchr(arg, ':'); if (aux == NULL) { - pr_err("invalid argument %s for --lsm-profile", arg); + pr_err("invalid argument %s for --lsm-profile\n", arg); return -1; } diff --git a/criu/mount.c b/criu/mount.c index 700bb8fb2..8c2016d4e 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -3267,7 +3267,7 @@ int collect_mnt_namespaces(bool for_dump) if (ret == -EPERM) pr_info("Can't mount binfmt_misc: EPERM. Running in user_ns?\n"); else if (ret < 0 && ret != -EBUSY && ret != -ENODEV && ret != -ENOENT) { - pr_err("Can't mount binfmt_misc: %d %s", ret, strerror(-ret)); + pr_err("Can't mount binfmt_misc: %d %s\n", ret, strerror(-ret)); goto err; } else if (ret == 0) { ret = -1; diff --git a/criu/tty.c b/criu/tty.c index 0ff690c82..d49aafd61 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -2201,7 +2201,7 @@ int devpts_check_bindmount(struct mount_info *m) return 0; if (sscanf(m->root, "/%d", &index) != 1) { - pr_err("Unable to parse %s", m->root); + pr_err("Unable to parse %s\n", m->root); return -1; } @@ -2234,7 +2234,8 @@ found: } if (master_mp->nsid->type != NS_ROOT) { - pr_err("The master for %s isn't from the root mntns", m->root); + pr_err("The master for %s isn't from the root mntns\n", + m->root); return -1; } From 16259242f58c4b45e159cd8e0893d6164ae34f7a Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 23 Mar 2017 15:02:05 -0700 Subject: [PATCH 0454/4375] criu/namespaces.c: fix pr_perror usage 1. No newline (pr_perror() already adds one for you) 2. No colon before file name, e.g. WAS: Can't open file: /some/file: permission denied NOW: Can't open file /some/file: permission denied Cc: Kirill Tkhai Cc: Dengguangxing Reviewed-by: Kirill Tkhai Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/namespaces.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/namespaces.c b/criu/namespaces.c index c4a75a620..48722da7e 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -103,7 +103,7 @@ static int check_ns_file(char *ns_file) ret = access(ns_file, 0); if (ret < 0) { - pr_perror("Can't access join-ns file: %s", ns_file); + pr_perror("Can't access join-ns file %s", ns_file); return -1; } return 0; @@ -1539,7 +1539,7 @@ static int get_join_ns_fd(struct join_ns *jn) fd = open(pnsf, O_RDONLY); if (fd < 0) { - pr_perror("Can't open ns file: %s", pnsf); + pr_perror("Can't open ns file %s", pnsf); return -1; } jn->ns_fd = fd; From f4e7b6e78f3051b5519d8fc384cabf1621add308 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 23 Mar 2017 15:02:06 -0700 Subject: [PATCH 0455/4375] criu/namespaces.c: correct pr_err vs pr_perror usage So, in places where we have errno available (and it makes sense to show it), we want to use pr_perror(). In places where errno is not set/used, use pr_err(). Cc: Dengguangxing Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/namespaces.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/criu/namespaces.c b/criu/namespaces.c index 48722da7e..e4e32a003 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -47,7 +47,7 @@ int check_namespace_opts(void) { errno = 22; if (join_ns_flags & opts.empty_ns) { - pr_perror("Conflict flags: -join-ns and -empty-ns"); + pr_err("Conflicting flags: --join-ns and --empty-ns\n"); return -1; } if (join_ns_flags & CLONE_NEWUSER) @@ -90,12 +90,13 @@ static int check_ns_file(char *ns_file) if (!check_int_str(ns_file)) { pid = atoi(ns_file); if (pid <= 0) { - pr_perror("Invalid join_ns pid %s", ns_file); + pr_err("Invalid join_ns pid %s\n", ns_file); return -1; } proc_dir = open_pid_proc(pid); if (proc_dir < 0) { - pr_perror("Invalid join_ns pid: /proc/%s not found", ns_file); + pr_err("Invalid join_ns pid: /proc/%s not found\n", + ns_file); return -1; } return 0; From ba78d155578d5a8d78f4e0de5aa999c6cccc6dcf Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 23 Mar 2017 15:02:11 -0700 Subject: [PATCH 0456/4375] Spring whitespace cleanup Replace 8-spaces with a tab in code. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/arch/ppc64/cpu.c | 34 +++++++------- criu/arch/ppc64/crtools.c | 98 +++++++++++++++++++-------------------- criu/arch/x86/restorer.c | 4 +- criu/mem.c | 22 ++++----- criu/pstree.c | 2 +- criu/sk-netlink.c | 4 +- criu/sk-packet.c | 8 ++-- soccr/soccr.c | 28 +++++------ 8 files changed, 100 insertions(+), 100 deletions(-) diff --git a/criu/arch/ppc64/cpu.c b/criu/arch/ppc64/cpu.c index f90f99713..4fcfb065a 100644 --- a/criu/arch/ppc64/cpu.c +++ b/criu/arch/ppc64/cpu.c @@ -38,8 +38,8 @@ int cpu_dump_cpuinfo(void) int ret = -1; img = open_image(CR_FD_CPUINFO, O_DUMP); - if (!img) - return -1; + if (!img) + return -1; cpu_info.ppc64_entry = &cpu_ppc64_info_ptr; cpu_info.n_ppc64_entry = 1; @@ -51,7 +51,7 @@ int cpu_dump_cpuinfo(void) ret = pb_write_one(img, &cpu_info, PB_CPUINFO); close_image(img); - return ret; + return ret; } int cpu_validate_cpuinfo(void) @@ -60,12 +60,12 @@ int cpu_validate_cpuinfo(void) CpuinfoPpc64Entry *cpu_ppc64_entry; struct cr_img *img; int ret = -1; - img = open_image(CR_FD_CPUINFO, O_RSTR); - if (!img) - return -1; + img = open_image(CR_FD_CPUINFO, O_RSTR); + if (!img) + return -1; - if (pb_read_one(img, &cpu_info, PB_CPUINFO) < 0) - goto error; + if (pb_read_one(img, &cpu_info, PB_CPUINFO) < 0) + goto error; if (cpu_info->n_ppc64_entry != 1) { pr_err("No PPC64 related entry in image\n"); @@ -121,22 +121,22 @@ error: int cpuinfo_dump(void) { - if (cpu_init()) - return -1; + if (cpu_init()) + return -1; - if (cpu_dump_cpuinfo()) - return -1; + if (cpu_dump_cpuinfo()) + return -1; - return 0; + return 0; } int cpuinfo_check(void) { - if (cpu_init()) - return -1; + if (cpu_init()) + return -1; - if (cpu_validate_cpuinfo()) - return 1; + if (cpu_validate_cpuinfo()) + return 1; return 0; } diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index c4f0df790..ecda5ce93 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -239,7 +239,7 @@ static void xfree_tm_state(UserPpc64TmRegsEntry *tme) xfree(tme->vsxstate->vsxregs); xfree(tme->vsxstate); } - if (tme->gpregs) { + if (tme->gpregs) { if (tme->gpregs->gpr) xfree(tme->gpregs->gpr); xfree(tme->gpregs); @@ -286,25 +286,25 @@ static int copy_tm_regs(user_regs_struct_t *regs, user_fpregs_struct_t *fpregs, CoreEntry *core) { UserPpc64TmRegsEntry *tme; - UserPpc64RegsEntry *gpregs = core->ti_ppc64->gpregs; + UserPpc64RegsEntry *gpregs = core->ti_ppc64->gpregs; pr_debug("Copying TM registers\n"); - tme = xmalloc(sizeof(*tme)); - if (!tme) - return -1; + tme = xmalloc(sizeof(*tme)); + if (!tme) + return -1; user_ppc64_tm_regs_entry__init(tme); - tme->gpregs = allocate_gp_regs(); - if (!tme->gpregs) - goto out_free; + tme->gpregs = allocate_gp_regs(); + if (!tme->gpregs) + goto out_free; - gpregs->has_tfhar = true; - gpregs->tfhar = fpregs->tm.tm_spr_regs.tfhar; - gpregs->has_texasr = true; - gpregs->texasr = fpregs->tm.tm_spr_regs.texasr; - gpregs->has_tfiar = true; - gpregs->tfiar = fpregs->tm.tm_spr_regs.tfiar; + gpregs->has_tfhar = true; + gpregs->tfhar = fpregs->tm.tm_spr_regs.tfhar; + gpregs->has_texasr = true; + gpregs->texasr = fpregs->tm.tm_spr_regs.texasr; + gpregs->has_tfiar = true; + gpregs->tfiar = fpregs->tm.tm_spr_regs.tfiar; /* This is the checkpointed state, we must save it in place of the @@ -315,32 +315,32 @@ static int copy_tm_regs(user_regs_struct_t *regs, user_fpregs_struct_t *fpregs, copy_gp_regs(gpregs, &fpregs->tm.regs); if (fpregs->tm.flags & USER_FPREGS_FL_FP) { - core->ti_ppc64->fpstate = copy_fp_regs(fpregs->tm.fpregs); - if (!core->ti_ppc64->fpstate) - goto out_free; - } + core->ti_ppc64->fpstate = copy_fp_regs(fpregs->tm.fpregs); + if (!core->ti_ppc64->fpstate) + goto out_free; + } if (fpregs->tm.flags & USER_FPREGS_FL_ALTIVEC) { - core->ti_ppc64->vrstate = copy_altivec_regs(fpregs->tm.vrregs); - if (!core->ti_ppc64->vrstate) - goto out_free; + core->ti_ppc64->vrstate = copy_altivec_regs(fpregs->tm.vrregs); + if (!core->ti_ppc64->vrstate) + goto out_free; - /* - * Force the MSR_VEC bit of the restored MSR otherwise the - * kernel will not restore them from the signal frame. - */ - gpregs->msr |= MSR_VEC; + /* + * Force the MSR_VEC bit of the restored MSR otherwise the + * kernel will not restore them from the signal frame. + */ + gpregs->msr |= MSR_VEC; if (fpregs->tm.flags & USER_FPREGS_FL_VSX) { core->ti_ppc64->vsxstate = copy_vsx_regs(fpregs->tm.vsxregs); if (!core->ti_ppc64->vsxstate) goto out_free; /* - * Force the MSR_VSX bit of the restored MSR otherwise - * the kernel will not restore them from the signal - * frame. - */ - gpregs->msr |= MSR_VSX; + * Force the MSR_VSX bit of the restored MSR otherwise + * the kernel will not restore them from the signal + * frame. + */ + gpregs->msr |= MSR_VSX; } } @@ -380,7 +380,7 @@ static int __copy_task_regs(user_regs_struct_t *regs, fpstate = &(core->ti_ppc64->fpstate); vrstate = &(core->ti_ppc64->vrstate); vsxstate = &(core->ti_ppc64->vsxstate); - } + } copy_gp_regs(gpregs, regs); if (fpregs->flags & USER_FPREGS_FL_FP) { @@ -392,22 +392,22 @@ static int __copy_task_regs(user_regs_struct_t *regs, *vrstate = copy_altivec_regs(fpregs->vrregs); if (!*vrstate) return -1; - /* - * Force the MSR_VEC bit of the restored MSR otherwise the - * kernel will not restore them from the signal frame. - */ - gpregs->msr |= MSR_VEC; + /* + * Force the MSR_VEC bit of the restored MSR otherwise the + * kernel will not restore them from the signal frame. + */ + gpregs->msr |= MSR_VEC; if (fpregs->flags & USER_FPREGS_FL_VSX) { *vsxstate = copy_vsx_regs(fpregs->vsxregs); if (!*vsxstate) return -1; - /* - * Force the MSR_VSX bit of the restored MSR otherwise - * the kernel will not restore them from the signal - * frame. - */ - gpregs->msr |= MSR_VSX; + /* + * Force the MSR_VSX bit of the restored MSR otherwise + * the kernel will not restore them from the signal + * frame. + */ + gpregs->msr |= MSR_VSX; } } return 0; @@ -441,7 +441,7 @@ int arch_alloc_thread_info(CoreEntry *core) void arch_free_thread_info(CoreEntry *core) { - if (CORE_THREAD_ARCH_INFO(core)) { + if (CORE_THREAD_ARCH_INFO(core)) { if (CORE_THREAD_ARCH_INFO(core)->fpstate) { xfree(CORE_THREAD_ARCH_INFO(core)->fpstate->fpregs); xfree(CORE_THREAD_ARCH_INFO(core)->fpstate); @@ -455,11 +455,11 @@ void arch_free_thread_info(CoreEntry *core) xfree(CORE_THREAD_ARCH_INFO(core)->vsxstate); } xfree_tm_state(CORE_THREAD_ARCH_INFO(core)->tmstate); - xfree(CORE_THREAD_ARCH_INFO(core)->gpregs->gpr); - xfree(CORE_THREAD_ARCH_INFO(core)->gpregs); - xfree(CORE_THREAD_ARCH_INFO(core)); - CORE_THREAD_ARCH_INFO(core) = NULL; - } + xfree(CORE_THREAD_ARCH_INFO(core)->gpregs->gpr); + xfree(CORE_THREAD_ARCH_INFO(core)->gpregs); + xfree(CORE_THREAD_ARCH_INFO(core)); + CORE_THREAD_ARCH_INFO(core) = NULL; + } } int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index a4ddee543..a66304385 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -73,8 +73,8 @@ void restore_tls(tls_t *ptls) memcpy(stack32, desc, sizeof(user_desc_t)); asm volatile ( - " mov %1,%%eax \n" - " mov %2,%%ebx \n" + " mov %1,%%eax \n" + " mov %2,%%ebx \n" " int $0x80 \n" " mov %%eax,%0 \n" : "=g"(ret) diff --git a/criu/mem.c b/criu/mem.c index eeaedeef6..255e88e37 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -57,19 +57,19 @@ int do_task_reset_dirty_track(int pid) ret = write(fd, cmd, sizeof(cmd)); if (ret < 0) { - if (errno == EINVAL) /* No clear-soft-dirty in kernel */ - ret = 1; - else { - pr_perror("Can't reset %d's dirty memory tracker (%d)", pid, errno); - ret = -1; - } - } else { - pr_info(" ... done\n"); - ret = 0; + if (errno == EINVAL) /* No clear-soft-dirty in kernel */ + ret = 1; + else { + pr_perror("Can't reset %d's dirty memory tracker (%d)", pid, errno); + ret = -1; + } + } else { + pr_info(" ... done\n"); + ret = 0; } - close(fd); - return ret; + close(fd); + return ret; } unsigned long dump_pages_args_size(struct vm_area_list *vmas) diff --git a/criu/pstree.c b/criu/pstree.c index d537e5831..b1006e725 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -586,7 +586,7 @@ err: return ret; } -#define RESERVED_PIDS 300 +#define RESERVED_PIDS 300 static int get_free_pid() { static struct pid *prev, *next; diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c index e61aa4455..0363c5e16 100644 --- a/criu/sk-netlink.c +++ b/criu/sk-netlink.c @@ -15,10 +15,10 @@ struct netlink_sk_desc { struct socket_desc sd; - u32 portid; + u32 portid; u32 *groups; u32 gsize; - u32 dst_portid; + u32 dst_portid; u32 dst_group; u8 state; u8 protocol; diff --git a/criu/sk-packet.c b/criu/sk-packet.c index 841a4aae6..9c3e6f340 100644 --- a/criu/sk-packet.c +++ b/criu/sk-packet.c @@ -27,10 +27,10 @@ struct packet_sock_info { }; struct packet_mreq_max { - int mr_ifindex; - unsigned short mr_type; - unsigned short mr_alen; - unsigned char mr_address[MAX_ADDR_LEN]; + int mr_ifindex; + unsigned short mr_type; + unsigned short mr_alen; + unsigned char mr_address[MAX_ADDR_LEN]; }; struct packet_sock_desc { diff --git a/soccr/soccr.c b/soccr/soccr.c index 7d093b1aa..70f99357a 100644 --- a/soccr/soccr.c +++ b/soccr/soccr.c @@ -16,17 +16,17 @@ #endif enum { - TCPF_ESTABLISHED = (1 << 1), - TCPF_SYN_SENT = (1 << 2), - TCPF_SYN_RECV = (1 << 3), - TCPF_FIN_WAIT1 = (1 << 4), - TCPF_FIN_WAIT2 = (1 << 5), - TCPF_TIME_WAIT = (1 << 6), - TCPF_CLOSE = (1 << 7), - TCPF_CLOSE_WAIT = (1 << 8), - TCPF_LAST_ACK = (1 << 9), - TCPF_LISTEN = (1 << 10), - TCPF_CLOSING = (1 << 11), + TCPF_ESTABLISHED = (1 << 1), + TCPF_SYN_SENT = (1 << 2), + TCPF_SYN_RECV = (1 << 3), + TCPF_FIN_WAIT1 = (1 << 4), + TCPF_FIN_WAIT2 = (1 << 5), + TCPF_TIME_WAIT = (1 << 6), + TCPF_CLOSE = (1 << 7), + TCPF_CLOSE_WAIT = (1 << 8), + TCPF_LAST_ACK = (1 << 9), + TCPF_LISTEN = (1 << 10), + TCPF_CLOSING = (1 << 11), }; /* @@ -561,9 +561,9 @@ static int send_fin(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, libnet_type = LIBNET_RAW4; l = libnet_init( - libnet_type, /* injection type */ - NULL, /* network interface */ - errbuf); /* errbuf */ + libnet_type, /* injection type */ + NULL, /* network interface */ + errbuf); /* errbuf */ if (l == NULL) return -1; From df9d94515f1a8c62c9681a69a6eea58bc1d196aa Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 28 Mar 2017 18:10:34 -0700 Subject: [PATCH 0457/4375] Use *open_proc* where possible Using open_proc/fopen_proc/__open_proc is better since - it uses openat - it comes with nice error reporting Let's use it in places where we can. Even if it does not give any improvements (such as in cr-check.c), error message unification is good enough reason to do so. Requested-by: Pavel Emelyanov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/autofs.c | 6 ++---- criu/cr-check.c | 12 ++++-------- criu/kerndat.c | 9 +++------ criu/namespaces.c | 8 ++------ criu/net.c | 6 ++---- 5 files changed, 13 insertions(+), 28 deletions(-) diff --git a/criu/autofs.c b/criu/autofs.c index a436e9fa9..15b0fc4b3 100644 --- a/criu/autofs.c +++ b/criu/autofs.c @@ -359,11 +359,9 @@ static int access_autofs_mount(struct mount_info *pm) if (new_pid_ns < 0) return -1; - old_pid_ns = open("/proc/self/ns/pid", O_RDONLY); - if (old_pid_ns < 0) { - pr_perror("Can't open /proc/self/ns/pid"); + old_pid_ns = open_proc(PROC_SELF, "ns/pid"); + if (old_pid_ns < 0) goto close_new_pid_ns; - } if (switch_ns(pm->nsid->ns_pid, &mnt_ns_desc, &old_mnt_ns)) { pr_err("failed to switch to mount namespace\n"); diff --git a/criu/cr-check.c b/criu/cr-check.c index c7304af6d..2c97c880b 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -244,11 +244,9 @@ static int check_fcntl(void) u32 v[2]; int fd; - fd = open("/proc/self/comm", O_RDONLY); - if (fd < 0) { - pr_perror("Can't open self comm file"); + fd = open_proc(PROC_SELF, "comm"); + if (fd < 0) return -1; - } if (fcntl(fd, F_GETOWNER_UIDS, (long)v)) { pr_perror("Can'r fetch file owner UIDs"); @@ -726,11 +724,9 @@ static unsigned long get_ring_len(unsigned long addr) FILE *maps; char buf[256]; - maps = fopen("/proc/self/maps", "r"); - if (!maps) { - pr_perror("No maps proc file"); + maps = fopen_proc(PROC_SELF, "maps"); + if (!maps) return 0; - } while (fgets(buf, sizeof(buf), maps)) { unsigned long start, end; diff --git a/criu/kerndat.c b/criu/kerndat.c index 414e9c414..37efcff2c 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -294,9 +294,8 @@ int kerndat_get_dirty_track(void) goto no_dt; ret = -1; - pm2 = open("/proc/self/pagemap", O_RDONLY); + pm2 = open_proc(PROC_SELF, "pagemap"); if (pm2 < 0) { - pr_perror("Can't open pagemap file"); munmap(map, PAGE_SIZE); return ret; } @@ -397,11 +396,9 @@ int kerndat_fdinfo_has_lock() int fd, pfd = -1, exit_code = -1, len; char buf[PAGE_SIZE]; - fd = open("/proc/locks", O_RDONLY); - if (fd < 0) { - pr_perror("Unable to open /proc/locks"); + fd = open_proc(PROC_GEN, "locks"); + if (fd < 0) return -1; - } if (flock(fd, LOCK_SH)) { pr_perror("Can't take a lock"); diff --git a/criu/namespaces.c b/criu/namespaces.c index e4e32a003..ed8a66248 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -238,16 +238,12 @@ int switch_ns(int pid, struct ns_desc *nd, int *rst) int switch_ns_by_fd(int nsfd, struct ns_desc *nd, int *rst) { - char buf[32]; int ret = -1; if (rst) { - snprintf(buf, sizeof(buf), "/proc/self/ns/%s", nd->str); - *rst = open(buf, O_RDONLY); - if (*rst < 0) { - pr_perror("Can't open ns file"); + *rst = open_proc(PROC_SELF, "ns/%s", nd->str); + if (*rst < 0) goto err_ns; - } } ret = setns(nsfd, nd->cflag); diff --git a/criu/net.c b/criu/net.c index 297295b59..d2c10f7da 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1715,11 +1715,9 @@ int netns_keep_nsfd(void) * that before we leave the existing namespaces. */ - ns_fd = open("/proc/self/ns/net", O_RDONLY | O_CLOEXEC); - if (ns_fd < 0) { - pr_perror("Can't cache net fd"); + ns_fd = __open_proc(PROC_SELF, 0, O_RDONLY | O_CLOEXEC, "ns/net"); + if (ns_fd < 0) return -1; - } ret = install_service_fd(NS_FD_OFF, ns_fd); if (ret < 0) From 8abb4a7f7fb339573e41ae17e25382aa883e7743 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 30 Mar 2017 22:00:56 +0300 Subject: [PATCH 0458/4375] unix: a unix name can be a non-null terminated string In this patch, we replace all zero characters to '@'. ==30==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300000e3ca at pc 0x7f34144b6be1 bp 0x7ffee7b6bb20 sp 0x7ffee7b6b298 READ of size 26 at 0x60300000e3ca thread T0 #0 0x7f34144b6be0 (/lib64/libasan.so.3+0x8dbe0) #1 0x7f34144b8e4d in __interceptor_vsnprintf (/lib64/libasan.so.3+0x8fe4d) #2 0x4966cb in vprint_on_level criu/log.c:228 #3 0x496b64 in print_on_level criu/log.c:249 #4 0x505c94 in collect_one_unixsk criu/sk-unix.c:1401 #5 0x4e7ae3 in collect_image criu/protobuf.c:213 #6 0x462c5c in root_prepare_shared criu/cr-restore.c:247 #7 0x462c5c in restore_task_with_children criu/cr-restore.c:1420 #8 0x7f34132d70ec in __clone (/lib64/libc.so.6+0x1030ec) 0x60300000e3ca is located 0 bytes to the right of 26-byte region [0x60300000e3b0,0x60300000e3ca) allocated by thread T0 here: #0 0x7f34144efe70 in malloc (/lib64/libasan.so.3+0xc6e70) #1 0x7f3413bdb021 (/lib64/libprotobuf-c.so.1+0x6021) Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index c7441e588..83c54d3f9 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -975,6 +975,9 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) int cwd_fd = -1, root_fd = -1; int ret = -1; + if (ui->ue->name.len == 0) + return 0; + if ((ui->ue->type == SOCK_STREAM) && (ui->ue->state == TCP_ESTABLISHED)) { /* * FIXME this can be done, but for doing this properly we @@ -1362,6 +1365,8 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) { struct unix_sk_info *ui = o; static bool post_queued = false; + char *uname, *prefix = ""; + int ulen; ui->ue = pb_msg(base, UnixSkEntry); ui->name_dir = (void *)ui->ue->name_dir; @@ -1391,10 +1396,32 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) INIT_LIST_HEAD(&ui->connected); INIT_LIST_HEAD(&ui->node); ui->flags = 0; - pr_info(" `- Got %#x peer %#x (name %s dir %s)\n", + + uname = ui->name; + ulen = ui->ue->name.len; + if (ulen > 0 && uname[0] == 0) { + prefix = "@"; + uname++; + ulen--; + if (memrchr(uname, 0, ulen)) { + /* replace zero characters */ + char *s = alloca(ulen + 1); + int i; + + for (i = 0; i < ulen; i++) + s[i] = uname[i] ? : '@'; + uname = s; + } + } else if (ulen == 0) { + ulen = 1; + uname = "-"; + } + + pr_info(" `- Got %#x peer %#x (name %s%.*s dir %s)\n", ui->ue->ino, ui->ue->peer, - ui->name ? (ui->name[0] ? ui->name : &ui->name[1]) : "-", + prefix, ulen, uname, ui->name_dir ? ui->name_dir : "-"); + list_add_tail(&ui->list, &unix_sockets); return file_desc_add(&ui->d, ui->ue->id, &unix_desc_ops); } From 5a7b90b5957049c6dd2b45e4504bbae72b642e5a Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 30 Mar 2017 22:00:57 +0300 Subject: [PATCH 0459/4375] zdtm/unix: add zero characters into a socket address An abstract name can contain zero characters. Signed-off-by: Andrei Vagin --- test/zdtm/static/sk-unix-unconn.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/zdtm/static/sk-unix-unconn.c b/test/zdtm/static/sk-unix-unconn.c index 8e600130d..abf59e39b 100644 --- a/test/zdtm/static/sk-unix-unconn.c +++ b/test/zdtm/static/sk-unix-unconn.c @@ -12,7 +12,7 @@ const char *test_author = "Vagin Andrew "; int main(int argc, char ** argv) { int sk, skc; - int ret; + int ret, len; char path[PATH_MAX]; struct sockaddr_un addr; socklen_t addrlen; @@ -31,12 +31,13 @@ int main(int argc, char ** argv) return 1; } - snprintf(path, sizeof(path), "X/zdtm-%s-%d", argv[0], getpid()); + len = snprintf(path, sizeof(path), "X/zdtm-%s-%d/X", argv[0], getpid()); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, path, sizeof(addr.sun_path)); - addrlen = sizeof(addr.sun_family) + strlen(path); + addrlen = sizeof(addr.sun_family) + len; addr.sun_path[0] = 0; + addr.sun_path[len - 1] = 0; ret = bind(sk, (struct sockaddr *) &addr, addrlen); if (ret) { From fc9fea15af30fc23f97ab9cc94d284644e4402c1 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 4 Apr 2017 20:45:20 +0300 Subject: [PATCH 0460/4375] soccr: Print errors in send_fin (v2) v2: Use logerr where needed. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- soccr/soccr.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/soccr/soccr.c b/soccr/soccr.c index 70f99357a..cb3f7b9c1 100644 --- a/soccr/soccr.c +++ b/soccr/soccr.c @@ -564,11 +564,15 @@ static int send_fin(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, libnet_type, /* injection type */ NULL, /* network interface */ errbuf); /* errbuf */ - if (l == NULL) + if (l == NULL) { + loge("libnet_init failed (%s)\n", errbuf); return -1; + } - if (setsockopt(l->fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark))) + if (setsockopt(l->fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark))) { + logerr("Can't set SO_MARK (%d) for socket\n", mark); goto err; + } ret = libnet_build_tcp( ntohs(sk->dst_addr->v4.sin_port), /* source port */ From 444702c6425782e0c877de42f1818933dcf88dd2 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 3 Apr 2017 21:08:40 +0300 Subject: [PATCH 0461/4375] compel: Print why memfd()-ing task fails Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/src/lib/infect.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index c0b05e3d9..7f6d2f3f1 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -747,8 +747,11 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) fd = (int)(long)sret; if (fd == -ENOSYS) return 1; - if (fd < 0) + if (fd < 0) { + errno = -fd; + pr_perror("Can't create memfd in victim"); return fd; + } ctl->map_length = round_up(size, page_size()); lfd = ctl->ictx.open_proc(ctl->rpid, O_RDWR, "fd/%d", fd); From 70ac7a10cd9d3b5bef2112121ca19aa3d5542c43 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 30 Mar 2017 02:34:01 +0300 Subject: [PATCH 0462/4375] travis: run tests with asan v2: Use the devicemapper storage driver for docker containers to run more tests. AUFS doesn't support file handles, so a few tests (e.g. inotify00 can't be run). Signed-off-by: Andrei Vagin --- .travis.yml | 1 + scripts/build/Dockerfile.fedora-asan | 16 ++++++++++++++++ scripts/build/Makefile | 2 +- scripts/travis/Makefile | 5 +++++ scripts/travis/asan.sh | 21 +++++++++++++++++++++ 5 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 scripts/build/Dockerfile.fedora-asan create mode 100755 scripts/travis/asan.sh diff --git a/.travis.yml b/.travis.yml index a5dfb9f18..78b1f0c4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ env: - TR_ARCH=local GCOV=1 - TR_ARCH=local CLANG=1 - TR_ARCH=alpine + - TR_ARCH=asan - TR_ARCH=x86_64 - TR_ARCH=armv7hf - TR_ARCH=aarch64 diff --git a/scripts/build/Dockerfile.fedora-asan b/scripts/build/Dockerfile.fedora-asan new file mode 100644 index 000000000..13aad28a0 --- /dev/null +++ b/scripts/build/Dockerfile.fedora-asan @@ -0,0 +1,16 @@ +FROM fedora:latest +ARG CC=gcc +ARG ENV1=FOOBAR + +RUN dnf install -y git gcc make +RUN dnf install -y protobuf-devel protobuf-c-devel libaio-devel libcap-devel libnl3-devel libnet-devel +RUN dnf install -y python ccache libasan findutils tar python-yaml protobuf-python iptables iproute python-ipaddr procps-ng + +COPY . /criu +WORKDIR /criu + +ENV CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes +RUN mv .ccache /tmp; make mrproper; ccache -s; \ + date; make -j $(nproc) ASAN=1 CC="$CC"; date +RUN make ASAN=1 -C test/zdtm -j $(nproc) + diff --git a/scripts/build/Makefile b/scripts/build/Makefile index b17bf10f5..53087111e 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -1,6 +1,6 @@ QEMU_ARCHES := armv7hf aarch64 ppc64le # require qemu ARCHES := $(QEMU_ARCHES) x86_64 -TARGETS := $(ARCHES) alpine +TARGETS := $(ARCHES) alpine fedora-asan TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) all: $(TARGETS) $(TARGETS_CLANG) diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index 0dadd65f7..e759ac25e 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -15,6 +15,11 @@ alpine: $(MAKE) -C ../build $@$(target-suffix) docker run --rm -it --privileged -v /lib/modules:/lib/modules criu-alpine ./test/zdtm.py run -t zdtm/static/env00 +asan: + echo 'DOCKER_OPTS="--storage-driver=devicemapper"' > /etc/default/docker + restart docker + $(MAKE) -C ../build fedora-asan + docker run --rm -it --privileged -v /lib/modules:/lib/modules criu-fedora-asan ./scripts/travis/asan.sh %: $(MAKE) -C ../build $@$(target-suffix) diff --git a/scripts/travis/asan.sh b/scripts/travis/asan.sh new file mode 100755 index 000000000..5b34da61e --- /dev/null +++ b/scripts/travis/asan.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +set -x + +cat /proc/self/mountinfo + +chmod 0777 test +chmod 0777 test/zdtm/transition/ +chmod 0777 test/zdtm/static + +./test/zdtm.py run -a --keep-going -k always --parallel 4 -x zdtm/static/rtc +ret=$? + +for i in `find / -name 'asan.log*'`; do + echo $i; + echo ======================================== + cat $i; + echo ======================================== + ret=1; +done; +exit $ret From 3bdaf5a9d87e29ddfbc7fd75c1ae8185f7025930 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 5 Apr 2017 14:32:59 +0300 Subject: [PATCH 0463/4375] zdtm: rely on -D_GNU_SOURCE passed from Makefiles After the commit 02c763939c10 ("test/zdtm: unify common code") CFLAGS with -D_GNU_SOURCE defined in the top Makefile are being passed to tests Makefiles. As _GNU_SOURCE is also defined by tests, that resulted in zdtm tests build failures: make[2]: Entering directory `/home/criu/test/zdtm/lib' CC test.o test.c:1:0: error: "_GNU_SOURCE" redefined [-Werror] #define _GNU_SOURCE ^ :0:0: note: this is the location of the previous definition cc1: all warnings being treated as errors make[2]: *** [test.o] Error 1 However, we didn't catch this in time by Travis-CI, as zdtm.py doesn't do `make zdtm`, rather it does `make -C test/zdtm/{lib,static,transition}`. By calling middle makefile this way, it doesn't have _GNU_SOURCE in CFLAGS from top-Makefile. I think the right thing to do here - is following CRIU's way: rely on definition of _GNU_SOURCE by Makefiles. This patch is almost fully generated with find test/zdtm/ -name '*.c' -type f \ -exec sed -i '/define _GNU_SOURCE/{n;/^$/d;}' '{}' \; \ -exec sed -i '/define _GNU_SOURCE/d' '{}' \; With an exception for adding -D_GNU_SOURCE in tests Makefile.inc for keeping the same behaviour for zdtm.py. Also changed utsname.c to use utsname::domainname, rather private utsname::__domainname, as now it's uncovered (from sys/utsname.h): > struct utsname > { ... > # ifdef __USE_GNU > char domainname[_UTSNAME_DOMAIN_LENGTH]; > # else > char __domainname[_UTSNAME_DOMAIN_LENGTH]; > # endif Reported-by: Adrian Reber Cc: Kir Kolyshkin Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/Makefile.inc | 1 + test/zdtm/lib/fs.c | 2 -- test/zdtm/lib/lock.c | 2 -- test/zdtm/lib/ns.c | 1 - test/zdtm/lib/test.c | 1 - test/zdtm/static/autofs.c | 2 -- test/zdtm/static/caps00.c | 1 - test/zdtm/static/cgroup_stray.c | 1 - test/zdtm/static/cgroupns.c | 1 - test/zdtm/static/clone_fs.c | 1 - test/zdtm/static/console.c | 2 -- test/zdtm/static/del_standalone_un.c | 1 - test/zdtm/static/deleted_unix_sock.c | 1 - test/zdtm/static/different_creds.c | 1 - test/zdtm/static/eventfs00.c | 1 - test/zdtm/static/fanotify00.c | 1 - test/zdtm/static/fdt_shared.c | 1 - test/zdtm/static/fifo-rowo-pair.c | 1 - test/zdtm/static/file_fown.c | 1 - test/zdtm/static/file_locks00.c | 2 -- test/zdtm/static/file_locks01.c | 2 -- test/zdtm/static/file_locks02.c | 2 -- test/zdtm/static/file_locks03.c | 2 -- test/zdtm/static/file_locks04.c | 2 -- test/zdtm/static/file_locks05.c | 2 -- test/zdtm/static/file_locks06.c | 2 -- test/zdtm/static/file_locks07.c | 2 -- test/zdtm/static/file_locks08.c | 2 -- test/zdtm/static/groups.c | 1 - test/zdtm/static/helper_zombie_child.c | 1 - test/zdtm/static/inotify00.c | 1 - test/zdtm/static/inotify02.c | 2 -- test/zdtm/static/inotify_irmap.c | 1 - test/zdtm/static/maps01.c | 1 - test/zdtm/static/mnt_ext_auto.c | 1 - test/zdtm/static/mnt_ext_master.c | 1 - test/zdtm/static/mnt_tracefs.c | 1 - test/zdtm/static/mntns_deleted.c | 2 -- test/zdtm/static/mntns_ghost.c | 1 - test/zdtm/static/mntns_link_remap.c | 1 - test/zdtm/static/mntns_open.c | 1 - test/zdtm/static/mntns_overmount.c | 1 - test/zdtm/static/mntns_remap.c | 1 - test/zdtm/static/mntns_ro_root.c | 1 - test/zdtm/static/mntns_root_bind.c | 1 - test/zdtm/static/mntns_shared_bind.c | 1 - test/zdtm/static/mntns_shared_bind03.c | 1 - test/zdtm/static/mntns_shared_vs_private.c | 1 - test/zdtm/static/mountpoints.c | 1 - test/zdtm/static/msgque.c | 1 - test/zdtm/static/pid00.c | 1 - test/zdtm/static/proc-self.c | 1 - test/zdtm/static/remap_dead_pid.c | 1 - test/zdtm/static/sem.c | 1 - test/zdtm/static/session00.c | 1 - test/zdtm/static/session01.c | 1 - test/zdtm/static/session02.c | 1 - test/zdtm/static/session03.c | 1 - test/zdtm/static/shm-mp.c | 1 - test/zdtm/static/shm.c | 1 - test/zdtm/static/sigaltstack.c | 2 -- test/zdtm/static/signalfd00.c | 1 - test/zdtm/static/sigpending.c | 1 - test/zdtm/static/sk-unix-rel.c | 2 -- test/zdtm/static/sock_peercred.c | 1 - test/zdtm/static/socket-ext.c | 2 -- test/zdtm/static/socket-tcp.c | 3 --- test/zdtm/static/socket_dgram_data.c | 1 - test/zdtm/static/socket_queues.c | 2 -- test/zdtm/static/socket_snd_addr.c | 1 - test/zdtm/static/sockets00.c | 2 -- test/zdtm/static/sockets01.c | 2 -- test/zdtm/static/sockets02.c | 2 -- test/zdtm/static/sockets03.c | 2 -- test/zdtm/static/sockets_dgram.c | 2 -- test/zdtm/static/sockets_spair.c | 2 -- test/zdtm/static/tempfs_subns.c | 1 - test/zdtm/static/utsname.c | 2 +- test/zdtm/static/vt.c | 2 -- test/zdtm/static/xids00.c | 1 - test/zdtm/transition/ipc.c | 1 - test/zdtm/transition/maps008.c | 1 - test/zdtm/transition/shmem.c | 1 - 83 files changed, 2 insertions(+), 110 deletions(-) diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index c7b40e763..79f0fc628 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -23,6 +23,7 @@ SRCARCH ?= $(ARCH) CC := gcc CFLAGS += -g -O2 -Wall -Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS += $(USERCFLAGS) +CFLAGS += -D_GNU_SOURCE CPPFLAGS += -iquote $(LIBDIR)/arch/$(SRCARCH)/include ifeq ($(strip $(V)),) diff --git a/test/zdtm/lib/fs.c b/test/zdtm/lib/fs.c index 04788e9c4..37f5e4191 100644 --- a/test/zdtm/lib/fs.c +++ b/test/zdtm/lib/fs.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/lib/lock.c b/test/zdtm/lib/lock.c index 9d2a646a6..3c3691d98 100644 --- a/test/zdtm/lib/lock.c +++ b/test/zdtm/lib/lock.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/lib/ns.c b/test/zdtm/lib/ns.c index 19a2b2ae4..7a0949f22 100644 --- a/test/zdtm/lib/ns.c +++ b/test/zdtm/lib/ns.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/lib/test.c b/test/zdtm/lib/test.c index 75b7d93bd..a01eac377 100644 --- a/test/zdtm/lib/test.c +++ b/test/zdtm/lib/test.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/autofs.c b/test/zdtm/static/autofs.c index 1644a6e10..68a62940d 100644 --- a/test/zdtm/static/autofs.c +++ b/test/zdtm/static/autofs.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/caps00.c b/test/zdtm/static/caps00.c index 5911fa19b..62484c4f4 100644 --- a/test/zdtm/static/caps00.c +++ b/test/zdtm/static/caps00.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/cgroup_stray.c b/test/zdtm/static/cgroup_stray.c index 9736845c0..235434ed2 100644 --- a/test/zdtm/static/cgroup_stray.c +++ b/test/zdtm/static/cgroup_stray.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/cgroupns.c b/test/zdtm/static/cgroupns.c index 955ab7227..cee704353 100644 --- a/test/zdtm/static/cgroupns.c +++ b/test/zdtm/static/cgroupns.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/clone_fs.c b/test/zdtm/static/clone_fs.c index 5cebea586..e368aff99 100644 --- a/test/zdtm/static/clone_fs.c +++ b/test/zdtm/static/clone_fs.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/console.c b/test/zdtm/static/console.c index 41246aea0..026eacb2e 100644 --- a/test/zdtm/static/console.c +++ b/test/zdtm/static/console.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/del_standalone_un.c b/test/zdtm/static/del_standalone_un.c index 0fd3795bf..b512ff710 100644 --- a/test/zdtm/static/del_standalone_un.c +++ b/test/zdtm/static/del_standalone_un.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/deleted_unix_sock.c b/test/zdtm/static/deleted_unix_sock.c index 793c96884..bcc33f3de 100644 --- a/test/zdtm/static/deleted_unix_sock.c +++ b/test/zdtm/static/deleted_unix_sock.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/different_creds.c b/test/zdtm/static/different_creds.c index af7aa3c6f..59fd1fa7f 100644 --- a/test/zdtm/static/different_creds.c +++ b/test/zdtm/static/different_creds.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/eventfs00.c b/test/zdtm/static/eventfs00.c index e05f514c4..72fd38a9c 100644 --- a/test/zdtm/static/eventfs00.c +++ b/test/zdtm/static/eventfs00.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include diff --git a/test/zdtm/static/fanotify00.c b/test/zdtm/static/fanotify00.c index 3084e1850..9fc3d7a3b 100644 --- a/test/zdtm/static/fanotify00.c +++ b/test/zdtm/static/fanotify00.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include diff --git a/test/zdtm/static/fdt_shared.c b/test/zdtm/static/fdt_shared.c index e66f9f56d..b1c74d0ae 100644 --- a/test/zdtm/static/fdt_shared.c +++ b/test/zdtm/static/fdt_shared.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include #include diff --git a/test/zdtm/static/fifo-rowo-pair.c b/test/zdtm/static/fifo-rowo-pair.c index b96714772..85aad027d 100644 --- a/test/zdtm/static/fifo-rowo-pair.c +++ b/test/zdtm/static/fifo-rowo-pair.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include diff --git a/test/zdtm/static/file_fown.c b/test/zdtm/static/file_fown.c index c0732e72a..f29ba45af 100644 --- a/test/zdtm/static/file_fown.c +++ b/test/zdtm/static/file_fown.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include diff --git a/test/zdtm/static/file_locks00.c b/test/zdtm/static/file_locks00.c index 82888709e..8a1ecc26f 100644 --- a/test/zdtm/static/file_locks00.c +++ b/test/zdtm/static/file_locks00.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/file_locks01.c b/test/zdtm/static/file_locks01.c index 24f54acc7..aadc5e422 100644 --- a/test/zdtm/static/file_locks01.c +++ b/test/zdtm/static/file_locks01.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/file_locks02.c b/test/zdtm/static/file_locks02.c index 2db3bd0a0..4e2e31b60 100644 --- a/test/zdtm/static/file_locks02.c +++ b/test/zdtm/static/file_locks02.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/file_locks03.c b/test/zdtm/static/file_locks03.c index 167fd2e19..9d5f198ef 100644 --- a/test/zdtm/static/file_locks03.c +++ b/test/zdtm/static/file_locks03.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/file_locks04.c b/test/zdtm/static/file_locks04.c index 28ed497b8..96170d51e 100644 --- a/test/zdtm/static/file_locks04.c +++ b/test/zdtm/static/file_locks04.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/file_locks05.c b/test/zdtm/static/file_locks05.c index f7d34b19e..33877f842 100644 --- a/test/zdtm/static/file_locks05.c +++ b/test/zdtm/static/file_locks05.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/file_locks06.c b/test/zdtm/static/file_locks06.c index 8eafa7c58..53f088f0d 100644 --- a/test/zdtm/static/file_locks06.c +++ b/test/zdtm/static/file_locks06.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/file_locks07.c b/test/zdtm/static/file_locks07.c index 25051b925..8bd517491 100644 --- a/test/zdtm/static/file_locks07.c +++ b/test/zdtm/static/file_locks07.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/file_locks08.c b/test/zdtm/static/file_locks08.c index 7963704da..a654c205b 100644 --- a/test/zdtm/static/file_locks08.c +++ b/test/zdtm/static/file_locks08.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/groups.c b/test/zdtm/static/groups.c index f7548eacf..01ec3a12b 100644 --- a/test/zdtm/static/groups.c +++ b/test/zdtm/static/groups.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/helper_zombie_child.c b/test/zdtm/static/helper_zombie_child.c index 1e6b4bda7..657d56f27 100644 --- a/test/zdtm/static/helper_zombie_child.c +++ b/test/zdtm/static/helper_zombie_child.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/inotify00.c b/test/zdtm/static/inotify00.c index 00190dc58..3c7cab0a7 100644 --- a/test/zdtm/static/inotify00.c +++ b/test/zdtm/static/inotify00.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include diff --git a/test/zdtm/static/inotify02.c b/test/zdtm/static/inotify02.c index eca36dde8..9b343a873 100644 --- a/test/zdtm/static/inotify02.c +++ b/test/zdtm/static/inotify02.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include diff --git a/test/zdtm/static/inotify_irmap.c b/test/zdtm/static/inotify_irmap.c index 872201018..cf35886e2 100644 --- a/test/zdtm/static/inotify_irmap.c +++ b/test/zdtm/static/inotify_irmap.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include diff --git a/test/zdtm/static/maps01.c b/test/zdtm/static/maps01.c index 024dff1fc..8940119ef 100644 --- a/test/zdtm/static/maps01.c +++ b/test/zdtm/static/maps01.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/mnt_ext_auto.c b/test/zdtm/static/mnt_ext_auto.c index 69d814939..947ea00cb 100644 --- a/test/zdtm/static/mnt_ext_auto.c +++ b/test/zdtm/static/mnt_ext_auto.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/mnt_ext_master.c b/test/zdtm/static/mnt_ext_master.c index c0ef7ad5f..f2c8e38d4 100644 --- a/test/zdtm/static/mnt_ext_master.c +++ b/test/zdtm/static/mnt_ext_master.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include diff --git a/test/zdtm/static/mnt_tracefs.c b/test/zdtm/static/mnt_tracefs.c index 968658b5b..99d60870a 100644 --- a/test/zdtm/static/mnt_tracefs.c +++ b/test/zdtm/static/mnt_tracefs.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/mntns_deleted.c b/test/zdtm/static/mntns_deleted.c index b38d8340b..39f9d0b47 100644 --- a/test/zdtm/static/mntns_deleted.c +++ b/test/zdtm/static/mntns_deleted.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/mntns_ghost.c b/test/zdtm/static/mntns_ghost.c index dca0c3450..e0d31572a 100644 --- a/test/zdtm/static/mntns_ghost.c +++ b/test/zdtm/static/mntns_ghost.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/mntns_link_remap.c b/test/zdtm/static/mntns_link_remap.c index a148a9e0c..642641b16 100644 --- a/test/zdtm/static/mntns_link_remap.c +++ b/test/zdtm/static/mntns_link_remap.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/mntns_open.c b/test/zdtm/static/mntns_open.c index 629d76275..e19c4ea72 100644 --- a/test/zdtm/static/mntns_open.c +++ b/test/zdtm/static/mntns_open.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/mntns_overmount.c b/test/zdtm/static/mntns_overmount.c index 541355c54..aa297a055 100644 --- a/test/zdtm/static/mntns_overmount.c +++ b/test/zdtm/static/mntns_overmount.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/mntns_remap.c b/test/zdtm/static/mntns_remap.c index f7cdba443..fd62cbf40 100644 --- a/test/zdtm/static/mntns_remap.c +++ b/test/zdtm/static/mntns_remap.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/mntns_ro_root.c b/test/zdtm/static/mntns_ro_root.c index 365be50e0..8415eec30 100644 --- a/test/zdtm/static/mntns_ro_root.c +++ b/test/zdtm/static/mntns_ro_root.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/mntns_root_bind.c b/test/zdtm/static/mntns_root_bind.c index 3bd0bece0..3f15a2726 100644 --- a/test/zdtm/static/mntns_root_bind.c +++ b/test/zdtm/static/mntns_root_bind.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/mntns_shared_bind.c b/test/zdtm/static/mntns_shared_bind.c index f11b2df98..ef48bd8a2 100644 --- a/test/zdtm/static/mntns_shared_bind.c +++ b/test/zdtm/static/mntns_shared_bind.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/mntns_shared_bind03.c b/test/zdtm/static/mntns_shared_bind03.c index 32d08691f..e75fe6297 100644 --- a/test/zdtm/static/mntns_shared_bind03.c +++ b/test/zdtm/static/mntns_shared_bind03.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/mntns_shared_vs_private.c b/test/zdtm/static/mntns_shared_vs_private.c index 771480b83..5849bbbdb 100644 --- a/test/zdtm/static/mntns_shared_vs_private.c +++ b/test/zdtm/static/mntns_shared_vs_private.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/mountpoints.c b/test/zdtm/static/mountpoints.c index ba88cd99c..17fa9311c 100644 --- a/test/zdtm/static/mountpoints.c +++ b/test/zdtm/static/mountpoints.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/msgque.c b/test/zdtm/static/msgque.c index a855bec36..6bbb103bd 100644 --- a/test/zdtm/static/msgque.c +++ b/test/zdtm/static/msgque.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include diff --git a/test/zdtm/static/pid00.c b/test/zdtm/static/pid00.c index 0b03ef596..e40bf73ae 100644 --- a/test/zdtm/static/pid00.c +++ b/test/zdtm/static/pid00.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/proc-self.c b/test/zdtm/static/proc-self.c index 54cc5f1f3..8292c08cc 100644 --- a/test/zdtm/static/proc-self.c +++ b/test/zdtm/static/proc-self.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include diff --git a/test/zdtm/static/remap_dead_pid.c b/test/zdtm/static/remap_dead_pid.c index b46fd2b0b..1ee61a9d0 100644 --- a/test/zdtm/static/remap_dead_pid.c +++ b/test/zdtm/static/remap_dead_pid.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/sem.c b/test/zdtm/static/sem.c index c3603cb3c..6e459a883 100644 --- a/test/zdtm/static/sem.c +++ b/test/zdtm/static/sem.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include diff --git a/test/zdtm/static/session00.c b/test/zdtm/static/session00.c index 2c79f0391..5889a92b9 100644 --- a/test/zdtm/static/session00.c +++ b/test/zdtm/static/session00.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/session01.c b/test/zdtm/static/session01.c index 9bea83d92..155e9a460 100644 --- a/test/zdtm/static/session01.c +++ b/test/zdtm/static/session01.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/session02.c b/test/zdtm/static/session02.c index 024585202..37f245d2e 100644 --- a/test/zdtm/static/session02.c +++ b/test/zdtm/static/session02.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/session03.c b/test/zdtm/static/session03.c index 2504d0179..04fb83461 100644 --- a/test/zdtm/static/session03.c +++ b/test/zdtm/static/session03.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/shm-mp.c b/test/zdtm/static/shm-mp.c index e29904f3a..084796ae2 100644 --- a/test/zdtm/static/shm-mp.c +++ b/test/zdtm/static/shm-mp.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/shm.c b/test/zdtm/static/shm.c index fc90a9955..d03332135 100644 --- a/test/zdtm/static/shm.c +++ b/test/zdtm/static/shm.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include diff --git a/test/zdtm/static/sigaltstack.c b/test/zdtm/static/sigaltstack.c index 71b316ab2..3ccd18277 100644 --- a/test/zdtm/static/sigaltstack.c +++ b/test/zdtm/static/sigaltstack.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/signalfd00.c b/test/zdtm/static/signalfd00.c index 5a1527382..61b1f0398 100644 --- a/test/zdtm/static/signalfd00.c +++ b/test/zdtm/static/signalfd00.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include diff --git a/test/zdtm/static/sigpending.c b/test/zdtm/static/sigpending.c index 70c2580a1..4adcfa626 100644 --- a/test/zdtm/static/sigpending.c +++ b/test/zdtm/static/sigpending.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/sk-unix-rel.c b/test/zdtm/static/sk-unix-rel.c index d341ce9af..f69a81697 100644 --- a/test/zdtm/static/sk-unix-rel.c +++ b/test/zdtm/static/sk-unix-rel.c @@ -1,6 +1,4 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/sock_peercred.c b/test/zdtm/static/sock_peercred.c index 1a9cfe20b..e681ecec9 100644 --- a/test/zdtm/static/sock_peercred.c +++ b/test/zdtm/static/sock_peercred.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/socket-ext.c b/test/zdtm/static/socket-ext.c index 46bf6c9ff..4e550534b 100644 --- a/test/zdtm/static/socket-ext.c +++ b/test/zdtm/static/socket-ext.c @@ -1,6 +1,4 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/socket-tcp.c b/test/zdtm/static/socket-tcp.c index 02f4c559b..19dc53b85 100644 --- a/test/zdtm/static/socket-tcp.c +++ b/test/zdtm/static/socket-tcp.c @@ -1,6 +1,3 @@ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif #include "zdtmtst.h" #ifdef ZDTM_IPV6 diff --git a/test/zdtm/static/socket_dgram_data.c b/test/zdtm/static/socket_dgram_data.c index 7464a46ac..9437d44a3 100644 --- a/test/zdtm/static/socket_dgram_data.c +++ b/test/zdtm/static/socket_dgram_data.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/socket_queues.c b/test/zdtm/static/socket_queues.c index 486d12a58..375b449e0 100644 --- a/test/zdtm/static/socket_queues.c +++ b/test/zdtm/static/socket_queues.c @@ -1,6 +1,4 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/socket_snd_addr.c b/test/zdtm/static/socket_snd_addr.c index 1d72d4e4a..fa587a03e 100644 --- a/test/zdtm/static/socket_snd_addr.c +++ b/test/zdtm/static/socket_snd_addr.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/static/sockets00.c b/test/zdtm/static/sockets00.c index 9d0095740..a9558d7ad 100644 --- a/test/zdtm/static/sockets00.c +++ b/test/zdtm/static/sockets00.c @@ -1,6 +1,4 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/sockets01.c b/test/zdtm/static/sockets01.c index a111e9d40..12650536f 100644 --- a/test/zdtm/static/sockets01.c +++ b/test/zdtm/static/sockets01.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/sockets02.c b/test/zdtm/static/sockets02.c index a7bec03f7..ed4afbbe0 100644 --- a/test/zdtm/static/sockets02.c +++ b/test/zdtm/static/sockets02.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/sockets03.c b/test/zdtm/static/sockets03.c index 9247d16a7..309e7a080 100644 --- a/test/zdtm/static/sockets03.c +++ b/test/zdtm/static/sockets03.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/sockets_dgram.c b/test/zdtm/static/sockets_dgram.c index a34bb144c..952453d01 100644 --- a/test/zdtm/static/sockets_dgram.c +++ b/test/zdtm/static/sockets_dgram.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/sockets_spair.c b/test/zdtm/static/sockets_spair.c index f2c916f34..ed9ffa94f 100644 --- a/test/zdtm/static/sockets_spair.c +++ b/test/zdtm/static/sockets_spair.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/tempfs_subns.c b/test/zdtm/static/tempfs_subns.c index 413d0a1e2..42195b57c 100644 --- a/test/zdtm/static/tempfs_subns.c +++ b/test/zdtm/static/tempfs_subns.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include #include diff --git a/test/zdtm/static/utsname.c b/test/zdtm/static/utsname.c index 5e1e0cb88..964548a8f 100644 --- a/test/zdtm/static/utsname.c +++ b/test/zdtm/static/utsname.c @@ -36,7 +36,7 @@ int main(int argc, char **argv) fail("Nodename doesn't match"); return 1; } - if (strcmp(ZDTM_DOMAIN, after.__domainname)) { + if (strcmp(ZDTM_DOMAIN, after.domainname)) { fail("Domainname doesn't match"); return 1; } diff --git a/test/zdtm/static/vt.c b/test/zdtm/static/vt.c index ab688402e..0db0f2cd8 100644 --- a/test/zdtm/static/vt.c +++ b/test/zdtm/static/vt.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include diff --git a/test/zdtm/static/xids00.c b/test/zdtm/static/xids00.c index c3ddfb483..0e8f324f6 100644 --- a/test/zdtm/static/xids00.c +++ b/test/zdtm/static/xids00.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/transition/ipc.c b/test/zdtm/transition/ipc.c index 4affe04b2..be52d7396 100644 --- a/test/zdtm/transition/ipc.c +++ b/test/zdtm/transition/ipc.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include diff --git a/test/zdtm/transition/maps008.c b/test/zdtm/transition/maps008.c index ce4b4f411..a89309d2f 100644 --- a/test/zdtm/transition/maps008.c +++ b/test/zdtm/transition/maps008.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/test/zdtm/transition/shmem.c b/test/zdtm/transition/shmem.c index 5cca2744a..56b0f678b 100644 --- a/test/zdtm/transition/shmem.c +++ b/test/zdtm/transition/shmem.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include From 71d93a5a454147d0de353bdbfed4343aa92f0ca2 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 3 Apr 2017 19:19:33 +0300 Subject: [PATCH 0464/4375] shmem: Split some routines Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/shmem.c | 61 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/criu/shmem.c b/criu/shmem.c index 586352a53..0d60d2f6b 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -457,12 +457,12 @@ static int shmem_wait_and_open(int pid, struct shmem_info *si, VmaEntry *vi) return 0; } -static int restore_shmem_content(void *addr, struct shmem_info *si) +static int do_restore_shmem_content(void *addr, unsigned long size, unsigned long shmid) { int ret = 0; struct page_read pr; - ret = open_page_read(si->shmid, &pr, PR_SHMEM); + ret = open_page_read(shmid, &pr, PR_SHMEM); if (ret <= 0) return -1; @@ -477,7 +477,7 @@ static int restore_shmem_content(void *addr, struct shmem_info *si) vaddr = (unsigned long)decode_pointer(pr.pe->vaddr); nr_pages = pr.pe->nr_pages; - if (vaddr + nr_pages * PAGE_SIZE > si->size) + if (vaddr + nr_pages * PAGE_SIZE > size) break; pr.read_pages(&pr, vaddr, nr_pages, addr + vaddr, 0); @@ -487,6 +487,11 @@ static int restore_shmem_content(void *addr, struct shmem_info *si) return ret; } +static int restore_shmem_content(void *addr, struct shmem_info *si) +{ + return do_restore_shmem_content(addr, si->size, si->shmid); +} + static int open_shmem(int pid, struct vma_area *vma) { VmaEntry *vi = vma->e; @@ -658,32 +663,18 @@ static int next_data_segment(int fd, unsigned long pfn, return 0; } -static int dump_one_shmem(struct shmem_info *si) +static int do_dump_one_shmem(int fd, void *addr, struct shmem_info *si) { struct page_pipe *pp; struct page_xfer xfer; - int err, ret = -1, fd; - void *addr = NULL; + int err, ret = -1; unsigned long pfn, nrpages, next_data_pnf = 0, next_hole_pfn = 0; - pr_info("Dumping shared memory %ld\n", si->shmid); - - fd = open_proc(si->pid, "map_files/%lx-%lx", si->start, si->end); - if (fd < 0) - goto err; - - addr = mmap(NULL, si->size, PROT_READ, MAP_SHARED, fd, 0); - if (addr == MAP_FAILED) { - pr_err("Can't map shmem 0x%lx (0x%lx-0x%lx)\n", - si->shmid, si->start, si->end); - goto err; - } - nrpages = (si->size + PAGE_SIZE - 1) / PAGE_SIZE; pp = create_page_pipe((nrpages + 1) / 2, NULL, PP_CHUNK_MODE); if (!pp) - goto err_unmap; + goto err; err = open_page_xfer(&xfer, CR_FD_SHMEM_PAGEMAP, si->shmid); if (err) @@ -735,10 +726,34 @@ err_xfer: xfer.close(&xfer); err_pp: destroy_page_pipe(pp); -err_unmap: - munmap(addr, si->size); err: - close_safe(&fd); + return ret; +} + +static int dump_one_shmem(struct shmem_info *si) +{ + int fd, ret = -1; + void *addr; + + pr_info("Dumping shared memory %ld\n", si->shmid); + + fd = open_proc(si->pid, "map_files/%lx-%lx", si->start, si->end); + if (fd < 0) + goto err; + + addr = mmap(NULL, si->size, PROT_READ, MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { + pr_err("Can't map shmem 0x%lx (0x%lx-0x%lx)\n", + si->shmid, si->start, si->end); + goto errc; + } + + ret = do_dump_one_shmem(fd, addr, si); + + munmap(addr, si->size); +errc: + close(fd); +err: return ret; } From 0ba02b2cb5526ad3c4d572da8bfb2ad6e4880fc7 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 3 Apr 2017 19:19:48 +0300 Subject: [PATCH 0465/4375] ipcns: Split some routines Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/ipc_ns.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/criu/ipc_ns.c b/criu/ipc_ns.c index af1cb7c06..0fcee6880 100644 --- a/criu/ipc_ns.c +++ b/criu/ipc_ns.c @@ -777,18 +777,11 @@ err: return ret; } -static int prepare_ipc_shm_pages(struct cr_img *img, const IpcShmEntry *shm) +static int restore_content(void *data, struct cr_img *img, const IpcShmEntry *shm) { - void *data; int ifd; ssize_t size, off; - data = shmat(shm->desc->id, NULL, 0); - if (data == (void *)-1) { - pr_perror("Failed to attach IPC shared memory"); - return -errno; - } - ifd = img_raw_fd(img); size = round_up(shm->size, sizeof(u32)); off = 0; @@ -803,11 +796,28 @@ static int prepare_ipc_shm_pages(struct cr_img *img, const IpcShmEntry *shm) off += ret; } while (off < size); + + return 0; +} + +static int prepare_ipc_shm_pages(struct cr_img *img, const IpcShmEntry *shm) +{ + int ret; + void *data; + + data = shmat(shm->desc->id, NULL, 0); + if (data == (void *)-1) { + pr_perror("Failed to attach IPC shared memory"); + return -errno; + } + + ret = restore_content(data, img, shm); + if (shmdt(data)) { pr_perror("Failed to detach IPC shared memory"); return -errno; } - return 0; + return ret; } static int prepare_ipc_shm_seg(struct cr_img *img, const IpcShmEntry *shm) From 9d2e1dfebedfbb3229c6a7ef9a330ab7ebe001cf Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 3 Apr 2017 19:20:04 +0300 Subject: [PATCH 0466/4375] ipc: Keep shmem segments contents into pagemap/page images Right now the contents of the sysvipc shmem segment is stored as raw blob in the ipcns-shm image. This is bad for two reasons. First is that huge segments with holes are filled with real zeroes in image. Second is that we prefer not to mix images with pb object and raw data. To fix both let's re-use the shmem.c code that keeps anon shared memory contents in pagemap/pages images. https://github.com/xemul/criu/issues/287 Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/shmem.h | 2 ++ criu/ipc_ns.c | 41 +++++++++++------------------------------ criu/shmem.c | 32 +++++++++++++++++++++++++++++++- images/ipc-shm.proto | 1 + 4 files changed, 45 insertions(+), 31 deletions(-) diff --git a/criu/include/shmem.h b/criu/include/shmem.h index 63e7e9f63..04ab8d076 100644 --- a/criu/include/shmem.h +++ b/criu/include/shmem.h @@ -13,6 +13,8 @@ extern int collect_sysv_shmem(unsigned long shmid, unsigned long size); extern int cr_dump_shmem(void); extern int add_shmem_area(pid_t pid, VmaEntry *vma, u64 *map); extern int fixup_sysv_shmems(void); +extern int dump_one_sysv_shmem(void *addr, unsigned long size, unsigned long shmid); +extern int restore_sysv_shmem_content(void *addr, unsigned long size, unsigned long shmid); #define SYSV_SHMEM_SKIP_FD (0x7fffffff) diff --git a/criu/ipc_ns.c b/criu/ipc_ns.c index 0fcee6880..d8590fa39 100644 --- a/criu/ipc_ns.c +++ b/criu/ipc_ns.c @@ -338,15 +338,10 @@ static int ipc_sysctl_req(IpcVarEntry *e, int op) return sysctl_op(req, nr, op, CLONE_NEWIPC); } -/* - * TODO: Function below should be later improved to locate and dump only dirty - * pages via updated sys_mincore(). - */ -static int dump_ipc_shm_pages(struct cr_img *img, const IpcShmEntry *shm) +static int dump_ipc_shm_pages(const IpcShmEntry *shm) { + int ret; void *data; - int ifd; - ssize_t size, off; data = shmat(shm->desc->id, NULL, SHM_RDONLY); if (data == (void *)-1) { @@ -354,32 +349,13 @@ static int dump_ipc_shm_pages(struct cr_img *img, const IpcShmEntry *shm) return -errno; } - /* - * FIXME -- this just write the whole memory segment into the - * image. In case the segment is huge this takes time. Need - * to adopt the holes detection code (next_data_segment) from - * shmem.c - */ - ifd = img_raw_fd(img); - size = round_up(shm->size, sizeof(u32)); - off = 0; - do { - ssize_t ret; - - ret = write(ifd, data + off, size - off); - if (ret <= 0) { - pr_perror("Failed to write IPC shared memory data"); - return (int)ret; - } - - off += ret; - } while (off < size); + ret = dump_one_sysv_shmem(data, shm->size, shm->desc->id); if (shmdt(data)) { pr_perror("Failed to detach IPC shared memory"); return -errno; } - return 0; + return ret; } static int dump_ipc_shm_seg(struct cr_img *img, int id, const struct shmid_ds *ds) @@ -390,6 +366,8 @@ static int dump_ipc_shm_seg(struct cr_img *img, int id, const struct shmid_ds *d shm.desc = &desc; shm.size = ds->shm_segsz; + shm.has_in_pagemaps = true; + shm.in_pagemaps = true; fill_ipc_desc(id, shm.desc, &ds->shm_perm); pr_info_ipc_shm(&shm); @@ -398,7 +376,7 @@ static int dump_ipc_shm_seg(struct cr_img *img, int id, const struct shmid_ds *d pr_err("Failed to write IPC shared memory segment\n"); return ret; } - return dump_ipc_shm_pages(img, &shm); + return dump_ipc_shm_pages(&shm); } static int dump_ipc_shm(struct cr_img *img) @@ -811,7 +789,10 @@ static int prepare_ipc_shm_pages(struct cr_img *img, const IpcShmEntry *shm) return -errno; } - ret = restore_content(data, img, shm); + if (shm->has_in_pagemaps && shm->in_pagemaps) + ret = restore_sysv_shmem_content(data, shm->size, shm->desc->id); + else + ret = restore_content(data, img, shm); if (shmdt(data)) { pr_perror("Failed to detach IPC shared memory"); diff --git a/criu/shmem.c b/criu/shmem.c index 0d60d2f6b..69165b64c 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -492,6 +492,11 @@ static int restore_shmem_content(void *addr, struct shmem_info *si) return do_restore_shmem_content(addr, si->size, si->shmid); } +int restore_sysv_shmem_content(void *addr, unsigned long size, unsigned long shmid) +{ + return do_restore_shmem_content(addr, round_up(size, PAGE_SIZE), shmid); +} + static int open_shmem(int pid, struct vma_area *vma) { VmaEntry *vi = vma->e; @@ -689,7 +694,7 @@ static int do_dump_one_shmem(int fd, void *addr, struct shmem_info *si) next_data_segment(fd, pfn, &next_data_pnf, &next_hole_pfn)) goto err_xfer; - if (is_shmem_tracking_en()) { + if (si->pstate_map && is_shmem_tracking_en()) { pgstate = get_pstate(si->pstate_map, pfn); use_mc = pgstate == PST_DONT_DUMP; } @@ -757,6 +762,31 @@ err: return ret; } +int dump_one_sysv_shmem(void *addr, unsigned long size, unsigned long shmid) +{ + int fd, ret; + struct shmem_info *si, det; + + si = shmem_find(shmid); + if (!si) { + pr_info("Detached shmem...\n"); + det.pid = SYSVIPC_SHMEM_PID; + det.shmid = shmid; + det.size = round_up(size, PAGE_SIZE); + det.pstate_map = NULL; + si = &det; + } + + fd = open_proc(PROC_SELF, "map_files/%lx-%lx", + (unsigned long)addr, (unsigned long)addr + si->size); + if (fd < 0) + return -1; + + ret = do_dump_one_shmem(fd, addr, si); + close(fd); + return ret; +} + int cr_dump_shmem(void) { int ret = 0, i; diff --git a/images/ipc-shm.proto b/images/ipc-shm.proto index 4f331d2c2..31e172eb8 100644 --- a/images/ipc-shm.proto +++ b/images/ipc-shm.proto @@ -5,4 +5,5 @@ import "ipc-desc.proto"; message ipc_shm_entry { required ipc_desc_entry desc = 1; required uint64 size = 2; + optional bool in_pagemaps = 3; } From bc169fefb1fa1460c33f4ffe5ea65c41901c7015 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 6 Apr 2017 17:03:30 +0200 Subject: [PATCH 0467/4375] RPC: add script to test the new RPC version interface This script connects to 'criu swrk' and asks for the version. If running from a git checkout the output would look like this: $ ./version.py Connecting to CRIU in swrk mode to check the version: RPC: Success CRIU major 2 CRIU minor 12 CRIU gitid v2.12-635-g6d3ae4d If not running from git checkout it looks like this: $ ./version.py Connecting to CRIU in swrk mode to check the version: RPC: Success CRIU major 2 CRIU minor 12 If running with a CRIU binary which does not support the VERSION command: $ ./version.py Connecting to CRIU in swrk mode to check the version: Error (cr-service.c:116): RPC error: Invalid req: Success RPC: Unexpected msg type Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/others/rpc/version.py | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100755 test/others/rpc/version.py diff --git a/test/others/rpc/version.py b/test/others/rpc/version.py new file mode 100755 index 000000000..93975f4ba --- /dev/null +++ b/test/others/rpc/version.py @@ -0,0 +1,48 @@ +#!/usr/bin/python2 + +import socket +import sys +import rpc_pb2 as rpc +import argparse +import subprocess + +print('Connecting to CRIU in swrk mode to check the version:') + +css = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) +swrk = subprocess.Popen(['./criu', "swrk", "%d" % css[0].fileno()]) +css[0].close() + +s = css[1] + +# Create criu msg, set it's type to dump request +# and set dump options. Checkout more options in protobuf/rpc.proto +req = rpc.criu_req() +req.type = rpc.VERSION + +# Send request +s.send(req.SerializeToString()) + +# Recv response +resp = rpc.criu_resp() +MAX_MSG_SIZE = 1024 +resp.ParseFromString(s.recv(MAX_MSG_SIZE)) + +if resp.type != rpc.VERSION: + print('RPC: Unexpected msg type') + sys.exit(-1) +else: + if resp.success: + print('RPC: Success') + print('CRIU major %d' % resp.version.major) + print('CRIU minor %d' % resp.version.minor) + if resp.version.HasField('gitid'): + print('CRIU gitid %s' % resp.version.gitid) + if resp.version.HasField('sublevel'): + print('CRIU sublevel %s' % resp.version.sublevel) + if resp.version.HasField('extra'): + print('CRIU extra %s' % resp.version.extra) + if resp.version.HasField('name'): + print('CRIU name %s' % resp.version.name) + else: + print 'Fail' + sys.exit(-1) From fe974169a56bec09d36f83485ca7b5a595ae4794 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 6 Apr 2017 17:03:29 +0200 Subject: [PATCH 0468/4375] RPC: add version check interface Instead of parsing the output of 'criu -V' this offers a RPC interface to get CRIU's version. In a follow up patch a test script is included to use the new interface: ./version.py Connecting to CRIU in swrk mode to check the version: RPC: Success CRIU major 2 CRIU minor 12 CRIU gitid v2.12-635-g6d3ae4d This change exports the following version fields: * major * minor * gitid (optional) * sublevel (optional) * extra (optional) * name (optional) The optional gitid field is not set when CRIU is not built from git. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-service.c | 39 +++++++++++++++++++++++++++++++++++++++ images/rpc.proto | 13 +++++++++++++ 2 files changed, 52 insertions(+) diff --git a/criu/cr-service.c b/criu/cr-service.c index d5b3848ac..49cbe682f 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -15,6 +15,7 @@ #include #include +#include "version.h" #include "crtools.h" #include "cr_options.h" #include "external.h" @@ -799,10 +800,45 @@ static int chk_keepopen_req(CriuReq *msg) return 0; else if (msg->type == CRIU_REQ_TYPE__FEATURE_CHECK) return 0; + else if (msg->type == CRIU_REQ_TYPE__VERSION) + return 0; return -1; } +/* + * Return the version information, depending on the information + * available in version.h + */ +static int handle_version(int sk, CriuReq * msg) +{ + CriuResp resp = CRIU_RESP__INIT; + CriuVersion version = CRIU_VERSION__INIT; + + /* This assumes we will always have a major and minor version */ + version.major = CRIU_VERSION_MAJOR; + version.minor = CRIU_VERSION_MINOR; + if (strcmp(CRIU_GITID, "0")) { + version.gitid = CRIU_GITID; + } +#ifdef CRIU_VERSION_SUBLEVEL + version.has_sublevel = 1; + version.sublevel = CRIU_VERSION_SUBLEVEL; +#endif +#ifdef CRIU_VERSION_EXTRA + version.has_extra = 1; + version.extra = CRIU_VERSION_EXTRA; +#endif +#ifdef CRIU_VERSION_NAME + /* This is not actually exported in version.h */ + version.name = CRIU_VERSION_NAME; +#endif + resp.type = msg->type; + resp.success = true; + resp.version = &version; + return send_criu_msg(sk, &resp); +} + /* * Generic function to handle CRIU_REQ_TYPE__FEATURE_CHECK. * @@ -969,6 +1005,9 @@ more: case CRIU_REQ_TYPE__FEATURE_CHECK: ret = handle_feature_check(sk, msg); break; + case CRIU_REQ_TYPE__VERSION: + ret = handle_version(sk, msg); + break; default: send_criu_err(sk, "Invalid req"); diff --git a/images/rpc.proto b/images/rpc.proto index 394469ad8..2c65617aa 100644 --- a/images/rpc.proto +++ b/images/rpc.proto @@ -139,6 +139,8 @@ enum criu_req_type { CPUINFO_CHECK = 8; FEATURE_CHECK = 9; + + VERSION = 10; } /* @@ -191,4 +193,15 @@ message criu_resp { optional int32 cr_errno = 7; optional criu_features features = 8; optional string cr_errmsg = 9; + optional criu_version version = 10; +} + +/* Answer for criu_req_type.VERSION requests */ +message criu_version { + required int32 major = 1; + required int32 minor = 2; + optional string gitid = 3; + optional int32 sublevel = 4; + optional int32 extra = 5; + optional string name = 6; } From 5e3509ba1649a5a7a5b6cd807dc672d08fa696f0 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Apr 2017 14:02:00 +0300 Subject: [PATCH 0469/4375] crit: Decode some numbers into strings There are several places in image files, where we store integers, but these numbers actually mean some string. E.g. socket families, states and types and tasks states. So here's the (criu).dict option for such fields that helps to convert the numbers into strings and back. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- images/core.proto | 2 +- images/opts.proto | 1 + images/sk-inet.proto | 8 ++++---- images/sk-unix.proto | 4 ++-- lib/py/images/pb2dict.py | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/images/core.proto b/images/core.proto index 14f13f8b9..9c2254d32 100644 --- a/images/core.proto +++ b/images/core.proto @@ -23,7 +23,7 @@ enum seccomp_mode { }; message task_core_entry { - required uint32 task_state = 1; + required uint32 task_state = 1 [(criu).dict = "gen"]; required uint32 exit_code = 2; required uint32 personality = 3; diff --git a/images/opts.proto b/images/opts.proto index 380d54ae0..a2cdd754c 100644 --- a/images/opts.proto +++ b/images/opts.proto @@ -8,6 +8,7 @@ message CRIU_Opts { optional string flags = 3; optional bool dev = 4; // Device major:minor packed optional bool odev = 5; // ... in old format + optional string dict = 6; } extend google.protobuf.FieldOptions { diff --git a/images/sk-inet.proto b/images/sk-inet.proto index 177f83fca..30f0134b0 100644 --- a/images/sk-inet.proto +++ b/images/sk-inet.proto @@ -19,10 +19,10 @@ message inet_sk_entry { */ required uint32 id = 1; required uint32 ino = 2; - required uint32 family = 3; - required uint32 type = 4; - required uint32 proto = 5; - required uint32 state = 6; + required uint32 family = 3 [(criu).dict = "sk"]; + required uint32 type = 4 [(criu).dict = "sk"]; + required uint32 proto = 5 [(criu).dict = "sk"]; + required uint32 state = 6 [(criu).dict = "sk"]; required uint32 src_port = 7; required uint32 dst_port = 8; required uint32 flags = 9 [(criu).hex = true]; diff --git a/images/sk-unix.proto b/images/sk-unix.proto index 3026214bf..8c0176beb 100644 --- a/images/sk-unix.proto +++ b/images/sk-unix.proto @@ -24,8 +24,8 @@ message unix_sk_entry { */ required uint32 id = 1; required uint32 ino = 2; - required uint32 type = 3; - required uint32 state = 4; + required uint32 type = 3 [(criu).dict = "sk"]; + required uint32 state = 4 [(criu).dict = "sk"]; required uint32 flags = 5 [(criu).hex = true]; required uint32 uflags = 6 [(criu).hex = true]; required uint32 backlog = 7; diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index 177cda315..2ce40cdaf 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -57,6 +57,9 @@ def _marked_as_dev(field): def _marked_as_odev(field): return field.GetOptions().Extensions[opts_pb2.criu].odev +def _marked_as_dict(field): + return field.GetOptions().Extensions[opts_pb2.criu].dict + mmap_prot_map = [ ('PROT_READ', 0x1), ('PROT_WRITE', 0x2), @@ -106,6 +109,25 @@ flags_maps = { 'rfile.flags' : rfile_flags_map, } +gen_maps = { + 'task_state' : { 1: 'Alive', 3: 'Zombie', 6: 'Stopped' }, +} + +sk_maps = { + 'family' : { 2: 'INET' }, + 'type' : { 1: 'STREAM', 2: 'DGRAM' }, + 'state' : { 1: 'ESTABLISHED', 7: 'CLOSE', 10: 'LISTEN' }, + 'proto' : { 6: 'TCP' }, +} + +gen_rmaps = { k: {v2:k2 for k2,v2 in v.items()} for k,v in gen_maps.items() } +sk_rmaps = { k: {v2:k2 for k2,v2 in v.items()} for k,v in sk_maps.items() } + +dict_maps = { + 'gen' : ( gen_maps, gen_rmaps ), + 'sk' : ( sk_maps, sk_rmaps ), +} + def map_flags(value, flags_map): bs = map(lambda x: x[0], filter(lambda x: value & x[1], flags_map)) value &= ~sum(map(lambda x: x[1], flags_map)) @@ -168,6 +190,10 @@ def _pb2dict_cast(field, value, pretty = False, is_hex = False): else: return map_flags(value, flags_map) + dct = _marked_as_dict(field) + if dct: + return dict_maps[dct][0][field.name].get(value, cast(value)) + return cast(value) else: raise Exception("Field(%s) has unsupported type %d" % (field.name, field.type)) @@ -225,6 +251,13 @@ def _dict2pb_cast(field, value): else: return unmap_flags(value, flags_map) + dct = _marked_as_dict(field) + if dct: + ret = dict_maps[dct][1][field.name].get(value, None) + if ret == None: + ret = cast(value, 0) + return ret + # Some int or long fields might be stored as hex # strings. See _pb2dict_cast. return cast(value, 0) From e77d36c375ce4ea4fb2f5c22d949fa58766879fb Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Apr 2017 14:02:43 +0300 Subject: [PATCH 0470/4375] crit: Beautify unix names recode Unix socket name can be a string with any bytes in it. So to print the name we use base64 encoding. Doing so doesn't allow to see the socket name when it contains only printable chars. So here's the custom encoding for bytes fields, that can be used for custom conversion. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- images/opts.proto | 1 + images/sk-unix.proto | 2 +- lib/py/images/pb2dict.py | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/images/opts.proto b/images/opts.proto index a2cdd754c..70c7fd481 100644 --- a/images/opts.proto +++ b/images/opts.proto @@ -9,6 +9,7 @@ message CRIU_Opts { optional bool dev = 4; // Device major:minor packed optional bool odev = 5; // ... in old format optional string dict = 6; + optional string conv = 7; } extend google.protobuf.FieldOptions { diff --git a/images/sk-unix.proto b/images/sk-unix.proto index 8c0176beb..76e006ddd 100644 --- a/images/sk-unix.proto +++ b/images/sk-unix.proto @@ -37,7 +37,7 @@ message unix_sk_entry { * Abstract name may contain \0 at any point, * so we need to carry it as byte sequence... */ - required bytes name = 11; + required bytes name = 11 [(criu).conv = "unix_name"]; optional sk_shutdown shutdown = 12; diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index 2ce40cdaf..4e89e8e04 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -60,6 +60,9 @@ def _marked_as_odev(field): def _marked_as_dict(field): return field.GetOptions().Extensions[opts_pb2.criu].dict +def _custom_conv(field): + return field.GetOptions().Extensions[opts_pb2.criu].conv + mmap_prot_map = [ ('PROT_READ', 0x1), ('PROT_WRITE', 0x2), @@ -157,6 +160,33 @@ def encode_dev(field, value): else: return dev[0] << kern_minorbits | dev[1] +def encode_base64(value): + return value.encode('base64') +def decode_base64(value): + return value.decode('base64') + +def encode_unix(value): + return value.encode('quopri') +def decode_unix(value): + return value.decode('quopri') + +encode = { 'unix_name': encode_unix } +decode = { 'unix_name': decode_unix } + +def get_bytes_enc(field): + c = _custom_conv(field) + if c: + return encode[c] + else: + return encode_base64 + +def get_bytes_dec(field): + c = _custom_conv(field) + if c: + return decode[c] + else: + return decode_base64 + def is_string(value): return isinstance(value, unicode) or isinstance(value, str) @@ -167,7 +197,7 @@ def _pb2dict_cast(field, value, pretty = False, is_hex = False): if field.type == FD.TYPE_MESSAGE: return pb2dict(value, pretty, is_hex) elif field.type == FD.TYPE_BYTES: - return value.encode('base64') + return get_bytes_enc(field)(value) elif field.type == FD.TYPE_ENUM: return field.enum_type.values_by_number.get(value, None).name elif field.type in _basic_cast: @@ -233,7 +263,7 @@ def _dict2pb_cast(field, value): # and non-repeated messages need special treatment # in this case, and are hadled separately. if field.type == FD.TYPE_BYTES: - return value.decode('base64') + return get_bytes_dec(field)(value) elif field.type == FD.TYPE_ENUM: return field.enum_type.values_by_name.get(value, None).number elif field.type in _basic_cast: From ab33ae2d95359cabb9e211127c64fe2016e79f96 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 10 Apr 2017 22:41:50 +0300 Subject: [PATCH 0471/4375] test/maps01: document mmap() failures Arm32 devices often have poor amount of RAM. E.g., RPI2 board has only 1Gb memory. This lead to failures with maps01 test, which tries to mmap() 1Gb of memory. The failures of test is not very evident - let's document mmap() errors here to blow some light on the situation. Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/maps01.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/test/zdtm/static/maps01.c b/test/zdtm/static/maps01.c index 8940119ef..119d7a6a4 100644 --- a/test/zdtm/static/maps01.c +++ b/test/zdtm/static/maps01.c @@ -11,10 +11,10 @@ #include #include "zdtmtst.h" -#define MEM_SIZE (1L << 30) -#define MEM_OFFSET (1L << 29) +#define MEM_SIZE (1LU << 30) +#define MEM_OFFSET (1LU << 29) #define MEM_OFFSET2 (MEM_SIZE - PAGE_SIZE) -#define MEM_OFFSET3 (20 * PAGE_SIZE) +#define MEM_OFFSET3 (20LU * PAGE_SIZE) const char *test_doc = "Test shared memory"; const char *test_author = "Andrew Vagin > 20); goto err; + } p = mmap(NULL, MEM_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - if (p == MAP_FAILED) + if (p == MAP_FAILED) { + pr_err("Failed to mmap %ld Mb shared anonymous R/W memory\n", + MEM_SIZE >> 20); goto err; + } p2 = mmap(NULL, MEM_OFFSET, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (p2 == MAP_FAILED) + if (p2 == MAP_FAILED) { + pr_err("Failed to mmap %lu Mb anonymous memory\n", + MEM_OFFSET >> 20); goto err; + } pid = test_fork(); if (pid < 0) { + pr_err("Fork failed with %d\n", pid); goto err; } else if (pid == 0) { void *p3; p3 = mmap(NULL, MEM_OFFSET3, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (p3 == MAP_FAILED) + if (p3 == MAP_FAILED) { + pr_err("Failed to mmap %lu Mb anonymous R/W memory\n", + MEM_OFFSET3 >> 20); goto err; + } crc = ~0; datagen(m + MEM_OFFSET, PAGE_SIZE, &crc); From 692da1485aac3edee8865b8206a4c64cf8181e53 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 10 Apr 2017 22:41:51 +0300 Subject: [PATCH 0472/4375] arm/compel: add generated headers to .gitignore [criu]# git status -s ?? compel/arch/arm/plugins/std/syscalls/syscalls.S ?? compel/plugins/include/uapi/std/syscall-aux.S ?? compel/plugins/include/uapi/std/syscall-aux.h Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/.gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compel/.gitignore b/compel/.gitignore index c254402c3..5b6886325 100644 --- a/compel/.gitignore +++ b/compel/.gitignore @@ -1,8 +1,11 @@ arch/x86/plugins/std/sys-exec-tbl-64.c arch/x86/plugins/std/syscalls-64.S +arch/arm/plugins/std/syscalls/syscalls.S include/version.h plugins/include/uapi/std/asm/syscall-types.h plugins/include/uapi/std/syscall-64.h plugins/include/uapi/std/syscall-codes-64.h plugins/include/uapi/std/syscall-codes.h plugins/include/uapi/std/syscall.h +plugins/include/uapi/std/syscall-aux.h +plugins/include/uapi/std/syscall-aux.S From 057c3f2947aae5699cfb0e2b4904be0c6500fc50 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 10 Apr 2017 22:41:52 +0300 Subject: [PATCH 0473/4375] python: specify python2 as .py interpreter On some distro the default python interpreter is Python 3, which results in such errors: > Running zdtm/static/socket-tcp-closed.hook(--post-start) > make[1]: Nothing to be done for default. > ./socket-tcp-closed --pidfile=socket-tcp-closed.pid --outfile=socket-tcp-closed.out > File "zdtm/static/socket-tcp-closed.hook", line 16 > except OSError, e: > ^ > SyntaxError: invalid syntax > ######### Test zdtm/static/socket-tcp-closed FAIL at hook --post-start ######### > Running zdtm/static/socket-tcp-closed.hook(--clean) > File "zdtm/static/socket-tcp-closed.hook", line 16 > except OSError, e: > ^ > SyntaxError: invalid syntax > Traceback (most recent call last): > File "zdtm.py", line 1921, in > do_run_test(tinfo[0], tinfo[1], tinfo[2], tinfo[3]) > File "zdtm.py", line 1388, in do_run_test > try_run_hook(t, ["--clean"]) > File "zdtm.py", line 1053, in try_run_hook > raise test_fail_exc("hook " + " ".join(args)) > __main__.test_fail_exc: <__main__.test_fail_exc instance at 0x76294468> Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- coredump/criu-coredump | 2 +- crit/crit | 2 +- lib/py/images/images.py | 2 +- scripts/magic-gen.py | 2 +- test/check_actions.py | 2 +- test/others/ext-tty/run.py | 2 +- test/zdtm/static/socket-tcp-fin-wait1.hook | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/coredump/criu-coredump b/coredump/criu-coredump index b667e862a..25c188c6b 100755 --- a/coredump/criu-coredump +++ b/coredump/criu-coredump @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 import argparse import os diff --git a/crit/crit b/crit/crit index cc3f5ab22..8b1e19bb9 100755 --- a/crit/crit +++ b/crit/crit @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 import argparse import sys import json diff --git a/lib/py/images/images.py b/lib/py/images/images.py index c593a3b85..0edbe80ea 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -1,4 +1,4 @@ -#!/bin/env python +#!/bin/env python2 # This file contains methods to deal with criu images. # diff --git a/scripts/magic-gen.py b/scripts/magic-gen.py index 6719e4c3e..319e99812 100755 --- a/scripts/magic-gen.py +++ b/scripts/magic-gen.py @@ -1,4 +1,4 @@ -#!/bin/env python +#!/bin/env python2 import os, sys import struct diff --git a/test/check_actions.py b/test/check_actions.py index 70d257fbd..96c07a758 100755 --- a/test/check_actions.py +++ b/test/check_actions.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 import sys import os diff --git a/test/others/ext-tty/run.py b/test/others/ext-tty/run.py index 3806d5043..052f9c1a1 100755 --- a/test/others/ext-tty/run.py +++ b/test/others/ext-tty/run.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 import subprocess import os, sys, time, signal, pty diff --git a/test/zdtm/static/socket-tcp-fin-wait1.hook b/test/zdtm/static/socket-tcp-fin-wait1.hook index ae0b51d39..9630e0d74 100755 --- a/test/zdtm/static/socket-tcp-fin-wait1.hook +++ b/test/zdtm/static/socket-tcp-fin-wait1.hook @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 import sys sys.path.append("../crit") From d7c86c8b024f622ae27766ee97970aaa26e50f2f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 10 Apr 2017 22:41:53 +0300 Subject: [PATCH 0474/4375] arm32/Makefile: fix readable mappings getting +x Flag `noexecstack' for ld implies `EXSTACK_DISABLE_X' ELF flag on CRIU binary. Without this flag the kernel ELF loader will set `READ_IMPLIES_EXEC' personality bit: > if (elf_read_implies_exec(loc->elf_ex, executable_stack)) > current->personality |= READ_IMPLIES_EXEC; This flag is checked by sys_mmap(): > if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC)) > if (!(file && path_noexec(&file->f_path))) > prot |= PROT_EXEC; Which results in each mmap() syscall returning +x mapping for any readable mapping for CRIU binary, e.g: Before C/R: 76fc4000-76fc5000 r--p 0001f000 b3:02 131656 /usr/lib/ld-2.25.so 76fc5000-76fc6000 rw-p 00020000 b3:02 131656 /usr/lib/ld-2.25.so After restore: 76fc4000-76fc5000 r-xp 0001f000 b3:02 131656 /usr/lib/ld-2.25.so 76fc5000-76fc6000 rwxp 00020000 b3:02 131656 /usr/lib/ld-2.25.so Which also makes ZDTM very sad: 1: Old maps lost: set(["76f80000-76f81000 ['rw-p', '0120400']", "25000-26000 ['rw-p', '0120400']", "76f7d000-76f7f000 ['rw-p']", "14a8000-14c9000 ['rw-p']", "76f4a000-76f4c000 ['r--p', '0120400']", "7ed3d000-7ed7f000 ['rw-p']", "76f7f000-76f80000 ['r--p', '0120400']", "24000-25000 ['r--p', '0120400']", "76f4c000-76f50000 ['rw-p', '0120400']"]) 1: New maps appeared: set(["76f7f000-76f80000 ['r-xp', '0120400']", "7ed3d000-7ed7f000 ['rwxp']", "76f4a000-76f4c000 ['r-xp', '0120400']", "76f80000-76f81000 ['rwxp', '0120400']", "24000-25000 ['r-xp', '0120400']", "14a8000-14c9000 ['rwxp']", "25000-26000 ['rwxp', '0120400']", "76f7d000-76f7f000 ['rwxp']", "76f4c000-76f50000 ['rwxp', '0120400']"]) Maybe we also need to set it for arm64 or even for all archs, but that needs to be tested in the first place, so add it now to arm32, x86 already has it. Acked-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/arm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/arch/arm/Makefile b/criu/arch/arm/Makefile index d79ab6238..d01c69a16 100644 --- a/criu/arch/arm/Makefile +++ b/criu/arch/arm/Makefile @@ -5,7 +5,7 @@ ccflags-y += -iquote criu/include -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) asflags-y += -D__ASSEMBLY__ -ldflags-y += -r +ldflags-y += -r -z noexecstack obj-y += cpu.o obj-y += crtools.o From e98d16e77df30730cf8587b776629203e9aa3b15 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 12 Apr 2017 20:29:34 +0300 Subject: [PATCH 0475/4375] arm: Workaround shmat() page coloring alignment Please, see incode comment about the issue. There was an attempt to fix this feature in kernel: http://www.spinics.net/lists/arm-kernel/msg258870.html I'll send a patch for kernel with a correct justification. Still it's worth to workaround this on older kernels. mremap() after shmat() makes it possible to C/R shmem between ARMv7 CPUs. Without it C/R will fail even on the same platform. That is possible that this workaround changes *restore failure* to *corruption* in shared memory after restore. Still, I think it's worth to be applied by the following reasons: 1. All ARMv7 CPUs do not have VIPT aliasing data cache. And ARMv6 CPUs may have any, but they are not popular because of UMP. 2. SysV IPC shmem should be writable and SHMLBA unaligned (if it's only readable, then it's OK). 3. For the data corruption we need to migrate from non-VIPT cached CPUs to VIPT aliasing. 4. As this is shmem migration between platforms - quite likely we have it`s copy (in case of whole IPC namespace dump - in images). 5. C/R before on the same CPU may fail (quite likely, more than 50% of zdtm/transition/ipc failed while I've test it). So, I think it's very unlikely that someone uses CRIU to migrate from ARMv7 to ARMv6 unaligned writable shmem, but if he is - here is a BIG WARNING on restore. And after all: we've restored application as it was on checkpoint, we can't reliably tell that shmem needs align on the target platform, but we warned on restoring. I wanted to test the cpuid for VIPT caching firstly, but it's in cp15 coprocessor, which means it's unavailable from userspace. Only one reliable way to tell is to check couple of first boot lines in dmesg: [ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/arm/include/asm/restorer.h | 3 ++ criu/arch/arm/restorer.c | 59 ++++++++++++++++++++++++++++ criu/pie/restorer.c | 12 +++++- 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h index 7e4b09c89..f7b963bae 100644 --- a/criu/arch/arm/include/asm/restorer.h +++ b/criu/arch/arm/include/asm/restorer.h @@ -57,6 +57,9 @@ int restore_gpregs(struct rt_sigframe *f, UserArmRegsEntry *r); int restore_nonsigframe_gpregs(UserArmRegsEntry *r); +#define ARCH_HAS_SHMAT_HOOK +unsigned long arch_shmat(int shmid, void *shmaddr, + int shmflg, unsigned long size); static inline void restore_tls(tls_t *ptls) { asm ( diff --git a/criu/arch/arm/restorer.c b/criu/arch/arm/restorer.c index 21234b95d..588c1c074 100644 --- a/criu/arch/arm/restorer.c +++ b/criu/arch/arm/restorer.c @@ -7,8 +7,67 @@ #include "log.h" #include #include "cpu.h" +#include "page.h" +#include "common/err.h" int restore_nonsigframe_gpregs(UserArmRegsEntry *r) { return 0; } + +/* + * On ARMv6 CPUs with VIPT caches there are aliasing issues: + * if two different cache line indexes correspond to the same physical + * address, then changes made to one of the alias might be lost or they + * can overwrite each other. To overcome aliasing issues, page coloring + * with 4 pages align for shared mappings was introduced (SHMLBA) in kernel. + * Which resulted in unique physical address after any tag in cache + * (because two upper bits corresponding to page address get unused in tags). + * + * The problem here is in shmat() syscall: + * 1. if shmaddr is NULL then do_shmat() uses arch_get_unmapped_area() + * to allocate shared mapping. Which checks if CPU cache is VIPT + * and only then use SHMLBA alignment. + * 2. if shmaddr is specified then do_shmat() checks that address has + * SHMLBA alignment regardless to CPU cache aliasing. + * + * All above means that on non-VIPT CPU (like any ARMv7) we can get + * non-SHMLBA, but page-aligned address with shmat(shmid, NULL, shmflg), + * but we can't restore it with shmat(shmid, shmaddr, shmflg). + * Which results that we can dump e.g., application with shmem aligned + * on 2 pages, but can't restore it on the same ARMv7 CPU. + * + * To workaround this kernel feature, use mremap() on shmem mapping, + * allocated with shmat(shmid, NULL, shmflg). + */ +#define SHMLBA (4UL * PAGE_SIZE) +unsigned long arch_shmat(int shmid, void *shmaddr, + int shmflg, unsigned long size) +{ + unsigned long smap; + + /* SHMLBA-aligned, direct call shmat() */ + if (!((unsigned long)shmaddr & (SHMLBA - 1))) + return sys_shmat(shmid, shmaddr, shmflg); + + smap = sys_shmat(shmid, NULL, shmflg); + if (IS_ERR_VALUE(smap)) { + pr_err("shmat() with NULL shmaddr failed: %d\n", (int)smap); + return smap; + } + + /* We're lucky! */ + if (smap == (unsigned long)shmaddr) + return smap; + + /* Warn ALOUD */ + pr_warn("Restoring shmem %p unaligned to SHMLBA.\n", shmaddr); + pr_warn("Make sure that you don't migrate shmem from non-VIPT cached CPU to VIPT cached (e.g., ARMv7 -> ARMv6)\n"); + pr_warn("Otherwise YOU HAVE A CHANCE OF DATA CORRUPTIONS in writeable shmem\n"); + + smap = sys_mremap(smap, size, size, + MREMAP_FIXED | MREMAP_MAYMOVE, (unsigned long)shmaddr); + if (IS_ERR_VALUE(smap)) + pr_err("mremap() for shmem failed: %d\n", (int)smap); + return smap; +} diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 51bf8c880..a106f79d4 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -531,6 +531,14 @@ static long restore_self_exe_late(struct task_restore_args *args) return ret; } +#ifndef ARCH_HAS_SHMAT_HOOK +unsigned long arch_shmat(int shmid, void *shmaddr, + int shmflg, unsigned long size) +{ + return sys_shmat(shmid, shmaddr, shmflg); +} +#endif + static unsigned long restore_mapping(VmaEntry *vma_entry) { int prot = vma_entry->prot; @@ -539,6 +547,8 @@ static unsigned long restore_mapping(VmaEntry *vma_entry) if (vma_entry_is(vma_entry, VMA_AREA_SYSVIPC)) { int att_flags; + void *shmaddr = decode_pointer(vma_entry->start); + unsigned long shmsize = (vma_entry->end - vma_entry->start); /* * See comment in open_shmem_sysv() for what SYSV_SHMEM_SKIP_FD * means and why we check for PROT_EXEC few lines below. @@ -553,7 +563,7 @@ static unsigned long restore_mapping(VmaEntry *vma_entry) att_flags = SHM_RDONLY; pr_info("Attach SYSV shmem %d at %"PRIx64"\n", (int)vma_entry->fd, vma_entry->start); - return sys_shmat(vma_entry->fd, decode_pointer(vma_entry->start), att_flags); + return arch_shmat(vma_entry->fd, shmaddr, att_flags, shmsize); } /* From 164e048a8a3af3de4d18f8e4f45094362d4bb892 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 18 Apr 2017 20:04:08 +0300 Subject: [PATCH 0476/4375] zdtm/ia32: print st_size as (long long) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes compile-time errors on Fedora like: In file included from unlink_fstat01.c:9:0: > unlink_fstat01.c: In function ‘main’: > ../lib/zdtmtst.h:123:11: error: format ‘%ld’ expects argument of type ‘long int’, but argument 4 has type ‘__off64_t {aka long long int}’ [-Werror=format=] > test_msg("FAIL: %s:%d: " format " (errno = %d (%s))\n", \ Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/autofs.c | 15 +++++++++------ test/zdtm/static/unlink_fstat01.c | 6 ++++-- test/zdtm/static/unlink_fstat02.c | 9 ++++++--- test/zdtm/static/unlink_fstat03.c | 9 ++++++--- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/test/zdtm/static/autofs.c b/test/zdtm/static/autofs.c index 68a62940d..747ab69dc 100644 --- a/test/zdtm/static/autofs.c +++ b/test/zdtm/static/autofs.c @@ -220,18 +220,21 @@ static int check_fd(struct autofs_params *p) ret++; } if (st.st_size != p->fd_stat.st_size) { - pr_err("%s: st_size differs: %ld != %ld\n", p->mountpoint, - st.st_size, p->fd_stat.st_size); + pr_err("%s: st_size differs: %lld != %lld\n", p->mountpoint, + (long long)st.st_size, + (long long)p->fd_stat.st_size); ret++; } if (st.st_blksize != p->fd_stat.st_blksize) { - pr_err("%s: st_blksize differs %ld != %ld:\n", p->mountpoint, - (long)st.st_blksize, (long)p->fd_stat.st_blksize); + pr_err("%s: st_blksize differs %lld != %lld:\n", p->mountpoint, + (long long)st.st_blksize, + (long long)p->fd_stat.st_blksize); ret++; } if (st.st_blocks != p->fd_stat.st_blocks) { - pr_err("%s: st_blocks differs: %ld != %ld\n", p->mountpoint, - st.st_blocks, p->fd_stat.st_blocks); + pr_err("%s: st_blocks differs: %lld != %lld\n", p->mountpoint, + (long long)st.st_blocks, + (long long)p->fd_stat.st_blocks); ret++; } diff --git a/test/zdtm/static/unlink_fstat01.c b/test/zdtm/static/unlink_fstat01.c index b82c8618b..43ea6b9f6 100644 --- a/test/zdtm/static/unlink_fstat01.c +++ b/test/zdtm/static/unlink_fstat01.c @@ -70,13 +70,15 @@ int main(int argc, char ** argv) } if (fst.st_size != fsize) { - fail("(via fstat): file size changed to %ld", fst.st_size); + fail("(via fstat): file size changed to %lld", + (long long)fst.st_size); goto failed; } fst.st_size = lseek(fd, 0, SEEK_END); if (fst.st_size != fsize) { - fail("(via lseek): file size changed to %ld", fst.st_size); + fail("(via lseek): file size changed to %lld", + (long long)fst.st_size); goto failed; } diff --git a/test/zdtm/static/unlink_fstat02.c b/test/zdtm/static/unlink_fstat02.c index ce32e9ecf..1ffeffd73 100644 --- a/test/zdtm/static/unlink_fstat02.c +++ b/test/zdtm/static/unlink_fstat02.c @@ -47,7 +47,8 @@ int main(int argc, char ** argv) } if (fst.st_size != 0) { - pr_perror("%s file size eq %ld", filename, fst.st_size); + pr_perror("%s file size eq %lld", + filename, (long long)fst.st_size); goto failed; } @@ -86,13 +87,15 @@ int main(int argc, char ** argv) } if (fst.st_size != fsize) { - fail("(via fstat): file size changed to %ld", fst.st_size); + fail("(via fstat): file size changed to %lld", + (long long)fst.st_size); goto failed; } fst.st_size = lseek(fd[0], 0, SEEK_END); if (fst.st_size != fsize) { - fail("(via lseek): file size changed to %ld", fst.st_size); + fail("(via lseek): file size changed to %lld", + (long long)fst.st_size); goto failed; } diff --git a/test/zdtm/static/unlink_fstat03.c b/test/zdtm/static/unlink_fstat03.c index 8b3bf8dcc..b31ef1993 100644 --- a/test/zdtm/static/unlink_fstat03.c +++ b/test/zdtm/static/unlink_fstat03.c @@ -44,7 +44,8 @@ int main(int argc, char ** argv) } if (fst.st_size != 0) { - pr_perror("%s file size eq %ld", filename, fst.st_size); + pr_perror("%s file size eq %lld", filename, + (long long)fst.st_size); goto failed; } @@ -84,13 +85,15 @@ int main(int argc, char ** argv) } if (fst2.st_size != fsize) { - fail("(via fstat): file size changed to %ld", fst.st_size); + fail("(via fstat): file size changed to %lld", + (long long)fst.st_size); goto failed; } fst2.st_size = lseek(fd, 0, SEEK_END); if (fst2.st_size != fsize) { - fail("(via lseek): file size changed to %ld", fst.st_size); + fail("(via lseek): file size changed to %lld", + (long long)fst.st_size); goto failed; } From f2504723c91aebfed2b9ce47dcaddefd328a057b Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 18 Apr 2017 20:04:09 +0300 Subject: [PATCH 0477/4375] vdso/ia32: separate compat vdso helper As helper unmaps 64-bit vDSO blob, it can call only raw syscalls. Also by that reason it's code should be not instrumented with GCOV/ASAN. Disable instrumentation by separating it into new object and filtering gcov/asan cflags. Fixes: #290 @avagin, it rarely reproduces, I failed to reproduce even once (with gcov, on the same env00 test, with the same linux-next) please, reopen #290 if you'll spot it afterward. Reported-by: Andrei Vagin Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/Makefile.crtools | 4 ++- criu/include/vdso.h | 5 +++ criu/vdso-compat.c | 71 +++++++++++++++++++++++++++++++++++++++++++ criu/vdso.c | 66 ++-------------------------------------- 4 files changed, 81 insertions(+), 65 deletions(-) create mode 100644 criu/vdso-compat.c diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 51573cd43..5c2911ffc 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -86,7 +86,9 @@ ifeq ($(VDSO),y) obj-y += pie-util-vdso.o obj-y += vdso.o obj-y += pie-util-vdso-elf32.o -CFLAGS_pie-util-vdso-elf32.o += -DCONFIG_VDSO_32 +CFLAGS_pie-util-vdso-elf32.o += -DCONFIG_VDSO_32 +obj-$(CONFIG_COMPAT) += vdso-compat.o +CFLAGS_REMOVE_vdso-compat.o += $(CFLAGS-ASAN) $(CFLAGS-GCOV) endif PROTOBUF_GEN := scripts/protobuf-gen.sh diff --git a/criu/include/vdso.h b/criu/include/vdso.h index 9b6010c03..e118ed7f3 100644 --- a/criu/include/vdso.h +++ b/criu/include/vdso.h @@ -18,6 +18,11 @@ extern int vdso_init(void); extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct vm_area_list *vma_area_list); +#ifdef CONFIG_COMPAT +void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd, + int err_fd, void *vdso_buf, size_t buf_size); +#endif + #else /* CONFIG_VDSO */ #define vdso_init() (0) diff --git a/criu/vdso-compat.c b/criu/vdso-compat.c new file mode 100644 index 000000000..7669eb3df --- /dev/null +++ b/criu/vdso-compat.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +#include "types.h" +#include "parasite-syscall.h" +#include "parasite.h" +#include "vdso.h" + +static void exit_on(int ret, int err_fd, char *reason) +{ + if (ret) { + syscall(__NR_write, err_fd, reason, strlen(reason)); + syscall(__NR_exit, ret); + } +} +/* + * Because of restrictions of ARCH_MAP_VDSO_* API, new vDSO blob + * can be mapped only if there is no vDSO blob present for a process. + * This is a helper process, it unmaps 64-bit vDSO and maps 32-bit vDSO. + * Then it copies vDSO blob to shared with CRIU mapping. + * + * The purpose is to fill compat vdso's symtable (vdso_compat_rt). + * It's an optimization to fill symtable only once at CRIU restore + * for all restored tasks. + * + * @native - 64-bit vDSO blob (for easy unmap) + * @pipe_fd - to get size of compat blob from /proc/.../maps + * @err_fd - to print error messages + * @vdso_buf, buf_size - shared with CRIU buffer + * + * WARN: This helper shouldn't call pr_err() or any syscall with + * Glibc's wrapper function - it may very likely blow up. + */ +void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd, + int err_fd, void *vdso_buf, size_t buf_size) +{ + size_t vma_size; + void *vdso_addr; + long vdso_size; + long ret; + + vma_size = native->vma_end - native->vma_start; + ret = syscall(__NR_munmap, native->vma_start, vma_size); + exit_on(ret, err_fd, "Error: Failed to unmap native vdso\n"); + + vma_size = native->vvar_end - native->vvar_start; + ret = syscall(__NR_munmap, native->vvar_start, vma_size); + exit_on(ret, err_fd, "Error: Failed to unmap native vvar\n"); + + ret = syscall(__NR_arch_prctl, ARCH_MAP_VDSO_32, native->vma_start); + if (ret < 0) + exit_on(ret, err_fd, "Error: ARCH_MAP_VDSO failed\n"); + + vdso_size = ret; + if (vdso_size > buf_size) + exit_on(-1, err_fd, "Error: Compatible vdso's size is bigger than reserved buf\n"); + + /* Stop so CRIU could parse smaps to find 32-bit vdso's size */ + ret = syscall(__NR_kill, syscall(__NR_getpid), SIGSTOP); + exit_on(ret, err_fd, "Error: Can't stop myself with SIGSTOP (having a good time)\n"); + + ret = syscall(__NR_read, pipe_fd, &vdso_addr, sizeof(void *)); + if (ret != sizeof(void *)) + exit_on(-1, err_fd, "Error: Can't read size of mmaped vdso from pipe\n"); + + memcpy(vdso_buf, vdso_addr, vdso_size); + + syscall(__NR_exit, 0); +} diff --git a/criu/vdso.c b/criu/vdso.c index 770853514..8bc7b5d3b 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -330,68 +330,6 @@ static int vdso_fill_self_symtable(struct vdso_symtable *s) } #ifdef CONFIG_COMPAT -static void exit_on(int ret, int err_fd, char *reason) -{ - if (ret) { - syscall(__NR_write, err_fd, reason, strlen(reason)); - syscall(__NR_exit, ret); - } -} -/* - * Because of restrictions of ARCH_MAP_VDSO_* API, new vDSO blob - * can be mapped only if there is no vDSO blob present for a process. - * This is a helper process, it unmaps 64-bit vDSO and maps 32-bit vDSO. - * Then it copies vDSO blob to shared with CRIU mapping. - * - * The purpose is to fill compat vdso's symtable (vdso_compat_rt). - * It's an optimization to fill symtable only once at CRIU restore - * for all restored tasks. - * - * @native - 64-bit vDSO blob (for easy unmap) - * @pipe_fd - to get size of compat blob from /proc/.../maps - * @err_fd - to print error messages - * @vdso_buf, buf_size - shared with CRIU buffer - * - * WARN: This helper shouldn't call pr_err() or any syscall with - * Glibc's wrapper function - it may very likely blow up. - */ -static void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd, - int err_fd, void *vdso_buf, size_t buf_size) -{ - size_t vma_size; - void *vdso_addr; - long vdso_size; - long ret; - - vma_size = native->vma_end - native->vma_start; - ret = syscall(__NR_munmap, native->vma_start, vma_size); - exit_on(ret, err_fd, "Error: Failed to unmap native vdso\n"); - - vma_size = native->vvar_end - native->vvar_start; - ret = syscall(__NR_munmap, native->vvar_start, vma_size); - exit_on(ret, err_fd, "Error: Failed to unmap native vvar\n"); - - ret = syscall(__NR_arch_prctl, ARCH_MAP_VDSO_32, native->vma_start); - if (ret < 0) - exit_on(ret, err_fd, "Error: ARCH_MAP_VDSO failed\n"); - - vdso_size = ret; - if (vdso_size > buf_size) - exit_on(-1, err_fd, "Error: Compatible vdso's size is bigger than reserved buf\n"); - - /* Stop so CRIU could parse smaps to find 32-bit vdso's size */ - ret = syscall(__NR_kill, syscall(__NR_getpid), SIGSTOP); - exit_on(ret, err_fd, "Error: Can't stop myself with SIGSTOP (having a good time)\n"); - - ret = syscall(__NR_read, pipe_fd, &vdso_addr, sizeof(void *)); - if (ret != sizeof(void *)) - exit_on(-1, err_fd, "Error: Can't read size of mmaped vdso from pipe\n"); - - memcpy(vdso_buf, vdso_addr, vdso_size); - - syscall(__NR_exit, 0); -} - static int vdso_mmap_compat(struct vdso_symtable *native, struct vdso_symtable *compat, void *vdso_buf, size_t buf_size) { @@ -503,13 +441,13 @@ out_unmap: return ret; } -#else +#else /* CONFIG_COMPAT */ static int vdso_fill_compat_symtable(struct vdso_symtable *native, struct vdso_symtable *compat) { return 0; } -#endif +#endif /* CONFIG_COMPAT */ int vdso_init(void) { From 0d76ff08833eefae1073b81bc7c6f83cb14f4419 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 19 Apr 2017 16:31:46 +0300 Subject: [PATCH 0478/4375] arm/make: add missed syscalls.S dependency As for compiling syscalls.S needed syscall-aux.h header, which is linked with making $(sys-asm-types), add it to deps. Fixes: > In file included from compel/arch/aarch64/plugins/std/syscalls/syscalls.S:2:0: > compel/include/uapi/compel/plugins/std/syscall-codes.h:568:44: fatal error: compel/plugins/std/syscall-aux.h: No such file or directory > #include > ^ > compilation terminated. Cc: Pavel Emelyanov Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/arm/plugins/std/syscalls/Makefile.syscalls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls b/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls index 5695b86b9..c89f1a56a 100644 --- a/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls +++ b/compel/arch/arm/plugins/std/syscalls/Makefile.syscalls @@ -25,7 +25,7 @@ endif sys-exec-tbl := sys-exec-tbl.c -$(sys-asm) $(sys-types) $(sys-codes) $(sys-proto): $(sys-gen) $(sys-def) $(sys-asm-common) +$(sys-asm) $(sys-types) $(sys-codes) $(sys-proto): $(sys-gen) $(sys-def) $(sys-asm-common) $(sys-asm-types) $(E) " GEN " $@ $(Q) perl \ $(sys-gen) \ From fce878938e33823123278d0bce06cb5f830a55e8 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 24 Apr 2017 11:46:26 +0300 Subject: [PATCH 0479/4375] criu: Version 3.0 So, we've done a HUUGE rework in this release, that's why it's 3.0. Two biggest changes are: * Compel library -- the framwork for parasite code injection. * 32bit x86 support. Note, that it's neither x32 support, not 32-bit criu. It's purely the ability to dump 32-bit tasks on 64-bit host. With compel at hands the 'criu exec' is removed. Main set of kudos go to Cyrill and Dima for this heavy lifting :) Other things include shutdown-ed UDP sockets, bind-mounts to external bind mounts, ASAN, extentions to RPC, rework of SysVIPC shmem dump format and some bugfixes and beautifications in CRIT. Signed-off-by: Pavel Emelyanov --- Makefile.versions | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index 59d74b485..1e7d1887b 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. -CRIU_VERSION_MAJOR := 2 -CRIU_VERSION_MINOR := 12 +CRIU_VERSION_MAJOR := 3 +CRIU_VERSION_MINOR := 0 CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Vulcanite Rook +CRIU_VERSION_NAME := Basalt Wagtail CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From 8512efdf88e023b44bcad17e8411f1420680d187 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 26 Jan 2017 12:58:00 +0300 Subject: [PATCH 0480/4375] files: Unify clone_service_fd() Make this function more generic: we want to do not dup not only transport socket of parent, but just all service fds, which were not opened at the moment of clone() in parent. But, yes, currently it's only transport socket. travis-ci: success for files: Unify clone_service_fd() Signed-off-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov --- criu/util.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/criu/util.c b/criu/util.c index 437796b2b..da78d8d30 100644 --- a/criu/util.c +++ b/criu/util.c @@ -481,11 +481,10 @@ int clone_service_fd(int id) return 0; for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) { - int old = __get_service_fd(i, service_fd_id); + int old = get_service_fd(i); int new = __get_service_fd(i, id); - /* Do not dup parent's transport fd */ - if (i == TRANSPORT_FD_OFF) + if (old < 0) continue; ret = dup2(old, new); if (ret == -1) { From b2009641c4fe5a867ae010a2eaa5303a44b9c306 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 8 Feb 2017 16:06:00 +0300 Subject: [PATCH 0481/4375] zdtm/static/fpu01: check for OSXSAVE instead of XSAVE When checking for XSAVE availability it makes more sense to check for OSXSAVE than to check for XSAVE. This way the check works on systems booted with the 'noxsave' kernel command-line. travis-ci: success for zdtm/static/fpu01: check for OSXSAVE instead of XSAVE Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- test/zdtm/static/fpu01.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/fpu01.c b/test/zdtm/static/fpu01.c index bc41b6977..11c480546 100644 --- a/test/zdtm/static/fpu01.c +++ b/test/zdtm/static/fpu01.c @@ -19,7 +19,7 @@ static int verify_cpu(void) /* Do we have xsave? */ cpuid(1, &eax, &ebx, &ecx, &edx); - if (!(ecx & (1u << 26))) + if (!(ecx & (1u << 27))) return -1; /* Is YMM here? */ From 42cbc9e35880905630f39bacb94315ce581250b6 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 5 Apr 2017 11:25:36 +0300 Subject: [PATCH 0482/4375] scripts/install-debian-packages: add libnl-route-3-dev Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- contrib/debian/dev-packages.lst | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/debian/dev-packages.lst b/contrib/debian/dev-packages.lst index 767de4475..b0b664f72 100644 --- a/contrib/debian/dev-packages.lst +++ b/contrib/debian/dev-packages.lst @@ -17,3 +17,4 @@ iproute2 libcap-dev libaio-dev python-yaml +libnl-route-3-dev From f17b60eff386ac73d86741a430e0a487efe5589a Mon Sep 17 00:00:00 2001 From: Veronika Kabatova Date: Wed, 5 Apr 2017 17:01:29 +0200 Subject: [PATCH 0483/4375] Extend the parser to accept negative options Introducing negative options for true / false values. The original getopt_long parser is kept since it is able to set flag-like values (instead of setting these values in the switch when it's not needed). The type of the options needed to be changed to integers for getopt_long to accept flag-like value settings (as per getopt_long documentation, the address of integer variable has to be passed). Corresponding negative options are not added for deprecated options. This patch is a preparation for the addition of configuration files (GitHub issue #278). General idea of this feature is to have global configuration files in /etc/criu.d/ directory and user-specific configuration files in $HOME/.criu.d/ directory, with the possibility of specifying a chosen file to be used (default files will be used if none is specified, or none in case the default ones are not present, to not break compatibility). The options in configuration files should be possible to be overriden by the options specified on command line, hence the negative options addition. The whole feature of configuration files will remove the need of specifying all the options on command line, with the possibility of reusing a file for different use case with only overriding some of the values specified there. In case both types of option (negative and positive) are passed, the later one will be applied -- this works with the philosophy of overriding the "earlier" options from configuration files. Changes since v1: - Describe the --no- option prefix in the beginning of OPTIONS section in both man page and --help instead of mentioning it at every eligible line (this also fixes line length issue with --help) - Fix the accidental removal of check_only case caused by bad rebase - Use a macro for getopt_long struct option generating instead of additional defines and hardcoded lines Signed-off-by: Veronika Kabatova Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 4 ++ criu/crtools.c | 117 +++++++++++++++----------------------- criu/include/cr_options.h | 40 ++++++------- 3 files changed, 70 insertions(+), 91 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 4a0ecdad4..b121f8b2b 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -24,6 +24,10 @@ on a different system, or both. OPTIONS ------- +Most of the true / false long options (the ones without arguments) can be +prefixed with *--no-* to negate the option (example: *--display-stats* +and *--no-display-stats*). + Common options ~~~~~~~~~~~~~~ Common options are applicable to any 'command'. diff --git a/criu/crtools.c b/criu/crtools.c index 20f8fa9f4..ba805b9cc 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -211,6 +211,11 @@ bool deprecated_ok(char *what) int main(int argc, char *argv[], char *envp[]) { + +#define BOOL_OPT(OPT_NAME, SAVE_TO) \ + {OPT_NAME, no_argument, SAVE_TO, true},\ + {"no-" OPT_NAME, no_argument, SAVE_TO, false} + pid_t pid = 0, tree_id = 0; int ret = -1; bool usage_error = true; @@ -225,9 +230,9 @@ int main(int argc, char *argv[], char *envp[]) { "pid", required_argument, 0, 'p' }, { "leave-stopped", no_argument, 0, 's' }, { "leave-running", no_argument, 0, 'R' }, - { "restore-detached", no_argument, 0, 'd' }, - { "restore-sibling", no_argument, 0, 'S' }, - { "daemon", no_argument, 0, 'd' }, + BOOL_OPT("restore-detached", &opts.restore_detach), + BOOL_OPT("restore-sibling", &opts.restore_sibling), + BOOL_OPT("daemon", &opts.restore_detach), { "contents", no_argument, 0, 'c' }, { "file", required_argument, 0, 'f' }, { "fields", required_argument, 0, 'F' }, @@ -238,27 +243,27 @@ int main(int argc, char *argv[], char *envp[]) { "root", required_argument, 0, 'r' }, { USK_EXT_PARAM, optional_argument, 0, 'x' }, { "help", no_argument, 0, 'h' }, - { SK_EST_PARAM, no_argument, 0, 1042 }, + BOOL_OPT(SK_EST_PARAM, &opts.tcp_established_ok), { "close", required_argument, 0, 1043 }, - { "log-pid", no_argument, 0, 1044 }, + BOOL_OPT("log-pid", &opts.log_file_per_pid), { "version", no_argument, 0, 'V' }, - { "evasive-devices", no_argument, 0, 1045 }, + BOOL_OPT("evasive-devices", &opts.evasive_devices), { "pidfile", required_argument, 0, 1046 }, { "veth-pair", required_argument, 0, 1047 }, { "action-script", required_argument, 0, 1049 }, - { LREMAP_PARAM, no_argument, 0, 1041 }, - { OPT_SHELL_JOB, no_argument, 0, 'j' }, - { OPT_FILE_LOCKS, no_argument, 0, 'l' }, - { "page-server", no_argument, 0, 1050 }, + BOOL_OPT(LREMAP_PARAM, &opts.link_remap_ok), + BOOL_OPT(OPT_SHELL_JOB, &opts.shell_job), + BOOL_OPT(OPT_FILE_LOCKS, &opts.handle_file_locks), + BOOL_OPT("page-server", &opts.use_page_server), { "address", required_argument, 0, 1051 }, { "port", required_argument, 0, 1052 }, { "prev-images-dir", required_argument, 0, 1053 }, { "ms", no_argument, 0, 1054 }, - { "track-mem", no_argument, 0, 1055 }, - { "auto-dedup", no_argument, 0, 1056 }, + BOOL_OPT("track-mem", &opts.track_mem), + BOOL_OPT("auto-dedup", &opts.auto_dedup), { "libdir", required_argument, 0, 'L' }, { "cpu-cap", optional_argument, 0, 1057 }, - { "force-irmap", no_argument, 0, 1058 }, + BOOL_OPT("force-irmap", &opts.force_irmap), { "ext-mount-map", required_argument, 0, 'M' }, { "exec-cmd", no_argument, 0, 1059 }, { "manage-cgroups", optional_argument, 0, 1060 }, @@ -267,8 +272,8 @@ int main(int argc, char *argv[], char *envp[]) { "feature", required_argument, 0, 1063 }, { "skip-mnt", required_argument, 0, 1064 }, { "enable-fs", required_argument, 0, 1065 }, - { "enable-external-sharing", no_argument, 0, 1066 }, - { "enable-external-masters", no_argument, 0, 1067 }, + { "enable-external-sharing", no_argument, &opts.enable_external_sharing, true }, + { "enable-external-masters", no_argument, &opts.enable_external_masters, true }, { "freeze-cgroup", required_argument, 0, 1068 }, { "ghost-limit", required_argument, 0, 1069 }, { "irmap-scan-path", required_argument, 0, 1070 }, @@ -276,20 +281,22 @@ 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, 1077 }, - { "experimental", no_argument, 0, 1078 }, + BOOL_OPT("extra", &opts.check_extra_features), + BOOL_OPT("experimental", &opts.check_experimental_features), { "all", no_argument, 0, 1079 }, { "cgroup-props", required_argument, 0, 1080 }, { "cgroup-props-file", required_argument, 0, 1081 }, { "cgroup-dump-controller", required_argument, 0, 1082 }, - { SK_INFLIGHT_PARAM, no_argument, 0, 1083 }, - { "deprecated", no_argument, 0, 1084 }, - { "display-stats", no_argument, 0, 1086 }, - { "weak-sysctls", no_argument, 0, 1087 }, + BOOL_OPT(SK_INFLIGHT_PARAM, &opts.tcp_skip_in_flight), + BOOL_OPT("deprecated", &opts.deprecated_ok), + BOOL_OPT("display-stats", &opts.display_stats), + BOOL_OPT("weak-sysctls", &opts.weak_sysctls), { "status-fd", required_argument, 0, 1088 }, { }, }; +#undef BOOL_OPT + BUILD_BUG_ON(PAGE_SIZE != PAGE_IMAGE_SIZE); BUILD_BUG_ON(CTL_32 != SYSCTL_TYPE__CTL_32); BUILD_BUG_ON(__CTL_STR != SYSCTL_TYPE__CTL_STR); @@ -326,6 +333,8 @@ int main(int argc, char *argv[], char *envp[]) opt = getopt_long(argc, argv, short_opts, long_opts, &idx); if (opt == -1) break; + if (!opt) + continue; switch (opt) { case 's': @@ -390,14 +399,6 @@ int main(int argc, char *argv[], char *envp[]) } else log_level++; break; - case 1041: - pr_info("Will allow link remaps on FS\n"); - opts.link_remap_ok = true; - break; - case 1042: - pr_info("Will dump TCP connections\n"); - opts.tcp_established_ok = true; - break; case 1043: { int fd; @@ -406,12 +407,6 @@ int main(int argc, char *argv[], char *envp[]) close(fd); break; } - case 1044: - opts.log_file_per_pid = 1; - break; - case 1045: - opts.evasive_devices = true; - break; case 1046: opts.pidfile = optarg; break; @@ -432,9 +427,6 @@ int main(int argc, char *argv[], char *envp[]) if (add_script(optarg)) return 1; - break; - case 1050: - opts.use_page_server = true; break; case 1051: opts.addr = optarg; @@ -453,12 +445,6 @@ int main(int argc, char *argv[], char *envp[]) case 1053: opts.img_parent = optarg; break; - case 1055: - opts.track_mem = true; - break; - case 1056: - opts.auto_dedup = true; - break; case 1057: if (parse_cpu_cap(&opts, optarg)) goto usage; @@ -516,12 +502,6 @@ int main(int argc, char *argv[], char *envp[]) if (!add_fsname_auto(optarg)) return 1; break; - case 1066: - opts.enable_external_sharing = true; - break; - case 1067: - opts.enable_external_masters = true; - break; case 1068: opts.freeze_cgroup = optarg; break; @@ -570,12 +550,6 @@ int main(int argc, char *argv[], char *envp[]) return 1; } break; - case 1077: - opts.check_extra_features = true; - break; - case 1078: - opts.check_experimental_features = true; - break; case 1079: opts.check_extra_features = true; opts.check_experimental_features = true; @@ -590,21 +564,6 @@ int main(int argc, char *argv[], char *envp[]) if (!cgp_add_dump_controller(optarg)) return 1; break; - case 1083: - pr_msg("Will skip in-flight TCP connections\n"); - opts.tcp_skip_in_flight = true; - break; - case 1084: - pr_msg("Turn deprecated stuff ON\n"); - opts.deprecated_ok = true; - break; - case 1086: - opts.display_stats = true; - break; - case 1087: - pr_msg("Will skip non-existant sysctls on restore\n"); - opts.weak_sysctls = true; - break; case 1088: if (sscanf(optarg, "%d", &opts.status_fd) != 1) { pr_err("Unable to parse a value of --status-fd\n"); @@ -624,6 +583,17 @@ int main(int argc, char *argv[], char *envp[]) } } + if (opts.deprecated_ok) + pr_msg("Turn deprecated stuff ON\n"); + if (opts.tcp_skip_in_flight) + pr_msg("Will skip in-flight TCP connections\n"); + if (opts.tcp_established_ok) + pr_info("Will dump TCP connections\n"); + if (opts.link_remap_ok) + pr_info("Will allow link remaps on FS\n"); + if (opts.weak_sysctls) + pr_msg("Will skip non-existant sysctls on restore\n"); + if (getenv("CRIU_DEPRECATED")) { pr_msg("Turn deprecated stuff ON via env\n"); opts.deprecated_ok = true; @@ -819,6 +789,11 @@ usage: } pr_msg("\n" + +"Most of the true / false long options (the ones without arguments) can be\n" +"prefixed with --no- to negate the option (example: --display-stats and\n" +"--no-display-stats).\n" +"\n" "Dump/Restore options:\n" "\n" "* Generic:\n" diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index b824a21c0..c879de97a 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -51,21 +51,21 @@ struct cr_options { int final_state; char *show_dump_file; char *show_fmt; - bool check_extra_features; - bool check_experimental_features; + int check_extra_features; + int check_experimental_features; bool show_pages_content; union { - bool restore_detach; + int restore_detach; bool daemon_mode; }; - bool restore_sibling; + int restore_sibling; bool ext_unix_sk; - bool shell_job; - bool handle_file_locks; - bool tcp_established_ok; - bool evasive_devices; - bool link_remap_ok; - bool log_file_per_pid; + int shell_job; + int handle_file_locks; + int tcp_established_ok; + int evasive_devices; + int link_remap_ok; + int log_file_per_pid; bool swrk_restore; char *output; char *root; @@ -76,15 +76,15 @@ struct cr_options { struct list_head external; struct list_head join_ns; char *libdir; - bool use_page_server; + int use_page_server; unsigned short port; char *addr; int ps_socket; - bool track_mem; + int track_mem; char *img_parent; - bool auto_dedup; + int auto_dedup; unsigned int cpu_cap; - bool force_irmap; + int force_irmap; char **exec_cmd; unsigned int manage_cgroups; char *new_global_cg_root; @@ -92,8 +92,8 @@ struct cr_options { char *cgroup_props_file; struct list_head new_cgroup_roots; bool autodetect_ext_mounts; - bool enable_external_sharing; - bool enable_external_masters; + int enable_external_sharing; + int enable_external_masters; bool aufs; /* auto-deteced, not via cli */ bool overlayfs; #ifdef CONFIG_BINFMT_MISC_VIRTUALIZED @@ -105,7 +105,7 @@ struct cr_options { char *lsm_profile; unsigned int timeout; unsigned int empty_ns; - bool tcp_skip_in_flight; + int tcp_skip_in_flight; char *work_dir; /* @@ -114,9 +114,9 @@ struct cr_options { * the deprecated stuff is not working, but it's still possible * to turn one ON while the code is in. */ - bool deprecated_ok; - bool display_stats; - bool weak_sysctls; + int deprecated_ok; + int display_stats; + int weak_sysctls; int status_fd; bool orphan_pts_master; }; From e3538116f1abf86721b3bb5c3e92f24396649d09 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 20 Apr 2017 14:13:44 +0300 Subject: [PATCH 0484/4375] restore: Don't parse /proc/pid/threads for single-threaded tasks We do this to get real pids of the threads, but sometimes we just know that value. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 6c8692335..5c9b9576e 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1542,8 +1542,12 @@ static int attach_to_tasks(bool root_seized) if (!task_alive(item)) continue; - if (parse_threads(item->pid->real, &item->threads, &item->nr_threads)) - return -1; + if (item->nr_threads == 1) { + item->threads[0].real = item->pid->real; + } else { + if (parse_threads(item->pid->real, &item->threads, &item->nr_threads)) + return -1; + } for (i = 0; i < item->nr_threads; i++) { pid_t pid = item->threads[i].real; @@ -1595,8 +1599,12 @@ static int catch_tasks(bool root_seized, enum trace_flags *flag) if (!task_alive(item)) continue; - if (parse_threads(item->pid->real, &item->threads, &item->nr_threads)) - return -1; + if (item->nr_threads == 1) { + item->threads[0].real = item->pid->real; + } else { + if (parse_threads(item->pid->real, &item->threads, &item->nr_threads)) + return -1; + } for (i = 0; i < item->nr_threads; i++) { pid_t pid = item->threads[i].real; From 7a1944ba00452bcbc594e6efc89577974890f829 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 20 Apr 2017 14:14:07 +0300 Subject: [PATCH 0485/4375] files: No getpid in vain Each opening of a file results in getpid() call which is now a pure syscall :( For this particular case this value is poitless, as log engine already prints pids. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/files.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/criu/files.c b/criu/files.c index 324115b1a..913cec057 100644 --- a/criu/files.c +++ b/criu/files.c @@ -638,11 +638,10 @@ int restore_fown(int fd, FownEntry *fown) { struct f_owner_ex owner; uid_t uids[3]; - pid_t pid = getpid(); if (fown->signum) { if (fcntl(fd, F_SETSIG, fown->signum)) { - pr_perror("%d: Can't set signal", pid); + pr_perror("Can't set signal"); return -1; } } @@ -652,12 +651,12 @@ int restore_fown(int fd, FownEntry *fown) return 0; if (getresuid(&uids[0], &uids[1], &uids[2])) { - pr_perror("%d: Can't get current UIDs", pid); + pr_perror("Can't get current UIDs"); return -1; } if (setresuid(fown->uid, fown->euid, uids[2])) { - pr_perror("%d: Can't set UIDs", pid); + pr_perror("Can't set UIDs"); return -1; } @@ -665,13 +664,12 @@ int restore_fown(int fd, FownEntry *fown) owner.pid = fown->pid; if (fcntl(fd, F_SETOWN_EX, &owner)) { - pr_perror("%d: Can't setup %d file owner pid", - pid, fd); + pr_perror("Can't setup %d file owner pid", fd); return -1; } if (setresuid(uids[0], uids[1], uids[2])) { - pr_perror("%d: Can't revert UIDs back", pid); + pr_perror("Can't revert UIDs back"); return -1; } From 33385148cb16c8bcf4b716f7e01d63fec0cd17d1 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 21 Apr 2017 14:16:35 +0300 Subject: [PATCH 0486/4375] kdat: remove cr-exec shambles As cr-exec is deprecated-removed, drop ruins. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/crtools.h | 1 - criu/include/kerndat.h | 1 - criu/kerndat.c | 11 ----------- 3 files changed, 13 deletions(-) diff --git a/criu/include/crtools.h b/criu/include/crtools.h index ef0129ba0..658e269ce 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -20,7 +20,6 @@ extern int cr_pre_dump_tasks(pid_t pid); extern int cr_restore_tasks(void); extern int convert_to_elf(char *elf_path, int fd_core); extern int cr_check(void); -extern int cr_exec(int pid, char **opts); extern int cr_dedup(void); extern int check_add_feature(char *arg); diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 68a597801..3c208dcef 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -12,7 +12,6 @@ struct stat; extern int kerndat_init(void); extern int kerndat_init_rst(void); -extern int kerndat_init_cr_exec(void); extern int kerndat_get_dirty_track(void); extern int kerndat_fdinfo_has_lock(void); extern int kerndat_loginuid(bool only_dump); diff --git a/criu/kerndat.c b/criu/kerndat.c index 37efcff2c..530de4326 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -632,14 +632,3 @@ int kerndat_init_rst(void) return ret; } - -int kerndat_init_cr_exec(void) -{ - int ret; - - ret = get_task_size(); - if (!ret) - ret = kerndat_compat_restore(); - - return ret; -} From f830c2d8d0e345722dc24f3a6101b8c4660bce34 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 21 Apr 2017 14:15:05 +0300 Subject: [PATCH 0487/4375] ia32: Clearify if 32bit C/R is compile-disabled Point that ia32 C/R was disabled due to missed packages. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile.config | 3 +++ criu/cr-check.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/Makefile.config b/Makefile.config index 50516109a..0dd9d0433 100644 --- a/Makefile.config +++ b/Makefile.config @@ -24,6 +24,9 @@ ifeq ($(SRCARCH),x86) ifeq ($(call try-cc,$(FEATURE_TEST_X86_COMPAT),-m32),true) export CONFIG_COMPAT := y FEATURE_DEFINES += -DCONFIG_COMPAT +else + $(info Note: Building without ia32 C/R, missed packages:) + $(info $(info) libc6-dev-i386, gcc-multilib) endif endif diff --git a/criu/cr-check.c b/criu/cr-check.c index 2c97c880b..58dc7b4f9 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1057,9 +1057,13 @@ static int check_loginuid(void) static int check_compat_cr(void) { +#ifdef CONFIG_COMPAT if (kdat_compat_sigreturn_test()) return 0; pr_warn("compat_cr is not supported. Requires kernel >= v4.9\n"); +#else + pr_warn("CRIU built without CONFIG_COMPAT - can't C/R ia32\n"); +#endif return -1; } From 2c425ed67c904aa358f1fb2d3ff52f11ebf2827a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 14 Apr 2017 19:56:40 +0300 Subject: [PATCH 0488/4375] sysctl: Use open_proc() Many of sysctl_op-s we have read (or write) single entry. In current implementaiton this results in two opens and two closes for each -- open /proc/sys, then open the rest. It's better to use open_proc() as the latter already have fd for /proc cached. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/sysctl.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/criu/sysctl.c b/criu/sysctl.c index 1f3c9af90..f1e110ed3 100644 --- a/criu/sysctl.c +++ b/criu/sysctl.c @@ -351,23 +351,15 @@ out: static int __nonuserns_sysctl_op(struct sysctl_req *req, size_t nr_req, int op) { - int dir, ret, exit_code = -1;; - - dir = open("/proc/sys", O_RDONLY, O_DIRECTORY); - if (dir < 0) { - pr_perror("Can't open sysctl dir"); - return -1; - } + int ret, exit_code = -1;; while (nr_req--) { - int fd, flags; + int fd; if (op == CTL_READ) - flags = O_RDONLY; + fd = open_proc(PROC_GEN, "sys/%s", req->name); else - flags = O_WRONLY; - - fd = openat(dir, req->name, flags); + fd = open_proc_rw(PROC_GEN, "sys/%s", req->name); if (fd < 0) { if (errno == ENOENT && (req->flags & CTL_FLAGS_OPTIONAL)) { req++; @@ -394,7 +386,6 @@ static int __nonuserns_sysctl_op(struct sysctl_req *req, size_t nr_req, int op) exit_code = 0; out: - close(dir); return exit_code; } From 58c1309aac2114d005f30ff919bb04beae9f2b5c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 21 Apr 2017 23:28:11 +0300 Subject: [PATCH 0489/4375] ia32: Rename has_compat_sigreturn => compat_cr This naming is left from the first compatible kernel patches. At that time to return to 32-bit task rt_sigreturn was used with a special flag. Now it's not true anymore, the naming doesn't relate. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/infect.c | 2 +- compel/include/uapi/infect.h | 2 +- criu/arch/aarch64/include/asm/restorer.h | 2 +- criu/arch/arm/include/asm/restorer.h | 2 +- criu/arch/ppc64/include/asm/restorer.h | 2 +- criu/arch/x86/crtools.c | 2 +- criu/arch/x86/include/asm/restorer.h | 2 +- criu/cr-check.c | 2 +- criu/include/kerndat.h | 2 +- criu/kerndat.c | 4 ++-- criu/parasite-syscall.c | 4 ++-- criu/vdso.c | 2 +- 12 files changed, 14 insertions(+), 14 deletions(-) diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index b64a55d97..9c919e64e 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -406,7 +406,7 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) if (ret < 0) return false; - if (ret && !(ctl->ictx.flags & INFECT_HAS_COMPAT_SIGRETURN)) { + if (ret && !(ctl->ictx.flags & INFECT_COMPATIBLE)) { pr_err("Can't dump task %d running in 32-bit mode\n", pid); return false; } diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index da0ca3a69..005d6bda6 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -123,7 +123,7 @@ extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *); #define INFECT_NO_MEMFD 0x1 /* don't use memfd() */ #define INFECT_FAIL_CONNECT 0x2 /* make parasite connect() fail */ #define INFECT_NO_BREAKPOINTS 0x4 /* no breakpoints in pie tracking */ -#define INFECT_HAS_COMPAT_SIGRETURN 0x8 +#define INFECT_COMPATIBLE 0x8 /* can run parasite inside compat tasks */ /* * There are several ways to describe a blob to compel diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h index b5dd42e54..60cd99fb5 100644 --- a/criu/arch/aarch64/include/asm/restorer.h +++ b/criu/arch/aarch64/include/asm/restorer.h @@ -52,7 +52,7 @@ : "sp", "x0", "memory") -#define kdat_compat_sigreturn_test() 0 +#define kdat_compatible_cr() 0 int restore_gpregs(struct rt_sigframe *f, UserAarch64RegsEntry *r); int restore_nonsigframe_gpregs(UserAarch64RegsEntry *r); diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h index f7b963bae..007260a3a 100644 --- a/criu/arch/arm/include/asm/restorer.h +++ b/criu/arch/arm/include/asm/restorer.h @@ -53,7 +53,7 @@ : "memory") -#define kdat_compat_sigreturn_test() 0 +#define kdat_compatible_cr() 0 int restore_gpregs(struct rt_sigframe *f, UserArmRegsEntry *r); int restore_nonsigframe_gpregs(UserArmRegsEntry *r); diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h index c779a1869..d16ec26ac 100644 --- a/criu/arch/ppc64/include/asm/restorer.h +++ b/criu/arch/ppc64/include/asm/restorer.h @@ -48,7 +48,7 @@ "r"(&thread_args[i]) /* %6 */ \ : "memory","0","3","4","5","6","7","14","15") -#define kdat_compat_sigreturn_test() 0 +#define kdat_compatible_cr() 0 int restore_gpregs(struct rt_sigframe *f, UserPpc64RegsEntry *r); int restore_nonsigframe_gpregs(UserPpc64RegsEntry *r); diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index bce19aa6e..d0121b48e 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -26,7 +26,7 @@ #include "images/core.pb-c.h" #include "images/creds.pb-c.h" -int kdat_compat_sigreturn_test(void) +int kdat_compatible_cr(void) { #ifdef CONFIG_COMPAT unsigned long auxval; diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index e8a619620..acd7218f8 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -69,7 +69,7 @@ arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; } # define ARCH_MAP_VDSO_32 0x2002 #endif -extern int kdat_compat_sigreturn_test(void); +extern int kdat_compatible_cr(void); static inline void __setup_sas_compat(struct ucontext_ia32* uc, ThreadSasEntry *sas) diff --git a/criu/cr-check.c b/criu/cr-check.c index 58dc7b4f9..208484b4a 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1058,7 +1058,7 @@ static int check_loginuid(void) static int check_compat_cr(void) { #ifdef CONFIG_COMPAT - if (kdat_compat_sigreturn_test()) + if (kdat_compatible_cr()) return 0; pr_warn("compat_cr is not supported. Requires kernel >= v4.9\n"); #else diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 3c208dcef..97194cd23 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -33,7 +33,7 @@ struct kerndat_s { unsigned long task_size; bool ipv6; bool has_loginuid; - bool has_compat_sigreturn; + bool compat_cr; enum pagemap_func pmap; unsigned int has_xtlocks; unsigned long mmap_min_addr; diff --git a/criu/kerndat.c b/criu/kerndat.c index 530de4326..1e3ef51f4 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -557,11 +557,11 @@ err: static int kerndat_compat_restore(void) { - int ret = kdat_compat_sigreturn_test(); + int ret = kdat_compatible_cr(); if (ret < 0) /* failure */ return ret; - kdat.has_compat_sigreturn = !!ret; + kdat.compat_cr = !!ret; return 0; } diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index fdd20a06e..e4ce028f1 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -503,8 +503,8 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ictx->flags |= INFECT_FAIL_CONNECT; if (fault_injected(FI_NO_BREAKPOINTS)) ictx->flags |= INFECT_NO_BREAKPOINTS; - if (kdat.has_compat_sigreturn) - ictx->flags |= INFECT_HAS_COMPAT_SIGRETURN; + if (kdat.compat_cr) + ictx->flags |= INFECT_COMPATIBLE; ictx->log_fd = log_get_fd(); diff --git a/criu/vdso.c b/criu/vdso.c index 8bc7b5d3b..5f7cad4ed 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -455,7 +455,7 @@ int vdso_init(void) pr_err("Failed to fill self vdso symtable\n"); return -1; } - if (kdat.has_compat_sigreturn && + if (kdat.compat_cr && vdso_fill_compat_symtable(&vdso_sym_rt, &vdso_compat_rt)) { pr_err("Failed to fill compat vdso symtable\n"); return -1; From 1e1d0dde26ddb280d61dcff9bf6e698626c230e2 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 13 Apr 2017 18:27:13 +0300 Subject: [PATCH 0490/4375] pycriu: Dont produce zombies When running criu_dump() with zero pid (self dump) a zombie from the library is left underneath the running processes and this zombie is thus written into the images. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- lib/py/criu.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/py/criu.py b/lib/py/criu.py index 87257580e..c4a09ea2b 100644 --- a/lib/py/criu.py +++ b/lib/py/criu.py @@ -113,6 +113,9 @@ class _criu_comm_bin(_criu_comm): os._exit(0) else: exec_criu() + else: + if daemon: + os.waitpid(p, 0) css[0].close() self.swrk = struct.unpack('i', css[1].recv(4))[0] From d149adbcd9740eb51f4312de988333204c7004e6 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 13 Apr 2017 18:30:16 +0300 Subject: [PATCH 0491/4375] vdso: Speed up /proc/pid/maps parse This file is parsed on each start, it's nicer to make it use bfd engine and save several syscalls and #PFs. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/vdso.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index 5f7cad4ed..d8157cc3e 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -229,19 +229,28 @@ err: static int vdso_parse_maps(pid_t pid, struct vdso_symtable *s) { int exit_code = -1; - char buf[512]; - FILE *maps; + char *buf; + struct bfd f; *s = (struct vdso_symtable)VDSO_SYMTABLE_INIT; - maps = fopen_proc(pid, "maps"); - if (!maps) + f.fd = open_proc(pid, "maps"); + if (f.fd < 0) return -1; - while (fgets(buf, sizeof(buf), maps)) { + if (bfdopenr(&f)) + goto err; + + while (1) { unsigned long start, end; char *has_vdso, *has_vvar; + buf = breadline(&f); + if (buf == NULL) + break; + if (IS_ERR(buf)) + goto err; + has_vdso = strstr(buf, "[vdso]"); if (!has_vdso) has_vvar = strstr(buf, "[vvar]"); @@ -275,7 +284,7 @@ static int vdso_parse_maps(pid_t pid, struct vdso_symtable *s) exit_code = 0; err: - fclose(maps); + bclose(&f); return exit_code; } From 5859206432d90b482ff168a149059422c9f26466 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 14 Apr 2017 19:56:58 +0300 Subject: [PATCH 0492/4375] restore: Parse self maps via bfd When injecting the restorer blob criu parses /proc/self/maps file to find out the hole for the blob itself. It happens every time and the maps file for criu is now HUGE (~12k), so it's much more efficient to use bfd for it rather than glibc's fopen. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/proc_parse.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 5e9780a41..19a010e7f 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -422,20 +422,30 @@ static int vma_get_mapfile(const char *fname, struct vma_area *vma, DIR *mfd, int parse_self_maps_lite(struct vm_area_list *vms) { - FILE *maps; struct vma_area *prev = NULL; + struct bfd maps; + char *buf; vm_area_list_init(vms); - maps = fopen_proc(PROC_SELF, "maps"); - if (maps == NULL) + maps.fd = open_proc(PROC_SELF, "maps"); + if (maps.fd < 0) return -1; - while (fgets(buf, BUF_SIZE, maps) != NULL) { + if (bfdopenr(&maps)) + return -1; + + while (1) { struct vma_area *vma; char *end; unsigned long s, e; + buf = breadline(&maps); + if (!buf) + break; + if (IS_ERR(buf)) + goto err; + s = strtoul(buf, &end, 16); e = strtoul(end + 1, NULL, 16); @@ -448,10 +458,8 @@ int parse_self_maps_lite(struct vm_area_list *vms) prev->e->end = e; else { vma = alloc_vma_area(); - if (!vma) { - fclose(maps); - return -1; - } + if (!vma) + goto err; vma->e->start = s; vma->e->end = e; @@ -463,8 +471,12 @@ int parse_self_maps_lite(struct vm_area_list *vms) pr_debug("Parsed %"PRIx64"-%"PRIx64" vma\n", prev->e->start, prev->e->end); } - fclose(maps); + bclose(&maps); return 0; + +err: + bclose(&maps); + return -1; } #ifdef CONFIG_VDSO From 502eb4d9cc66d5a37823783fff4fa2a8e8283665 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Mar 2017 16:55:35 +0300 Subject: [PATCH 0493/4375] restore: Add add_post_prepare_cb_once helper Reviewed-by: Kirill Tkhai Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/crtools.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/criu/include/crtools.h b/criu/include/crtools.h index 658e269ce..15e074462 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -25,4 +25,17 @@ extern int cr_dedup(void); extern int check_add_feature(char *arg); extern void pr_check_features(const char *offset, const char *sep, int width); +#define add_post_prepare_cb_once(actor, data) \ + ({ \ + static int __cb_called = 0; \ + int ret = 0; \ + \ + if (!__cb_called) { \ + ret = add_post_prepare_cb(actor, data); \ + __cb_called = 1; \ + } \ + \ + ret; \ + }) + #endif /* __CR_CRTOOLS_H__ */ From 3e5b374288a0e3f07b6755aae07a0a4ba3307232 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Mar 2017 16:55:36 +0300 Subject: [PATCH 0494/4375] tty: Use add_post_prepare_cb_once Reviewed-by: Kirill Tkhai Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/tty.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/criu/tty.c b/criu/tty.c index d49aafd61..156f05e66 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -1625,12 +1625,9 @@ static int collect_one_tty(void *obj, ProtobufCMessage *msg, struct cr_img *i) pr_info("Collected tty ID %#x (%s)\n", info->tfe->id, info->driver->name); - if (list_empty(&all_ttys)) { - if (add_post_prepare_cb(tty_verify_active_pairs, NULL)) - return -1; - if (add_post_prepare_cb(tty_setup_slavery, NULL)) - return -1; - } + if (add_post_prepare_cb_once(tty_verify_active_pairs, NULL) || + add_post_prepare_cb_once(tty_setup_slavery, NULL)) + return -1; info->fdstore_id = -1; list_add(&info->list, &all_ttys); From c5615e6e5cdb61b66550e9edaa8fd934e373d3e0 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Mar 2017 16:55:37 +0300 Subject: [PATCH 0495/4375] pipes: Use add_post_prepare_cb_once Reviewed-by: Kirill Tkhai Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/pipes.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/criu/pipes.c b/criu/pipes.c index 4d15d739e..8b3fd6f84 100644 --- a/criu/pipes.c +++ b/criu/pipes.c @@ -372,9 +372,8 @@ int collect_one_pipe_ops(void *o, ProtobufCMessage *base, struct file_desc_ops * list_add(&pi->pipe_list, &tmp->pipe_list); } - if (list_empty(&pipes)) - if (add_post_prepare_cb(mark_pipe_master, NULL)) - return -1; + if (add_post_prepare_cb_once(mark_pipe_master, NULL)) + return -1; list_add_tail(&pi->list, &pipes); From 31cde250481b019e397e6ab9d4bf3c64d7da8e3d Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 4 Apr 2017 03:58:52 +0300 Subject: [PATCH 0496/4375] soccr: fix log messages and add a few more Signed-off-by: Andrei Vagin --- soccr/soccr.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/soccr/soccr.c b/soccr/soccr.c index cb3f7b9c1..0a7748149 100644 --- a/soccr/soccr.c +++ b/soccr/soccr.c @@ -76,7 +76,7 @@ void libsoccr_set_log(unsigned int level, void (*fn)(unsigned int level, const c log = fn; } -#define loge(msg, ...) do { if (log && (log_level >= SOCCR_LOG_ERR)) log(SOCCR_LOG_ERR, "Error: " msg, ##__VA_ARGS__); } while (0) +#define loge(msg, ...) do { if (log && (log_level >= SOCCR_LOG_ERR)) log(SOCCR_LOG_ERR, "Error (%s:%d): " msg, __FILE__, __LINE__, ##__VA_ARGS__); } while (0) #define logerr(msg, ...) loge(msg ": %s\n", ##__VA_ARGS__, strerror(errno)) #define logd(msg, ...) do { if (log && (log_level >= SOCCR_LOG_DBG)) log(SOCCR_LOG_DBG, "Debug: " msg, ##__VA_ARGS__); } while (0) @@ -121,8 +121,10 @@ struct libsoccr_sk *libsoccr_pause(int fd) struct libsoccr_sk *ret; ret = malloc(sizeof(*ret)); - if (!ret) + if (!ret) { + loge("Unable to allocate memory\n"); return NULL; + } if (tcp_repair_on(fd) < 0) { free(ret); @@ -321,8 +323,10 @@ static int get_queue(int sk, int queue_id, * make sure there are len bytes for real */ buf = malloc(len + 1); - if (!buf) + if (!buf) { + loge("Unable to allocate memory\n"); goto err_buf; + } ret = recv(sk, buf, len + 1, MSG_PEEK | MSG_DONTWAIT); if (ret != len) @@ -353,8 +357,10 @@ int libsoccr_save(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigne { struct tcp_info ti; - if (!data || data_size < SOCR_DATA_MIN_SIZE) + if (!data || data_size < SOCR_DATA_MIN_SIZE) { + loge("Invalid input parameters\n"); return -1; + } memset(data, 0, data_size); @@ -443,16 +449,22 @@ static int libsoccr_set_sk_data_noq(struct libsoccr_sk *sk, int onr = 0; __u32 seq; - if (!data || data_size < SOCR_DATA_MIN_SIZE) + if (!data || data_size < SOCR_DATA_MIN_SIZE) { + loge("Invalid input parameters\n"); return -1; + } - if (!sk->dst_addr || !sk->src_addr) + if (!sk->dst_addr || !sk->src_addr) { + loge("Destination or/and source addresses aren't set\n"); return -1; + } mstate = 1 << data->state; - if (data->state == TCP_LISTEN) + if (data->state == TCP_LISTEN) { + loge("Unable to handle listen sockets\n"); return -1; + } if (sk->src_addr->sa.sa_family == AF_INET) addr_size = sizeof(sk->src_addr->v4); @@ -460,7 +472,7 @@ static int libsoccr_set_sk_data_noq(struct libsoccr_sk *sk, addr_size = sizeof(sk->src_addr->v6); if (bind(sk->fd, &sk->src_addr->sa, addr_size)) { - loge("Can't bind inet socket back\n"); + logerr("Can't bind inet socket back"); return -1; } @@ -626,7 +638,7 @@ static int send_fin(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, l, /* libnet handle */ 0); /* libnet id */ else { - loge("Unknown socket family"); + loge("Unknown socket family\n"); goto err; } if (ret == -1) { @@ -636,7 +648,7 @@ static int send_fin(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, ret = libnet_write(l); if (ret == -1) { - loge("Unable to send a fin packet: %s", libnet_geterror(l)); + loge("Unable to send a fin packet: %s\n", libnet_geterror(l)); goto err; } From 4dd0735fc22d071fb27858447601758d2da860c9 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 13 Apr 2017 18:29:13 +0300 Subject: [PATCH 0497/4375] restore: Save some time mounting proc When restoring w/o namespaces it doesn't make sence to mount /proc by hands and detach it. We can just use the host-side one. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 5c9b9576e..072f9c04b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1249,19 +1249,24 @@ static int mount_proc(void) int fd, ret; char proc_mountpoint[] = "crtools-proc.XXXXXX"; - if (mkdtemp(proc_mountpoint) == NULL) { - pr_perror("mkdtemp failed %s", proc_mountpoint); - return -1; + if (root_ns_mask == 0) + fd = ret = open("/proc", O_DIRECTORY); + else { + if (mkdtemp(proc_mountpoint) == NULL) { + pr_perror("mkdtemp failed %s", proc_mountpoint); + return -1; + } + + pr_info("Mount procfs in %s\n", proc_mountpoint); + if (mount("proc", proc_mountpoint, "proc", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL)) { + pr_perror("mount failed"); + rmdir(proc_mountpoint); + return -1; + } + + ret = fd = open_detach_mount(proc_mountpoint); } - pr_info("Mount procfs in %s\n", proc_mountpoint); - if (mount("proc", proc_mountpoint, "proc", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL)) { - pr_perror("mount failed"); - rmdir(proc_mountpoint); - return -1; - } - - ret = fd = open_detach_mount(proc_mountpoint); if (fd >= 0) { ret = set_proc_fd(fd); close(fd); From eeb0afc4118e53aa76dca9f9870cc231ed1a7cb4 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 24 Apr 2017 16:41:24 +0300 Subject: [PATCH 0498/4375] make: Report dependencies absence more exactly I bumped in this myself when I had libc6-dev-i386 installed, while criu said I didn't. Save other guys'es time, spent in this place. Signed-off-by: Kirill Tkhai Acked-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.config b/Makefile.config index 0dd9d0433..ec6c2d145 100644 --- a/Makefile.config +++ b/Makefile.config @@ -25,8 +25,8 @@ ifeq ($(call try-cc,$(FEATURE_TEST_X86_COMPAT),-m32),true) export CONFIG_COMPAT := y FEATURE_DEFINES += -DCONFIG_COMPAT else - $(info Note: Building without ia32 C/R, missed packages:) - $(info $(info) libc6-dev-i386, gcc-multilib) + $(info Note: Building without ia32 C/R, missed package(s):) + $(info $(info) libc6-dev-i386 and/or gcc-multilib) endif endif From 99c7e7283dcc1826e008ce4f8984863014454256 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 24 Apr 2017 21:37:14 +0300 Subject: [PATCH 0499/4375] make: use aarch64 name for 64-bit ARM platform Let's call it aarch64 across all CRIU - as I was confused at least once with arm64 name in NMK and this arch-support check. Yet allowed to be named arm64, as NMK patch is separated. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index d70a413c0..cea5f747e 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ export HOSTCFLAGS # # Architecture specific options. -ifneq ($(filter-out x86 arm arm64 ppc64,$(ARCH)),) +ifneq ($(filter-out x86 arm arm64 aarch64 ppc64,$(ARCH)),) $(error "The architecture $(ARCH) isn't supported") endif @@ -35,7 +35,7 @@ ifeq ($(ARCH),arm) SRCARCH := arm endif -ifeq ($(ARCH),arm64) +ifneq ($(filter arm64 aarch64,$(ARCH)),) ARCH := aarch64 SRCARCH := aarch64 VDSO := y From a42ad2f033d0d0c45d9b525f3bc80811f7e53b38 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 24 Apr 2017 21:37:15 +0300 Subject: [PATCH 0500/4375] build/nmk: rename arm64 => aarch64 Let's keep the same name for 64-bit ARM platform across source. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/include.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nmk/scripts/include.mk b/scripts/nmk/scripts/include.mk index 711b9da7f..04ccb3ade 100644 --- a/scripts/nmk/scripts/include.mk +++ b/scripts/nmk/scripts/include.mk @@ -17,7 +17,7 @@ SUBARCH := $(shell uname -m | sed \ -e s/ppc64.*/ppc64/ \ -e s/mips.*/mips/ \ -e s/sh[234].*/sh/ \ - -e s/aarch64.*/arm64/) + -e s/aarch64.*/aarch64/) ARCH ?= $(SUBARCH) SRCARCH := $(ARCH) From 52188d31bec840038cea990a9e3ee7d60c19a569 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 24 Apr 2017 21:37:16 +0300 Subject: [PATCH 0501/4375] make: drop SRCARCH redefinition It's defined in NMK - don't redefine it. Remove BTW twice exports and twice definition of $(LDARCH). Call 64-bit ARM as aarch64. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index cea5f747e..7f757e127 100644 --- a/Makefile +++ b/Makefile @@ -21,40 +21,27 @@ export HOSTCFLAGS # # Architecture specific options. -ifneq ($(filter-out x86 arm arm64 aarch64 ppc64,$(ARCH)),) +ifneq ($(filter-out x86 arm aarch64 ppc64,$(ARCH)),) $(error "The architecture $(ARCH) isn't supported") endif ifeq ($(ARCH),x86) - SRCARCH := x86 LDARCH := i386:x86-64 VDSO := y endif -ifeq ($(ARCH),arm) - SRCARCH := arm -endif - -ifneq ($(filter arm64 aarch64,$(ARCH)),) - ARCH := aarch64 - SRCARCH := aarch64 +ifeq ($(ARCH),aarch64) VDSO := y endif ifeq ($(ARCH),ppc64) - SRCARCH := ppc64 LDARCH := powerpc:common64 VDSO := y endif LDARCH ?= $(SRCARCH) -export SRCARCH LDARCH VDSO - -SRCARCH ?= $(ARCH) -LDARCH ?= $(SRCARCH) - -export SRCARCH LDARCH VDSO +export LDARCH VDSO UNAME-M := $(shell uname -m) export UNAME-M From 3af5fb23c464f36ed8cd30bdf0f07d0338ab3c4d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 24 Apr 2017 21:37:17 +0300 Subject: [PATCH 0502/4375] make: separate supported architecture checks Arch-specific options will be clearer without support checks. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 7f757e127..ce16baaff 100644 --- a/Makefile +++ b/Makefile @@ -19,12 +19,22 @@ export CFLAGS HOSTCFLAGS ?= $(CFLAGS) export HOSTCFLAGS +UNAME-M := $(shell uname -m) + # -# Architecture specific options. +# Supported Architectures ifneq ($(filter-out x86 arm aarch64 ppc64,$(ARCH)),) $(error "The architecture $(ARCH) isn't supported") endif +# The PowerPC 64 bits architecture could be big or little endian. +# They are handled in the same way. +ifeq ($(UNAME-M),ppc64) + error := $(error ppc64 big endian is not yet supported) +endif + +# +# Architecture specific options. ifeq ($(ARCH),x86) LDARCH := i386:x86-64 VDSO := y @@ -43,9 +53,6 @@ LDARCH ?= $(SRCARCH) export LDARCH VDSO -UNAME-M := $(shell uname -m) -export UNAME-M - ifeq ($(ARCH),arm) ARMV := $(shell echo $(UNAME-M) | sed -nr 's/armv([[:digit:]]).*/\1/p; t; i7') DEFINES := -DCONFIG_ARMV$(ARMV) @@ -69,15 +76,7 @@ ifeq ($(ARCH),x86) DEFINES := -DCONFIG_X86_64 endif -# -# The PowerPC 64 bits architecture could be big or little endian. -# They are handled in the same way. -# ifeq ($(ARCH),ppc64) - ifeq ($(UNAME-M),ppc64) - error := $(error ppc64 big endian not yet supported) - endif - DEFINES := -DCONFIG_PPC64 endif From 578d57fb3dee0226fd4d5a1b16d13a3f3cb0ae23 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 24 Apr 2017 21:37:18 +0300 Subject: [PATCH 0503/4375] make: combine arch-specific options together DEFINES, LDARCH, VDSO in one place - visually simpler, more terse. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index ce16baaff..a4b96207e 100644 --- a/Makefile +++ b/Makefile @@ -35,24 +35,6 @@ endif # # Architecture specific options. -ifeq ($(ARCH),x86) - LDARCH := i386:x86-64 - VDSO := y -endif - -ifeq ($(ARCH),aarch64) - VDSO := y -endif - -ifeq ($(ARCH),ppc64) - LDARCH := powerpc:common64 - VDSO := y -endif - -LDARCH ?= $(SRCARCH) - -export LDARCH VDSO - ifeq ($(ARCH),arm) ARMV := $(shell echo $(UNAME-M) | sed -nr 's/armv([[:digit:]]).*/\1/p; t; i7') DEFINES := -DCONFIG_ARMV$(ARMV) @@ -69,17 +51,24 @@ ifeq ($(ARCH),arm) endif ifeq ($(ARCH),aarch64) - DEFINES := -DCONFIG_AARCH64 -endif - -ifeq ($(ARCH),x86) - DEFINES := -DCONFIG_X86_64 + VDSO := y + DEFINES := -DCONFIG_AARCH64 endif ifeq ($(ARCH),ppc64) + LDARCH := powerpc:common64 + VDSO := y DEFINES := -DCONFIG_PPC64 endif +ifeq ($(ARCH),x86) + LDARCH := i386:x86-64 + VDSO := y + DEFINES := -DCONFIG_X86_64 +endif + +LDARCH ?= $(SRCARCH) +export LDARCH VDSO export PROTOUFIX DEFINES USERCFLAGS # From 04b0a0bd7509cb209d072b276de7859ea02a73d7 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 24 Apr 2017 21:37:19 +0300 Subject: [PATCH 0504/4375] make: keep HOSTCFLAGS clean from target cflags HOSTCFLAGS are populated with CFLAGS if they are set from environment: CFLAGS=-O1 make But it turns out that =? operator, which sets variable iff it was unset previously - is recursive expanded operator. Which means that value of HOSTCFLAGS is evaluated every time it's used. Which is wrong with the current flaw in Makefile: 1. it assigns HOSTCFLAGS with CFLAGS from environment as recursive 2. it assigns target-related options to CFLAGS such as -march. 3. HOSTCFLAGS are used (with the current code - here they are expanded from CFLAGS). Which results in target-related options supplied to host objects building, which breaks cross-compilation. Fix by omitting recursive expansion for HOSTCFLAGS. Still we need to keep $(WARNINGS) and $(DEFINES) in HOSTCFLAGS. Link: https://lists.openvz.org/pipermail/criu/2017-April/037109.html Cc: Cyrill Gorcunov Reported-by: "Brinkmann, Harald" Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index a4b96207e..0f29fb959 100644 --- a/Makefile +++ b/Makefile @@ -13,11 +13,9 @@ $(__nmk_dir)%.mk: ; include $(__nmk_dir)include.mk include $(__nmk_dir)macro.mk -CFLAGS += $(USERCFLAGS) -export CFLAGS - -HOSTCFLAGS ?= $(CFLAGS) -export HOSTCFLAGS +ifeq ($(origin HOSTCFLAGS), undefined) + HOSTCFLAGS := $(CFLAGS) $(USERCFLAGS) +endif UNAME-M := $(shell uname -m) @@ -69,15 +67,13 @@ endif LDARCH ?= $(SRCARCH) export LDARCH VDSO -export PROTOUFIX DEFINES USERCFLAGS +export PROTOUFIX DEFINES # # Independent options for all tools. DEFINES += -D_FILE_OFFSET_BITS=64 DEFINES += -D_GNU_SOURCE -CFLAGS += $(USERCFLAGS) - WARNINGS := -Wall -Wformat-security CFLAGS-GCOV := --coverage -fno-exceptions -fno-inline @@ -111,7 +107,9 @@ ifeq ($(GMON),1) export GMON GMONLDOPT endif -CFLAGS += $(WARNINGS) $(DEFINES) -iquote include/ +CFLAGS += $(USERCFLAGS) $(WARNINGS) $(DEFINES) -iquote include/ +HOSTCFLAGS += $(WARNINGS) $(DEFINES) -iquote include/ +export CFLAGS USERCLFAGS HOSTCFLAGS # Default target all: criu lib From acda66c294827e1b2135de46df6eae1fbacc4115 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 25 Apr 2017 02:51:17 +0300 Subject: [PATCH 0505/4375] sysctl: surpress errors from open_proc Some sysctl-s are optional, so criu has to skip them silently Signed-off-by: Andrei Vagin --- criu/sysctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/sysctl.c b/criu/sysctl.c index f1e110ed3..4b15e1506 100644 --- a/criu/sysctl.c +++ b/criu/sysctl.c @@ -357,9 +357,9 @@ static int __nonuserns_sysctl_op(struct sysctl_req *req, size_t nr_req, int op) int fd; if (op == CTL_READ) - fd = open_proc(PROC_GEN, "sys/%s", req->name); + fd = do_open_proc(PROC_GEN, O_RDONLY, "sys/%s", req->name); else - fd = open_proc_rw(PROC_GEN, "sys/%s", req->name); + fd = do_open_proc(PROC_GEN, O_RDWR, "sys/%s", req->name); if (fd < 0) { if (errno == ENOENT && (req->flags & CTL_FLAGS_OPTIONAL)) { req++; From fa1fbe08b19010eeabfad9a80dc2e15915f915d1 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 19 Apr 2017 16:51:01 +0300 Subject: [PATCH 0506/4375] img: Move sigactions into core Right now they all sit in a separate file. Since we don't support CLONE_SIGHAND (and don't plan to) it's much better to have them in core, all the more so by the time we dump/restore sigacts, the core entry is at hands already. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 2 +- criu/cr-restore.c | 57 ++++++++++++++++++++++++++++++--- criu/include/image-desc.h | 2 +- criu/include/parasite-syscall.h | 2 +- criu/parasite-syscall.c | 33 +++++++++++-------- images/core.proto | 3 +- 6 files changed, 77 insertions(+), 22 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index d0639f398..6ff3dc66a 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1332,7 +1332,7 @@ static int dump_one_task(struct pstree_item *item) if (ret) goto err_cure; - ret = parasite_dump_sigacts_seized(parasite_ctl, cr_imgset); + ret = parasite_dump_sigacts_seized(parasite_ctl, item); if (ret) { pr_err("Can't dump sigactions (pid: %d) with parasite\n", pid); goto err_cure; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 072f9c04b..39f161aaa 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -421,6 +421,40 @@ static int restore_compat_sigaction(int sig, SaEntry *e) } #endif +static int prepare_sigactions_from_core(TaskCoreEntry *tc) +{ + int sig, i; + + if (tc->n_sigactions != SIGMAX - 2) { + pr_err("Bad number of sigactions in the image (%d, want %d)\n", + (int)tc->n_sigactions, SIGMAX - 2); + return -1; + } + + pr_info("Restore on-core sigactions for %d\n", vpid(current)); + + for (sig = 1, i = 0; sig <= SIGMAX; sig++) { + int ret; + SaEntry *e; + bool sigaction_is_compat; + + if (sig == SIGKILL || sig == SIGSTOP) + continue; + + e = tc->sigactions[i++]; + sigaction_is_compat = e->has_compat_sigaction && e->compat_sigaction; + if (sigaction_is_compat) + ret = restore_compat_sigaction(sig, e); + else + ret = restore_native_sigaction(sig, e); + + if (ret < 0) + return ret; + } + + return 0; +} + /* Returns number of restored signals, -1 or negative errno on fail */ static int restore_one_sigaction(int sig, struct cr_img *img, int pid) { @@ -453,16 +487,13 @@ static int restore_one_sigaction(int sig, struct cr_img *img, int pid) return ret; } -static int prepare_sigactions(void) +static int prepare_sigactions_from_image(void) { int pid = vpid(current); struct cr_img *img; int sig, rst = 0; int ret = 0; - if (!task_alive(current)) - return 0; - pr_info("Restore sigacts for %d\n", pid); img = open_image(CR_FD_SIGACT, O_RSTR, pid); @@ -484,10 +515,26 @@ static int prepare_sigactions(void) SIGMAX - 3 /* KILL, STOP and CHLD */); close_image(img); + return ret; +} + +static int prepare_sigactions(CoreEntry *core) +{ + int ret; + + if (!task_alive(current)) + return 0; + + if (core->tc->n_sigactions != 0) + ret = prepare_sigactions_from_core(core->tc); + else + ret = prepare_sigactions_from_image(); + if (stack32) { free_compat_syscall_stack(stack32); stack32 = NULL; } + return ret; } @@ -1442,7 +1489,7 @@ static int restore_task_with_children(void *_arg) if (prepare_mappings(current)) goto err; - if (prepare_sigactions() < 0) + if (prepare_sigactions(ca->core) < 0) goto err; if (fault_injected(FI_RESTORE_ROOT_ONLY)) { diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 09d187d22..eba5d00a1 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -14,7 +14,6 @@ enum { CR_FD_CORE, CR_FD_IDS, CR_FD_MM, - CR_FD_SIGACT, CR_FD_CREDS, CR_FD_FS, _CR_FD_TASK_TO, @@ -89,6 +88,7 @@ enum { CR_FD_BINFMT_MISC_OLD, CR_FD_PAGES, + CR_FD_SIGACT, CR_FD_VMAS, CR_FD_PAGES_OLD, CR_FD_SHM_PAGES_OLD, diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 3887446d6..7a09d105e 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -22,7 +22,7 @@ struct rt_sigframe; struct parasite_ctl; -extern int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_imgset); +extern int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct pstree_item *); extern int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct pstree_item *); struct proc_posix_timers_stat; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index e4ce028f1..3afc7b651 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -215,12 +215,12 @@ err_rth: return -1; } -int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_imgset) +int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct pstree_item *item) { + TaskCoreEntry *tc = item->core[0]->tc; struct parasite_dump_sa_args *args; int ret, sig; - struct cr_img *img; - SaEntry se = SA_ENTRY__INIT; + SaEntry *sa, **psa; args = compel_parasite_args(ctl, struct parasite_dump_sa_args); @@ -228,7 +228,14 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_ if (ret < 0) return ret; - img = img_from_set(cr_imgset, CR_FD_SIGACT); + psa = xmalloc((SIGMAX - 2) * (sizeof(SaEntry *) + sizeof(SaEntry))); + if (!psa) + return -1; + + sa = (SaEntry *)(psa + SIGMAX - 2); + + tc->n_sigactions = SIGMAX - 2; + tc->sigactions = psa; for (sig = 1; sig <= SIGMAX; sig++) { int i = sig - 1; @@ -236,16 +243,16 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_ if (sig == SIGSTOP || sig == SIGKILL) continue; - ASSIGN_TYPED(se.sigaction, encode_pointer(args->sas[i].rt_sa_handler)); - ASSIGN_TYPED(se.flags, args->sas[i].rt_sa_flags); - ASSIGN_TYPED(se.restorer, encode_pointer(args->sas[i].rt_sa_restorer)); - BUILD_BUG_ON(sizeof(se.mask) != sizeof(args->sas[0].rt_sa_mask.sig)); - memcpy(&se.mask, args->sas[i].rt_sa_mask.sig, sizeof(se.mask)); - se.has_compat_sigaction = true; - se.compat_sigaction = !compel_mode_native(ctl); + sa_entry__init(sa); + ASSIGN_TYPED(sa->sigaction, encode_pointer(args->sas[i].rt_sa_handler)); + ASSIGN_TYPED(sa->flags, args->sas[i].rt_sa_flags); + ASSIGN_TYPED(sa->restorer, encode_pointer(args->sas[i].rt_sa_restorer)); + BUILD_BUG_ON(sizeof(sa->mask) != sizeof(args->sas[0].rt_sa_mask.sig)); + memcpy(&sa->mask, args->sas[i].rt_sa_mask.sig, sizeof(sa->mask)); + sa->has_compat_sigaction = true; + sa->compat_sigaction = !compel_mode_native(ctl); - if (pb_write_one(img, &se, PB_SIGACT) < 0) - return -1; + *(psa++) = sa++; } return 0; diff --git a/images/core.proto b/images/core.proto index 9c2254d32..1f13d4484 100644 --- a/images/core.proto +++ b/images/core.proto @@ -8,7 +8,7 @@ import "core-ppc64.proto"; import "rlimit.proto"; import "timer.proto"; import "creds.proto"; - +import "sa.proto"; import "siginfo.proto"; import "opts.proto"; @@ -45,6 +45,7 @@ message task_core_entry { optional uint32 loginuid = 13; optional int32 oom_score_adj = 14; + repeated sa_entry sigactions = 15; } message task_kobj_ids_entry { From 44e966e43381a39b6664b0fb31c36e6dc59adccc Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 24 Apr 2017 21:35:17 +0300 Subject: [PATCH 0507/4375] test/make: suppress "Nothing to be done for `default'." Let's pretend that we're doing something ;-D FWIW: cleaning two lines in the test output: Acked-by: Cyrill Gorcunov ========================== Run zdtm/static/tty03 in h ========================== make[2]: Nothing to be done for `default'. Start test make[2]: Nothing to be done for `default'. ./tty03 --pidfile=tty03.pid --outfile=tty03.out Run criu dump Run criu restore Send the 15 signal to 24 Wait for zdtm/static/tty03(24) to die for 0.100000 Removing dump/zdtm/static/tty03/24 ========================= Test zdtm/static/tty03 PASS ========================== Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/Makefile.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index 79f0fc628..91d9a36ac 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -58,6 +58,7 @@ DEPEND.c = $(COMPILE.c) -MM -MP $(Q)$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ default: all + @true .PHONY: default gitignore-clean: From 0d945c97c22782c9f8e885c9e813285695bbaed2 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 24 Apr 2017 15:51:47 +0300 Subject: [PATCH 0508/4375] make: don't run feature-tests for tags/etags/cscope Each `make tags` resulted in running feature-tests. That's not needed for tags generation. Don't waste time on tests as we don't compile anything. Reported-by: Kirill Tkhai Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0f29fb959..82acb2b47 100644 --- a/Makefile +++ b/Makefile @@ -167,7 +167,7 @@ criu-deps += include/common/asm # # Configure variables. export CONFIG_HEADER := criu/include/config.h -ifeq ($(filter clean mrproper,$(MAKECMDGOALS)),) +ifeq ($(filter tags etags cscope clean mrproper,$(MAKECMDGOALS)),) include Makefile.config else # To clean all files, enable make/build options here From dd3f23e28df137908ceb47f6a5fdf9ef4d8ab7b6 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 28 Apr 2017 21:30:46 +0300 Subject: [PATCH 0509/4375] cr-restore: prepare removing arch_export_unmap_compat for !CONFIG_COMPAT We don't need __export_unmap_compat() for !CONFIG_COMPAT in restorer blob. This preparation will allow to move compatible unmap that's written in x86 asm from generic restorer blob to arch/x86. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 39f161aaa..47b060d8f 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2931,6 +2931,15 @@ static int rst_prep_creds(pid_t pid, CoreEntry *core, unsigned long *creds_pos) return 0; } +static void *restorer_munmap_addr(CoreEntry *core, void *restorer_blob) +{ +#ifdef CONFIG_COMPAT + if (core_is_compat(core)) + return restorer_sym(restorer_blob, arch_export_unmap_compat); +#endif + return restorer_sym(restorer_blob, arch_export_unmap); +} + static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, unsigned long alen, CoreEntry *core) { void *mem = MAP_FAILED; @@ -3036,12 +3045,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns */ task_args->clone_restore_fn = restorer_sym(mem, arch_export_restore_thread); restore_task_exec_start = restorer_sym(mem, arch_export_restore_task); - if (core_is_compat(core)) - rsti(current)->munmap_restorer = - restorer_sym(mem, arch_export_unmap_compat); - else - rsti(current)->munmap_restorer = - restorer_sym(mem, arch_export_unmap); + rsti(current)->munmap_restorer = restorer_munmap_addr(core, mem); task_args->bootstrap_start = mem; mem += restorer_len; From 8544895a528b78878747d13ab24bb6a23c883ebf Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 28 Apr 2017 21:30:47 +0300 Subject: [PATCH 0510/4375] ia32/restorer: move 32-bit pie unmap to x86 We need compat realization for restorer unmap as after rt_sigreturn() the task is stopped it 32-bit code and ptrace API doesn't allow setting x86_64 full registers set to ia32 task. Generic restorer has now x86-specific __export_unmap_compat() function, which isn't right. Clean restorer from x86-related realization. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/restorer_unmap.S | 12 ++++++++++++ criu/pie/Makefile | 1 + criu/pie/restorer.c | 25 ++----------------------- 3 files changed, 15 insertions(+), 23 deletions(-) create mode 100644 criu/arch/x86/restorer_unmap.S diff --git a/criu/arch/x86/restorer_unmap.S b/criu/arch/x86/restorer_unmap.S new file mode 100644 index 000000000..09c4c9583 --- /dev/null +++ b/criu/arch/x86/restorer_unmap.S @@ -0,0 +1,12 @@ +#include "common/asm/linkage.h" +#include "compel/plugins/std/syscall-codes.h" + + .text +ENTRY(__export_unmap_compat) + .code32 + mov bootstrap_start, %ebx + mov bootstrap_len, %ecx + movl $__NR32_munmap, %eax + int $0x80 + int $0x03 /* Guard */ + .code64 diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 6a4fba9c1..73d95d5f1 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -25,6 +25,7 @@ restorer-obj-y += ./$(ARCH_DIR)/restorer.o ifeq ($(ARCH),x86) ifeq ($(CONFIG_COMPAT),y) restorer-obj-y += ./$(ARCH_DIR)/call32.o + restorer-obj-y += ./$(ARCH_DIR)/restorer_unmap.o restorer-obj-y += ./$(ARCH_DIR)/sigaction_compat_pie.o endif endif diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index a106f79d4..807388743 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -929,35 +929,14 @@ static unsigned long vdso_rt_size; #define vdso_rt_size (0) #endif -static void *bootstrap_start; -static unsigned int bootstrap_len; +void *bootstrap_start = NULL; +unsigned int bootstrap_len = 0; void __export_unmap(void) { sys_munmap(bootstrap_start, bootstrap_len - vdso_rt_size); } -#ifdef CONFIG_X86_64 -asm ( - " .pushsection .text\n" - " .global __export_unmap_compat\n" - "__export_unmap_compat:\n" - " .code32\n" - " mov bootstrap_start, %ebx\n" - " mov bootstrap_len, %ecx\n" - " sub vdso_rt_size, %ecx\n" - " movl $"__stringify(__NR32_munmap)", %eax\n" - " int $0x80\n" - " .code64\n" - " .popsection\n" -); -extern char __export_unmap_compat; -#else -void __export_unmap_compat(void) -{ -} -#endif - /* * This function unmaps all VMAs, which don't belong to * the restored process or the restorer. From a7281b11fd6e31d654e2ace387fe6677dff86fa6 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 22 Apr 2017 01:02:37 +0300 Subject: [PATCH 0511/4375] test: restore ns_last_pid before executing restore in a second time It is required for cases when we inject a fault in criu restore. In this case we execute "criu restore" and check that it fails, then we execute "criu restore" without a fault and check that it passes. If the first "criu restore" restores only a part of processes, the second criu can get PID of one of restored processes. https://github.com/xemul/criu/issues/282 Signed-off-by: Andrei Vagin --- test/zdtm.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index fcbacbd2a..ffa48a8d1 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -851,6 +851,8 @@ class criu: status_fds = os.pipe() s_args += ["--status-fd", str(status_fds[1])] + ns_last_pid = open("/proc/sys/kernel/ns_last_pid").read() + ret = self.__criu.run(action, s_args, self.__fault, strace, preexec, nowait) if nowait: @@ -873,6 +875,9 @@ class criu: else: # on restore we move only a log file, because we need images os.rename(os.path.join(__ddir, log), os.path.join(__ddir, log + ".fail")) + # restore ns_last_pid to avoid a case when criu gets + # PID of one of restored processes. + open("/proc/sys/kernel/ns_last_pid", "w+").write(ns_last_pid) # try again without faults print "Run criu " + action ret = self.__criu.run(action, s_args, False, strace, preexec) From 7393a4b7f9007e9c81e920de2628bbf68cb0f485 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 15 Feb 2017 02:59:26 +0300 Subject: [PATCH 0512/4375] restore: add a function to wait when other tasks finish a stage It is used now to close descriptors of mount namespaces and will be used for network namespaces too. Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 47b060d8f..5f262b5a2 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -120,6 +120,7 @@ static int prepare_rlimits(int pid, struct task_restore_args *, CoreEntry *core) static int prepare_posix_timers(int pid, struct task_restore_args *ta, CoreEntry *core); static int prepare_signals(int pid, struct task_restore_args *, CoreEntry *core); +static void restore_wait_other_tasks(); static int crtools_prepare_shared(void) { @@ -1511,7 +1512,7 @@ static int restore_task_with_children(void *_arg) * Wait when all tasks passed the CR_STATE_FORKING stage. * It means that all tasks entered into their namespaces. */ - futex_wait_while_gt(&task_entries->nr_in_progress, 1); + restore_wait_other_tasks(); fini_restore_mntns(); } @@ -1556,6 +1557,26 @@ static inline int stage_participants(int next_stage) return -1; } +static inline int stage_current_participants(int next_stage) +{ + switch (next_stage) { + case CR_STATE_FORKING: + return 1; + case CR_STATE_RESTORE: + /* + * Each thread has to be reported about this stage, + * so if we want to wait all other tast, we have to + * exclude all threads of the current process. + * It is supposed that we will wait other tasks, + * before creating threads of the current task. + */ + return current->nr_threads; + } + + BUG(); + return -1; +} + static int restore_wait_inprogress_tasks() { int ret; @@ -1584,6 +1605,18 @@ static int restore_switch_stage(int next_stage) return restore_wait_inprogress_tasks(); } +/* Wait all tasks except the current one */ +static void restore_wait_other_tasks() +{ + int participants, stage; + + stage = futex_get(&task_entries->start); + participants = stage_current_participants(stage); + + futex_wait_while_gt(&task_entries->nr_in_progress, + participants); +} + static int attach_to_tasks(bool root_seized) { struct pstree_item *item; From 6b44cd8ea93e2fafafddf1aec4fb70690bb84d05 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Apr 2017 15:27:24 +0300 Subject: [PATCH 0513/4375] restore: Remove bogus futex kick The restore_switch_stage() already waits tasks at the end, so there's no need in one more waiting. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 5f262b5a2..09356fe29 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1942,11 +1942,6 @@ static int restore_root_task(struct pstree_item *init) goto out_kill; ret = restore_switch_stage(CR_STATE_POST_RESTORE_NS); - if (ret < 0) - goto out_kill; - - pr_info("Wait until namespaces are created\n"); - ret = restore_wait_inprogress_tasks(); if (ret) goto out_kill; From fad59b7b24d0dd9bfb02df8ba1762c58ef4d0dc1 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Apr 2017 15:27:42 +0300 Subject: [PATCH 0514/4375] restore: Normalize first and last staging switches Don't set futexes by hands, use the restore_switch_stage helpers explicitly (for code readability). Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 09356fe29..0c6bfc32d 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1592,10 +1592,18 @@ static int restore_wait_inprogress_tasks() return 0; } -static void __restore_switch_stage(int next_stage) +static inline void __restore_switch_stage_nw(int next_stage) { futex_set(&task_entries->nr_in_progress, stage_participants(next_stage)); + futex_set(&task_entries->start, next_stage); +} + +static inline void __restore_switch_stage(int next_stage) +{ + if (next_stage != CR_STATE_COMPLETE) + futex_set(&task_entries->nr_in_progress, + stage_participants(next_stage)); futex_set_and_wake(&task_entries->start, next_stage); } @@ -1893,8 +1901,7 @@ static int restore_root_task(struct pstree_item *init) if (prepare_namespace_before_tasks()) return -1; - futex_set(&task_entries->nr_in_progress, - stage_participants(CR_STATE_RESTORE_NS)); + __restore_switch_stage_nw(CR_STATE_RESTORE_NS); ret = fork_with_pid(init); if (ret < 0) @@ -2051,7 +2058,7 @@ static int restore_root_task(struct pstree_item *init) ret = catch_tasks(root_seized, &flag); pr_info("Restore finished successfully. Resuming tasks.\n"); - futex_set_and_wake(&task_entries->start, CR_STATE_COMPLETE); + __restore_switch_stage(CR_STATE_COMPLETE); if (ret == 0) ret = compel_stop_on_syscall(task_entries->nr_threads, @@ -2130,7 +2137,7 @@ static int prepare_task_entries(void) task_entries->nr_threads = 0; task_entries->nr_tasks = 0; task_entries->nr_helpers = 0; - futex_set(&task_entries->start, CR_STATE_RESTORE_NS); + futex_set(&task_entries->start, CR_STATE_FAIL); mutex_init(&task_entries->userns_sync_lock); return 0; From e571ef6294215b77e36cbd52675eac9aa1ea8036 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Apr 2017 15:27:55 +0300 Subject: [PATCH 0515/4375] restore: Fix indentation of one if Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 0c6bfc32d..74e6874f4 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1427,8 +1427,8 @@ static int restore_task_with_children(void *_arg) /* Wait prepare_userns */ if (current->parent == NULL && - restore_finish_stage(task_entries, CR_STATE_RESTORE_NS) < 0) - goto err; + restore_finish_stage(task_entries, CR_STATE_RESTORE_NS) < 0) + goto err; /* * Call this _before_ forking to optimize cgroups From 6d9ec5ec8630210e045884c0634fd6e1ce455a5e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Apr 2017 15:28:10 +0300 Subject: [PATCH 0516/4375] restore: Move staging switch/wait code to the top of the file Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 183 +++++++++++++++++++++++----------------------- 1 file changed, 91 insertions(+), 92 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 74e6874f4..5fd0e0a4b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -120,7 +120,97 @@ static int prepare_rlimits(int pid, struct task_restore_args *, CoreEntry *core) static int prepare_posix_timers(int pid, struct task_restore_args *ta, CoreEntry *core); static int prepare_signals(int pid, struct task_restore_args *, CoreEntry *core); -static void restore_wait_other_tasks(); +static inline int stage_participants(int next_stage) +{ + switch (next_stage) { + case CR_STATE_FAIL: + return 0; + case CR_STATE_RESTORE_NS: + case CR_STATE_POST_RESTORE_NS: + case CR_STATE_RESTORE_SHARED: + return 1; + case CR_STATE_FORKING: + return task_entries->nr_tasks + task_entries->nr_helpers; + case CR_STATE_RESTORE: + return task_entries->nr_threads + task_entries->nr_helpers; + case CR_STATE_RESTORE_SIGCHLD: + return task_entries->nr_threads; + case CR_STATE_RESTORE_CREDS: + return task_entries->nr_threads; + } + + BUG(); + return -1; +} + +static inline int stage_current_participants(int next_stage) +{ + switch (next_stage) { + case CR_STATE_FORKING: + return 1; + case CR_STATE_RESTORE: + /* + * Each thread has to be reported about this stage, + * so if we want to wait all other tast, we have to + * exclude all threads of the current process. + * It is supposed that we will wait other tasks, + * before creating threads of the current task. + */ + return current->nr_threads; + } + + BUG(); + return -1; +} + +static int restore_wait_inprogress_tasks() +{ + int ret; + futex_t *np = &task_entries->nr_in_progress; + + futex_wait_while_gt(np, 0); + ret = (int)futex_get(np); + if (ret < 0) { + set_cr_errno(get_task_cr_err()); + return ret; + } + + return 0; +} + +static inline void __restore_switch_stage_nw(int next_stage) +{ + futex_set(&task_entries->nr_in_progress, + stage_participants(next_stage)); + futex_set(&task_entries->start, next_stage); +} + +static inline void __restore_switch_stage(int next_stage) +{ + if (next_stage != CR_STATE_COMPLETE) + futex_set(&task_entries->nr_in_progress, + stage_participants(next_stage)); + futex_set_and_wake(&task_entries->start, next_stage); +} + +static int restore_switch_stage(int next_stage) +{ + __restore_switch_stage(next_stage); + return restore_wait_inprogress_tasks(); +} + +/* Wait all tasks except the current one */ +static void restore_wait_other_tasks() +{ + int participants, stage; + + stage = futex_get(&task_entries->start); + participants = stage_current_participants(stage); + + futex_wait_while_gt(&task_entries->nr_in_progress, + participants); +} + static int crtools_prepare_shared(void) { @@ -1534,97 +1624,6 @@ err: exit(1); } -static inline int stage_participants(int next_stage) -{ - switch (next_stage) { - case CR_STATE_FAIL: - return 0; - case CR_STATE_RESTORE_NS: - case CR_STATE_POST_RESTORE_NS: - case CR_STATE_RESTORE_SHARED: - return 1; - case CR_STATE_FORKING: - return task_entries->nr_tasks + task_entries->nr_helpers; - case CR_STATE_RESTORE: - return task_entries->nr_threads + task_entries->nr_helpers; - case CR_STATE_RESTORE_SIGCHLD: - return task_entries->nr_threads; - case CR_STATE_RESTORE_CREDS: - return task_entries->nr_threads; - } - - BUG(); - return -1; -} - -static inline int stage_current_participants(int next_stage) -{ - switch (next_stage) { - case CR_STATE_FORKING: - return 1; - case CR_STATE_RESTORE: - /* - * Each thread has to be reported about this stage, - * so if we want to wait all other tast, we have to - * exclude all threads of the current process. - * It is supposed that we will wait other tasks, - * before creating threads of the current task. - */ - return current->nr_threads; - } - - BUG(); - return -1; -} - -static int restore_wait_inprogress_tasks() -{ - int ret; - futex_t *np = &task_entries->nr_in_progress; - - futex_wait_while_gt(np, 0); - ret = (int)futex_get(np); - if (ret < 0) { - set_cr_errno(get_task_cr_err()); - return ret; - } - - return 0; -} - -static inline void __restore_switch_stage_nw(int next_stage) -{ - futex_set(&task_entries->nr_in_progress, - stage_participants(next_stage)); - futex_set(&task_entries->start, next_stage); -} - -static inline void __restore_switch_stage(int next_stage) -{ - if (next_stage != CR_STATE_COMPLETE) - futex_set(&task_entries->nr_in_progress, - stage_participants(next_stage)); - futex_set_and_wake(&task_entries->start, next_stage); -} - -static int restore_switch_stage(int next_stage) -{ - __restore_switch_stage(next_stage); - return restore_wait_inprogress_tasks(); -} - -/* Wait all tasks except the current one */ -static void restore_wait_other_tasks() -{ - int participants, stage; - - stage = futex_get(&task_entries->start); - participants = stage_current_participants(stage); - - futex_wait_while_gt(&task_entries->nr_in_progress, - participants); -} - static int attach_to_tasks(bool root_seized) { struct pstree_item *item; From 5b870266a35a9b70d5825f322504f39e72e75401 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Apr 2017 15:28:25 +0300 Subject: [PATCH 0517/4375] restore: Rename CR_STATE_RESTORE_NS -> _ROOT_TASK The stage name is what tasks do, not what criu waits for. When the first stage is started we want the root task to come up, rather than namespaces to get restored. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 6 +++--- criu/include/restorer.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 5fd0e0a4b..36f8e1ca4 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -125,7 +125,7 @@ static inline int stage_participants(int next_stage) switch (next_stage) { case CR_STATE_FAIL: return 0; - case CR_STATE_RESTORE_NS: + case CR_STATE_ROOT_TASK: case CR_STATE_POST_RESTORE_NS: case CR_STATE_RESTORE_SHARED: return 1; @@ -1517,7 +1517,7 @@ static int restore_task_with_children(void *_arg) /* Wait prepare_userns */ if (current->parent == NULL && - restore_finish_stage(task_entries, CR_STATE_RESTORE_NS) < 0) + restore_finish_stage(task_entries, CR_STATE_ROOT_TASK) < 0) goto err; /* @@ -1900,7 +1900,7 @@ static int restore_root_task(struct pstree_item *init) if (prepare_namespace_before_tasks()) return -1; - __restore_switch_stage_nw(CR_STATE_RESTORE_NS); + __restore_switch_stage_nw(CR_STATE_ROOT_TASK); ret = fork_with_pid(init); if (ret < 0) diff --git a/criu/include/restorer.h b/criu/include/restorer.h index d0f786d94..27767173c 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -201,7 +201,7 @@ static inline unsigned long restorer_stack(struct restore_mem_zone *mz) enum { CR_STATE_FAIL = -1, - CR_STATE_RESTORE_NS = 0, /* is used for executing "setup-namespace" scripts */ + CR_STATE_ROOT_TASK = 0, /* is used for executing "setup-namespace" scripts */ /* * Need to wait a mount namespace which * will be used to clean up remap files. From 16214d99eee8226c3a67bad1018c5f3c944405b0 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Apr 2017 15:28:41 +0300 Subject: [PATCH 0518/4375] restore: Rename CR_STATE_POST_RESTORE_NS -> _PREPARE_NAMESPACES This is wat root task does -- calls prepare_namespace(). Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 6 +++--- criu/include/restorer.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 36f8e1ca4..26376aa7b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -126,7 +126,7 @@ static inline int stage_participants(int next_stage) case CR_STATE_FAIL: return 0; case CR_STATE_ROOT_TASK: - case CR_STATE_POST_RESTORE_NS: + case CR_STATE_PREPARE_NAMESPACES: case CR_STATE_RESTORE_SHARED: return 1; case CR_STATE_FORKING: @@ -1564,7 +1564,7 @@ static int restore_task_with_children(void *_arg) if (prepare_namespace(current, ca->clone_flags)) goto err; - if (restore_finish_stage(task_entries, CR_STATE_POST_RESTORE_NS) < 0) + if (restore_finish_stage(task_entries, CR_STATE_PREPARE_NAMESPACES) < 0) goto err; if (root_prepare_shared()) @@ -1947,7 +1947,7 @@ static int restore_root_task(struct pstree_item *init) if (ret) goto out_kill; - ret = restore_switch_stage(CR_STATE_POST_RESTORE_NS); + ret = restore_switch_stage(CR_STATE_PREPARE_NAMESPACES); if (ret) goto out_kill; diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 27767173c..4deaf78d5 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -206,7 +206,7 @@ enum { * Need to wait a mount namespace which * will be used to clean up remap files. */ - CR_STATE_POST_RESTORE_NS, + CR_STATE_PREPARE_NAMESPACES, CR_STATE_RESTORE_SHARED, CR_STATE_FORKING, CR_STATE_RESTORE, From eb43ea2389904447cfdfc9fd89143e06b99e378e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Apr 2017 15:28:55 +0300 Subject: [PATCH 0519/4375] restore: Kill CR_STATE_RESTORE_SHARED Looks like this separate stage is not needed. The scripts involved in ns restore are synchronized with existing stages like this: criu: root task: ROOT_TASK stage "setup-ns" script PREPARE_NAMESPACES prepare_namespace() "post-setup-ns" script FORKING restore_task_mnt_ns() which seems to be OK. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 11 ++--------- criu/include/restorer.h | 1 - 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 26376aa7b..8dee80d85 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -127,7 +127,6 @@ static inline int stage_participants(int next_stage) return 0; case CR_STATE_ROOT_TASK: case CR_STATE_PREPARE_NAMESPACES: - case CR_STATE_RESTORE_SHARED: return 1; case CR_STATE_FORKING: return task_entries->nr_tasks + task_entries->nr_helpers; @@ -1569,9 +1568,6 @@ static int restore_task_with_children(void *_arg) if (root_prepare_shared()) goto err; - - if (restore_finish_stage(task_entries, CR_STATE_RESTORE_SHARED) < 0) - goto err; } if (restore_task_mnt_ns(current)) @@ -1970,15 +1966,12 @@ static int restore_root_task(struct pstree_item *init) goto out_kill; } - timing_start(TIME_FORK); - ret = restore_switch_stage(CR_STATE_RESTORE_SHARED); - if (ret < 0) - goto out_kill; - ret = run_scripts(ACT_POST_SETUP_NS); if (ret) goto out_kill; + timing_start(TIME_FORK); + ret = restore_switch_stage(CR_STATE_FORKING); if (ret < 0) goto out_kill; diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 4deaf78d5..4eb18d31f 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -207,7 +207,6 @@ enum { * will be used to clean up remap files. */ CR_STATE_PREPARE_NAMESPACES, - CR_STATE_RESTORE_SHARED, CR_STATE_FORKING, CR_STATE_RESTORE, CR_STATE_RESTORE_SIGCHLD, From 3ebe6c833813481d50099f61830b7547a4dff511 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Apr 2017 15:29:12 +0300 Subject: [PATCH 0520/4375] restore: Write comments about stages Describe what the tasks do during restore and what the expectations at the sync points are. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/restorer.h | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 4eb18d31f..9a40c7e0e 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -200,17 +200,47 @@ static inline unsigned long restorer_stack(struct restore_mem_zone *mz) } enum { - CR_STATE_FAIL = -1, - CR_STATE_ROOT_TASK = 0, /* is used for executing "setup-namespace" scripts */ /* - * Need to wait a mount namespace which - * will be used to clean up remap files. + * Restore stages. The stage is started by criu process, then + * confirmed by all tasks involved in it. Then criu does some + * actions and starts the next stage. + * + * The first stated stage is CR_STATE_ROOT_TASK which is started + * right before calling fork_with_pid() for the root_item. + */ + CR_STATE_FAIL = -1, + /* + * Root task is created and does some pre-checks. + * After the stage ACT_SETUP_NS scripts are performed. + */ + CR_STATE_ROOT_TASK = 0, + /* + * The prepare_namespace() is called. + * After the stage criu opens root task's mntns and + * calls ACT_POST_SETUP_NS scripts. */ CR_STATE_PREPARE_NAMESPACES, + /* + * All tasks fork and call open_transport_socket(). + * Stage is needed to make sure they all have the socket. + */ CR_STATE_FORKING, + /* + * Main restore stage. By the end of it all tasks are + * almost ready and what's left is: + * pick up zombies and helpers + * restore sigchild handlers used to detect restore errors + * restore credentials + */ CR_STATE_RESTORE, + /* + * Tasks restore sigchild handlers. + * Stage is needed to synchronize the change in error + * propagation via sigchild. + */ CR_STATE_RESTORE_SIGCHLD, /* + * Final stage. * For security reason processes can be resumed only when all * credentials are restored. Otherwise someone can attach to a * process, which are not restored credentials yet and execute From 3bd08b7701e5adb03af3c19882e44b75f2ec6dad Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Apr 2017 15:29:26 +0300 Subject: [PATCH 0521/4375] restore: Relax the FORKING stage Here's why: This stage is needed to make sure all tasks have appeared and did some actions (that are called before restore_finish_stage()). With this description there's no need in involving criu process in it, this stage is purely inter-tasks sync point. Taking into account we do already make root task wait for others to complete forking (it calls restore_wait_ther_tasks()) we may rework this stage not to involve criu process in it. Here's how: So the criu task starts the forking stage, then goes waiting for "inprogress tasks". The latter wait is purely about nr_in_progress counter, thus there's no strict requirement that the stage remains the same by the time criu is woken up. Siad that, the root task waits for other tasks to finish forking, does fini_restore_mntns() (already in the code), then switches the stage to the next (the RESTORE one). Other tasks do normal staging barrier. Criu task is not woken up as nr_in_progress always remains >= 1. The result is -2 context switches -- from root task to criu and back -- which gives us good boost when restoring single task app. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 45 ++++++++++++++++++++++------------------- criu/include/restorer.h | 15 ++++++++++++++ 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 8dee80d85..1ef1c25d4 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1584,30 +1584,37 @@ static int restore_task_with_children(void *_arg) BUG(); } + timing_start(TIME_FORK); + if (create_children_and_session()) goto err; + timing_stop(TIME_FORK); if (unmap_guard_pages(current)) goto err; restore_pgid(); - if (current->parent == NULL) { - /* - * Wait when all tasks passed the CR_STATE_FORKING stage. - * It means that all tasks entered into their namespaces. - */ - restore_wait_other_tasks(); - - fini_restore_mntns(); - } - if (open_transport_socket()) return -1; - if (restore_finish_stage(task_entries, CR_STATE_FORKING) < 0) - goto err; + if (current->parent == NULL) { + /* + * Wait when all tasks passed the CR_STATE_FORKING stage. + * The stage was started by criu, but now it waits for + * the CR_STATE_RESTORE to finish. See comment near the + * CR_STATE_FORKING macro for details. + * + * It means that all tasks entered into their namespaces. + */ + restore_wait_other_tasks(); + fini_restore_mntns(); + __restore_switch_stage(CR_STATE_RESTORE); + } else { + if (restore_finish_stage(task_entries, CR_STATE_FORKING) < 0) + goto err; + } if (restore_one_task(vpid(current), ca->core)) goto err; @@ -1970,19 +1977,15 @@ static int restore_root_task(struct pstree_item *init) if (ret) goto out_kill; - timing_start(TIME_FORK); - ret = restore_switch_stage(CR_STATE_FORKING); if (ret < 0) goto out_kill; - timing_stop(TIME_FORK); - - ret = restore_switch_stage(CR_STATE_RESTORE); - if (ret < 0) - goto out_kill; - - /* Zombies die after CR_STATE_RESTORE */ + /* + * Zombies die after CR_STATE_RESTORE which is switched + * by root task, not by us. See comment before CR_STATE_FORKING + * in the header for details. + */ for_each_pstree_item(item) { if (item->pid->state == TASK_DEAD) task_entries->nr_threads--; diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 9a40c7e0e..7f516e2cf 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -223,6 +223,21 @@ enum { /* * All tasks fork and call open_transport_socket(). * Stage is needed to make sure they all have the socket. + * Also this stage is a sync point after which the + * fini_restore_mntns() can be called. + * + * This stage is a little bit special. Normally all stages + * are controlled by criu process, but when this stage + * starts criu process starts waiting for the tasks to + * finish it, but by the time it gets woken up the stage + * finished is CR_STATE_RESTORE. The forking stage is + * barrier-ed by the root task, this task is also the one + * that switches the stage (into restoring). + * + * The above is done to lower the amount of context + * switches from root task to criu and back, since the + * separate forking stage is not needed by criu, it's + * purely to make sure all tasks be in sync. */ CR_STATE_FORKING, /* From 4a83e29788bc03da0cdbb900d8ded8ab55c3db3f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Apr 2017 15:29:52 +0300 Subject: [PATCH 0522/4375] restore: Bypass sync points of NS-related stages when not needed When we don't restore any namespaces criu forces tasks to wake it up two times simply to no-op and wake up tasks back. This can be optimized by simply omitting the not needed wakeups. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 1ef1c25d4..fba01b943 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -210,6 +210,15 @@ static void restore_wait_other_tasks() participants); } +static int restore_finish_ns_stage(int from, int to) +{ + if (root_ns_mask) + return restore_finish_stage(task_entries, from); + + /* Nobody waits for this stage change, just go ahead */ + __restore_switch_stage_nw(to); + return 0; +} static int crtools_prepare_shared(void) { @@ -1516,7 +1525,7 @@ static int restore_task_with_children(void *_arg) /* Wait prepare_userns */ if (current->parent == NULL && - restore_finish_stage(task_entries, CR_STATE_ROOT_TASK) < 0) + restore_finish_ns_stage(CR_STATE_ROOT_TASK, CR_STATE_PREPARE_NAMESPACES) < 0) goto err; /* @@ -1563,7 +1572,7 @@ static int restore_task_with_children(void *_arg) if (prepare_namespace(current, ca->clone_flags)) goto err; - if (restore_finish_stage(task_entries, CR_STATE_PREPARE_NAMESPACES) < 0) + if (restore_finish_ns_stage(CR_STATE_PREPARE_NAMESPACES, CR_STATE_FORKING) < 0) goto err; if (root_prepare_shared()) @@ -1934,6 +1943,9 @@ static int restore_root_task(struct pstree_item *init) } } + if (!root_ns_mask) + goto skip_ns_bouncing; + /* * uid_map and gid_map must be filled from a parent user namespace. * prepare_userns_creds() must be called after filling mappings. @@ -1977,7 +1989,11 @@ static int restore_root_task(struct pstree_item *init) if (ret) goto out_kill; - ret = restore_switch_stage(CR_STATE_FORKING); + __restore_switch_stage(CR_STATE_FORKING); + +skip_ns_bouncing: + + ret = restore_wait_inprogress_tasks(); if (ret < 0) goto out_kill; From 63316337253cdfe6543976b99d584696ec5de74a Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 2 May 2017 16:51:42 -0700 Subject: [PATCH 0523/4375] inotify_system_nodel.c: make it a static symlink inotify_system_nodel.c is supposed to be a symlink to inotify_system.c, but somehow the file was committed. This, together with the statement in Makefile to recreate the file, lead to replacing the file with a symlink during make. Remove the file, add the symlink, and remove the Makefile rule. PS yes, I have checked the files are identical. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 3 - test/zdtm/static/inotify_system_nodel.c | 392 +----------------------- 2 files changed, 1 insertion(+), 394 deletions(-) mode change 100644 => 120000 test/zdtm/static/inotify_system_nodel.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 4f8c3ff78..217cf357f 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -314,9 +314,6 @@ all: $(TST) criu-rtc.so install: all .PHONY: all install -inotify_system_nodel.c: inotify_system.c - ln -sf inotify_system.c inotify_system_nodel.c - $(TST_NOFILE:%=%.pid): %.pid: % $( -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "zdtmtst.h" - -const char *test_doc = "Inotify on symlink should be checked"; -#ifndef NODEL -char filename[] = "file"; -char linkname[] = "file.lnk"; -const char *inot_dir = "./inotify"; -#else -char filename[] = "file.nodel"; -char linkname[] = "file.nodel.lnk"; -const char *inot_dir = "./inotify.nodel"; -#endif - -#ifdef __NR_inotify_init -#include - -#ifndef IN_DONT_FOLLOW -/* Missed in SLES 10 header */ -#define IN_DONT_FOLLOW 0x02000000 -#endif - -#define EVENT_MAX 1024 -/* size of the event structure, not counting name */ -#define EVENT_SIZE (sizeof (struct inotify_event)) -/* reasonable guess as to size of 1024 events */ -#define EVENT_BUF_LEN (EVENT_MAX * (EVENT_SIZE + 16)) -#define BUF_SIZE 256 - -#define min_value(a,b) (a -#include - -typedef struct { - int inot; - int file; - int link; - int dir; -} desc; - -void do_wait() { - test_daemon(); - test_waitsig(); -} - -int createFiles(char *path, char *target, char *link) { - int fd; - fd = open(path,O_CREAT, 0644); - if (fd < 0) { - pr_perror("can't open %s", path); - return -1; - } - close(fd); - if (symlink(target, link) < 0) { - pr_perror("can't symlink %s to %s", path, link); - return -1; - } - return 0; -} - -int addWatcher(int fd, const char *path) { - int wd; - wd = inotify_add_watch(fd, path, IN_ALL_EVENTS | IN_DONT_FOLLOW); - if (wd < 0) { - pr_perror("inotify_add_watch(%d, %s, IN_ALL_EVENTS) Failed, %s", - fd, path, strerror(errno)); - return -1; - } - return wd; -} - -int fChmod(char *path) { - if (chmod(path, 0755) < 0) { - pr_perror("chmod(%s, 0755) Failed, %s", - path, strerror(errno)); - return -1; - } - return 0; -} - -int fWriteClose(char *path) { - int fd = open(path, O_RDWR | O_CREAT, 0700); - if (fd == -1) { - pr_perror("open(%s, O_RDWR|O_CREAT,0700) Failed, %s", - path, strerror(errno)); - return -1; - } - if (write(fd, "string", 7) == -1) { - pr_perror("write(%d, %s, 1) Failed, %s", fd, path, strerror(errno)); - return -1; - } - if (close(fd) == -1) { - pr_perror("close(%s) Failed, %s", path, strerror(errno)); - return -1; - } - return 0; -} - -int fNoWriteClose(char *path) { - char buf[BUF_SIZE]; - int fd = open(path, O_RDONLY); - if ( fd < 0 ) { - pr_perror("open(%s, O_RDONLY) Failed, %s", - path, strerror(errno)); - return -1; - } - if (read(fd, buf, BUF_SIZE) == -1) { - pr_perror("read error: %s", strerror(errno)); - close(fd); - return -1; - } - if (close(fd) == -1) { - pr_perror("close(%s) Failed, %s", path, strerror(errno)); - return -1; - } - return 0; -} - -int fMove(char *from, char *to) { - if (rename(from, to) == -1) { - pr_perror("rename error (from: %s to: %s) : %s", - from, to, strerror(errno)); - return -1; - } - return 0; -} - -desc init_env(const char *dir, char *file_path, char *link_path) { - desc in_desc = {-1, -1, -1, -1}; - if (mkdir(dir, 0777) < 0) { - pr_perror("error in creating directory: %s, %s", - dir, strerror(errno)); - return in_desc; - } - in_desc.inot = inotify_init(); - if (in_desc.inot < 0) { - pr_perror("inotify_init () Failed, %s", strerror(errno)); - rmdir(dir); - return in_desc; - } - - if (snprintf(file_path, BUF_SIZE, "%s/%s", dir, filename) >= BUF_SIZE) { - pr_perror("filename %s is too long", filename); - rmdir(dir); - return in_desc; - } - - if (snprintf(link_path, BUF_SIZE, "%s/%s", dir, linkname) >= BUF_SIZE) { - pr_perror("filename %s is too long", linkname); - rmdir(dir); - return in_desc; - } - - in_desc.dir = addWatcher(in_desc.inot, dir); - if (createFiles(file_path, filename, link_path)) { - return in_desc; - } - in_desc.link = addWatcher(in_desc.inot, link_path); - in_desc.file = addWatcher(in_desc.inot, file_path); - - return in_desc; -} - -int fDelete(char *path) { - if (unlink(path) != 0) { - pr_perror("unlink: (%s)", strerror(errno)); - return -1; - } - return 0; -} - -int fRemDir(const char *target) { - if(rmdir(target)) { - pr_perror("rmdir: (%s)", strerror(errno)); - return -1; - } - return 0; -} - -int test_actions(const char *dir, char *file_path, char *link_path) { - - if ( - fChmod(link_path) == 0 && - fWriteClose(link_path) == 0 && - fNoWriteClose(link_path) == 0 && - fMove(file_path, filename) == 0 && - fMove(filename, file_path) == 0 -#ifndef NODEL - && fDelete(file_path) == 0 && - fDelete(link_path) == 0 && - fRemDir(dir) == 0 -#endif - ) - { - return 0; - } - return -1; -} - -void dump_events(char *buf, int len) { - int marker = 0; - struct inotify_event *event; - while (marker < len) { - event = (struct inotify_event *) &buf[marker]; - test_msg("\t%s (%x mask, %d len", handle_event(event->mask), event->mask, event->len); - if (event->len) - test_msg(", '%s' name", event->name); - test_msg(")\n"); - marker += EVENT_SIZE + event->len; - } -} - -int harmless(int mask) -{ - switch (mask) { - case IN_CLOSE_NOWRITE: - case IN_ATTRIB: - return 1; - } - return 0; -} - -int errors(int exp_len, int len, char *etalon_buf, char *buf) { - int marker=0; - int error=0; - while (marker < len){ - struct inotify_event *event; - struct inotify_event *exp_event; - event = (struct inotify_event *) &buf[marker]; - /* It's OK if some additional events are recevived */ - if (marker < exp_len) - exp_event = (struct inotify_event *) &etalon_buf[marker]; - else { - if (!harmless(event->mask)) { - fail("got unexpected event %s (%x mask)\n", - handle_event(event->mask), event->mask); - error++; - } - goto next_event; - } - - if (event->mask != exp_event->mask) { - fail("Handled %s (%x mask), expected %s (%x mask)", - handle_event(event->mask), event->mask, - handle_event(exp_event->mask), - exp_event->mask); - error++; - } - if (event->len != exp_event->len) { - fail("Incorrect length of field name."); - error++; - break; - } - else if (event->len && strncmp(event->name, exp_event->name, event->len)) { - fail("Handled file name %s, expected %s", - event->name, - exp_event->name); - error++; - } -next_event: - marker += EVENT_SIZE + event->len; - } - return error; -} - -int read_set(int inot_fd, char *event_set) { - int len; - if ((len = read(inot_fd, event_set, EVENT_BUF_LEN)) < 0) { - pr_perror("read(%d, buf, %lu) Failed", - inot_fd, (unsigned long)EVENT_BUF_LEN); - return -1; - } - return len; -} - -void common_close(desc *descr) { - if (descr->inot > 0) { - close(descr->inot); - descr->inot=-1; - descr->file=-1; - descr->dir=-1; - descr->link=-1; - } -} - -int get_event_set(char *event_set, int wait) { - int len; - char link_path[BUF_SIZE]; - char file_path[BUF_SIZE]; - desc common_desc; - - common_desc = init_env(inot_dir, file_path, link_path); - if ((common_desc.inot < 0) || (common_desc.file < 0) || \ - (common_desc.dir < 0) || (common_desc.link < 0)) { - common_close(&common_desc); - return -1; - } - if(test_actions(inot_dir, file_path, link_path) < 0) { - common_close(&common_desc); - return -1; - } - if (wait) { - do_wait(); - } - len = read_set(common_desc.inot, event_set); - common_close(&common_desc); -#ifdef NODEL - if (! (fDelete(file_path) == 0 && - fDelete(link_path) == 0 && - fRemDir(inot_dir) == 0)) - return -1; -#endif - return len; -} - -int check(int len, char *event_set, int exp_len, char *etalon_event_set) { - - if ((exp_len < 0) || (len < 0)){ - fail("Error in preparing event sets."); - return -1; - } - if (len < exp_len) { - fail("Events are lost. Read: %d, Expected: %d", len, exp_len); - test_msg("expected events\n"); - dump_events(etalon_event_set, exp_len); - test_msg("real events\n"); - dump_events(event_set, len); - return -1; - } - if (errors(exp_len, len, etalon_event_set, event_set) == 0) { - pass(); - return 0; - } - return -1; -} - -int main(int argc, char ** argv) -{ - int exp_len=-1, len=-1; - char etalon_event_set[EVENT_BUF_LEN]; - char event_set[EVENT_BUF_LEN]; - - test_init(argc, argv); - - exp_len = get_event_set(etalon_event_set, 0); - len = get_event_set(event_set, 1); - - if (check(len, event_set, exp_len, etalon_event_set)) { - return 1; - } - return 0; -} -#else - -int main(int argc, char ** argv) -{ - test_init(argc, argv); - skip("Inotify not supported."); - return 0; -} -#endif //__NR_inotify_init diff --git a/test/zdtm/static/inotify_system_nodel.c b/test/zdtm/static/inotify_system_nodel.c new file mode 120000 index 000000000..36049d901 --- /dev/null +++ b/test/zdtm/static/inotify_system_nodel.c @@ -0,0 +1 @@ +inotify_system.c \ No newline at end of file From 44a2a651934910eb892a69909988c9e8a754bf0f Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 2 May 2017 16:51:43 -0700 Subject: [PATCH 0524/4375] test/zdtm/Makefile.inc: don't regen all deps As it was pointed out by our esteemed maintainer (let his light shine), after my recent changes to test/zdtm Makefiles all dependencies are regenerated even if we only need to build a single test (for example, cd test/zdtm/static && make env00). This was caused by "-include $(DEP)" statement. Make sees that these files are need to be included, but are missing, and since it knows how to generate them it goes on to do so. The solution is to use $(wildcard) function which returns the list of _existing_ files, and so include will only receive the files that exist. Reported-by: Andrei Vagin Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index 91d9a36ac..9b758c339 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -89,7 +89,7 @@ dep: $(DEP) no-deps-targets := clean cleandep cleanout realclean groups.cleanout ifeq ($(filter $(no-deps-targets), $(MAKECMDGOALS)),) --include $(DEP) +-include $(wildcard $(DEP)) endif .SECONDARY: From dd4925b500b025f0b433edbd4cd1b2c508c8748c Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 2 May 2017 16:51:44 -0700 Subject: [PATCH 0525/4375] test/zdtm/Makefiles: disable built-in rules MAKEFLAGS += -r only works for sub-make, and it is not applicable to the current instance. Since previous commit make is not re-running itself (after re-reading deps files), so MAKEFLAGS no longer works. Use one more way to disable built-in rules that stand in our way. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/Makefile.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index 9b758c339..5e8836e90 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -1,3 +1,4 @@ +.SUFFIXES: MAKEFLAGS += -r ARCH ?= $(shell uname -m | sed \ From 14a01115466611c55bfccd6b42f3a3c75f83f5fc Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 2 May 2017 16:51:45 -0700 Subject: [PATCH 0526/4375] test/zdtm: clean get_smaps_bits.d This is an auxiliary source file. The corresponding object file was cleaned, but .d was not. Add it to SRC/OBJ/DEP so the appropriate files will be cleaned automatically. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 217cf357f..8c8c38362 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -299,8 +299,9 @@ TST_STATE = \ conntracks \ route_rules \ +AUX_SRC = get_smaps_bits.c -SRC = $(TST:%=%.c) +SRC = $(TST:%=%.c) $(AUX_SRC) OBJ = $(SRC:%.c=%.o) DEP = $(SRC:%.c=%.d) PID = $(TST:%=%.pid) @@ -454,7 +455,7 @@ $(LIB): force $(Q) $(MAKE) -C $(LIBDIR) clean-more: - $(RM) criu-rtc.so criu-rtc.pb-c.c criu-rtc.pb-c.h get_smaps_bits.o + $(RM) criu-rtc.so criu-rtc.pb-c.c criu-rtc.pb-c.h .PHONY: clean-more clean: clean-more From 1e1a85f1b87bbd35f04ced3502a5aa56e108f257 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 2 May 2017 16:51:46 -0700 Subject: [PATCH 0527/4375] test/zdtm: rm get_smaps_bits proto from zdtmtst.h The function is not included into the library, so having its prototype there was a shortcut. Move it to a separate include file. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/lib/zdtmtst.h | 1 - test/zdtm/static/get_smaps_bits.h | 6 ++++++ test/zdtm/static/maps02.c | 1 + test/zdtm/static/mlock_setuid.c | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 test/zdtm/static/get_smaps_bits.h diff --git a/test/zdtm/lib/zdtmtst.h b/test/zdtm/lib/zdtmtst.h index 3f9f55056..de01cc2be 100644 --- a/test/zdtm/lib/zdtmtst.h +++ b/test/zdtm/lib/zdtmtst.h @@ -141,5 +141,4 @@ extern int tcp_init_server(int family, int *port); extern int tcp_accept_server(int sock); extern int tcp_init_client(int family, char *servIP, unsigned short servPort); -extern int get_smaps_bits(unsigned long where, unsigned long *flags, unsigned long *madv); #endif /* _VIMITESU_H_ */ diff --git a/test/zdtm/static/get_smaps_bits.h b/test/zdtm/static/get_smaps_bits.h new file mode 100644 index 000000000..ce1070daf --- /dev/null +++ b/test/zdtm/static/get_smaps_bits.h @@ -0,0 +1,6 @@ +#ifndef ZDTM_GET_SMAPS_BITS_H_ +#define ZDTM_GET_SMAPS_BITS_H_ + +extern int get_smaps_bits(unsigned long where, unsigned long *flags, unsigned long *madv); + +#endif /* ZDTM_GET_SMAPS_BITS_H_ */ diff --git a/test/zdtm/static/maps02.c b/test/zdtm/static/maps02.c index 571323547..eb7c09bdc 100644 --- a/test/zdtm/static/maps02.c +++ b/test/zdtm/static/maps02.c @@ -1,5 +1,6 @@ #include #include "zdtmtst.h" +#include "get_smaps_bits.h" #ifndef MADV_DONTDUMP #define MADV_DONTDUMP 16 diff --git a/test/zdtm/static/mlock_setuid.c b/test/zdtm/static/mlock_setuid.c index a6847a654..a737bddf9 100644 --- a/test/zdtm/static/mlock_setuid.c +++ b/test/zdtm/static/mlock_setuid.c @@ -2,6 +2,7 @@ #include #include #include "zdtmtst.h" +#include "get_smaps_bits.h" #define MEM_SIZE (69632) From 6329e660a41bb6bc23f85061a1931c97de136664 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 2 May 2017 16:51:47 -0700 Subject: [PATCH 0528/4375] test/zdtm/static: split ofd_file_locks.h to .c/.h Having a "header library" is nice if it's small and clean, but - we compile its code a few times; - there is no distinction between internal and external functions. Let's separate functions out of header and into a .c file. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 3 +- test/zdtm/static/ofd_file_locks.c | 138 +++++++++++++++++++++++++++++ test/zdtm/static/ofd_file_locks.h | 139 +----------------------------- 3 files changed, 143 insertions(+), 137 deletions(-) create mode 100644 test/zdtm/static/ofd_file_locks.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 8c8c38362..26cb6eaf2 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -299,7 +299,7 @@ TST_STATE = \ conntracks \ route_rules \ -AUX_SRC = get_smaps_bits.c +AUX_SRC = get_smaps_bits.c ofd_file_locks.c SRC = $(TST:%=%.c) $(AUX_SRC) OBJ = $(SRC:%.c=%.o) @@ -385,6 +385,7 @@ $(TST): | $(LIB) aio00: LDLIBS += -laio different_creds: LDLIBS += -lcap +file_locks06 file_locks07 file_locks08: ofd_file_locks.o futex: CFLAGS += -pthread futex: LDFLAGS += -pthread futex-rl: CFLAGS += -pthread diff --git a/test/zdtm/static/ofd_file_locks.c b/test/zdtm/static/ofd_file_locks.c new file mode 100644 index 000000000..61495a202 --- /dev/null +++ b/test/zdtm/static/ofd_file_locks.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" +#include "fs.h" +#include "ofd_file_locks.h" + +static int parse_ofd_lock(char *buf, struct flock64 *lck) +{ + char fl_flag[10], fl_type[15], fl_option[10], fl_end[32]; + long long start; + int num; + + if (strncmp(buf, "lock:\t", 6) != 0) + return 1; /* isn't lock, skip record */ + + num = sscanf(buf, + "%*s %*d: %s %s %s %*d %*x:%*x:%*d %lld %s", + fl_flag, fl_type, fl_option, &start, fl_end); + + if (num < 4) { + pr_err("Invalid lock info %s\n", buf); + return -1; + } + if (strcmp(fl_flag, "OFDLCK")) + return 1; + + lck->l_start = start; + + if (strcmp(fl_end, "EOF")) { + unsigned long end; + + if (sscanf(fl_end, "%lu", &end) <= 0) { + pr_err("Invalid lock entry\n"); + return -1; + } + lck->l_len = end - lck->l_start + 1; + } else { + lck->l_len = 0; + } + if (strcmp(fl_option, "WRITE") == 0) + lck->l_type = F_WRLCK; + else + lck->l_type = F_RDLCK; + + return 0; +} + +static int read_fd_ofd_lock(int pid, int fd, struct flock64 *lck) +{ + char path[PATH_MAX]; + char buf[100]; + int num; + FILE *proc_file = NULL; + + sprintf(path, "/proc/%i/fdinfo/%i", pid, fd); + proc_file = fopen(path, "r"); + + if (!proc_file) { + pr_err("Can't open %s\n", path); + return -1; + } + + num = -1; + while (fgets(buf, sizeof(buf), proc_file)) { + num = parse_ofd_lock(buf, lck); + if (num <= 0) + break; + } + + if (fclose(proc_file)) { + pr_err("Can't close %s\n", path); + return -1; + } + return num; +} + +int check_lock_exists(const char *filename, struct flock64 *lck) +{ + int ret = -1; + int fd; + + fd = open(filename, O_RDWR, 0666); + + if (lck->l_type == F_RDLCK) { + /* check, that there is no write lock */ + ret = fcntl(fd, F_OFD_GETLK, lck); + if (ret) { + pr_err("fcntl failed (%i)\n", ret); + goto out; + } + if (lck->l_type != F_UNLCK) { + pr_err("OFD lock type do not match\n"); + goto out; + } + } + + /* check, that lock is set */ + lck->l_type = F_WRLCK; + ret = fcntl(fd, F_OFD_GETLK, lck); + if (ret) { + pr_err("fcntl failed (%i)\n", ret); + goto out; + } + if (lck->l_type == F_UNLCK) { + pr_err("Lock not found\n"); + goto out; + } + + ret = 0; +out: + if (close(fd)) + return -1; + return ret; +} + +static int check_file_locks_match(struct flock64 *orig_lck, struct flock64 *lck) +{ + return orig_lck->l_start == lck->l_start && + orig_lck->l_len == lck->l_len && + orig_lck->l_type == lck->l_type; +} + +int check_file_lock_restored(int pid, int fd, struct flock64 *lck) +{ + struct flock64 lck_restored; + + if (read_fd_ofd_lock(pid, fd, &lck_restored)) + return -1; + + if (!check_file_locks_match(lck, &lck_restored)) { + pr_err("Can't restore file lock (fd: %i)\n", fd); + return -1; + } + return 0; +} diff --git a/test/zdtm/static/ofd_file_locks.h b/test/zdtm/static/ofd_file_locks.h index b2c249a9b..0d500e1bf 100644 --- a/test/zdtm/static/ofd_file_locks.h +++ b/test/zdtm/static/ofd_file_locks.h @@ -2,12 +2,6 @@ #define ZDTM_OFD_FILE_LOCKS_H_ #include -#include -#include -#include - -#include "zdtmtst.h" -#include "fs.h" #ifndef F_OFD_GETLK #define F_OFD_GETLK 36 @@ -16,138 +10,11 @@ #endif /* - * Header library for parsing of OFD locks + * Functions for parsing of OFD locks * from procfs and checking them after restoring. */ -static int parse_ofd_lock(char *buf, struct flock64 *lck) -{ - char fl_flag[10], fl_type[15], fl_option[10], fl_end[32]; - long long start; - int num; - - if (strncmp(buf, "lock:\t", 6) != 0) - return 1; /* isn't lock, skip record */ - - num = sscanf(buf, - "%*s %*d: %s %s %s %*d %*x:%*x:%*d %lld %s", - fl_flag, fl_type, fl_option, &start, fl_end); - - if (num < 4) { - pr_err("Invalid lock info %s\n", buf); - return -1; - } - if (strcmp(fl_flag, "OFDLCK")) - return 1; - - lck->l_start = start; - - if (strcmp(fl_end, "EOF")) { - unsigned long end; - - if (sscanf(fl_end, "%lu", &end) <= 0) { - pr_err("Invalid lock entry\n"); - return -1; - } - lck->l_len = end - lck->l_start + 1; - } else { - lck->l_len = 0; - } - if (strcmp(fl_option, "WRITE") == 0) - lck->l_type = F_WRLCK; - else - lck->l_type = F_RDLCK; - - return 0; -} - -static int read_fd_ofd_lock(int pid, int fd, struct flock64 *lck) -{ - char path[PATH_MAX]; - char buf[100]; - int num; - FILE *proc_file = NULL; - - sprintf(path, "/proc/%i/fdinfo/%i", pid, fd); - proc_file = fopen(path, "r"); - - if (!proc_file) { - pr_err("Can't open %s\n", path); - return -1; - } - - num = -1; - while (fgets(buf, sizeof(buf), proc_file)) { - num = parse_ofd_lock(buf, lck); - if (num <= 0) - break; - } - - if (fclose(proc_file)) { - pr_err("Can't close %s\n", path); - return -1; - } - return num; -} - -static int check_lock_exists(const char *filename, struct flock64 *lck) -{ - int ret = -1; - int fd; - - fd = open(filename, O_RDWR, 0666); - - if (lck->l_type == F_RDLCK) { - /* check, that there is no write lock */ - ret = fcntl(fd, F_OFD_GETLK, lck); - if (ret) { - pr_err("fcntl failed (%i)\n", ret); - goto out; - } - if (lck->l_type != F_UNLCK) { - pr_err("OFD lock type do not match\n"); - goto out; - } - } - - /* check, that lock is set */ - lck->l_type = F_WRLCK; - ret = fcntl(fd, F_OFD_GETLK, lck); - if (ret) { - pr_err("fcntl failed (%i)\n", ret); - goto out; - } - if (lck->l_type == F_UNLCK) { - pr_err("Lock not found\n"); - goto out; - } - - ret = 0; -out: - if (close(fd)) - return -1; - return ret; -} - -static int check_file_locks_match(struct flock64 *orig_lck, struct flock64 *lck) -{ - return orig_lck->l_start == lck->l_start && - orig_lck->l_len == lck->l_len && - orig_lck->l_type == lck->l_type; -} - -static int check_file_lock_restored(int pid, int fd, struct flock64 *lck) -{ - struct flock64 lck_restored; - - if (read_fd_ofd_lock(pid, fd, &lck_restored)) - return -1; - - if (!check_file_locks_match(lck, &lck_restored)) { - pr_err("Can't restore file lock (fd: %i)\n", fd); - return -1; - } - return 0; -} +extern int check_lock_exists(const char *filename, struct flock64 *lck); +extern int check_file_lock_restored(int pid, int fd, struct flock64 *lck); #endif /* ZDTM_OFD_FILE_LOCKS_H_ */ From 0469a46a55e4c311e5c11db2a2cef68a72e619c2 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 3 May 2017 15:48:14 +0300 Subject: [PATCH 0529/4375] seize: Fix size error in creds_dumpable() The goal of this function is to compare everything except caps, but caps size is took to compare. It's wrong, there must be used offsetof(struct proc_status_creds, cap_inh) instead. Also, sigpnd may be different too. v3: Move excluding sigpnd from comparation in this patch (was in another patch). Reorder fields in seize_task_status(). Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 4 ++-- criu/seize.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 005d6bda6..0d79f1346 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -16,10 +16,10 @@ extern int compel_interrupt_task(int pid); struct seize_task_status { - char state; - int ppid; unsigned long long sigpnd; unsigned long long shdpnd; + char state; + int ppid; int seccomp_mode; }; diff --git a/criu/seize.c b/criu/seize.c index d5079ca6c..064b4a8ec 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -629,9 +629,7 @@ static inline bool thread_collected(struct pstree_item *i, pid_t tid) static bool creds_dumpable(struct proc_status_creds *parent, struct proc_status_creds *child) { - const size_t size = sizeof(struct proc_status_creds) - - offsetof(struct proc_status_creds, cap_inh); - + size_t size; /* * The comparison rules are the following * @@ -640,17 +638,20 @@ static bool creds_dumpable(struct proc_status_creds *parent, * semantic comparison (FIXME) but for * now we require them to be exactly * identical + * - sigpnd may be different * - the rest of members must match */ - if (memcmp(parent, child, size)) { + size = offsetof(struct proc_status_creds, cap_inh) - + sizeof(parent->s.sigpnd); + + if (memcmp(&parent->s.sigpnd, &child->s.sigpnd, size)) { if (!pr_quelled(LOG_DEBUG)) { pr_debug("Creds undumpable (parent:child)\n" " uids: %d:%d %d:%d %d:%d %d:%d\n" " gids: %d:%d %d:%d %d:%d %d:%d\n" " state: %d:%d" " ppid: %d:%d\n" - " sigpnd: %llu:%llu\n" " shdpnd: %llu:%llu\n" " seccomp_mode: %d:%d\n" " last_filter: %u:%u\n", @@ -664,7 +665,6 @@ static bool creds_dumpable(struct proc_status_creds *parent, parent->gids[3], child->gids[3], parent->s.state, child->s.state, parent->s.ppid, child->s.ppid, - parent->s.sigpnd, child->s.sigpnd, parent->s.shdpnd, child->s.shdpnd, parent->s.seccomp_mode, child->s.seccomp_mode, parent->last_filter, child->last_filter); From 08ca20e29e30a776d7c6f627e8d1f85f40fb8adb Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 3 May 2017 15:48:25 +0300 Subject: [PATCH 0530/4375] compel: Add more arguments to compel_wait_task() Some get_status() methods may allocate data, because not all of the fields in /proc/[pid]/status file have the fixed size. For example, NSpid, which size may vary. Introduce new method free_status() in counterweight for such type get_status() methods. it will be called in case of we go to try_again and need to free allocated data. Also, introduce data parameter for a use in the future. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 5 +++-- compel/src/lib/infect.c | 13 ++++++++----- criu/include/proc_parse.h | 2 +- criu/proc_parse.c | 2 +- criu/seize.c | 6 +++--- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 0d79f1346..3264e923f 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -24,8 +24,9 @@ struct seize_task_status { }; extern int compel_wait_task(int pid, int ppid, - int (*get_status)(int pid, struct seize_task_status *), - struct seize_task_status *st); + int (*get_status)(int pid, struct seize_task_status *, void *data), + void (*free_status)(int pid, struct seize_task_status *, void *data), + struct seize_task_status *st, void *data); extern int compel_stop_task(int pid); extern int compel_resume_task(pid_t pid, int orig_state, int state); diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 7f6d2f3f1..07200a7a6 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -52,7 +52,7 @@ static inline void close_safe(int *pfd) } } -static int parse_pid_status(int pid, struct seize_task_status *ss) +static int parse_pid_status(int pid, struct seize_task_status *ss, void *data) { char aux[128]; FILE *f; @@ -107,7 +107,7 @@ int compel_stop_task(int pid) ret = compel_interrupt_task(pid); if (ret == 0) - ret = compel_wait_task(pid, -1, parse_pid_status, &ss); + ret = compel_wait_task(pid, -1, parse_pid_status, NULL, &ss, NULL); return ret; } @@ -192,8 +192,9 @@ static int skip_sigstop(int pid, int nr_signals) * up with someone else. */ int compel_wait_task(int pid, int ppid, - int (*get_status)(int pid, struct seize_task_status *), - struct seize_task_status *ss) + int (*get_status)(int pid, struct seize_task_status *, void *), + void (*free_status)(int pid, struct seize_task_status *, void *), + struct seize_task_status *ss, void *data) { siginfo_t si; int status, nr_sigstop; @@ -220,7 +221,7 @@ try_again: wait_errno = errno; } - ret2 = get_status(pid, ss); + ret2 = get_status(pid, ss, data); if (ret2) goto err; @@ -271,6 +272,8 @@ try_again: } ret = 0; + if (free_status) + free_status(pid, ss, data); goto try_again; } diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h index d67ac5e56..5538757f9 100644 --- a/criu/include/proc_parse.h +++ b/criu/include/proc_parse.h @@ -96,7 +96,7 @@ extern int parse_pid_stat(pid_t pid, struct proc_pid_stat *s); extern unsigned int parse_pid_loginuid(pid_t pid, int *err, bool ignore_noent); extern int parse_pid_oom_score_adj(pid_t pid, int *err); extern int prepare_loginuid(unsigned int value, unsigned int loglevel); -extern int parse_pid_status(pid_t pid, struct seize_task_status *); +extern int parse_pid_status(pid_t pid, struct seize_task_status *, void *data); extern int parse_file_locks(void); extern int get_fd_mntid(int fd, int *mnt_id); diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 19a010e7f..f1237cf9f 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -993,7 +993,7 @@ static int cap_parse(char *str, unsigned int *res) return 0; } -int parse_pid_status(pid_t pid, struct seize_task_status *ss) +int parse_pid_status(pid_t pid, struct seize_task_status *ss, void *data) { struct proc_status_creds *cr = container_of(ss, struct proc_status_creds, s); struct bfd f; diff --git a/criu/seize.c b/criu/seize.c index 064b4a8ec..ae99ddf56 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -490,7 +490,7 @@ static int collect_children(struct pstree_item *item) goto free; } - ret = compel_wait_task(pid, item->pid->real, parse_pid_status, &creds->s); + ret = compel_wait_task(pid, item->pid->real, parse_pid_status, NULL, &creds->s, NULL); if (ret < 0) { /* * Here is a race window between parse_children() and seize(), @@ -716,7 +716,7 @@ static int collect_threads(struct pstree_item *item) if (!opts.freeze_cgroup && compel_interrupt_task(pid)) continue; - ret = compel_wait_task(pid, item_ppid(item), parse_pid_status, &t_creds.s); + ret = compel_wait_task(pid, item_ppid(item), parse_pid_status, NULL, &t_creds.s, NULL); if (ret < 0) { /* * Here is a race window between parse_threads() and seize(), @@ -855,7 +855,7 @@ int collect_pstree(void) if (!creds) goto err; - ret = compel_wait_task(pid, -1, parse_pid_status, &creds->s); + ret = compel_wait_task(pid, -1, parse_pid_status, NULL, &creds->s, NULL); if (ret < 0) goto err; From ff65b3b9ed740d8cb7daf8d47b9c7973e020802a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 4 May 2017 16:31:44 +0300 Subject: [PATCH 0531/4375] kdat: Relax loginuid checks Introduce 3-state mode and check them always. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-check.c | 4 ++-- criu/cr-dump.c | 2 +- criu/cr-restore.c | 6 +++--- criu/include/kerndat.h | 10 ++++++++-- criu/kerndat.c | 15 ++++++--------- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index 208484b4a..f39130f1b 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1044,10 +1044,10 @@ static int check_userns(void) static int check_loginuid(void) { - if (kerndat_loginuid(false) < 0) + if (kerndat_loginuid() < 0) return -1; - if (!kdat.has_loginuid) { + if (kdat.luid != LUID_FULL) { pr_warn("Loginuid restore is OFF.\n"); return -1; } diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 6ff3dc66a..1c41d5f59 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -341,7 +341,7 @@ static int dump_pid_misc(pid_t pid, TaskCoreEntry *tc) { int ret; - if (kdat.has_loginuid) { + if (kdat.luid != LUID_NONE) { pr_info("dumping /proc/%d/loginuid\n", pid); tc->has_loginuid = true; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index fba01b943..abd55af00 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -762,7 +762,7 @@ static int prepare_proc_misc(pid_t pid, TaskCoreEntry *tc) int ret; /* loginuid value is critical to restore */ - if (kdat.has_loginuid && tc->has_loginuid && + if (kdat.luid == LUID_FULL && tc->has_loginuid && tc->loginuid != INVALID_UID) { ret = prepare_loginuid(tc->loginuid, LOG_ERROR); if (ret < 0) @@ -1815,7 +1815,7 @@ static int prepare_userns_hook(void) { int ret; - if (!kdat.has_loginuid) + if (kdat.luid != LUID_FULL) return 0; /* * Save old loginuid and set it to INVALID_UID: @@ -1837,7 +1837,7 @@ static int prepare_userns_hook(void) static void restore_origin_ns_hook(void) { - if (!kdat.has_loginuid) + if (kdat.luid != LUID_FULL) return; /* not critical: it does not affect CT in any way */ diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 97194cd23..9de8875d9 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -14,7 +14,7 @@ extern int kerndat_init(void); extern int kerndat_init_rst(void); extern int kerndat_get_dirty_track(void); extern int kerndat_fdinfo_has_lock(void); -extern int kerndat_loginuid(bool only_dump); +extern int kerndat_loginuid(void); enum pagemap_func { PM_UNKNOWN, @@ -23,6 +23,12 @@ enum pagemap_func { PM_FULL, }; +enum loginuid_func { + LUID_NONE, + LUID_READ, + LUID_FULL, +}; + struct kerndat_s { dev_t shmem_dev; int last_cap; @@ -32,7 +38,7 @@ struct kerndat_s { bool has_fdinfo_lock; unsigned long task_size; bool ipv6; - bool has_loginuid; + enum loginuid_func luid; bool compat_cr; enum pagemap_func pmap; unsigned int has_xtlocks; diff --git a/criu/kerndat.c b/criu/kerndat.c index 1e3ef51f4..5f53f7d0a 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -441,22 +441,19 @@ static int get_ipv6() return 0; } -int kerndat_loginuid(bool only_dump) +int kerndat_loginuid(void) { unsigned int saved_loginuid; int ret; - kdat.has_loginuid = false; + kdat.luid = LUID_NONE; /* No such file: CONFIG_AUDITSYSCALL disabled */ saved_loginuid = parse_pid_loginuid(PROC_SELF, &ret, true); if (ret < 0) return 0; - if (only_dump) { - kdat.has_loginuid = true; - return 0; - } + kdat.luid = LUID_READ; /* * From kernel v3.13-rc2 it's possible to unset loginuid value, @@ -469,7 +466,7 @@ int kerndat_loginuid(bool only_dump) if (prepare_loginuid(saved_loginuid, LOG_WARN) < 0) return 0; - kdat.has_loginuid = true; + kdat.luid = LUID_FULL; return 0; } @@ -585,7 +582,7 @@ int kerndat_init(void) if (!ret) ret = get_ipv6(); if (!ret) - ret = kerndat_loginuid(true); + ret = kerndat_loginuid(); if (!ret) ret = kerndat_iptables_has_xtlocks(); if (!ret) @@ -619,7 +616,7 @@ int kerndat_init_rst(void) if (!ret) ret = get_ipv6(); if (!ret) - ret = kerndat_loginuid(false); + ret = kerndat_loginuid(); if (!ret) ret = kerndat_iptables_has_xtlocks(); if (!ret) From a840995689f7ab898ba34fd10e014704165e2f83 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 4 May 2017 16:32:02 +0300 Subject: [PATCH 0532/4375] kdat: Relax uffd checks (v2) v2: When uffd is present, the reported features may still be 0, so we need one more bool for uffd syscall itself. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/uffd.c | 1167 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1167 insertions(+) create mode 100644 criu/uffd.c diff --git a/criu/uffd.c b/criu/uffd.c new file mode 100644 index 000000000..205045e34 --- /dev/null +++ b/criu/uffd.c @@ -0,0 +1,1167 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "linux/userfaultfd.h" + +#include "int.h" +#include "page.h" +#include "criu-log.h" +#include "criu-plugin.h" +#include "pagemap.h" +#include "files-reg.h" +#include "kerndat.h" +#include "mem.h" +#include "uffd.h" +#include "util-pie.h" +#include "protobuf.h" +#include "pstree.h" +#include "crtools.h" +#include "cr_options.h" +#include "xmalloc.h" +#include +#include "restorer.h" +#include "page-xfer.h" +#include "common/lock.h" +#include "rst-malloc.h" +#include "util.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "uffd: " + +#define lp_debug(lpi, fmt, arg...) pr_debug("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) +#define lp_info(lpi, fmt, arg...) pr_info("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) +#define lp_warn(lpi, fmt, arg...) pr_warn("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) +#define lp_err(lpi, fmt, arg...) pr_err("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) +#define lp_perror(lpi, fmt, arg...) pr_perror("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) + +#define NEED_UFFD_API_FEATURES (UFFD_FEATURE_EVENT_FORK | \ + UFFD_FEATURE_EVENT_REMAP | \ + UFFD_FEATURE_EVENT_UNMAP | \ + UFFD_FEATURE_EVENT_REMOVE) + +#define LAZY_PAGES_SOCK_NAME "lazy-pages.socket" + +static mutex_t *lazy_sock_mutex; + +struct lazy_iov { + struct list_head l; + unsigned long base; /* run-time start address, tracks remaps */ + unsigned long img_base; /* start address at the dump time */ + unsigned long len; +}; + +struct lp_req { + unsigned long addr; /* actual #PF (or background) destination */ + unsigned long img_addr; /* the corresponding address at the dump time */ + struct list_head l; +}; + +struct lazy_pages_info { + int pid; + + struct list_head iovs; + struct list_head reqs; + + struct lazy_pages_info *parent; + + struct page_read pr; + + unsigned long total_pages; + unsigned long copied_pages; + + struct epoll_rfd lpfd; + + struct list_head l; + + void *buf; +}; + +/* global lazy-pages daemon state */ +static LIST_HEAD(lpis); +static LIST_HEAD(exiting_lpis); +static LIST_HEAD(pending_lpis); +static int epollfd; + +static int handle_uffd_event(struct epoll_rfd *lpfd); + +static struct lazy_pages_info *lpi_init(void) +{ + struct lazy_pages_info *lpi = NULL; + + lpi = xmalloc(sizeof(*lpi)); + if (!lpi) + return NULL; + + memset(lpi, 0, sizeof(*lpi)); + INIT_LIST_HEAD(&lpi->iovs); + INIT_LIST_HEAD(&lpi->reqs); + INIT_LIST_HEAD(&lpi->l); + lpi->lpfd.revent = handle_uffd_event; + + return lpi; +} + +static void free_lazy_iovs(struct lazy_pages_info *lpi) +{ + struct lazy_iov *p, *n; + + list_for_each_entry_safe(p, n, &lpi->iovs, l) { + list_del(&p->l); + xfree(p); + } +} + +static void lpi_fini(struct lazy_pages_info *lpi) +{ + + if (!lpi) + return; + free(lpi->buf); + free_lazy_iovs(lpi); + if (lpi->lpfd.fd > 0) + close(lpi->lpfd.fd); + if (lpi->pr.close) + lpi->pr.close(&lpi->pr); + free(lpi); +} + +static int prepare_sock_addr(struct sockaddr_un *saddr) +{ + int len; + + memset(saddr, 0, sizeof(struct sockaddr_un)); + + saddr->sun_family = AF_UNIX; + len = snprintf(saddr->sun_path, sizeof(saddr->sun_path), + "%s", LAZY_PAGES_SOCK_NAME); + if (len >= sizeof(saddr->sun_path)) { + pr_err("Wrong UNIX socket name: %s\n", LAZY_PAGES_SOCK_NAME); + return -1; + } + + return 0; +} + +static int send_uffd(int sendfd, int pid) +{ + int fd; + int ret = -1; + + if (sendfd < 0) + return -1; + + fd = get_service_fd(LAZY_PAGES_SK_OFF); + if (fd < 0) { + pr_err("%s: get_service_fd\n", __func__); + return -1; + } + + mutex_lock(lazy_sock_mutex); + + /* The "transfer protocol" is first the pid as int and then + * the FD for UFFD */ + pr_debug("Sending PID %d\n", pid); + if (send(fd, &pid, sizeof(pid), 0) < 0) { + pr_perror("PID sending error"); + goto out; + } + + /* for a zombie process pid will be negative */ + if (pid < 0) { + ret = 0; + goto out; + } + + if (send_fd(fd, NULL, 0, sendfd) < 0) { + pr_err("send_fd error\n"); + goto out; + } + + ret = 0; +out: + mutex_unlock(lazy_sock_mutex); + close(fd); + return ret; +} + +int lazy_pages_setup_zombie(int pid) +{ + if (!opts.lazy_pages) + return 0; + + if (send_uffd(0, -pid)) + return -1; + + return 0; +} + +/* This function is used by 'criu restore --lazy-pages' */ +int setup_uffd(int pid, struct task_restore_args *task_args) +{ + struct uffdio_api uffdio_api; + + if (!opts.lazy_pages) { + task_args->uffd = -1; + return 0; + } + + /* + * Open userfaulfd FD which is passed to the restorer blob and + * to a second process handling the userfaultfd page faults. + */ + task_args->uffd = syscall(SYS_userfaultfd, O_CLOEXEC | O_NONBLOCK); + if (task_args->uffd < 0) { + pr_perror("Unable to open an userfaultfd descriptor"); + return -1; + } + + /* + * Check if the UFFD_API is the one which is expected + */ + uffdio_api.api = UFFD_API; + uffdio_api.features = kdat.uffd_features & NEED_UFFD_API_FEATURES; + if (ioctl(task_args->uffd, UFFDIO_API, &uffdio_api)) { + pr_err("Checking for UFFDIO_API failed.\n"); + goto err; + } + if (uffdio_api.api != UFFD_API) { + pr_err("Result of looking up UFFDIO_API does not match: %Lu\n", uffdio_api.api); + goto err; + } + + if (send_uffd(task_args->uffd, pid) < 0) + goto err; + + return 0; +err: + close(task_args->uffd); + return -1; +} + +int prepare_lazy_pages_socket(void) +{ + int fd, new_fd; + int len; + struct sockaddr_un sun; + + if (!opts.lazy_pages) + return 0; + + if (prepare_sock_addr(&sun)) + return -1; + + lazy_sock_mutex = shmalloc(sizeof(*lazy_sock_mutex)); + if (!lazy_sock_mutex) + return -1; + + mutex_init(lazy_sock_mutex); + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return -1; + + new_fd = install_service_fd(LAZY_PAGES_SK_OFF, fd); + close(fd); + if (new_fd < 0) + return -1; + + len = offsetof(struct sockaddr_un, sun_path) + strlen(sun.sun_path); + if (connect(new_fd, (struct sockaddr *) &sun, len) < 0) { + pr_perror("connect to %s failed", sun.sun_path); + close(new_fd); + return -1; + } + + return 0; +} + +static int server_listen(struct sockaddr_un *saddr) +{ + int fd; + int len; + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return -1; + + unlink(saddr->sun_path); + + len = offsetof(struct sockaddr_un, sun_path) + strlen(saddr->sun_path); + + if (bind(fd, (struct sockaddr *) saddr, len) < 0) { + goto out; + } + + if (listen(fd, 10) < 0) { + goto out; + } + + return fd; + +out: + close(fd); + return -1; +} + +static MmEntry *init_mm_entry(struct lazy_pages_info *lpi) +{ + struct cr_img *img; + MmEntry *mm; + int ret; + + img = open_image(CR_FD_MM, O_RSTR, lpi->pid); + if (!img) + return NULL; + + ret = pb_read_one_eof(img, &mm, PB_MM); + close_image(img); + if (ret == -1) + return NULL; + lp_debug(lpi, "Found %zd VMAs in image\n", mm->n_vmas); + + return mm; +} + +static struct lazy_iov *find_lazy_iov(struct lazy_pages_info *lpi, + unsigned long addr) +{ + struct lazy_iov *iov; + + list_for_each_entry(iov, &lpi->iovs, l) + if (addr >= iov->base && addr < iov->base + iov->len) + return iov; + + return NULL; +} + +static int split_iov(struct lazy_iov *iov, unsigned long addr, bool new_below) +{ + struct lazy_iov *new; + + new = xzalloc(sizeof(*new)); + if (!new) + return -1; + + if (new_below) { + new->base = iov->base; + new->img_base = iov->img_base; + new->len = addr - iov->base; + iov->base = addr; + iov->img_base += new->len; + iov->len -= new->len; + list_add_tail(&new->l, &iov->l); + } else { + new->base = addr; + new->img_base = iov->img_base + addr - iov->base; + new->len = iov->len - (addr - iov->base); + iov->len -= new->len; + list_add(&new->l, &iov->l); + } + + return 0; +} + +static int copy_lazy_iovs(struct lazy_pages_info *src, + struct lazy_pages_info *dst) +{ + struct lazy_iov *iov, *new, *n; + int max_iov_len = 0; + + list_for_each_entry(iov, &src->iovs, l) { + new = xzalloc(sizeof(*new)); + if (!new) + return -1; + + new->base = iov->base; + new->img_base = iov->img_base; + new->len = iov->len; + + list_add_tail(&new->l, &dst->iovs); + + if (new->len > max_iov_len) + max_iov_len = new->len; + } + + if (posix_memalign(&dst->buf, PAGE_SIZE, max_iov_len)) + goto free_iovs; + + return 0; + +free_iovs: + list_for_each_entry_safe(iov, n, &dst->iovs, l) + xfree(iov); + return -1; +} + +/* + * Purge range (addr, addr + len) from lazy_iovs. The range may + * cover several continuous IOVs. + */ +static int drop_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, + int len) +{ + struct lazy_iov *iov, *n; + + list_for_each_entry_safe(iov, n, &lpi->iovs, l) { + unsigned long start = iov->base; + unsigned long end = start + iov->len; + + if (len <= 0 || addr + len < start) + break; + + if (addr >= end) + continue; + + if (addr < start) { + len -= (start - addr); + addr = start; + } + + /* + * The range completely fits into the current IOV. + * If addr equals iov_base we just "drop" the + * beginning of the IOV. Otherwise, we make the IOV to + * end at addr, and add a new IOV start starts at + * addr + len. + */ + if (addr + len < end) { + if (addr == start) { + iov->base += len; + iov->img_base += len; + iov->len -= len; + } else { + if (split_iov(iov, addr + len, false)) + return -1; + iov->len -= len; + } + break; + } + + /* + * The range spawns beyond the end of the current IOV. + * If addr equals iov_base we just "drop" the entire + * IOV. Otherwise, we cut the beginning of the IOV + * and continue to the next one with the updated range + */ + if (addr == start) { + list_del(&iov->l); + xfree(iov); + } else { + iov->len -= (end - addr); + } + + len -= (end - addr); + addr = end; + } + + return 0; +} + +static int remap_lazy_iovs(struct lazy_pages_info *lpi, unsigned long from, + unsigned long to, unsigned long len) +{ + unsigned long off = to - from; + struct lazy_iov *iov, *n, *p; + LIST_HEAD(remaps); + + list_for_each_entry_safe(iov, n, &lpi->iovs, l) { + unsigned long iov_end = iov->base + iov->len; + + if (from > iov_end) + continue; + + if (len <= 0 || from + len < iov->base) + break; + + if (from < iov->base) { + len -= (iov->base - from); + from = iov->base; + } + + if (from > iov->base) + if (split_iov(iov, from, true)) + return -1; + if (from + len < iov_end) + if (split_iov(iov, from + len, false)) + return -1; + + list_safe_reset_next(iov, n, l); + + /* here we have iov->base = from, iov_end <= from + len */ + from = iov_end; + len -= iov->len; + iov->base += off; + list_move_tail(&iov->l, &remaps); + } + + list_for_each_entry_safe(iov, n, &remaps, l) { + list_for_each_entry(p, &lpi->iovs, l) { + if (iov->base < p->base) { + list_move_tail(&iov->l, &p->l); + break; + } + if (list_is_last(&p->l, &lpi->iovs) && + iov->base > p->base) { + list_move(&iov->l, &p->l); + break; + } + } + } + + return 0; +} + +/* + * Create a list of IOVs that can be handled using userfaultfd. The + * IOVs generally correspond to lazy pagemap entries, except the cases + * when a single pagemap entry covers several VMAs. In those cases + * IOVs are split at VMA boundaries because UFFDIO_COPY may be done + * only inside a single VMA. + * We assume here that pagemaps and VMAs are sorted. + */ +static int collect_lazy_iovs(struct lazy_pages_info *lpi) +{ + struct page_read *pr = &lpi->pr; + struct lazy_iov *iov, *n; + MmEntry *mm; + int nr_pages = 0, n_vma = 0, max_iov_len = 0; + int ret = -1; + unsigned long start, end, len; + + mm = init_mm_entry(lpi); + if (!mm) + return -1; + + while (pr->advance(pr)) { + if (!pagemap_lazy(pr->pe)) + continue; + + start = pr->pe->vaddr; + end = start + pr->pe->nr_pages * page_size(); + nr_pages += pr->pe->nr_pages; + + for (; n_vma < mm->n_vmas; n_vma++) { + VmaEntry *vma = mm->vmas[n_vma]; + + if (start >= vma->end) + continue; + + iov = xzalloc(sizeof(*iov)); + if (!iov) + goto free_iovs; + + len = min_t(uint64_t, end, vma->end) - start; + iov->base = start; + iov->img_base = start; + iov->len = len; + list_add_tail(&iov->l, &lpi->iovs); + + if (len > max_iov_len) + max_iov_len = len; + + if (end <= vma->end) + break; + + start = vma->end; + } + } + + if (posix_memalign(&lpi->buf, PAGE_SIZE, max_iov_len)) + goto free_iovs; + + ret = nr_pages; + goto free_mm; + +free_iovs: + list_for_each_entry_safe(iov, n, &lpi->iovs, l) + xfree(iov); +free_mm: + mm_entry__free_unpacked(mm, NULL); + + return ret; +} + +static int uffd_io_complete(struct page_read *pr, unsigned long vaddr, int nr); + +static int ud_open(int client, struct lazy_pages_info **_lpi) +{ + struct lazy_pages_info *lpi; + int ret = -1; + int pr_flags = PR_TASK; + + lpi = lpi_init(); + if (!lpi) + goto out; + + /* The "transfer protocol" is first the pid as int and then + * the FD for UFFD */ + ret = recv(client, &lpi->pid, sizeof(lpi->pid), 0); + if (ret != sizeof(lpi->pid)) { + if (ret < 0) + pr_perror("PID recv error"); + else + pr_err("PID recv: short read\n"); + goto out; + } + + if (lpi->pid < 0) { + pr_debug("Zombie PID: %d\n", lpi->pid); + lpi_fini(lpi); + return 0; + } + + lpi->lpfd.fd = recv_fd(client); + if (lpi->lpfd.fd < 0) { + pr_err("recv_fd error\n"); + goto out; + } + pr_debug("Received PID: %d, uffd: %d\n", lpi->pid, lpi->lpfd.fd); + + if (opts.use_page_server) + pr_flags |= PR_REMOTE; + ret = open_page_read(lpi->pid, &lpi->pr, pr_flags); + if (ret <= 0) { + ret = -1; + goto out; + } + + lpi->pr.io_complete = uffd_io_complete; + + /* + * Find the memory pages belonging to the restored process + * so that it is trackable when all pages have been transferred. + */ + ret = collect_lazy_iovs(lpi); + if (ret < 0) + goto out; + lpi->total_pages = ret; + + lp_debug(lpi, "Found %ld pages to be handled by UFFD\n", lpi->total_pages); + + list_add_tail(&lpi->l, &lpis); + *_lpi = lpi; + + return 0; + +out: + lpi_fini(lpi); + return -1; +} + +static int handle_exit(struct lazy_pages_info *lpi) +{ + lp_debug(lpi, "EXIT\n"); + if (epoll_del_rfd(epollfd, &lpi->lpfd)) + return -1; + free_lazy_iovs(lpi); + close(lpi->lpfd.fd); + + /* keep it for summary */ + list_move_tail(&lpi->l, &lpis); + + return 0; +} + +static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) +{ + struct uffdio_copy uffdio_copy; + unsigned long len = nr_pages * page_size(); + int rc; + + uffdio_copy.dst = address; + uffdio_copy.src = (unsigned long)lpi->buf; + uffdio_copy.len = len; + uffdio_copy.mode = 0; + uffdio_copy.copy = 0; + + lp_debug(lpi, "uffd_copy: 0x%llx/%ld\n", uffdio_copy.dst, len); + rc = ioctl(lpi->lpfd.fd, UFFDIO_COPY, &uffdio_copy); + if (rc) { + if (errno == ENOSPC) { + handle_exit(lpi); + return 0; + } + if (uffdio_copy.copy != -EEXIST) { + lp_debug(lpi, "uffd_copy: rc:%d copy:%Ld, errno:%d\n", + rc, uffdio_copy.copy, errno); + return -1; + } + } else if (uffdio_copy.copy != len) { + lp_err(lpi, "UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy); + return -1; + } + + lpi->copied_pages += nr_pages; + + return 0; +} + +static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long img_addr, int nr) +{ + unsigned long addr = 0; + struct lp_req *req; + + list_for_each_entry(req, &lpi->reqs, l) { + if (req->img_addr == img_addr) { + addr = req->addr; + list_del(&req->l); + xfree(req); + break; + } + } + + BUG_ON(!addr); + + if (uffd_copy(lpi, addr, nr)) + return -1; + + return drop_lazy_iovs(lpi, addr, nr * PAGE_SIZE); +} + +static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr) +{ + struct lazy_pages_info *lpi; + + lpi = container_of(pr, struct lazy_pages_info, pr); + return complete_page_fault(lpi, img_addr, nr); +} + +static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) +{ + struct uffdio_zeropage uffdio_zeropage; + unsigned long len = page_size() * nr_pages; + int rc; + + uffdio_zeropage.range.start = address; + uffdio_zeropage.range.len = len; + uffdio_zeropage.mode = 0; + + lp_debug(lpi, "zero page at 0x%llx\n", address); + rc = ioctl(lpi->lpfd.fd, UFFDIO_ZEROPAGE, &uffdio_zeropage); + if (rc) { + lp_err(lpi, "UFFDIO_ZEROPAGE error %d\n", rc); + return -1; + } + + return 0; +} + +/* + * Seek for the requested address in the pagemap. If it is found, the + * subsequent call to pr->page_read will bring us the data. If the + * address is not found in the pagemap, but no error occured, the + * address should be mapped to zero pfn. + * + * Returns 0 for zero pages, 1 for "real" pages and negative value on + * error + */ +static int uffd_seek_pages(struct lazy_pages_info *lpi, __u64 address, int nr) +{ + int ret; + + lpi->pr.reset(&lpi->pr); + + ret = lpi->pr.seek_pagemap(&lpi->pr, address); + if (!ret) { + lp_err(lpi, "no pagemap covers %llx\n", address); + return ret; + } + + lpi->pr.skip_pages(&lpi->pr, address - lpi->pr.pe->vaddr); + + return 0; +} + +static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr, unsigned flags) +{ + int ret; + + ret = uffd_seek_pages(lpi, address, nr); + if (ret) + return ret; + + ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, flags); + if (ret <= 0) { + lp_err(lpi, "failed reading pages at %llx\n", address); + return ret; + } + + return 0; +} + +static int handle_remaining_pages(struct lazy_pages_info *lpi) +{ + struct lazy_iov *iov; + struct lp_req *req; + int nr_pages, err; + + iov = list_first_entry(&lpi->iovs, struct lazy_iov, l); + nr_pages = iov->len / PAGE_SIZE; + + req = xzalloc(sizeof(*req)); + if (!req) + return -1; + + req->addr = iov->base; + req->img_addr = iov->img_base; + list_add(&req->l, &lpi->reqs); + + err = uffd_handle_pages(lpi, req->img_addr, nr_pages, 0); + if (err < 0) { + lp_err(lpi, "Error during UFFD copy\n"); + return -1; + } + + return 0; +} + +static int handle_remove(struct lazy_pages_info *lpi, struct uffd_msg *msg) +{ + struct uffdio_range unreg; + + unreg.start = msg->arg.remove.start; + unreg.len = msg->arg.remove.end - msg->arg.remove.start; + + lp_debug(lpi, "%s: %Lx(%Lx)\n", + msg->event == UFFD_EVENT_REMOVE ? "REMOVE" : "UNMAP", + unreg.start, unreg.len); + + /* + * The REMOVE event does not change the VMA, so we need to + * make sure that we won't handle #PFs in the removed + * range. With UNMAP, there's no VMA to worry about + */ + if (msg->event == UFFD_EVENT_REMOVE && + ioctl(lpi->lpfd.fd, UFFDIO_UNREGISTER, &unreg)) { + pr_perror("Failed to unregister (%llx - %llx)", unreg.start, + unreg.start + unreg.len); + return -1; + } + + return drop_lazy_iovs(lpi, unreg.start, unreg.len); +} + +static int handle_remap(struct lazy_pages_info *lpi, struct uffd_msg *msg) +{ + unsigned long from = msg->arg.remap.from; + unsigned long to = msg->arg.remap.to; + unsigned long len = msg->arg.remap.len; + + lp_debug(lpi, "REMAP: %lx -> %lx (%ld)\n", from , to, len); + + return remap_lazy_iovs(lpi, from, to, len); +} + +static int handle_fork(struct lazy_pages_info *parent_lpi, struct uffd_msg *msg) +{ + struct lazy_pages_info *lpi; + int uffd = msg->arg.fork.ufd; + + lp_debug(parent_lpi, "FORK: child with ufd=%d\n", uffd); + + lpi = lpi_init(); + if (!lpi) + return -1; + + if (copy_lazy_iovs(parent_lpi, lpi)) + goto out; + + lpi->pid = parent_lpi->pid; + lpi->lpfd.fd = uffd; + lpi->parent = parent_lpi->parent ? parent_lpi->parent : parent_lpi; + lpi->copied_pages = lpi->parent->copied_pages; + lpi->total_pages = lpi->parent->total_pages; + list_add_tail(&lpi->l, &pending_lpis); + + dup_page_read(&lpi->parent->pr, &lpi->pr); + + return 1; + +out: + lpi_fini(lpi); + return -1; +} + +static int complete_forks(int epollfd, struct epoll_event **events, int *nr_fds) +{ + struct lazy_pages_info *lpi, *n; + + list_for_each_entry(lpi, &pending_lpis, l) + (*nr_fds)++; + + *events = xrealloc(*events, sizeof(struct epoll_event) * (*nr_fds)); + if (!*events) + return -1; + + list_for_each_entry_safe(lpi, n, &pending_lpis, l) { + if (epoll_add_rfd(epollfd, &lpi->lpfd)) + return -1; + + list_del_init(&lpi->l); + list_add_tail(&lpi->l, &lpis); + } + + return 0; +} + +static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) +{ + struct lp_req *req; + struct lazy_iov *iov; + __u64 address; + int ret; + + /* Align requested address to the next page boundary */ + address = msg->arg.pagefault.address & ~(page_size() - 1); + lp_debug(lpi, "#PF at 0x%llx\n", address); + + list_for_each_entry(req, &lpi->reqs, l) + if (req->addr == address) + return 0; + + iov = find_lazy_iov(lpi, address); + if (!iov) + return uffd_zero(lpi, address, 1); + + req = xzalloc(sizeof(*req)); + if (!req) + return -1; + req->addr = address; + req->img_addr = iov->img_base + (address - iov->base); + list_add(&req->l, &lpi->reqs); + + ret = uffd_handle_pages(lpi, req->img_addr, 1, PR_ASYNC | PR_ASAP); + if (ret < 0) { + lp_err(lpi, "Error during regular page copy\n"); + return -1; + } + + return 0; +} + +static int handle_uffd_event(struct epoll_rfd *lpfd) +{ + struct lazy_pages_info *lpi; + struct uffd_msg msg; + int ret; + + lpi = container_of(lpfd, struct lazy_pages_info, lpfd); + + ret = read(lpfd->fd, &msg, sizeof(msg)); + if (!ret) + return 1; + + if (ret != sizeof(msg)) { + /* we've already handled the page fault for another thread */ + if (errno == EAGAIN) + return 0; + if (ret < 0) + lp_perror(lpi, "Can't read uffd message"); + else + lp_err(lpi, "Can't read uffd message: short read"); + return -1; + } + + switch (msg.event) { + case UFFD_EVENT_PAGEFAULT: + return handle_page_fault(lpi, &msg); + case UFFD_EVENT_REMOVE: + case UFFD_EVENT_UNMAP: + return handle_remove(lpi, &msg); + case UFFD_EVENT_REMAP: + return handle_remap(lpi, &msg); + case UFFD_EVENT_FORK: + return handle_fork(lpi, &msg); + default: + lp_err(lpi, "unexpected uffd event %u\n", msg.event); + return -1; + } + + return 0; +} + +static int lazy_pages_summary(struct lazy_pages_info *lpi) +{ + lp_debug(lpi, "UFFD transferred pages: (%ld/%ld)\n", + lpi->copied_pages, lpi->total_pages); + +#if 0 + if ((lpi->copied_pages != lpi->total_pages) && (lpi->total_pages > 0)) { + lp_warn(lpi, "Only %ld of %ld pages transferred via UFFD\n" + "Something probably went wrong.\n", + lpi->copied_pages, lpi->total_pages); + return 1; + } +#endif + + return 0; +} + +#define POLL_TIMEOUT 1000 + +static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) +{ + struct lazy_pages_info *lpi; + int poll_timeout = POLL_TIMEOUT; + int ret; + + for (;;) { + bool remaining = false; + + ret = epoll_run_rfds(epollfd, events, nr_fds, poll_timeout); + if (ret < 0) + goto out; + if (ret > 0) { + if (complete_forks(epollfd, &events, &nr_fds)) + return -1; + continue; + } + + if (poll_timeout) + pr_debug("Start handling remaining pages\n"); + + poll_timeout = 0; + list_for_each_entry(lpi, &lpis, l) { + if (!list_empty(&lpi->iovs)) { + remaining = true; + ret = handle_remaining_pages(lpi); + if (ret < 0) + goto out; + break; + } + } + + if (!remaining) + break; + } + + list_for_each_entry(lpi, &lpis, l) + ret += lazy_pages_summary(lpi); + +out: + return ret; + +} + +static int prepare_lazy_socket(void) +{ + int listen; + struct sockaddr_un saddr; + + if (prepare_sock_addr(&saddr)) + return -1; + + pr_debug("Waiting for incoming connections on %s\n", saddr.sun_path); + if ((listen = server_listen(&saddr)) < 0) { + pr_perror("server_listen error"); + return -1; + } + + return listen; +} + +static int prepare_uffds(int listen, int epollfd) +{ + int i; + int client; + socklen_t len; + struct sockaddr_un saddr; + + /* accept new client request */ + len = sizeof(struct sockaddr_un); + if ((client = accept(listen, (struct sockaddr *) &saddr, &len)) < 0) { + pr_perror("server_accept error"); + close(listen); + return -1; + } + + for (i = 0; i < task_entries->nr_tasks; i++) { + struct lazy_pages_info *lpi = NULL; + if (ud_open(client, &lpi)) + goto close_uffd; + if (lpi == NULL) + continue; + if (epoll_add_rfd(epollfd, &lpi->lpfd)) + goto close_uffd; + } + + close_safe(&client); + close(listen); + return 0; + +close_uffd: + close_safe(&client); + close(listen); + return -1; +} + +int cr_lazy_pages(bool daemon) +{ + struct epoll_event *events; + int nr_fds; + int lazy_sk; + int ret; + + if (kerndat_uffd() || !kdat.has_uffd) + return -1; + + if (prepare_dummy_pstree()) + return -1; + + lazy_sk = prepare_lazy_socket(); + if (lazy_sk < 0) + return -1; + + if (daemon) { + ret = cr_daemon(1, 0, &lazy_sk, -1); + if (ret == -1) { + pr_err("Can't run in the background\n"); + return -1; + } + if (ret > 0) { /* parent task, daemon started */ + if (opts.pidfile) { + if (write_pidfile(ret) == -1) { + pr_perror("Can't write pidfile"); + kill(ret, SIGKILL); + waitpid(ret, NULL, 0); + return -1; + } + } + + return 0; + } + } + + if (close_status_fd()) + return -1; + + nr_fds = task_entries->nr_tasks + (opts.use_page_server ? 1 : 0); + epollfd = epoll_prepare(nr_fds, &events); + if (epollfd < 0) + return -1; + + if (prepare_uffds(lazy_sk, epollfd)) + return -1; + + if (opts.use_page_server) { + if (connect_to_page_server_to_recv(epollfd)) + return -1; + } + + ret = handle_requests(epollfd, events, nr_fds); + + return ret; +} From e4d14b65d78f7d5461182bb0c3cbe6c63f8a66a1 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 4 May 2017 16:32:17 +0300 Subject: [PATCH 0533/4375] kdat: Merge dump and restore kerndats Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/include/kerndat.h | 1 - criu/kerndat.c | 32 -------------------------------- criu/lsm.c | 2 +- 4 files changed, 2 insertions(+), 35 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index abd55af00..29b1f274b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2167,7 +2167,7 @@ int cr_restore_tasks(void) if (init_stats(RESTORE_STATS)) goto err; - if (kerndat_init_rst()) + if (kerndat_init()) goto err; timing_start(TIME_RESTORE); diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 9de8875d9..6edf4c6f5 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -11,7 +11,6 @@ struct stat; */ extern int kerndat_init(void); -extern int kerndat_init_rst(void); extern int kerndat_get_dirty_track(void); extern int kerndat_fdinfo_has_lock(void); extern int kerndat_loginuid(void); diff --git a/criu/kerndat.c b/criu/kerndat.c index 5f53f7d0a..0ad2596c8 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -589,40 +589,8 @@ int kerndat_init(void) ret = kerndat_tcp_repair(); if (!ret) ret = kerndat_compat_restore(); - - kerndat_lsm(); - kerndat_mmap_min_addr(); - - return ret; -} - -int kerndat_init_rst(void) -{ - int ret; - - /* - * Read TCP sysctls before anything else, - * since the limits we're interested in are - * not available inside namespaces. - */ - - ret = check_pagemap(); - if (!ret) - ret = get_last_cap(); if (!ret) ret = kerndat_has_memfd_create(); - if (!ret) - ret = get_task_size(); - if (!ret) - ret = get_ipv6(); - if (!ret) - ret = kerndat_loginuid(); - if (!ret) - ret = kerndat_iptables_has_xtlocks(); - if (!ret) - ret = kerndat_tcp_repair(); - if (!ret) - ret = kerndat_compat_restore(); kerndat_lsm(); kerndat_mmap_min_addr(); diff --git a/criu/lsm.c b/criu/lsm.c index 8c014d432..4f5c43605 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -111,7 +111,7 @@ void kerndat_lsm(void) { /* On restore, if someone passes --lsm-profile, we might end up doing * detection twice, once during flag parsing and once for - * kerndat_init_rst(). Let's detect when we've already done detection + * kerndat_init(). Let's detect when we've already done detection * and not do it again. */ if (name) From 07a00662ad4bde7bdb75de7e8aa985ef21016bee Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 4 May 2017 16:32:32 +0300 Subject: [PATCH 0534/4375] kdat: Cache kdat object into /run/criu.kdat (v4) Doing kerndat checks on every criu start is way too slow. We need some way to speed this checks up on a particular box. As suggested by Andre, Dima and Mike let's try to keep the collected kdat bits into some tmpfs file. Keeping it on tmpfs would invaludate this cache on every machine reboot. There have been many suggestions how to generate this file, my proposal is to create it once the kdat object is filled by criu, w/o any explicit command. Optionally we can add 'criu kdat --save|--drop' actions to manage this file. v2: * don't ignore return code of write() (some glibcs complain) * unlink tmp file in case rename failed v3: * add one more magic into kerndat_s which is the 'date +%s' * ignore any errors opening or saving cache. Only size/magic mismatch matters (and result in dropping the cache) * cache file path is Makefile-configurable (RUNDIR) * don't save cache if kerndat auto-detection failed v4: * Use ?= for RUNDIR definition. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- Makefile.install | 3 +- criu/Makefile.crtools | 1 + criu/include/kerndat.h | 1 + criu/include/magic.h | 6 +++ criu/kerndat.c | 84 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 94 insertions(+), 1 deletion(-) diff --git a/Makefile.install b/Makefile.install index f1e541500..979ef0dc1 100644 --- a/Makefile.install +++ b/Makefile.install @@ -7,6 +7,7 @@ MANDIR := $(PREFIX)/share/man LIBDIR := $(PREFIX)/lib INCLUDEDIR := $(PREFIX)/include LIBEXECDIR := $(PREFIX)/libexec +RUNDIR ?= /run # # For recent Debian/Ubuntu with multiarch support. @@ -21,7 +22,7 @@ else endif endif -export PREFIX BINDIR SBINDIR MANDIR +export PREFIX BINDIR SBINDIR MANDIR RUNDIR export LIBDIR INCLUDEDIR LIBEXECDIR install-man: diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 5c2911ffc..adc64ef7a 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -1,6 +1,7 @@ ccflags-y += -iquote criu/$(ARCH) ccflags-y += $(COMPEL_UAPI_INCLUDES) CFLAGS_REMOVE_clone-noasan.o += $(CFLAGS-ASAN) +CFLAGS_kerndat.o += -DKDAT_MAGIC_2=${shell date +%s} -DKDAT_RUNDIR=\"$(RUNDIR)\" ldflags-y += -r obj-y += action-scripts.o diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 6edf4c6f5..ba8c10da7 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -29,6 +29,7 @@ enum loginuid_func { }; struct kerndat_s { + u32 magic1, magic2; dev_t shmem_dev; int last_cap; u64 zero_page_pfn; diff --git a/criu/include/magic.h b/criu/include/magic.h index deb54b1d0..a0071eec4 100644 --- a/criu/include/magic.h +++ b/criu/include/magic.h @@ -115,4 +115,10 @@ #define STATS_MAGIC 0x57093306 /* Ostashkov */ #define IRMAP_CACHE_MAGIC 0x57004059 /* Ivanovo */ +/* + * Main magic for kerndat_s structure. + */ + +#define KDAT_MAGIC 0x57023458 /* Torzhok */ + #endif /* __CR_MAGIC_H__ */ diff --git a/criu/kerndat.c b/criu/kerndat.c index 0ad2596c8..f946cef78 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -562,10 +562,91 @@ static int kerndat_compat_restore(void) return 0; } +#define KERNDAT_CACHE_FILE KDAT_RUNDIR"/criu.kdat" +#define KERNDAT_CACHE_FILE_TMP KDAT_RUNDIR"/.criu.kdat" + +static int kerndat_try_load_cache(void) +{ + int fd, ret; + + fd = open(KERNDAT_CACHE_FILE, O_RDONLY); + if (fd < 0) { + pr_warn("Can't load %s\n", KERNDAT_CACHE_FILE); + return 1; + } + + ret = read(fd, &kdat, sizeof(kdat)); + if (ret < 0) { + pr_perror("Can't read kdat cache"); + return -1; + } + + close(fd); + + if (ret != sizeof(kdat) || + kdat.magic1 != KDAT_MAGIC || + kdat.magic2 != KDAT_MAGIC_2) { + pr_warn("Stale %s file\n", KERNDAT_CACHE_FILE); + unlink(KERNDAT_CACHE_FILE); + return 1; + } + + pr_info("Loaded kdat cache from %s\n", KERNDAT_CACHE_FILE); + return 0; +} + +static void kerndat_save_cache(void) +{ + int fd, ret; + struct statfs s; + + fd = open(KERNDAT_CACHE_FILE_TMP, O_CREAT | O_EXCL | O_WRONLY, 0600); + if (fd < 0) + /* + * It can happen that we race with some other criu + * instance. That's OK, just ignore this error and + * proceed. + */ + return; + + if (fstatfs(fd, &s) < 0 || s.f_type != TMPFS_MAGIC) { + pr_warn("Can't keep kdat cache on non-tempfs\n"); + close(fd); + goto unl; + } + + /* + * One magic to make sure we're reading the kdat file. + * One more magic to make somehow sure we don't read kdat + * from some other criu + */ + kdat.magic1 = KDAT_MAGIC; + kdat.magic2 = KDAT_MAGIC_2; + ret = write(fd, &kdat, sizeof(kdat)); + close(fd); + + if (ret == sizeof(kdat)) + ret = rename(KERNDAT_CACHE_FILE_TMP, KERNDAT_CACHE_FILE); + else { + ret = -1; + errno = EIO; + } + + if (ret < 0) { + pr_perror("Couldn't save %s", KERNDAT_CACHE_FILE); +unl: + unlink(KERNDAT_CACHE_FILE_TMP); + } +} + int kerndat_init(void) { int ret; + ret = kerndat_try_load_cache(); + if (ret <= 0) + return ret; + ret = check_pagemap(); if (!ret) ret = kerndat_get_shmemdev(); @@ -595,5 +676,8 @@ int kerndat_init(void) kerndat_lsm(); kerndat_mmap_min_addr(); + if (!ret) + kerndat_save_cache(); + return ret; } From fc33d333af384737e4454dedd9239f2edfa22055 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 4 May 2017 16:32:46 +0300 Subject: [PATCH 0535/4375] criu: Move mod preload into kdat Modules pre-load is also slow, but guarding this code with the presence of criu.kdat cache file seems reasonable. Or course, one may unload the needed modules by hands, but such smart user may as well remove the /run/criu.kdat file :) Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/crtools.c | 6 ------ criu/kerndat.c | 4 ++++ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index ba805b9cc..6cc6cf3ea 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -25,11 +25,9 @@ #include "crtools.h" #include "cr_options.h" #include "external.h" -#include "sockets.h" #include "files.h" #include "sk-inet.h" #include "net.h" -#include "netfilter.h" #include "version.h" #include "page-xfer.h" #include "tty.h" @@ -700,9 +698,6 @@ int main(int argc, char *argv[], char *envp[]) pr_info("Will do snapshot from %s\n", opts.img_parent); if (!strcmp(argv[optind], "dump")) { - preload_socket_modules(); - preload_netfilter_modules(); - if (!tree_id) goto opt_pid_missing; return cr_dump_tasks(tree_id); @@ -716,7 +711,6 @@ int main(int argc, char *argv[], char *envp[]) } if (!strcmp(argv[optind], "restore")) { - preload_netfilter_modules(); if (tree_id) pr_warn("Using -t with criu restore is obsoleted\n"); diff --git a/criu/kerndat.c b/criu/kerndat.c index f946cef78..354fb672b 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -29,6 +29,7 @@ #include "sk-inet.h" #include #include +#include "netfilter.h" struct kerndat_s kdat = { }; @@ -647,6 +648,9 @@ int kerndat_init(void) if (ret <= 0) return ret; + preload_socket_modules(); + preload_netfilter_modules(); + ret = check_pagemap(); if (!ret) ret = kerndat_get_shmemdev(); From ea6357e65188c741f3ea5c3f52bf76bffb2da4c1 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 3 May 2017 22:40:12 +0300 Subject: [PATCH 0536/4375] criu/ia32: don't redefine __NR32_rt_sigaction Cleanup: use nr, provided by compel. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/sigaction_compat.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/criu/arch/x86/sigaction_compat.c b/criu/arch/x86/sigaction_compat.c index 52f22a4f9..5965ef79f 100644 --- a/criu/arch/x86/sigaction_compat.c +++ b/criu/arch/x86/sigaction_compat.c @@ -2,14 +2,10 @@ #include "asm/restorer.h" #include #include "asm/compat.h" +#include #ifdef CR_NOGLIBC -# include # include -#else -# ifndef __NR32_rt_sigaction -# define __NR32_rt_sigaction 174 -# endif #endif #include "cpu.h" From d011a9fb42a46d253f34ff20974dff585bf0d63a Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 3 May 2017 22:40:13 +0300 Subject: [PATCH 0537/4375] restorer: remove always true `has_futex' arg Check for presence of robust futex list is in the reality (futex_rla_len != 0). That does code on dumping, in get_task_futex_robust_list(): > ret = syscall(SYS_get_robust_list, pid, &head, &len); > if (ret < 0 && errno == ENOSYS) { [..] > len = 0; [..] > } [..] > info->futex_rla_len = (u32)len; And in images: futex_rla_len == 0 means that futex is not present. So, we don't need additional restorer's parameter `has_futex' which is always true, remove it. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 1 - criu/include/restorer.h | 1 - criu/pie/restorer.c | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 29b1f274b..8617f4f86 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3237,7 +3237,6 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns rst_reloc_creds(&thread_args[i], &creds_pos_next); - thread_args[i].has_futex = true; thread_args[i].futex_rla = tcore->thread_core->futex_rla; thread_args[i].futex_rla_len = tcore->thread_core->futex_rla_len; thread_args[i].pdeath_sig = tcore->thread_core->pdeath_sig; diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 7f516e2cf..81839f398 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -82,7 +82,6 @@ struct thread_restore_args { UserRegsEntry gpregs; u64 clear_tid_addr; - bool has_futex; u64 futex_rla; u32 futex_rla_len; diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 807388743..48329d7e0 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -426,7 +426,7 @@ static int restore_thread_common(struct thread_restore_args *args) { sys_set_tid_address((int *)decode_pointer(args->clear_tid_addr)); - if (args->has_futex && args->futex_rla_len) { + if (args->futex_rla_len) { int ret; ret = sys_set_robust_list(decode_pointer(args->futex_rla), From 9a282cbb77824adcfebcea80350a482f5a3b5a1f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 3 May 2017 22:40:14 +0300 Subject: [PATCH 0538/4375] ia32/futex: add dumping compat_robust_list The kernel keeps two different pointers for 32-bit and 64-bit futex lists: robust_list and compat_robust_list in task_struct. So, dump compat_robust_list for ia32 tasks. Note: this means that one can set *both* compat_robust_list and robust_list pointers by using as we're here 32-bit and 64-bit syscalls. That's one of mixed-bitness application questions. For simplification (and omitting more syscalls), we dump here only one of the pointers. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/include/asm/dump.h | 2 + criu/arch/arm/include/asm/dump.h | 2 + criu/arch/ppc64/include/asm/dump.h | 2 + criu/arch/x86/crtools.c | 72 ++++++++++++++++++++++++++++ criu/arch/x86/include/asm/dump.h | 1 + criu/cr-dump.c | 14 +++++- 6 files changed, 91 insertions(+), 2 deletions(-) diff --git a/criu/arch/aarch64/include/asm/dump.h b/criu/arch/aarch64/include/asm/dump.h index 8a9666289..bc3dbcf3a 100644 --- a/criu/arch/aarch64/include/asm/dump.h +++ b/criu/arch/aarch64/include/asm/dump.h @@ -11,4 +11,6 @@ static inline void core_put_tls(CoreEntry *core, tls_t tls) core->ti_aarch64->tls = tls; } +#define get_task_futex_robust_list_compat(pid, info) -1 + #endif diff --git a/criu/arch/arm/include/asm/dump.h b/criu/arch/arm/include/asm/dump.h index f08e53843..2382ba42c 100644 --- a/criu/arch/arm/include/asm/dump.h +++ b/criu/arch/arm/include/asm/dump.h @@ -11,4 +11,6 @@ static inline void core_put_tls(CoreEntry *core, tls_t tls) core->ti_arm->tls = tls; } +#define get_task_futex_robust_list_compat(pid, info) -1 + #endif diff --git a/criu/arch/ppc64/include/asm/dump.h b/criu/arch/ppc64/include/asm/dump.h index 6439adafd..a81ee02bd 100644 --- a/criu/arch/ppc64/include/asm/dump.h +++ b/criu/arch/ppc64/include/asm/dump.h @@ -8,4 +8,6 @@ extern void arch_free_thread_info(CoreEntry *core); #define core_put_tls(core, tls) +#define get_task_futex_robust_list_compat(pid, info) -1 + #endif diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index d0121b48e..756a36e37 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -7,6 +7,7 @@ #include "types.h" #include "log.h" +#include "asm/compat.h" #include "asm/parasite-syscall.h" #include "asm/restorer.h" #include @@ -436,3 +437,74 @@ int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) } return 0; } + +struct syscall_args32 { + uint32_t nr, arg0, arg1, arg2, arg3, arg4, arg5; +}; + +static void do_full_int80(struct syscall_args32 *args) +{ + register unsigned long bp asm("bp") = args->arg5; + asm volatile ("int $0x80" + : "+a" (args->nr), + "+b" (args->arg0), "+c" (args->arg1), "+d" (args->arg2), + "+S" (args->arg3), "+D" (args->arg4), "+r" (bp) + : : "r8", "r9", "r10", "r11"); + args->arg5 = bp; +} + +static int get_robust_list32(pid_t pid, uintptr_t head, uintptr_t len) +{ + struct syscall_args32 s = { + .nr = __NR32_get_robust_list, + .arg0 = pid, + .arg1 = (uint32_t)head, + .arg2 = (uint32_t)len, + }; + + do_full_int80(&s); + return (int)s.nr; +} + +static int set_robust_list32(uint32_t head, uint32_t len) +{ + struct syscall_args32 s = { + .nr = __NR32_set_robust_list, + .arg0 = head, + .arg1 = len, + }; + + do_full_int80(&s); + return (int)s.nr; +} + +int get_task_futex_robust_list_compat(pid_t pid, ThreadCoreEntry *info) +{ + void *mmap32; + int ret = -1; + + mmap32 = alloc_compat_syscall_stack(); + if (!mmap32) + return -1; + + ret = get_robust_list32(pid, (uintptr_t)mmap32, (uintptr_t)mmap32 + 4); + + if (ret == -ENOSYS) { + /* Check native get_task_futex_robust_list() for details. */ + if (set_robust_list32(0, 0) == (uint32_t)-ENOSYS) { + info->futex_rla = 0; + info->futex_rla_len = 0; + ret = 0; + } + } else if (ret == 0) { + uint32_t *arg1 = (uint32_t*)mmap32; + + info->futex_rla = *arg1; + info->futex_rla_len = *(arg1 + 1); + ret = 0; + } + + + free_compat_syscall_stack(mmap32); + return ret; +} diff --git a/criu/arch/x86/include/asm/dump.h b/criu/arch/x86/include/asm/dump.h index ca7cd675f..c79e0dfa9 100644 --- a/criu/arch/x86/include/asm/dump.h +++ b/criu/arch/x86/include/asm/dump.h @@ -4,6 +4,7 @@ extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *); extern int arch_alloc_thread_info(CoreEntry *core); extern void arch_free_thread_info(CoreEntry *core); +extern int get_task_futex_robust_list_compat(pid_t pid, ThreadCoreEntry *info); static inline void core_put_tls(CoreEntry *core, tls_t tls) { diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 1c41d5f59..b9fa28496 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -673,8 +673,18 @@ int dump_thread_core(int pid, CoreEntry *core, const struct parasite_dump_thread ThreadCoreEntry *tc = core->thread_core; ret = collect_lsm_profile(pid, tc->creds); - if (!ret) - ret = get_task_futex_robust_list(pid, tc); + if (!ret) { + /* + * XXX: It's possible to set two: 32-bit and 64-bit + * futex list's heads. That makes about no sense, but + * it's possible. Until we meet such application, dump + * only one: native or compat futex's list pointer. + */ + if (!core_is_compat(core)) + ret = get_task_futex_robust_list(pid, tc); + else + ret = get_task_futex_robust_list_compat(pid, tc); + } if (!ret) ret = dump_sched_info(pid, tc); if (!ret) { From 9e3e46565de91b62e5c0a8c5a2fc0e2ef2813793 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 3 May 2017 22:40:15 +0300 Subject: [PATCH 0539/4375] ia32/futex: restore compat_robust_list The same as for Checkpointing - we need to call 32-bit syscall for compatible tasks here to correctly restore compat_robust_list, not robust_list. Note: I check here restorer's *task* arg for compatible mode, not restorer *thread* arg. As changing application's mode during runtime is very rare thing itself, application that runs different bitness threads is most likely not present at all. If we ever meet such application, this could be improved. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/include/asm/restorer.h | 10 ++++-- criu/arch/arm/include/asm/restorer.h | 10 ++++-- criu/arch/ppc64/include/asm/restorer.h | 10 ++++-- criu/arch/x86/crtools.c | 15 --------- criu/arch/x86/include/asm/compat.h | 16 ++++++++++ criu/arch/x86/include/asm/restorer.h | 11 +++++-- criu/arch/x86/restorer.c | 14 +++++++++ criu/pie/restorer.c | 40 ++++++++++++++++++------ 8 files changed, 93 insertions(+), 33 deletions(-) diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h index 60cd99fb5..78cc9bd39 100644 --- a/criu/arch/aarch64/include/asm/restorer.h +++ b/criu/arch/aarch64/include/asm/restorer.h @@ -64,7 +64,13 @@ static inline void restore_tls(tls_t *ptls) static inline void *alloc_compat_syscall_stack(void) { return NULL; } static inline void free_compat_syscall_stack(void *stack32) { } -static inline int -arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; } +static inline int arch_compat_rt_sigaction(void *stack, int sig, void *act) +{ + return -1; +} +static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) +{ + return -1; +} #endif diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h index 007260a3a..8748281fc 100644 --- a/criu/arch/arm/include/asm/restorer.h +++ b/criu/arch/arm/include/asm/restorer.h @@ -77,7 +77,13 @@ static inline void restore_tls(tls_t *ptls) { static inline void *alloc_compat_syscall_stack(void) { return NULL; } static inline void free_compat_syscall_stack(void *stack32) { } -static inline int -arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; } +static inline int arch_compat_rt_sigaction(void *stack, int sig, void *act) +{ + return -1; +} +static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) +{ + return -1; +} #endif diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h index d16ec26ac..e3d2d291e 100644 --- a/criu/arch/ppc64/include/asm/restorer.h +++ b/criu/arch/ppc64/include/asm/restorer.h @@ -63,7 +63,13 @@ unsigned long sys_shmat(int shmid, const void *shmaddr, int shmflg); static inline void *alloc_compat_syscall_stack(void) { return NULL; } static inline void free_compat_syscall_stack(void *stack32) { } -static inline int -arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; } +static inline int arch_compat_rt_sigaction(void *stack, int sig, void *act) +{ + return -1; +} +static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) +{ + return -1; +} #endif /*__CR_ASM_RESTORER_H__*/ diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 756a36e37..d0694a0e1 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -438,21 +438,6 @@ int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r) return 0; } -struct syscall_args32 { - uint32_t nr, arg0, arg1, arg2, arg3, arg4, arg5; -}; - -static void do_full_int80(struct syscall_args32 *args) -{ - register unsigned long bp asm("bp") = args->arg5; - asm volatile ("int $0x80" - : "+a" (args->nr), - "+b" (args->arg0), "+c" (args->arg1), "+d" (args->arg2), - "+S" (args->arg3), "+D" (args->arg4), "+r" (bp) - : : "r8", "r9", "r10", "r11"); - args->arg5 = bp; -} - static int get_robust_list32(pid_t pid, uintptr_t head, uintptr_t len) { struct syscall_args32 s = { diff --git a/criu/arch/x86/include/asm/compat.h b/criu/arch/x86/include/asm/compat.h index 6d20c93f6..cad5d0ff7 100644 --- a/criu/arch/x86/include/asm/compat.h +++ b/criu/arch/x86/include/asm/compat.h @@ -34,6 +34,22 @@ static inline void free_compat_syscall_stack(void *mem) mem, ret); } +struct syscall_args32 { + uint32_t nr, arg0, arg1, arg2, arg3, arg4, arg5; +}; + +static inline void do_full_int80(struct syscall_args32 *args) +{ + register unsigned long bp asm("bp") = args->arg5; + asm volatile ("int $0x80" + : "+a" (args->nr), + "+b" (args->arg0), "+c" (args->arg1), "+d" (args->arg2), + "+S" (args->arg3), "+D" (args->arg4), "+r" (bp) + : : "r8", "r9", "r10", "r11"); + args->arg5 = bp; +} + + #ifdef CONFIG_COMPAT extern unsigned long call32_from_64(void *stack, void *func); #endif diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index acd7218f8..e7199f684 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -12,10 +12,17 @@ extern void restore_tls(tls_t *ptls); extern int arch_compat_rt_sigaction(void *stack32, int sig, rt_sigaction_t_compat *act); +extern int set_compat_robust_list(uint32_t head_ptr, uint32_t len); #else /* CONFIG_COMPAT */ static inline void restore_tls(tls_t *ptls) { } -static inline int -arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; } +static inline int arch_compat_rt_sigaction(void *stack, int sig, void *act) +{ + return -1; +} +static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) +{ + return -1; +} #endif /* !CONFIG_COMPAT */ #define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \ diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index a66304385..d6da030b2 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -3,9 +3,11 @@ #include "types.h" #include "restorer.h" +#include "asm/compat.h" #include "asm/restorer.h" #include +#include #include #include #include "log.h" @@ -34,6 +36,18 @@ int restore_nonsigframe_gpregs(UserX86RegsEntry *r) #ifdef CONFIG_COMPAT +int set_compat_robust_list(uint32_t head_ptr, uint32_t len) +{ + struct syscall_args32 s = { + .nr = __NR32_set_robust_list, + .arg0 = head_ptr, + .arg1 = len, + }; + + do_full_int80(&s); + return (int)s.nr; +} + static int prepare_stack32(void **stack32) { if (*stack32) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 48329d7e0..e6ad86e44 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -422,20 +422,40 @@ die: return -1; } +static int restore_robust_futex(struct thread_restore_args *args) +{ + uint32_t futex_len = args->futex_rla_len; + int ret; + + if (!args->futex_rla_len) + return 0; + + /* + * XXX: We check here *task's* mode, not *thread's*. + * But it's possible to write an application with mixed + * threads (on x86): some in 32-bit mode, some in 64-bit. + * Quite unlikely that such application exists at all. + */ + if (args->ta->compatible_mode) { + uint32_t futex = (uint32_t)args->futex_rla; + ret = set_compat_robust_list(futex, futex_len); + } else { + void *futex = decode_pointer(args->futex_rla); + ret = sys_set_robust_list(futex, futex_len); + } + + if (ret) + pr_err("Failed to recover futex robust list: %d\n", ret); + + return ret; +} + static int restore_thread_common(struct thread_restore_args *args) { sys_set_tid_address((int *)decode_pointer(args->clear_tid_addr)); - if (args->futex_rla_len) { - int ret; - - ret = sys_set_robust_list(decode_pointer(args->futex_rla), - args->futex_rla_len); - if (ret) { - pr_err("Failed to recover futex robust list: %d\n", ret); - return -1; - } - } + if (restore_robust_futex(args)) + return -1; restore_sched_info(&args->sp); From af6e70b2b9f81cf68202aac36c7267c91837bafa Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 13 Apr 2017 18:26:36 +0300 Subject: [PATCH 0540/4375] crit: RSS explorer When running 'cirt x dir rss' one will see the way pagemap chunks are scatered across the VMs of processes. Sample output from the env00 zdtm test is 22 400000 / 1 00400000 / 5 /root/criu/test/zdtm/static/env00 604000 / 2 00604000 / 1 /root/criu/test/zdtm/static/env00 00605000 / 1 /root/criu/test/zdtm/static/env00 853000 / 1 00853000 / 33 7faba2d4b000 / 6 7faba2d4b000 / 4 /usr/lib64/libc-2.22.so 7faba2d4f000 / 2 /usr/lib64/libc-2.22.so 7faba2d51000 / 2 7faba2d51000 / 4 7faba2d54000 / 1 ~ 7faba2f64000 / 3 7faba2f64000 / 3 7faba2f74000 / 1 7faba2f74000 / 1 7faba2f75000 / 2 7faba2f75000 / 1 /usr/lib64/ld-2.22.so 7faba2f76000 / 1 /usr/lib64/ld-2.22.so 7faba2f77000 / 1 7faba2f77000 / 1 7fffb4de3000 / 3 7fffb4de2000 / 70 7fffb4e24000 / 2 ~ 7fffb4e27000 / 1 ~ 7fffb4f6a000 / 2 7fffb4f6a000 / 2 Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- crit/crit | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/crit/crit b/crit/crit index 8b1e19bb9..a6a6832b5 100755 --- a/crit/crit +++ b/crit/crit @@ -212,7 +212,42 @@ def explore_mems(opts): print "\t%-36s%s%s" % (astr, prot, fn) -explorers = { 'ps': explore_ps, 'fds': explore_fds, 'mems': explore_mems } +def explore_rss(opts): + ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) + for p in ps_img['entries']: + pid = p['pid'] + vmas = pycriu.images.load(dinf(opts, 'mm-%d.img' % pid))['entries'][0]['vmas'] + pms = pycriu.images.load(dinf(opts, 'pagemap-%d.img' % pid))['entries'] + + print "%d" % pid + vmi = 0 + pvmi = -1 + for pm in pms[1:]: + pstr = '\t%lx / %-8d' % (pm['vaddr'], pm['nr_pages']) + while vmas[vmi]['end'] <= pm['vaddr']: + vmi += 1 + + pme = pm['vaddr'] + (pm['nr_pages'] << 12) + vstr = '' + while vmas[vmi]['start'] < pme: + vma = vmas[vmi] + if vmi == pvmi: + vstr += ' ~' + else: + vstr += ' %08lx / %-8d' % (vma['start'], (vma['end'] - vma['start'])>>12) + if vma['status'] & ((1 << 6) | (1 << 7)): + vstr += ' ' + get_file_str(opts, {'type': 'REG', 'id': vma['shmid']}) + pvmi = vmi + vstr += '\n\t%23s' % '' + vmi += 1 + + vmi -= 1 + + print '%-24s%s' % (pstr, vstr) + + + +explorers = { 'ps': explore_ps, 'fds': explore_fds, 'mems': explore_mems, 'rss': explore_rss } def explore(opts): explorers[opts['what']](opts) @@ -258,7 +293,7 @@ def main(): # Explore x_parser = subparsers.add_parser('x', help = 'explore image dir') x_parser.add_argument('dir') - x_parser.add_argument('what', choices = [ 'ps', 'fds', 'mems' ]) + x_parser.add_argument('what', choices = [ 'ps', 'fds', 'mems', 'rss']) x_parser.set_defaults(func=explore) # Show From 2a37b50765b9f88383d213aad0ce7768c124ec95 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 28 Apr 2017 21:28:37 +0300 Subject: [PATCH 0541/4375] soccr.h: use uint32_t instead of __u32 As uint32_t already has occupied the header, use it for all 32-bit unsigns. That will allow to drop additional include . Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- soccr/soccr.h | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/soccr/soccr.h b/soccr/soccr.h index a6562bfb7..2957fd6c4 100644 --- a/soccr/soccr.h +++ b/soccr/soccr.h @@ -72,24 +72,24 @@ union libsoccr_addr { * socket and given back into the library in two steps (see below). */ struct libsoccr_sk_data { - __u32 state; - __u32 inq_len; - __u32 inq_seq; - __u32 outq_len; - __u32 outq_seq; - __u32 unsq_len; - __u32 opt_mask; - __u32 mss_clamp; - __u32 snd_wscale; - __u32 rcv_wscale; - __u32 timestamp; + uint32_t state; + uint32_t inq_len; + uint32_t inq_seq; + uint32_t outq_len; + uint32_t outq_seq; + uint32_t unsq_len; + uint32_t opt_mask; + uint32_t mss_clamp; + uint32_t snd_wscale; + uint32_t rcv_wscale; + uint32_t timestamp; - __u32 flags; /* SOCCR_FLAGS_... below */ - __u32 snd_wl1; - __u32 snd_wnd; - __u32 max_window; - __u32 rcv_wnd; - __u32 rcv_wup; + uint32_t flags; /* SOCCR_FLAGS_... below */ + uint32_t snd_wl1; + uint32_t snd_wnd; + uint32_t max_window; + uint32_t rcv_wnd; + uint32_t rcv_wup; }; /* From 03eccbf1c868b0b909d7c51d5fa4aef655b32964 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 28 Apr 2017 21:28:38 +0300 Subject: [PATCH 0542/4375] soccr: clean a bit includes list soccr.h: After previous patch is not needed anymore, is needed as we test for it in feature tests, i.e., struct tcp_repair_window is declared there. Also drop forward-declaration of (struct libsoccr_sk) - it's declared again below. soccr.c: Sort headers by name so errors like twice-including errno.h will not happen again. Also remove assert.h. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- soccr/soccr.c | 10 ++++------ soccr/soccr.h | 9 ++++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/soccr/soccr.c b/soccr/soccr.c index 0a7748149..583f1eaaa 100644 --- a/soccr/soccr.c +++ b/soccr/soccr.c @@ -1,13 +1,11 @@ +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include -#include - #include "soccr.h" #ifndef SIOCOUTQNSD diff --git a/soccr/soccr.h b/soccr/soccr.h index 2957fd6c4..c9d138bfc 100644 --- a/soccr/soccr.h +++ b/soccr/soccr.h @@ -1,8 +1,9 @@ #ifndef __LIBSOCCR_H__ #define __LIBSOCCR_H__ -#include -#include -#include +#include /* sockaddr_in, sockaddr_in6 */ +#include /* TCP_REPAIR_WINDOW, TCP_TIMESTAMP */ +#include /* uint32_t */ +#include /* sockaddr */ #include "config.h" @@ -49,8 +50,6 @@ enum { #define TCP_REPAIR_WINDOW 29 #endif -struct libsoccr_sk; - void libsoccr_set_log(unsigned int level, void (*fn)(unsigned int level, const char *fmt, ...)); #define SOCCR_LOG_ERR 1 From 4669d6330e784feafa9a48185d5b08c3393659be Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 2 May 2017 16:53:22 -0700 Subject: [PATCH 0543/4375] crit: fix 'make install' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently, setup.py from distutils interprets --root= option without an argument as "--root=." and we end up with what is described in https://github.com/xemul/criu/issues/309. Fix is to prepend DESTDIR value (if any) to --prefix argument. v2: fix uninstall as well v3: same code, resent via gmail Reported-by: Juraj Oršulić Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- lib/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index a8647ce7a..b1bb05727 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -56,7 +56,7 @@ install: lib-c lib-py crit/crit lib/c/criu.pc.in $(Q) sed -e 's,@version@,$(CRIU_VERSION),' -e 's,@libdir@,$(LIBDIR),' -e 's,@includedir@,$(dir $(INCLUDEDIR)/criu/),' lib/c/criu.pc.in > lib/c/criu.pc $(Q) install -m 644 lib/c/criu.pc $(DESTDIR)$(LIBDIR)/pkgconfig $(E) " INSTALL " crit - $(Q) $(PYTHON_BIN) scripts/crit-setup.py install --root=$(DESTDIR) --prefix=$(PREFIX) --record $(CRIT_SETUP_FILES) + $(Q) $(PYTHON_BIN) scripts/crit-setup.py install --prefix=$(DESTDIR)$(PREFIX) --record $(CRIT_SETUP_FILES) .PHONY: install uninstall: @@ -68,5 +68,5 @@ uninstall: $(E) " UNINSTALL" pkgconfig/criu.pc $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBDIR)/pkgconfig/,criu.pc) $(E) " UNINSTALL" crit - $(Q) while read -r file; do $(RM) "$(DESTDIR)$$file"; done < $(CRIT_SETUP_FILES) + $(Q) while read -r file; do $(RM) "$$file"; done < $(CRIT_SETUP_FILES) .PHONY: uninstall From 71dcc6e9183ad7383df2a20f1b5bc681e856e535 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 4 May 2017 23:27:47 +0300 Subject: [PATCH 0544/4375] travis: check the --empty-ns option Reviewed-by: Kirill Tkhai Looks-good-to: Pavel Emelyanov Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 50a51ff35..37e418abc 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -88,6 +88,8 @@ ip net add test ./test/zdtm.py run -t zdtm/static/env00 --rpc # Basic ./test/zdtm.py run -t zdtm/static/ptrace_sig -f h --rpc # Error handling (crfail test) +./test/zdtm.py run --empty-ns -T zdtm/static/socket-tcp*-local --iter 2 + pip install flake8 make lint From 98204deb347ed0df31f98d9f54e1b506fa66190a Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 6 May 2017 08:40:16 +0300 Subject: [PATCH 0545/4375] test: don't use nsenter in tests Ubuntu 14.04 (Travis) doesn't have it. Reviewed-by: Kirill Tkhai Looks-good-to: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/empty-netns-prep.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/empty-netns-prep.sh b/test/empty-netns-prep.sh index 212eb39c6..07e7e8f45 100755 --- a/test/empty-netns-prep.sh +++ b/test/empty-netns-prep.sh @@ -1,8 +1,16 @@ -#!/bin/sh +#!/bin/bash + +set -ex if [ "$CRTOOLS_SCRIPT_ACTION" == "setup-namespaces" ]; then echo "Will up lo at $CRTOOLS_INIT_PID netns" - nsenter -t "$CRTOOLS_INIT_PID" --net ip link set up dev lo || exit 1 + mkdir -p /var/run/netns + mount -t tmpfs xxx /var/run/netns + touch /var/run/netns/emptyns + mount --bind /proc/$CRTOOLS_INIT_PID/ns/net /var/run/netns/emptyns + ip netns exec emptyns ip link set up dev lo || exit 1 + ip netns exec emptyns ip a + umount -l /var/run/netns fi exit 0 From 4a57dfec9ec6bbb4fcd095b3bd8dcdc620f93d71 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 20 Apr 2017 01:03:44 -0500 Subject: [PATCH 0546/4375] compel plugins: add optional plugins As we have more than 1 working plugin right now, let's implement the TODO item for "compel plugins" command. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/src/main.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/compel/src/main.c b/compel/src/main.c index 4584ef915..4f53e7e5d 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -125,7 +125,8 @@ static int usage(int rc) { fprintf(out, "Usage:\n" -" compel [--compat] includes | cflags | ldflags | plugins\n" +" compel [--compat] includes | cflags | ldflags\n" +" compel plugins [PLUGIN_NAME ...]\n" " compel [--compat] [--static] libs\n" " compel -f FILE -o FILE [-p NAME] [-l N] hgen\n" " -f, --file FILE input (parasite object) file name\n" @@ -188,18 +189,27 @@ static void print_ldflags(bool compat) } } -static void print_plugins(const char *list[]) +static void print_plugin(const char *name) { const char suffix[] = ".lib.a"; - while (*list != NULL) { - if (uninst_root) - printf("%s/plugins/%s%s\n", - uninst_root, *list, suffix); - else - printf("%s/compel/%s%s\n", LIBEXECDIR, *list, suffix); - list++; - } + if (uninst_root) + printf("%s/plugins/%s%s\n", + uninst_root, name, suffix); + else + printf("%s/compel/%s%s\n", LIBEXECDIR, name, suffix); +} + +static void print_plugins(char *const list[]) +{ + char *builtin_list[] = { "std", NULL }; + char **p = builtin_list; + + while (*p != NULL) + print_plugin(*p++); + + while (*list != NULL) + print_plugin(*list++); } static int print_libs(bool is_static) @@ -294,7 +304,6 @@ int main(int argc, char *argv[]) bool is_static = false; int opt, idx; char *action; - const char *plugins_list[] = { "std", NULL }; static const char short_opts[] = "csf:o:p:hVl:"; static struct option long_opts[] = { @@ -372,9 +381,7 @@ int main(int argc, char *argv[]) } if (!strcmp(action, "plugins")) { - /* TODO: add option to specify additional plugins - * if/when we'll have any */ - print_plugins(plugins_list); + print_plugins(argv + optind); return 0; } From ef6c3f6ce6172b4c2539f1bf0d76328b4d0ee56b Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 20 Apr 2017 01:03:45 -0500 Subject: [PATCH 0547/4375] compel/test/fdspy: fix linking 1. Commit 8b99809 ("compel: make plugins .a archives") changed the suffix of compel plugins, so this test no longer compiles. 2. "compel plugins" can print auxiliary plugins now, let's use it. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/test/fdspy/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/test/fdspy/Makefile b/compel/test/fdspy/Makefile index 4fed7912e..027c373fe 100644 --- a/compel/test/fdspy/Makefile +++ b/compel/test/fdspy/Makefile @@ -22,7 +22,7 @@ parasite.h: parasite.po $(COMPEL) hgen -o $@ -f $< parasite.po: parasite.o - ld $(shell $(COMPEL) ldflags) -o $@ $^ $(shell $(COMPEL) plugins) ../../plugins/fds.built-in.o + ld $(shell $(COMPEL) ldflags) -o $@ $^ $(shell $(COMPEL) plugins fds) parasite.o: parasite.c $(CC) $(CFLAGS) -c $(shell $(COMPEL) cflags) -o $@ $^ From 0c4eaafd4a79c796b7b7ce7ca218c07bd36444a5 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 11 May 2017 12:10:42 +0300 Subject: [PATCH 0548/4375] vma: Add vma_next() helper Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 4 ++-- criu/include/vma.h | 5 +++++ criu/mem.c | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 8617f4f86..7e1670a97 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2226,7 +2226,7 @@ static long restorer_get_vma_hint(struct list_head *tgt_vma_list, break; if (prev_vma_end < s_vma->e->end) prev_vma_end = s_vma->e->end; - s_vma = list_entry(s_vma->list.next, struct vma_area, list); + s_vma = vma_next(s_vma); continue; } @@ -2239,7 +2239,7 @@ static long restorer_get_vma_hint(struct list_head *tgt_vma_list, break; if (prev_vma_end < t_vma->e->end) prev_vma_end = t_vma->e->end; - t_vma = list_entry(t_vma->list.next, struct vma_area, list); + t_vma = vma_next(t_vma); continue; } diff --git a/criu/include/vma.h b/criu/include/vma.h index d73886dba..748563d64 100644 --- a/criu/include/vma.h +++ b/criu/include/vma.h @@ -104,4 +104,9 @@ static inline bool vma_area_is_private(struct vma_area *vma, return vma_entry_is_private(vma->e, task_size); } +static inline struct vma_area *vma_next(struct vma_area *vma) +{ + return list_entry(vma->list.next, struct vma_area, list); +} + #endif /* __CR_VMA_H__ */ diff --git a/criu/mem.c b/criu/mem.c index 255e88e37..0d4360566 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -724,7 +724,7 @@ static int restore_priv_vma_content(struct pstree_item *t) while (va >= vma->e->end) { if (vma->list.next == vmas) goto err_addr; - vma = list_entry(vma->list.next, struct vma_area, list); + vma = vma_next(vma); } /* From aebbdbf1efaa0cc00f125588b893744988e36a1e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 11 May 2017 12:10:59 +0300 Subject: [PATCH 0549/4375] compel: Add preadv syscall Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- compel/arch/arm/plugins/std/syscalls/syscall.def | 1 + compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl | 1 + compel/arch/x86/plugins/std/syscalls/syscall_32.tbl | 1 + compel/arch/x86/plugins/std/syscalls/syscall_64.tbl | 1 + 4 files changed, 4 insertions(+) diff --git a/compel/arch/arm/plugins/std/syscalls/syscall.def b/compel/arch/arm/plugins/std/syscalls/syscall.def index 647bc2033..91213e0e7 100644 --- a/compel/arch/arm/plugins/std/syscalls/syscall.def +++ b/compel/arch/arm/plugins/std/syscalls/syscall.def @@ -107,3 +107,4 @@ io_submit 2 246 (aio_context_t ctx_id, long nr, struct iocb **iocbpp) io_getevents 4 245 (aio_context_t ctx, long min_nr, long nr, struct io_event *evs, struct timespec *tmo) seccomp 277 383 (unsigned int op, unsigned int flags, const char *uargs) gettimeofday 169 78 (struct timeval *tv, struct timezone *tz) +preadv 69 361 (int fd, struct iovec *iov, unsigned long nr, loff_t off) diff --git a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl index 23d54b38f..9cb2fb6ea 100644 --- a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl +++ b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl @@ -104,3 +104,4 @@ __NR_io_getevents 229 sys_io_getevents (aio_context_t ctx_id, long min_nr, long __NR_io_submit 230 sys_io_submit (aio_context_t ctx_id, long nr, struct iocb **iocbpp) __NR_ipc 117 sys_ipc (unsigned int call, int first, unsigned long second, unsigned long third, const void *ptr, long fifth) __NR_gettimeofday 78 sys_gettimeofday (struct timeval *tv, struct timezone *tz) +__NR_preadv 320 sys_preadv (int fd, struct iovec *iov, unsigned long nr, loff_t off) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl index 5d6cebd6e..0eea9d061 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl @@ -84,6 +84,7 @@ __NR_get_robust_list 312 sys_get_robust_list (int pid, struct robust_list_head __NR_vmsplice 316 sys_vmsplice (int fd, const struct iovec *iov, unsigned int nr_segs, unsigned int flags) __NR_signalfd 321 sys_signalfd (int ufd, const k_rtsigset_t *sigmask, size_t sigsetsize) __NR_timerfd_settime 325 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) +__NR_preadv 333 sys_preadv (int fd, struct iovec *iov, unsigned long nr, loff_t off) __NR_rt_tgsigqueueinfo 335 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *uinfo) __NR_fanotify_init 338 sys_fanotify_init (unsigned int flags, unsigned int event_f_flags) __NR_fanotify_mark 339 sys_fanotify_mark (int fanotify_fd, unsigned int flag, uint32_t mask, int dfd, const char *pathname) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl index 35262c002..c291c9a42 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl @@ -96,6 +96,7 @@ __NR_seccomp 317 sys_seccomp (unsigned int op, unsigned int flags, const cha __NR_vmsplice 278 sys_vmsplice (int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags) __NR_timerfd_settime 286 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) __NR_signalfd4 289 sys_signalfd (int fd, k_rtsigset_t *mask, size_t sizemask, int flags) +__NR_preadv 295 sys_preadv (int fd, struct iovec *iov, unsigned long nr, loff_t off) __NR_rt_tgsigqueueinfo 297 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *info) __NR_fanotify_init 300 sys_fanotify_init (unsigned int flags, unsigned int event_f_flags) __NR_fanotify_mark 301 sys_fanotify_mark (int fanotify_fd, unsigned int flags, uint64_t mask, int dfd, const char *pathname) From b43f7aa6159708874cacac77c20f22bf23047b86 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 11 May 2017 12:11:19 +0300 Subject: [PATCH 0550/4375] page_read: Make it possible to get pages.img ID from page_read The pages.img will need to get opened one more time w/o the pagemap.img. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/image.c | 14 ++++++-------- criu/include/image.h | 4 ++-- criu/include/pagemap.h | 1 + criu/page-xfer.c | 4 +++- criu/pagemap.c | 2 +- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/criu/image.c b/criu/image.c index 9715d1602..84e6c8af5 100644 --- a/criu/image.c +++ b/criu/image.c @@ -461,29 +461,27 @@ void up_page_ids_base(void) page_ids += 0x10000; } -struct cr_img *open_pages_image_at(int dfd, unsigned long flags, struct cr_img *pmi) +struct cr_img *open_pages_image_at(int dfd, unsigned long flags, struct cr_img *pmi, u32 *id) { - unsigned id; - if (flags == O_RDONLY || flags == O_RDWR) { PagemapHead *h; if (pb_read_one(pmi, &h, PB_PAGEMAP_HEAD) < 0) return NULL; - id = h->pages_id; + *id = h->pages_id; pagemap_head__free_unpacked(h, NULL); } else { PagemapHead h = PAGEMAP_HEAD__INIT; - id = h.pages_id = page_ids++; + *id = h.pages_id = page_ids++; if (pb_write_one(pmi, &h, PB_PAGEMAP_HEAD) < 0) return NULL; } - return open_image_at(dfd, CR_FD_PAGES, flags, id); + return open_image_at(dfd, CR_FD_PAGES, flags, *id); } -struct cr_img *open_pages_image(unsigned long flags, struct cr_img *pmi) +struct cr_img *open_pages_image(unsigned long flags, struct cr_img *pmi, u32 *id) { - return open_pages_image_at(get_service_fd(IMG_FD_OFF), flags, pmi); + return open_pages_image_at(get_service_fd(IMG_FD_OFF), flags, pmi, id); } /* diff --git a/criu/include/image.h b/criu/include/image.h index 1c22a4f66..22f34afff 100644 --- a/criu/include/image.h +++ b/criu/include/image.h @@ -150,8 +150,8 @@ extern void close_image_dir(void); extern struct cr_img *open_image_at(int dfd, int type, unsigned long flags, ...); #define open_image(typ, flags, ...) open_image_at(-1, typ, flags, ##__VA_ARGS__) extern int open_image_lazy(struct cr_img *img); -extern struct cr_img *open_pages_image(unsigned long flags, struct cr_img *pmi); -extern struct cr_img *open_pages_image_at(int dfd, unsigned long flags, struct cr_img *pmi); +extern struct cr_img *open_pages_image(unsigned long flags, struct cr_img *pmi, u32 *pages_id); +extern struct cr_img *open_pages_image_at(int dfd, unsigned long flags, struct cr_img *pmi, u32 *pages_id); extern void up_page_ids_base(void); extern struct cr_img *img_from_fd(int fd); /* for cr-show mostly */ diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index e87e9f1a7..6633eec20 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -55,6 +55,7 @@ struct page_read { /* Private data of reader */ struct cr_img *pmi; struct cr_img *pi; + u32 pages_img_id; PagemapEntry *pe; /* current pagemap we are on */ struct page_read *parent; /* parent pagemap (if ->in_parent diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 71aee0d6b..436c41c2c 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -267,11 +267,13 @@ static void close_page_xfer(struct page_xfer *xfer) static int open_page_local_xfer(struct page_xfer *xfer, int fd_type, long id) { + u32 pages_id; + xfer->pmi = open_image(fd_type, O_DUMP, id); if (!xfer->pmi) return -1; - xfer->pi = open_pages_image(O_DUMP, xfer->pmi); + xfer->pi = open_pages_image(O_DUMP, xfer->pmi, &pages_id); if (!xfer->pi) { close_image(xfer->pmi); return -1; diff --git a/criu/pagemap.c b/criu/pagemap.c index 991d92e81..9c11c261a 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -655,7 +655,7 @@ int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) return -1; } - pr->pi = open_pages_image_at(dfd, flags, pr->pmi); + pr->pi = open_pages_image_at(dfd, flags, pr->pmi, &pr->pages_img_id); if (!pr->pi) { close_page_read(pr); return -1; From 9058baae7eaa05f5392241cb9edb7c277bb195b4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 11 May 2017 12:11:36 +0300 Subject: [PATCH 0551/4375] pagemap: Enqueue iovec to arbitrary list We currently can batch pagemap entries into page-read list, but will need to queue them into per-pstree_entry one. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/pagemap.h | 3 +++ criu/pagemap.c | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index 6633eec20..eded0d351 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -95,6 +95,9 @@ extern int open_page_read(int pid, struct page_read *, int pr_flags); extern int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags); +int pagemap_enqueue_iovec(struct page_read *pr, void *buf, + unsigned long len, struct list_head *to); + extern int dedup_one_iovec(struct page_read *pr, unsigned long base, unsigned long len); diff --git a/criu/pagemap.c b/criu/pagemap.c index 9c11c261a..512beed8b 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -279,7 +279,8 @@ static int read_local_page(struct page_read *pr, unsigned long vaddr, return 0; } -static int enqueue_async_iov(struct page_read *pr, unsigned long len, void *buf) +static int enqueue_async_iov(struct page_read *pr, void *buf, + unsigned long len, struct list_head *to) { struct page_read_iov *pr_iov; struct iovec *iov; @@ -303,19 +304,19 @@ static int enqueue_async_iov(struct page_read *pr, unsigned long len, void *buf) pr_iov->to = iov; pr_iov->nr = 1; - list_add_tail(&pr_iov->l, &pr->async); + list_add_tail(&pr_iov->l, to); return 0; } -static int enqueue_async_page(struct page_read *pr, unsigned long vaddr, - unsigned long len, void *buf) +int pagemap_enqueue_iovec(struct page_read *pr, void *buf, + unsigned long len, struct list_head *to) { struct page_read_iov *cur_async = NULL; struct iovec *iov; - if (!list_empty(&pr->async)) - cur_async = list_entry(pr->async.prev, struct page_read_iov, l); + if (!list_empty(to)) + cur_async = list_entry(to->prev, struct page_read_iov, l); /* * We don't have any async requests or we have new read @@ -324,7 +325,7 @@ static int enqueue_async_page(struct page_read *pr, unsigned long vaddr, * Start the new preadv request here. */ if (!cur_async || pr->pi_off != cur_async->end) - return enqueue_async_iov(pr, len, buf); + return enqueue_async_iov(pr, buf, len, to); /* * This read is pure continuation of the previous one. Let's @@ -339,7 +340,7 @@ static int enqueue_async_page(struct page_read *pr, unsigned long vaddr, unsigned int n_iovs = cur_async->nr + 1; if (n_iovs >= IOV_MAX) - return enqueue_async_iov(pr, len, buf); + return enqueue_async_iov(pr, buf, len, to); iov = xrealloc(cur_async->to, n_iovs * sizeof(*iov)); if (!iov) @@ -366,7 +367,7 @@ static int maybe_read_page(struct page_read *pr, unsigned long vaddr, unsigned long len = nr * PAGE_SIZE; if (flags & PR_ASYNC) - ret = enqueue_async_page(pr, vaddr, len, buf); + ret = pagemap_enqueue_iovec(pr, buf, len, &pr->async); else ret = read_local_page(pr, vaddr, len, buf); From 6eee76d4035ee0d38acf534890adf0f5e17583eb Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 13 May 2017 03:11:19 +0300 Subject: [PATCH 0552/4375] restore: simplify sigchld handler The idea is simple. Everyone has to wait its children, a restore is interrupted if we found abandoned zombie. Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 48 ++++++++++------------------------------------- 1 file changed, 10 insertions(+), 38 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 7e1670a97..1fb7a9243 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1207,54 +1207,26 @@ err: static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) { - struct pstree_item *pi; - pid_t pid = siginfo->si_pid; - int status; - int exit; + int status, pid, exit; - exit = (siginfo->si_code == CLD_EXITED); - status = siginfo->si_status; - - /* skip scripts */ - if (!current && root_item->pid->real != pid) { - pid = waitpid(root_item->pid->real, &status, WNOHANG); - if (pid <= 0) - return; - exit = WIFEXITED(status); - status = exit ? WEXITSTATUS(status) : WTERMSIG(status); - } - - if (!current && siginfo->si_code == CLD_TRAPPED && - siginfo->si_status == SIGCHLD) { - /* The root task is ptraced. Allow it to handle SIGCHLD */ - ptrace(PTRACE_CONT, siginfo->si_pid, 0, SIGCHLD); - return; - } - - if (!current || status) - goto err; - - while (pid) { + while (1) { pid = waitpid(-1, &status, WNOHANG); if (pid <= 0) return; + if (!current && WIFSTOPPED(status) && + WSTOPSIG(status) == SIGCHLD) { + /* The root task is ptraced. Allow it to handle SIGCHLD */ + ptrace(PTRACE_CONT, siginfo->si_pid, 0, SIGCHLD); + return; + } + exit = WIFEXITED(status); status = exit ? WEXITSTATUS(status) : WTERMSIG(status); - if (status) - break; - /* Exited (with zero code) helpers are OK */ - list_for_each_entry(pi, ¤t->children, sibling) - if (vpid(pi) == siginfo->si_pid) - break; - - BUG_ON(&pi->sibling == ¤t->children); - if (pi->pid->state != TASK_HELPER) - break; + break; } -err: if (exit) pr_err("%d exited, status=%d\n", pid, status); else From 6f8f85ffd4f5aa29d592417e59032617e21af8e5 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 5 May 2017 17:52:04 +0300 Subject: [PATCH 0553/4375] ia32/kdat: Check for 32-bit mmap() bug There were kernel bug with 32-bit mmap() returning 64-bit pointer. The fix is in Torvalds master, will be released in v4.12 kernel. Checkpointing after v4.9 kernel works good, but restoring will result in application which will mmap() 64-bit addresses resulting in segfault/memory corruptions/etc. As our policy is fail on dump if we can't restore on the same target, error checkpointing for v4.9. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 126 ++++++++++++++++++++++++++++++++++++++-- criu/cr-check.c | 2 +- 2 files changed, 121 insertions(+), 7 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index d0694a0e1..90b809b5e 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -1,9 +1,12 @@ +#include +#include #include #include #include #include #include #include +#include #include "types.h" #include "log.h" @@ -27,17 +30,22 @@ #include "images/core.pb-c.h" #include "images/creds.pb-c.h" -int kdat_compatible_cr(void) -{ #ifdef CONFIG_COMPAT +static int has_arch_map_vdso(void) +{ unsigned long auxval; int ret; errno = 0; auxval = getauxval(AT_SYSINFO_EHDR); - if (!auxval || errno == ENOENT) { - pr_err("Failed to get auxval, err: %lu\n", auxval); - return 0; + if (!auxval) { + if (errno == ENOENT) { /* No vDSO - OK */ + pr_warn("No SYSINFO_EHDR - no vDSO\n"); + return 1; + } else { /* That can't happen, according to man */ + pr_err("Failed to get auxval: errno %d\n", errno); + return -1; + } } /* * Mapping vDSO while have not unmap it yet: @@ -46,10 +54,116 @@ int kdat_compatible_cr(void) ret = syscall(SYS_arch_prctl, ARCH_MAP_VDSO_32, 1); if (ret == -1 && errno == EEXIST) return 1; -#endif return 0; } +void *mmap_ia32(void *addr, size_t len, int prot, + int flags, int fildes, off_t off) +{ + struct syscall_args32 s; + + s.nr = __NR32_mmap2; + s.arg0 = (uint32_t)(uintptr_t)addr; + s.arg1 = (uint32_t)len; + s.arg2 = prot; + s.arg3 = flags; + s.arg4 = fildes; + s.arg5 = (uint32_t)off; + + do_full_int80(&s); + + return (void *)(uintptr_t)s.nr; +} + +/* + * The idea of the test: + * From kernel's top-down allocator we assume here that + * 1. A = mmap(0, ...); munmap(A); + * 2. B = mmap(0, ...); + * results in A == B. + * ...but if we have 32-bit mmap() bug, then A will have only lower + * 4 bytes of 64-bit address allocated with mmap(). + * That means, that the next mmap() will return B != A + * (as munmap(A) hasn't really unmapped A mapping). + * + * As mapping with lower 4 bytes of A may really exist, we run + * this test under fork(). + * + * Another approach to test bug's presence would be to parse + * /proc/self/maps before and after 32-bit mmap(), but that would + * be soo slow. + */ +static void mmap_bug_test(void) +{ + void *map1, *map2; + int err; + + map1 = mmap_ia32(0, PAGE_SIZE, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); + /* 32-bit error, not sign-extended - can't use IS_ERR_VALUE() here */ + err = (uintptr_t)map1 % PAGE_SIZE; + if (err) { + pr_err("ia32 mmap() failed: %d\n", err); + exit(1); + } + + if (munmap(map1, PAGE_SIZE)) { + pr_err("Failed to unmap() 32-bit mapping: %m\n"); + exit(1); + } + + map2 = mmap_ia32(0, PAGE_SIZE, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); + err = (uintptr_t)map2 % PAGE_SIZE; + if (err) { + pr_err("ia32 mmap() failed: %d\n", err); + exit(1); + } + + if (map1 != map2) + exit(1); + exit(0); +} + +/* + * Pre v4.12 kernels have a bug: for a process started as 64-bit + * 32-bit mmap() may return 8 byte pointer. + * Which is fatal for us: after 32-bit C/R a task will map 64-bit + * addresses, cut upper 4 bytes and try to use lower 4 bytes. + * This is a check if the bug was fixed in the kernel. + */ +static int has_32bit_mmap_bug(void) +{ + pid_t child = fork(); + int stat; + + if (child == 0) + mmap_bug_test(); + + if (waitpid(child, &stat, 0) != child) { + pr_err("Failed to wait for mmap test"); + kill(child, SIGKILL); + return -1; + } + + if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0) + return 1; + return 0; +} + +int kdat_compatible_cr(void) +{ + if (!has_arch_map_vdso()) + return 0; + if (has_32bit_mmap_bug()) + return 0; + return 1; +} +#else +int kdat_compatible_cr(void) +{ + return 0; +} +#endif + int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) { CoreEntry *core = x; diff --git a/criu/cr-check.c b/criu/cr-check.c index f39130f1b..cd23f7863 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1060,7 +1060,7 @@ static int check_compat_cr(void) #ifdef CONFIG_COMPAT if (kdat_compatible_cr()) return 0; - pr_warn("compat_cr is not supported. Requires kernel >= v4.9\n"); + pr_warn("compat_cr is not supported. Requires kernel >= v4.12\n"); #else pr_warn("CRIU built without CONFIG_COMPAT - can't C/R ia32\n"); #endif From 695295ae9845447eacdb6011ba5a5a5a7a4c62f4 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 28 Apr 2017 03:59:30 +0300 Subject: [PATCH 0554/4375] fsnotify: don't save mnt_id if a mount namepsace isn't dumped Processes can be restored in another mntns, so mnt_id will be useless in this case. If mntns isn't dumped, we have to dump a path to a mount point. Cc: Cyrill Gorcunov Signed-off-by: Andrei Vagin Reviewed-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/fsnotify.c | 29 +++++++++++++++++++---------- images/fsnotify.proto | 1 + 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 65833caeb..a127218ee 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -180,9 +180,10 @@ static char *alloc_openable(unsigned int s_dev, unsigned long i_ino, FhEntry *f_ path = xstrdup(buf); if (path == NULL) goto err; - - f_handle->has_mnt_id = true; - f_handle->mnt_id = m->mnt_id; + if (root_ns_mask & CLONE_NEWNS) { + f_handle->has_mnt_id = true; + f_handle->mnt_id = m->mnt_id; + } return path; } } else @@ -425,6 +426,8 @@ static int dump_fanotify_entry(union fdinfo_entries *e, void *arg) pr_err("Can't find mnt_id 0x%x\n", fme->me->mnt_id); goto out; } + if (!(root_ns_mask & CLONE_NEWNS)) + fme->me->path = m->mountpoint + 1; fme->s_dev = m->s_dev; pr_info("mark: s_dev %#08x mnt_id %#08x mask %#08x\n", @@ -621,18 +624,24 @@ static int restore_one_fanotify(int fd, struct fsnotify_mark_info *mark) if (fme->type == MARK_TYPE__MOUNT) { struct mount_info *m; int mntns_root; + char *p = fme->me->path; + struct ns_id *nsid = NULL; - m = lookup_mnt_id(fme->me->mnt_id); - if (!m) { - pr_err("Can't find mount mnt_id 0x%x\n", fme->me->mnt_id); - return -1; + if (root_ns_mask & CLONE_NEWNS) { + m = lookup_mnt_id(fme->me->mnt_id); + if (!m) { + pr_err("Can't find mount mnt_id 0x%x\n", fme->me->mnt_id); + return -1; + } + nsid = m->nsid; + p = m->ns_mountpoint; } - mntns_root = mntns_get_root_fd(m->nsid); + mntns_root = mntns_get_root_fd(nsid); - target = openat(mntns_root, m->ns_mountpoint, O_PATH); + target = openat(mntns_root, p, O_PATH); if (target == -1) { - pr_perror("Unable to open %s", m->ns_mountpoint); + pr_perror("Unable to open %s", p); goto err; } diff --git a/images/fsnotify.proto b/images/fsnotify.proto index 1f73d9b01..399a449a0 100644 --- a/images/fsnotify.proto +++ b/images/fsnotify.proto @@ -33,6 +33,7 @@ message fanotify_inode_mark_entry { message fanotify_mount_mark_entry { required uint32 mnt_id = 1; + optional string path = 2; } message fanotify_mark_entry { From 0237eb27c82e71f06c1d89e2ed0f389442d78613 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 28 Apr 2017 03:59:31 +0300 Subject: [PATCH 0555/4375] restore: don't collect mounts if mntns isn't restored Currently it is only used to get a file descriptor to the mount namespace root, but if we have only one mntns, we can open "/". Cc: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/fsnotify.c | 1 - criu/mount.c | 28 ++++++++-------------------- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index a127218ee..6bc840c98 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -532,7 +532,6 @@ static char *get_mark_path(const char *who, struct file_remap *remap, char *path = "."; uint32_t mnt_id = f_handle->has_mnt_id ? f_handle->mnt_id : -1; - /* irmap cache is collected in the root namespaces. */ mntns_root = mntns_get_root_by_mnt_id(mnt_id); diff --git a/criu/mount.c b/criu/mount.c index 8c2016d4e..ba1c6bcfa 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2457,22 +2457,6 @@ out: return exit_code; } -static int rst_collect_local_mntns(enum ns_type typ) -{ - struct ns_id *nsid; - - nsid = rst_new_ns_id(0, getpid(), &mnt_ns_desc, typ); - if (!nsid) - return -1; - - mntinfo = collect_mntinfo(nsid, false); - if (!mntinfo) - return -1; - - nsid->ns_populated = true; - return 0; -} - static int get_mp_root(MntEntry *me, struct mount_info *mi) { char *ext = NULL; @@ -2978,7 +2962,7 @@ int prepare_mnt_ns(void) struct ns_id *nsid; if (!(root_ns_mask & CLONE_NEWNS)) - return rst_collect_local_mntns(NS_CRIU); + return 0; pr_info("Restoring mount namespace\n"); @@ -3155,6 +3139,8 @@ set_root: int mntns_get_root_fd(struct ns_id *mntns) { + if (!(root_ns_mask & CLONE_NEWNS)) + return __mntns_get_root_fd(0); /* * All namespaces are restored from the root task and during the * CR_STATE_FORKING stage the root task has two file descriptors for @@ -3205,10 +3191,12 @@ struct ns_id *lookup_nsid_by_mnt_id(int mnt_id) int mntns_get_root_by_mnt_id(int mnt_id) { - struct ns_id *mntns; + struct ns_id *mntns = NULL; - mntns = lookup_nsid_by_mnt_id(mnt_id); - BUG_ON(mntns == NULL); + if (root_ns_mask & CLONE_NEWNS) { + mntns = lookup_nsid_by_mnt_id(mnt_id); + BUG_ON(mntns == NULL); + } return mntns_get_root_fd(mntns); } From f734928c8af4c963fdd46ed81fcf987ec86688e6 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 28 Apr 2017 16:18:38 +0300 Subject: [PATCH 0556/4375] tty: Make sure no /dev/tty inheritance exist Currently we support restoring opened /dev/tty reference if only control terminal belongs to the same process, ie no inheritance is allowed. Thus we should refuse to dump in such scenario otherwise restore will fail. Reported-by: Stanislav Kinsburskiy Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/tty.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/criu/tty.c b/criu/tty.c index 156f05e66..51516c731 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -114,6 +114,7 @@ struct tty_dump_info { u32 id; pid_t sid; pid_t pgrp; + pid_t pid_real; int fd; int mnt_id; struct tty_driver *driver; @@ -1752,6 +1753,7 @@ static int dump_tty_info(int lfd, u32 id, const struct fd_parms *p, struct tty_d dinfo->id = id; dinfo->sid = pti->sid; dinfo->pgrp = pti->pgrp; + dinfo->pid_real = p->pid; dinfo->fd = p->fd; dinfo->mnt_id = p->mnt_id; dinfo->driver = driver; @@ -2111,8 +2113,45 @@ static int tty_dump_queued_data(void) return ret; } +static int tty_verify_ctty(void) +{ + struct tty_dump_info *d, *p; + + list_for_each_entry(d, &all_ttys, list) { + struct tty_dump_info *n = NULL; + + if (d->driver->type != TTY_TYPE__CTTY) + continue; + + list_for_each_entry(p, &all_ttys, list) { + if (!is_pty(p->driver) || + p->sid != d->sid || + p->pgrp != d->sid) + continue; + n = p; + break; + } + + if (!n) { + pr_err("ctty inheritance detected sid/pgrp %d, " + "no PTY peer with sid/pgrp needed\n", + d->sid); + return -ENOENT; + } else if (n->pid_real != d->pid_real) { + pr_err("ctty inheritance detected sid/pgrp %d " + "(ctty pid_real %d pty pid_real %d)\n", + d->sid, d->pid_real, n->pid_real); + return -ENOENT; + } + } + + return 0; +} + int tty_post_actions(void) { + if (tty_verify_ctty()) + return -1; if (tty_verify_active_pairs(NULL)) return -1; else if (tty_dump_queued_data()) From 27be93b7db4e3a16751d87823fd86b47ba72742c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 22 May 2017 11:23:11 +0300 Subject: [PATCH 0557/4375] Revert "kdat: Relax uffd checks (v2)" This reverts commit a840995689f7ab898ba34fd10e014704165e2f83, that got into master by mistake. Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 1167 --------------------------------------------------- 1 file changed, 1167 deletions(-) delete mode 100644 criu/uffd.c diff --git a/criu/uffd.c b/criu/uffd.c deleted file mode 100644 index 205045e34..000000000 --- a/criu/uffd.c +++ /dev/null @@ -1,1167 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "linux/userfaultfd.h" - -#include "int.h" -#include "page.h" -#include "criu-log.h" -#include "criu-plugin.h" -#include "pagemap.h" -#include "files-reg.h" -#include "kerndat.h" -#include "mem.h" -#include "uffd.h" -#include "util-pie.h" -#include "protobuf.h" -#include "pstree.h" -#include "crtools.h" -#include "cr_options.h" -#include "xmalloc.h" -#include -#include "restorer.h" -#include "page-xfer.h" -#include "common/lock.h" -#include "rst-malloc.h" -#include "util.h" - -#undef LOG_PREFIX -#define LOG_PREFIX "uffd: " - -#define lp_debug(lpi, fmt, arg...) pr_debug("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) -#define lp_info(lpi, fmt, arg...) pr_info("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) -#define lp_warn(lpi, fmt, arg...) pr_warn("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) -#define lp_err(lpi, fmt, arg...) pr_err("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) -#define lp_perror(lpi, fmt, arg...) pr_perror("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) - -#define NEED_UFFD_API_FEATURES (UFFD_FEATURE_EVENT_FORK | \ - UFFD_FEATURE_EVENT_REMAP | \ - UFFD_FEATURE_EVENT_UNMAP | \ - UFFD_FEATURE_EVENT_REMOVE) - -#define LAZY_PAGES_SOCK_NAME "lazy-pages.socket" - -static mutex_t *lazy_sock_mutex; - -struct lazy_iov { - struct list_head l; - unsigned long base; /* run-time start address, tracks remaps */ - unsigned long img_base; /* start address at the dump time */ - unsigned long len; -}; - -struct lp_req { - unsigned long addr; /* actual #PF (or background) destination */ - unsigned long img_addr; /* the corresponding address at the dump time */ - struct list_head l; -}; - -struct lazy_pages_info { - int pid; - - struct list_head iovs; - struct list_head reqs; - - struct lazy_pages_info *parent; - - struct page_read pr; - - unsigned long total_pages; - unsigned long copied_pages; - - struct epoll_rfd lpfd; - - struct list_head l; - - void *buf; -}; - -/* global lazy-pages daemon state */ -static LIST_HEAD(lpis); -static LIST_HEAD(exiting_lpis); -static LIST_HEAD(pending_lpis); -static int epollfd; - -static int handle_uffd_event(struct epoll_rfd *lpfd); - -static struct lazy_pages_info *lpi_init(void) -{ - struct lazy_pages_info *lpi = NULL; - - lpi = xmalloc(sizeof(*lpi)); - if (!lpi) - return NULL; - - memset(lpi, 0, sizeof(*lpi)); - INIT_LIST_HEAD(&lpi->iovs); - INIT_LIST_HEAD(&lpi->reqs); - INIT_LIST_HEAD(&lpi->l); - lpi->lpfd.revent = handle_uffd_event; - - return lpi; -} - -static void free_lazy_iovs(struct lazy_pages_info *lpi) -{ - struct lazy_iov *p, *n; - - list_for_each_entry_safe(p, n, &lpi->iovs, l) { - list_del(&p->l); - xfree(p); - } -} - -static void lpi_fini(struct lazy_pages_info *lpi) -{ - - if (!lpi) - return; - free(lpi->buf); - free_lazy_iovs(lpi); - if (lpi->lpfd.fd > 0) - close(lpi->lpfd.fd); - if (lpi->pr.close) - lpi->pr.close(&lpi->pr); - free(lpi); -} - -static int prepare_sock_addr(struct sockaddr_un *saddr) -{ - int len; - - memset(saddr, 0, sizeof(struct sockaddr_un)); - - saddr->sun_family = AF_UNIX; - len = snprintf(saddr->sun_path, sizeof(saddr->sun_path), - "%s", LAZY_PAGES_SOCK_NAME); - if (len >= sizeof(saddr->sun_path)) { - pr_err("Wrong UNIX socket name: %s\n", LAZY_PAGES_SOCK_NAME); - return -1; - } - - return 0; -} - -static int send_uffd(int sendfd, int pid) -{ - int fd; - int ret = -1; - - if (sendfd < 0) - return -1; - - fd = get_service_fd(LAZY_PAGES_SK_OFF); - if (fd < 0) { - pr_err("%s: get_service_fd\n", __func__); - return -1; - } - - mutex_lock(lazy_sock_mutex); - - /* The "transfer protocol" is first the pid as int and then - * the FD for UFFD */ - pr_debug("Sending PID %d\n", pid); - if (send(fd, &pid, sizeof(pid), 0) < 0) { - pr_perror("PID sending error"); - goto out; - } - - /* for a zombie process pid will be negative */ - if (pid < 0) { - ret = 0; - goto out; - } - - if (send_fd(fd, NULL, 0, sendfd) < 0) { - pr_err("send_fd error\n"); - goto out; - } - - ret = 0; -out: - mutex_unlock(lazy_sock_mutex); - close(fd); - return ret; -} - -int lazy_pages_setup_zombie(int pid) -{ - if (!opts.lazy_pages) - return 0; - - if (send_uffd(0, -pid)) - return -1; - - return 0; -} - -/* This function is used by 'criu restore --lazy-pages' */ -int setup_uffd(int pid, struct task_restore_args *task_args) -{ - struct uffdio_api uffdio_api; - - if (!opts.lazy_pages) { - task_args->uffd = -1; - return 0; - } - - /* - * Open userfaulfd FD which is passed to the restorer blob and - * to a second process handling the userfaultfd page faults. - */ - task_args->uffd = syscall(SYS_userfaultfd, O_CLOEXEC | O_NONBLOCK); - if (task_args->uffd < 0) { - pr_perror("Unable to open an userfaultfd descriptor"); - return -1; - } - - /* - * Check if the UFFD_API is the one which is expected - */ - uffdio_api.api = UFFD_API; - uffdio_api.features = kdat.uffd_features & NEED_UFFD_API_FEATURES; - if (ioctl(task_args->uffd, UFFDIO_API, &uffdio_api)) { - pr_err("Checking for UFFDIO_API failed.\n"); - goto err; - } - if (uffdio_api.api != UFFD_API) { - pr_err("Result of looking up UFFDIO_API does not match: %Lu\n", uffdio_api.api); - goto err; - } - - if (send_uffd(task_args->uffd, pid) < 0) - goto err; - - return 0; -err: - close(task_args->uffd); - return -1; -} - -int prepare_lazy_pages_socket(void) -{ - int fd, new_fd; - int len; - struct sockaddr_un sun; - - if (!opts.lazy_pages) - return 0; - - if (prepare_sock_addr(&sun)) - return -1; - - lazy_sock_mutex = shmalloc(sizeof(*lazy_sock_mutex)); - if (!lazy_sock_mutex) - return -1; - - mutex_init(lazy_sock_mutex); - - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - return -1; - - new_fd = install_service_fd(LAZY_PAGES_SK_OFF, fd); - close(fd); - if (new_fd < 0) - return -1; - - len = offsetof(struct sockaddr_un, sun_path) + strlen(sun.sun_path); - if (connect(new_fd, (struct sockaddr *) &sun, len) < 0) { - pr_perror("connect to %s failed", sun.sun_path); - close(new_fd); - return -1; - } - - return 0; -} - -static int server_listen(struct sockaddr_un *saddr) -{ - int fd; - int len; - - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - return -1; - - unlink(saddr->sun_path); - - len = offsetof(struct sockaddr_un, sun_path) + strlen(saddr->sun_path); - - if (bind(fd, (struct sockaddr *) saddr, len) < 0) { - goto out; - } - - if (listen(fd, 10) < 0) { - goto out; - } - - return fd; - -out: - close(fd); - return -1; -} - -static MmEntry *init_mm_entry(struct lazy_pages_info *lpi) -{ - struct cr_img *img; - MmEntry *mm; - int ret; - - img = open_image(CR_FD_MM, O_RSTR, lpi->pid); - if (!img) - return NULL; - - ret = pb_read_one_eof(img, &mm, PB_MM); - close_image(img); - if (ret == -1) - return NULL; - lp_debug(lpi, "Found %zd VMAs in image\n", mm->n_vmas); - - return mm; -} - -static struct lazy_iov *find_lazy_iov(struct lazy_pages_info *lpi, - unsigned long addr) -{ - struct lazy_iov *iov; - - list_for_each_entry(iov, &lpi->iovs, l) - if (addr >= iov->base && addr < iov->base + iov->len) - return iov; - - return NULL; -} - -static int split_iov(struct lazy_iov *iov, unsigned long addr, bool new_below) -{ - struct lazy_iov *new; - - new = xzalloc(sizeof(*new)); - if (!new) - return -1; - - if (new_below) { - new->base = iov->base; - new->img_base = iov->img_base; - new->len = addr - iov->base; - iov->base = addr; - iov->img_base += new->len; - iov->len -= new->len; - list_add_tail(&new->l, &iov->l); - } else { - new->base = addr; - new->img_base = iov->img_base + addr - iov->base; - new->len = iov->len - (addr - iov->base); - iov->len -= new->len; - list_add(&new->l, &iov->l); - } - - return 0; -} - -static int copy_lazy_iovs(struct lazy_pages_info *src, - struct lazy_pages_info *dst) -{ - struct lazy_iov *iov, *new, *n; - int max_iov_len = 0; - - list_for_each_entry(iov, &src->iovs, l) { - new = xzalloc(sizeof(*new)); - if (!new) - return -1; - - new->base = iov->base; - new->img_base = iov->img_base; - new->len = iov->len; - - list_add_tail(&new->l, &dst->iovs); - - if (new->len > max_iov_len) - max_iov_len = new->len; - } - - if (posix_memalign(&dst->buf, PAGE_SIZE, max_iov_len)) - goto free_iovs; - - return 0; - -free_iovs: - list_for_each_entry_safe(iov, n, &dst->iovs, l) - xfree(iov); - return -1; -} - -/* - * Purge range (addr, addr + len) from lazy_iovs. The range may - * cover several continuous IOVs. - */ -static int drop_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, - int len) -{ - struct lazy_iov *iov, *n; - - list_for_each_entry_safe(iov, n, &lpi->iovs, l) { - unsigned long start = iov->base; - unsigned long end = start + iov->len; - - if (len <= 0 || addr + len < start) - break; - - if (addr >= end) - continue; - - if (addr < start) { - len -= (start - addr); - addr = start; - } - - /* - * The range completely fits into the current IOV. - * If addr equals iov_base we just "drop" the - * beginning of the IOV. Otherwise, we make the IOV to - * end at addr, and add a new IOV start starts at - * addr + len. - */ - if (addr + len < end) { - if (addr == start) { - iov->base += len; - iov->img_base += len; - iov->len -= len; - } else { - if (split_iov(iov, addr + len, false)) - return -1; - iov->len -= len; - } - break; - } - - /* - * The range spawns beyond the end of the current IOV. - * If addr equals iov_base we just "drop" the entire - * IOV. Otherwise, we cut the beginning of the IOV - * and continue to the next one with the updated range - */ - if (addr == start) { - list_del(&iov->l); - xfree(iov); - } else { - iov->len -= (end - addr); - } - - len -= (end - addr); - addr = end; - } - - return 0; -} - -static int remap_lazy_iovs(struct lazy_pages_info *lpi, unsigned long from, - unsigned long to, unsigned long len) -{ - unsigned long off = to - from; - struct lazy_iov *iov, *n, *p; - LIST_HEAD(remaps); - - list_for_each_entry_safe(iov, n, &lpi->iovs, l) { - unsigned long iov_end = iov->base + iov->len; - - if (from > iov_end) - continue; - - if (len <= 0 || from + len < iov->base) - break; - - if (from < iov->base) { - len -= (iov->base - from); - from = iov->base; - } - - if (from > iov->base) - if (split_iov(iov, from, true)) - return -1; - if (from + len < iov_end) - if (split_iov(iov, from + len, false)) - return -1; - - list_safe_reset_next(iov, n, l); - - /* here we have iov->base = from, iov_end <= from + len */ - from = iov_end; - len -= iov->len; - iov->base += off; - list_move_tail(&iov->l, &remaps); - } - - list_for_each_entry_safe(iov, n, &remaps, l) { - list_for_each_entry(p, &lpi->iovs, l) { - if (iov->base < p->base) { - list_move_tail(&iov->l, &p->l); - break; - } - if (list_is_last(&p->l, &lpi->iovs) && - iov->base > p->base) { - list_move(&iov->l, &p->l); - break; - } - } - } - - return 0; -} - -/* - * Create a list of IOVs that can be handled using userfaultfd. The - * IOVs generally correspond to lazy pagemap entries, except the cases - * when a single pagemap entry covers several VMAs. In those cases - * IOVs are split at VMA boundaries because UFFDIO_COPY may be done - * only inside a single VMA. - * We assume here that pagemaps and VMAs are sorted. - */ -static int collect_lazy_iovs(struct lazy_pages_info *lpi) -{ - struct page_read *pr = &lpi->pr; - struct lazy_iov *iov, *n; - MmEntry *mm; - int nr_pages = 0, n_vma = 0, max_iov_len = 0; - int ret = -1; - unsigned long start, end, len; - - mm = init_mm_entry(lpi); - if (!mm) - return -1; - - while (pr->advance(pr)) { - if (!pagemap_lazy(pr->pe)) - continue; - - start = pr->pe->vaddr; - end = start + pr->pe->nr_pages * page_size(); - nr_pages += pr->pe->nr_pages; - - for (; n_vma < mm->n_vmas; n_vma++) { - VmaEntry *vma = mm->vmas[n_vma]; - - if (start >= vma->end) - continue; - - iov = xzalloc(sizeof(*iov)); - if (!iov) - goto free_iovs; - - len = min_t(uint64_t, end, vma->end) - start; - iov->base = start; - iov->img_base = start; - iov->len = len; - list_add_tail(&iov->l, &lpi->iovs); - - if (len > max_iov_len) - max_iov_len = len; - - if (end <= vma->end) - break; - - start = vma->end; - } - } - - if (posix_memalign(&lpi->buf, PAGE_SIZE, max_iov_len)) - goto free_iovs; - - ret = nr_pages; - goto free_mm; - -free_iovs: - list_for_each_entry_safe(iov, n, &lpi->iovs, l) - xfree(iov); -free_mm: - mm_entry__free_unpacked(mm, NULL); - - return ret; -} - -static int uffd_io_complete(struct page_read *pr, unsigned long vaddr, int nr); - -static int ud_open(int client, struct lazy_pages_info **_lpi) -{ - struct lazy_pages_info *lpi; - int ret = -1; - int pr_flags = PR_TASK; - - lpi = lpi_init(); - if (!lpi) - goto out; - - /* The "transfer protocol" is first the pid as int and then - * the FD for UFFD */ - ret = recv(client, &lpi->pid, sizeof(lpi->pid), 0); - if (ret != sizeof(lpi->pid)) { - if (ret < 0) - pr_perror("PID recv error"); - else - pr_err("PID recv: short read\n"); - goto out; - } - - if (lpi->pid < 0) { - pr_debug("Zombie PID: %d\n", lpi->pid); - lpi_fini(lpi); - return 0; - } - - lpi->lpfd.fd = recv_fd(client); - if (lpi->lpfd.fd < 0) { - pr_err("recv_fd error\n"); - goto out; - } - pr_debug("Received PID: %d, uffd: %d\n", lpi->pid, lpi->lpfd.fd); - - if (opts.use_page_server) - pr_flags |= PR_REMOTE; - ret = open_page_read(lpi->pid, &lpi->pr, pr_flags); - if (ret <= 0) { - ret = -1; - goto out; - } - - lpi->pr.io_complete = uffd_io_complete; - - /* - * Find the memory pages belonging to the restored process - * so that it is trackable when all pages have been transferred. - */ - ret = collect_lazy_iovs(lpi); - if (ret < 0) - goto out; - lpi->total_pages = ret; - - lp_debug(lpi, "Found %ld pages to be handled by UFFD\n", lpi->total_pages); - - list_add_tail(&lpi->l, &lpis); - *_lpi = lpi; - - return 0; - -out: - lpi_fini(lpi); - return -1; -} - -static int handle_exit(struct lazy_pages_info *lpi) -{ - lp_debug(lpi, "EXIT\n"); - if (epoll_del_rfd(epollfd, &lpi->lpfd)) - return -1; - free_lazy_iovs(lpi); - close(lpi->lpfd.fd); - - /* keep it for summary */ - list_move_tail(&lpi->l, &lpis); - - return 0; -} - -static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) -{ - struct uffdio_copy uffdio_copy; - unsigned long len = nr_pages * page_size(); - int rc; - - uffdio_copy.dst = address; - uffdio_copy.src = (unsigned long)lpi->buf; - uffdio_copy.len = len; - uffdio_copy.mode = 0; - uffdio_copy.copy = 0; - - lp_debug(lpi, "uffd_copy: 0x%llx/%ld\n", uffdio_copy.dst, len); - rc = ioctl(lpi->lpfd.fd, UFFDIO_COPY, &uffdio_copy); - if (rc) { - if (errno == ENOSPC) { - handle_exit(lpi); - return 0; - } - if (uffdio_copy.copy != -EEXIST) { - lp_debug(lpi, "uffd_copy: rc:%d copy:%Ld, errno:%d\n", - rc, uffdio_copy.copy, errno); - return -1; - } - } else if (uffdio_copy.copy != len) { - lp_err(lpi, "UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy); - return -1; - } - - lpi->copied_pages += nr_pages; - - return 0; -} - -static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long img_addr, int nr) -{ - unsigned long addr = 0; - struct lp_req *req; - - list_for_each_entry(req, &lpi->reqs, l) { - if (req->img_addr == img_addr) { - addr = req->addr; - list_del(&req->l); - xfree(req); - break; - } - } - - BUG_ON(!addr); - - if (uffd_copy(lpi, addr, nr)) - return -1; - - return drop_lazy_iovs(lpi, addr, nr * PAGE_SIZE); -} - -static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr) -{ - struct lazy_pages_info *lpi; - - lpi = container_of(pr, struct lazy_pages_info, pr); - return complete_page_fault(lpi, img_addr, nr); -} - -static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) -{ - struct uffdio_zeropage uffdio_zeropage; - unsigned long len = page_size() * nr_pages; - int rc; - - uffdio_zeropage.range.start = address; - uffdio_zeropage.range.len = len; - uffdio_zeropage.mode = 0; - - lp_debug(lpi, "zero page at 0x%llx\n", address); - rc = ioctl(lpi->lpfd.fd, UFFDIO_ZEROPAGE, &uffdio_zeropage); - if (rc) { - lp_err(lpi, "UFFDIO_ZEROPAGE error %d\n", rc); - return -1; - } - - return 0; -} - -/* - * Seek for the requested address in the pagemap. If it is found, the - * subsequent call to pr->page_read will bring us the data. If the - * address is not found in the pagemap, but no error occured, the - * address should be mapped to zero pfn. - * - * Returns 0 for zero pages, 1 for "real" pages and negative value on - * error - */ -static int uffd_seek_pages(struct lazy_pages_info *lpi, __u64 address, int nr) -{ - int ret; - - lpi->pr.reset(&lpi->pr); - - ret = lpi->pr.seek_pagemap(&lpi->pr, address); - if (!ret) { - lp_err(lpi, "no pagemap covers %llx\n", address); - return ret; - } - - lpi->pr.skip_pages(&lpi->pr, address - lpi->pr.pe->vaddr); - - return 0; -} - -static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr, unsigned flags) -{ - int ret; - - ret = uffd_seek_pages(lpi, address, nr); - if (ret) - return ret; - - ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, flags); - if (ret <= 0) { - lp_err(lpi, "failed reading pages at %llx\n", address); - return ret; - } - - return 0; -} - -static int handle_remaining_pages(struct lazy_pages_info *lpi) -{ - struct lazy_iov *iov; - struct lp_req *req; - int nr_pages, err; - - iov = list_first_entry(&lpi->iovs, struct lazy_iov, l); - nr_pages = iov->len / PAGE_SIZE; - - req = xzalloc(sizeof(*req)); - if (!req) - return -1; - - req->addr = iov->base; - req->img_addr = iov->img_base; - list_add(&req->l, &lpi->reqs); - - err = uffd_handle_pages(lpi, req->img_addr, nr_pages, 0); - if (err < 0) { - lp_err(lpi, "Error during UFFD copy\n"); - return -1; - } - - return 0; -} - -static int handle_remove(struct lazy_pages_info *lpi, struct uffd_msg *msg) -{ - struct uffdio_range unreg; - - unreg.start = msg->arg.remove.start; - unreg.len = msg->arg.remove.end - msg->arg.remove.start; - - lp_debug(lpi, "%s: %Lx(%Lx)\n", - msg->event == UFFD_EVENT_REMOVE ? "REMOVE" : "UNMAP", - unreg.start, unreg.len); - - /* - * The REMOVE event does not change the VMA, so we need to - * make sure that we won't handle #PFs in the removed - * range. With UNMAP, there's no VMA to worry about - */ - if (msg->event == UFFD_EVENT_REMOVE && - ioctl(lpi->lpfd.fd, UFFDIO_UNREGISTER, &unreg)) { - pr_perror("Failed to unregister (%llx - %llx)", unreg.start, - unreg.start + unreg.len); - return -1; - } - - return drop_lazy_iovs(lpi, unreg.start, unreg.len); -} - -static int handle_remap(struct lazy_pages_info *lpi, struct uffd_msg *msg) -{ - unsigned long from = msg->arg.remap.from; - unsigned long to = msg->arg.remap.to; - unsigned long len = msg->arg.remap.len; - - lp_debug(lpi, "REMAP: %lx -> %lx (%ld)\n", from , to, len); - - return remap_lazy_iovs(lpi, from, to, len); -} - -static int handle_fork(struct lazy_pages_info *parent_lpi, struct uffd_msg *msg) -{ - struct lazy_pages_info *lpi; - int uffd = msg->arg.fork.ufd; - - lp_debug(parent_lpi, "FORK: child with ufd=%d\n", uffd); - - lpi = lpi_init(); - if (!lpi) - return -1; - - if (copy_lazy_iovs(parent_lpi, lpi)) - goto out; - - lpi->pid = parent_lpi->pid; - lpi->lpfd.fd = uffd; - lpi->parent = parent_lpi->parent ? parent_lpi->parent : parent_lpi; - lpi->copied_pages = lpi->parent->copied_pages; - lpi->total_pages = lpi->parent->total_pages; - list_add_tail(&lpi->l, &pending_lpis); - - dup_page_read(&lpi->parent->pr, &lpi->pr); - - return 1; - -out: - lpi_fini(lpi); - return -1; -} - -static int complete_forks(int epollfd, struct epoll_event **events, int *nr_fds) -{ - struct lazy_pages_info *lpi, *n; - - list_for_each_entry(lpi, &pending_lpis, l) - (*nr_fds)++; - - *events = xrealloc(*events, sizeof(struct epoll_event) * (*nr_fds)); - if (!*events) - return -1; - - list_for_each_entry_safe(lpi, n, &pending_lpis, l) { - if (epoll_add_rfd(epollfd, &lpi->lpfd)) - return -1; - - list_del_init(&lpi->l); - list_add_tail(&lpi->l, &lpis); - } - - return 0; -} - -static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) -{ - struct lp_req *req; - struct lazy_iov *iov; - __u64 address; - int ret; - - /* Align requested address to the next page boundary */ - address = msg->arg.pagefault.address & ~(page_size() - 1); - lp_debug(lpi, "#PF at 0x%llx\n", address); - - list_for_each_entry(req, &lpi->reqs, l) - if (req->addr == address) - return 0; - - iov = find_lazy_iov(lpi, address); - if (!iov) - return uffd_zero(lpi, address, 1); - - req = xzalloc(sizeof(*req)); - if (!req) - return -1; - req->addr = address; - req->img_addr = iov->img_base + (address - iov->base); - list_add(&req->l, &lpi->reqs); - - ret = uffd_handle_pages(lpi, req->img_addr, 1, PR_ASYNC | PR_ASAP); - if (ret < 0) { - lp_err(lpi, "Error during regular page copy\n"); - return -1; - } - - return 0; -} - -static int handle_uffd_event(struct epoll_rfd *lpfd) -{ - struct lazy_pages_info *lpi; - struct uffd_msg msg; - int ret; - - lpi = container_of(lpfd, struct lazy_pages_info, lpfd); - - ret = read(lpfd->fd, &msg, sizeof(msg)); - if (!ret) - return 1; - - if (ret != sizeof(msg)) { - /* we've already handled the page fault for another thread */ - if (errno == EAGAIN) - return 0; - if (ret < 0) - lp_perror(lpi, "Can't read uffd message"); - else - lp_err(lpi, "Can't read uffd message: short read"); - return -1; - } - - switch (msg.event) { - case UFFD_EVENT_PAGEFAULT: - return handle_page_fault(lpi, &msg); - case UFFD_EVENT_REMOVE: - case UFFD_EVENT_UNMAP: - return handle_remove(lpi, &msg); - case UFFD_EVENT_REMAP: - return handle_remap(lpi, &msg); - case UFFD_EVENT_FORK: - return handle_fork(lpi, &msg); - default: - lp_err(lpi, "unexpected uffd event %u\n", msg.event); - return -1; - } - - return 0; -} - -static int lazy_pages_summary(struct lazy_pages_info *lpi) -{ - lp_debug(lpi, "UFFD transferred pages: (%ld/%ld)\n", - lpi->copied_pages, lpi->total_pages); - -#if 0 - if ((lpi->copied_pages != lpi->total_pages) && (lpi->total_pages > 0)) { - lp_warn(lpi, "Only %ld of %ld pages transferred via UFFD\n" - "Something probably went wrong.\n", - lpi->copied_pages, lpi->total_pages); - return 1; - } -#endif - - return 0; -} - -#define POLL_TIMEOUT 1000 - -static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) -{ - struct lazy_pages_info *lpi; - int poll_timeout = POLL_TIMEOUT; - int ret; - - for (;;) { - bool remaining = false; - - ret = epoll_run_rfds(epollfd, events, nr_fds, poll_timeout); - if (ret < 0) - goto out; - if (ret > 0) { - if (complete_forks(epollfd, &events, &nr_fds)) - return -1; - continue; - } - - if (poll_timeout) - pr_debug("Start handling remaining pages\n"); - - poll_timeout = 0; - list_for_each_entry(lpi, &lpis, l) { - if (!list_empty(&lpi->iovs)) { - remaining = true; - ret = handle_remaining_pages(lpi); - if (ret < 0) - goto out; - break; - } - } - - if (!remaining) - break; - } - - list_for_each_entry(lpi, &lpis, l) - ret += lazy_pages_summary(lpi); - -out: - return ret; - -} - -static int prepare_lazy_socket(void) -{ - int listen; - struct sockaddr_un saddr; - - if (prepare_sock_addr(&saddr)) - return -1; - - pr_debug("Waiting for incoming connections on %s\n", saddr.sun_path); - if ((listen = server_listen(&saddr)) < 0) { - pr_perror("server_listen error"); - return -1; - } - - return listen; -} - -static int prepare_uffds(int listen, int epollfd) -{ - int i; - int client; - socklen_t len; - struct sockaddr_un saddr; - - /* accept new client request */ - len = sizeof(struct sockaddr_un); - if ((client = accept(listen, (struct sockaddr *) &saddr, &len)) < 0) { - pr_perror("server_accept error"); - close(listen); - return -1; - } - - for (i = 0; i < task_entries->nr_tasks; i++) { - struct lazy_pages_info *lpi = NULL; - if (ud_open(client, &lpi)) - goto close_uffd; - if (lpi == NULL) - continue; - if (epoll_add_rfd(epollfd, &lpi->lpfd)) - goto close_uffd; - } - - close_safe(&client); - close(listen); - return 0; - -close_uffd: - close_safe(&client); - close(listen); - return -1; -} - -int cr_lazy_pages(bool daemon) -{ - struct epoll_event *events; - int nr_fds; - int lazy_sk; - int ret; - - if (kerndat_uffd() || !kdat.has_uffd) - return -1; - - if (prepare_dummy_pstree()) - return -1; - - lazy_sk = prepare_lazy_socket(); - if (lazy_sk < 0) - return -1; - - if (daemon) { - ret = cr_daemon(1, 0, &lazy_sk, -1); - if (ret == -1) { - pr_err("Can't run in the background\n"); - return -1; - } - if (ret > 0) { /* parent task, daemon started */ - if (opts.pidfile) { - if (write_pidfile(ret) == -1) { - pr_perror("Can't write pidfile"); - kill(ret, SIGKILL); - waitpid(ret, NULL, 0); - return -1; - } - } - - return 0; - } - } - - if (close_status_fd()) - return -1; - - nr_fds = task_entries->nr_tasks + (opts.use_page_server ? 1 : 0); - epollfd = epoll_prepare(nr_fds, &events); - if (epollfd < 0) - return -1; - - if (prepare_uffds(lazy_sk, epollfd)) - return -1; - - if (opts.use_page_server) { - if (connect_to_page_server_to_recv(epollfd)) - return -1; - } - - ret = handle_requests(epollfd, events, nr_fds); - - return ret; -} From 12e3adc68c8fa91687deb109faacf217c9136afe Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 22 May 2017 11:40:37 +0300 Subject: [PATCH 0558/4375] criu: Version 3.1 Signed-off-by: Pavel Emelyanov --- Makefile.versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index 1e7d1887b..a2526390d 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 0 +CRIU_VERSION_MINOR := 1 CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Basalt Wagtail +CRIU_VERSION_NAME := Graphene Swift CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From 2a6b8e174388036c69cce4ca64f9ca87d36866ef Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 17 May 2017 12:32:40 -0700 Subject: [PATCH 0559/4375] travis-tests: install less packages asciidoc pulls in a lot of dependencies, most of those are not needed as we just use it to convert txt to a man page. Adding --no-install-recommended option to apt-get makes it skip those additional dependencies. The only needed package is xmlto, so let's add it explicitly. This results is some 50 packages being skipped (mostly TeX/LaTeX and some extra SGML tools), wow! Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 37e418abc..c3025285e 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -4,7 +4,7 @@ set -x -e TRAVIS_PKGS="protobuf-c-compiler libprotobuf-c0-dev libaio-dev libprotobuf-dev protobuf-compiler python-ipaddr libcap-dev libnl-3-dev gcc-multilib libc6-dev-i386 gdb bash python-protobuf - libnet-dev util-linux asciidoc" + libnet-dev util-linux asciidoc xmlto" travis_prep () { [ -n "$SKIP_TRAVIS_PREP" ] && return @@ -31,7 +31,7 @@ travis_prep () { fi apt-get update -qq - apt-get install -qq $TRAVIS_PKGS + apt-get install -qq --no-install-recommends $TRAVIS_PKGS chmod a+x $HOME } From 88699b49f7cc13938cd104f1861079d59fd6b915 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 17 May 2017 12:32:41 -0700 Subject: [PATCH 0560/4375] travis-tests: set CRIU_PMC_OFF conditionally We only needed it for kernel 3.19. Apparently, Ubuntu 14.04.5 comes with a kernel from 16.04 (i.e. 4.4), so we can disable this workaround! Anyway, just in case, let's do it conditionally. While at it, slightly improve the comment. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index c3025285e..c50f0139c 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -53,10 +53,11 @@ time make CC="$CC" -j4 -C test/zdtm umask 0000 export SKIP_PREP=1 -# The 3.19 Ubuntu kernel has a bug. When pagemap are read for a few vma-s -# for one read call, it returns incorrect data. -# https://github.com/xemul/criu/issues/207 -export CRIU_PMC_OFF=1 +# The 3.19 kernel (from Ubuntu 14.04) has a bug. When /proc/PID/pagemap +# is read for a few VMAs in one read call, incorrect data is returned. +# See https://github.com/xemul/criu/issues/207 +# Kernel 4.4 (from Ubuntu 14.04.5 update) fixes this. +uname -r | grep -q ^3\.19 && export CRIU_PMC_OFF=1 chmod 0777 test/ chmod 0777 test/zdtm/static From 4bd43e226f6bf91f099aed150340a831c54f282c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 15 May 2017 17:01:16 +0300 Subject: [PATCH 0561/4375] fsnotify: Fix legacy fanotify collect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wrong helper is called. ✓ travis-ci: success for Sanitize fsnotify legacy code Signed-off-by: Pavel Emelyanov --- criu/fsnotify.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 6bc840c98..6375bcb2d 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -828,7 +828,7 @@ static int collect_fanotify_mark(struct fsnotify_mark_info *mark) list_for_each_entry(p, &fanotify_info_head, list) { if (p->ffe->id == mark->fme->id) - return __collect_inotify_mark(p, mark); + return __collect_fanotify_mark(p, mark); } pr_err("Can't find fanotify with id %#08x\n", mark->fme->id); From 80f84ab0a40ec986ef2f49897c3b0a4095d439e4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 15 May 2017 17:01:32 +0300 Subject: [PATCH 0562/4375] fsnotify: Deprecate separate images for marks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marks images were merged into regular in 1.3. ✓ travis-ci: success for Sanitize fsnotify legacy code Signed-off-by: Pavel Emelyanov --- criu/fsnotify.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 6375bcb2d..b0ca9d29c 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -30,6 +30,7 @@ #include "filesystems.h" #include "image.h" #include "util.h" +#include "crtools.h" #include "files.h" #include "files-reg.h" #include "file-ids.h" @@ -909,6 +910,9 @@ static int collect_one_inotify_mark(void *o, ProtobufCMessage *msg, struct cr_im { struct fsnotify_mark_info *mark = o; + if (!deprecated_ok("separate images for fsnotify marks")) + return -1; + mark->iwe = pb_msg(msg, InotifyWdEntry); INIT_LIST_HEAD(&mark->list); mark->remap = NULL; @@ -937,6 +941,9 @@ static int collect_one_fanotify_mark(void *o, ProtobufCMessage *msg, struct cr_i { struct fsnotify_mark_info *mark = o; + if (!deprecated_ok("separate images for fsnotify marks")) + return -1; + mark->fme = pb_msg(msg, FanotifyMarkEntry); INIT_LIST_HEAD(&mark->list); mark->remap = NULL; From d965f5887d26a0031bcd3fd44af403df678a1e0a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 15 May 2017 17:01:47 +0300 Subject: [PATCH 0563/4375] fsnotify: Kill fsnotify lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lists are only needed to collect marks (deprecated) into notify objects. The latter ones are stored in fdsec hash, so for this legacy case we can find them there. ✓ travis-ci: success for Sanitize fsnotify legacy code Signed-off-by: Pavel Emelyanov --- criu/fsnotify.c | 51 ++++++++++--------------------------------------- 1 file changed, 10 insertions(+), 41 deletions(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index b0ca9d29c..00a26cf6e 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -61,7 +61,6 @@ struct fsnotify_mark_info { }; struct fsnotify_file_info { - struct list_head list; union { InotifyFileEntry *ife; FanotifyFileEntry *ffe; @@ -77,9 +76,6 @@ typedef struct { u64 __handle[16]; } fh_t; -static LIST_HEAD(inotify_info_head); -static LIST_HEAD(fanotify_info_head); - /* Checks if file descriptor @lfd is inotify */ int is_inotify_link(char *link) { @@ -760,31 +756,6 @@ static struct file_desc_ops fanotify_desc_ops = { .open = open_fanotify_fd, }; -static struct fsnotify_file_info *find_inotify_info(unsigned id) -{ - struct fsnotify_file_info *p; - static struct fsnotify_file_info *last = NULL; - - if (last && last->ife->id == id) { - /* - * An optimization for clean dump image -- criu puts - * wd-s for one inotify in one row, thus sometimes - * we can avoid scanning the inotify_info_head. - */ - pr_debug("\t\tlast ify for %#08x found\n", id); - return last; - } - - list_for_each_entry(p, &inotify_info_head, list) - if (p->ife->id == id) { - last = p; - return p; - } - - pr_err("Can't find inotify with id %#08x\n", id); - return NULL; -} - static int __collect_inotify_mark(struct fsnotify_file_info *p, struct fsnotify_mark_info *mark) { struct fsnotify_mark_info *m; @@ -804,13 +775,14 @@ static int __collect_inotify_mark(struct fsnotify_file_info *p, struct fsnotify_ static int collect_inotify_mark(struct fsnotify_mark_info *mark) { - struct fsnotify_file_info *p; + struct file_desc *d; - p = find_inotify_info(mark->iwe->id); - if (!p) - return -1; + d = find_file_desc_raw(FD_TYPES__INOTIFY, mark->iwe->id); + if (d) + return __collect_inotify_mark(container_of(d, struct fsnotify_file_info, d), mark); - return __collect_inotify_mark(p, mark); + pr_err("Can't find inotify with id %#08x\n", mark->iwe->id); + return -1; } static int __collect_fanotify_mark(struct fsnotify_file_info *p, @@ -825,12 +797,11 @@ static int __collect_fanotify_mark(struct fsnotify_file_info *p, static int collect_fanotify_mark(struct fsnotify_mark_info *mark) { - struct fsnotify_file_info *p; + struct file_desc *d; - list_for_each_entry(p, &fanotify_info_head, list) { - if (p->ffe->id == mark->fme->id) - return __collect_fanotify_mark(p, mark); - } + d = find_file_desc_raw(FD_TYPES__FANOTIFY, mark->fme->id); + if (d) + return __collect_fanotify_mark(container_of(d, struct fsnotify_file_info, d), mark); pr_err("Can't find fanotify with id %#08x\n", mark->fme->id); return -1; @@ -843,7 +814,6 @@ static int collect_one_inotify(void *o, ProtobufCMessage *msg, struct cr_img *im info->ife = pb_msg(msg, InotifyFileEntry); INIT_LIST_HEAD(&info->marks); - list_add(&info->list, &inotify_info_head); pr_info("Collected id %#08x flags %#08x\n", info->ife->id, info->ife->flags); for (i = 0; i < info->ife->n_wd; i++) { @@ -878,7 +848,6 @@ static int collect_one_fanotify(void *o, ProtobufCMessage *msg, struct cr_img *i info->ffe = pb_msg(msg, FanotifyFileEntry); INIT_LIST_HEAD(&info->marks); - list_add(&info->list, &fanotify_info_head); pr_info("Collected id %#08x flags %#08x\n", info->ffe->id, info->ffe->flags); for (i = 0; i < info->ffe->n_mark; i++) { From 30e2fd2175a2cca027f3deb9e3841450ebac0852 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 15 May 2017 17:02:03 +0300 Subject: [PATCH 0564/4375] fsnotify: Tossing legacy bits around MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This just moves all the deprecated code into one place. ✓ travis-ci: success for Sanitize fsnotify legacy code Signed-off-by: Pavel Emelyanov --- criu/fsnotify.c | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 00a26cf6e..e3d62e54a 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -773,18 +773,6 @@ static int __collect_inotify_mark(struct fsnotify_file_info *p, struct fsnotify_ return 0; } -static int collect_inotify_mark(struct fsnotify_mark_info *mark) -{ - struct file_desc *d; - - d = find_file_desc_raw(FD_TYPES__INOTIFY, mark->iwe->id); - if (d) - return __collect_inotify_mark(container_of(d, struct fsnotify_file_info, d), mark); - - pr_err("Can't find inotify with id %#08x\n", mark->iwe->id); - return -1; -} - static int __collect_fanotify_mark(struct fsnotify_file_info *p, struct fsnotify_mark_info *mark) { @@ -795,18 +783,6 @@ static int __collect_fanotify_mark(struct fsnotify_file_info *p, return 0; } -static int collect_fanotify_mark(struct fsnotify_mark_info *mark) -{ - struct file_desc *d; - - d = find_file_desc_raw(FD_TYPES__FANOTIFY, mark->fme->id); - if (d) - return __collect_fanotify_mark(container_of(d, struct fsnotify_file_info, d), mark); - - pr_err("Can't find fanotify with id %#08x\n", mark->fme->id); - return -1; -} - static int collect_one_inotify(void *o, ProtobufCMessage *msg, struct cr_img *img) { struct fsnotify_file_info *info = o; @@ -878,6 +854,7 @@ struct collect_image_info fanotify_cinfo = { static int collect_one_inotify_mark(void *o, ProtobufCMessage *msg, struct cr_img *i) { struct fsnotify_mark_info *mark = o; + struct file_desc *d; if (!deprecated_ok("separate images for fsnotify marks")) return -1; @@ -896,7 +873,13 @@ static int collect_one_inotify_mark(void *o, ProtobufCMessage *msg, struct cr_im */ mark->iwe->mask &= ~KERNEL_FS_EVENT_ON_CHILD; - return collect_inotify_mark(mark); + d = find_file_desc_raw(FD_TYPES__INOTIFY, mark->iwe->id); + if (!d) { + pr_err("Can't find inotify with id %#08x\n", mark->iwe->id); + return -1; + } + + return __collect_inotify_mark(container_of(d, struct fsnotify_file_info, d), mark); } struct collect_image_info inotify_mark_cinfo = { @@ -909,6 +892,7 @@ struct collect_image_info inotify_mark_cinfo = { static int collect_one_fanotify_mark(void *o, ProtobufCMessage *msg, struct cr_img *i) { struct fsnotify_mark_info *mark = o; + struct file_desc *d; if (!deprecated_ok("separate images for fsnotify marks")) return -1; @@ -917,7 +901,13 @@ static int collect_one_fanotify_mark(void *o, ProtobufCMessage *msg, struct cr_i INIT_LIST_HEAD(&mark->list); mark->remap = NULL; - return collect_fanotify_mark(mark); + d = find_file_desc_raw(FD_TYPES__FANOTIFY, mark->fme->id); + if (!d) { + pr_err("Can't find fanotify with id %#08x\n", mark->fme->id); + return -1; + } + + return __collect_fanotify_mark(container_of(d, struct fsnotify_file_info, d), mark); } struct collect_image_info fanotify_mark_cinfo = { From b01bd93757b78b10c293edef1ab90c1d9d445e6a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 18 May 2017 12:35:19 +0300 Subject: [PATCH 0565/4375] rst: Collect procfs remaps at once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no need in separate call to prepare_procfs_remaps(). All remaps are collected one step earlier and we can do open_remap_dead_process() right at once. Also rename the latter routine. ✓ travis-ci: success for Sanitize initialization bits Signed-off-by: Pavel Emelyanov --- criu/cr-restore.c | 5 ----- criu/files-reg.c | 42 +++++++++++++--------------------------- criu/include/files-reg.h | 1 - 3 files changed, 13 insertions(+), 35 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 1fb7a9243..d29dfa40d 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -229,11 +229,6 @@ static int crtools_prepare_shared(void) if (collect_remaps_and_regfiles()) return -1; - /* dead pid remap needs to allocate task helpers which all tasks need - * to see */ - if (prepare_procfs_remaps()) - return -1; - /* Connections are unlocked from criu */ if (collect_inet_sockets()) return -1; diff --git a/criu/files-reg.c b/criu/files-reg.c index 451427589..b0ac71f86 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -374,7 +374,7 @@ static int open_remap_linked(struct reg_file_info *rfi, return 0; } -static int open_remap_dead_process(struct reg_file_info *rfi, +static int collect_remap_dead_process(struct reg_file_info *rfi, RemapFilePathEntry *rfe) { struct pstree_item *helper; @@ -434,12 +434,21 @@ static int collect_one_remap(void *obj, ProtobufCMessage *msg, struct cr_img *i) ri->rfi = container_of(fdesc, struct reg_file_info, d); - if (rfe->remap_type == REMAP_TYPE__GHOST) { + switch (rfe->remap_type) { + case REMAP_TYPE__GHOST: if (collect_remap_ghost(ri->rfi, ri->rfe)) return -1; - } else if (rfe->remap_type == REMAP_TYPE__LINKED) { + break; + case REMAP_TYPE__LINKED: if (collect_remap_linked(ri->rfi, ri->rfe)) return -1; + break; + case REMAP_TYPE__PROCFS: + if (collect_remap_dead_process(ri->rfi, rfe) < 0) + return -1; + break; + default: + break; } list_add_tail(&ri->list, &remaps); @@ -463,7 +472,7 @@ static int prepare_one_remap(struct remap_info *ri) ret = open_remap_ghost(rfi, rfe); break; case REMAP_TYPE__PROCFS: - /* handled earlier by prepare_procfs_remaps */ + /* handled earlier by collect_remap_dead_process */ ret = 0; break; default: @@ -475,31 +484,6 @@ out: return ret; } -/* We separate the preparation of PROCFS remaps because they allocate pstree - * items, which need to be seen by the root task. We can't do all remaps here, - * because the files haven't been loaded yet. - */ -int prepare_procfs_remaps(void) -{ - struct remap_info *ri; - - list_for_each_entry(ri, &remaps, list) { - RemapFilePathEntry *rfe = ri->rfe; - struct reg_file_info *rfi = ri->rfi; - - switch (rfe->remap_type) { - case REMAP_TYPE__PROCFS: - if (open_remap_dead_process(rfi, rfe) < 0) - return -1; - break; - default: - continue; - } - } - - return 0; -} - int prepare_remaps(void) { struct remap_info *ri; diff --git a/criu/include/files-reg.h b/criu/include/files-reg.h index 5a6c69132..ba2ad6c81 100644 --- a/criu/include/files-reg.h +++ b/criu/include/files-reg.h @@ -53,7 +53,6 @@ extern int try_clean_remaps(bool only_ghosts); extern int strip_deleted(struct fd_link *link); -extern int prepare_procfs_remaps(void); extern int dead_pid_conflict(void); #endif /* __CR_FILES_REG_H__ */ From 2356e5ffc6e03c5edd481f098880169976c4163e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 18 May 2017 12:35:34 +0300 Subject: [PATCH 0566/4375] regfiles: Do not serialize remap lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We used to have users counter on remap which was incremented each time this routine was called. Nowadays remaps are managed w/o the refcounting and we no longer need global mutex protection for it. ✓ travis-ci: success for Sanitize initialization bits Signed-off-by: Pavel Emelyanov --- criu/files-reg.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index b0ac71f86..9c0a0a22f 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -623,14 +623,11 @@ struct file_remap *lookup_ghost_remap(u32 dev, u32 ino) { struct ghost_file *gf; - mutex_lock(ghost_file_mutex); list_for_each_entry(gf, &ghost_files, list) { if (gf->ino == ino && (gf->dev == dev)) { - mutex_unlock(ghost_file_mutex); return &gf->remap; } } - mutex_unlock(ghost_file_mutex); return NULL; } From 23e092f7090820d02b2ca2de1b0b83376a00548a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 18 May 2017 12:35:48 +0300 Subject: [PATCH 0567/4375] ghosts: Add comment about shared path allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ghost remaps allocate path with shmalloc. Add comment why this is such. ✓ travis-ci: success for Sanitize initialization bits Signed-off-by: Pavel Emelyanov --- criu/files-reg.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/criu/files-reg.c b/criu/files-reg.c index 9c0a0a22f..3d03cd5e9 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -259,6 +259,13 @@ static int collect_remap_ghost(struct reg_file_info *rfi, if (!gf) return -1; + /* + * The rpath is shmalloc-ed because we create the ghost + * file in root task context and generate its path there. + * However the path should be visible by the criu task + * in order to remove the ghost files from root FS (see + * try_clean_remaps()). + */ gf->remap.rpath = shmalloc(PATH_MAX); if (!gf->remap.rpath) return -1; From a534c76c42e951af33d7ca4e2bc8566e1aa6819b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 18 May 2017 12:36:03 +0300 Subject: [PATCH 0568/4375] remaps: Rename clean_linked_remap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This routine cleans any file remap. ✓ travis-ci: success for Sanitize initialization bits Signed-off-by: Pavel Emelyanov --- criu/files-reg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 3d03cd5e9..185e00998 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -505,7 +505,7 @@ int prepare_remaps(void) return ret; } -static int clean_linked_remap(struct remap_info *ri) +static int clean_one_remap(struct remap_info *ri) { char path[PATH_MAX]; int mnt_id, ret, rmntns_root; @@ -550,11 +550,11 @@ int try_clean_remaps(bool only_ghosts) list_for_each_entry(ri, &remaps, list) { if (ri->rfe->remap_type == REMAP_TYPE__GHOST) - ret |= clean_linked_remap(ri); + ret |= clean_one_remap(ri); else if (only_ghosts) continue; else if (ri->rfe->remap_type == REMAP_TYPE__LINKED) - ret |= clean_linked_remap(ri); + ret |= clean_one_remap(ri); } return ret; From 237bd26982a1e3f2a80fd8d5bd323c8d99359c3a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 18 May 2017 12:36:18 +0300 Subject: [PATCH 0569/4375] remap: Rename global lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now this lock is only needed to serialize remap open code, so name it such. ✓ travis-ci: success for Sanitize initialization bits Signed-off-by: Pavel Emelyanov --- criu/files-reg.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 185e00998..c6ae19f30 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -59,7 +59,13 @@ struct ghost_file { static u32 ghost_file_ids = 1; static LIST_HEAD(ghost_files); -static mutex_t *ghost_file_mutex; +/* + * When opening remaps we first create a link on the remap + * target, then open one, then unlink. In case the remap + * source has more than one instance, these tree steps + * should be serialized with each other. + */ +static mutex_t *remap_open_lock; static LIST_HEAD(remaps); @@ -1446,7 +1452,7 @@ int open_path(struct file_desc *d, BUG(); } - mutex_lock(ghost_file_mutex); + mutex_lock(remap_open_lock); if (rfi->remap->is_dir) { /* * FIXME Can't make directory under new name. @@ -1532,7 +1538,7 @@ ext: rm_parent_dirs(mntns_root, rfi->path, level); } - mutex_unlock(ghost_file_mutex); + mutex_unlock(remap_open_lock); } if (orig_path) rfi->path = orig_path; @@ -1719,11 +1725,11 @@ static struct collect_image_info reg_file_cinfo = { int prepare_shared_reg_files(void) { - ghost_file_mutex = shmalloc(sizeof(*ghost_file_mutex)); - if (!ghost_file_mutex) + remap_open_lock = shmalloc(sizeof(*remap_open_lock)); + if (!remap_open_lock) return -1; - mutex_init(ghost_file_mutex); + mutex_init(remap_open_lock); return 0; } From 77443aa5205b8fa0ec5d7b3acf6541e89e06535f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 18 May 2017 12:36:32 +0300 Subject: [PATCH 0570/4375] regfiles: Kill prepare_shared_reg_files() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This routine just initializes the remap open lock, and there's already the code that initializes the whole remap engine. Re-arrange this part. ✓ travis-ci: success for Sanitize initialization bits Signed-off-by: Pavel Emelyanov --- criu/cr-restore.c | 3 --- criu/files-reg.c | 24 ++++++++++++++---------- criu/include/files-reg.h | 2 -- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index d29dfa40d..d6d0b5683 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -325,9 +325,6 @@ static int root_prepare_shared(void) pr_info("Preparing info about shared resources\n"); - if (prepare_shared_reg_files()) - return -1; - if (prepare_remaps()) return -1; diff --git a/criu/files-reg.c b/criu/files-reg.c index c6ae19f30..506aedf97 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -67,6 +67,16 @@ static LIST_HEAD(ghost_files); */ static mutex_t *remap_open_lock; +static inline int init_remap_lock(void) +{ + remap_open_lock = shmalloc(sizeof(*remap_open_lock)); + if (!remap_open_lock) + return -1; + + mutex_init(remap_open_lock); + return 0; +} + static LIST_HEAD(remaps); /* @@ -502,6 +512,10 @@ int prepare_remaps(void) struct remap_info *ri; int ret = 0; + ret = init_remap_lock(); + if (ret) + return ret; + list_for_each_entry(ri, &remaps, list) { ret = prepare_one_remap(ri); if (ret) @@ -1723,16 +1737,6 @@ static struct collect_image_info reg_file_cinfo = { .flags = COLLECT_SHARED, }; -int prepare_shared_reg_files(void) -{ - remap_open_lock = shmalloc(sizeof(*remap_open_lock)); - if (!remap_open_lock) - return -1; - - mutex_init(remap_open_lock); - return 0; -} - int collect_remaps_and_regfiles(void) { if (collect_image(®_file_cinfo)) diff --git a/criu/include/files-reg.h b/criu/include/files-reg.h index ba2ad6c81..c205da7f1 100644 --- a/criu/include/files-reg.h +++ b/criu/include/files-reg.h @@ -32,8 +32,6 @@ extern int open_path(struct file_desc *, int (*open_cb)(int ns_root_fd, struct reg_file_info *, void *), void *arg); extern void clear_ghost_files(void); -extern int prepare_shared_reg_files(void); - extern const struct fdtype_ops regfile_dump_ops; extern int do_open_reg_noseek_flags(int ns_root_fd, struct reg_file_info *rfi, void *arg); extern int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p); From a216fb1e5ea39c64b7d0fc8f4486634ffe2f139b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 18 May 2017 12:36:45 +0300 Subject: [PATCH 0571/4375] tty: Merge tty post actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to schedule both post-actions, we can merge them. This also sanitizes the "void *unised" arguments for both. ✓ travis-ci: success for Sanitize initialization bits Signed-off-by: Pavel Emelyanov --- criu/tty.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/criu/tty.c b/criu/tty.c index 51516c731..de4195ab6 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -372,7 +372,7 @@ static int tty_get_index(u32 id) } /* Make sure the active pairs do exist */ -static int tty_verify_active_pairs(void * unused) +static int tty_verify_active_pairs(void) { unsigned long i, unpaired_slaves = 0; @@ -1360,7 +1360,7 @@ static int tty_setup_orphan_slavery(void) return 0; } -static int tty_setup_slavery(void * unused) +static int tty_setup_slavery(void) { struct tty_info *info, *peer, *m; @@ -1556,6 +1556,15 @@ struct collect_image_info tty_info_cinfo = { .collect = collect_one_tty_info_entry, }; +static int prep_tty_restore(void *unused) +{ + if (tty_verify_active_pairs()) + return -1; + if (tty_setup_slavery()) + return -1; + return 0; +} + static int collect_one_tty(void *obj, ProtobufCMessage *msg, struct cr_img *i) { struct tty_info *info = obj; @@ -1626,8 +1635,7 @@ static int collect_one_tty(void *obj, ProtobufCMessage *msg, struct cr_img *i) pr_info("Collected tty ID %#x (%s)\n", info->tfe->id, info->driver->name); - if (add_post_prepare_cb_once(tty_verify_active_pairs, NULL) || - add_post_prepare_cb_once(tty_setup_slavery, NULL)) + if (add_post_prepare_cb_once(prep_tty_restore, NULL)) return -1; info->fdstore_id = -1; @@ -2152,7 +2160,7 @@ int tty_post_actions(void) { if (tty_verify_ctty()) return -1; - if (tty_verify_active_pairs(NULL)) + if (tty_verify_active_pairs()) return -1; else if (tty_dump_queued_data()) return -1; From 7ce496eb10e6e55478dca3ebaa7eec6fa2c9646d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 18 May 2017 12:37:01 +0300 Subject: [PATCH 0572/4375] tty: Kill prepare_shared_tty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The routine in question just sets up the mutex to access /dev/ptmx. This initialization can be done when we collect a single tty. ✓ travis-ci: success for Sanitize initialization bits Signed-off-by: Pavel Emelyanov --- criu/cr-restore.c | 4 +--- criu/include/tty.h | 1 - criu/tty.c | 12 +++++++++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index d6d0b5683..48007d06d 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1505,11 +1505,9 @@ static int restore_task_with_children(void *_arg) if (current->parent == NULL) { int i; - if (prepare_shared_tty()) - goto err; - if (fdstore_init()) goto err; + if (join_namespaces()) { pr_perror("Join namespaces failed"); goto err; diff --git a/criu/include/tty.h b/criu/include/tty.h index 5ad8b0987..5550a72c4 100644 --- a/criu/include/tty.h +++ b/criu/include/tty.h @@ -27,7 +27,6 @@ extern int dump_verify_tty_sids(void); extern struct collect_image_info tty_info_cinfo; extern struct collect_image_info tty_cinfo; extern struct collect_image_info tty_cdata; -extern int prepare_shared_tty(void); struct mount_info; extern int devpts_restore(struct mount_info *pm); diff --git a/criu/tty.c b/criu/tty.c index de4195ab6..585e9ceab 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -326,8 +326,11 @@ static mutex_t *tty_mutex; static bool tty_is_master(struct tty_info *info); -int prepare_shared_tty(void) +static int init_tty_mutex(void) { + if (tty_mutex) + return 0; + tty_mutex = shmalloc(sizeof(*tty_mutex)); if (!tty_mutex) { pr_err("Can't create ptmx index mutex\n"); @@ -1638,6 +1641,13 @@ static int collect_one_tty(void *obj, ProtobufCMessage *msg, struct cr_img *i) if (add_post_prepare_cb_once(prep_tty_restore, NULL)) return -1; + /* + * Call it explicitly. Post-callbacks will be called after + * namespaces preparation, while the latter needs this mutex. + */ + if (init_tty_mutex()) + return -1; + info->fdstore_id = -1; list_add(&info->list, &all_ttys); return file_desc_add(&info->d, info->tfe->id, &tty_desc_ops); From e03aa018c2072552ac04a65adb6d74f4ba5cba28 Mon Sep 17 00:00:00 2001 From: Kang Yan Date: Fri, 28 Apr 2017 09:26:17 +0800 Subject: [PATCH 0573/4375] Update Makefile Signed-off-by: Andrei Vagin --- test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Makefile b/test/Makefile index a728e0cb3..6d7557124 100644 --- a/test/Makefile +++ b/test/Makefile @@ -25,7 +25,7 @@ zdtm: zdtm-pre-dump: ./zdtm.py run --pre 2:1 -t zdtm/transition/fork -f uns -.PHONY: zdtm +.PHONY: zdtm-pre-dump zdtm-snapshot: ./zdtm.py run --pre 2:1 --snap -t zdtm/transition/fork -f uns From 7d8adbee2b94d36c33d3791513328c0e0d4b7c59 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 19 May 2017 15:13:09 +0300 Subject: [PATCH 0574/4375] mount: Find NS_ROOT for cr-time mount on restore After commit 2e8970beda5b "mount: create a mount point for the root mount namespace in the roots yard", top of the tree of mount_infos points to the fake mount. So, when we're looking for appropriate place for binfmt_misc, we can't find "xxx/proc/sys/fs/binfmt_misc". Fix that by finding real NS_ROOT manually. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/mount.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index ba1c6bcfa..af17cb038 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -41,7 +41,7 @@ #undef LOG_PREFIX #define LOG_PREFIX "mnt: " -#define BINFMT_MISC_HOME "/proc/sys/fs/binfmt_misc" +#define BINFMT_MISC_HOME "proc/sys/fs/binfmt_misc" #define CRTIME_MNT_ID 0 /* A helper mount_info entry for the roots yard */ @@ -1193,15 +1193,41 @@ out: static __maybe_unused int add_cr_time_mount(struct mount_info *root, char *fsname, const char *path, unsigned int s_dev) { struct mount_info *mi, *t, *parent; + bool add_slash = false; + int len; + + if (!root->nsid) { + /* On restore we have fake top mount_info. Find real NS_ROOT */ + list_for_each_entry(t, &root->children, siblings) + if (t->nsid->type == NS_ROOT) { + root = t; + break; + } + if (!root->nsid) { + pr_err("Can't find NS_ROOT\n"); + return -1; + } + } mi = mnt_entry_alloc(); if (!mi) return -1; - mi->mountpoint = xmalloc(strlen(path) + 2); + + len = strlen(root->mountpoint); + /* It may be "./" or "./path/to/dir" */ + if (root->mountpoint[len - 1] != '/') { + add_slash = true; + len++; + } + + mi->mountpoint = xmalloc(len + strlen(path) + 1); if (!mi->mountpoint) return -1; mi->ns_mountpoint = mi->mountpoint; - sprintf(mi->mountpoint, ".%s", path); + if (!add_slash) + sprintf(mi->mountpoint, "%s%s", root->mountpoint, path); + else + sprintf(mi->mountpoint, "%s/%s", root->mountpoint, path); mi->mnt_id = CRTIME_MNT_ID; mi->flags = mi->sb_flags = 0; mi->root = xstrdup("/"); @@ -3250,7 +3276,7 @@ int collect_mnt_namespaces(bool for_dump) } if (ns) { - ret = mount_cr_time_mount(ns, &s_dev, "binfmt_misc", BINFMT_MISC_HOME, + ret = mount_cr_time_mount(ns, &s_dev, "binfmt_misc", "/" BINFMT_MISC_HOME, "binfmt_misc"); if (ret == -EPERM) pr_info("Can't mount binfmt_misc: EPERM. Running in user_ns?\n"); From f32ffdef90839be9fe6f50c65404217395149452 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 31 May 2017 23:23:38 +0300 Subject: [PATCH 0575/4375] nmk: Provide try-asm build check function I need to add feature test written in assembly to check if the feature can be compiled. Add a make function for this purpose. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/utils.mk | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/nmk/scripts/utils.mk b/scripts/nmk/scripts/utils.mk index 1736ada90..0cf216bc0 100644 --- a/scripts/nmk/scripts/utils.mk +++ b/scripts/nmk/scripts/utils.mk @@ -1,11 +1,19 @@ ifndef ____nmk_defined__utils # -# Usage: option = $(call try-cc,source-to-build,cc-options,cc-defines) -try-cc = $(shell sh -c 'echo "$(1)" | \ - $(CC) $(3) -x c - $(2) -o /dev/null > /dev/null 2>&1 && \ +# Usage: option := $(call try-compile,language,source-to-build,cc-options,cc-defines) +try-compile = $(shell sh -c 'echo "$(2)" | \ + $(CC) $(4) -x $(1) - $(3) -o /dev/null > /dev/null 2>&1 && \ echo true || echo false') +# +# Usage: option := $(call try-cc,source-to-build,cc-options,cc-defines) +try-cc = $(call try-compile,c,$(1),$(2),$(3)) + +# +# Usage: option := $(call try-cc,source-to-build,cc-options,cc-defines) +try-asm = $(call try-compile,assembler-with-cpp,$(1),$(2),$(3)) + # pkg-config-check # Usage: ifeq ($(call pkg-config-check, library),y) pkg-config-check = $(shell sh -c 'pkg-config $(1) && echo y') From 37b3e5953b484d2eb5e27b79a80c83bcd24baafd Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 31 May 2017 23:23:39 +0300 Subject: [PATCH 0576/4375] ia32/feature-test: Don't check i686 libraries presence I was adapting CRIU with ia32 support for building with Koji, and found that Koji can't build x86_64 packages and have i686 libs installed. While at it, I found that i686 libraries requirement is no longer valid since I've deleted the second parasite. Drop feature test for i686 libs and put test for gcc. That will effectively test if gcc can compile 32-bit code and bug with debian's gcc (#315). Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile.config | 8 +++++--- scripts/feature-tests.mak | 35 +++++++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/Makefile.config b/Makefile.config index ec6c2d145..0e557805c 100644 --- a/Makefile.config +++ b/Makefile.config @@ -21,12 +21,14 @@ $(CONFIG_FILE): ifeq ($(SRCARCH),x86) # CONFIG_COMPAT is only for x86 now, no need for compile-test other archs -ifeq ($(call try-cc,$(FEATURE_TEST_X86_COMPAT),-m32),true) +ifeq ($(call try-asm,$(FEATURE_TEST_X86_COMPAT)),true) export CONFIG_COMPAT := y FEATURE_DEFINES += -DCONFIG_COMPAT else - $(info Note: Building without ia32 C/R, missed package(s):) - $(info $(info) libc6-dev-i386 and/or gcc-multilib) + $(info Note: Building without ia32 C/R, missed ia32 support in gcc) + $(info $(info) That may be related to missing gcc-multilib in your) + $(info $(info) distribution or you may have Debian with buggy toolchain) + $(info $(info) (issue https://github.com/xemul/criu/issues/315)) endif endif diff --git a/scripts/feature-tests.mak b/scripts/feature-tests.mak index ad50eb4ad..12bf54181 100644 --- a/scripts/feature-tests.mak +++ b/scripts/feature-tests.mak @@ -90,13 +90,36 @@ int main(int argc, char *argv[], char *envp[]) endef define FEATURE_TEST_X86_COMPAT +#define __ALIGN .align 4, 0x90 +#define ENTRY(name) \ + .globl name; \ + .type name, @function; \ + __ALIGN; \ + name: -/* Test for glibc-devel.i686 presence */ -#include +#define END(sym) \ + .size sym, . - sym -int main(int argc, char **argv) -{ - return 0; -} +#define __USER32_CS 0x23 +#define __USER_CS 0x33 + .text + +ENTRY(call32_from_64) + /* Switch into compatibility mode */ + pushq \$$__USER32_CS + pushq \$$1f + lretq +1: + .code32 + /* Run function and switch back */ + call *%esi + jmp \$$__USER_CS,\$$1f + .code64 +1: +END(call32_from_64) + +ENTRY(main) + nop +END(main) endef From 871ce841a7d2a4567cbf662f8b63210e5c3692d1 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 31 May 2017 23:23:40 +0300 Subject: [PATCH 0577/4375] travis/ia32: Remove libc6.i386 dependency Not needed anymore for CONFIG_COMPAT. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.x86_64.hdr | 3 +-- scripts/travis/travis-tests | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/build/Dockerfile.x86_64.hdr b/scripts/build/Dockerfile.x86_64.hdr index 2f136098c..ba8282cbf 100644 --- a/scripts/build/Dockerfile.x86_64.hdr +++ b/scripts/build/Dockerfile.x86_64.hdr @@ -1,5 +1,4 @@ FROM ubuntu:trusty RUN apt-get update -qq && apt-get install -qq \ - gcc-multilib \ - libc6-dev-i386 + gcc-multilib diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index c50f0139c..90f5f346e 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -3,7 +3,7 @@ set -x -e TRAVIS_PKGS="protobuf-c-compiler libprotobuf-c0-dev libaio-dev libprotobuf-dev protobuf-compiler python-ipaddr libcap-dev - libnl-3-dev gcc-multilib libc6-dev-i386 gdb bash python-protobuf + libnl-3-dev gcc-multilib gdb bash python-protobuf libnet-dev util-linux asciidoc xmlto" travis_prep () { From dc8261ced53044af2e9a177f4e3c3f0e1fdccacf Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 4 May 2017 22:14:50 +0300 Subject: [PATCH 0578/4375] net: suggest enabling NETFILTER_XT_MARK if iptables-restore failed On x86_64 defconfig it's =m, so if you boot kernel without initramfs in qemu, you will see this. [xemul: split long line] Fixes: #292 Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/net.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/criu/net.c b/criu/net.c index d2c10f7da..9b704f96d 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1780,6 +1780,12 @@ int network_lock_internal() if (kdat.ipv6) ret |= iptables_restore(true, conf, sizeof(conf) - 1); + if (ret) + pr_err("Locking network failed: iptables-restore returned %d. " + "This may be connected to disabled " + "CONFIG_NETFILTER_XT_MARK kernel build config " + "option.\n", ret); + if (restore_ns(nsret, &net_ns_desc)) ret = -1; From 47f3b889557e344e84c662cca9e2a926907856eb Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 26 May 2017 20:02:45 +0300 Subject: [PATCH 0579/4375] restore: fix sys_wait4 error handling in case no child Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index e6ad86e44..b6628f75d 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1024,7 +1024,7 @@ static int wait_helpers(struct task_restore_args *task_args) pid_t pid = task_args->helpers[i]; /* Check that a helper completed. */ - if (sys_wait4(pid, &status, 0, NULL) == -1) { + if (sys_wait4(pid, &status, 0, NULL) == -ECHILD) { /* It has been waited in sigchld_handler */ continue; } From baed8b8c6ddf05d810359ec90133afba74eb0089 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 18 May 2017 21:10:18 +0300 Subject: [PATCH 0580/4375] pie/vdso: return back ELF header mismatch error I've deleted it previously by the reason that I searched vdso vma in [vdso/vvar] vma's pair by magic header. So, I needed to suppress this error. >From that moment, I've reworked how 32-bit vdso is parsed and now we don't need to search it, even more: we parse it only once in the criu helper. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/util-vdso.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/criu/pie/util-vdso.c b/criu/pie/util-vdso.c index ef87f07d5..51fea56a3 100644 --- a/criu/pie/util-vdso.c +++ b/criu/pie/util-vdso.c @@ -87,8 +87,11 @@ static int has_elf_identity(Ehdr_t *ehdr) BUILD_BUG_ON(sizeof(elf_ident) != sizeof(ehdr->e_ident)); - if (memcmp(ehdr->e_ident, elf_ident, sizeof(elf_ident))) + if (memcmp(ehdr->e_ident, elf_ident, sizeof(elf_ident))) { + pr_err("ELF header magic mismatch\n"); return false; + } + return true; } From 28c35b181561095ae761ef05d6faa4637d95dffa Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 18 May 2017 21:10:19 +0300 Subject: [PATCH 0581/4375] vdso/compat: Don't unmap missing vdso/vvar vmas I've met missing vvar on Virtuozzo 7 kernel - just skip unmapping it. TODO: check ia32 C/R with kernel CONFIG_VDSO=n Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/vdso-compat.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/criu/vdso-compat.c b/criu/vdso-compat.c index 7669eb3df..757377a15 100644 --- a/criu/vdso-compat.c +++ b/criu/vdso-compat.c @@ -41,13 +41,17 @@ void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd, long vdso_size; long ret; - vma_size = native->vma_end - native->vma_start; - ret = syscall(__NR_munmap, native->vma_start, vma_size); - exit_on(ret, err_fd, "Error: Failed to unmap native vdso\n"); + if (native->vma_start != VDSO_BAD_ADDR) { + vma_size = native->vma_end - native->vma_start; + ret = syscall(__NR_munmap, native->vma_start, vma_size); + exit_on(ret, err_fd, "Error: Failed to unmap native vdso\n"); + } - vma_size = native->vvar_end - native->vvar_start; - ret = syscall(__NR_munmap, native->vvar_start, vma_size); - exit_on(ret, err_fd, "Error: Failed to unmap native vvar\n"); + if (native->vvar_start != VVAR_BAD_ADDR) { + vma_size = native->vvar_end - native->vvar_start; + ret = syscall(__NR_munmap, native->vvar_start, vma_size); + exit_on(ret, err_fd, "Error: Failed to unmap native vvar\n"); + } ret = syscall(__NR_arch_prctl, ARCH_MAP_VDSO_32, native->vma_start); if (ret < 0) From fd5ae6d9b58fef6bc24e812f65c1411c6076bda4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 11 May 2017 12:11:53 +0300 Subject: [PATCH 0582/4375] mem: Shuffle page-read around The page-read will be needed during the premap stage. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/mem.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/criu/mem.c b/criu/mem.c index 0d4360566..51b881173 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -643,7 +643,8 @@ static int map_private_vma(struct pstree_item *t, return 0; } -static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, void *at) +static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, + void *at, struct page_read *pr) { struct list_head *parent_vmas; struct vma_area *pvma, *vma; @@ -681,7 +682,7 @@ static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, vo return ret; } -static int restore_priv_vma_content(struct pstree_item *t) +static int restore_priv_vma_content(struct pstree_item *t, struct page_read *pr) { struct vma_area *vma; int ret = 0; @@ -692,26 +693,21 @@ static int restore_priv_vma_content(struct pstree_item *t) unsigned int nr_droped = 0; unsigned int nr_compared = 0; unsigned long va; - struct page_read pr; vma = list_first_entry(vmas, struct vma_area, list); - ret = open_page_read(vpid(t), &pr, PR_TASK); - if (ret <= 0) - return -1; - /* * Read page contents. */ while (1) { unsigned long off, i, nr_pages; - ret = pr.advance(&pr); + ret = pr->advance(pr); if (ret <= 0) break; - va = (unsigned long)decode_pointer(pr.pe->vaddr); - nr_pages = pr.pe->nr_pages; + va = (unsigned long)decode_pointer(pr->pe->vaddr); + nr_pages = pr->pe->nr_pages; for (i = 0; i < nr_pages; i++) { unsigned char buf[PAGE_SIZE]; @@ -748,7 +744,7 @@ static int restore_priv_vma_content(struct pstree_item *t) if (vma->ppage_bitmap) { /* inherited vma */ clear_bit(off, vma->ppage_bitmap); - ret = pr.read_pages(&pr, va, 1, buf, 0); + ret = pr->read_pages(pr, va, 1, buf, 0); if (ret < 0) goto err_read; @@ -776,7 +772,7 @@ static int restore_priv_vma_content(struct pstree_item *t) nr = min_t(int, nr_pages - i, (vma->e->end - va) / PAGE_SIZE); - ret = pr.read_pages(&pr, va, nr, p, PR_ASYNC); + ret = pr->read_pages(pr, va, nr, p, PR_ASYNC); if (ret < 0) goto err_read; @@ -791,10 +787,10 @@ static int restore_priv_vma_content(struct pstree_item *t) } err_read: - if (pr.sync(&pr)) + if (pr->sync(pr)) return -1; - pr.close(&pr); + pr->close(pr); if (ret < 0) return ret; @@ -846,6 +842,7 @@ int prepare_mappings(struct pstree_item *t) int ret = 0; void *addr; struct vm_area_list *vmas; + struct page_read pr; void *old_premmapped_addr = NULL; unsigned long old_premmapped_len; @@ -867,11 +864,19 @@ int prepare_mappings(struct pstree_item *t) rsti(t)->premmapped_addr = addr; rsti(t)->premmapped_len = vmas->priv_size; - ret = premap_priv_vmas(t, vmas, addr); + ret = open_page_read(vpid(t), &pr, PR_TASK); + if (ret <= 0) + return -1; + + pr.advance(&pr); /* shift to the 1st iovec */ + + ret = premap_priv_vmas(t, vmas, addr, &pr); if (ret < 0) goto out; - ret = restore_priv_vma_content(t); + pr.reset(&pr); + + ret = restore_priv_vma_content(t, &pr); if (ret < 0) goto out; From 5ca537a21168e1a0becacb47947602bcdb4f3e7b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 11 May 2017 12:12:11 +0300 Subject: [PATCH 0583/4375] vma: Introduce vma_premapped flag Not all private VMA-s will be premmaped, so a separate sign of a VMA being on the premap area is needed. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/image.h | 1 + criu/mem.c | 13 +++++++------ criu/pie/restorer.c | 8 ++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/criu/include/image.h b/criu/include/image.h index 22f34afff..f752dee2d 100644 --- a/criu/include/image.h +++ b/criu/include/image.h @@ -89,6 +89,7 @@ #define VMA_AREA_VVAR (1 << 12) #define VMA_AREA_AIORING (1 << 13) +#define VMA_PREMMAPED (1 << 30) #define VMA_UNSUPP (1 << 31) #define CR_CAP_SIZE 2 diff --git a/criu/mem.c b/criu/mem.c index 51b881173..616378391 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -522,7 +522,7 @@ int prepare_mm_pid(struct pstree_item *i) } /* Map a private vma, if it is not mapped by a parent yet */ -static int map_private_vma(struct pstree_item *t, +static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void **tgt_addr, struct vma_area **pvma, struct list_head *pvma_list) { @@ -550,7 +550,7 @@ static int map_private_vma(struct pstree_item *t, if (p->e->start > vma->e->start) break; - if (!vma_area_is_private(p, kdat.task_size)) + if (!vma_area_is(p, VMA_PREMMAPED)) continue; if (p->e->end != vma->e->end || @@ -627,6 +627,7 @@ static int map_private_vma(struct pstree_item *t, *pvma = list_entry(p->list.next, struct vma_area, list); } + vma->e->status |= VMA_PREMMAPED; vma->premmaped_addr = (unsigned long) addr; pr_debug("\tpremap %#016"PRIx64"-%#016"PRIx64" -> %016lx\n", vma->e->start, vma->e->end, (unsigned long)addr); @@ -654,7 +655,7 @@ static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, /* * Keep parent vmas at hands to check whether we can "inherit" them. - * See comments in map_private_vma. + * See comments in premap_private_vma. */ if (t->parent) parent_vmas = &rsti(t->parent)->vmas.h; @@ -674,7 +675,7 @@ static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, if (!vma_area_is_private(vma, kdat.task_size)) continue; - ret = map_private_vma(t, vma, &at, &pvma, parent_vmas); + ret = premap_private_vma(t, vma, &at, &pvma, parent_vmas); if (ret < 0) break; } @@ -901,7 +902,7 @@ int unmap_guard_pages(struct pstree_item *t) struct list_head *vmas = &rsti(t)->vmas.h; list_for_each_entry(vma, vmas, list) { - if (!vma_area_is_private(vma, kdat.task_size)) + if (!vma_area_is(vma, VMA_PREMMAPED)) continue; if (vma->e->flags & MAP_GROWSDOWN) { @@ -961,7 +962,7 @@ int prepare_vmas(struct pstree_item *t, struct task_restore_args *ta) */ *vme = *vma->e; - if (vma_area_is_private(vma, kdat.task_size)) + if (vma_area_is(vma, VMA_PREMMAPED)) vma_premmaped_start(vme) = vma->premmaped_addr; } diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index b6628f75d..b219d9022 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -624,7 +624,7 @@ static unsigned long restore_mapping(VmaEntry *vma_entry) * of tail. To set tail, we write to /dev/null and use the fact this * operation is synchronious for the device. Also, we unmap temporary * anonymous area, used to store content of ring buffer during restore - * and mapped in map_private_vma(). + * and mapped in premap_private_vma(). */ static int restore_aio_ring(struct rst_aio_ring *raio) { @@ -1141,7 +1141,7 @@ long __export_restore_task(struct task_restore_args *args) for (i = 0; i < args->vmas_n; i++) { vma_entry = args->vmas + i; - if (!vma_entry_is_private(vma_entry, args->task_size)) + if (!vma_entry_is(vma_entry, VMA_PREMMAPED)) continue; if (vma_entry->end >= args->task_size) @@ -1159,7 +1159,7 @@ long __export_restore_task(struct task_restore_args *args) for (i = args->vmas_n - 1; i >= 0; i--) { vma_entry = args->vmas + i; - if (!vma_entry_is_private(vma_entry, args->task_size)) + if (!vma_entry_is(vma_entry, VMA_PREMMAPED)) continue; if (vma_entry->start > args->task_size) @@ -1182,7 +1182,7 @@ long __export_restore_task(struct task_restore_args *args) if (!vma_entry_is(vma_entry, VMA_AREA_REGULAR)) continue; - if (vma_entry_is_private(vma_entry, args->task_size)) + if (vma_entry_is(vma_entry, VMA_PREMMAPED)) continue; va = restore_mapping(vma_entry); From 216658cdf062b2b45b1e3c782eeb430409692a55 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 11 May 2017 12:12:30 +0300 Subject: [PATCH 0584/4375] vma: Keep pointer on parent vma We currently keep pointer on parent vma bitmap, but more info about the parent will be needed soon. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/vma.h | 2 +- criu/mem.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/criu/include/vma.h b/criu/include/vma.h index 748563d64..796466a52 100644 --- a/criu/include/vma.h +++ b/criu/include/vma.h @@ -52,8 +52,8 @@ struct vma_area { struct /* for restore */ { int (*vm_open)(int pid, struct vma_area *vma); struct file_desc *vmfd; + struct vma_area *pvma; /* parent for inherited VMAs */ unsigned long *page_bitmap; /* existent pages */ - unsigned long *ppage_bitmap; /* parent's existent pages */ unsigned long premmaped_addr; /* restore only */ }; }; diff --git a/criu/mem.c b/criu/mem.c index 616378391..3331b3890 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -615,7 +615,7 @@ static int premap_private_vma(struct pstree_item *t, * This region was found in parent -- remap it to inherit physical * pages (if any) from it (and COW them later if required). */ - vma->ppage_bitmap = p->page_bitmap; + vma->pvma = p; addr = mremap(paddr, size, size, MREMAP_FIXED | MREMAP_MAYMOVE, *tgt_addr); @@ -742,8 +742,8 @@ static int restore_priv_vma_content(struct pstree_item *t, struct page_read *pr) vma->premmaped_addr); set_bit(off, vma->page_bitmap); - if (vma->ppage_bitmap) { /* inherited vma */ - clear_bit(off, vma->ppage_bitmap); + if (vma->pvma) { /* inherited vma */ + clear_bit(off, vma->pvma->page_bitmap); ret = pr->read_pages(pr, va, 1, buf, 0); if (ret < 0) @@ -800,13 +800,13 @@ err_read: unsigned long size, i = 0; void *addr = decode_pointer(vma->premmaped_addr); - if (vma->ppage_bitmap == NULL) + if (vma->pvma == NULL) continue; size = vma_entry_len(vma->e) / PAGE_SIZE; while (1) { /* Find all pages, which are not shared with this child */ - i = find_next_bit(vma->ppage_bitmap, size, i); + i = find_next_bit(vma->pvma->page_bitmap, size, i); if ( i >= size) break; From f6bfdb8d1a19f7f344db7611ad1aa425bbce9457 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 11 May 2017 12:12:52 +0300 Subject: [PATCH 0585/4375] vma: Move cow decision earlier (v2) Collect VMAs into COW-groups. This is done by checking each pstree_item's VMA list in parallel with the parent one and finding VMAs that have chances to get COW pages. The vma->parent pointer is used to tie such areas together. v2: * Reworded comment about pvmas * Check for both vmas to be private, not only child * Handle helper tasks Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 + criu/include/mem.h | 1 + criu/include/vma.h | 12 ++++ criu/mem.c | 164 +++++++++++++++++++++++++++++---------------- 4 files changed, 120 insertions(+), 59 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 48007d06d..68b99d607 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -357,6 +357,8 @@ static int root_prepare_shared(void) if (ret < 0) goto err; + prepare_cow_vmas(); + ret = prepare_restorer_blob(); if (ret) goto err; diff --git a/criu/include/mem.h b/criu/include/mem.h index c6c5ca373..2fae797c6 100644 --- a/criu/include/mem.h +++ b/criu/include/mem.h @@ -16,6 +16,7 @@ struct mem_dump_ctl { extern bool page_in_parent(bool dirty); extern int prepare_mm_pid(struct pstree_item *i); +extern void prepare_cow_vmas(void); extern int do_task_reset_dirty_track(int pid); extern unsigned long dump_pages_args_size(struct vm_area_list *vmas); extern int parasite_dump_pages_seized(struct pstree_item *item, diff --git a/criu/include/vma.h b/criu/include/vma.h index 796466a52..8ec25608c 100644 --- a/criu/include/vma.h +++ b/criu/include/vma.h @@ -55,6 +55,18 @@ struct vma_area { struct vma_area *pvma; /* parent for inherited VMAs */ unsigned long *page_bitmap; /* existent pages */ unsigned long premmaped_addr; /* restore only */ + + /* + * Some notes about pvma, page_bitmap and premmaped_addr bits + * above. + * + * The pvma is set in prepare_cow_vmas() when we resolve which + * VMAs _may_ inherit pages from each other. + * The page_bitmap and premmaped_addr are set in prepare_mappings() + * when the respective VMAs get mmap-ed or mremap-ed. + * These VMAs are then inherited during fork_with_pid()-s + * called from create_children_and_session(). + */ }; }; }; diff --git a/criu/mem.c b/criu/mem.c index 3331b3890..f3cdbe8c5 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -521,15 +521,101 @@ int prepare_mm_pid(struct pstree_item *i) return ret; } +static inline bool check_cow_vmas(struct vma_area *vma, struct vma_area *pvma) +{ + /* + * VMAs that _may_[1] have COW-ed pages should ... + * + * [1] I say "may" because whether or not particular pages are + * COW-ed is determined later in restore_priv_vma_content() by + * memcmp'aring the contents. + */ + + /* ... coinside by start/stop pair (start is checked by caller) */ + if (vma->e->end != pvma->e->end) + return false; + /* ... both be private (and thus have space in premmaped area) */ + if (!vma_area_is_private(vma, kdat.task_size)) + return false; + if (!vma_area_is_private(pvma, kdat.task_size)) + return false; + /* ... have growsdown and anon flags coinside */ + if ((vma->e->flags ^ pvma->e->flags) & (MAP_GROWSDOWN | MAP_ANONYMOUS)) + return false; + /* ... belong to the same file if being filemap */ + if (!(vma->e->flags & MAP_ANONYMOUS) && vma->e->shmid != pvma->e->shmid) + return false; + + pr_debug("Found two COW VMAs @0x%"PRIx64"-0x%"PRIx64"\n", vma->e->start, pvma->e->end); + return true; +} + +static void prepare_cow_vmas_for(struct vm_area_list *vmas, struct vm_area_list *pvmas) +{ + struct vma_area *vma, *pvma; + + vma = list_first_entry(&vmas->h, struct vma_area, list); + pvma = list_first_entry(&pvmas->h, struct vma_area, list); + + while (1) { + if ((vma->e->start == pvma->e->start) && check_cow_vmas(vma, pvma)) + vma->pvma = pvma; + + /* <= here to shift from matching VMAs and ... */ + while (vma->e->start <= pvma->e->start) { + vma = vma_next(vma); + if (&vma->list == &vmas->h) + return; + } + + /* ... no == here since we must stop on matching pair */ + while (pvma->e->start < vma->e->start) { + pvma = vma_next(pvma); + if (&pvma->list == &pvmas->h) + return; + } + } +} + +void prepare_cow_vmas(void) +{ + struct pstree_item *pi; + + for_each_pstree_item(pi) { + struct pstree_item *ppi; + struct vm_area_list *vmas, *pvmas; + + ppi = pi->parent; + if (!ppi) + continue; + + vmas = &rsti(pi)->vmas; + if (vmas->nr == 0) /* Zombie */ + continue; + + pvmas = &rsti(ppi)->vmas; + if (pvmas->nr == 0) /* zombies cannot have kids, + * but helpers can (and do) */ + continue; + + if (rsti(pi)->mm->exe_file_id != rsti(ppi)->mm->exe_file_id) + /* + * Tasks running different executables have + * close to zero chance of having cow-ed areas + * and actually kernel never creates such. + */ + continue; + + prepare_cow_vmas_for(vmas, pvmas); + } +} + /* Map a private vma, if it is not mapped by a parent yet */ -static int premap_private_vma(struct pstree_item *t, - struct vma_area *vma, void **tgt_addr, - struct vma_area **pvma, struct list_head *pvma_list) +static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void **tgt_addr) { int ret; - void *addr, *paddr = NULL; + void *addr; unsigned long nr_pages, size; - struct vma_area *p = *pvma; if (vma_area_is(vma, VMA_FILE_PRIVATE)) { ret = vma->vm_open(vpid(t), vma); @@ -546,51 +632,20 @@ static int premap_private_vma(struct pstree_item *t, if (vma->page_bitmap == NULL) return -1; - list_for_each_entry_from(p, pvma_list, list) { - if (p->e->start > vma->e->start) - break; - - if (!vma_area_is(p, VMA_PREMMAPED)) - continue; - - if (p->e->end != vma->e->end || - p->e->start != vma->e->start) - continue; - - /* Check flags, which must be identical for both vma-s */ - if ((vma->e->flags ^ p->e->flags) & (MAP_GROWSDOWN | MAP_ANONYMOUS)) - break; - - if (!(vma->e->flags & MAP_ANONYMOUS) && - vma->e->shmid != p->e->shmid) - break; - - pr_info("COW %#016"PRIx64"-%#016"PRIx64" %#016"PRIx64" vma\n", - vma->e->start, vma->e->end, vma->e->pgoff); - paddr = decode_pointer(p->premmaped_addr); - - break; - } - /* * A grow-down VMA has a guard page, which protect a VMA below it. * So one more page is mapped here to restore content of the first page */ - if (vma->e->flags & MAP_GROWSDOWN) { + if (vma->e->flags & MAP_GROWSDOWN) vma->e->start -= PAGE_SIZE; - if (paddr) - paddr -= PAGE_SIZE; - } size = vma_entry_len(vma->e); - if (paddr == NULL) { + if (vma->pvma == NULL) { int flag = 0; /* * The respective memory area was NOT found in the parent. * Map a new one. */ - pr_info("Map %#016"PRIx64"-%#016"PRIx64" %#016"PRIx64" vma\n", - vma->e->start, vma->e->end, vma->e->pgoff); /* * Restore AIO ring buffer content to temporary anonymous area. @@ -608,14 +663,19 @@ static int premap_private_vma(struct pstree_item *t, pr_perror("Unable to map ANON_VMA"); return -1; } - - *pvma = p; } else { + void *paddr; + /* - * This region was found in parent -- remap it to inherit physical - * pages (if any) from it (and COW them later if required). + * The area in question can be COWed with the parent. Remap the + * parent area. Note, that it has already being passed through + * the restore_priv_vma_content() call and thus may have some + * pages in it. */ - vma->pvma = p; + + paddr = decode_pointer(vma->pvma->premmaped_addr); + if (vma->e->flags & MAP_GROWSDOWN) + paddr -= PAGE_SIZE; addr = mremap(paddr, size, size, MREMAP_FIXED | MREMAP_MAYMOVE, *tgt_addr); @@ -623,8 +683,6 @@ static int premap_private_vma(struct pstree_item *t, pr_perror("Unable to remap a private vma"); return -1; } - - *pvma = list_entry(p->list.next, struct vma_area, list); } vma->e->status |= VMA_PREMMAPED; @@ -647,23 +705,11 @@ static int premap_private_vma(struct pstree_item *t, static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, void *at, struct page_read *pr) { - struct list_head *parent_vmas; - struct vma_area *pvma, *vma; + struct vma_area *vma; unsigned long pstart = 0; int ret = 0; LIST_HEAD(empty); - /* - * Keep parent vmas at hands to check whether we can "inherit" them. - * See comments in premap_private_vma. - */ - if (t->parent) - parent_vmas = &rsti(t->parent)->vmas.h; - else - parent_vmas = ∅ - - pvma = list_first_entry(parent_vmas, struct vma_area, list); - list_for_each_entry(vma, &vmas->h, list) { if (pstart > vma->e->start) { ret = -1; @@ -675,7 +721,7 @@ static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, if (!vma_area_is_private(vma, kdat.task_size)) continue; - ret = premap_private_vma(t, vma, &at, &pvma, parent_vmas); + ret = premap_private_vma(t, vma, &at); if (ret < 0) break; } From 76c1ec4e27254c9d32b08c83660071a9b038e770 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 11 May 2017 12:13:14 +0300 Subject: [PATCH 0586/4375] vma: Do not open vmas when inheriting Inherited VMAs don't need the descriptor to work with. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/mem.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/criu/mem.c b/criu/mem.c index f3cdbe8c5..d5fb8bdaf 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -617,16 +617,6 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void void *addr; unsigned long nr_pages, size; - if (vma_area_is(vma, VMA_FILE_PRIVATE)) { - ret = vma->vm_open(vpid(t), vma); - if (ret < 0) { - pr_err("Can't fixup VMA's fd\n"); - return -1; - } - - vma->vm_open = NULL; /* prevent from 2nd open in prepare_vmas */ - } - nr_pages = vma_entry_len(vma->e) / PAGE_SIZE; vma->page_bitmap = xzalloc(BITS_TO_LONGS(nr_pages) * sizeof(long)); if (vma->page_bitmap == NULL) @@ -653,6 +643,13 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void */ if (vma_entry_is(vma->e, VMA_AREA_AIORING)) flag |= MAP_ANONYMOUS; + else if (vma_area_is(vma, VMA_FILE_PRIVATE)) { + ret = vma->vm_open(vpid(t), vma); + if (ret < 0) { + pr_err("Can't fixup VMA's fd\n"); + return -1; + } + } addr = mmap(*tgt_addr, size, vma->e->prot | PROT_WRITE, @@ -663,6 +660,9 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void pr_perror("Unable to map ANON_VMA"); return -1; } + + if (vma_area_is(vma, VMA_FILE_PRIVATE)) + close(vma->e->fd); } else { void *paddr; @@ -696,7 +696,7 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void } if (vma_area_is(vma, VMA_FILE_PRIVATE)) - close(vma->e->fd); + vma->vm_open = NULL; /* prevent from 2nd open in prepare_vmas */ *tgt_addr += size; return 0; From 074e7b8901079792b46e20d15af4223a4b7f2455 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 11 May 2017 12:13:33 +0300 Subject: [PATCH 0587/4375] vma: Mark cow roots Next patch will stop premapping some private vmas. In particular -- those, that are not COW-ed with anyone. To make this work we need to distinguish vmas that are not cowed with anyone from those cowed with children only. Currently both have vma->parent pointer set to NULL, so for former let's introduce the special mark. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/vma.h | 2 ++ criu/mem.c | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/criu/include/vma.h b/criu/include/vma.h index 8ec25608c..ddffb7c86 100644 --- a/criu/include/vma.h +++ b/criu/include/vma.h @@ -71,6 +71,8 @@ struct vma_area { }; }; +#define VMA_COW_ROOT ((struct vma_area *)1) + typedef int (*dump_filemap_t)(struct vma_area *vma_area, int fd); extern struct vma_area *alloc_vma_area(void); diff --git a/criu/mem.c b/criu/mem.c index d5fb8bdaf..21ab40bf5 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -550,6 +550,11 @@ static inline bool check_cow_vmas(struct vma_area *vma, struct vma_area *pvma) return true; } +static inline bool vma_inherited(struct vma_area *vma) +{ + return (vma->pvma != NULL && vma->pvma != VMA_COW_ROOT); +} + static void prepare_cow_vmas_for(struct vm_area_list *vmas, struct vm_area_list *pvmas) { struct vma_area *vma, *pvma; @@ -558,8 +563,11 @@ static void prepare_cow_vmas_for(struct vm_area_list *vmas, struct vm_area_list pvma = list_first_entry(&pvmas->h, struct vma_area, list); while (1) { - if ((vma->e->start == pvma->e->start) && check_cow_vmas(vma, pvma)) + if ((vma->e->start == pvma->e->start) && check_cow_vmas(vma, pvma)) { vma->pvma = pvma; + if (pvma->pvma == NULL) + pvma->pvma = VMA_COW_ROOT; + } /* <= here to shift from matching VMAs and ... */ while (vma->e->start <= pvma->e->start) { @@ -630,7 +638,7 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void vma->e->start -= PAGE_SIZE; size = vma_entry_len(vma->e); - if (vma->pvma == NULL) { + if (!vma_inherited(vma)) { int flag = 0; /* * The respective memory area was NOT found in the parent. @@ -788,7 +796,7 @@ static int restore_priv_vma_content(struct pstree_item *t, struct page_read *pr) vma->premmaped_addr); set_bit(off, vma->page_bitmap); - if (vma->pvma) { /* inherited vma */ + if (vma_inherited(vma)) { clear_bit(off, vma->pvma->page_bitmap); ret = pr->read_pages(pr, va, 1, buf, 0); @@ -846,7 +854,7 @@ err_read: unsigned long size, i = 0; void *addr = decode_pointer(vma->premmaped_addr); - if (vma->pvma == NULL) + if (!vma_inherited(vma)) continue; size = vma_entry_len(vma->e) / PAGE_SIZE; From 91388fce03f8dde9eca6a3cb7c9afb6bc0fbdfcb Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 11 May 2017 12:13:52 +0300 Subject: [PATCH 0588/4375] mem: Delayed vma/pr restore (v2) Performance experiments show, that we spend (relatively) a lot of time mremap-ing areas from premap area into their proper places. This time depends on the task being restored, but for those with many vmas this can be up to 20%. The thing is that premapping is only needed to restore cow pages since we don't have any API in the kernel to share a page between two or more anonymous vmas. For non-cowing areas we map mmap() them directly in place. But for such cases we'll also need to restore the page's contents also from the pie code. Doing the whole page-read code from PIE is way too complex (for now), so the proposal is to optimize the case when we have a single local pagemap layer. This is what pr.pieok boolean stands for. v2: * Fixed ARM compiling (vma addresses formatting) * Unused tail of premapped area was left in task after restore * Preadv-ing pages in restorer context worked on corrupted iovs due to mistakes in pointer arithmetics * AIO mapping skipped at premap wasn't mapped in pie * Growsdown VMAs should sometimes (when they are "guarded" by previous VMA and guard page's contents cannot be restored in place) be premmaped * Always premmap for lazy-pages restore Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 1 + criu/include/pagemap.h | 6 +++ criu/include/restorer.h | 12 ++++++ criu/include/rst_info.h | 2 + criu/mem.c | 94 +++++++++++++++++++++++++++++++++++++++-- criu/pagemap.c | 32 +++++++++++++- criu/pie/restorer.c | 52 ++++++++++++++++++++++- criu/pstree.c | 1 + 8 files changed, 193 insertions(+), 7 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 68b99d607..fb0f95b94 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3136,6 +3136,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns RST_MEM_FIXUP_PPTR(task_args->helpers); RST_MEM_FIXUP_PPTR(task_args->zombies); RST_MEM_FIXUP_PPTR(task_args->seccomp_filters); + RST_MEM_FIXUP_PPTR(task_args->vma_ios); if (core->tc->has_seccomp_mode) task_args->seccomp_mode = core->tc->seccomp_mode; diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index eded0d351..b18852279 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -52,6 +52,9 @@ struct page_read { int (*sync)(struct page_read *pr); int (*seek_pagemap)(struct page_read *pr, unsigned long vaddr); + /* Whether or not pages can be read in PIE code */ + bool pieok; + /* Private data of reader */ struct cr_img *pmi; struct cr_img *pi; @@ -95,8 +98,11 @@ extern int open_page_read(int pid, struct page_read *, int pr_flags); extern int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags); +struct task_restore_args; + int pagemap_enqueue_iovec(struct page_read *pr, void *buf, unsigned long len, struct list_head *to); +int pagemap_render_iovec(struct list_head *from, struct task_restore_args *ta); extern int dedup_one_iovec(struct page_read *pr, unsigned long base, unsigned long len); diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 81839f398..2748544c9 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -101,6 +101,14 @@ struct thread_restore_args { typedef long (*thread_restore_fcall_t) (struct thread_restore_args *args); +struct restore_vma_io { + int nr_iovs; + loff_t off; + struct iovec iovs[0]; +}; + +#define RIO_SIZE(niovs) (sizeof(struct restore_vma_io) + (niovs) * sizeof(struct iovec)) + struct task_restore_args { struct thread_restore_args *t; /* thread group leader */ @@ -121,6 +129,10 @@ struct task_restore_args { VmaEntry *vmas; unsigned int vmas_n; + int vma_ios_fd; + struct restore_vma_io *vma_ios; + unsigned int vma_ios_n; + struct restore_posix_timer *posix_timers; unsigned int posix_timers_n; diff --git a/criu/include/rst_info.h b/criu/include/rst_info.h index 92dfc9d93..c3dbe2dd3 100644 --- a/criu/include/rst_info.h +++ b/criu/include/rst_info.h @@ -39,6 +39,8 @@ struct rst_info { struct vm_area_list vmas; struct _MmEntry *mm; + struct list_head vma_io; + unsigned int pages_img_id; u32 cg_set; diff --git a/criu/mem.c b/criu/mem.c index 21ab40bf5..96bff619d 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -710,8 +710,34 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void return 0; } +static inline bool vma_force_premap(struct vma_area *vma, struct list_head *head) +{ + /* + * Growsdown VMAs always have one guard page at the + * beginning and sometimes this page contains data. + * In case the VMA is premmaped, we premmap one page + * larger VMA. In case of in place restore we can only + * do this if the VMA in question is not "guarded" by + * some other VMA. + */ + if (vma->e->flags & MAP_GROWSDOWN) { + if (vma->list.prev != head) { + struct vma_area *prev; + + prev = list_entry(vma->list.prev, struct vma_area, list); + if (prev->e->end == vma->e->start) { + pr_debug("Force premmap for 0x%"PRIx64":0x%"PRIx64"\n", + vma->e->start, vma->e->end); + return true; + } + } + } + + return false; +} + static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, - void *at, struct page_read *pr) + void **at, struct page_read *pr) { struct vma_area *vma; unsigned long pstart = 0; @@ -729,7 +755,14 @@ static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, if (!vma_area_is_private(vma, kdat.task_size)) continue; - ret = premap_private_vma(t, vma, &at); + if (vma->pvma == NULL && pr->pieok && !vma_force_premap(vma, &vmas->h)) + /* + * VMA in question is not shared with anyone. We'll + * restore it with its contents in restorer. + */ + continue; + + ret = premap_private_vma(t, vma, at); if (ret < 0) break; } @@ -742,6 +775,7 @@ static int restore_priv_vma_content(struct pstree_item *t, struct page_read *pr) struct vma_area *vma; int ret = 0; struct list_head *vmas = &rsti(t)->vmas.h; + struct list_head *vma_io = &rsti(t)->vma_io; unsigned int nr_restored = 0; unsigned int nr_shared = 0; @@ -750,6 +784,7 @@ static int restore_priv_vma_content(struct pstree_item *t, struct page_read *pr) unsigned long va; vma = list_first_entry(vmas, struct vma_area, list); + rsti(t)->pages_img_id = pr->pages_img_id; /* * Read page contents. @@ -791,6 +826,28 @@ static int restore_priv_vma_content(struct pstree_item *t, struct page_read *pr) goto err_addr; } + if (!vma_area_is(vma, VMA_PREMMAPED)) { + unsigned long len = min_t(unsigned long, + (nr_pages - i) * PAGE_SIZE, + vma->e->end - va); + + if (pagemap_enqueue_iovec(pr, (void *)va, len, vma_io)) + return -1; + + pr->skip_pages(pr, len); + + va += len; + len >>= PAGE_SHIFT; + nr_restored += len; + i += len - 1; + pr_debug("Enqueue page-read\n"); + continue; + } + + /* + * Otherwise to the COW restore + */ + off = (va - vma->e->start) / PAGE_SIZE; p = decode_pointer((off) * PAGE_SIZE + vma->premmaped_addr); @@ -925,7 +982,7 @@ int prepare_mappings(struct pstree_item *t) pr.advance(&pr); /* shift to the 1st iovec */ - ret = premap_priv_vmas(t, vmas, addr, &pr); + ret = premap_priv_vmas(t, vmas, &addr, &pr); if (ret < 0) goto out; @@ -942,6 +999,23 @@ int prepare_mappings(struct pstree_item *t) old_premmapped_addr, old_premmapped_len); } + /* + * Not all VMAs were premmaped. Find out the unused tail of the + * premapped area and unmap it. + */ + old_premmapped_len = addr - rsti(t)->premmapped_addr; + if (old_premmapped_len < rsti(t)->premmapped_len) { + unsigned long tail; + + tail = rsti(t)->premmapped_len - old_premmapped_len; + ret = munmap(addr, tail); + if (ret < 0) + pr_perror("Unable to unmap %p(%lx)", addr, tail); + rsti(t)->premmapped_len = old_premmapped_len; + pr_info("Shrunk premap area to %p(%lx)\n", + rsti(t)->premmapped_addr, rsti(t)->premmapped_len); + } + out: return ret; } @@ -995,6 +1069,18 @@ int open_vmas(struct pstree_item *t) return 0; } +static int prepare_vma_ios(struct pstree_item *t, struct task_restore_args *ta) +{ + struct cr_img *pages; + + pages = open_image(CR_FD_PAGES, O_RSTR, rsti(t)->pages_img_id); + if (!pages) + return -1; + + ta->vma_ios_fd = img_raw_fd(pages); + return pagemap_render_iovec(&rsti(t)->vma_io, ta); +} + int prepare_vmas(struct pstree_item *t, struct task_restore_args *ta) { struct vma_area *vma; @@ -1020,6 +1106,6 @@ int prepare_vmas(struct pstree_item *t, struct task_restore_args *ta) vma_premmaped_start(vme) = vma->premmaped_addr; } - return 0; + return prepare_vma_ios(t, ta); } diff --git a/criu/pagemap.c b/criu/pagemap.c index 512beed8b..2e163ce5f 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -10,7 +10,8 @@ #include "cr_options.h" #include "servicefd.h" #include "pagemap.h" - +#include "restorer.h" +#include "rst-malloc.h" #include "fault-injection.h" #include "xmalloc.h" #include "protobuf.h" @@ -309,6 +310,32 @@ static int enqueue_async_iov(struct page_read *pr, void *buf, return 0; } +int pagemap_render_iovec(struct list_head *from, struct task_restore_args *ta) +{ + struct page_read_iov *piov; + + ta->vma_ios = (struct restore_vma_io *)rst_mem_align_cpos(RM_PRIVATE); + ta->vma_ios_n = 0; + + list_for_each_entry(piov, from, l) { + struct restore_vma_io *rio; + + pr_info("`- render %d iovs (%p:%zd...)\n", piov->nr, + piov->to[0].iov_base, piov->to[0].iov_len); + rio = rst_mem_alloc(RIO_SIZE(piov->nr), RM_PRIVATE); + if (!rio) + return -1; + + rio->nr_iovs = piov->nr; + rio->off = piov->from; + memcpy(rio->iovs, piov->to, piov->nr * sizeof(struct iovec)); + + ta->vma_ios_n++; + } + + return 0; +} + int pagemap_enqueue_iovec(struct page_read *pr, void *buf, unsigned long len, struct list_head *to) { @@ -641,6 +668,7 @@ int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) pr->bunch.iov_len = 0; pr->bunch.iov_base = NULL; pr->pmes = NULL; + pr->pieok = false; pr->pmi = open_image_at(dfd, i_typ, O_RSTR, (long)pid); if (!pr->pmi) @@ -673,6 +701,8 @@ int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) pr->sync = process_async_reads; pr->seek_pagemap = seek_pagemap; pr->id = ids++; + if (!pr->parent) + pr->pieok = true; pr_debug("Opened page read %u (parent %u)\n", pr->id, pr->parent ? pr->parent->id : 0); diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index b219d9022..db13d64cc 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -595,6 +595,10 @@ static unsigned long restore_mapping(VmaEntry *vma_entry) if (vma_entry_is(vma_entry, VMA_ANON_SHARED) && (vma_entry->fd != -1UL)) flags &= ~MAP_ANONYMOUS; + /* See comment in premap_private_vma() for this flag change */ + if (vma_entry_is(vma_entry, VMA_AREA_AIORING)) + flags |= MAP_ANONYMOUS; + /* A mapping of file with MAP_SHARED is up to date */ if (vma_entry->fd == -1 || !(vma_entry->flags & MAP_SHARED)) prot |= PROT_WRITE; @@ -1082,7 +1086,7 @@ long __export_restore_task(struct task_restore_args *args) int i; VmaEntry *vma_entry; unsigned long va; - + struct restore_vma_io *rio; struct rt_sigframe *rt_sigframe; struct prctl_mm_map prctl_map; unsigned long new_sp; @@ -1179,7 +1183,8 @@ long __export_restore_task(struct task_restore_args *args) for (i = 0; i < args->vmas_n; i++) { vma_entry = args->vmas + i; - if (!vma_entry_is(vma_entry, VMA_AREA_REGULAR)) + if (!vma_entry_is(vma_entry, VMA_AREA_REGULAR) && + !vma_entry_is(vma_entry, VMA_AREA_AIORING)) continue; if (vma_entry_is(vma_entry, VMA_PREMMAPED)) @@ -1193,6 +1198,49 @@ long __export_restore_task(struct task_restore_args *args) } } + /* + * Now read the contents (if any) + */ + + rio = args->vma_ios; + for (i = 0; i < args->vma_ios_n; i++) { + struct iovec *iovs = rio->iovs; + int nr = rio->nr_iovs; + ssize_t r; + + while (nr) { + pr_debug("Preadv %lx:%d... (%d iovs)\n", + (unsigned long)iovs->iov_base, + (int)iovs->iov_len, nr); + r = sys_preadv(args->vma_ios_fd, iovs, nr, rio->off); + if (r < 0) { + pr_err("Can't read pages data (%d)\n", (int)r); + goto core_restore_end; + } + + pr_debug("`- returned %ld\n", (long)r); + rio->off += r; + /* Advance the iovecs */ + do { + if (iovs->iov_len <= r) { + pr_debug(" `- skip pagemap\n"); + r -= iovs->iov_len; + iovs++; + nr--; + continue; + } + + iovs->iov_base += r; + iovs->iov_len -= r; + break; + } while (nr > 0); + } + + rio = ((void *)rio) + RIO_SIZE(rio->nr_iovs); + } + + sys_close(args->vma_ios_fd); + #ifdef CONFIG_VDSO /* * Proxify vDSO. diff --git a/criu/pstree.c b/criu/pstree.c index b1006e725..9b2d171dc 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -209,6 +209,7 @@ struct pstree_item *__alloc_pstree_item(bool rst) memset(item, 0, sz); vm_area_list_init(&rsti(item)->vmas); + INIT_LIST_HEAD(&rsti(item)->vma_io); item->pid = (void *)item + sizeof(*item) + sizeof(struct rst_info); } From c9194500bfbf746cde75b360bea05fd9412ddb96 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 15 May 2017 17:14:31 +0300 Subject: [PATCH 0589/4375] mem: Don't do unneeded mprotects When a vma we restore doesn't have any pages in pagemaps there's not need to enforce PROT_WRITE bit on it. This only applies to non-premmaped vmas. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/image.h | 1 + criu/mem.c | 27 ++++++++++++++++++++++++++- criu/pie/restorer.c | 6 ++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/criu/include/image.h b/criu/include/image.h index f752dee2d..99d4e78d5 100644 --- a/criu/include/image.h +++ b/criu/include/image.h @@ -89,6 +89,7 @@ #define VMA_AREA_VVAR (1 << 12) #define VMA_AREA_AIORING (1 << 13) +#define VMA_NO_PROT_WRITE (1 << 29) #define VMA_PREMMAPED (1 << 30) #define VMA_UNSUPP (1 << 31) diff --git a/criu/mem.c b/criu/mem.c index 96bff619d..a09393702 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -659,6 +659,13 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void } } + /* + * All mappings here get PROT_WRITE regardless of whether we + * put any data into it or not, because this area will get + * mremap()-ed (branch below) so we MIGHT need to have WRITE + * bits there. Ideally we'd check for the whole COW-chain + * having any data in. + */ addr = mmap(*tgt_addr, size, vma->e->prot | PROT_WRITE, vma->e->flags | MAP_FIXED | flag, @@ -755,14 +762,26 @@ static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, if (!vma_area_is_private(vma, kdat.task_size)) continue; - if (vma->pvma == NULL && pr->pieok && !vma_force_premap(vma, &vmas->h)) + if (vma->pvma == NULL && pr->pieok && !vma_force_premap(vma, &vmas->h)) { /* * VMA in question is not shared with anyone. We'll * restore it with its contents in restorer. + * Now let's check whether we need to map it with + * PROT_WRITE or not. */ + do { + if (pr->pe->vaddr + pr->pe->nr_pages * PAGE_SIZE <= vma->e->start) + continue; + if (pr->pe->vaddr > vma->e->end) + vma->e->status |= VMA_NO_PROT_WRITE; + break; + } while (pr->advance(pr)); + continue; + } ret = premap_private_vma(t, vma, at); + if (ret < 0) break; } @@ -831,6 +850,12 @@ static int restore_priv_vma_content(struct pstree_item *t, struct page_read *pr) (nr_pages - i) * PAGE_SIZE, vma->e->end - va); + if (vma->e->status & VMA_NO_PROT_WRITE) { + pr_debug("VMA 0x%"PRIx64":0x%"PRIx64" RO %#lx:%lu IO\n", + vma->e->start, vma->e->end, va, nr_pages); + BUG(); + } + if (pagemap_enqueue_iovec(pr, (void *)va, len, vma_io)) return -1; diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index db13d64cc..b4a5eb344 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -600,7 +600,8 @@ static unsigned long restore_mapping(VmaEntry *vma_entry) flags |= MAP_ANONYMOUS; /* A mapping of file with MAP_SHARED is up to date */ - if (vma_entry->fd == -1 || !(vma_entry->flags & MAP_SHARED)) + if ((vma_entry->fd == -1 || !(vma_entry->flags & MAP_SHARED)) && + !(vma_entry->status & VMA_NO_PROT_WRITE)) prot |= PROT_WRITE; pr_debug("\tmmap(%"PRIx64" -> %"PRIx64", %x %x %d)\n", @@ -1261,7 +1262,8 @@ long __export_restore_task(struct task_restore_args *args) if (!(vma_entry_is(vma_entry, VMA_AREA_REGULAR))) continue; - if (vma_entry->prot & PROT_WRITE) + if ((vma_entry->prot & PROT_WRITE) || + (vma_entry->status & VMA_NO_PROT_WRITE)) continue; sys_mprotect(decode_pointer(vma_entry->start), From 77e9c5d8067d75670fc04348e0fcbe79e474156e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 18 May 2017 20:24:49 +0300 Subject: [PATCH 0590/4375] vma: Move fdflags evaluation into collect_filemap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this routine we'll need to compare fdflags, so to avoid double if-s, let's calculate and set fdflags early. ✓ travis-ci: success for mem: Do not re-open files for mappings when not required Signed-off-by: Pavel Emelyanov --- criu/files-reg.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 506aedf97..2603863d6 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1635,14 +1635,8 @@ static int open_filemap(int pid, struct vma_area *vma) * We open file w/o lseek, as mappings don't care about it */ - BUG_ON(vma->vmfd == NULL); - if (vma->e->has_fdflags) - flags = vma->e->fdflags; - else if ((vma->e->prot & PROT_WRITE) && - vma_area_is(vma, VMA_FILE_SHARED)) - flags = O_RDWR; - else - flags = O_RDONLY; + BUG_ON((vma->vmfd == NULL) || !vma->e->has_fdflags); + flags = vma->e->fdflags; ret = open_path(vma->vmfd, do_open_reg_noseek_flags, &flags); if (ret < 0) @@ -1656,6 +1650,16 @@ int collect_filemap(struct vma_area *vma) { struct file_desc *fd; + if (!vma->e->has_fdflags) { + /* Make a wild guess for the fdflags */ + vma->e->has_fdflags = true; + if ((vma->e->prot & PROT_WRITE) && + vma_area_is(vma, VMA_FILE_SHARED)) + vma->e->fdflags = O_RDWR; + else + vma->e->fdflags = O_RDONLY; + } + fd = collect_special_file(vma->e->shmid); if (!fd) return -1; From a0738c75c7cc1283fe8a83ee8ab0d5c6f5645642 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 18 May 2017 20:25:14 +0300 Subject: [PATCH 0591/4375] vma: Do not open similar VMAs multiple times MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On real apps it's typical to have sequences ov VMAs with absolutely the same file mapped. We've seen this dump-time and fixed multiple openings of map_files links with the file_borrowed flag. Restore situation is the same -- the vm_open() call in many cases re-open the same path with the same flags. This slows things down. To fix this -- chain VMAs with mapped files to each other and only the first one opens the file and only the last one closes it. ✓ travis-ci: success for mem: Do not re-open files for mappings when not required Signed-off-by: Pavel Emelyanov --- criu/files-reg.c | 26 ++++++++++++++++++++++++-- criu/include/files-reg.h | 7 ++++++- criu/include/image.h | 1 + criu/include/vma.h | 1 + criu/mem.c | 6 ++++-- criu/pie/restorer.c | 3 ++- 6 files changed, 38 insertions(+), 6 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 2603863d6..26c8f76d1 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1624,6 +1624,16 @@ int open_reg_by_id(u32 id) return open_reg_fd(fd); } +static int borrow_filemap(int pid, struct vma_area *vma) +{ + struct vma_area *fvma = vma->fvma; + + BUG_ON(!(fvma->e->status & VMA_NO_CLOSE)); + vma->e->fd = fvma->e->fd; + + return 0; +} + static int open_filemap(int pid, struct vma_area *vma) { u32 flags; @@ -1646,7 +1656,7 @@ static int open_filemap(int pid, struct vma_area *vma) return 0; } -int collect_filemap(struct vma_area *vma) +int collect_filemap(struct vma_area *vma, struct vma_file_ctx *ctx) { struct file_desc *fd; @@ -1665,7 +1675,19 @@ int collect_filemap(struct vma_area *vma) return -1; vma->vmfd = fd; - vma->vm_open = open_filemap; + if (ctx->vma && ctx->flags == vma->e->flags && ctx->fd == fd) { + vma->vm_open = borrow_filemap; + vma->fvma = ctx->vma; + ctx->vma->e->status |= VMA_NO_CLOSE; + /* Change VMA so that next borrower sets NO_CLOSE on us */ + ctx->vma = vma; + } else { + vma->vm_open = open_filemap; + ctx->flags = vma->e->fdflags; + ctx->fd = fd; + ctx->vma = vma; + } + return 0; } diff --git a/criu/include/files-reg.h b/criu/include/files-reg.h index c205da7f1..afae3623b 100644 --- a/criu/include/files-reg.h +++ b/criu/include/files-reg.h @@ -40,7 +40,12 @@ extern struct file_remap *lookup_ghost_remap(u32 dev, u32 ino); extern struct file_desc *try_collect_special_file(u32 id, int optional); #define collect_special_file(id) try_collect_special_file(id, 0) -extern int collect_filemap(struct vma_area *); +struct vma_file_ctx { + u32 flags; + struct file_desc *fd; + struct vma_area *vma; +}; +extern int collect_filemap(struct vma_area *, struct vma_file_ctx *ctx); extern int collect_remaps_and_regfiles(void); diff --git a/criu/include/image.h b/criu/include/image.h index 99d4e78d5..fbf6ec247 100644 --- a/criu/include/image.h +++ b/criu/include/image.h @@ -89,6 +89,7 @@ #define VMA_AREA_VVAR (1 << 12) #define VMA_AREA_AIORING (1 << 13) +#define VMA_NO_CLOSE (1 << 28) #define VMA_NO_PROT_WRITE (1 << 29) #define VMA_PREMMAPED (1 << 30) #define VMA_UNSUPP (1 << 31) diff --git a/criu/include/vma.h b/criu/include/vma.h index ddffb7c86..4f9500eba 100644 --- a/criu/include/vma.h +++ b/criu/include/vma.h @@ -53,6 +53,7 @@ struct vma_area { int (*vm_open)(int pid, struct vma_area *vma); struct file_desc *vmfd; struct vma_area *pvma; /* parent for inherited VMAs */ + struct vma_area *fvma; /* vma from which to borrow a file */ unsigned long *page_bitmap; /* existent pages */ unsigned long premmaped_addr; /* restore only */ diff --git a/criu/mem.c b/criu/mem.c index a09393702..e3166efbe 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -450,6 +450,7 @@ int prepare_mm_pid(struct pstree_item *i) int ret = -1, vn = 0; struct cr_img *img; struct rst_info *ri = rsti(i); + struct vma_file_ctx ctx = {}; img = open_image(CR_FD_MM, O_RSTR, pid); if (!img) @@ -509,7 +510,7 @@ int prepare_mm_pid(struct pstree_item *i) ret = collect_shmem(pid, vma); else if (vma_area_is(vma, VMA_FILE_PRIVATE) || vma_area_is(vma, VMA_FILE_SHARED)) - ret = collect_filemap(vma); + ret = collect_filemap(vma, &ctx); else if (vma_area_is(vma, VMA_AREA_SOCKET)) ret = collect_socket_map(vma); else @@ -676,7 +677,8 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void return -1; } - if (vma_area_is(vma, VMA_FILE_PRIVATE)) + if (vma_area_is(vma, VMA_FILE_PRIVATE) && + !vma_area_is(vma, VMA_NO_CLOSE)) close(vma->e->fd); } else { void *paddr; diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index b4a5eb344..8e96c9c40 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -618,7 +618,8 @@ static unsigned long restore_mapping(VmaEntry *vma_entry) vma_entry->fd, vma_entry->pgoff); - if (vma_entry->fd != -1) + if ((vma_entry->fd != -1) && + !(vma_entry->status & VMA_NO_CLOSE)) sys_close(vma_entry->fd); return addr; From f0a87835e1fb7cf45d7c1a5b42ae0eac55a65eb8 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 9 Jun 2017 19:23:37 +0300 Subject: [PATCH 0592/4375] vma: Fix badly inherited FD in filemap_open Previous patch (5a1e1aac) tried to minimize the amount of open()s called when mmap()ing the files. Unfortunatley, there was a mistake and wrong flags were compared which resulted in the whole optimization working randomly (typically not working). Fixing the flags comparison revealed another problem. The patch in question correllated with the 03e8c417 one, which caused some vmas to be opened and mmaped much later than the premap. When hitting the situation when vmas sharing their fds are partially premapped and partially not, the whole vm_open sharing became broken in multiple places -- either needed fd was not opened, or the not needed left un-closed. To fix this the context, that tracks whether the fd should be shared or not, should be moved from collect stage to the real opening loop. In this case we need to explicitly know which vmas _may_ share fds (file private and shared) with each other, so the sharing knowledge becomes spread between open_filemap() and its callers. Oh, well... Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 89 +++++++++++++++++++++++++++++----------- criu/include/files-reg.h | 9 ++-- criu/include/image.h | 2 +- criu/include/vma.h | 1 - criu/mem.c | 24 ++++++++--- criu/pie/restorer.c | 2 +- 6 files changed, 88 insertions(+), 39 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 26c8f76d1..095e8f7f0 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1624,14 +1624,58 @@ int open_reg_by_id(u32 id) return open_reg_fd(fd); } -static int borrow_filemap(int pid, struct vma_area *vma) +struct filemap_ctx { + u32 flags; + struct file_desc *desc; + int fd; + /* + * Whether or not to close the fd when we're about to + * put a new one into ctx. + * + * True is used by premap, so that it just calls vm_open + * in sequence, immediatelly mmap()s the file, then it + * can be closed. + * + * False is used by open_vmas() which pre-opens the files + * for restorer, and the latter mmap()s them and closes. + * + * ... + */ + bool close; + /* ... + * + * but closing all vmas won't work, as some of them share + * the descriptor, so only the ones that terminate the + * fd-sharing chain are marked with VMA_CLOSE flag, saying + * restorer to close the vma's fd. + * + * Said that, this vma pointer references the previously + * seen vma, so that once fd changes, this one gets the + * closing flag. + */ + struct vma_area *vma; +}; + +static struct filemap_ctx ctx; + +void filemap_ctx_init(bool auto_close) { - struct vma_area *fvma = vma->fvma; + ctx.desc = NULL; /* to fail the first comparison in open_ */ + ctx.fd = -1; /* not to close random fd in _fini */ + ctx.vma = NULL; /* not to put spurious VMA_CLOSE in _fini */ + /* flags may remain any */ + ctx.close = auto_close; +} - BUG_ON(!(fvma->e->status & VMA_NO_CLOSE)); - vma->e->fd = fvma->e->fd; - - return 0; +void filemap_ctx_fini(void) +{ + if (ctx.close) { + if (ctx.fd >= 0) + close(ctx.fd); + } else { + if (ctx.vma) + ctx.vma->e->status |= VMA_CLOSE; + } } static int open_filemap(int pid, struct vma_area *vma) @@ -1648,15 +1692,24 @@ static int open_filemap(int pid, struct vma_area *vma) BUG_ON((vma->vmfd == NULL) || !vma->e->has_fdflags); flags = vma->e->fdflags; - ret = open_path(vma->vmfd, do_open_reg_noseek_flags, &flags); - if (ret < 0) - return ret; + if (ctx.flags != flags || ctx.desc != vma->vmfd) { + ret = open_path(vma->vmfd, do_open_reg_noseek_flags, &flags); + if (ret < 0) + return ret; - vma->e->fd = ret; + filemap_ctx_fini(); + + ctx.flags = flags; + ctx.desc = vma->vmfd; + ctx.fd = ret; + } + + ctx.vma = vma; + vma->e->fd = ctx.fd; return 0; } -int collect_filemap(struct vma_area *vma, struct vma_file_ctx *ctx) +int collect_filemap(struct vma_area *vma) { struct file_desc *fd; @@ -1675,19 +1728,7 @@ int collect_filemap(struct vma_area *vma, struct vma_file_ctx *ctx) return -1; vma->vmfd = fd; - if (ctx->vma && ctx->flags == vma->e->flags && ctx->fd == fd) { - vma->vm_open = borrow_filemap; - vma->fvma = ctx->vma; - ctx->vma->e->status |= VMA_NO_CLOSE; - /* Change VMA so that next borrower sets NO_CLOSE on us */ - ctx->vma = vma; - } else { - vma->vm_open = open_filemap; - ctx->flags = vma->e->fdflags; - ctx->fd = fd; - ctx->vma = vma; - } - + vma->vm_open = open_filemap; return 0; } diff --git a/criu/include/files-reg.h b/criu/include/files-reg.h index afae3623b..1c49be950 100644 --- a/criu/include/files-reg.h +++ b/criu/include/files-reg.h @@ -40,12 +40,9 @@ extern struct file_remap *lookup_ghost_remap(u32 dev, u32 ino); extern struct file_desc *try_collect_special_file(u32 id, int optional); #define collect_special_file(id) try_collect_special_file(id, 0) -struct vma_file_ctx { - u32 flags; - struct file_desc *fd; - struct vma_area *vma; -}; -extern int collect_filemap(struct vma_area *, struct vma_file_ctx *ctx); +extern int collect_filemap(struct vma_area *); +extern void filemap_ctx_init(bool auto_close); +extern void filemap_ctx_fini(void); extern int collect_remaps_and_regfiles(void); diff --git a/criu/include/image.h b/criu/include/image.h index fbf6ec247..d60cbadd2 100644 --- a/criu/include/image.h +++ b/criu/include/image.h @@ -89,7 +89,7 @@ #define VMA_AREA_VVAR (1 << 12) #define VMA_AREA_AIORING (1 << 13) -#define VMA_NO_CLOSE (1 << 28) +#define VMA_CLOSE (1 << 28) #define VMA_NO_PROT_WRITE (1 << 29) #define VMA_PREMMAPED (1 << 30) #define VMA_UNSUPP (1 << 31) diff --git a/criu/include/vma.h b/criu/include/vma.h index 4f9500eba..ddffb7c86 100644 --- a/criu/include/vma.h +++ b/criu/include/vma.h @@ -53,7 +53,6 @@ struct vma_area { int (*vm_open)(int pid, struct vma_area *vma); struct file_desc *vmfd; struct vma_area *pvma; /* parent for inherited VMAs */ - struct vma_area *fvma; /* vma from which to borrow a file */ unsigned long *page_bitmap; /* existent pages */ unsigned long premmaped_addr; /* restore only */ diff --git a/criu/mem.c b/criu/mem.c index e3166efbe..2c4323d8c 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -450,7 +450,6 @@ int prepare_mm_pid(struct pstree_item *i) int ret = -1, vn = 0; struct cr_img *img; struct rst_info *ri = rsti(i); - struct vma_file_ctx ctx = {}; img = open_image(CR_FD_MM, O_RSTR, pid); if (!img) @@ -510,7 +509,7 @@ int prepare_mm_pid(struct pstree_item *i) ret = collect_shmem(pid, vma); else if (vma_area_is(vma, VMA_FILE_PRIVATE) || vma_area_is(vma, VMA_FILE_SHARED)) - ret = collect_filemap(vma, &ctx); + ret = collect_filemap(vma); else if (vma_area_is(vma, VMA_AREA_SOCKET)) ret = collect_socket_map(vma); else @@ -676,10 +675,6 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void pr_perror("Unable to map ANON_VMA"); return -1; } - - if (vma_area_is(vma, VMA_FILE_PRIVATE) && - !vma_area_is(vma, VMA_NO_CLOSE)) - close(vma->e->fd); } else { void *paddr; @@ -753,6 +748,8 @@ static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, int ret = 0; LIST_HEAD(empty); + filemap_ctx_init(true); + list_for_each_entry(vma, &vmas->h, list) { if (pstart > vma->e->start) { ret = -1; @@ -788,6 +785,8 @@ static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, break; } + filemap_ctx_fini(); + return ret; } @@ -1079,6 +1078,8 @@ int open_vmas(struct pstree_item *t) struct vma_area *vma; struct vm_area_list *vmas = &rsti(t)->vmas; + filemap_ctx_init(false); + list_for_each_entry(vma, &vmas->h, list) { if (!vma_area_is(vma, VMA_AREA_REGULAR) || !vma->vm_open) continue; @@ -1091,8 +1092,19 @@ int open_vmas(struct pstree_item *t) pr_err("`- Can't open vma\n"); return -1; } + + /* + * File mappings have vm_open set to open_filemap which, in + * turn, puts the VMA_CLOSE bit itself. For all the rest we + * need to put it by hads, so that the restorer closes the fd + */ + if (!(vma_area_is(vma, VMA_FILE_PRIVATE) || + vma_area_is(vma, VMA_FILE_SHARED))) + vma->e->status |= VMA_CLOSE; } + filemap_ctx_fini(); + return 0; } diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 8e96c9c40..6216e43e7 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -619,7 +619,7 @@ static unsigned long restore_mapping(VmaEntry *vma_entry) vma_entry->pgoff); if ((vma_entry->fd != -1) && - !(vma_entry->status & VMA_NO_CLOSE)) + (vma_entry->status & VMA_CLOSE)) sys_close(vma_entry->fd); return addr; From 9de01e1b8974cadae86d340ed4f19740e9f4afa0 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 10 Mar 2016 10:39:00 +0300 Subject: [PATCH 0593/4375] Make skip_pages function available criu-wide For the upcoming userfaultfd integration the skip_pages functionality is required to find the userfaultfd requested pages. Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/include/pagemap.h | 1 + criu/pagemap.c | 1 + 2 files changed, 2 insertions(+) diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index b18852279..eddcc37d2 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -49,6 +49,7 @@ struct page_read { /* Advance page_read to the next entry (including zero pagemaps) */ int (*advance)(struct page_read *pr); void (*close)(struct page_read *); + void (*skip_pages)(struct page_read *, unsigned long len); int (*sync)(struct page_read *pr); int (*seek_pagemap)(struct page_read *pr, unsigned long vaddr); diff --git a/criu/pagemap.c b/criu/pagemap.c index 2e163ce5f..126dce6ae 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -698,6 +698,7 @@ int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) pr->read_pages = read_pagemap_page; pr->advance = advance; pr->close = close_page_read; + pr->skip_pages = skip_pagemap_pages; pr->sync = process_async_reads; pr->seek_pagemap = seek_pagemap; pr->id = ids++; From 80e146da2076d8a828590176d57c8eabbe78017c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 27 Jun 2016 07:53:21 +0300 Subject: [PATCH 0594/4375] criu: pagemap: add reset method Rather than do open/close to reset pagemap, just update it's state. Signed-off-by: Mike Rapoport Acked-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/include/pagemap.h | 1 + criu/pagemap.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index eddcc37d2..b993c4759 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -52,6 +52,7 @@ struct page_read { void (*skip_pages)(struct page_read *, unsigned long len); int (*sync)(struct page_read *pr); int (*seek_pagemap)(struct page_read *pr, unsigned long vaddr); + void (*reset)(struct page_read *pr); /* Whether or not pages can be read in PIE code */ bool pieok; diff --git a/criu/pagemap.c b/criu/pagemap.c index 126dce6ae..dc42731ae 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -547,6 +547,19 @@ static void close_page_read(struct page_read *pr) free_pagemaps(pr); } +static void reset_pagemap(struct page_read *pr) +{ + pr->cvaddr = 0; + pr->pi_off = 0; + pr->curr_pme = -1; + pr->pe = NULL; + + /* FIXME: take care of bunch */ + + if (pr->parent) + reset_pagemap(pr->parent); +} + static int try_open_parent(int dfd, int pid, struct page_read *pr, int pr_flags) { int pfd, ret; @@ -701,6 +714,7 @@ int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) pr->skip_pages = skip_pagemap_pages; pr->sync = process_async_reads; pr->seek_pagemap = seek_pagemap; + pr->reset = reset_pagemap; pr->id = ids++; if (!pr->parent) pr->pieok = true; From c48099d83a1ca10d5fc020a4181c5c4f47bc3761 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 26 May 2017 16:02:27 +0300 Subject: [PATCH 0595/4375] image: Introduce collect-nofree flag Current collect helper frees the pb entry if there's zero priv_size on cinfo. For files we'll have zero priv_size (as entries will be collected by sub-cinfos), while the entry in question should NOT be freed. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/protobuf.h | 1 + criu/protobuf.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/include/protobuf.h b/criu/include/protobuf.h index a90fcd1b2..1afeed121 100644 --- a/criu/include/protobuf.h +++ b/criu/include/protobuf.h @@ -36,6 +36,7 @@ struct collect_image_info { }; #define COLLECT_SHARED 0x1 /* use shared memory for obj-s */ +#define COLLECT_NOFREE 0x2 /* don't free entry after callback */ #define COLLECT_HAPPENED 0x4 /* image was opened and collected */ extern int collect_image(struct collect_image_info *); diff --git a/criu/protobuf.c b/criu/protobuf.c index 3db829de9..5c770b847 100644 --- a/criu/protobuf.c +++ b/criu/protobuf.c @@ -217,7 +217,7 @@ int collect_image(struct collect_image_info *cinfo) break; } - if (!cinfo->priv_size) + if (!cinfo->priv_size && !(cinfo->flags & COLLECT_NOFREE)) cr_pb_descs[cinfo->pb_type].free(msg, NULL); } From 5f7572783047ebc52ca611918747738268f37177 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 26 May 2017 16:02:40 +0300 Subject: [PATCH 0596/4375] epol: Sanitize epoll tfds collecting This case is legacy, tfds are merged into epoll entry, but to make it working we have separate list of tfds and extra code in ->open callback. Keep the legacy code in one place. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/eventpoll.c | 48 ++++++++++++++++++++++------------------------- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index fb0f95b94..71a638665 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -262,8 +262,8 @@ static struct collect_image_info *cinfos[] = { &packet_sk_cinfo, &netlink_sk_cinfo, &eventfd_cinfo, - &epoll_tfd_cinfo, &epoll_cinfo, + &epoll_tfd_cinfo, &signalfd_cinfo, &inotify_cinfo, &inotify_mark_cinfo, diff --git a/criu/eventpoll.c b/criu/eventpoll.c index c638f8f3b..1253f23b8 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -34,13 +34,6 @@ struct eventpoll_file_info { struct file_desc d; }; -struct eventpoll_tfd_file_info { - EventpollTfdEntry *tdefe; - struct list_head list; -}; - -static LIST_HEAD(eventpoll_tfds); - /* Checks if file descriptor @lfd is eventfd */ int is_eventpoll_link(char *link) { @@ -188,7 +181,6 @@ static int eventpoll_retore_tfd(int fd, int id, EventpollTfdEntry *tdefe) static int eventpoll_post_open(struct file_desc *d, int fd) { - struct eventpoll_tfd_file_info *td_info; struct eventpoll_file_info *info; int i; @@ -203,19 +195,6 @@ static int eventpoll_post_open(struct file_desc *d, int fd) return -1; } - list_for_each_entry(td_info, &eventpoll_tfds, list) { - if (epoll_not_ready_tfd(td_info->tdefe)) - return 1; - } - list_for_each_entry(td_info, &eventpoll_tfds, list) { - if (td_info->tdefe->id != info->efe->id) - continue; - - if (eventpoll_retore_tfd(fd, info->efe->id, td_info->tdefe)) - return -1; - - } - return 0; } @@ -226,14 +205,31 @@ static struct file_desc_ops desc_ops = { static int collect_one_epoll_tfd(void *o, ProtobufCMessage *msg, struct cr_img *i) { - struct eventpoll_tfd_file_info *info = o; + EventpollTfdEntry *tfde; + struct file_desc *d; + struct eventpoll_file_info *ef; + EventpollFileEntry *efe; + int n_tfd; if (!deprecated_ok("Epoll TFD image")) return -1; - info->tdefe = pb_msg(msg, EventpollTfdEntry); - list_add(&info->list, &eventpoll_tfds); - pr_info_eventpoll_tfd("Collected ", info->tdefe); + tfde = pb_msg(msg, EventpollTfdEntry); + d = find_file_desc_raw(FD_TYPES__EVENTPOLL, tfde->id); + if (!d) { + pr_err("No epoll FD for %u\n", tfde->id); + return -1; + } + + ef = container_of(d, struct eventpoll_file_info, d); + efe = ef->efe; + + n_tfd = efe->n_tfd + 1; + if (xrealloc_safe(&efe->tfd, n_tfd * sizeof(EventpollTfdEntry *))) + return -1; + + efe->tfd[efe->n_tfd] = tfde; + efe->n_tfd = n_tfd; return 0; } @@ -241,8 +237,8 @@ static int collect_one_epoll_tfd(void *o, ProtobufCMessage *msg, struct cr_img * struct collect_image_info epoll_tfd_cinfo = { .fd_type = CR_FD_EVENTPOLL_TFD, .pb_type = PB_EVENTPOLL_TFD, - .priv_size = sizeof(struct eventpoll_tfd_file_info), .collect = collect_one_epoll_tfd, + .flags = COLLECT_NOFREE, }; static int collect_one_epoll(void *o, ProtobufCMessage *msg, struct cr_img *i) From 5e97706a5c5490a763538a2b2ba465b7e61fa8ba Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 26 May 2017 18:39:40 +0300 Subject: [PATCH 0597/4375] pipe: Fix comment about list head entry The list in question is not used for fles nowadays. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/pipes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/include/pipes.h b/criu/include/pipes.h index 47d98aee7..83fb71cfc 100644 --- a/criu/include/pipes.h +++ b/criu/include/pipes.h @@ -50,7 +50,7 @@ struct pipe_info { PipeEntry *pe; struct list_head pipe_list; /* All pipe_info with the same pipe_id * This is pure circular list without head */ - struct list_head list; /* list head for fdinfo_list_entry-s */ + struct list_head list; /* global list of pipes */ struct file_desc d; unsigned int create : 1, reopen : 1; From 2fe24bc451ced9d224554998015606a024a9968c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 19 Jun 2017 12:59:14 +0300 Subject: [PATCH 0598/4375] criu: Version 3.2 This is the no-new-features release :) We have several bugfixes, memory restore optimization and a little bit more. Signed-off-by: Pavel Emelyanov --- Makefile.versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index a2526390d..e0aa2f5e9 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 1 +CRIU_VERSION_MINOR := 2 CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Graphene Swift +CRIU_VERSION_NAME := Tin Hoopoe CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From 8a4a164f3e33be9b2d28d54fe430e92f40626054 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 26 Jun 2017 23:55:28 +0300 Subject: [PATCH 0599/4375] kerndat: Detect if we have guard page mangle in procfs output In vanilla kernel commit 1be7107fbe18eed3e319a6c3e83c78254b693acb show_map_vma() no longer report PAGE_SIZE. Detect it with simple test and remember in kdat settings. Suggested-by: Oleg Nesterov Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/kerndat.h | 1 + criu/kerndat.c | 76 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index ba8c10da7..891cbdd41 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -44,6 +44,7 @@ struct kerndat_s { unsigned int has_xtlocks; unsigned long mmap_min_addr; bool has_tcp_half_closed; + bool stack_guard_gap_hidden; }; extern struct kerndat_s kdat; diff --git a/criu/kerndat.c b/criu/kerndat.c index 354fb672b..80ec58bcf 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -563,6 +563,80 @@ static int kerndat_compat_restore(void) return 0; } +static int kerndat_detect_stack_guard_gap(void) +{ + int num, ret = -1, detected = 0; + unsigned long start, end; + char r, w, x, s; + char buf[1024]; + FILE *maps; + void *mem; + + mem = mmap(NULL, (3ul << 20), PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0); + if (mem == MAP_FAILED) { + pr_perror("Can't mmap stack area"); + return -1; + } + munmap(mem, (3ul << 20)); + + mem = mmap(mem + (2ul << 20), (1ul << 20), PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN, -1, 0); + if (mem == MAP_FAILED) { + pr_perror("Can't mmap stack area"); + return -1; + } + + maps = fopen("/proc/self/maps", "r"); + if (maps == NULL) { + munmap(mem, 4096); + return -1; + } + + while (fgets(buf, sizeof(buf), maps)) { + num = sscanf(buf, "%lx-%lx %c%c%c%c", + &start, &end, &r, &w, &x, &s); + if (num < 6) { + pr_err("Can't parse: %s\n", buf); + goto err; + } + + /* + * When reading /proc/$pid/[s]maps the + * start/end addresses migh be cutted off + * with PAGE_SIZE on kernels prior 4.12 + * (see kernel commit 1be7107fbe18ee). + * + * Same time there was semi-complete + * patch released which hitted a number + * of repos (Ubuntu, Fedora) where instead + * of PAGE_SIZE the 1M gap is cutted off. + */ + if (start == (unsigned long)mem) { + kdat.stack_guard_gap_hidden = false; + detected = 1; + break; + } else if (start == ((unsigned long)mem + (1ul << 20))) { + pr_warn("Unsupported stack guard detected, confused but continue\n"); + kdat.stack_guard_gap_hidden = true; + detected = 1; + break; + } else if (start == ((unsigned long)mem + PAGE_SIZE)) { + kdat.stack_guard_gap_hidden = true; + detected = 1; + break; + } + } + + if (detected) + ret = 0; + +err: + munmap(mem, (1ul << 20)); + fclose(maps); + return ret; +} + #define KERNDAT_CACHE_FILE KDAT_RUNDIR"/criu.kdat" #define KERNDAT_CACHE_FILE_TMP KDAT_RUNDIR"/.criu.kdat" @@ -676,6 +750,8 @@ int kerndat_init(void) ret = kerndat_compat_restore(); if (!ret) ret = kerndat_has_memfd_create(); + if (!ret) + ret = kerndat_detect_stack_guard_gap(); kerndat_lsm(); kerndat_mmap_min_addr(); From be37925cff8aaf43f14866bd0a60dca6068a8d97 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 26 Jun 2017 23:55:29 +0300 Subject: [PATCH 0600/4375] mem: Don't assume guard page is returned in procfs with new kernels If the guard page is not reported in show_map_vma we should not ajust vma address neither we should call unmap_guard_pages in restorer. https://github.com/xemul/criu/issues/322 Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/mem.h | 2 ++ criu/mem.c | 19 ++++++++++++++----- criu/proc_parse.c | 3 ++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/criu/include/mem.h b/criu/include/mem.h index 2fae797c6..2fc8e1e0e 100644 --- a/criu/include/mem.h +++ b/criu/include/mem.h @@ -9,11 +9,13 @@ struct parasite_ctl; struct vm_area_list; struct page_pipe; struct pstree_item; +struct vma_area; struct mem_dump_ctl { bool pre_dump; }; +extern bool vma_has_guard_gap_hidden(struct vma_area *vma); extern bool page_in_parent(bool dirty); extern int prepare_mm_pid(struct pstree_item *i); extern void prepare_cow_vmas(void); diff --git a/criu/mem.c b/criu/mem.c index 2c4323d8c..cd41829b2 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -499,7 +499,7 @@ int prepare_mm_pid(struct pstree_item *i) if (vma_area_is_private(vma, kdat.task_size)) { ri->vmas.priv_size += vma_area_len(vma); - if (vma->e->flags & MAP_GROWSDOWN) + if (vma_has_guard_gap_hidden(vma)) ri->vmas.priv_size += PAGE_SIZE; } @@ -634,7 +634,7 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void * A grow-down VMA has a guard page, which protect a VMA below it. * So one more page is mapped here to restore content of the first page */ - if (vma->e->flags & MAP_GROWSDOWN) + if (vma_has_guard_gap_hidden(vma)) vma->e->start -= PAGE_SIZE; size = vma_entry_len(vma->e); @@ -686,7 +686,7 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void */ paddr = decode_pointer(vma->pvma->premmaped_addr); - if (vma->e->flags & MAP_GROWSDOWN) + if (vma_has_guard_gap_hidden(vma)) paddr -= PAGE_SIZE; addr = mremap(paddr, size, size, @@ -702,7 +702,7 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void pr_debug("\tpremap %#016"PRIx64"-%#016"PRIx64" -> %016lx\n", vma->e->start, vma->e->end, (unsigned long)addr); - if (vma->e->flags & MAP_GROWSDOWN) { /* Skip gurad page */ + if (vma_has_guard_gap_hidden(vma)) { /* Skip gurad page */ vma->e->start += PAGE_SIZE; vma->premmaped_addr += PAGE_SIZE; } @@ -717,7 +717,8 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void static inline bool vma_force_premap(struct vma_area *vma, struct list_head *head) { /* - * Growsdown VMAs always have one guard page at the + * On kernels with 4K guard pages, growsdown VMAs + * always have one guard page at the * beginning and sometimes this page contains data. * In case the VMA is premmaped, we premmap one page * larger VMA. In case of in place restore we can only @@ -1046,6 +1047,11 @@ out: return ret; } +bool vma_has_guard_gap_hidden(struct vma_area *vma) +{ + return kdat.stack_guard_gap_hidden && (vma->e->flags & MAP_GROWSDOWN); +} + /* * A gard page must be unmapped after restoring content and * forking children to restore COW memory. @@ -1055,6 +1061,9 @@ int unmap_guard_pages(struct pstree_item *t) struct vma_area *vma; struct list_head *vmas = &rsti(t)->vmas.h; + if (!kdat.stack_guard_gap_hidden) + return 0; + list_for_each_entry(vma, vmas, list) { if (!vma_area_is(vma, VMA_PREMMAPED)) continue; diff --git a/criu/proc_parse.c b/criu/proc_parse.c index f1237cf9f..5e36db540 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -25,6 +25,7 @@ #include "kerndat.h" #include "vdso.h" #include "vma.h" +#include "mem.h" #include "bfd.h" #include "proc_parse.h" #include "fdinfo.h" @@ -637,7 +638,7 @@ static int vma_list_add(struct vma_area *vma_area, } /* Add a guard page only if here is enough space for it */ - if ((vma_area->e->flags & MAP_GROWSDOWN) && + if (vma_has_guard_gap_hidden(vma_area) && *prev_end < vma_area->e->start) vma_area->e->start -= PAGE_SIZE; /* Guard page */ *prev_end = vma_area->e->end; From b745fc058aa621adc9af70927de6a3fa1fce207a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 27 Jun 2017 09:58:00 +0300 Subject: [PATCH 0601/4375] test: grow_map -- Mark as noauto "With the recent kernel changes criu should never look outside of start-end region reported by /proc/maps; and restore doesn't even need to know if a GROWSDOWN region will actually grow or not, because (iiuc) you do not need to auto-grow the stack vma during restore, criu re-creates the whole vma with the same length using MAP_FIXED and it should never write below the addr returned by mmap(MAP_FIXED)" // Oleg Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/grow_map.desc | 1 + test/zdtm/static/grow_map02.desc | 1 + test/zdtm/static/grow_map03.desc | 1 + 3 files changed, 3 insertions(+) create mode 100644 test/zdtm/static/grow_map.desc create mode 100644 test/zdtm/static/grow_map02.desc create mode 100644 test/zdtm/static/grow_map03.desc diff --git a/test/zdtm/static/grow_map.desc b/test/zdtm/static/grow_map.desc new file mode 100644 index 000000000..95c58b401 --- /dev/null +++ b/test/zdtm/static/grow_map.desc @@ -0,0 +1 @@ +{'flags': 'noauto'} diff --git a/test/zdtm/static/grow_map02.desc b/test/zdtm/static/grow_map02.desc new file mode 100644 index 000000000..95c58b401 --- /dev/null +++ b/test/zdtm/static/grow_map02.desc @@ -0,0 +1 @@ +{'flags': 'noauto'} diff --git a/test/zdtm/static/grow_map03.desc b/test/zdtm/static/grow_map03.desc new file mode 100644 index 000000000..95c58b401 --- /dev/null +++ b/test/zdtm/static/grow_map03.desc @@ -0,0 +1 @@ +{'flags': 'noauto'} From 81776f856a388056e2c2897eaca3deee0ea362f0 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 23 Jun 2017 04:25:24 +0300 Subject: [PATCH 0602/4375] travis: roll-back to the old Trusty image https://github.com/xemul/criu/issues/324 Signed-off-by: Andrei Vagin --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 78b1f0c4d..d4d53e434 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,3 +22,4 @@ script: after_success: - ccache -s - make -C scripts/travis after_success +group: deprecated-2017Q2 From ebc485385bad1b32560c0bb82edfa43fc195f17a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 26 Jun 2017 16:19:53 +0300 Subject: [PATCH 0603/4375] lsm: Remove write-only lsm name variable Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/lsm.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/criu/lsm.c b/criu/lsm.c index 4f5c43605..acdb1fb65 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -21,7 +21,6 @@ static Lsmtype lsmtype; static int (*get_label)(pid_t, char **) = NULL; -static char *name = NULL; static int apparmor_get_label(pid_t pid, char **profile_name) { @@ -120,7 +119,6 @@ void kerndat_lsm(void) if (access(AA_SECURITYFS_PATH, F_OK) == 0) { get_label = apparmor_get_label; lsmtype = LSMTYPE__APPARMOR; - name = "apparmor"; return; } @@ -133,14 +131,12 @@ void kerndat_lsm(void) if (access("/sys/fs/selinux", F_OK) == 0) { get_label = selinux_get_label; lsmtype = LSMTYPE__SELINUX; - name = "selinux"; return; } #endif get_label = NULL; lsmtype = LSMTYPE__NO_LSM; - name = "none"; } Lsmtype host_lsm_type(void) From 09c131c8a39bcf3920e968ef4aeb7067471271bf Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 26 Jun 2017 16:20:07 +0300 Subject: [PATCH 0604/4375] lsm: Postpone lsm_profile vs kerndat checks We need to keep the host LSM mode on kerndat (next patches), at the same time the --lsm-profile option needs to correspond to it. So split the option handling into two parts -- first keep it as is, next -- check for kerndat correspondance. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 6 ++++++ criu/cr-restore.c | 3 +++ criu/crtools.c | 4 ++-- criu/include/lsm.h | 2 +- criu/lsm.c | 27 +++++++++------------------ 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index b9fa28496..a5682df99 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1539,6 +1539,9 @@ int cr_pre_dump_tasks(pid_t pid) if (kerndat_init()) goto err; + if (lsm_check_opts()) + goto err; + if (irmap_load_cache()) goto err; @@ -1689,6 +1692,9 @@ int cr_dump_tasks(pid_t pid) if (kerndat_init()) goto err; + if (lsm_check_opts()) + goto err; + if (irmap_load_cache()) goto err; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 71a638665..cfc8f5042 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2134,6 +2134,9 @@ int cr_restore_tasks(void) if (kerndat_init()) goto err; + if (lsm_check_opts()) + goto err; + timing_start(TIME_RESTORE); if (cpu_init() < 0) diff --git a/criu/crtools.c b/criu/crtools.c index 6cc6cf3ea..5213a6ff5 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -511,8 +511,8 @@ int main(int argc, char *argv[], char *envp[]) return -1; break; case 1071: - if (parse_lsm_arg(optarg) < 0) - return -1; + opts.lsm_profile = optarg; + opts.lsm_supplied = true; break; case 1072: opts.timeout = atoi(optarg); diff --git a/criu/include/lsm.h b/criu/include/lsm.h index b97195e38..b4fce1303 100644 --- a/criu/include/lsm.h +++ b/criu/include/lsm.h @@ -33,5 +33,5 @@ int validate_lsm(char *profile); */ int render_lsm_profile(char *profile, char **val); -extern int parse_lsm_arg(char *arg); +extern int lsm_check_opts(void); #endif /* __CR_LSM_H__ */ diff --git a/criu/lsm.c b/criu/lsm.c index acdb1fb65..aef4397c7 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -108,14 +108,6 @@ static int selinux_get_label(pid_t pid, char **output) void kerndat_lsm(void) { - /* On restore, if someone passes --lsm-profile, we might end up doing - * detection twice, once during flag parsing and once for - * kerndat_init(). Let's detect when we've already done detection - * and not do it again. - */ - if (name) - return; - if (access(AA_SECURITYFS_PATH, F_OK) == 0) { get_label = apparmor_get_label; lsmtype = LSMTYPE__APPARMOR; @@ -207,43 +199,42 @@ int render_lsm_profile(char *profile, char **val) return 0; } -int parse_lsm_arg(char *arg) +int lsm_check_opts(void) { char *aux; - kerndat_lsm(); + if (!opts.lsm_supplied) + return 0; - aux = strchr(arg, ':'); + aux = strchr(opts.lsm_profile, ':'); if (aux == NULL) { - pr_err("invalid argument %s for --lsm-profile\n", arg); + pr_err("invalid argument %s for --lsm-profile\n", opts.lsm_profile); return -1; } *aux = '\0'; aux++; - if (strcmp(arg, "apparmor") == 0) { + if (strcmp(opts.lsm_profile, "apparmor") == 0) { if (lsmtype != LSMTYPE__APPARMOR) { pr_err("apparmor LSM specified but apparmor not supported by kernel\n"); return -1; } opts.lsm_profile = aux; - } else if (strcmp(arg, "selinux") == 0) { + } else if (strcmp(opts.lsm_profile, "selinux") == 0) { if (lsmtype != LSMTYPE__SELINUX) { pr_err("selinux LSM specified but selinux not supported by kernel\n"); return -1; } opts.lsm_profile = aux; - } else if (strcmp(arg, "none") == 0) { + } else if (strcmp(opts.lsm_profile, "none") == 0) { opts.lsm_profile = NULL; } else { - pr_err("unknown lsm %s\n", arg); + pr_err("unknown lsm %s\n", opts.lsm_profile); return -1; } - opts.lsm_supplied = true; - return 0; } From 171acca813901969b72915d262412263d1d06ad4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 26 Jun 2017 16:20:20 +0300 Subject: [PATCH 0605/4375] lsm: Make get_type() switch-able call This is to remove the function pointer and have only "type" variable left. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/lsm.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/criu/lsm.c b/criu/lsm.c index aef4397c7..266d98bf5 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -20,7 +20,6 @@ #endif static Lsmtype lsmtype; -static int (*get_label)(pid_t, char **) = NULL; static int apparmor_get_label(pid_t pid, char **profile_name) { @@ -109,7 +108,6 @@ static int selinux_get_label(pid_t pid, char **output) void kerndat_lsm(void) { if (access(AA_SECURITYFS_PATH, F_OK) == 0) { - get_label = apparmor_get_label; lsmtype = LSMTYPE__APPARMOR; return; } @@ -121,13 +119,11 @@ void kerndat_lsm(void) * well. */ if (access("/sys/fs/selinux", F_OK) == 0) { - get_label = selinux_get_label; lsmtype = LSMTYPE__SELINUX; return; } #endif - get_label = NULL; lsmtype = LSMTYPE__NO_LSM; } @@ -138,18 +134,32 @@ Lsmtype host_lsm_type(void) int collect_lsm_profile(pid_t pid, CredsEntry *ce) { + int ret; + ce->lsm_profile = NULL; - if (lsmtype == LSMTYPE__NO_LSM) - return 0; - - if (get_label(pid, &ce->lsm_profile) < 0) - return -1; + switch (lsmtype) { + case LSMTYPE__NO_LSM: + ret = 0; + break; + case LSMTYPE__APPARMOR: + ret = apparmor_get_label(pid, &ce->lsm_profile); + break; +#ifdef CONFIG_HAS_SELINUX + case LSMTYPE__SELINUX: + ret = selinux_get_label(pid, &ce->lsm_profile); + break; +#endif + default: + BUG(); + ret = -1; + break; + } if (ce->lsm_profile) pr_info("%d has lsm profile %s\n", pid, ce->lsm_profile); - return 0; + return ret; } // in inventory.c From e6302380a6b4c9f7839bde5b78bc8ed6b39d4bc5 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 26 Jun 2017 16:20:35 +0300 Subject: [PATCH 0606/4375] lsm: Move host lsmtype on kerndat Currently this is lsm.c's static variable, but since kdat is now cached (and uncached) this value stays zero (no lsm) if the cache file gets loaded, which is obviously wrong and breaks the restore all the time on lsm-enabled hosts. https://github.com/xemul/criu/issues/323 Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/kerndat.h | 3 +++ criu/lsm.c | 21 ++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 891cbdd41..295fcd473 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -1,6 +1,8 @@ #ifndef __CR_KERNDAT_H__ #define __CR_KERNDAT_H__ +#include + #include "int.h" struct stat; @@ -45,6 +47,7 @@ struct kerndat_s { unsigned long mmap_min_addr; bool has_tcp_half_closed; bool stack_guard_gap_hidden; + int lsm; }; extern struct kerndat_s kdat; diff --git a/criu/lsm.c b/criu/lsm.c index 266d98bf5..2d77f6277 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -5,6 +5,7 @@ #include #include +#include "kerndat.h" #include "config.h" #include "pstree.h" #include "util.h" @@ -19,8 +20,6 @@ #include #endif -static Lsmtype lsmtype; - static int apparmor_get_label(pid_t pid, char **profile_name) { FILE *f; @@ -108,7 +107,7 @@ static int selinux_get_label(pid_t pid, char **output) void kerndat_lsm(void) { if (access(AA_SECURITYFS_PATH, F_OK) == 0) { - lsmtype = LSMTYPE__APPARMOR; + kdat.lsm = LSMTYPE__APPARMOR; return; } @@ -119,17 +118,17 @@ void kerndat_lsm(void) * well. */ if (access("/sys/fs/selinux", F_OK) == 0) { - lsmtype = LSMTYPE__SELINUX; + kdat.lsm = LSMTYPE__SELINUX; return; } #endif - lsmtype = LSMTYPE__NO_LSM; + kdat.lsm = LSMTYPE__NO_LSM; } Lsmtype host_lsm_type(void) { - return lsmtype; + return kdat.lsm; } int collect_lsm_profile(pid_t pid, CredsEntry *ce) @@ -138,7 +137,7 @@ int collect_lsm_profile(pid_t pid, CredsEntry *ce) ce->lsm_profile = NULL; - switch (lsmtype) { + switch (kdat.lsm) { case LSMTYPE__NO_LSM: ret = 0; break; @@ -167,7 +166,7 @@ extern Lsmtype image_lsm; int validate_lsm(char *lsm_profile) { - if (image_lsm == LSMTYPE__NO_LSM || image_lsm == lsmtype) + if (image_lsm == LSMTYPE__NO_LSM || image_lsm == kdat.lsm) return 0; /* @@ -187,7 +186,7 @@ int render_lsm_profile(char *profile, char **val) { *val = NULL; - switch (lsmtype) { + switch (kdat.lsm) { case LSMTYPE__APPARMOR: if (strcmp(profile, "unconfined") != 0 && asprintf(val, "changeprofile %s", profile) < 0) { pr_err("allocating lsm profile failed\n"); @@ -226,14 +225,14 @@ int lsm_check_opts(void) aux++; if (strcmp(opts.lsm_profile, "apparmor") == 0) { - if (lsmtype != LSMTYPE__APPARMOR) { + if (kdat.lsm != LSMTYPE__APPARMOR) { pr_err("apparmor LSM specified but apparmor not supported by kernel\n"); return -1; } opts.lsm_profile = aux; } else if (strcmp(opts.lsm_profile, "selinux") == 0) { - if (lsmtype != LSMTYPE__SELINUX) { + if (kdat.lsm != LSMTYPE__SELINUX) { pr_err("selinux LSM specified but selinux not supported by kernel\n"); return -1; } From f25fda8431fc75c499cf0c5dafcac0469e18e2d5 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 28 Jun 2017 08:49:36 +0300 Subject: [PATCH 0607/4375] criu: Version 3.2.1 This is a hot-fix with a regression fix and an urgent support for the latest-n-greatest kernel API change. Signed-off-by: Pavel Emelyanov --- Makefile.versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.versions b/Makefile.versions index e0aa2f5e9..b6e17e55d 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -2,7 +2,7 @@ # CRIU version. CRIU_VERSION_MAJOR := 3 CRIU_VERSION_MINOR := 2 -CRIU_VERSION_SUBLEVEL := +CRIU_VERSION_SUBLEVEL := 1 CRIU_VERSION_EXTRA := CRIU_VERSION_NAME := Tin Hoopoe CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) From 0f5e0bc822fc4d57d895239bfed07b2079ee8ac7 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 15:22:16 +0300 Subject: [PATCH 0608/4375] Add project logo at the top --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b5f8fec50..51a985eb6 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +

+ ## CRIU (Checkpoint and Restore in Userspace) An utility to checkpoint/restore tasks. Using this tool, you can freeze a From b6bb8380db2d258d0666a0bd3ff648f8b981324d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 15:24:47 +0300 Subject: [PATCH 0609/4375] Add licensing info --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 51a985eb6..cba1f6b38 100644 --- a/README.md +++ b/README.md @@ -24,3 +24,7 @@ Pages worth starting with are: * Send all bug reports to [mailing list](https://lists.openvz.org/mailman/listinfo/criu); * Spread the word about CRIU in [social networks](http://criu.org/Contacts); + +### Licence + +The project is licensed under GPLv2 (though files sitting in the lib/ directory are LGPLv2.1). From 149890a8784f47b9a907082e75f5d93c645c0911 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 6 Jul 2017 16:57:44 +0300 Subject: [PATCH 0610/4375] Add information about phaul, soccr and compel --- README.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cba1f6b38..343c63986 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ collection of files. You can then use the files to restore and run the application from the point it was frozen at. The distinctive feature of the CRIU project is that it is mainly implemented in user space. +Also, CRIU provides a library for Live migration, and exposes two low-level +core features as standalone libraries. Thes are libcompel for parasite code +injection and libsoccr for TCP connections checkpoint-restore. + The project home is at http://criu.org. Pages worth starting with are: @@ -18,13 +22,32 @@ Pages worth starting with are: ### A video tour on basic CRIU features [![CRIU introduction](https://asciinema.org/a/7fnt2prsumvxiwf3ng61fgct3.png)](https://asciinema.org/a/7fnt2prsumvxiwf3ng61fgct3) -### How to contribute +## Live migration + +True [live migration](https://criu.org/Live_migration) using CRIU is possible, but doing +all the steps by hands might be complicated. The [phaul sub-project](https://criu.org/P.Haul) +provides a Go library that incapsulates most of the complexity. + +## Parasite code ijection + +In order to get state of the running process CRIU needs to make this process execute +some code, that would fetch the required information. To make this happen without +killing the application itself, CRIU uses the [parasite code injection](https://criu.org/Parasite_code) +technique, which is also available as a standalone library called [libcompel](https://criu.org/Compel). + +## TCP sockets checkpoint-restore + +One of the CRIu features is the ability to save and restore state of a TCP socket +without breaking the connection. This functionality is considered to be useful by +tiself, and we have it available as the [libsoccr library](https://criu.org/Libsoccr). + +## How to contribute * [How to submit patches](http://criu.org/How_to_submit_patches); * Send all bug reports to [mailing list](https://lists.openvz.org/mailman/listinfo/criu); * Spread the word about CRIU in [social networks](http://criu.org/Contacts); -### Licence +## Licence The project is licensed under GPLv2 (though files sitting in the lib/ directory are LGPLv2.1). From 4c332970bd25ac34049026ff036c94d68cc40934 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 4 May 2017 21:42:36 +0300 Subject: [PATCH 0611/4375] images: Implement collect_images() to minimaze code lines Pack repeated actions in one. Also, fixed the "return -1" from the middle of restore_task_with_children(), while cleanup is need. v2: goto err in case of error instead of return -1. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 19 +++++-------------- criu/include/protobuf.h | 10 ++++++++++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index cfc8f5042..274259234 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -320,7 +320,7 @@ static int run_post_prepare(void) static int root_prepare_shared(void) { - int ret = 0, i; + int ret = 0; struct pstree_item *pi; pr_info("Preparing info about shared resources\n"); @@ -331,11 +331,8 @@ static int root_prepare_shared(void) if (prepare_seccomp_filters()) return -1; - for (i = 0; i < ARRAY_SIZE(cinfos); i++) { - ret = collect_image(cinfos[i]); - if (ret) - return -1; - } + if (collect_images(cinfos, ARRAY_SIZE(cinfos))) + return -1; for_each_pstree_item(pi) { if (pi->pid->state == TASK_HELPER) @@ -1505,8 +1502,6 @@ static int restore_task_with_children(void *_arg) /* Restore root task */ if (current->parent == NULL) { - int i; - if (fdstore_init()) goto err; @@ -1526,12 +1521,8 @@ static int restore_task_with_children(void *_arg) if (mount_proc()) goto err; - for (i = 0; i < ARRAY_SIZE(before_ns_cinfos); i++) { - ret = collect_image(before_ns_cinfos[i]); - if (ret) - return -1; - } - + if (collect_images(before_ns_cinfos, ARRAY_SIZE(before_ns_cinfos))) + goto err; if (prepare_namespace(current, ca->clone_flags)) goto err; diff --git a/criu/include/protobuf.h b/criu/include/protobuf.h index 1afeed121..6097ba0bb 100644 --- a/criu/include/protobuf.h +++ b/criu/include/protobuf.h @@ -41,4 +41,14 @@ struct collect_image_info { extern int collect_image(struct collect_image_info *); +static inline int collect_images(struct collect_image_info **array, unsigned size) +{ + int i; + for (i = 0; i < size; i++) { + if (collect_image(array[i])) + return -1; + } + return 0; +} + #endif /* __CR_PROTOBUF_H__ */ From 2c37042821906f013634e305899cb25ff1a5a7b1 Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Fri, 2 Jun 2017 09:30:22 +0300 Subject: [PATCH 0612/4375] tcp: Add tcp-close option to restore connected TCP sockets in closed state New restore option 'tcp-close' was introduced. It restores all connected TCP sockets in TCP_CLOSE state. Here we consider tcp sockets in TCP_ESTABLISHED, TCP_FIN_WAIT2, TCP_FIN_WAIT1, TCP_CLOSE_WAIT, TCP_LAST_ACK, TCP_CLOSING, TCP_SYN_SENT states as connected sockets. This is consistent with current CRIU usage of these states. Thus this option doesn't affect sockets with original states of TCP_LISTEN and TCP_CLOSE. Signed-off-by: Pavel Begunkov Signed-off-by: Eugene Batalov Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 3 +++ criu/crtools.c | 5 +++++ criu/include/cr_options.h | 1 + criu/include/sk-inet.h | 1 + criu/sk-inet.c | 2 +- criu/sk-tcp.c | 6 ++++++ 6 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index b121f8b2b..779bca095 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -264,6 +264,9 @@ For example, the command line for the above example should look like this: The TCP stack on the client side is expected to handle the re-connect gracefully. +*--tcp-close*:: + Restore connected TCP sockets in closed state. + *--evasive-devices*:: Use any path to a device file if the original one is inaccessible. diff --git a/criu/crtools.c b/criu/crtools.c index 5213a6ff5..c3950cb16 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -290,6 +290,7 @@ int main(int argc, char *argv[], char *envp[]) BOOL_OPT("display-stats", &opts.display_stats), BOOL_OPT("weak-sysctls", &opts.weak_sysctls), { "status-fd", required_argument, 0, 1088 }, + { SK_CLOSE_PARAM, no_argument, 0, 1089 }, { }, }; @@ -568,6 +569,9 @@ int main(int argc, char *argv[], char *envp[]) return 1; } break; + case 1089: + opts.tcp_close = true; + break; case 'V': pr_msg("Version: %s\n", CRIU_VERSION); if (strcmp(CRIU_GITID, "0")) @@ -826,6 +830,7 @@ usage: "* Special resources support:\n" " --" SK_EST_PARAM " checkpoint/restore established TCP connections\n" " --" SK_INFLIGHT_PARAM " skip (ignore) in-flight TCP connections\n" +" --" SK_CLOSE_PARAM " restore connected TCP sockets in closed state\n" " -r|--root PATH change the root filesystem (when run in mount namespace)\n" " --evasive-devices use any path to a device file if the original one\n" " is inaccessible\n" diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index c879de97a..45ee6cb1b 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -63,6 +63,7 @@ struct cr_options { int shell_job; int handle_file_locks; int tcp_established_ok; + bool tcp_close; int evasive_devices; int link_remap_ok; int log_file_per_pid; diff --git a/criu/include/sk-inet.h b/criu/include/sk-inet.h index bf6fb1d77..3b302ff70 100644 --- a/criu/include/sk-inet.h +++ b/criu/include/sk-inet.h @@ -75,6 +75,7 @@ extern int restore_one_tcp(int sk, struct inet_sk_info *si); #define SK_EST_PARAM "tcp-established" #define SK_INFLIGHT_PARAM "skip-in-flight" +#define SK_CLOSE_PARAM "tcp-close" struct task_restore_args; int prepare_tcp_socks(struct task_restore_args *); diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 046d04be5..7ad4cd993 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -648,7 +648,7 @@ static int open_inet_sk(struct file_desc *d, int *new_fd) goto err; if (tcp_connection(ie)) { - if (!opts.tcp_established_ok) { + if (!opts.tcp_established_ok && !opts.tcp_close) { pr_err("Connected TCP socket in image\n"); goto err; } diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c index 3acc71093..20ea528bb 100644 --- a/criu/sk-tcp.c +++ b/criu/sk-tcp.c @@ -8,6 +8,7 @@ #include "../soccr/soccr.h" +#include "cr_options.h" #include "util.h" #include "common/list.h" #include "log.h" @@ -407,6 +408,11 @@ int restore_one_tcp(int fd, struct inet_sk_info *ii) pr_info("Restoring TCP connection\n"); + if (opts.tcp_close && + ii->ie->state != TCP_LISTEN && ii->ie->state != TCP_CLOSE) { + return 0; + } + sk = libsoccr_pause(fd); if (!sk) return -1; From 0f5e2217ef9df00573bf66154e7a797ea4064ab1 Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Fri, 2 Jun 2017 09:32:27 +0300 Subject: [PATCH 0613/4375] zdtm: Check that 'tcp-close' option closes sockets There are 2 test cases: 1. Connected socket should be restored in the closed state 2. Listening socket state should not change after restore Signed-off-by: Pavel Begunkov Signed-off-by: Eugene Batalov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 2 + test/zdtm/static/socket-tcp-close0.c | 72 +++++++++++++++++++++++++ test/zdtm/static/socket-tcp-close0.desc | 1 + test/zdtm/static/socket-tcp-close1.c | 50 +++++++++++++++++ test/zdtm/static/socket-tcp-close1.desc | 1 + 5 files changed, 126 insertions(+) create mode 100644 test/zdtm/static/socket-tcp-close0.c create mode 100644 test/zdtm/static/socket-tcp-close0.desc create mode 100644 test/zdtm/static/socket-tcp-close1.c create mode 120000 test/zdtm/static/socket-tcp-close1.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 26cb6eaf2..909adf557 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -82,6 +82,8 @@ TST_NOFILE := \ socket-tcp-closed \ socket-tcp-closed-last-ack \ socket-tcp6-closed \ + socket-tcp-close0 \ + socket-tcp-close1 \ socket-tcp-unconn \ socket-tcp6-unconn \ socket-tcp-syn-sent \ diff --git a/test/zdtm/static/socket-tcp-close0.c b/test/zdtm/static/socket-tcp-close0.c new file mode 100644 index 000000000..2bc0f64f9 --- /dev/null +++ b/test/zdtm/static/socket-tcp-close0.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check that tcp-close option closes connected tcp socket"; +const char *test_author = "Pavel Begunkov "; + +static int port = 8880; + +static int check_socket_closed(int sk) +{ + int err, buffer = 0; + struct tcp_info info; + socklen_t len = sizeof(info); + + err = getsockopt(sk, IPPROTO_TCP, TCP_INFO, (void *)&info, &len); + if (err != 0) { + pr_perror("Can't get socket state\n"); + return -1; + } else if (info.tcpi_state != TCP_CLOSE) { + pr_err("Invalid socket state (%i)\n", (int)info.tcpi_state); + return -1; + } + + err = recv(sk, &buffer, sizeof(buffer), 0); + if (!err || errno != ENOTCONN) { + pr_perror("Invalid recv response\n"); + return -1; + } + return 0; +} + +int main(int argc, char **argv) +{ + int fd, fd_s, clt; + + test_init(argc, argv); + + fd_s = tcp_init_server(AF_INET, &port); + if (fd_s < 0) { + pr_err("Server initializations failed\n"); + return 1; + } + clt = tcp_init_client(AF_INET, "localhost", port); + if (clt < 0) + return 1; + + fd = tcp_accept_server(fd_s); + if (fd < 0) { + pr_err("Can't accept client connection\n"); + return 1; + } + close(fd_s); + + test_daemon(); + test_waitsig(); + + if (check_socket_closed(fd)) { + fail("Server socket isn't closed\n"); + return 1; + } + if (check_socket_closed(clt)) { + fail("Client socket isn't closed\n"); + return 1; + } + pass(); + return 0; +} diff --git a/test/zdtm/static/socket-tcp-close0.desc b/test/zdtm/static/socket-tcp-close0.desc new file mode 100644 index 000000000..e85de0e66 --- /dev/null +++ b/test/zdtm/static/socket-tcp-close0.desc @@ -0,0 +1 @@ +{'dopts': '--tcp-established', 'ropts': '--tcp-close'} diff --git a/test/zdtm/static/socket-tcp-close1.c b/test/zdtm/static/socket-tcp-close1.c new file mode 100644 index 000000000..54511a341 --- /dev/null +++ b/test/zdtm/static/socket-tcp-close1.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check that tcp-close option doesn't close listening tcp socket"; +const char *test_author = "Pavel Begunkov "; + +static int port = 8880; + +static int check_socket_state(int sk, int state) +{ + int err; + struct tcp_info info; + socklen_t len = sizeof(info); + + err = getsockopt(sk, IPPROTO_TCP, TCP_INFO, (void *)&info, &len); + if (err != 0) { + pr_perror("Can't get socket state\n"); + return -1; + } + return info.tcpi_state == state ? 0 : -1; +} + +int main(int argc, char **argv) +{ + int fd_s; + + test_init(argc, argv); + + fd_s = tcp_init_server(AF_INET, &port); + if (fd_s < 0) { + pr_err("Server initializations failed\n"); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (check_socket_state(fd_s, TCP_LISTEN)) { + fail("Listen socket state is changed\n"); + close(fd_s); + return 1; + } + close(fd_s); + pass(); + return 0; +} diff --git a/test/zdtm/static/socket-tcp-close1.desc b/test/zdtm/static/socket-tcp-close1.desc new file mode 120000 index 000000000..836b8fa51 --- /dev/null +++ b/test/zdtm/static/socket-tcp-close1.desc @@ -0,0 +1 @@ +socket-tcp-close0.desc \ No newline at end of file From 3299759865ff15d86400059d45c8cf897042741d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 29 May 2017 15:59:08 +0300 Subject: [PATCH 0614/4375] x86/ia32: fix build with DEBUG=1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC isn't happy if we use %rbp as register for local variable with -ggdb3 option. Which resulted in the following build error for `make DEBUG=1`: > In file included from criu/arch/x86/crtools.c:10:0: > criu/arch/x86/include/asm/compat.h: In function ‘do_full_int80’: > criu/arch/x86/include/asm/compat.h:50:1: error: bp cannot be used in asm here Fix it by saving/restoring %rbp around 32-bit syscall manually. Just while at it - add a comment about r8-r11 clobbers. Reported-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/arch/x86/include/asm/compat.h | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/criu/arch/x86/include/asm/compat.h b/criu/arch/x86/include/asm/compat.h index cad5d0ff7..dce28adf6 100644 --- a/criu/arch/x86/include/asm/compat.h +++ b/criu/arch/x86/include/asm/compat.h @@ -40,13 +40,24 @@ struct syscall_args32 { static inline void do_full_int80(struct syscall_args32 *args) { - register unsigned long bp asm("bp") = args->arg5; - asm volatile ("int $0x80" + /* + * r8-r11 registers are cleared during returning to userspace + * from syscall - that's x86_64 ABI to avoid leaking kernel + * pointers. + * + * Other than that - we can't use %rbp in clobbers as GCC's inline + * assembly doesn't allow to do so. So, here is explicitly saving + * %rbp before syscall and restoring it's value afterward. + */ + asm volatile ("pushq %%rbp\n\t" + "mov %6, %%ebp\n\t" + "int $0x80\n\t" + "mov %%ebp, %6\n\t" + "popq %%rbp\n\t" : "+a" (args->nr), "+b" (args->arg0), "+c" (args->arg1), "+d" (args->arg2), - "+S" (args->arg3), "+D" (args->arg4), "+r" (bp) + "+S" (args->arg3), "+D" (args->arg4), "+g" (args->arg5) : : "r8", "r9", "r10", "r11"); - args->arg5 = bp; } From 1ddcd443baf5e04ace3804f9e0afccd1c8d97e5a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 1 Jun 2017 11:45:10 +0300 Subject: [PATCH 0615/4375] test: shm-unaligned -- Use unique key For convenient simultaneous run. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 2 ++ test/zdtm/static/shm.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 909adf557..50783ea81 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -454,6 +454,8 @@ socket-tcp6-unconn: CFLAGS += -D ZDTM_IPV6 pty-console: CFLAGS += -D ZDTM_DEV_CONSOLE +shm-unaligned: CFLAGS += -DZDTM_SHM_UNALIGNED + $(LIB): force $(Q) $(MAKE) -C $(LIBDIR) diff --git a/test/zdtm/static/shm.c b/test/zdtm/static/shm.c index d03332135..a177e3561 100644 --- a/test/zdtm/static/shm.c +++ b/test/zdtm/static/shm.c @@ -111,7 +111,11 @@ int main(int argc, char **argv) test_init(argc, argv); +#ifdef ZDTM_SHM_UNALIGNED key = ftok(argv[0], 822155666); +#else + key = ftok(argv[0], 822155667); +#endif if (key == -1) { pr_perror("Can't make key"); goto out; From c3cff79cd6ddd43c810d54dccf58e3531ee1cdc4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 15 Jun 2017 19:04:11 +0300 Subject: [PATCH 0616/4375] ghost: Fixup mkreg_ghost prototype We don't need gf there, but will need more than just mode. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 095e8f7f0..999252abe 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -142,11 +142,11 @@ static int trim_last_parent(char *path) return 0; } -static int mkreg_ghost(char *path, u32 mode, struct ghost_file *gf, struct cr_img *img) +static int mkreg_ghost(char *path, GhostFileEntry *gfe, struct cr_img *img) { int gfd, ret; - gfd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode); + gfd = open(path, O_WRONLY | O_CREAT | O_EXCL, gfe->mode); if (gfd < 0) return -1; @@ -218,7 +218,7 @@ again: if ((ret = mkdirpat(AT_FDCWD, path, gfe->mode)) < 0) msg = "Can't make ghost dir"; } else { - if ((ret = mkreg_ghost(path, gfe->mode, gf, img)) < 0) + if ((ret = mkreg_ghost(path, gfe, img)) < 0) msg = "Can't create ghost regfile"; } From 0ce86c360773895821699b4071a33bf1bba81de5 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 15 Jun 2017 19:04:30 +0300 Subject: [PATCH 0617/4375] ghost: Add chunked ghost files If the ghost file is too big, it might make sence to try seeking for holes in it, thus reducing the image size. We've seen this once for tmpfs files in issue #230. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 140 ++++++++++++++++++++++++++++++++++- criu/include/protobuf-desc.h | 1 + images/ghost-file.proto | 7 ++ 3 files changed, 146 insertions(+), 2 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 999252abe..689891899 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -9,9 +9,15 @@ #include #include #include +#include #include #include +#ifndef SEEK_DATA +#define SEEK_DATA 3 +#define SEEK_HOLE 4 +#endif + /* Stolen from kernel/fs/nfs/unlink.c */ #define SILLYNAME_PREF ".nfs" #define SILLYNAME_SUFF_LEN (((unsigned)sizeof(u64) << 1) + ((unsigned)sizeof(unsigned int) << 1)) @@ -142,6 +148,115 @@ static int trim_last_parent(char *path) return 0; } +#define BUFSIZE (4096) + +static int copy_chunk_from_file(int fd, int img, off_t off, size_t len) +{ + char *buf = NULL; + int ret; + + while (len > 0) { + ret = sendfile(img, fd, &off, len); + if (ret <= 0) { + pr_perror("Can't send ghost to image"); + return -1; + } + + len -= ret; + } + + xfree(buf); + + return 0; +} + +static int copy_file_to_chunks(int fd, struct cr_img *img, size_t file_size) +{ + GhostChunkEntry ce = GHOST_CHUNK_ENTRY__INIT; + off_t data, hole = 0; + + while (hole < file_size) { + data = lseek(fd, hole, SEEK_DATA); + if (data < 0) { + if (errno == ENXIO) + /* No data */ + break; + else if (hole == 0) { + /* No SEEK_HOLE/DATA by FS */ + data = 0; + hole = file_size; + } else { + pr_perror("Can't seek file data"); + return -1; + } + } else { + hole = lseek(fd, data, SEEK_HOLE); + if (hole < 0) { + pr_perror("Can't seek file hole"); + return -1; + } + } + + ce.len = hole - data; + ce.off = data; + + if (pb_write_one(img, &ce, PB_GHOST_CHUNK)) + return -1; + + if (copy_chunk_from_file(fd, img_raw_fd(img), ce.off, ce.len)) + return -1; + } + + return 0; +} + +static int copy_chunk_to_file(int img, int fd, off_t off, size_t len) +{ + char *buf = NULL; + int ret; + + while (len > 0) { + if (lseek(fd, off, SEEK_SET) < 0) { + pr_perror("Can't seek file"); + return -1; + } + ret = sendfile(fd, img, NULL, len); + if (ret < 0) { + pr_perror("Can't send data"); + return -1; + } + + off += ret; + len -= ret; + } + + xfree(buf); + + return 0; +} + +static int copy_file_from_chunks(struct cr_img *img, int fd, size_t file_size) +{ + if (ftruncate(fd, file_size) < 0) { + pr_perror("Can't make file size"); + return -1; + } + + while (1) { + int ret; + GhostChunkEntry *ce; + + ret = pb_read_one_eof(img, &ce, PB_GHOST_CHUNK); + if (ret <= 0) + return ret; + + if (copy_chunk_to_file(img_raw_fd(img), fd, ce->off, ce->len)) + return -1; + + ghost_chunk_entry__free_unpacked(ce, NULL); + } +} + static int mkreg_ghost(char *path, GhostFileEntry *gfe, struct cr_img *img) { int gfd, ret; @@ -150,7 +265,15 @@ static int mkreg_ghost(char *path, GhostFileEntry *gfe, struct cr_img *img) if (gfd < 0) return -1; - ret = copy_file(img_raw_fd(img), gfd, 0); + if (gfe->chunks) { + if (!gfe->has_size) { + pr_err("Corrupted ghost image -> no size\n"); + return -1; + } + + ret = copy_file_from_chunks(img, gfd, gfe->size); + } else + ret = copy_file(img_raw_fd(img), gfd, 0); if (ret < 0) unlink(path); close(gfd); @@ -587,6 +710,9 @@ static struct collect_image_info remap_cinfo = { .collect = collect_one_remap, }; +/* Tiny files don't need to generate chunks in ghost image. */ +#define GHOST_CHUNKS_THRESH (3 * 4096) + static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_dev) { struct cr_img *img; @@ -619,6 +745,12 @@ static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_de gfe.rdev = st->st_rdev; } + if (S_ISREG(st->st_mode) && (st->st_size >= GHOST_CHUNKS_THRESH)) { + gfe.has_chunks = gfe.chunks = true; + gfe.has_size = true; + gfe.size = st->st_size; + } + if (pb_write_one(img, &gfe, PB_GHOST_FILE)) return -1; @@ -636,7 +768,11 @@ static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_de pr_perror("Can't open ghost original file"); return -1; } - ret = copy_file(fd, img_raw_fd(img), st->st_size); + + if (gfe.chunks) + ret = copy_file_to_chunks(fd, img, st->st_size); + else + ret = copy_file(fd, img_raw_fd(img), st->st_size); close(fd); if (ret) return -1; diff --git a/criu/include/protobuf-desc.h b/criu/include/protobuf-desc.h index 6c76b494f..023047de5 100644 --- a/criu/include/protobuf-desc.h +++ b/criu/include/protobuf-desc.h @@ -59,6 +59,7 @@ enum { PB_BINFMT_MISC, /* 50 */ PB_TTY_DATA, PB_AUTOFS, + PB_GHOST_CHUNK, /* PB_AUTOGEN_STOP */ diff --git a/images/ghost-file.proto b/images/ghost-file.proto index 4b3415b68..eda466451 100644 --- a/images/ghost-file.proto +++ b/images/ghost-file.proto @@ -13,4 +13,11 @@ message ghost_file_entry { optional uint32 rdev = 6 [(criu).dev = true, (criu).odev = true]; optional timeval atim = 7; optional timeval mtim = 8; + optional bool chunks = 9; + optional uint64 size = 10; +} + +message ghost_chunk_entry { + required uint64 len = 1; + required uint64 off = 2; } From c7ab0cd934d3f4cff22f1791abf0ff2438c60772 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 15 Jun 2017 19:04:46 +0300 Subject: [PATCH 0618/4375] crit: Add support for chunked ghost images Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- lib/py/images/images.py | 80 +++++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 14 deletions(-) diff --git a/lib/py/images/images.py b/lib/py/images/images.py index 0edbe80ea..894e1c2c0 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -220,6 +220,71 @@ class pagemap_handler: def count(self, f): return entry_handler(None).count(f) - 1 +# Special handler for ghost-file.img +class ghost_file_handler: + def load(self, f, pretty = False, no_payload = False): + entries = [] + + gf = ghost_file_entry() + buf = f.read(4) + size, = struct.unpack('i', buf) + gf.ParseFromString(f.read(size)) + g_entry = pb2dict.pb2dict(gf, pretty) + + if gf.chunks: + entries.append(g_entry) + while True: + gc = ghost_chunk_entry() + buf = f.read(4) + if buf == '': + break + size, = struct.unpack('i', buf) + gc.ParseFromString(f.read(size)) + entry = pb2dict.pb2dict(gc, pretty) + if no_payload: + f.seek(gc.len, os.SEEK_CUR) + else: + entry['extra'] = f.read(gc.len).encode('base64') + entries.append(entry) + else: + if no_payload: + f.seek(0, os.SEEK_END) + else: + g_entry['extra'] = f.read().encode('base64') + entries.append(g_entry) + + return entries + + def loads(self, s, pretty = False): + f = io.BytesIO(s) + return self.load(f, pretty) + + def dump(self, entries, f): + pb = ghost_file_entry() + item = entries.pop(0) + pb2dict.dict2pb(item, pb) + pb_str = pb.SerializeToString() + size = len(pb_str) + f.write(struct.pack('i', size)) + f.write(pb_str) + + if pb.chunks: + for item in entries: + pb = ghost_chunk_entry() + pb2dict.dict2pb(item, pb) + pb_str = pb.SerializeToString() + size = len(pb_str) + f.write(struct.pack('i', size)) + f.write(pb_str) + f.write(item['extra'].decode('base64')) + else: + f.write(item['extra'].decode('base64')) + + def dumps(self, entries): + f = io.BytesIO('') + self.dump(entries, f) + return f.read() + # In following extra handlers we use base64 encoding # to store binary data. Even though, the nature @@ -255,19 +320,6 @@ class sk_queues_extra_handler: f.seek(pload.length, os.SEEK_CUR) return pload.length -class ghost_file_extra_handler: - def load(self, f, pb): - data = f.read() - return data.encode('base64') - - def dump(self, extra, f, pb): - data = extra.decode('base64') - f.write(data) - - def skip(self, f, pb): - p = f.tell() - f.seek(0, os.SEEK_END) - return f.tell() - p class tcp_stream_extra_handler: def load(self, f, pb): @@ -404,7 +456,7 @@ handlers = { 'UTSNS' : entry_handler(utsns_entry), 'IPC_VAR' : entry_handler(ipc_var_entry), 'FS' : entry_handler(fs_entry), - 'GHOST_FILE' : entry_handler(ghost_file_entry, ghost_file_extra_handler()), + 'GHOST_FILE' : ghost_file_handler(), 'MM' : entry_handler(mm_entry), 'CGROUP' : entry_handler(cgroup_entry), 'TCP_STREAM' : entry_handler(tcp_stream_entry, tcp_stream_extra_handler()), From d8dd470367aa5c34e039113d56f892a9a43a3fb0 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 15 Jun 2017 19:05:03 +0300 Subject: [PATCH 0619/4375] zdtm: Tests for ghost files with holes Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 5 + test/zdtm/static/ghost_holes00.c | 163 +++++++++++++++++++++++++++++++ test/zdtm/static/ghost_holes01.c | 1 + test/zdtm/static/ghost_holes02.c | 1 + 4 files changed, 170 insertions(+) create mode 100644 test/zdtm/static/ghost_holes00.c create mode 120000 test/zdtm/static/ghost_holes01.c create mode 120000 test/zdtm/static/ghost_holes02.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 50783ea81..08cc3d9cc 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -196,6 +196,9 @@ TST_FILE = \ unlink_fstat01+ \ unlink_fstat02 \ unlink_fstat03 \ + ghost_holes00 \ + ghost_holes01 \ + ghost_holes02 \ unlink_largefile \ mtime_mmap \ fifo \ @@ -431,6 +434,8 @@ mlock_setuid: get_smaps_bits.o inotify01: CFLAGS += -DINOTIFY01 unlink_fstat01+: CFLAGS += -DUNLINK_OVER unlink_fstat04: CFLAGS += -DUNLINK_FSTAT04 +ghost_holes01: CFLAGS += -DTAIL_HOLE +ghost_holes02: CFLAGS += -DHEAD_HOLE sk-freebind-false: CFLAGS += -DZDTM_FREEBIND_FALSE stopped01: CFLAGS += -DZDTM_STOPPED_KILL stopped02: CFLAGS += -DZDTM_STOPPED_TKILL diff --git a/test/zdtm/static/ghost_holes00.c b/test/zdtm/static/ghost_holes00.c new file mode 100644 index 000000000..11561d9fe --- /dev/null +++ b/test/zdtm/static/ghost_holes00.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Test ghost with one hole in the middle"; + +char *filename; +TEST_OPTION(filename, string, "file name", 1); + +/* Buffer that is suitable for hole size */ +#define BUFSIZE 4096 +static unsigned char buf4k[BUFSIZE]; + +#ifdef HEAD_HOLE +#define HH 1 +#else +#define HH 0 +#endif + +#ifdef TAIL_HOLE +#define TH 1 +#else +#define TH 0 +#endif + +#define DATA1_BLK (HH) +#define DATA1_OFF (DATA1_BLK * BUFSIZE) +#define DATA2_BLK (HH + 2) +#define DATA2_OFF (DATA2_BLK * BUFSIZE) +#define FILE_BLOCKS (TH + HH + 1 /* mid hole */ + 2 /* data */) +#define FILE_SIZE (FILE_BLOCKS * BUFSIZE) + +int main(int argc, char ** argv) +{ + int fd; + struct stat st; + uint32_t crc; + bool chk_hole = true; + + test_init(argc, argv); + + fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644); + if (fd < 0) { + pr_perror("can't open %s", filename); + exit(1); + } + + if (unlink(filename) < 0) { + pr_perror("can't unlink %s", filename); + goto failed; + } + + crc = ~0; + datagen(buf4k, BUFSIZE, &crc); + if (pwrite(fd, buf4k, BUFSIZE, DATA1_OFF) != BUFSIZE) { + pr_perror("can't write data1"); + goto failed; + } + + crc = ~0; + datagen(buf4k, BUFSIZE, &crc); + if (pwrite(fd, buf4k, BUFSIZE, DATA2_OFF) != BUFSIZE) { + pr_perror("can't write data2"); + goto failed; + } + + if (ftruncate(fd, FILE_SIZE)) { + pr_perror("Can't fixup file size"); + goto failed; + } + + if (lseek(fd, DATA1_OFF, SEEK_HOLE) != DATA1_OFF + BUFSIZE) { + test_msg("Won't check for hole\n"); + chk_hole = false; + } + + test_daemon(); + test_waitsig(); + + if (fstat(fd, &st) < 0) { + fail("can't stat after"); + goto failed; + } + + if (st.st_size != FILE_SIZE) { + fail("file size changed to %ld", (long)st.st_size); + goto failed; + } + + test_msg("Blocks %u OK\n", FILE_BLOCKS); + + /* Data 1 */ + if (pread(fd, buf4k, BUFSIZE, DATA1_OFF) != BUFSIZE) { + fail("pread1 fail"); + goto failed; + } + + crc = ~0; + if (datachk(buf4k, BUFSIZE, &crc)) { + fail("datachk1 fail"); + goto failed; + } + + test_msg("Data @%u OK\n", DATA1_BLK); + + /* Data 2 */ + if (pread(fd, buf4k, BUFSIZE, DATA2_OFF) != BUFSIZE) { + fail("pread2 fail"); + goto failed; + } + + crc = ~0; + if (datachk(buf4k, BUFSIZE, &crc)) { + fail("datachk2 fail"); + goto failed; + } + + test_msg("Data @%u OK\n", DATA2_BLK); + + /* Hole */ + if (chk_hole) { +#ifdef HEAD_HOLE + if (lseek(fd, 0, SEEK_HOLE) != 0) { + fail("hh not found"); + goto failed; + } + + test_msg("Head hole OK\n"); +#endif + + if (lseek(fd, DATA1_OFF, SEEK_HOLE) != DATA1_OFF + BUFSIZE) { + fail("mh not found"); + goto failed; + } + + test_msg("Mid hole OK\n"); + +#ifdef TAIL_HOLE + if (lseek(fd, DATA2_OFF, SEEK_HOLE) != DATA2_OFF + BUFSIZE) { + fail("tail hole not found"); + goto failed; + } + + test_msg("Tail hole OK\n"); +#endif + } + + close(fd); + pass(); + return 0; + +failed: + close(fd); + return 1; +} diff --git a/test/zdtm/static/ghost_holes01.c b/test/zdtm/static/ghost_holes01.c new file mode 120000 index 000000000..82bf9de6c --- /dev/null +++ b/test/zdtm/static/ghost_holes01.c @@ -0,0 +1 @@ +ghost_holes00.c \ No newline at end of file diff --git a/test/zdtm/static/ghost_holes02.c b/test/zdtm/static/ghost_holes02.c new file mode 120000 index 000000000..82bf9de6c --- /dev/null +++ b/test/zdtm/static/ghost_holes02.c @@ -0,0 +1 @@ +ghost_holes00.c \ No newline at end of file From 5cac11310f223719ab4a457f5cb90c064f07cd0d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 19 Jun 2017 17:03:30 +0300 Subject: [PATCH 0620/4375] fsnotify: Fix bad field name in list iterations Surprisingly, but offsetof(inotify_wd_entry, node) == offsetof(fanotify_mark_entry, node) even though both structures have node field in the middle and the fields sitting above one are totally different. So the code works, but ... we're risking :) Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/fsnotify.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index e3d62e54a..3c71bf3ac 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -468,7 +468,7 @@ static int dump_one_fanotify(int lfd, u32 id, const struct fd_parms *p) goto free; i = 0; - list_for_each_entry(we, &wd_list.list, ify.node) + list_for_each_entry(we, &wd_list.list, ffy.node) fe.mark[i++] = &we->ffy.e; fe.n_mark = wd_list.n; @@ -480,7 +480,7 @@ static int dump_one_fanotify(int lfd, u32 id, const struct fd_parms *p) ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FANOTIFY_FILE), &fe, PB_FANOTIFY_FILE); free: xfree(fe.mark); - list_for_each_entry_safe(we, tmp, &wd_list.list, ify.node) + list_for_each_entry_safe(we, tmp, &wd_list.list, ffy.node) free_fanotify_mark_entry(we); return ret; } From beda098364d3ebb842bfc427bd0b8ec67c056ce2 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Mon, 15 May 2017 21:17:08 -0700 Subject: [PATCH 0621/4375] compel: be silent if no errors In case of success, we want to be silent when on default log level. This is a time-honored UNIX tradition, who we are to break it? Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/src/main.c b/compel/src/main.c index 4f53e7e5d..1171478cb 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -103,7 +103,7 @@ err: if (opts.fout) fclose(opts.fout); if (!ret) - printf("%s generated successfully.\n", opts.output_filename); + pr_info("%s generated successfully.\n", opts.output_filename); return ret; } From 0dcb780a8fd9102aa215674c3dcd38e60815d117 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 27 Jun 2017 12:51:02 +0300 Subject: [PATCH 0622/4375] utils: Add "test/zdtm/lib" directory definitions to tags file Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 82acb2b47..e2d89e3e4 100644 --- a/Makefile +++ b/Makefile @@ -299,22 +299,23 @@ criu-$(tar-name).tar.bz2: dist tar: criu-$(tar-name).tar.bz2 ; .PHONY: dist tar +TAGS_FILES_REGEXP := . -name '*.[hcS]' ! -path './.*' \( ! -path './test/*' -o -path './test/zdtm/lib/*' \) tags: $(call msg-gen, $@) $(Q) $(RM) tags - $(Q) $(FIND) . -name '*.[hcS]' ! -path './.*' ! -path './test/*' -print | xargs $(CTAGS) -a + $(Q) $(FIND) $(TAGS_FILES_REGEXP) -print | xargs $(CTAGS) -a .PHONY: tags etags: $(call msg-gen, $@) $(Q) $(RM) TAGS - $(Q) $(FIND) . -name '*.[hcS]' ! -path './.*' ! -path './test/*' -print | xargs $(ETAGS) -a + $(Q) $(FIND) $(TAGS_FILES_REGEXP) -print | xargs $(ETAGS) -a .PHONY: etags cscope: $(call msg-gen, $@) - $(Q) $(FIND) . -name '*.[hcS]' ! -path './.*' ! -path './test/*' ! -type l -print > cscope.files + $(Q) $(FIND) $(TAGS_FILES_REGEXP) ! -type l -print > cscope.files $(Q) $(CSCOPE) -bkqu .PHONY: cscope From c94d0cacb44c38e392de13d901212e0184c0c140 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 22 Jun 2017 20:38:36 +0300 Subject: [PATCH 0623/4375] eventfd: Rework parse_fdinfo not to use callback Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-check.c | 17 ++++++----------- criu/eventfd.c | 39 ++++++++++++--------------------------- criu/include/fdinfo.h | 1 - criu/proc_parse.c | 7 ++----- 4 files changed, 20 insertions(+), 44 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index cd23f7863..cd989fb03 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -272,16 +272,11 @@ static int check_proc_stat(void) return 0; } -static int check_one_fdinfo(union fdinfo_entries *e, void *arg) -{ - *(int *)arg = (int)e->efd.counter; - return 0; -} - static int check_fdinfo_eventfd(void) { int fd, ret; - int cnt = 13, proc_cnt = 0; + int cnt = 13; + EventfdFileEntry fe = EVENTFD_FILE_ENTRY__INIT; fd = eventfd(cnt, 0); if (fd < 0) { @@ -289,7 +284,7 @@ static int check_fdinfo_eventfd(void) return -1; } - ret = parse_fdinfo(fd, FD_TYPES__EVENTFD, check_one_fdinfo, &proc_cnt); + ret = parse_fdinfo(fd, FD_TYPES__EVENTFD, NULL, &fe); close(fd); if (ret) { @@ -297,13 +292,13 @@ static int check_fdinfo_eventfd(void) return -1; } - if (proc_cnt != cnt) { + if (fe.counter != cnt) { pr_err("Counter mismatch (or not met) %d want %d\n", - proc_cnt, cnt); + (int)fe.counter, cnt); return -1; } - pr_info("Eventfd fdinfo works OK (%d vs %d)\n", cnt, proc_cnt); + pr_info("Eventfd fdinfo works OK (%d vs %d)\n", cnt, (int)fe.counter); return 0; } diff --git a/criu/eventfd.c b/criu/eventfd.c index 68edb1c56..7212ad4c4 100644 --- a/criu/eventfd.c +++ b/criu/eventfd.c @@ -43,35 +43,20 @@ static void pr_info_eventfd(char *action, EventfdFileEntry *efe) action, efe->id, efe->flags, efe->counter); } -struct eventfd_dump_arg { - u32 id; - const struct fd_parms *p; - bool dumped; -}; - -static int dump_eventfd_entry(union fdinfo_entries *e, void *arg) -{ - struct eventfd_dump_arg *da = arg; - - if (da->dumped) { - pr_err("Several counters in a file?\n"); - return -1; - } - - da->dumped = true; - e->efd.id = da->id; - e->efd.flags = da->p->flags; - e->efd.fown = (FownEntry *)&da->p->fown; - - pr_info_eventfd("Dumping ", &e->efd); - return pb_write_one(img_from_set(glob_imgset, CR_FD_EVENTFD_FILE), - &e->efd, PB_EVENTFD_FILE); -} - static int dump_one_eventfd(int lfd, u32 id, const struct fd_parms *p) { - struct eventfd_dump_arg da = { .id = id, .p = p, }; - return parse_fdinfo(lfd, FD_TYPES__EVENTFD, dump_eventfd_entry, &da); + EventfdFileEntry efd = EVENTFD_FILE_ENTRY__INIT; + + if (parse_fdinfo(lfd, FD_TYPES__EVENTFD, NULL, &efd)) + return -1; + + efd.id = id; + efd.flags = p->flags; + efd.fown = (FownEntry *)&p->fown; + + pr_info_eventfd("Dumping ", &efd); + return pb_write_one(img_from_set(glob_imgset, CR_FD_EVENTFD_FILE), + &efd, PB_EVENTFD_FILE); } const struct fdtype_ops eventfd_dump_ops = { diff --git a/criu/include/fdinfo.h b/criu/include/fdinfo.h index a36e9138b..830b3fcf0 100644 --- a/criu/include/fdinfo.h +++ b/criu/include/fdinfo.h @@ -31,7 +31,6 @@ struct eventpoll_tfd_entry { }; union fdinfo_entries { - EventfdFileEntry efd; SignalfdEntry sfd; struct inotify_wd_entry ify; struct fanotify_mark_entry ffy; diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 5e36db540..9d36fb2fe 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1715,17 +1715,14 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, continue; if (fdinfo_field(str, "eventfd-count")) { - eventfd_file_entry__init(&entry.efd); + EventfdFileEntry *efd = arg; if (type != FD_TYPES__EVENTFD) goto parse_err; ret = sscanf(str, "eventfd-count: %"PRIx64, - &entry.efd.counter); + &efd->counter); if (ret != 1) goto parse_err; - ret = cb(&entry, arg); - if (ret) - goto out; entry_met = true; continue; From 54fb48d715bbecfac4c2a9c2873e23867c77aea3 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 22 Jun 2017 20:38:51 +0300 Subject: [PATCH 0624/4375] signalfd: Rework parse_fdinfo no to use callback Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-check.c | 8 ++------ criu/include/fdinfo.h | 1 - criu/proc_parse.c | 7 ++----- criu/signalfd.c | 37 +++++++++++-------------------------- 4 files changed, 15 insertions(+), 38 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index cd989fb03..7eb5ccc31 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -302,11 +302,6 @@ static int check_fdinfo_eventfd(void) return 0; } -static int check_one_sfd(union fdinfo_entries *e, void *arg) -{ - return 0; -} - int check_mnt_id(void) { struct fdinfo_common fdinfo = { .mnt_id = -1 }; @@ -328,6 +323,7 @@ static int check_fdinfo_signalfd(void) { int fd, ret; sigset_t mask; + SignalfdEntry sfd = SIGNALFD_ENTRY__INIT; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); @@ -337,7 +333,7 @@ static int check_fdinfo_signalfd(void) return -1; } - ret = parse_fdinfo(fd, FD_TYPES__SIGNALFD, check_one_sfd, NULL); + ret = parse_fdinfo(fd, FD_TYPES__SIGNALFD, NULL, &sfd); close(fd); if (ret) { diff --git a/criu/include/fdinfo.h b/criu/include/fdinfo.h index 830b3fcf0..18e85ede2 100644 --- a/criu/include/fdinfo.h +++ b/criu/include/fdinfo.h @@ -31,7 +31,6 @@ struct eventpoll_tfd_entry { }; union fdinfo_entries { - SignalfdEntry sfd; struct inotify_wd_entry ify; struct fanotify_mark_entry ffy; struct eventpoll_tfd_entry epl; diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 9d36fb2fe..674088356 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1768,17 +1768,14 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, continue; } if (fdinfo_field(str, "sigmask")) { - signalfd_entry__init(&entry.sfd); + SignalfdEntry *sfd = arg; if (type != FD_TYPES__SIGNALFD) goto parse_err; ret = sscanf(str, "sigmask: %Lx", - (unsigned long long *)&entry.sfd.sigmask); + (unsigned long long *)&sfd->sigmask); if (ret != 1) goto parse_err; - ret = cb(&entry, arg); - if (ret) - goto out; entry_met = true; continue; diff --git a/criu/signalfd.c b/criu/signalfd.c index 7c3ab4f33..660f510d9 100644 --- a/criu/signalfd.c +++ b/criu/signalfd.c @@ -24,34 +24,19 @@ int is_signalfd_link(char *link) return is_anon_link_type(link, "[signalfd]"); } -struct signalfd_dump_arg { - u32 id; - const struct fd_parms *p; - bool dumped; -}; - -static int dump_signalfd_entry(union fdinfo_entries *e, void *arg) -{ - struct signalfd_dump_arg *da = arg; - - if (da->dumped) { - pr_err("Several counters in a file?\n"); - return -1; - } - - da->dumped = true; - e->sfd.id = da->id; - e->sfd.flags = da->p->flags; - e->sfd.fown = (FownEntry *)&da->p->fown; - - return pb_write_one(img_from_set(glob_imgset, CR_FD_SIGNALFD), - &e->sfd, PB_SIGNALFD); -} - static int dump_one_signalfd(int lfd, u32 id, const struct fd_parms *p) { - struct signalfd_dump_arg da = { .id = id, .p = p, }; - return parse_fdinfo(lfd, FD_TYPES__SIGNALFD, dump_signalfd_entry, &da); + SignalfdEntry sfd = SIGNALFD_ENTRY__INIT; + + if (parse_fdinfo(lfd, FD_TYPES__SIGNALFD, NULL, &sfd)) + return -1; + + sfd.id = id; + sfd.flags = p->flags; + sfd.fown = (FownEntry *)&p->fown; + + return pb_write_one(img_from_set(glob_imgset, CR_FD_SIGNALFD), + &sfd, PB_SIGNALFD); } const struct fdtype_ops signalfd_dump_ops = { From cd8db2edc5aabe9cd03df45e33d7c24a7b0d566d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 22 Jun 2017 20:39:08 +0300 Subject: [PATCH 0625/4375] eventpoll: Rework parse_fdinfo not to use callback Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-check.c | 19 ++++++------------- criu/eventpoll.c | 39 +++++++-------------------------------- criu/include/fdinfo.h | 7 ------- criu/proc_parse.c | 23 +++++++++++------------ 4 files changed, 24 insertions(+), 64 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index 7eb5ccc31..4f6156a0b 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -344,17 +344,11 @@ static int check_fdinfo_signalfd(void) return 0; } -static int check_one_epoll(union fdinfo_entries *e, void *arg) -{ - *(int *)arg = e->epl.e.tfd; - free_event_poll_entry(e); - return 0; -} - static int check_fdinfo_eventpoll(void) { - int efd, pfd[2], proc_fd = 0, ret = -1; + int efd, pfd[2], ret = -1; struct epoll_event ev; + EventpollFileEntry efe = EVENTPOLL_FILE_ENTRY__INIT; if (pipe(pfd)) { pr_perror("Can't make pipe to watch"); @@ -375,20 +369,19 @@ static int check_fdinfo_eventpoll(void) goto epoll_err; } - ret = parse_fdinfo(efd, FD_TYPES__EVENTPOLL, check_one_epoll, &proc_fd); + ret = parse_fdinfo(efd, FD_TYPES__EVENTPOLL, NULL, &efe); if (ret) { pr_err("Error parsing proc fdinfo\n"); goto epoll_err; } - if (pfd[0] != proc_fd) { - pr_err("TFD mismatch (or not met) %d want %d\n", - proc_fd, pfd[0]); + if (efe.n_tfd != 1 || efe.tfd[0]->tfd != pfd[0]) { + pr_err("TFD mismatch (or not met)\n"); ret = -1; goto epoll_err; } - pr_info("Epoll fdinfo works OK (%d vs %d)\n", pfd[0], proc_fd); + pr_info("Epoll fdinfo works OK\n"); epoll_err: close(efd); diff --git a/criu/eventpoll.c b/criu/eventpoll.c index 1253f23b8..87e2457d5 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -51,53 +51,28 @@ static void pr_info_eventpoll(char *action, EventpollFileEntry *e) pr_info("%seventpoll: id %#08x flags %#04x\n", action, e->id, e->flags); } -struct eventpoll_list { - struct list_head list; - int n; -}; - -static int dump_eventpoll_entry(union fdinfo_entries *e, void *arg) -{ - struct eventpoll_list *ep_list = (struct eventpoll_list *) arg; - EventpollTfdEntry *efd = &e->epl.e; - - pr_info_eventpoll_tfd("Dumping: ", efd); - - list_add_tail(&e->epl.node, &ep_list->list); - ep_list->n++; - - return 0; -} - static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) { EventpollFileEntry e = EVENTPOLL_FILE_ENTRY__INIT; - struct eventpoll_list ep_list = {LIST_HEAD_INIT(ep_list.list), 0}; - union fdinfo_entries *te, *tmp; int i, ret = -1; e.id = id; e.flags = p->flags; e.fown = (FownEntry *)&p->fown; - if (parse_fdinfo(lfd, FD_TYPES__EVENTPOLL, dump_eventpoll_entry, &ep_list)) + if (parse_fdinfo(lfd, FD_TYPES__EVENTPOLL, NULL, &e)) goto out; - e.tfd = xmalloc(sizeof(struct EventpollTfdEntry *) * ep_list.n); - if (!e.tfd) - goto out; - - i = 0; - list_for_each_entry(te, &ep_list.list, epl.node) - e.tfd[i++] = &te->epl.e; - e.n_tfd = ep_list.n; - pr_info_eventpoll("Dumping ", &e); ret = pb_write_one(img_from_set(glob_imgset, CR_FD_EVENTPOLL_FILE), &e, PB_EVENTPOLL_FILE); out: - list_for_each_entry_safe(te, tmp, &ep_list.list, epl.node) - free_event_poll_entry(te); + for (i = 0; i < e.n_tfd; i++) { + if (!ret) + pr_info_eventpoll_tfd("Dumping: ", e.tfd[i]); + eventpoll_tfd_entry__free_unpacked(e.tfd[i], NULL); + } + xfree(e.tfd); return ret; } diff --git a/criu/include/fdinfo.h b/criu/include/fdinfo.h index 18e85ede2..45f5746ab 100644 --- a/criu/include/fdinfo.h +++ b/criu/include/fdinfo.h @@ -25,21 +25,14 @@ struct fanotify_mark_entry { }; }; -struct eventpoll_tfd_entry { - EventpollTfdEntry e; - struct list_head node; -}; - union fdinfo_entries { struct inotify_wd_entry ify; struct fanotify_mark_entry ffy; - struct eventpoll_tfd_entry epl; TimerfdEntry tfy; }; extern void free_inotify_wd_entry(union fdinfo_entries *e); extern void free_fanotify_mark_entry(union fdinfo_entries *e); -extern void free_event_poll_entry(union fdinfo_entries *e); struct fdinfo_common { off64_t pos; diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 674088356..4f9f2d7a2 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1547,11 +1547,6 @@ void free_fanotify_mark_entry(union fdinfo_entries *e) xfree(e); } -void free_event_poll_entry(union fdinfo_entries *e) -{ - xfree(e); -} - static void parse_fhandle_encoded(char *tok, FhEntry *fh) { char *d = (char *)fh->handle; @@ -1743,27 +1738,31 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, continue; } if (fdinfo_field(str, "tfd")) { - union fdinfo_entries *e; + EventpollFileEntry *epfe = arg; + EventpollTfdEntry *e; + int i; if (type != FD_TYPES__EVENTPOLL) goto parse_err; - e = xmalloc(sizeof(union fdinfo_entries)); + e = xmalloc(sizeof(EventpollTfdEntry)); if (!e) goto out; - eventpoll_tfd_entry__init(&e->epl.e); + eventpoll_tfd_entry__init(e); ret = sscanf(str, "tfd: %d events: %x data: %"PRIx64, - &e->epl.e.tfd, &e->epl.e.events, &e->epl.e.data); + &e->tfd, &e->events, &e->data); if (ret != 3) { - free_event_poll_entry(e); + eventpoll_tfd_entry__free_unpacked(e, NULL); goto parse_err; } - ret = cb(e, arg); - if (ret) + + i = epfe->n_tfd++; + if (xrealloc_safe(&epfe->tfd, epfe->n_tfd * sizeof(EventpollTfdEntry *))) goto out; + epfe->tfd[i] = e; entry_met = true; continue; } From 3150b56ddcf3fa591b412cd56d95587e81cd5c2f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 22 Jun 2017 20:39:34 +0300 Subject: [PATCH 0626/4375] inotify: Rework parse_fdinfo not to use callback Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-check.c | 18 +++++-------- criu/fsnotify.c | 60 +++++++++++++++++-------------------------- criu/include/fdinfo.h | 8 ------ criu/proc_parse.c | 41 ++++++++++++++--------------- 4 files changed, 49 insertions(+), 78 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index 4f6156a0b..c8e3543f5 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -392,16 +392,10 @@ pipe_err: return ret; } -static int check_one_inotify(union fdinfo_entries *e, void *arg) -{ - *(int *)arg = e->ify.e.wd; - free_inotify_wd_entry(e); - return 0; -} - static int check_fdinfo_inotify(void) { - int ifd, wd, proc_wd = -1, ret; + int ifd, wd, ret; + InotifyFileEntry ify = INOTIFY_FILE_ENTRY__INIT; ifd = inotify_init1(0); if (ifd < 0) { @@ -416,7 +410,7 @@ static int check_fdinfo_inotify(void) return -1; } - ret = parse_fdinfo(ifd, FD_TYPES__INOTIFY, check_one_inotify, &proc_wd); + ret = parse_fdinfo(ifd, FD_TYPES__INOTIFY, NULL, &ify); close(ifd); if (ret < 0) { @@ -424,12 +418,12 @@ static int check_fdinfo_inotify(void) return -1; } - if (wd != proc_wd) { - pr_err("WD mismatch (or not met) %d want %d\n", proc_wd, wd); + if (ify.n_wd != 1 || ify.wd[0]->wd != wd) { + pr_err("WD mismatch (or not met)\n"); return -1; } - pr_info("Inotify fdinfo works OK (%d vs %d)\n", wd, proc_wd); + pr_info("Inotify fdinfo works OK\n"); return 0; } diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 3c71bf3ac..7bd441161 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -302,12 +302,8 @@ struct watch_list { int n; }; -static int dump_inotify_entry(union fdinfo_entries *e, void *arg) +static int check_one_wd(InotifyWdEntry *we) { - struct watch_list *wd_list = (struct watch_list *) arg; - struct inotify_wd_entry *wd_entry = (struct inotify_wd_entry *) e; - InotifyWdEntry *we = &wd_entry->e; - pr_info("wd: wd %#08x s_dev %#08x i_ino %#16"PRIx64" mask %#08x\n", we->wd, we->s_dev, we->i_ino, we->mask); pr_info("\t[fhandle] bytes %#08x type %#08x __handle %#016"PRIx64":%#016"PRIx64"\n", @@ -318,22 +314,15 @@ static int dump_inotify_entry(union fdinfo_entries *e, void *arg) pr_warn_once("\t\tDetected FS_EVENT_ON_CHILD bit " "in mask (will be ignored on restore)\n"); - if (check_open_handle(we->s_dev, we->i_ino, we->f_handle)) { - free_inotify_wd_entry(e); + if (check_open_handle(we->s_dev, we->i_ino, we->f_handle)) return -1; - } - - list_add_tail(&wd_entry->node, &wd_list->list); - wd_list->n++; return 0; } static int dump_one_inotify(int lfd, u32 id, const struct fd_parms *p) { - struct watch_list wd_list = {.list = LIST_HEAD_INIT(wd_list.list), .n = 0}; InotifyFileEntry ie = INOTIFY_FILE_ENTRY__INIT; - union fdinfo_entries *we, *tmp; int exit_code = -1, i, ret; ret = fd_has_data(lfd); @@ -346,17 +335,12 @@ static int dump_one_inotify(int lfd, u32 id, const struct fd_parms *p) ie.flags = p->flags; ie.fown = (FownEntry *)&p->fown; - if (parse_fdinfo(lfd, FD_TYPES__INOTIFY, dump_inotify_entry, &wd_list)) + if (parse_fdinfo(lfd, FD_TYPES__INOTIFY, NULL, &ie)) goto free; - ie.wd = xmalloc(sizeof(*ie.wd) * wd_list.n); - if (!ie.wd) - goto free; - - i = 0; - list_for_each_entry(we, &wd_list.list, ify.node) - ie.wd[i++] = &we->ify.e; - ie.n_wd = wd_list.n; + for (i = 0; i < ie.n_wd; i++) + if (check_one_wd(ie.wd[i])) + goto free; pr_info("id %#08x flags %#08x\n", ie.id, ie.flags); if (pb_write_one(img_from_set(glob_imgset, CR_FD_INOTIFY_FILE), &ie, PB_INOTIFY_FILE)) @@ -364,27 +348,31 @@ static int dump_one_inotify(int lfd, u32 id, const struct fd_parms *p) exit_code = 0; free: + for (i = 0; i < ie.n_wd; i++) + xfree(ie.wd[i]); xfree(ie.wd); - list_for_each_entry_safe(we, tmp, &wd_list.list, ify.node) - free_inotify_wd_entry(we); return exit_code; } -static int pre_dump_inotify_entry(union fdinfo_entries *e, void *arg) -{ - InotifyWdEntry *we = &e->ify.e; - int ret; - - ret = irmap_queue_cache(we->s_dev, we->i_ino, we->f_handle); - free_inotify_wd_entry(e); - - return ret; -} - static int pre_dump_one_inotify(int pid, int lfd) { - return parse_fdinfo_pid(pid, lfd, FD_TYPES__INOTIFY, pre_dump_inotify_entry, NULL); + InotifyFileEntry ie = INOTIFY_FILE_ENTRY__INIT; + int i; + + if (parse_fdinfo_pid(pid, lfd, FD_TYPES__INOTIFY, NULL, &ie)) + return -1; + + for (i = 0; i < ie.n_wd; i++) { + InotifyWdEntry *we = ie.wd[i]; + + if (irmap_queue_cache(we->s_dev, we->i_ino, we->f_handle)) + return -1; + + xfree(we); + } + + return 0; } const struct fdtype_ops inotify_dump_ops = { diff --git a/criu/include/fdinfo.h b/criu/include/fdinfo.h index 45f5746ab..5977a1d83 100644 --- a/criu/include/fdinfo.h +++ b/criu/include/fdinfo.h @@ -9,12 +9,6 @@ #include "images/fsnotify.pb-c.h" #include "images/timerfd.pb-c.h" -struct inotify_wd_entry { - InotifyWdEntry e; - FhEntry f_handle; - struct list_head node; -}; - struct fanotify_mark_entry { FanotifyMarkEntry e; FhEntry f_handle; @@ -26,12 +20,10 @@ struct fanotify_mark_entry { }; union fdinfo_entries { - struct inotify_wd_entry ify; struct fanotify_mark_entry ffy; TimerfdEntry tfy; }; -extern void free_inotify_wd_entry(union fdinfo_entries *e); extern void free_fanotify_mark_entry(union fdinfo_entries *e); struct fdinfo_common { diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 4f9f2d7a2..7b2e2ec6e 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1534,12 +1534,6 @@ static void free_fhandle(FhEntry *fh) xfree(fh->handle); } -void free_inotify_wd_entry(union fdinfo_entries *e) -{ - free_fhandle(e->ify.e.f_handle); - xfree(e); -} - void free_fanotify_mark_entry(union fdinfo_entries *e) { if (e->ffy.e.ie) @@ -1867,21 +1861,27 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, continue; } if (fdinfo_field(str, "inotify wd")) { + void *buf, *ob; + InotifyFileEntry *ie = arg; InotifyWdEntry *ify; - union fdinfo_entries *e; - int hoff; + int hoff, i; if (type != FD_TYPES__INOTIFY) goto parse_err; - e = xmalloc(sizeof(*e)); - if (!e) - goto parse_err; - ify = &e->ify.e; + ob = buf = xmalloc(sizeof(InotifyWdEntry) + + sizeof(FhEntry) + + FH_ENTRY_SIZES__min_entries * sizeof(uint64_t)); + if (!buf) + goto out; + ify = xptr_pull(&buf, InotifyWdEntry); inotify_wd_entry__init(ify); - ify->f_handle = &e->ify.f_handle; + ify->f_handle = xptr_pull(&buf, FhEntry); fh_entry__init(ify->f_handle); + ify->f_handle->n_handle = FH_ENTRY_SIZES__min_entries; + ify->f_handle->handle = xptr_pull_s(&buf, + FH_ENTRY_SIZES__min_entries * sizeof(uint64_t)); ret = sscanf(str, "inotify wd:%x ino:%"PRIx64" sdev:%x " @@ -1893,22 +1893,19 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, &ify->f_handle->bytes, &ify->f_handle->type, &hoff); if (ret != 7) { - free_inotify_wd_entry(e); + xfree(ob); goto parse_err; } - if (alloc_fhandle(ify->f_handle)) { - free_inotify_wd_entry(e); - goto out; - } - parse_fhandle_encoded(str + hoff, ify->f_handle); - ret = cb(e, arg); - - if (ret) + i = ie->n_wd++; + if (xrealloc_safe(&ie->wd, ie->n_wd * sizeof(InotifyWdEntry *))) { + xfree(ob); goto out; + } + ie->wd[i] = ify; entry_met = true; continue; } From e5b4ef20fc1258751ad53cf9215c82e9839c2108 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 22 Jun 2017 20:40:02 +0300 Subject: [PATCH 0627/4375] fanotify: Rework parse_fdinfo not to use callback Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/fsnotify.c | 77 ++++++++++---------------- criu/include/fdinfo.h | 13 ----- criu/include/fsnotify.h | 5 -- criu/proc_parse.c | 117 ++++++++++++++++++++-------------------- 4 files changed, 84 insertions(+), 128 deletions(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 7bd441161..f86fbea5e 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -296,12 +296,6 @@ err: return -1; } -struct watch_list { - struct fsnotify_params fsn_params; - struct list_head list; - int n; -}; - static int check_one_wd(InotifyWdEntry *we) { pr_info("wd: wd %#08x s_dev %#08x i_ino %#16"PRIx64" mask %#08x\n", @@ -381,11 +375,8 @@ const struct fdtype_ops inotify_dump_ops = { .pre_dump = pre_dump_one_inotify, }; -static int dump_fanotify_entry(union fdinfo_entries *e, void *arg) +static int check_one_mark(FanotifyMarkEntry *fme) { - struct watch_list *wd_list = (struct watch_list *) arg; - FanotifyMarkEntry *fme = &e->ffy.e; - if (fme->type == MARK_TYPE__INODE) { BUG_ON(!fme->ie); @@ -398,7 +389,7 @@ static int dump_fanotify_entry(union fdinfo_entries *e, void *arg) fme->ie->f_handle->handle[0], fme->ie->f_handle->handle[1]); if (check_open_handle(fme->s_dev, fme->ie->i_ino, fme->ie->f_handle)) - goto out; + return -1; } if (fme->type == MARK_TYPE__MOUNT) { @@ -409,7 +400,7 @@ static int dump_fanotify_entry(union fdinfo_entries *e, void *arg) m = lookup_mnt_id(fme->me->mnt_id); if (!m) { pr_err("Can't find mnt_id 0x%x\n", fme->me->mnt_id); - goto out; + return -1; } if (!(root_ns_mask & CLONE_NEWNS)) fme->me->path = m->mountpoint + 1; @@ -420,20 +411,12 @@ static int dump_fanotify_entry(union fdinfo_entries *e, void *arg) } - list_add_tail(&e->ffy.node, &wd_list->list); - wd_list->n++; - return 0; -out: - free_fanotify_mark_entry(e); - return -1; } static int dump_one_fanotify(int lfd, u32 id, const struct fd_parms *p) { - struct watch_list wd_list = {.list = LIST_HEAD_INIT(wd_list.list), .n = 0}; FanotifyFileEntry fe = FANOTIFY_FILE_ENTRY__INIT; - union fdinfo_entries *we, *tmp; int ret = -1, i; ret = fd_has_data(lfd); @@ -447,49 +430,43 @@ static int dump_one_fanotify(int lfd, u32 id, const struct fd_parms *p) fe.flags = p->flags; fe.fown = (FownEntry *)&p->fown; - if (parse_fdinfo(lfd, FD_TYPES__FANOTIFY, - dump_fanotify_entry, &wd_list) < 0) + if (parse_fdinfo(lfd, FD_TYPES__FANOTIFY, NULL, &fe) < 0) goto free; - fe.mark = xmalloc(sizeof(*fe.mark) * wd_list.n); - if (!fe.mark) - goto free; - - i = 0; - list_for_each_entry(we, &wd_list.list, ffy.node) - fe.mark[i++] = &we->ffy.e; - fe.n_mark = wd_list.n; + for (i = 0; i < fe.n_mark; i++) + if (check_one_mark(fe.mark[i])) + goto free; pr_info("id %#08x flags %#08x\n", fe.id, fe.flags); - fe.faflags = wd_list.fsn_params.faflags; - fe.evflags = wd_list.fsn_params.evflags; - ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FANOTIFY_FILE), &fe, PB_FANOTIFY_FILE); free: + for (i = 0; i < fe.n_mark; i++) + xfree(fe.mark[i]); xfree(fe.mark); - list_for_each_entry_safe(we, tmp, &wd_list.list, ffy.node) - free_fanotify_mark_entry(we); - return ret; -} - -static int pre_dump_fanotify_entry(union fdinfo_entries *e, void *arg) -{ - FanotifyMarkEntry *fme = &e->ffy.e; - int ret = 0; - - if (fme->type == MARK_TYPE__INODE) - ret = irmap_queue_cache(fme->s_dev, fme->ie->i_ino, - fme->ie->f_handle); - - free_fanotify_mark_entry(e); return ret; } static int pre_dump_one_fanotify(int pid, int lfd) { - struct fsnotify_params fsn_params = { }; - return parse_fdinfo_pid(pid, lfd, FD_TYPES__FANOTIFY, pre_dump_fanotify_entry, &fsn_params); + FanotifyFileEntry fe = FANOTIFY_FILE_ENTRY__INIT; + int i; + + if (parse_fdinfo_pid(pid, lfd, FD_TYPES__FANOTIFY, NULL, &fe)) + return -1; + + for (i = 0; i < fe.n_mark; i++) { + FanotifyMarkEntry *me = fe.mark[i]; + + if (me->type == MARK_TYPE__INODE && + irmap_queue_cache(me->s_dev, me->ie->i_ino, + me->ie->f_handle)) + return -1; + + xfree(me); + } + xfree(fe.mark); + return 0; } const struct fdtype_ops fanotify_dump_ops = { diff --git a/criu/include/fdinfo.h b/criu/include/fdinfo.h index 5977a1d83..ef7c3f6b2 100644 --- a/criu/include/fdinfo.h +++ b/criu/include/fdinfo.h @@ -9,23 +9,10 @@ #include "images/fsnotify.pb-c.h" #include "images/timerfd.pb-c.h" -struct fanotify_mark_entry { - FanotifyMarkEntry e; - FhEntry f_handle; - struct list_head node; - union { - FanotifyInodeMarkEntry ie; - FanotifyMountMarkEntry me; - }; -}; - union fdinfo_entries { - struct fanotify_mark_entry ffy; TimerfdEntry tfy; }; -extern void free_fanotify_mark_entry(union fdinfo_entries *e); - struct fdinfo_common { off64_t pos; int flags; diff --git a/criu/include/fsnotify.h b/criu/include/fsnotify.h index adc02034c..7bf5af455 100644 --- a/criu/include/fsnotify.h +++ b/criu/include/fsnotify.h @@ -8,11 +8,6 @@ #define KERNEL_FS_EVENT_ON_CHILD 0x08000000 -struct fsnotify_params { - u32 faflags; - u32 evflags; -}; - extern int is_inotify_link(char *link); extern int is_fanotify_link(char *link); extern const struct fdtype_ops inotify_dump_ops; diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 7b2e2ec6e..d0a6060c5 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1520,27 +1520,6 @@ static char nybble(const char n) return 0; } -static int alloc_fhandle(FhEntry *fh) -{ - fh->n_handle = FH_ENTRY_SIZES__min_entries; - fh->handle = xmalloc(pb_repeated_size(fh, handle)); - - return fh->handle == NULL ? -1 : 0; -} - -static void free_fhandle(FhEntry *fh) -{ - if (fh->handle) - xfree(fh->handle); -} - -void free_fanotify_mark_entry(union fdinfo_entries *e) -{ - if (e->ffy.e.ie) - free_fhandle(e->ffy.ie.f_handle); - xfree(e); -} - static void parse_fhandle_encoded(char *tok, FhEntry *fh) { char *d = (char *)fh->handle; @@ -1774,89 +1753,107 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, continue; } if (fdinfo_field(str, "fanotify flags")) { - struct fsnotify_params *p = arg; + FanotifyFileEntry *fe = arg; if (type != FD_TYPES__FANOTIFY) goto parse_err; ret = sscanf(str, "fanotify flags:%x event-flags:%x", - &p->faflags, &p->evflags); + &fe->faflags, &fe->evflags); if (ret != 2) goto parse_err; entry_met = true; continue; } if (fdinfo_field(str, "fanotify ino")) { - union fdinfo_entries *e; - int hoff = 0; + void *buf, *ob; + FanotifyFileEntry *fe = arg; + FanotifyMarkEntry *me; + int hoff = 0, i; if (type != FD_TYPES__FANOTIFY) goto parse_err; - e = xmalloc(sizeof(*e)); - if (!e) - goto parse_err; + ob = buf = xmalloc(sizeof(FanotifyMarkEntry) + + sizeof(FanotifyInodeMarkEntry) + + sizeof(FhEntry) + + FH_ENTRY_SIZES__min_entries * sizeof(uint64_t)); + if (!buf) + goto out; - fanotify_mark_entry__init(&e->ffy.e); - fanotify_inode_mark_entry__init(&e->ffy.ie); - fh_entry__init(&e->ffy.f_handle); - e->ffy.e.ie = &e->ffy.ie; - e->ffy.ie.f_handle = &e->ffy.f_handle; + me = xptr_pull(&buf, FanotifyMarkEntry); + fanotify_mark_entry__init(me); + me->ie = xptr_pull(&buf, FanotifyInodeMarkEntry); + fanotify_inode_mark_entry__init(me->ie); + me->ie->f_handle = xptr_pull(&buf, FhEntry); + fh_entry__init(me->ie->f_handle); + me->ie->f_handle->n_handle = FH_ENTRY_SIZES__min_entries; + me->ie->f_handle->handle = xptr_pull_s(&buf, + FH_ENTRY_SIZES__min_entries * sizeof(uint64_t)); ret = sscanf(str, "fanotify ino:%"PRIx64" sdev:%x mflags:%x mask:%x ignored_mask:%x " "fhandle-bytes:%x fhandle-type:%x f_handle: %n", - &e->ffy.ie.i_ino, &e->ffy.e.s_dev, - &e->ffy.e.mflags, &e->ffy.e.mask, &e->ffy.e.ignored_mask, - &e->ffy.f_handle.bytes, &e->ffy.f_handle.type, + &me->ie->i_ino, &me->s_dev, + &me->mflags, &me->mask, &me->ignored_mask, + &me->ie->f_handle->bytes, &me->ie->f_handle->type, &hoff); if (ret != 7 || hoff == 0) { - free_fanotify_mark_entry(e); + xfree(ob); goto parse_err; } - if (alloc_fhandle(&e->ffy.f_handle)) { - free_fanotify_mark_entry(e); + parse_fhandle_encoded(str + hoff, me->ie->f_handle); + me->type = MARK_TYPE__INODE; + + i = fe->n_mark++; + if (xrealloc_safe(&fe->mark, fe->n_mark * sizeof(FanotifyMarkEntry *))) { + xfree(ob); goto out; } - parse_fhandle_encoded(str + hoff, &e->ffy.f_handle); - - e->ffy.e.type = MARK_TYPE__INODE; - ret = cb(e, arg); - - - if (ret) - goto out; + fe->mark[i] = me; entry_met = true; continue; } if (fdinfo_field(str, "fanotify mnt_id")) { - union fdinfo_entries *e; + void *buf, *ob; + FanotifyFileEntry *fe = arg; + FanotifyMarkEntry *me; + int i; if (type != FD_TYPES__FANOTIFY) goto parse_err; - e = xmalloc(sizeof(*e)); - if (!e) - goto parse_err; - fanotify_mark_entry__init(&e->ffy.e); - fanotify_mount_mark_entry__init(&e->ffy.me); - e->ffy.e.me = &e->ffy.me; + ob = buf = xmalloc(sizeof(FanotifyMarkEntry) + + sizeof(FanotifyMountMarkEntry)); + if (!buf) + goto out; + + me = xptr_pull(&buf, FanotifyMarkEntry); + fanotify_mark_entry__init(me); + me->me = xptr_pull(&buf, FanotifyMountMarkEntry); + fanotify_mount_mark_entry__init(me->me); ret = sscanf(str, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x", - &e->ffy.e.me->mnt_id, &e->ffy.e.mflags, - &e->ffy.e.mask, &e->ffy.e.ignored_mask); - if (ret != 4) + &me->me->mnt_id, &me->mflags, + &me->mask, &me->ignored_mask); + if (ret != 4) { + xfree(ob); goto parse_err; + } - e->ffy.e.type = MARK_TYPE__MOUNT; - ret = cb(e, arg); - if (ret) + me->type = MARK_TYPE__MOUNT; + + i = fe->n_mark++; + if (xrealloc_safe(&fe->mark, fe->n_mark * sizeof(FanotifyMarkEntry *))) { + xfree(ob); goto out; + } + fe->mark[i] = me; entry_met = true; continue; } From c14cede697a72464f1eb70768c3a9e9ecc3a56a4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 22 Jun 2017 20:40:19 +0300 Subject: [PATCH 0628/4375] timerfd: Rework parse_fdinfo not to use callback Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/fdinfo.h | 1 - criu/proc_parse.c | 9 ++------- criu/timerfd.c | 31 +++++++++++++------------------ 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/criu/include/fdinfo.h b/criu/include/fdinfo.h index ef7c3f6b2..ab1f1222d 100644 --- a/criu/include/fdinfo.h +++ b/criu/include/fdinfo.h @@ -10,7 +10,6 @@ #include "images/timerfd.pb-c.h" union fdinfo_entries { - TimerfdEntry tfy; }; struct fdinfo_common { diff --git a/criu/proc_parse.c b/criu/proc_parse.c index d0a6060c5..07ca9dee2 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1613,8 +1613,6 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, return -1; while (1) { - union fdinfo_entries entry; - str = breadline(&f); if (!str) break; @@ -1696,16 +1694,13 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, continue; } if (fdinfo_field(str, "clockid")) { - timerfd_entry__init(&entry.tfy); + TimerfdEntry *tfe = arg; if (type != FD_TYPES__TIMERFD) goto parse_err; - ret = parse_timerfd(&f, str, &entry.tfy); + ret = parse_timerfd(&f, str, tfe); if (ret) goto parse_err; - ret = cb(&entry, arg); - if (ret) - goto out; entry_met = true; continue; diff --git a/criu/timerfd.c b/criu/timerfd.c index 476bf602e..60f77fc5d 100644 --- a/criu/timerfd.c +++ b/criu/timerfd.c @@ -64,26 +64,21 @@ int is_timerfd_link(char *link) return is_anon_link_type(link, "[timerfd]"); } -static int dump_timerfd_entry(union fdinfo_entries *e, void *arg) -{ - struct timerfd_dump_arg *da = arg; - TimerfdEntry *tfy = &e->tfy; - - tfy->id = da->id; - tfy->flags = da->p->flags; - tfy->fown = (FownEntry *)&da->p->fown; - - pr_info("Dumping id %#x clockid %d it_value(%llu, %llu) it_interval(%llu, %llu)\n", - tfy->id, tfy->clockid, (unsigned long long)tfy->vsec, (unsigned long long)tfy->vnsec, - (unsigned long long)tfy->isec, (unsigned long long)tfy->insec); - - return pb_write_one(img_from_set(glob_imgset, CR_FD_TIMERFD), &e->tfy, PB_TIMERFD); -} - static int dump_one_timerfd(int lfd, u32 id, const struct fd_parms *p) { - struct timerfd_dump_arg da = { .id = id, .p = p, }; - return parse_fdinfo(lfd, FD_TYPES__TIMERFD, dump_timerfd_entry, &da); + TimerfdEntry tfe = TIMERFD_ENTRY__INIT; + + if (parse_fdinfo(lfd, FD_TYPES__TIMERFD, NULL, &tfe)) + return -1; + + tfe.id = id; + tfe.flags = p->flags; + tfe.fown = (FownEntry *)&p->fown; + pr_info("Dumping id %#x clockid %d it_value(%llu, %llu) it_interval(%llu, %llu)\n", + tfe.id, tfe.clockid, (unsigned long long)tfe.vsec, (unsigned long long)tfe.vnsec, + (unsigned long long)tfe.isec, (unsigned long long)tfe.insec); + + return pb_write_one(img_from_set(glob_imgset, CR_FD_TIMERFD), &tfe, PB_TIMERFD); } const struct fdtype_ops timerfd_dump_ops = { From e42c76955562969158f6026d7073a98f14af187e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 22 Jun 2017 20:40:37 +0300 Subject: [PATCH 0629/4375] proc: Remove unneeded callback arg from parse_fdinfo Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/autofs.c | 2 +- criu/cr-check.c | 10 +++++----- criu/eventfd.c | 2 +- criu/eventpoll.c | 2 +- criu/files.c | 2 +- criu/fsnotify.c | 8 ++++---- criu/include/fdinfo.h | 9 ++------- criu/proc_parse.c | 15 ++++++--------- criu/signalfd.c | 2 +- criu/timerfd.c | 2 +- 10 files changed, 23 insertions(+), 31 deletions(-) diff --git a/criu/autofs.c b/criu/autofs.c index 15b0fc4b3..f34572033 100644 --- a/criu/autofs.c +++ b/criu/autofs.c @@ -92,7 +92,7 @@ static int autofs_check_fd_stat(struct stat *stat, int prgp, int fd, return 0; if (stat->st_ino != ino) return 0; - if (parse_fdinfo_pid(prgp, fd, FD_TYPES__UND, NULL, &fdinfo)) + if (parse_fdinfo_pid(prgp, fd, FD_TYPES__UND, &fdinfo)) return -1; *mode = fdinfo.flags & O_WRONLY; diff --git a/criu/cr-check.c b/criu/cr-check.c index c8e3543f5..1dd887aa0 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -284,7 +284,7 @@ static int check_fdinfo_eventfd(void) return -1; } - ret = parse_fdinfo(fd, FD_TYPES__EVENTFD, NULL, &fe); + ret = parse_fdinfo(fd, FD_TYPES__EVENTFD, &fe); close(fd); if (ret) { @@ -307,7 +307,7 @@ int check_mnt_id(void) struct fdinfo_common fdinfo = { .mnt_id = -1 }; int ret; - ret = parse_fdinfo(get_service_fd(LOG_FD_OFF), FD_TYPES__UND, NULL, &fdinfo); + ret = parse_fdinfo(get_service_fd(LOG_FD_OFF), FD_TYPES__UND, &fdinfo); if (ret < 0) return -1; @@ -333,7 +333,7 @@ static int check_fdinfo_signalfd(void) return -1; } - ret = parse_fdinfo(fd, FD_TYPES__SIGNALFD, NULL, &sfd); + ret = parse_fdinfo(fd, FD_TYPES__SIGNALFD, &sfd); close(fd); if (ret) { @@ -369,7 +369,7 @@ static int check_fdinfo_eventpoll(void) goto epoll_err; } - ret = parse_fdinfo(efd, FD_TYPES__EVENTPOLL, NULL, &efe); + ret = parse_fdinfo(efd, FD_TYPES__EVENTPOLL, &efe); if (ret) { pr_err("Error parsing proc fdinfo\n"); goto epoll_err; @@ -410,7 +410,7 @@ static int check_fdinfo_inotify(void) return -1; } - ret = parse_fdinfo(ifd, FD_TYPES__INOTIFY, NULL, &ify); + ret = parse_fdinfo(ifd, FD_TYPES__INOTIFY, &ify); close(ifd); if (ret < 0) { diff --git a/criu/eventfd.c b/criu/eventfd.c index 7212ad4c4..b3c76e3d2 100644 --- a/criu/eventfd.c +++ b/criu/eventfd.c @@ -47,7 +47,7 @@ static int dump_one_eventfd(int lfd, u32 id, const struct fd_parms *p) { EventfdFileEntry efd = EVENTFD_FILE_ENTRY__INIT; - if (parse_fdinfo(lfd, FD_TYPES__EVENTFD, NULL, &efd)) + if (parse_fdinfo(lfd, FD_TYPES__EVENTFD, &efd)) return -1; efd.id = id; diff --git a/criu/eventpoll.c b/criu/eventpoll.c index 87e2457d5..b58e068c9 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -60,7 +60,7 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) e.flags = p->flags; e.fown = (FownEntry *)&p->fown; - if (parse_fdinfo(lfd, FD_TYPES__EVENTPOLL, NULL, &e)) + if (parse_fdinfo(lfd, FD_TYPES__EVENTPOLL, &e)) goto out; pr_info_eventpoll("Dumping ", &e); diff --git a/criu/files.c b/criu/files.c index 913cec057..46adac2e1 100644 --- a/criu/files.c +++ b/criu/files.c @@ -339,7 +339,7 @@ static int fill_fd_params(struct pid *owner_pid, int fd, int lfd, return -1; } - if (parse_fdinfo_pid(owner_pid->real, fd, FD_TYPES__UND, NULL, &fdinfo)) + if (parse_fdinfo_pid(owner_pid->real, fd, FD_TYPES__UND, &fdinfo)) return -1; p->fs_type = fsbuf.f_type; diff --git a/criu/fsnotify.c b/criu/fsnotify.c index f86fbea5e..cb1b32ca3 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -329,7 +329,7 @@ static int dump_one_inotify(int lfd, u32 id, const struct fd_parms *p) ie.flags = p->flags; ie.fown = (FownEntry *)&p->fown; - if (parse_fdinfo(lfd, FD_TYPES__INOTIFY, NULL, &ie)) + if (parse_fdinfo(lfd, FD_TYPES__INOTIFY, &ie)) goto free; for (i = 0; i < ie.n_wd; i++) @@ -354,7 +354,7 @@ static int pre_dump_one_inotify(int pid, int lfd) InotifyFileEntry ie = INOTIFY_FILE_ENTRY__INIT; int i; - if (parse_fdinfo_pid(pid, lfd, FD_TYPES__INOTIFY, NULL, &ie)) + if (parse_fdinfo_pid(pid, lfd, FD_TYPES__INOTIFY, &ie)) return -1; for (i = 0; i < ie.n_wd; i++) { @@ -430,7 +430,7 @@ static int dump_one_fanotify(int lfd, u32 id, const struct fd_parms *p) fe.flags = p->flags; fe.fown = (FownEntry *)&p->fown; - if (parse_fdinfo(lfd, FD_TYPES__FANOTIFY, NULL, &fe) < 0) + if (parse_fdinfo(lfd, FD_TYPES__FANOTIFY, &fe) < 0) goto free; for (i = 0; i < fe.n_mark; i++) @@ -452,7 +452,7 @@ static int pre_dump_one_fanotify(int pid, int lfd) FanotifyFileEntry fe = FANOTIFY_FILE_ENTRY__INIT; int i; - if (parse_fdinfo_pid(pid, lfd, FD_TYPES__FANOTIFY, NULL, &fe)) + if (parse_fdinfo_pid(pid, lfd, FD_TYPES__FANOTIFY, &fe)) return -1; for (i = 0; i < fe.n_mark; i++) { diff --git a/criu/include/fdinfo.h b/criu/include/fdinfo.h index ab1f1222d..10fb31f68 100644 --- a/criu/include/fdinfo.h +++ b/criu/include/fdinfo.h @@ -9,9 +9,6 @@ #include "images/fsnotify.pb-c.h" #include "images/timerfd.pb-c.h" -union fdinfo_entries { -}; - struct fdinfo_common { off64_t pos; int flags; @@ -19,9 +16,7 @@ struct fdinfo_common { int owner; }; -extern int parse_fdinfo(int fd, int type, - int (*cb)(union fdinfo_entries *e, void *arg), void *arg); -extern int parse_fdinfo_pid(int pid, int fd, int type, - int (*cb)(union fdinfo_entries *e, void *arg), void *arg); +extern int parse_fdinfo(int fd, int type, void *arg); +extern int parse_fdinfo_pid(int pid, int fd, int type, void *arg); #endif diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 07ca9dee2..d0199b456 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1597,8 +1597,7 @@ nodata: static int parse_file_lock_buf(char *buf, struct file_lock *fl, bool is_blocked); -static int parse_fdinfo_pid_s(int pid, int fd, int type, - int (*cb)(union fdinfo_entries *e, void *arg), void *arg) +static int parse_fdinfo_pid_s(int pid, int fd, int type, void *arg) { struct bfd f; char *str; @@ -1922,23 +1921,21 @@ out: return exit_code; } -int parse_fdinfo_pid(int pid, int fd, int type, - int (*cb)(union fdinfo_entries *e, void *arg), void *arg) +int parse_fdinfo_pid(int pid, int fd, int type, void *arg) { - return parse_fdinfo_pid_s(pid, fd, type, cb, arg); + return parse_fdinfo_pid_s(pid, fd, type, arg); } -int parse_fdinfo(int fd, int type, - int (*cb)(union fdinfo_entries *e, void *arg), void *arg) +int parse_fdinfo(int fd, int type, void *arg) { - return parse_fdinfo_pid_s(PROC_SELF, fd, type, cb, arg); + return parse_fdinfo_pid_s(PROC_SELF, fd, type, arg); } int get_fd_mntid(int fd, int *mnt_id) { struct fdinfo_common fdinfo = { .mnt_id = -1}; - if (parse_fdinfo(fd, FD_TYPES__UND, NULL, &fdinfo)) + if (parse_fdinfo(fd, FD_TYPES__UND, &fdinfo)) return -1; *mnt_id = fdinfo.mnt_id; diff --git a/criu/signalfd.c b/criu/signalfd.c index 660f510d9..f33efa15f 100644 --- a/criu/signalfd.c +++ b/criu/signalfd.c @@ -28,7 +28,7 @@ static int dump_one_signalfd(int lfd, u32 id, const struct fd_parms *p) { SignalfdEntry sfd = SIGNALFD_ENTRY__INIT; - if (parse_fdinfo(lfd, FD_TYPES__SIGNALFD, NULL, &sfd)) + if (parse_fdinfo(lfd, FD_TYPES__SIGNALFD, &sfd)) return -1; sfd.id = id; diff --git a/criu/timerfd.c b/criu/timerfd.c index 60f77fc5d..aa2aae169 100644 --- a/criu/timerfd.c +++ b/criu/timerfd.c @@ -68,7 +68,7 @@ static int dump_one_timerfd(int lfd, u32 id, const struct fd_parms *p) { TimerfdEntry tfe = TIMERFD_ENTRY__INIT; - if (parse_fdinfo(lfd, FD_TYPES__TIMERFD, NULL, &tfe)) + if (parse_fdinfo(lfd, FD_TYPES__TIMERFD, &tfe)) return -1; tfe.id = id; From 3c9290d278e6386a5babb60886ed23b5cf5cae42 Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Mon, 19 Jun 2017 14:18:34 +0300 Subject: [PATCH 0630/4375] files: Fix compilation errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1: Signed underflow criu/files-reg.c: In function ‘open_path’: criu/files-reg.c:1299:14: error: iteration 2147483647 invokes undefined behavior [-Werror=aggressive-loop-optimizations] while (count--) { ~~~~~^~ 2: Uninitialized variable criu/files-reg.c: In function ‘make_parent_dirs_if_need’: criu/files-reg.c:1354:13: warning: ‘count’ may be used uninitialized in this function [-Wmaybe-uninitialized] P.S. arch linux 4.7.5-1. gcc (GCC) 6.3.1 20170109 Signed-off-by: Pavel Begunkov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 689891899..c4906a523 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1440,7 +1440,8 @@ static void rm_parent_dirs(int mntns_root, char *path, int count) if (!count) return; - while (count--) { + while (count > 0) { + count -= 1; p = strrchr(path, '/'); if (p) *p = '\0'; @@ -1575,7 +1576,7 @@ out_root: int open_path(struct file_desc *d, int(*open_cb)(int mntns_root, struct reg_file_info *, void *), void *arg) { - int tmp, mntns_root, level; + int tmp, mntns_root, level = 0; struct reg_file_info *rfi; char *orig_path = NULL; char path[PATH_MAX]; From 70c0b47d4449531a44b3ef044683162f80ebf7bd Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Wed, 28 Jun 2017 03:41:38 +0300 Subject: [PATCH 0631/4375] zdtm: skip 'tcp-close' tests if restore is skipped 'tcp-close' is a option that replaces connected tcp-sockets with 'closed' ones during restoring, therefore it have no sense without restore stage. Thus let's skip related tests if the 'norst' flag was specified. Signed-off-by: Pavel Begunkov Signed-off-by: Andrei Vagin --- test/zdtm.py | 4 ++++ test/zdtm/static/socket-tcp-close0.desc | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index ffa48a8d1..0e0ced45c 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1643,6 +1643,10 @@ def run_tests(opts): l.skip(t, "arch %s" % tdesc['arch']) continue + if test_flag(tdesc, 'reqrst') and opts['norst']: + l.skip(t, "restore stage is required") + continue + if run_all and test_flag(tdesc, 'noauto'): l.skip(t, "manual run only") continue diff --git a/test/zdtm/static/socket-tcp-close0.desc b/test/zdtm/static/socket-tcp-close0.desc index e85de0e66..75ce8a5a0 100644 --- a/test/zdtm/static/socket-tcp-close0.desc +++ b/test/zdtm/static/socket-tcp-close0.desc @@ -1 +1 @@ -{'dopts': '--tcp-established', 'ropts': '--tcp-close'} +{'dopts': '--tcp-established', 'ropts': '--tcp-close', 'flags': 'reqrst '} From 8494d70833e46cd6615464955772b87994d5b166 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 29 Jun 2017 10:35:12 +0300 Subject: [PATCH 0632/4375] irmap: Duplicate handle memory when queueing for predump With the recent cleanups in fdinfo parsing the memory allocation policy for entries has changed, thus keeping a pointer on the entry handle is no longer valid (it will be freed soon). Said that -- duplicate the memory for queued irmap work. https://github.com/xemul/criu/issues/328 Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/irmap.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/criu/irmap.c b/criu/irmap.c index c27fdd720..107e0f294 100644 --- a/criu/irmap.c +++ b/criu/irmap.c @@ -311,7 +311,12 @@ int irmap_queue_cache(unsigned int dev, unsigned long ino, ip->dev = dev; ip->ino = ino; ip->fh = *fh; - fh->handle = NULL; /* don't free in free_fhandle */ + ip->fh.handle = xmemdup(fh->handle, + FH_ENTRY_SIZES__min_entries * sizeof(uint64_t)); + if (!ip->fh.handle) { + xfree(ip); + return -1; + } pr_debug("Queue %x:%lx for pre-dump\n", dev, ino); From c0857d2517e86d54c2af337c5902ab3a4a066c4b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 30 Jun 2017 04:10:29 +0300 Subject: [PATCH 0633/4375] zdtm: check /proc/sys/kernel/taint and fail if it is non-zero We don't want to run tests, if a kernel has a problem. And we want to know when the taint flag is changed. Signed-off-by: Andrei Vagin Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/zdtm.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index 0e0ced45c..114e7f4cd 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1389,6 +1389,11 @@ class launcher: print >> self.__file_report, "# Timestamp: " + now.strftime("%Y-%m-%d %H:%M") + " (GMT+1)" print >> self.__file_report, "# " print >> self.__file_report, "1.." + str(nr_tests) + self.__taint = open("/proc/sys/kernel/tainted").read() + if int(self.__taint, 0) != 0: + print "The kernel is tainted: %r" % self.__taint + if not opts["ignore_taint"]: + raise Exception("The kernel is tainted: %r" % self.__taint) def __show_progress(self, msg): perc = self.__nr * 16 / self.__total @@ -1408,6 +1413,10 @@ class launcher: if len(self.__subs) >= self.__max: self.wait() + taint = open("/proc/sys/kernel/tainted").read() + if self.__taint != taint: + raise Exception("The kernel is tainted: %r (%r)" % (taint, self.__taint)) + if test_flag(desc, 'excl'): self.wait_all() @@ -1911,6 +1920,7 @@ rp.add_argument("-k", "--keep-img", help = "Whether or not to keep images after choices = ['always', 'never', 'failed'], default = 'failed') rp.add_argument("--report", help = "Generate summary report in directory") rp.add_argument("--keep-going", help = "Keep running tests in spite of failures", action = 'store_true') +rp.add_argument("--ignore-taint", help = "Don't care about a non-zero kernel taint flag", action = 'store_true') lp = sp.add_parser("list", help = "List tests") lp.set_defaults(action = list_tests) From d73a08b176d40b3b7a2a698f110b528bade321d5 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 13:55:47 +0300 Subject: [PATCH 0634/4375] image: Fix "collect happenned" flag This flag now means "image was opened", while the "empty image" concept makes this always true. Since there's one user of this flag, which is obviously incorrect, remove the latter and fix the former to mean "at least one object was read". Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/file-lock.c | 5 ----- criu/protobuf.c | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/criu/file-lock.c b/criu/file-lock.c index 2d4036c75..821821f59 100644 --- a/criu/file-lock.c +++ b/criu/file-lock.c @@ -426,11 +426,6 @@ int prepare_file_locks(int pid) if (!opts.handle_file_locks) return 0; - if (!(file_locks_cinfo.flags & COLLECT_HAPPENED)) { - pr_warn("Per-pid file locks are deprecated\n"); - return -1; - } - return restore_file_locks(pid); } diff --git a/criu/protobuf.c b/criu/protobuf.c index 5c770b847..219c7c088 100644 --- a/criu/protobuf.c +++ b/criu/protobuf.c @@ -186,7 +186,6 @@ int collect_image(struct collect_image_info *cinfo) if (!img) return -1; - cinfo->flags |= COLLECT_HAPPENED; if (cinfo->flags & COLLECT_SHARED) { o_alloc = shmalloc; o_free = shfree_last; @@ -210,6 +209,7 @@ int collect_image(struct collect_image_info *cinfo) break; } + cinfo->flags |= COLLECT_HAPPENED; ret = cinfo->collect(obj, msg, img); if (ret < 0) { o_free(obj); From 0a820d8db45607c843f92dd64a75e21505792a76 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 26 May 2017 15:44:42 +0300 Subject: [PATCH 0635/4375] restore: Do not allocate heads for post-prep actions Now the post-prep actions are xmalloc()-ed then added to the list. Let's make it sit right on the structures that need the post-prep, this would make some things much simpler and nicer soon. The approach is inspired by kernel rcu_head-s :) Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/autofs.c | 13 ++++++++----- criu/cr-restore.c | 30 ++++++++---------------------- criu/include/crtools.h | 24 +++++++++++------------- criu/pipes.c | 10 ++++++---- criu/sk-unix.c | 10 ++++++---- criu/tty.c | 10 +++++++--- 6 files changed, 46 insertions(+), 51 deletions(-) diff --git a/criu/autofs.c b/criu/autofs.c index f34572033..d6d2eee7f 100644 --- a/criu/autofs.c +++ b/criu/autofs.c @@ -531,6 +531,8 @@ typedef struct autofs_info_s { AutofsEntry *entry; char *mnt_path; dev_t mnt_dev; + struct mount_info *mi; + struct pprep_head ph; } autofs_info_t; static int dup_pipe_info(struct pipe_info *pi, int flags, @@ -927,9 +929,10 @@ static int autofs_create_pipe(struct pstree_item *task, autofs_info_t *i, return autofs_create_fle(task, fe, &i->pi.d); } -static int autofs_add_mount_info(void *data) +static int autofs_add_mount_info(struct pprep_head *ph) { - struct mount_info *mi = data; + autofs_info_t *ai = container_of(ph, autofs_info_t, ph); + struct mount_info *mi = ai->mi; autofs_info_t *info = mi->private; AutofsEntry *entry = info->entry; autofs_info_t *i; @@ -1063,11 +1066,11 @@ int autofs_mount(struct mount_info *mi, const char *source, const /* Otherwise we have to add shared object creation callback */ if (entry->fd != AUTOFS_CATATONIC_FD) { - ret = add_post_prepare_cb(autofs_add_mount_info, mi); - if (ret < 0) - goto free_info; + info->ph.actor = autofs_add_mount_info; + add_post_prepare_cb(&info->ph); } + info->mi = mi; mi->private = info; free_opts: diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 274259234..e8fb4adf8 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -285,36 +285,22 @@ static struct collect_image_info *before_ns_cinfos[] = { &tty_cdata, }; -struct post_prepare_cb { - struct list_head list; - int (*actor)(void *data); - void *data; -}; +static struct pprep_head *post_prepare_heads = NULL; -static struct list_head post_prepare_cbs = LIST_HEAD_INIT(post_prepare_cbs); - -int add_post_prepare_cb(int (*actor)(void *data), void *data) +void add_post_prepare_cb(struct pprep_head *ph) { - struct post_prepare_cb *cb; - - cb = xmalloc(sizeof(*cb)); - if (!cb) - return -1; - - cb->actor = actor; - cb->data = data; - list_add(&cb->list, &post_prepare_cbs); - return 0; + ph->next = post_prepare_heads; + post_prepare_heads = ph; } static int run_post_prepare(void) { - struct post_prepare_cb *o; + struct pprep_head *ph; - list_for_each_entry(o, &post_prepare_cbs, list) { - if (o->actor(o->data)) + for (ph = post_prepare_heads; ph != NULL; ph = ph->next) + if (ph->actor(ph)) return -1; - } + return 0; } diff --git a/criu/include/crtools.h b/criu/include/crtools.h index 15e074462..fb5fe73c0 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -13,7 +13,11 @@ extern int check_img_inventory(void); extern int write_img_inventory(InventoryEntry *he); extern int prepare_inventory(InventoryEntry *he); -extern int add_post_prepare_cb(int (*actor)(void *data), void *data); +struct pprep_head { + int (*actor)(struct pprep_head *); + struct pprep_head *next; +}; +extern void add_post_prepare_cb(struct pprep_head *); extern bool deprecated_ok(char *what); extern int cr_dump_tasks(pid_t pid); extern int cr_pre_dump_tasks(pid_t pid); @@ -25,17 +29,11 @@ extern int cr_dedup(void); extern int check_add_feature(char *arg); extern void pr_check_features(const char *offset, const char *sep, int width); -#define add_post_prepare_cb_once(actor, data) \ - ({ \ - static int __cb_called = 0; \ - int ret = 0; \ - \ - if (!__cb_called) { \ - ret = add_post_prepare_cb(actor, data); \ - __cb_called = 1; \ - } \ - \ - ret; \ - }) +#define add_post_prepare_cb_once(phead) do { \ + static int __cb_called = 0; \ + if (!__cb_called) \ + add_post_prepare_cb(phead); \ + __cb_called = 1; \ + } while (0) #endif /* __CR_CRTOOLS_H__ */ diff --git a/criu/pipes.c b/criu/pipes.c index 8b3fd6f84..c20fc61c1 100644 --- a/criu/pipes.c +++ b/criu/pipes.c @@ -75,7 +75,7 @@ int do_collect_pipe_data(struct pipe_data_rst *r, ProtobufCMessage *msg, } /* Choose who will restore a pipe. */ -static int mark_pipe_master(void *unused) +static int mark_pipe_master_cb(struct pprep_head *ph) { LIST_HEAD(head); @@ -141,6 +141,10 @@ static int mark_pipe_master(void *unused) return 0; } +static struct pprep_head mark_pipe_master = { + .actor = mark_pipe_master_cb, +}; + static struct pipe_data_rst *pd_hash_pipes[PIPE_DATA_HASH_SIZE]; int restore_pipe_data(int img_type, int pfd, u32 id, struct pipe_data_rst **hash) @@ -372,9 +376,7 @@ int collect_one_pipe_ops(void *o, ProtobufCMessage *base, struct file_desc_ops * list_add(&pi->pipe_list, &tmp->pipe_list); } - if (add_post_prepare_cb_once(mark_pipe_master, NULL)) - return -1; - + add_post_prepare_cb_once(&mark_pipe_master); list_add_tail(&pi->list, &pipes); return 0; diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 83c54d3f9..21cc42cb3 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1359,7 +1359,10 @@ static void unlink_stale(struct unix_sk_info *ui) revert_unix_sk_cwd(&cwd_fd, &root_fd); } -static int resolve_unix_peers(void *unused); +static int resolve_unix_peers_cb(struct pprep_head *ph); +static struct pprep_head resolve_unix_peers = { + .actor = resolve_unix_peers_cb, +}; static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) { @@ -1373,8 +1376,7 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) if (ui->ue->peer && !post_queued) { post_queued = true; - if (add_post_prepare_cb(resolve_unix_peers, NULL)) - return -1; + add_post_prepare_cb(&resolve_unix_peers); } if (ui->ue->name.len) { @@ -1460,7 +1462,7 @@ static void interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *pe } } -static int resolve_unix_peers(void *unused) +static int resolve_unix_peers_cb(struct pprep_head *ph) { struct unix_sk_info *ui, *peer; diff --git a/criu/tty.c b/criu/tty.c index 585e9ceab..7338d0cc5 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -1559,7 +1559,7 @@ struct collect_image_info tty_info_cinfo = { .collect = collect_one_tty_info_entry, }; -static int prep_tty_restore(void *unused) +static int prep_tty_restore_cb(struct pprep_head *ph) { if (tty_verify_active_pairs()) return -1; @@ -1568,6 +1568,11 @@ static int prep_tty_restore(void *unused) return 0; } +static struct pprep_head prep_tty_restore = { + .actor = prep_tty_restore_cb,, +}; + + static int collect_one_tty(void *obj, ProtobufCMessage *msg, struct cr_img *i) { struct tty_info *info = obj; @@ -1638,8 +1643,7 @@ static int collect_one_tty(void *obj, ProtobufCMessage *msg, struct cr_img *i) pr_info("Collected tty ID %#x (%s)\n", info->tfe->id, info->driver->name); - if (add_post_prepare_cb_once(prep_tty_restore, NULL)) - return -1; + add_post_prepare_cb_once(&prep_tty_restore); /* * Call it explicitly. Post-callbacks will be called after From a9001753c9e0fa5559c64de6b5aeb11026e7d7aa Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 26 May 2017 15:44:55 +0300 Subject: [PATCH 0636/4375] unix: Use once helper for post-prep Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 21cc42cb3..4b3e248fc 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1367,17 +1367,14 @@ static struct pprep_head resolve_unix_peers = { static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) { struct unix_sk_info *ui = o; - static bool post_queued = false; char *uname, *prefix = ""; int ulen; ui->ue = pb_msg(base, UnixSkEntry); ui->name_dir = (void *)ui->ue->name_dir; - if (ui->ue->peer && !post_queued) { - post_queued = true; - add_post_prepare_cb(&resolve_unix_peers); - } + if (ui->ue->peer) + add_post_prepare_cb_once(&resolve_unix_peers); if (ui->ue->name.len) { if (ui->ue->name.len > UNIX_PATH_MAX) { From d9d9686f3839ba25453f0c69107cd8094549dc8d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 26 May 2017 15:45:09 +0300 Subject: [PATCH 0637/4375] restore: Tune up _once stuff Having ppreh_heads we can simplify the _once helper by re-using the .next field. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/crtools.h | 15 ++++++++++----- criu/pipes.c | 4 +--- criu/sk-unix.c | 4 +--- criu/tty.c | 5 +---- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/criu/include/crtools.h b/criu/include/crtools.h index fb5fe73c0..ec2ca9c7d 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -29,11 +29,16 @@ extern int cr_dedup(void); extern int check_add_feature(char *arg); extern void pr_check_features(const char *offset, const char *sep, int width); -#define add_post_prepare_cb_once(phead) do { \ - static int __cb_called = 0; \ - if (!__cb_called) \ - add_post_prepare_cb(phead); \ - __cb_called = 1; \ +#define PPREP_HEAD_INACTIVE ((struct pprep_head *)-1) + +#define add_post_prepare_cb_once(phead) do { \ + if ((phead)->next == PPREP_HEAD_INACTIVE)\ + add_post_prepare_cb(phead); \ } while (0) +#define MAKE_PPREP_HEAD(name) struct pprep_head name = { \ + .next = PPREP_HEAD_INACTIVE, \ + .actor = name##_cb, \ + } + #endif /* __CR_CRTOOLS_H__ */ diff --git a/criu/pipes.c b/criu/pipes.c index c20fc61c1..cb150f3d7 100644 --- a/criu/pipes.c +++ b/criu/pipes.c @@ -141,9 +141,7 @@ static int mark_pipe_master_cb(struct pprep_head *ph) return 0; } -static struct pprep_head mark_pipe_master = { - .actor = mark_pipe_master_cb, -}; +static MAKE_PPREP_HEAD(mark_pipe_master); static struct pipe_data_rst *pd_hash_pipes[PIPE_DATA_HASH_SIZE]; diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 4b3e248fc..36a256d16 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1360,9 +1360,7 @@ static void unlink_stale(struct unix_sk_info *ui) } static int resolve_unix_peers_cb(struct pprep_head *ph); -static struct pprep_head resolve_unix_peers = { - .actor = resolve_unix_peers_cb, -}; +static MAKE_PPREP_HEAD(resolve_unix_peers); static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) { diff --git a/criu/tty.c b/criu/tty.c index 7338d0cc5..6f359b88e 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -1568,10 +1568,7 @@ static int prep_tty_restore_cb(struct pprep_head *ph) return 0; } -static struct pprep_head prep_tty_restore = { - .actor = prep_tty_restore_cb,, -}; - +static MAKE_PPREP_HEAD(prep_tty_restore); static int collect_one_tty(void *obj, ProtobufCMessage *msg, struct cr_img *i) { From 01e9542fb27d768f9a130ae132da0774ee7f062d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 26 May 2017 15:45:23 +0300 Subject: [PATCH 0638/4375] unix: Sanitize peer resolution with post-prep Having pprep_head built-in it becomes much easier to do socket-by-socket peer resolution. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 36a256d16..e8586e269 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -781,6 +781,7 @@ struct unix_sk_info { char *name_dir; unsigned flags; struct unix_sk_info *peer; + struct pprep_head peer_resolve; /* XXX : union with the above? */ struct file_desc d; struct list_head connected; /* List of sockets, connected to me */ struct list_head node; /* To link in peer's connected list */ @@ -1359,8 +1360,7 @@ static void unlink_stale(struct unix_sk_info *ui) revert_unix_sk_cwd(&cwd_fd, &root_fd); } -static int resolve_unix_peers_cb(struct pprep_head *ph); -static MAKE_PPREP_HEAD(resolve_unix_peers); +static int resolve_unix_peer(struct pprep_head *ph); static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) { @@ -1371,8 +1371,10 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) ui->ue = pb_msg(base, UnixSkEntry); ui->name_dir = (void *)ui->ue->name_dir; - if (ui->ue->peer) - add_post_prepare_cb_once(&resolve_unix_peers); + if (ui->ue->peer) { + ui->peer_resolve.actor = resolve_unix_peer; + add_post_prepare_cb(&ui->peer_resolve); + } if (ui->ue->name.len) { if (ui->ue->name.len > UNIX_PATH_MAX) { @@ -1457,15 +1459,17 @@ static void interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *pe } } -static int resolve_unix_peers_cb(struct pprep_head *ph) +static int resolve_unix_peer(struct pprep_head *ph) { struct unix_sk_info *ui, *peer; - list_for_each_entry(ui, &unix_sockets, list) { + ui = container_of(ph, struct unix_sk_info, peer_resolve); + + { if (ui->peer) - continue; - if (!ui->ue->peer) - continue; + goto out; + + BUG_ON(!ui->ue->peer); peer = find_unix_sk_by_ino(ui->ue->peer); @@ -1480,28 +1484,18 @@ static int resolve_unix_peers_cb(struct pprep_head *ph) peer->queuer = ui->ue->ino; if (ui == peer) /* socket connected to self %) */ - continue; + goto out; if (peer->ue->peer != ui->ue->ino) - continue; + goto out; + pr_info("Connected %#x -> %#x (%#x) flags %#x\n", + ui->ue->ino, ui->ue->peer, peer->ue->ino, ui->flags); set_peer(peer, ui); - /* socketpair or interconnected sockets */ interconnected_pair(ui, peer); } - pr_info("Unix sockets:\n"); - list_for_each_entry(ui, &unix_sockets, list) { - struct fdinfo_list_entry *fle; - - pr_info("\t%#x -> %#x (%#x) flags %#x\n", ui->ue->ino, ui->ue->peer, - ui->peer ? ui->peer->ue->ino : 0, ui->flags); - list_for_each_entry(fle, &ui->d.fd_info_head, desc_list) - pr_info("\t\tfd %d in pid %d\n", - fle->fe->fd, fle->pid); - - } - +out: return 0; } From 62f4275de271f6e7427c53fa1ea56668e26309cb Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 26 May 2017 15:45:37 +0300 Subject: [PATCH 0639/4375] unix: Shift code right (cont) This is the continuation of the previous patch. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 49 ++++++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index e8586e269..fc412023c 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1464,37 +1464,32 @@ static int resolve_unix_peer(struct pprep_head *ph) struct unix_sk_info *ui, *peer; ui = container_of(ph, struct unix_sk_info, peer_resolve); + if (ui->peer) + goto out; - { - if (ui->peer) - goto out; + BUG_ON(!ui->ue->peer); - BUG_ON(!ui->ue->peer); - - peer = find_unix_sk_by_ino(ui->ue->peer); - - if (!peer) { - pr_err("FATAL: Peer %#x unresolved for %#x\n", - ui->ue->peer, ui->ue->ino); - return -1; - } - - set_peer(ui, peer); - if (!peer->queuer) - peer->queuer = ui->ue->ino; - if (ui == peer) - /* socket connected to self %) */ - goto out; - if (peer->ue->peer != ui->ue->ino) - goto out; - - pr_info("Connected %#x -> %#x (%#x) flags %#x\n", - ui->ue->ino, ui->ue->peer, peer->ue->ino, ui->flags); - set_peer(peer, ui); - /* socketpair or interconnected sockets */ - interconnected_pair(ui, peer); + peer = find_unix_sk_by_ino(ui->ue->peer); + if (!peer) { + pr_err("FATAL: Peer %#x unresolved for %#x\n", + ui->ue->peer, ui->ue->ino); + return -1; } + set_peer(ui, peer); + if (!peer->queuer) + peer->queuer = ui->ue->ino; + if (ui == peer) + /* socket connected to self %) */ + goto out; + if (peer->ue->peer != ui->ue->ino) + goto out; + + pr_info("Connected %#x -> %#x (%#x) flags %#x\n", + ui->ue->ino, ui->ue->peer, peer->ue->ino, ui->flags); + set_peer(peer, ui); + /* socketpair or interconnected sockets */ + interconnected_pair(ui, peer); out: return 0; } From c517e4ab0765acbacef3357cbde56d1610d095ba Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 13:56:04 +0300 Subject: [PATCH 0640/4375] unix: Move stale unlink into post-prep The call to unlink() should happen in root task context, while the collection stage is about to be moved into the crtools, so keep the stale-unlink piece in post-prep for a socket. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index fc412023c..cbecb2021 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1360,7 +1360,19 @@ static void unlink_stale(struct unix_sk_info *ui) revert_unix_sk_cwd(&cwd_fd, &root_fd); } -static int resolve_unix_peer(struct pprep_head *ph); +static int resolve_unix_peer(struct unix_sk_info *ui); + +static int post_prepare_unix_sk(struct pprep_head *ph) +{ + struct unix_sk_info *ui; + + ui = container_of(ph, struct unix_sk_info, peer_resolve); + if (ui->ue->peer && resolve_unix_peer(ui)) + return -1; + if (ui->name) + unlink_stale(ui); + return 0; +} static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) { @@ -1371,11 +1383,6 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) ui->ue = pb_msg(base, UnixSkEntry); ui->name_dir = (void *)ui->ue->name_dir; - if (ui->ue->peer) { - ui->peer_resolve.actor = resolve_unix_peer; - add_post_prepare_cb(&ui->peer_resolve); - } - if (ui->ue->name.len) { if (ui->ue->name.len > UNIX_PATH_MAX) { pr_err("Bad unix name len %d\n", (int)ui->ue->name.len); @@ -1383,8 +1390,6 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) } ui->name = (void *)ui->ue->name.data; - - unlink_stale(ui); } else ui->name = NULL; @@ -1421,6 +1426,11 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) prefix, ulen, uname, ui->name_dir ? ui->name_dir : "-"); + if (ui->ue->peer || ui->name) { + ui->peer_resolve.actor = post_prepare_unix_sk; + add_post_prepare_cb(&ui->peer_resolve); + } + list_add_tail(&ui->list, &unix_sockets); return file_desc_add(&ui->d, ui->ue->id, &unix_desc_ops); } @@ -1459,11 +1469,10 @@ static void interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *pe } } -static int resolve_unix_peer(struct pprep_head *ph) +static int resolve_unix_peer(struct unix_sk_info *ui) { - struct unix_sk_info *ui, *peer; + struct unix_sk_info *peer; - ui = container_of(ph, struct unix_sk_info, peer_resolve); if (ui->peer) goto out; From ce68a85cee1aedae102a8c095046ad8d7944b460 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 13:56:31 +0300 Subject: [PATCH 0641/4375] fsnotofy: Do remap resolve in post-prep The remap is searhced by dev:ino pair that is known only when root task starts (and opend the remap). The collection stage is about to happen in crtools, so move the resolve in post-prep. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/fsnotify.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index cb1b32ca3..6ceafaa9c 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -57,6 +57,7 @@ struct fsnotify_mark_info { InotifyWdEntry *iwe; FanotifyMarkEntry *fme; }; + struct pprep_head prep; /* XXX union with remap */ struct file_remap *remap; }; @@ -721,6 +722,24 @@ static struct file_desc_ops fanotify_desc_ops = { .open = open_fanotify_fd, }; +static int inotify_resolve_remap(struct pprep_head *ph) +{ + struct fsnotify_mark_info *m; + + m = container_of(ph, struct fsnotify_mark_info, prep); + m->remap = lookup_ghost_remap(m->iwe->s_dev, m->iwe->i_ino); + return 0; +} + +static int fanotify_resolve_remap(struct pprep_head *ph) +{ + struct fsnotify_mark_info *m; + + m = container_of(ph, struct fsnotify_mark_info, prep); + m->remap = lookup_ghost_remap(m->fme->s_dev, m->fme->ie->i_ino); + return 0; +} + static int __collect_inotify_mark(struct fsnotify_file_info *p, struct fsnotify_mark_info *mark) { struct fsnotify_mark_info *m; @@ -734,7 +753,8 @@ static int __collect_inotify_mark(struct fsnotify_file_info *p, struct fsnotify_ break; list_add_tail(&mark->list, &m->list); - mark->remap = lookup_ghost_remap(mark->iwe->s_dev, mark->iwe->i_ino); + mark->prep.actor = inotify_resolve_remap; + add_post_prepare_cb(&mark->prep); return 0; } @@ -742,9 +762,10 @@ static int __collect_fanotify_mark(struct fsnotify_file_info *p, struct fsnotify_mark_info *mark) { list_add(&mark->list, &p->marks); - if (mark->fme->type == MARK_TYPE__INODE) - mark->remap = lookup_ghost_remap(mark->fme->s_dev, - mark->fme->ie->i_ino); + if (mark->fme->type == MARK_TYPE__INODE) { + mark->prep.actor = fanotify_resolve_remap; + add_post_prepare_cb(&mark->prep); + } return 0; } From d77d8cc402e597bb38edfb4e81db89fd7d96d0b6 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 29 Jun 2017 14:19:32 +0000 Subject: [PATCH 0642/4375] fix building with newer glibc Newer glibc releases have removed SIGUNUSED from bits/signum.h which breaks building criu on those systems: https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=8082d91e1c449e0cb137468b731004a5e605c8c6 SIGSYS returns the same value as SIGUNUSED and testing has shown that criu still successfully completes zdtm with this patch. Signed-off-by: Adrian Reber Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 1 - test/zdtm/static/pthread01.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index e8fb4adf8..6ba50f183 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -880,7 +880,6 @@ static void zombie_prepare_signals(void) (1 << SIGPOLL) |\ (1 << SIGIO) |\ (1 << SIGSYS) |\ - (1 << SIGUNUSED)|\ (1 << SIGSTKFLT)|\ (1 << SIGPWR) \ ) diff --git a/test/zdtm/static/pthread01.c b/test/zdtm/static/pthread01.c index 52f849c06..2520fcfee 100644 --- a/test/zdtm/static/pthread01.c +++ b/test/zdtm/static/pthread01.c @@ -43,7 +43,7 @@ static char *decode_signal(const sigset_t *s, char *buf) COLLECT(SIGTERM); COLLECT(SIGSTKFLT); COLLECT(SIGCHLD); COLLECT(SIGCONT); COLLECT(SIGSTOP); COLLECT(SIGTSTP); COLLECT(SIGTTIN); COLLECT(SIGTTOU); COLLECT(SIGURG); COLLECT(SIGXCPU); COLLECT(SIGXFSZ); COLLECT(SIGVTALRM); COLLECT(SIGPROF); COLLECT(SIGWINCH); COLLECT(SIGIO); - COLLECT(SIGPOLL); COLLECT(SIGPWR); COLLECT(SIGSYS); COLLECT(SIGUNUSED); + COLLECT(SIGPOLL); COLLECT(SIGPWR); COLLECT(SIGSYS); #undef COLLECT return buf; From 624aa178dcc7e4f0c7db13229f557473692590dd Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 30 Jun 2017 04:11:43 +0300 Subject: [PATCH 0643/4375] zdtm: don't call Popen() without wait() We have to collect all zombies Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 114e7f4cd..79f1a099a 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1712,7 +1712,7 @@ def run_tests(opts): finally: l.finish() if opts['join_ns']: - subprocess.Popen(["ip", "netns", "delete", "zdtm_netns"]) + subprocess.Popen(["ip", "netns", "delete", "zdtm_netns"]).wait() sti_fmt = "%-40s%-10s%s" From 3ed5c2f0ee3da0342bcd412818f2dcc186d788ac Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 30 Jun 2017 20:31:47 +0200 Subject: [PATCH 0644/4375] criu/files: Fix wait_fds_event() for 64 bit platforms The htole64() function returns a 64 bit value. This is stored in a 32 bit integer in wait_fds_event() which results in 0 for big-endian 64 bit platforms. The fuxtex() system call also requires 32 bit values. Fix this and use htole32() also for 64 bit platforms. Signed-off-by: Michael Holzheu Signed-off-by: Andrei Vagin --- criu/files.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/criu/files.c b/criu/files.c index 46adac2e1..8aafa8929 100644 --- a/criu/files.c +++ b/criu/files.c @@ -178,11 +178,8 @@ void wait_fds_event(void) { futex_t *f = ¤t->task_st; int value; -#if BITS_PER_LONG == 64 - value = htole64(FDS_EVENT); -#else + value = htole32(FDS_EVENT); -#endif futex_wait_if_cond(f, value, &); clear_fds_event(); } From 2f886ca174884b3d5f6554294f24d6c2affb4bd9 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 30 Jun 2017 20:31:48 +0200 Subject: [PATCH 0645/4375] criu/mount: Fix flags cast and sizeof(sflags) The "args" parameter in apply_sb_flags() is unsigned long. Therefore also use unsigned long for the cast. The "sflags" variable in do_new_mount() is unsigned long. Therefore use sizeof(sflags) instead of sizeof(int). Signed-off-by: Michael Holzheu Signed-off-by: Andrei Vagin --- criu/mount.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index af17cb038..8773ca2e8 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1773,8 +1773,8 @@ static char *mnt_fsname(struct mount_info *mi) static int apply_sb_flags(void *args, int fd, pid_t pid) { + unsigned long flags = *(unsigned long *) args; int rst = -1, err = -1; - long flags = *(int *) args; char path[PSFDS]; snprintf(path, sizeof(path), "/proc/self/fd/%d", fd); @@ -1839,10 +1839,9 @@ static int do_new_mount(struct mount_info *mi) pr_perror("Unable to open %s", mi->mountpoint); return -1; } - sflags |= MS_RDONLY; if (userns_call(apply_sb_flags, 0, - &sflags, sizeof(int), fd)) { + &sflags, sizeof(sflags), fd)) { pr_perror("Unable to apply mount falgs %d for %s", mi->sb_flags, mi->mountpoint); close(fd); From a01d879b627f72eddd8cd3201da83c5182c485a1 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 30 Jun 2017 20:31:49 +0200 Subject: [PATCH 0646/4375] zdtm/static/fdt_shared: Fix buffer size The TEST_STRING "Hello World!" has 13 bytes size. Therefore the 10 bytes used for the buffer size are not sufficient. Fix this and use sizeof() to be on the safe side. Signed-off-by: Michael Holzheu Signed-off-by: Andrei Vagin --- test/zdtm/static/fdt_shared.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/zdtm/static/fdt_shared.c b/test/zdtm/static/fdt_shared.c index b1c74d0ae..2111356f5 100644 --- a/test/zdtm/static/fdt_shared.c +++ b/test/zdtm/static/fdt_shared.c @@ -62,7 +62,7 @@ static pid_t clone_child(int (*fn)(void *), int flags) static int child2(void *_arg) { - char buf[10]; + char buf[sizeof(TEST_STRING)]; forked(); test_waitsig(); @@ -90,7 +90,7 @@ static int child3(void *_arg) static int child(void *_arg) { - char buf[10]; + char buf[sizeof(TEST_STRING)]; pid_t pid, pid2; int status; From adc47efdd2e3731f2a542ec61b724556e11c55ec Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Fri, 30 Jun 2017 20:31:50 +0200 Subject: [PATCH 0647/4375] zdtm/static/sem: Use "union semun" instead of int Use "union semun" for semctl() to make testcase also work on s390x. Signed-off-by: Alice Frosi Signed-off-by: Andrei Vagin --- test/zdtm/static/sem.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/test/zdtm/static/sem.c b/test/zdtm/static/sem.c index 6e459a883..1db8f0082 100644 --- a/test/zdtm/static/sem.c +++ b/test/zdtm/static/sem.c @@ -110,7 +110,13 @@ int main(int argc, char **argv) { int id, key; int i; - int val[NSEMS]; + /* See man semctl */ + union semun { + int val; + struct semid_ds *buf; + unsigned short *array; + struct seminfo *__buf; + } val[NSEMS]; int ret, fail_count = 0; test_init(argc, argv); @@ -129,7 +135,7 @@ int main(int argc, char **argv) } for (i = 0; i < NSEMS; i++) { - val[i] = lrand48() & 0x7; + val[i].val = lrand48() & 0x7; if (semctl(id, i, SETVAL, val[i]) == -1) { fail_count++; @@ -142,7 +148,7 @@ int main(int argc, char **argv) test_waitsig(); for (i = 0; i < NSEMS; i++) { - ret = check_sem_by_id(id, i, val[i]); + ret = check_sem_by_id(id, i, val[i].val); if (ret < 0) { fail_count++; fail("Check sem %d by id failed", i); @@ -155,14 +161,14 @@ int main(int argc, char **argv) goto out_destroy; } - val[i] = semctl(id, 0, GETVAL); - if (val[i] < 0) { + val[i].val = semctl(id, 0, GETVAL); + if (val[i].val < 0) { fail("Failed to get sem %d value", i); fail_count++; goto out_destroy; } - if (val[i] != 0) { - fail("Non-zero sem %d value: %d", i, val[i]); + if (val[i].val != 0) { + fail("Non-zero sem %d value: %d", i, val[i].val); fail_count++; } } From 8fcfa59b0486454dea9a8cc03d5d74918566ebb8 Mon Sep 17 00:00:00 2001 From: Veronika Kabatova Date: Tue, 20 Jun 2017 15:14:08 +0200 Subject: [PATCH 0648/4375] Add long option for verbosity changes Only long options are supported in configuration files. "-v" is the only short option which doesn't have a corresponding long option, therefore users wouldn't be able to setup verbosity in configuration files without this patch. Signed-off-by: Veronika Kabatova Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 7 ++++--- criu/crtools.c | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 779bca095..24fba66d5 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -32,11 +32,12 @@ Common options ~~~~~~~~~~~~~~ Common options are applicable to any 'command'. -*-v*[*v*...]:: +*-v*[*v*...], *--verbosity*:: Increase verbosity up from the default level. Multiple *v* can be used, - each increasing verbosity by one level. + each increasing verbosity by one level. Using long option without argument + increases verbosity by one level. -*-v*'num':: +*-v*'num', *--verbosity*='num':: Set verbosity level to 'num'. The higher the level, the more output is produced. + diff --git a/criu/crtools.c b/criu/crtools.c index c3950cb16..6bc22eddf 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -291,6 +291,7 @@ int main(int argc, char *argv[], char *envp[]) BOOL_OPT("weak-sysctls", &opts.weak_sysctls), { "status-fd", required_argument, 0, 1088 }, { SK_CLOSE_PARAM, no_argument, 0, 1089 }, + { "verbosity", optional_argument, 0, 'v' }, { }, }; @@ -896,8 +897,8 @@ usage: "* Logging:\n" " -o|--log-file FILE log file name\n" " --log-pid enable per-process logging to separate FILE.pid files\n" -" -v[v...] increase verbosity (can use multiple v)\n" -" -vNUM set verbosity to NUM (higher level means more output):\n" +" -v[v...]|--verbosity increase verbosity (can use multiple v)\n" +" -vNUM|--verbosity=NUM set verbosity to NUM (higher level means more output):\n" " -v1 - only errors and messages\n" " -v2 - also warnings (default level)\n" " -v3 - also information messages and timestamps\n" From 3c62d950e2966b26ab9db3c74c8c0680679be632 Mon Sep 17 00:00:00 2001 From: Veronika Kabatova Date: Tue, 20 Jun 2017 15:14:09 +0200 Subject: [PATCH 0649/4375] Change tcp-close option to negated style Code for tcp-close option was added after boolean-valued options were modified to accept their negations as well. Since tcp-close option works only with boolean values and does not accept any argument, it should be wriiten in the same manner to allow users to override the value when using configuration files. Signed-off-by: Veronika Kabatova Signed-off-by: Andrei Vagin --- criu/crtools.c | 5 +---- criu/include/cr_options.h | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index 6bc22eddf..e7a21ad61 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -290,7 +290,7 @@ int main(int argc, char *argv[], char *envp[]) BOOL_OPT("display-stats", &opts.display_stats), BOOL_OPT("weak-sysctls", &opts.weak_sysctls), { "status-fd", required_argument, 0, 1088 }, - { SK_CLOSE_PARAM, no_argument, 0, 1089 }, + BOOL_OPT(SK_CLOSE_PARAM, &opts.tcp_close), { "verbosity", optional_argument, 0, 'v' }, { }, }; @@ -570,9 +570,6 @@ int main(int argc, char *argv[], char *envp[]) return 1; } break; - case 1089: - opts.tcp_close = true; - break; case 'V': pr_msg("Version: %s\n", CRIU_VERSION); if (strcmp(CRIU_GITID, "0")) diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index 45ee6cb1b..b66742f9b 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -63,7 +63,7 @@ struct cr_options { int shell_job; int handle_file_locks; int tcp_established_ok; - bool tcp_close; + int tcp_close; int evasive_devices; int link_remap_ok; int log_file_per_pid; From eda4bc554a38823d3b9901e6c9dedd92674377f4 Mon Sep 17 00:00:00 2001 From: "Bernhard M. Wiedemann" Date: Fri, 30 Jun 2017 12:59:00 +0300 Subject: [PATCH 0650/4375] kdat: allow to override build time in order to allow for reproducible builds. See https://reproducible-builds.org/ for why this is good and https://reproducible-builds.org/specs/source-date-epoch/ for the definition of this variable. Signed-off-by: Bernhard M. Wiedemann Signed-off-by: Pavel Emelyanov --- criu/Makefile.crtools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index adc64ef7a..6b3fbdfb6 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -1,7 +1,7 @@ ccflags-y += -iquote criu/$(ARCH) ccflags-y += $(COMPEL_UAPI_INCLUDES) CFLAGS_REMOVE_clone-noasan.o += $(CFLAGS-ASAN) -CFLAGS_kerndat.o += -DKDAT_MAGIC_2=${shell date +%s} -DKDAT_RUNDIR=\"$(RUNDIR)\" +CFLAGS_kerndat.o += -DKDAT_MAGIC_2=${shell echo $${SOURCE_DATE_EPOCH:-$$(date +%s)}} -DKDAT_RUNDIR=\"$(RUNDIR)\" ldflags-y += -r obj-y += action-scripts.o From 3ef5a5e20ae420fb7409cb6d50e99d4b18a96c8b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 29 Jun 2017 20:34:00 +0300 Subject: [PATCH 0651/4375] sk-packet: Don't open image when not needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It looks like this call to open_image was left from the times when we reworked packets sending and collected them early. ✓ travis-ci: success for sk-packet: Don't open image when not needed Signed-off-by: Pavel Emelyanov --- criu/sk-queue.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/criu/sk-queue.c b/criu/sk-queue.c index f92d020db..28578b4a7 100644 --- a/criu/sk-queue.c +++ b/criu/sk-queue.c @@ -200,17 +200,12 @@ err_brk: int restore_sk_queue(int fd, unsigned int peer_id) { struct sk_packet *pkt, *tmp; - int ret; - struct cr_img *img; + int ret = -1; pr_info("Trying to restore recv queue for %u\n", peer_id); if (restore_prepare_socket(fd)) - return -1; - - img = open_image(CR_FD_SK_QUEUES, O_RSTR); - if (!img) - return -1; + goto out; list_for_each_entry_safe(pkt, tmp, &packets_list, list) { SkPacketEntry *entry = pkt->entry; @@ -233,21 +228,20 @@ int restore_sk_queue(int fd, unsigned int peer_id) xfree(pkt->data); if (ret < 0) { pr_perror("Failed to send packet"); - goto err; + goto out; } if (ret != entry->length) { pr_err("Restored skb trimmed to %d/%d\n", ret, (unsigned int)entry->length); - goto err; + ret = -1; + goto out; } list_del(&pkt->list); sk_packet_entry__free_unpacked(entry, NULL); xfree(pkt); } - close_image(img); - return 0; -err: - close_image(img); - return -1; + ret = 0; +out: + return ret; } From e3311ea37b7e851bb746ce7cf180e70c050ac98e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 29 Jun 2017 13:24:55 +0300 Subject: [PATCH 0652/4375] cgroup: Skip unified hier controllers (v2) The unified hierarchy controller doesn't have any name, so criu hangs while parsing this sort of strings. Let's skip those for now, until we implement cgroup2 support. https://github.com/xemul/criu/issues/252 v2: Code comments Reported-and-tested-by: Adrian Reber Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/proc_parse.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/criu/proc_parse.c b/criu/proc_parse.c index d0199b456..5da8a47d3 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -2252,8 +2252,19 @@ int parse_cgroup_file(FILE *f, struct list_head *retl, unsigned int *n) * 2:name=systemd:/user.slice/user-1000.slice/session-1.scope */ name = strchr(buf, ':'); - if (name) + if (name) { path = strchr(++name, ':'); + if (*name == ':') { + /* + * It's unified hierarchy. On kernels with legacy + * tree this item is added automatically, so we + * can just skip one. For those with full unified + * support is on ... we need to write new code. + */ + xfree(ncc); + continue; + } + } if (!name || !path) { pr_err("Failed parsing cgroup %s\n", buf); xfree(ncc); @@ -2417,6 +2428,13 @@ int collect_controllers(struct list_head *cgroups, unsigned int *n_cgroups) } controllers++; + if (*controllers == ':') + /* + * Unified hier. See comment in parse_cgroup_file + * for more details. + */ + continue; + off = strchr(controllers, ':'); if (!off) { pr_err("Unable to parse \"%s\"\n", buf); From 245b4b3698a3f605f7ae313ff46e2b6ba6fc2c38 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Jul 2017 00:44:44 +0300 Subject: [PATCH 0653/4375] files: Don't access value from stack in outer contex The struct fd_link link allocated in inner context might be freed before dump call (depending on compiler), instead use a safer approach. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/files.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/criu/files.c b/criu/files.c index 8aafa8929..72f98ef4d 100644 --- a/criu/files.c +++ b/criu/files.c @@ -407,8 +407,11 @@ static const struct fdtype_ops *get_mem_dev_ops(struct fd_parms *p, int minor) static int dump_chrdev(struct fd_parms *p, int lfd, struct cr_img *img) { + struct fd_link *link_old = p->link; int maj = major(p->stat.st_rdev); const struct fdtype_ops *ops; + struct fd_link link; + int err; switch (maj) { case MEM_MAJOR: @@ -423,8 +426,6 @@ static int dump_chrdev(struct fd_parms *p, int lfd, struct cr_img *img) char more[32]; if (is_tty(p->stat.st_rdev, p->stat.st_dev)) { - struct fd_link link; - if (fill_fdlink(lfd, p, &link)) return -1; p->link = &link; @@ -433,11 +434,15 @@ static int dump_chrdev(struct fd_parms *p, int lfd, struct cr_img *img) } sprintf(more, "%d:%d", maj, minor(p->stat.st_rdev)); - return dump_unsupp_fd(p, lfd, img, "chr", more); + err = dump_unsupp_fd(p, lfd, img, "chr", more); + p->link = link_old; + return err; } } - return do_dump_gen_file(p, lfd, ops, img); + err = do_dump_gen_file(p, lfd, ops, img); + p->link = link_old; + return err; } static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, From b0b9a9708610787fcc79b6835ebb03337ec92328 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 18 Jul 2017 21:55:27 +0300 Subject: [PATCH 0654/4375] criu: Version 3.3 Most of the changes this time are preparation for future new features and optimizations, that hasn't yet been well tested and polished. However, we have several new features. The most important one is the --tcp-close option to help migration of Docker containers, that constantly change their IP address. And, as usually, a set of bugfixes. Signed-off-by: Pavel Emelyanov --- Makefile.versions | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index b6e17e55d..397416308 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 2 -CRIU_VERSION_SUBLEVEL := 1 +CRIU_VERSION_MINOR := 3 +CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Tin Hoopoe +CRIU_VERSION_NAME := Crystal Pelican CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From 43ed56e3127bed8ea715a1d185c105e6e9092f67 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 5 Jul 2017 16:59:29 +0300 Subject: [PATCH 0655/4375] net: Support "dumping" dummy sit device This device is an API endpoint, just skip it. Also, prepare the ground for sit dump. Issue #11 Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/net.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/criu/net.c b/criu/net.c index 9b704f96d..e4bb9b203 100644 --- a/criu/net.c +++ b/criu/net.c @@ -635,6 +635,31 @@ static int dump_one_gre(struct ifinfomsg *ifi, char *kind, return dump_unknown_device(ifi, kind, tb, fds); } +static int dump_one_sit(struct ifinfomsg *ifi, char *kind, + struct nlattr **tb, struct cr_imgset *fds) +{ + char *name; + + if (strcmp(kind, "sit")) { + pr_err("SIT device with %s kind\n", kind); + return -1; + } + + name = (char *)RTA_DATA(tb[IFLA_IFNAME]); + if (!name) { + pr_err("sit device %d has no name\n", ifi->ifi_index); + return -1; + } + + if (!strcmp(name, "sit0")) { + pr_info("found %s, ignoring\n", name); + return 0; + } + + pr_warn("SIT device %s not supported natively\n", name); + return dump_unknown_device(ifi, kind, tb, fds); +} + static int dump_one_link(struct nlmsghdr *hdr, void *arg) { struct cr_imgset *fds = arg; @@ -673,6 +698,9 @@ static int dump_one_link(struct nlmsghdr *hdr, void *arg) case ARPHRD_IPGRE: ret = dump_one_gre(ifi, kind, tb, fds); break; + case ARPHRD_SIT: + ret = dump_one_sit(ifi, kind, tb, fds); + break; default: unk: ret = dump_unknown_device(ifi, kind, tb, fds); From 43d4a835110190070085968f61712576eeb34625 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 8 Aug 2017 15:59:00 +0300 Subject: [PATCH 0656/4375] Update README.md (Try to) Fix the readme problems found by the feedmereadmes guys: * Tuned up the tagline * Added info about what for, history, competitors, etc. * Put more links for potential contributors --- README.md | 54 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 343c63986..90ce1652f 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,51 @@

-## CRIU (Checkpoint and Restore in Userspace) +## CRIU -- A project to implement checkpoint/restore functionality for Linux -An utility to checkpoint/restore tasks. Using this tool, you can freeze a -running application (or part of it) and checkpoint it to a hard drive as a -collection of files. You can then use the files to restore and run the +CRIU (stands for Checkpoint and Restore in Userspace) is an utility to checkpoint/restore Linux tasks. + +Using this tool, you can freeze a running application (or part of it) and checkpoint +it to a hard drive as a collection of files. You can then use the files to restore and run the application from the point it was frozen at. The distinctive feature of the CRIU -project is that it is mainly implemented in user space. +project is that it is mainly implemented in user space. There are some more projects +doing C/R for Linux, and so far CRIU [appears to be](https://criu.org/Comparison_to_other_CR_projects) +the most feature-reach and up-to-date with the kernel. -Also, CRIU provides a library for Live migration, and exposes two low-level -core features as standalone libraries. Thes are libcompel for parasite code -injection and libsoccr for TCP connections checkpoint-restore. - -The project home is at http://criu.org. +The project [started](https://criu.org/History) as the way to do live migration for OpenVZ +Linux containers, but later grew to more sophisticated and flexible tool. It is currently +used by (integrated into) OpenVZ, LXC/LXD, Docker, and other software, project gets tremendous +help from the community, and its packages are included into many Linux distributions. +The project home is at http://criu.org. This wiki contains all the knowledge base for CRIU we have. Pages worth starting with are: -- [Kernel configuration, compilation, etc](http://criu.org/Installation) +- [Installation instructions](http://criu.org/Installation) - [A simple example of usage](http://criu.org/Simple_loop) -- [More sophisticated example with graphical app](http://criu.org/VNC) +- [Examples of more advanced usage](https://criu.org/Category:HOWTO) +- Troubleshooting can be hard, some help can be found [here](https://criu.org/When_C/R_fails), [here](https://criu.org/What_cannot_be_checkpointed) and [here](https://criu.org/FAQ) ### A video tour on basic CRIU features [![CRIU introduction](https://asciinema.org/a/7fnt2prsumvxiwf3ng61fgct3.png)](https://asciinema.org/a/7fnt2prsumvxiwf3ng61fgct3) -## Live migration +## Advanced features + +As main usage for CRIU is live migration, there's a library for it called P.Haul. Also the +project exposes two cool core features as standalone libraries. These are libcompel for parasite code +injection and libsoccr for TCP connections checkpoint-restore. + +### Live migration True [live migration](https://criu.org/Live_migration) using CRIU is possible, but doing all the steps by hands might be complicated. The [phaul sub-project](https://criu.org/P.Haul) provides a Go library that incapsulates most of the complexity. -## Parasite code ijection +### Parasite code ijection In order to get state of the running process CRIU needs to make this process execute some code, that would fetch the required information. To make this happen without killing the application itself, CRIU uses the [parasite code injection](https://criu.org/Parasite_code) technique, which is also available as a standalone library called [libcompel](https://criu.org/Compel). -## TCP sockets checkpoint-restore +### TCP sockets checkpoint-restore One of the CRIu features is the ability to save and restore state of a TCP socket without breaking the connection. This functionality is considered to be useful by @@ -43,10 +53,18 @@ tiself, and we have it available as the [libsoccr library](https://criu.org/Libs ## How to contribute -* [How to submit patches](http://criu.org/How_to_submit_patches); -* Send all bug reports to [mailing -list](https://lists.openvz.org/mailman/listinfo/criu); +CRIU project is (almost) the never ending story, because we have to always keep-up with the +Linux kernel supporting checkpoint and restore for all the features it provides. Thus we're +looking for contributors of all kinds -- feedback, bug reports, testing, coding, writing, etc. +Here are some useful hints to get involved. + +* We have both -- [very simple](https://github.com/xemul/criu/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) and [more sophisticated](https://github.com/xemul/criu/issues?q=is%3Aissue+is%3Aopen+label%3A%22new+feature%22) coding tasks; +* CRIU does need [extensive testing](https://github.com/xemul/criu/issues?q=is%3Aissue+is%3Aopen+label%3Atesting); +* Documentation is always hard, we have [some information](https://criu.org/Category:Empty_articles) that is to be extracted from people's heads into wiki pages as well as [some texts](https://criu.org/Category:Editor_help_needed) that all need to be converted into useful articles; +* Feedback is expected on the github issues page and on the [mailing list](https://lists.openvz.org/mailman/listinfo/criu); +* For historical reasons we do not accept PRs, instead [patches are welcome](http://criu.org/How_to_submit_patches); * Spread the word about CRIU in [social networks](http://criu.org/Contacts); +* If you're giving a talk about CRIU -- let us know, we'll mention it on the [wiki main page](https://criu.org/News/events); ## Licence From 447312cf582a4628962fade00af487d58e2b3fea Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Tue, 8 Aug 2017 23:39:57 +0300 Subject: [PATCH 0657/4375] docs: Fix errata in README.md Signed-off-by: Pavel Begunkov --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 90ce1652f..0c122bec2 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,14 @@ ## CRIU -- A project to implement checkpoint/restore functionality for Linux -CRIU (stands for Checkpoint and Restore in Userspace) is an utility to checkpoint/restore Linux tasks. +CRIU (stands for Checkpoint and Restore in Userspace) is a utility to checkpoint/restore Linux tasks. Using this tool, you can freeze a running application (or part of it) and checkpoint it to a hard drive as a collection of files. You can then use the files to restore and run the application from the point it was frozen at. The distinctive feature of the CRIU project is that it is mainly implemented in user space. There are some more projects doing C/R for Linux, and so far CRIU [appears to be](https://criu.org/Comparison_to_other_CR_projects) -the most feature-reach and up-to-date with the kernel. +the most feature-rich and up-to-date with the kernel. The project [started](https://criu.org/History) as the way to do live migration for OpenVZ Linux containers, but later grew to more sophisticated and flexible tool. It is currently @@ -36,9 +36,9 @@ injection and libsoccr for TCP connections checkpoint-restore. True [live migration](https://criu.org/Live_migration) using CRIU is possible, but doing all the steps by hands might be complicated. The [phaul sub-project](https://criu.org/P.Haul) -provides a Go library that incapsulates most of the complexity. +provides a Go library that encapsulates most of the complexity. -### Parasite code ijection +### Parasite code injection In order to get state of the running process CRIU needs to make this process execute some code, that would fetch the required information. To make this happen without @@ -47,13 +47,13 @@ technique, which is also available as a standalone library called [libcompel](ht ### TCP sockets checkpoint-restore -One of the CRIu features is the ability to save and restore state of a TCP socket +One of the CRIU features is the ability to save and restore state of a TCP socket without breaking the connection. This functionality is considered to be useful by -tiself, and we have it available as the [libsoccr library](https://criu.org/Libsoccr). +itself, and we have it available as the [libsoccr library](https://criu.org/Libsoccr). ## How to contribute -CRIU project is (almost) the never ending story, because we have to always keep-up with the +CRIU project is (almost) the never-ending story, because we have to always keep up with the Linux kernel supporting checkpoint and restore for all the features it provides. Thus we're looking for contributors of all kinds -- feedback, bug reports, testing, coding, writing, etc. Here are some useful hints to get involved. From b7b3b19f7e9601195237aab2cccf9e6a1a524b56 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 13:56:49 +0300 Subject: [PATCH 0658/4375] pb: Add a helper to collect single entry Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/protobuf.h | 1 + criu/protobuf.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/criu/include/protobuf.h b/criu/include/protobuf.h index 6097ba0bb..fb7489e9d 100644 --- a/criu/include/protobuf.h +++ b/criu/include/protobuf.h @@ -40,6 +40,7 @@ struct collect_image_info { #define COLLECT_HAPPENED 0x4 /* image was opened and collected */ extern int collect_image(struct collect_image_info *); +extern int collect_entry(ProtobufCMessage *base, struct collect_image_info *cinfo); static inline int collect_images(struct collect_image_info **array, unsigned size) { diff --git a/criu/protobuf.c b/criu/protobuf.c index 219c7c088..8eb73e019 100644 --- a/criu/protobuf.c +++ b/criu/protobuf.c @@ -172,6 +172,37 @@ err: return ret; } +int collect_entry(ProtobufCMessage *msg, struct collect_image_info *cinfo) +{ + void *obj; + void *(*o_alloc)(size_t size) = malloc; + void (*o_free)(void *ptr) = free; + + if (cinfo->flags & COLLECT_SHARED) { + o_alloc = shmalloc; + o_free = shfree_last; + } + + if (cinfo->priv_size) { + obj = o_alloc(cinfo->priv_size); + if (!obj) + return -1; + } else + obj = NULL; + + cinfo->flags |= COLLECT_HAPPENED; + if (cinfo->collect(obj, msg, NULL) < 0) { + o_free(obj); + cr_pb_descs[cinfo->pb_type].free(msg, NULL); + return -1; + } + + if (!cinfo->priv_size && !(cinfo->flags & COLLECT_NOFREE)) + cr_pb_descs[cinfo->pb_type].free(msg, NULL); + + return 0; +} + int collect_image(struct collect_image_info *cinfo) { int ret; From 904e7b383b8c9a420f5068e74070ce72855c48f4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 13:57:06 +0300 Subject: [PATCH 0659/4375] file: Introduce prepare_files() I'm about to merge all the file images into one big image, so here's the place that would read it and collect. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/files.c | 10 +++++++--- criu/include/files.h | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 6ba50f183..e62443ba5 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -222,7 +222,7 @@ static int restore_finish_ns_stage(int from, int to) static int crtools_prepare_shared(void) { - if (prepare_shared_fdinfo()) + if (prepare_files()) return -1; /* We might want to remove ghost files on failed restore */ diff --git a/criu/files.c b/criu/files.c index 72f98ef4d..41a8e0913 100644 --- a/criu/files.c +++ b/criu/files.c @@ -54,14 +54,12 @@ #define FDESC_HASH_SIZE 64 static struct hlist_head file_desc_hash[FDESC_HASH_SIZE]; -int prepare_shared_fdinfo(void) +static void init_fdesc_hash(void) { int i; for (i = 0; i < FDESC_HASH_SIZE; i++) INIT_HLIST_HEAD(&file_desc_hash[i]); - - return 0; } void file_desc_init(struct file_desc *d, u32 id, struct file_desc_ops *ops) @@ -1665,3 +1663,9 @@ int open_transport_socket(void) return 0; } + +int prepare_files(void) +{ + init_fdesc_hash(); + return 0; +} diff --git a/criu/include/files.h b/criu/include/files.h index 5aa613935..ee9b2569f 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -157,7 +157,7 @@ extern void show_saved_files(void); extern int prepare_fds(struct pstree_item *me); extern int prepare_fd_pid(struct pstree_item *me); extern int prepare_ctl_tty(int pid, struct rst_info *rst_info, u32 ctl_tty_id); -extern int prepare_shared_fdinfo(void); +extern int prepare_files(void); extern int restore_fs(struct pstree_item *); extern int prepare_fs_pid(struct pstree_item *); extern int set_fd_flags(int fd, int flags); From fe6fa3bec3249393c9cd2ead0d095e2bb9d92dad Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 13:57:22 +0300 Subject: [PATCH 0660/4375] image: Introduce files.img and file_entry There are two goals of this merge. First is to reduce the amount of image files we generate and scan on restore. The latter is more importaint, as even if we have no weird stuff like signalfd, we still try to open this file. So after the merge we try to open ~15 image files (out of ~30) less %) which is nice. The 2nd goal is to simplify the C/R support for SCM messages. This becomes possible with the fact, that all files we have can be distinguished by their ID only, w/o type. This, in turn, makes image layout for SCMs much simpler. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 7 +++++++ criu/files.c | 24 +++++++++++++++++++++++- criu/image-desc.c | 1 + criu/include/files.h | 3 +++ criu/include/image-desc.h | 1 + criu/include/magic.h | 1 + criu/include/protobuf-desc.h | 1 + images/fdinfo.proto | 5 +++++ lib/py/images/images.py | 1 + 9 files changed, 43 insertions(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index e62443ba5..e48088be6 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -278,6 +278,9 @@ static struct collect_image_info *cinfos[] = { &sk_queues_cinfo, }; +static struct collect_image_info *cinfos_files[] = { +}; + /* These images are requered to restore namespaces */ static struct collect_image_info *before_ns_cinfos[] = { &tty_info_cinfo, /* Restore devpts content */ @@ -320,6 +323,10 @@ static int root_prepare_shared(void) if (collect_images(cinfos, ARRAY_SIZE(cinfos))) return -1; + if (!files_collected() && + collect_images(cinfos_files, ARRAY_SIZE(cinfos_files))) + return -1; + for_each_pstree_item(pi) { if (pi->pid->state == TASK_HELPER) continue; diff --git a/criu/files.c b/criu/files.c index 41a8e0913..388bd281c 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1664,8 +1664,30 @@ int open_transport_socket(void) return 0; } +static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) +{ + int ret = 0; + FileEntry *fe; + + fe = pb_msg(base, FileEntry); + switch (fe->type) { + default: + pr_err("Unknown file type %d\n", fe->type); + return -1; + } + + return ret; +} + +struct collect_image_info files_cinfo = { + .fd_type = CR_FD_FILES, + .pb_type = PB_FILE, + .priv_size = 0, + .collect = collect_one_file, +}; + int prepare_files(void) { init_fdesc_hash(); - return 0; + return collect_image(&files_cinfo); } diff --git a/criu/image-desc.c b/criu/image-desc.c index 5e5224b13..7fedf1a09 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -99,6 +99,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY(USERNS, "userns-%d"), FD_ENTRY(NETNF_CT, "netns-ct-%d"), FD_ENTRY(NETNF_EXP, "netns-exp-%d"), + FD_ENTRY(FILES, "files"), [CR_FD_STATS] = { .fmt = "stats-%s", diff --git a/criu/include/files.h b/criu/include/files.h index ee9b2569f..9f65fa634 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -162,6 +162,9 @@ extern int restore_fs(struct pstree_item *); extern int prepare_fs_pid(struct pstree_item *); extern int set_fd_flags(int fd, int flags); +extern struct collect_image_info files_cinfo; +#define files_collected() (files_cinfo.flags & COLLECT_HAPPENED) + extern int close_old_fds(void); #ifndef AT_EMPTY_PATH #define AT_EMPTY_PATH 0x1000 diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index eba5d00a1..8a857cd94 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -54,6 +54,7 @@ enum { CR_FD_FDINFO, _CR_FD_GLOB_FROM, + CR_FD_FILES, CR_FD_SK_QUEUES, CR_FD_REG_FILES, CR_FD_EXT_FILES, diff --git a/criu/include/magic.h b/criu/include/magic.h index a0071eec4..05101f436 100644 --- a/criu/include/magic.h +++ b/criu/include/magic.h @@ -93,6 +93,7 @@ #define SECCOMP_MAGIC 0x64413049 /* Kostomuksha */ #define BINFMT_MISC_MAGIC 0x67343323 /* Apatity */ #define AUTOFS_MAGIC 0x49353943 /* Sochi */ +#define FILES_MAGIC 0x56303138 /* Toropets */ #define IFADDR_MAGIC RAW_IMAGE_MAGIC #define ROUTE_MAGIC RAW_IMAGE_MAGIC diff --git a/criu/include/protobuf-desc.h b/criu/include/protobuf-desc.h index 023047de5..31f5b9a79 100644 --- a/criu/include/protobuf-desc.h +++ b/criu/include/protobuf-desc.h @@ -60,6 +60,7 @@ enum { PB_TTY_DATA, PB_AUTOFS, PB_GHOST_CHUNK, + PB_FILE, /* PB_AUTOGEN_STOP */ diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 56506690c..86e39c19e 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -27,3 +27,8 @@ message fdinfo_entry { required fd_types type = 3; required uint32 fd = 4; } + +message file_entry { + required fd_types type = 1; + required uint32 id = 2; +} diff --git a/lib/py/images/images.py b/lib/py/images/images.py index 894e1c2c0..bb2f3834e 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -506,6 +506,7 @@ handlers = { 'USERNS' : entry_handler(userns_entry), 'SECCOMP' : entry_handler(seccomp_entry), 'AUTOFS' : entry_handler(autofs_entry), + 'FILES' : entry_handler(file_entry), } def __rhandler(f): From bee9eacad4c2556391c943e615d0b04024b0bf68 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 13:57:39 +0300 Subject: [PATCH 0661/4375] files: Move reg files into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 21 +++++++++++++++------ criu/files.c | 15 +++++++++++++++ criu/include/files-reg.h | 1 + criu/include/image-desc.h | 2 +- images/fdinfo.proto | 3 +++ 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index c4906a523..88a07d782 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -866,6 +866,7 @@ static int create_link_remap(char *path, int len, int lfd, const struct stat *st) { char link_name[PATH_MAX], *tmp; + FileEntry fe = FILE_ENTRY__INIT; RegFileEntry rfe = REG_FILE_ENTRY__INIT; FownEntry fwn = FOWN_ENTRY__INIT; int mntns_root; @@ -924,7 +925,11 @@ again: if (note_link_remap(link_name, nsid)) return -1; - return pb_write_one(img_from_set(glob_imgset, CR_FD_REG_FILES), &rfe, PB_REG_FILE); + fe.type = FD_TYPES__REG; + fe.id = rfe.id; + fe.reg = &rfe; + + return pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); } static int dump_linked_remap(char *path, int len, const struct stat *ost, @@ -1249,7 +1254,7 @@ int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p) struct ns_id *nsid; struct cr_img *rimg; char ext_id[64]; - + FileEntry fe = FILE_ENTRY__INIT; RegFileEntry rfe = REG_FILE_ENTRY__INIT; if (!p->link) { @@ -1309,8 +1314,12 @@ ext: rfe.size = p->stat.st_size; } - rimg = img_from_set(glob_imgset, CR_FD_REG_FILES); - return pb_write_one(rimg, &rfe, PB_REG_FILE); + fe.type = FD_TYPES__REG; + fe.id = rfe.id; + fe.reg = &rfe; + + rimg = img_from_set(glob_imgset, CR_FD_FILES); + return pb_write_one(rimg, &fe, PB_FILE); } const struct fdtype_ops regfile_dump_ops = { @@ -1933,7 +1942,7 @@ static int collect_one_regfile(void *o, ProtobufCMessage *base, struct cr_img *i return file_desc_add(&rfi->d, rfi->rfe->id, ®_desc_ops); } -static struct collect_image_info reg_file_cinfo = { +struct collect_image_info reg_file_cinfo = { .fd_type = CR_FD_REG_FILES, .pb_type = PB_REG_FILE, .priv_size = sizeof(struct reg_file_info), @@ -1943,7 +1952,7 @@ static struct collect_image_info reg_file_cinfo = { int collect_remaps_and_regfiles(void) { - if (collect_image(®_file_cinfo)) + if (!files_collected() && collect_image(®_file_cinfo)) return -1; if (collect_image(&remap_cinfo)) diff --git a/criu/files.c b/criu/files.c index 388bd281c..a3228b6b7 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1664,6 +1664,17 @@ int open_transport_socket(void) return 0; } +static int collect_one_file_entry(FileEntry *fe, u_int32_t id, ProtobufCMessage *base, + struct collect_image_info *cinfo) +{ + if (fe->id != id) { + pr_err("ID mismatch %u != %u\n", fe->id, id); + return -1; + } + + return collect_entry(base, cinfo); +} + static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) { int ret = 0; @@ -1674,6 +1685,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) default: pr_err("Unknown file type %d\n", fe->type); return -1; + case FD_TYPES__REG: + ret = collect_one_file_entry(fe, fe->reg->id, &fe->reg->base, ®_file_cinfo); + break; } return ret; @@ -1684,6 +1698,7 @@ struct collect_image_info files_cinfo = { .pb_type = PB_FILE, .priv_size = 0, .collect = collect_one_file, + .flags = COLLECT_NOFREE, }; int prepare_files(void) diff --git a/criu/include/files-reg.h b/criu/include/files-reg.h index 1c49be950..7a22d4d82 100644 --- a/criu/include/files-reg.h +++ b/criu/include/files-reg.h @@ -44,6 +44,7 @@ extern int collect_filemap(struct vma_area *); extern void filemap_ctx_init(bool auto_close); extern void filemap_ctx_fini(void); +extern struct collect_image_info reg_file_cinfo; extern int collect_remaps_and_regfiles(void); extern void delete_link_remaps(void); diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 8a857cd94..710e3ce7c 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -56,7 +56,6 @@ enum { _CR_FD_GLOB_FROM, CR_FD_FILES, CR_FD_SK_QUEUES, - CR_FD_REG_FILES, CR_FD_EXT_FILES, CR_FD_NS_FILES, CR_FD_INETSK, @@ -106,6 +105,7 @@ enum { CR_FD_INOTIFY_WD, CR_FD_FANOTIFY_MARK, CR_FD_EVENTPOLL_TFD, + CR_FD_REG_FILES, CR_FD_AUTOFS, diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 86e39c19e..836990e19 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -1,5 +1,7 @@ syntax = "proto2"; +import "regfile.proto"; + enum fd_types { UND = 0; REG = 1; @@ -31,4 +33,5 @@ message fdinfo_entry { message file_entry { required fd_types type = 1; required uint32 id = 2; + optional reg_file_entry reg = 3; } From 55519df9f17eaa9220104bd296f962669a47bf59 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 13:57:56 +0300 Subject: [PATCH 0662/4375] files: Move inet sockets into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/files.c | 3 +++ criu/include/image-desc.h | 2 +- criu/include/sockets.h | 2 +- criu/sk-inet.c | 12 ++++++------ images/fdinfo.proto | 2 ++ 6 files changed, 14 insertions(+), 9 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index e48088be6..77f0609f1 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -230,7 +230,7 @@ static int crtools_prepare_shared(void) return -1; /* Connections are unlocked from criu */ - if (collect_inet_sockets()) + if (!files_collected() && collect_image(&inet_sk_cinfo)) return -1; if (collect_binfmt_misc()) diff --git a/criu/files.c b/criu/files.c index a3228b6b7..94c6dc4c5 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1688,6 +1688,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__REG: ret = collect_one_file_entry(fe, fe->reg->id, &fe->reg->base, ®_file_cinfo); break; + case FD_TYPES__INETSK: + ret = collect_one_file_entry(fe, fe->isk->id, &fe->isk->base, &inet_sk_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 710e3ce7c..7aa43b9af 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -58,7 +58,6 @@ enum { CR_FD_SK_QUEUES, CR_FD_EXT_FILES, CR_FD_NS_FILES, - CR_FD_INETSK, CR_FD_UNIXSK, CR_FD_PACKETSK, CR_FD_NETLINK_SK, @@ -106,6 +105,7 @@ enum { CR_FD_FANOTIFY_MARK, CR_FD_EVENTPOLL_TFD, CR_FD_REG_FILES, + CR_FD_INETSK, CR_FD_AUTOFS, diff --git a/criu/include/sockets.h b/criu/include/sockets.h index 0de527c63..798c3b890 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -33,7 +33,7 @@ extern bool socket_test_collect_bit(unsigned int family, unsigned int proto); extern int sk_collect_one(unsigned ino, int family, struct socket_desc *d); struct ns_id; extern int collect_sockets(struct ns_id *); -extern int collect_inet_sockets(void); +extern struct collect_image_info inet_sk_cinfo; extern struct collect_image_info unix_sk_cinfo; extern int fix_external_unix_sockets(void); diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 7ad4cd993..94170cb93 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -306,6 +306,7 @@ static bool needs_scope_id(uint32_t *src_addr) static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int family) { struct inet_sk_desc *sk; + FileEntry fe = FILE_ENTRY__INIT; InetSkEntry ie = INET_SK_ENTRY__INIT; IpOptsEntry ipopts = IP_OPTS_ENTRY__INIT; SkOptsEntry skopts = SK_OPTS_ENTRY__INIT; @@ -419,7 +420,11 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa ie.state = sk->state; - if (pb_write_one(img_from_set(glob_imgset, CR_FD_INETSK), &ie, PB_INET_SK)) + fe.type = FD_TYPES__INETSK; + fe.id = ie.id; + fe.isk = &ie; + + if (pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE)) goto err; err: release_skopts(&skopts); @@ -522,11 +527,6 @@ struct collect_image_info inet_sk_cinfo = { .collect = collect_one_inetsk, }; -int collect_inet_sockets(void) -{ - return collect_image(&inet_sk_cinfo); -} - static int inet_validate_address(InetSkEntry *ie) { if ((ie->family == AF_INET) && diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 836990e19..ba6be3f6d 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -1,6 +1,7 @@ syntax = "proto2"; import "regfile.proto"; +import "sk-inet.proto"; enum fd_types { UND = 0; @@ -34,4 +35,5 @@ message file_entry { required fd_types type = 1; required uint32 id = 2; optional reg_file_entry reg = 3; + optional inet_sk_entry isk = 4; } From 1564dd4ec70bd0fb45e5e2b53d0323c0d2db23e6 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 13:58:13 +0300 Subject: [PATCH 0663/4375] files: Move ns files into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/files.c | 3 +++ criu/include/image-desc.h | 2 +- criu/namespaces.c | 10 ++++++++-- images/fdinfo.proto | 2 ++ 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 77f0609f1..547437c1f 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -255,7 +255,6 @@ static int crtools_prepare_shared(void) */ static struct collect_image_info *cinfos[] = { - &nsfile_cinfo, &pipe_cinfo, &fifo_cinfo, &unix_sk_cinfo, @@ -279,6 +278,7 @@ static struct collect_image_info *cinfos[] = { }; static struct collect_image_info *cinfos_files[] = { + &nsfile_cinfo, }; /* These images are requered to restore namespaces */ diff --git a/criu/files.c b/criu/files.c index 94c6dc4c5..e8bbf690a 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1691,6 +1691,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__INETSK: ret = collect_one_file_entry(fe, fe->isk->id, &fe->isk->base, &inet_sk_cinfo); break; + case FD_TYPES__NS: + ret = collect_one_file_entry(fe, fe->nsf->id, &fe->nsf->base, &nsfile_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 7aa43b9af..48b7b7292 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -57,7 +57,6 @@ enum { CR_FD_FILES, CR_FD_SK_QUEUES, CR_FD_EXT_FILES, - CR_FD_NS_FILES, CR_FD_UNIXSK, CR_FD_PACKETSK, CR_FD_NETLINK_SK, @@ -106,6 +105,7 @@ enum { CR_FD_EVENTPOLL_TFD, CR_FD_REG_FILES, CR_FD_INETSK, + CR_FD_NS_FILES, CR_FD_AUTOFS, diff --git a/criu/namespaces.c b/criu/namespaces.c index ed8a66248..e607ec4b0 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -464,7 +464,8 @@ static unsigned int get_ns_id(int pid, struct ns_desc *nd, protobuf_c_boolean *s int dump_one_ns_file(int lfd, u32 id, const struct fd_parms *p) { - struct cr_img *img = img_from_set(glob_imgset, CR_FD_NS_FILES); + struct cr_img *img; + FileEntry fe = FILE_ENTRY__INIT; NsFileEntry nfe = NS_FILE_ENTRY__INIT; struct fd_link *link = p->link; struct ns_id *nsid; @@ -480,7 +481,12 @@ int dump_one_ns_file(int lfd, u32 id, const struct fd_parms *p) nfe.ns_cflag = link->ns_d->cflag; nfe.flags = p->flags; - return pb_write_one(img, &nfe, PB_NS_FILE); + fe.type = FD_TYPES__NS; + fe.id = nfe.id; + fe.nsf = &nfe; + + img = img_from_set(glob_imgset, CR_FD_FILES); + return pb_write_one(img, &fe, PB_FILE); } const struct fdtype_ops nsfile_dump_ops = { diff --git a/images/fdinfo.proto b/images/fdinfo.proto index ba6be3f6d..89919ea32 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -2,6 +2,7 @@ syntax = "proto2"; import "regfile.proto"; import "sk-inet.proto"; +import "ns.proto"; enum fd_types { UND = 0; @@ -36,4 +37,5 @@ message file_entry { required uint32 id = 2; optional reg_file_entry reg = 3; optional inet_sk_entry isk = 4; + optional ns_file_entry nsf = 5; } From 52bf8c4a837bbea6d721cfd604db3c14bf450e00 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 13:59:37 +0300 Subject: [PATCH 0664/4375] files: Move packet sock into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/files.c | 4 ++++ criu/include/image-desc.h | 2 +- criu/sk-packet.c | 7 ++++++- images/fdinfo.proto | 2 ++ 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 547437c1f..990c646af 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -258,7 +258,6 @@ static struct collect_image_info *cinfos[] = { &pipe_cinfo, &fifo_cinfo, &unix_sk_cinfo, - &packet_sk_cinfo, &netlink_sk_cinfo, &eventfd_cinfo, &epoll_cinfo, @@ -279,6 +278,7 @@ static struct collect_image_info *cinfos[] = { static struct collect_image_info *cinfos_files[] = { &nsfile_cinfo, + &packet_sk_cinfo, }; /* These images are requered to restore namespaces */ diff --git a/criu/files.c b/criu/files.c index e8bbf690a..2cfaacfea 100644 --- a/criu/files.c +++ b/criu/files.c @@ -31,6 +31,7 @@ #include "eventfd.h" #include "eventpoll.h" #include "fsnotify.h" +#include "sk-packet.h" #include "mount.h" #include "signalfd.h" #include "namespaces.h" @@ -1694,6 +1695,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__NS: ret = collect_one_file_entry(fe, fe->nsf->id, &fe->nsf->base, &nsfile_cinfo); break; + case FD_TYPES__PACKETSK: + ret = collect_one_file_entry(fe, fe->psk->id, &fe->psk->base, &packet_sk_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 48b7b7292..5668d53c8 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -58,7 +58,6 @@ enum { CR_FD_SK_QUEUES, CR_FD_EXT_FILES, CR_FD_UNIXSK, - CR_FD_PACKETSK, CR_FD_NETLINK_SK, CR_FD_PIPES, CR_FD_PIPES_DATA, @@ -106,6 +105,7 @@ enum { CR_FD_REG_FILES, CR_FD_INETSK, CR_FD_NS_FILES, + CR_FD_PACKETSK, CR_FD_AUTOFS, diff --git a/criu/sk-packet.c b/criu/sk-packet.c index 9c3e6f340..f9017b57a 100644 --- a/criu/sk-packet.c +++ b/criu/sk-packet.c @@ -146,6 +146,7 @@ static int dump_rings(PacketSockEntry *psk, struct packet_sock_desc *sd) static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p) { + FileEntry fe = FILE_ENTRY__INIT; PacketSockEntry psk = PACKET_SOCK_ENTRY__INIT; SkOptsEntry skopts = SK_OPTS_ENTRY__INIT; struct packet_sock_desc *sd; @@ -194,7 +195,11 @@ static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p) if (ret) goto out; - ret = pb_write_one(img_from_set(glob_imgset, CR_FD_PACKETSK), &psk, PB_PACKET_SOCK); + fe.type = FD_TYPES__PACKETSK; + fe.id = psk.id; + fe.psk = &psk; + + ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); out: release_skopts(&skopts); xfree(psk.rx_ring); diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 89919ea32..56fe1c93e 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -3,6 +3,7 @@ syntax = "proto2"; import "regfile.proto"; import "sk-inet.proto"; import "ns.proto"; +import "packet-sock.proto"; enum fd_types { UND = 0; @@ -38,4 +39,5 @@ message file_entry { optional reg_file_entry reg = 3; optional inet_sk_entry isk = 4; optional ns_file_entry nsf = 5; + optional packet_sock_entry psk = 6; } From 341961beb0290c1a8b5bb657473029224c463b0a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 13:59:53 +0300 Subject: [PATCH 0665/4375] files: Move netlink sock into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/files.c | 3 +++ criu/include/image-desc.h | 2 +- criu/sk-netlink.c | 7 ++++++- images/fdinfo.proto | 2 ++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 990c646af..3e6c8365f 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -258,7 +258,6 @@ static struct collect_image_info *cinfos[] = { &pipe_cinfo, &fifo_cinfo, &unix_sk_cinfo, - &netlink_sk_cinfo, &eventfd_cinfo, &epoll_cinfo, &epoll_tfd_cinfo, @@ -279,6 +278,7 @@ static struct collect_image_info *cinfos[] = { static struct collect_image_info *cinfos_files[] = { &nsfile_cinfo, &packet_sk_cinfo, + &netlink_sk_cinfo, }; /* These images are requered to restore namespaces */ diff --git a/criu/files.c b/criu/files.c index 2cfaacfea..d09592fd0 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1698,6 +1698,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__PACKETSK: ret = collect_one_file_entry(fe, fe->psk->id, &fe->psk->base, &packet_sk_cinfo); break; + case FD_TYPES__NETLINKSK: + ret = collect_one_file_entry(fe, fe->nlsk->id, &fe->nlsk->base, &netlink_sk_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 5668d53c8..409293c30 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -58,7 +58,6 @@ enum { CR_FD_SK_QUEUES, CR_FD_EXT_FILES, CR_FD_UNIXSK, - CR_FD_NETLINK_SK, CR_FD_PIPES, CR_FD_PIPES_DATA, CR_FD_FIFO, @@ -106,6 +105,7 @@ enum { CR_FD_INETSK, CR_FD_NS_FILES, CR_FD_PACKETSK, + CR_FD_NETLINK_SK, CR_FD_AUTOFS, diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c index 0363c5e16..6ab2685f0 100644 --- a/criu/sk-netlink.c +++ b/criu/sk-netlink.c @@ -78,6 +78,7 @@ static bool can_dump_netlink_sk(int lfd) static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p) { struct netlink_sk_desc *sk; + FileEntry fe = FILE_ENTRY__INIT; NetlinkSkEntry ne = NETLINK_SK_ENTRY__INIT; SkOptsEntry skopts = SK_OPTS_ENTRY__INIT; @@ -137,7 +138,11 @@ static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p) if (dump_socket_opts(lfd, &skopts)) goto err; - if (pb_write_one(img_from_set(glob_imgset, CR_FD_NETLINK_SK), &ne, PB_NETLINK_SK)) + fe.type = FD_TYPES__NETLINKSK; + fe.id = ne.id; + fe.nlsk = ≠ + + if (pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE)) goto err; return 0; diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 56fe1c93e..6267ca22e 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -4,6 +4,7 @@ import "regfile.proto"; import "sk-inet.proto"; import "ns.proto"; import "packet-sock.proto"; +import "sk-netlink.proto"; enum fd_types { UND = 0; @@ -40,4 +41,5 @@ message file_entry { optional inet_sk_entry isk = 4; optional ns_file_entry nsf = 5; optional packet_sock_entry psk = 6; + optional netlink_sk_entry nlsk = 7; } From 8208e5a5ab0834a5bc8db6ce8c2e009c44005a04 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 14:00:09 +0300 Subject: [PATCH 0666/4375] files: Move eventfd into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/eventfd.c | 8 ++++++-- criu/files.c | 3 +++ criu/include/image-desc.h | 2 +- images/fdinfo.proto | 2 ++ 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 3e6c8365f..64a5f6b6e 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -258,7 +258,6 @@ static struct collect_image_info *cinfos[] = { &pipe_cinfo, &fifo_cinfo, &unix_sk_cinfo, - &eventfd_cinfo, &epoll_cinfo, &epoll_tfd_cinfo, &signalfd_cinfo, @@ -279,6 +278,7 @@ static struct collect_image_info *cinfos_files[] = { &nsfile_cinfo, &packet_sk_cinfo, &netlink_sk_cinfo, + &eventfd_cinfo, }; /* These images are requered to restore namespaces */ diff --git a/criu/eventfd.c b/criu/eventfd.c index b3c76e3d2..a3facada0 100644 --- a/criu/eventfd.c +++ b/criu/eventfd.c @@ -46,6 +46,7 @@ static void pr_info_eventfd(char *action, EventfdFileEntry *efe) static int dump_one_eventfd(int lfd, u32 id, const struct fd_parms *p) { EventfdFileEntry efd = EVENTFD_FILE_ENTRY__INIT; + FileEntry fe = FILE_ENTRY__INIT; if (parse_fdinfo(lfd, FD_TYPES__EVENTFD, &efd)) return -1; @@ -54,9 +55,12 @@ static int dump_one_eventfd(int lfd, u32 id, const struct fd_parms *p) efd.flags = p->flags; efd.fown = (FownEntry *)&p->fown; + fe.type = FD_TYPES__EVENTFD; + fe.id = efd.id; + fe.efd = &efd; + pr_info_eventfd("Dumping ", &efd); - return pb_write_one(img_from_set(glob_imgset, CR_FD_EVENTFD_FILE), - &efd, PB_EVENTFD_FILE); + return pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); } const struct fdtype_ops eventfd_dump_ops = { diff --git a/criu/files.c b/criu/files.c index d09592fd0..ecf1d3c89 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1701,6 +1701,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__NETLINKSK: ret = collect_one_file_entry(fe, fe->nlsk->id, &fe->nlsk->base, &netlink_sk_cinfo); break; + case FD_TYPES__EVENTFD: + ret = collect_one_file_entry(fe, fe->efd->id, &fe->efd->base, &eventfd_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 409293c30..bc00e6587 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -66,7 +66,6 @@ enum { CR_FD_TTY_INFO, CR_FD_TTY_DATA, CR_FD_REMAP_FPATH, - CR_FD_EVENTFD_FILE, CR_FD_EVENTPOLL_FILE, CR_FD_SIGNALFD, CR_FD_INOTIFY_FILE, @@ -106,6 +105,7 @@ enum { CR_FD_NS_FILES, CR_FD_PACKETSK, CR_FD_NETLINK_SK, + CR_FD_EVENTFD_FILE, CR_FD_AUTOFS, diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 6267ca22e..e3ed23648 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -5,6 +5,7 @@ import "sk-inet.proto"; import "ns.proto"; import "packet-sock.proto"; import "sk-netlink.proto"; +import "eventfd.proto"; enum fd_types { UND = 0; @@ -42,4 +43,5 @@ message file_entry { optional ns_file_entry nsf = 5; optional packet_sock_entry psk = 6; optional netlink_sk_entry nlsk = 7; + optional eventfd_file_entry efd = 8; } From fe0b08ef4f217eb18dbb484f29bc195107a50cb3 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 14:00:26 +0300 Subject: [PATCH 0667/4375] files: Move epoll into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 4 ++-- criu/eventpoll.c | 8 ++++++-- criu/files.c | 3 +++ criu/include/image-desc.h | 2 +- images/fdinfo.proto | 2 ++ 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 64a5f6b6e..bcecb843e 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -258,8 +258,6 @@ static struct collect_image_info *cinfos[] = { &pipe_cinfo, &fifo_cinfo, &unix_sk_cinfo, - &epoll_cinfo, - &epoll_tfd_cinfo, &signalfd_cinfo, &inotify_cinfo, &inotify_mark_cinfo, @@ -279,6 +277,8 @@ static struct collect_image_info *cinfos_files[] = { &packet_sk_cinfo, &netlink_sk_cinfo, &eventfd_cinfo, + &epoll_cinfo, + &epoll_tfd_cinfo, }; /* These images are requered to restore namespaces */ diff --git a/criu/eventpoll.c b/criu/eventpoll.c index b58e068c9..f0265ced2 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -53,6 +53,7 @@ static void pr_info_eventpoll(char *action, EventpollFileEntry *e) static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) { + FileEntry fe = FILE_ENTRY__INIT; EventpollFileEntry e = EVENTPOLL_FILE_ENTRY__INIT; int i, ret = -1; @@ -63,9 +64,12 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) if (parse_fdinfo(lfd, FD_TYPES__EVENTPOLL, &e)) goto out; + fe.type = FD_TYPES__EVENTPOLL; + fe.id = e.id; + fe.epfd = &e; + pr_info_eventpoll("Dumping ", &e); - ret = pb_write_one(img_from_set(glob_imgset, CR_FD_EVENTPOLL_FILE), - &e, PB_EVENTPOLL_FILE); + ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); out: for (i = 0; i < e.n_tfd; i++) { if (!ret) diff --git a/criu/files.c b/criu/files.c index ecf1d3c89..c8646a351 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1704,6 +1704,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__EVENTFD: ret = collect_one_file_entry(fe, fe->efd->id, &fe->efd->base, &eventfd_cinfo); break; + case FD_TYPES__EVENTPOLL: + ret = collect_one_file_entry(fe, fe->epfd->id, &fe->epfd->base, &epoll_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index bc00e6587..d5dc8bbb3 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -66,7 +66,6 @@ enum { CR_FD_TTY_INFO, CR_FD_TTY_DATA, CR_FD_REMAP_FPATH, - CR_FD_EVENTPOLL_FILE, CR_FD_SIGNALFD, CR_FD_INOTIFY_FILE, CR_FD_FANOTIFY_FILE, @@ -106,6 +105,7 @@ enum { CR_FD_PACKETSK, CR_FD_NETLINK_SK, CR_FD_EVENTFD_FILE, + CR_FD_EVENTPOLL_FILE, CR_FD_AUTOFS, diff --git a/images/fdinfo.proto b/images/fdinfo.proto index e3ed23648..f2fb2f876 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -6,6 +6,7 @@ import "ns.proto"; import "packet-sock.proto"; import "sk-netlink.proto"; import "eventfd.proto"; +import "eventpoll.proto"; enum fd_types { UND = 0; @@ -44,4 +45,5 @@ message file_entry { optional packet_sock_entry psk = 6; optional netlink_sk_entry nlsk = 7; optional eventfd_file_entry efd = 8; + optional eventpoll_file_entry epfd = 9; } From 1b6144368ae58fe88bca1dd06f3897a3b47f4f4e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 14:00:42 +0300 Subject: [PATCH 0668/4375] files: Move signalfd into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/files.c | 3 +++ criu/include/image-desc.h | 2 +- criu/signalfd.c | 8 ++++++-- images/fdinfo.proto | 2 ++ 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index bcecb843e..bff3ca6c9 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -258,7 +258,6 @@ static struct collect_image_info *cinfos[] = { &pipe_cinfo, &fifo_cinfo, &unix_sk_cinfo, - &signalfd_cinfo, &inotify_cinfo, &inotify_mark_cinfo, &fanotify_cinfo, @@ -279,6 +278,7 @@ static struct collect_image_info *cinfos_files[] = { &eventfd_cinfo, &epoll_cinfo, &epoll_tfd_cinfo, + &signalfd_cinfo, }; /* These images are requered to restore namespaces */ diff --git a/criu/files.c b/criu/files.c index c8646a351..cb728b4f1 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1707,6 +1707,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__EVENTPOLL: ret = collect_one_file_entry(fe, fe->epfd->id, &fe->epfd->base, &epoll_cinfo); break; + case FD_TYPES__SIGNALFD: + ret = collect_one_file_entry(fe, fe->sgfd->id, &fe->sgfd->base, &signalfd_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index d5dc8bbb3..1e1e2236a 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -66,7 +66,6 @@ enum { CR_FD_TTY_INFO, CR_FD_TTY_DATA, CR_FD_REMAP_FPATH, - CR_FD_SIGNALFD, CR_FD_INOTIFY_FILE, CR_FD_FANOTIFY_FILE, CR_FD_TUNFILE, @@ -106,6 +105,7 @@ enum { CR_FD_NETLINK_SK, CR_FD_EVENTFD_FILE, CR_FD_EVENTPOLL_FILE, + CR_FD_SIGNALFD, CR_FD_AUTOFS, diff --git a/criu/signalfd.c b/criu/signalfd.c index f33efa15f..bd117a3e0 100644 --- a/criu/signalfd.c +++ b/criu/signalfd.c @@ -27,6 +27,7 @@ int is_signalfd_link(char *link) static int dump_one_signalfd(int lfd, u32 id, const struct fd_parms *p) { SignalfdEntry sfd = SIGNALFD_ENTRY__INIT; + FileEntry fe = FILE_ENTRY__INIT; if (parse_fdinfo(lfd, FD_TYPES__SIGNALFD, &sfd)) return -1; @@ -35,8 +36,11 @@ static int dump_one_signalfd(int lfd, u32 id, const struct fd_parms *p) sfd.flags = p->flags; sfd.fown = (FownEntry *)&p->fown; - return pb_write_one(img_from_set(glob_imgset, CR_FD_SIGNALFD), - &sfd, PB_SIGNALFD); + fe.type = FD_TYPES__SIGNALFD; + fe.id = sfd.id; + fe.sgfd = &sfd; + + return pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); } const struct fdtype_ops signalfd_dump_ops = { diff --git a/images/fdinfo.proto b/images/fdinfo.proto index f2fb2f876..2c1f3009a 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -7,6 +7,7 @@ import "packet-sock.proto"; import "sk-netlink.proto"; import "eventfd.proto"; import "eventpoll.proto"; +import "signalfd.proto"; enum fd_types { UND = 0; @@ -46,4 +47,5 @@ message file_entry { optional netlink_sk_entry nlsk = 7; optional eventfd_file_entry efd = 8; optional eventpoll_file_entry epfd = 9; + optional signalfd_entry sgfd = 10; } From 5579d74c1531231b4581b3889dafc84e82b0579f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 14:00:58 +0300 Subject: [PATCH 0669/4375] files: Move tunfile into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/files.c | 3 +++ criu/include/image-desc.h | 2 +- criu/tun.c | 9 +++++++-- images/fdinfo.proto | 2 ++ 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index bff3ca6c9..a128da243 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -262,7 +262,6 @@ static struct collect_image_info *cinfos[] = { &inotify_mark_cinfo, &fanotify_cinfo, &fanotify_mark_cinfo, - &tunfile_cinfo, &ext_file_cinfo, &timerfd_cinfo, &file_locks_cinfo, @@ -279,6 +278,7 @@ static struct collect_image_info *cinfos_files[] = { &epoll_cinfo, &epoll_tfd_cinfo, &signalfd_cinfo, + &tunfile_cinfo, }; /* These images are requered to restore namespaces */ diff --git a/criu/files.c b/criu/files.c index cb728b4f1..6c73b8e69 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1710,6 +1710,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__SIGNALFD: ret = collect_one_file_entry(fe, fe->sgfd->id, &fe->sgfd->base, &signalfd_cinfo); break; + case FD_TYPES__TUNF: + ret = collect_one_file_entry(fe, fe->tunf->id, &fe->tunf->base, &tunfile_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 1e1e2236a..daad65749 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -68,7 +68,6 @@ enum { CR_FD_REMAP_FPATH, CR_FD_INOTIFY_FILE, CR_FD_FANOTIFY_FILE, - CR_FD_TUNFILE, CR_FD_CGROUP, CR_FD_TIMERFD, CR_FD_FILE_LOCKS, @@ -106,6 +105,7 @@ enum { CR_FD_EVENTFD_FILE, CR_FD_EVENTPOLL_FILE, CR_FD_SIGNALFD, + CR_FD_TUNFILE, CR_FD_AUTOFS, diff --git a/criu/tun.c b/criu/tun.c index 6a429b6c2..8dd95df59 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -268,6 +268,7 @@ static int dump_tunfile(int lfd, u32 id, const struct fd_parms *p) { int ret; struct cr_img *img; + FileEntry fe = FILE_ENTRY__INIT; TunfileEntry tfe = TUNFILE_ENTRY__INIT; struct ifreq ifr; @@ -306,8 +307,12 @@ static int dump_tunfile(int lfd, u32 id, const struct fd_parms *p) return -1; } - img = img_from_set(glob_imgset, CR_FD_TUNFILE); - return pb_write_one(img, &tfe, PB_TUNFILE); + fe.type = FD_TYPES__TUNF; + fe.id = tfe.id; + fe.tunf = &tfe; + + img = img_from_set(glob_imgset, CR_FD_FILES); + return pb_write_one(img, &fe, PB_FILE); } const struct fdtype_ops tunfile_dump_ops = { diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 2c1f3009a..a62c66e56 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -8,6 +8,7 @@ import "sk-netlink.proto"; import "eventfd.proto"; import "eventpoll.proto"; import "signalfd.proto"; +import "tun.proto"; enum fd_types { UND = 0; @@ -48,4 +49,5 @@ message file_entry { optional eventfd_file_entry efd = 8; optional eventpoll_file_entry epfd = 9; optional signalfd_entry sgfd = 10; + optional tunfile_entry tunf = 11; } From 24771da93d1d5e4a8f308b009c98ba8115520a7a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 14:01:14 +0300 Subject: [PATCH 0670/4375] files: Move timerfd into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/files.c | 3 +++ criu/include/image-desc.h | 2 +- criu/timerfd.c | 7 ++++++- images/fdinfo.proto | 2 ++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index a128da243..5c5db5e35 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -263,7 +263,6 @@ static struct collect_image_info *cinfos[] = { &fanotify_cinfo, &fanotify_mark_cinfo, &ext_file_cinfo, - &timerfd_cinfo, &file_locks_cinfo, &pipe_data_cinfo, &fifo_data_cinfo, @@ -279,6 +278,7 @@ static struct collect_image_info *cinfos_files[] = { &epoll_tfd_cinfo, &signalfd_cinfo, &tunfile_cinfo, + &timerfd_cinfo, }; /* These images are requered to restore namespaces */ diff --git a/criu/files.c b/criu/files.c index 6c73b8e69..423554af2 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1713,6 +1713,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__TUNF: ret = collect_one_file_entry(fe, fe->tunf->id, &fe->tunf->base, &tunfile_cinfo); break; + case FD_TYPES__TIMERFD: + ret = collect_one_file_entry(fe, fe->tfd->id, &fe->tfd->base, &timerfd_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index daad65749..c25f62586 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -69,7 +69,6 @@ enum { CR_FD_INOTIFY_FILE, CR_FD_FANOTIFY_FILE, CR_FD_CGROUP, - CR_FD_TIMERFD, CR_FD_FILE_LOCKS, CR_FD_SECCOMP, _CR_FD_GLOB_TO, @@ -106,6 +105,7 @@ enum { CR_FD_EVENTPOLL_FILE, CR_FD_SIGNALFD, CR_FD_TUNFILE, + CR_FD_TIMERFD, CR_FD_AUTOFS, diff --git a/criu/timerfd.c b/criu/timerfd.c index aa2aae169..b5ee5d8d7 100644 --- a/criu/timerfd.c +++ b/criu/timerfd.c @@ -67,6 +67,7 @@ int is_timerfd_link(char *link) static int dump_one_timerfd(int lfd, u32 id, const struct fd_parms *p) { TimerfdEntry tfe = TIMERFD_ENTRY__INIT; + FileEntry fe = FILE_ENTRY__INIT; if (parse_fdinfo(lfd, FD_TYPES__TIMERFD, &tfe)) return -1; @@ -78,7 +79,11 @@ static int dump_one_timerfd(int lfd, u32 id, const struct fd_parms *p) tfe.id, tfe.clockid, (unsigned long long)tfe.vsec, (unsigned long long)tfe.vnsec, (unsigned long long)tfe.isec, (unsigned long long)tfe.insec); - return pb_write_one(img_from_set(glob_imgset, CR_FD_TIMERFD), &tfe, PB_TIMERFD); + fe.type = FD_TYPES__TIMERFD; + fe.id = tfe.id; + fe.tfd = &tfe; + + return pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); } const struct fdtype_ops timerfd_dump_ops = { diff --git a/images/fdinfo.proto b/images/fdinfo.proto index a62c66e56..3d24d25b3 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -9,6 +9,7 @@ import "eventfd.proto"; import "eventpoll.proto"; import "signalfd.proto"; import "tun.proto"; +import "timerfd.proto"; enum fd_types { UND = 0; @@ -50,4 +51,5 @@ message file_entry { optional eventpoll_file_entry epfd = 9; optional signalfd_entry sgfd = 10; optional tunfile_entry tunf = 11; + optional timerfd_entry tfd = 12; } From fdf4b22a3eca7cf3ccdf08305e31e5e81f4721af Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 14:01:30 +0300 Subject: [PATCH 0671/4375] files: Move inotify into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 4 ++-- criu/files.c | 3 +++ criu/fsnotify.c | 7 ++++++- criu/include/image-desc.h | 2 +- images/fdinfo.proto | 2 ++ 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 5c5db5e35..befd189b9 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -258,8 +258,6 @@ static struct collect_image_info *cinfos[] = { &pipe_cinfo, &fifo_cinfo, &unix_sk_cinfo, - &inotify_cinfo, - &inotify_mark_cinfo, &fanotify_cinfo, &fanotify_mark_cinfo, &ext_file_cinfo, @@ -279,6 +277,8 @@ static struct collect_image_info *cinfos_files[] = { &signalfd_cinfo, &tunfile_cinfo, &timerfd_cinfo, + &inotify_cinfo, + &inotify_mark_cinfo, }; /* These images are requered to restore namespaces */ diff --git a/criu/files.c b/criu/files.c index 423554af2..35f0ef4b5 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1716,6 +1716,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__TIMERFD: ret = collect_one_file_entry(fe, fe->tfd->id, &fe->tfd->base, &timerfd_cinfo); break; + case FD_TYPES__INOTIFY: + ret = collect_one_file_entry(fe, fe->ify->id, &fe->ify->base, &inotify_cinfo); + break; } return ret; diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 6ceafaa9c..bd38562e2 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -317,6 +317,7 @@ static int check_one_wd(InotifyWdEntry *we) static int dump_one_inotify(int lfd, u32 id, const struct fd_parms *p) { + FileEntry fe = FILE_ENTRY__INIT; InotifyFileEntry ie = INOTIFY_FILE_ENTRY__INIT; int exit_code = -1, i, ret; @@ -337,8 +338,12 @@ static int dump_one_inotify(int lfd, u32 id, const struct fd_parms *p) if (check_one_wd(ie.wd[i])) goto free; + fe.type = FD_TYPES__INOTIFY; + fe.id = ie.id; + fe.ify = &ie; + pr_info("id %#08x flags %#08x\n", ie.id, ie.flags); - if (pb_write_one(img_from_set(glob_imgset, CR_FD_INOTIFY_FILE), &ie, PB_INOTIFY_FILE)) + if (pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE)) goto free; exit_code = 0; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index c25f62586..4f4f3678c 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -66,7 +66,6 @@ enum { CR_FD_TTY_INFO, CR_FD_TTY_DATA, CR_FD_REMAP_FPATH, - CR_FD_INOTIFY_FILE, CR_FD_FANOTIFY_FILE, CR_FD_CGROUP, CR_FD_FILE_LOCKS, @@ -106,6 +105,7 @@ enum { CR_FD_SIGNALFD, CR_FD_TUNFILE, CR_FD_TIMERFD, + CR_FD_INOTIFY_FILE, CR_FD_AUTOFS, diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 3d24d25b3..c0e5f6d5a 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -10,6 +10,7 @@ import "eventpoll.proto"; import "signalfd.proto"; import "tun.proto"; import "timerfd.proto"; +import "fsnotify.proto"; enum fd_types { UND = 0; @@ -52,4 +53,5 @@ message file_entry { optional signalfd_entry sgfd = 10; optional tunfile_entry tunf = 11; optional timerfd_entry tfd = 12; + optional inotify_file_entry ify = 13; } From 033d9e208ac7f9298e9e9615255759b789830932 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 14:01:47 +0300 Subject: [PATCH 0672/4375] files: Move fanotify into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 4 ++-- criu/files.c | 3 +++ criu/fsnotify.c | 7 ++++++- criu/include/image-desc.h | 2 +- images/fdinfo.proto | 1 + 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index befd189b9..e1dcf9830 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -258,8 +258,6 @@ static struct collect_image_info *cinfos[] = { &pipe_cinfo, &fifo_cinfo, &unix_sk_cinfo, - &fanotify_cinfo, - &fanotify_mark_cinfo, &ext_file_cinfo, &file_locks_cinfo, &pipe_data_cinfo, @@ -279,6 +277,8 @@ static struct collect_image_info *cinfos_files[] = { &timerfd_cinfo, &inotify_cinfo, &inotify_mark_cinfo, + &fanotify_cinfo, + &fanotify_mark_cinfo, }; /* These images are requered to restore namespaces */ diff --git a/criu/files.c b/criu/files.c index 35f0ef4b5..33d75cec7 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1719,6 +1719,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__INOTIFY: ret = collect_one_file_entry(fe, fe->ify->id, &fe->ify->base, &inotify_cinfo); break; + case FD_TYPES__FANOTIFY: + ret = collect_one_file_entry(fe, fe->ffy->id, &fe->ffy->base, &fanotify_cinfo); + break; } return ret; diff --git a/criu/fsnotify.c b/criu/fsnotify.c index bd38562e2..54f70e698 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -422,6 +422,7 @@ static int check_one_mark(FanotifyMarkEntry *fme) static int dump_one_fanotify(int lfd, u32 id, const struct fd_parms *p) { + FileEntry fle = FILE_ENTRY__INIT; FanotifyFileEntry fe = FANOTIFY_FILE_ENTRY__INIT; int ret = -1, i; @@ -445,7 +446,11 @@ static int dump_one_fanotify(int lfd, u32 id, const struct fd_parms *p) pr_info("id %#08x flags %#08x\n", fe.id, fe.flags); - ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FANOTIFY_FILE), &fe, PB_FANOTIFY_FILE); + fle.type = FD_TYPES__FANOTIFY; + fle.id = fe.id; + fle.ffy = &fe; + + ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fle, PB_FILE); free: for (i = 0; i < fe.n_mark; i++) xfree(fe.mark[i]); diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 4f4f3678c..42c13261f 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -66,7 +66,6 @@ enum { CR_FD_TTY_INFO, CR_FD_TTY_DATA, CR_FD_REMAP_FPATH, - CR_FD_FANOTIFY_FILE, CR_FD_CGROUP, CR_FD_FILE_LOCKS, CR_FD_SECCOMP, @@ -106,6 +105,7 @@ enum { CR_FD_TUNFILE, CR_FD_TIMERFD, CR_FD_INOTIFY_FILE, + CR_FD_FANOTIFY_FILE, CR_FD_AUTOFS, diff --git a/images/fdinfo.proto b/images/fdinfo.proto index c0e5f6d5a..876ad09f8 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -54,4 +54,5 @@ message file_entry { optional tunfile_entry tunf = 11; optional timerfd_entry tfd = 12; optional inotify_file_entry ify = 13; + optional fanotify_file_entry ffy = 14; } From 257e2e602304f6e2f830f74a53796b83d5329dad Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 14:02:03 +0300 Subject: [PATCH 0673/4375] files: Move ext files into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/files-ext.c | 10 +++++++--- criu/files.c | 3 +++ criu/include/image-desc.h | 2 +- images/fdinfo.proto | 2 ++ 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index e1dcf9830..fb826c2c2 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -258,7 +258,6 @@ static struct collect_image_info *cinfos[] = { &pipe_cinfo, &fifo_cinfo, &unix_sk_cinfo, - &ext_file_cinfo, &file_locks_cinfo, &pipe_data_cinfo, &fifo_data_cinfo, @@ -279,6 +278,7 @@ static struct collect_image_info *cinfos_files[] = { &inotify_mark_cinfo, &fanotify_cinfo, &fanotify_mark_cinfo, + &ext_file_cinfo, }; /* These images are requered to restore namespaces */ diff --git a/criu/files-ext.c b/criu/files-ext.c index df23ec671..af9c2681a 100644 --- a/criu/files-ext.c +++ b/criu/files-ext.c @@ -13,7 +13,7 @@ static int dump_one_ext_file(int lfd, u32 id, const struct fd_parms *p) { int ret; struct cr_img *rimg; - + FileEntry fe = FILE_ENTRY__INIT; ExtFileEntry xfe = EXT_FILE_ENTRY__INIT; ret = run_plugins(DUMP_EXT_FILE, lfd, id); @@ -23,8 +23,12 @@ static int dump_one_ext_file(int lfd, u32 id, const struct fd_parms *p) xfe.id = id; xfe.fown = (FownEntry *)&p->fown; - rimg = img_from_set(glob_imgset, CR_FD_EXT_FILES); - return pb_write_one(rimg, &xfe, PB_EXT_FILE); + fe.type = FD_TYPES__EXT; + fe.id = xfe.id; + fe.ext = &xfe; + + rimg = img_from_set(glob_imgset, CR_FD_FILES); + return pb_write_one(rimg, &fe, PB_FILE); } const struct fdtype_ops ext_dump_ops = { diff --git a/criu/files.c b/criu/files.c index 33d75cec7..7d3d266ad 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1722,6 +1722,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__FANOTIFY: ret = collect_one_file_entry(fe, fe->ffy->id, &fe->ffy->base, &fanotify_cinfo); break; + case FD_TYPES__EXT: + ret = collect_one_file_entry(fe, fe->ext->id, &fe->ext->base, &ext_file_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 42c13261f..34dda641f 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -56,7 +56,6 @@ enum { _CR_FD_GLOB_FROM, CR_FD_FILES, CR_FD_SK_QUEUES, - CR_FD_EXT_FILES, CR_FD_UNIXSK, CR_FD_PIPES, CR_FD_PIPES_DATA, @@ -106,6 +105,7 @@ enum { CR_FD_TIMERFD, CR_FD_INOTIFY_FILE, CR_FD_FANOTIFY_FILE, + CR_FD_EXT_FILES, CR_FD_AUTOFS, diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 876ad09f8..4f7ee9537 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -11,6 +11,7 @@ import "signalfd.proto"; import "tun.proto"; import "timerfd.proto"; import "fsnotify.proto"; +import "ext-file.proto"; enum fd_types { UND = 0; @@ -55,4 +56,5 @@ message file_entry { optional timerfd_entry tfd = 12; optional inotify_file_entry ify = 13; optional fanotify_file_entry ffy = 14; + optional ext_file_entry ext = 15; } From fd39196d98c765d8cd749b72cddbd05de7a7d8d8 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 14:02:20 +0300 Subject: [PATCH 0674/4375] files: Move unix sk into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/files.c | 3 +++ criu/include/image-desc.h | 2 +- criu/sk-unix.c | 14 ++++++++++++-- images/fdinfo.proto | 2 ++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index fb826c2c2..e6e5ef6f2 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -257,7 +257,6 @@ static int crtools_prepare_shared(void) static struct collect_image_info *cinfos[] = { &pipe_cinfo, &fifo_cinfo, - &unix_sk_cinfo, &file_locks_cinfo, &pipe_data_cinfo, &fifo_data_cinfo, @@ -265,6 +264,7 @@ static struct collect_image_info *cinfos[] = { }; static struct collect_image_info *cinfos_files[] = { + &unix_sk_cinfo, &nsfile_cinfo, &packet_sk_cinfo, &netlink_sk_cinfo, diff --git a/criu/files.c b/criu/files.c index 7d3d266ad..d4fdfdea0 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1725,6 +1725,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__EXT: ret = collect_one_file_entry(fe, fe->ext->id, &fe->ext->base, &ext_file_cinfo); break; + case FD_TYPES__UNIXSK: + ret = collect_one_file_entry(fe, fe->usk->id, &fe->usk->base, &unix_sk_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 34dda641f..9d253ba1e 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -56,7 +56,6 @@ enum { _CR_FD_GLOB_FROM, CR_FD_FILES, CR_FD_SK_QUEUES, - CR_FD_UNIXSK, CR_FD_PIPES, CR_FD_PIPES_DATA, CR_FD_FIFO, @@ -106,6 +105,7 @@ enum { CR_FD_INOTIFY_FILE, CR_FD_FANOTIFY_FILE, CR_FD_EXT_FILES, + CR_FD_UNIXSK, CR_FD_AUTOFS, diff --git a/criu/sk-unix.c b/criu/sk-unix.c index cbecb2021..3551078ba 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -175,8 +175,13 @@ static bool unix_sk_exception_lookup_id(unsigned int ino) static int write_unix_entry(struct unix_sk_desc *sk) { int ret; + FileEntry fe = FILE_ENTRY__INIT; - ret = pb_write_one(img_from_set(glob_imgset, CR_FD_UNIXSK), sk->ue, PB_UNIX_SK); + fe.type = FD_TYPES__UNIXSK; + fe.id = sk->ue->id; + fe.usk = sk->ue; + + ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); show_one_unix_img("Dumped", sk->ue); @@ -739,6 +744,7 @@ int fix_external_unix_sockets(void) pr_debug("Dumping external sockets\n"); list_for_each_entry(sk, &unix_sockets, list) { + FileEntry fe = FILE_ENTRY__INIT; UnixSkEntry e = UNIX_SK_ENTRY__INIT; FownEntry fown = FOWN_ENTRY__INIT; SkOptsEntry skopts = SK_OPTS_ENTRY__INIT; @@ -760,7 +766,11 @@ int fix_external_unix_sockets(void) e.fown = &fown; e.opts = &skopts; - if (pb_write_one(img_from_set(glob_imgset, CR_FD_UNIXSK), &e, PB_UNIX_SK)) + fe.type = FD_TYPES__UNIXSK; + fe.id = e.id; + fe.usk = &e; + + if (pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE)) goto err; show_one_unix_img("Dumped extern", &e); diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 4f7ee9537..5ef3972ff 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -12,6 +12,7 @@ import "tun.proto"; import "timerfd.proto"; import "fsnotify.proto"; import "ext-file.proto"; +import "sk-unix.proto"; enum fd_types { UND = 0; @@ -57,4 +58,5 @@ message file_entry { optional inotify_file_entry ify = 13; optional fanotify_file_entry ffy = 14; optional ext_file_entry ext = 15; + optional unix_sk_entry usk = 16; } From 8c70b99dc6f449d278c0670e9c67cea7b4627498 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 14:02:38 +0300 Subject: [PATCH 0675/4375] files: Move fifo into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/fifo.c | 9 +++++++-- criu/files.c | 3 +++ criu/include/image-desc.h | 2 +- images/fdinfo.proto | 2 ++ 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index e6e5ef6f2..e173dacaa 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -256,7 +256,6 @@ static int crtools_prepare_shared(void) static struct collect_image_info *cinfos[] = { &pipe_cinfo, - &fifo_cinfo, &file_locks_cinfo, &pipe_data_cinfo, &fifo_data_cinfo, @@ -265,6 +264,7 @@ static struct collect_image_info *cinfos[] = { static struct collect_image_info *cinfos_files[] = { &unix_sk_cinfo, + &fifo_cinfo, &nsfile_cinfo, &packet_sk_cinfo, &netlink_sk_cinfo, diff --git a/criu/fifo.c b/criu/fifo.c index 5e2b44ff5..73d45e07a 100644 --- a/criu/fifo.c +++ b/criu/fifo.c @@ -41,7 +41,8 @@ static struct pipe_data_dump pd_fifo = { .img_type = CR_FD_FIFO_DATA, }; static int dump_one_fifo(int lfd, u32 id, const struct fd_parms *p) { - struct cr_img *img = img_from_set(glob_imgset, CR_FD_FIFO); + struct cr_img *img = img_from_set(glob_imgset, CR_FD_FILES); + FileEntry fe = FILE_ENTRY__INIT; FifoEntry e = FIFO_ENTRY__INIT; /* @@ -58,7 +59,11 @@ static int dump_one_fifo(int lfd, u32 id, const struct fd_parms *p) e.id = id; e.pipe_id = pipe_id(p); - if (pb_write_one(img, &e, PB_FIFO)) + fe.type = FD_TYPES__FIFO; + fe.id = e.id; + fe.fifo = &e; + + if (pb_write_one(img, &fe, PB_FILE)) return -1; return dump_one_pipe_data(&pd_fifo, lfd, p); diff --git a/criu/files.c b/criu/files.c index d4fdfdea0..edcd363b2 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1728,6 +1728,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__UNIXSK: ret = collect_one_file_entry(fe, fe->usk->id, &fe->usk->base, &unix_sk_cinfo); break; + case FD_TYPES__FIFO: + ret = collect_one_file_entry(fe, fe->fifo->id, &fe->fifo->base, &fifo_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 9d253ba1e..bebee03c1 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -58,7 +58,6 @@ enum { CR_FD_SK_QUEUES, CR_FD_PIPES, CR_FD_PIPES_DATA, - CR_FD_FIFO, CR_FD_FIFO_DATA, CR_FD_TTY_FILES, CR_FD_TTY_INFO, @@ -106,6 +105,7 @@ enum { CR_FD_FANOTIFY_FILE, CR_FD_EXT_FILES, CR_FD_UNIXSK, + CR_FD_FIFO, CR_FD_AUTOFS, diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 5ef3972ff..8cbfd5d7f 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -13,6 +13,7 @@ import "timerfd.proto"; import "fsnotify.proto"; import "ext-file.proto"; import "sk-unix.proto"; +import "fifo.proto"; enum fd_types { UND = 0; @@ -59,4 +60,5 @@ message file_entry { optional fanotify_file_entry ffy = 14; optional ext_file_entry ext = 15; optional unix_sk_entry usk = 16; + optional fifo_entry fifo = 17; } From bb825d89c82db2c6bd4c54af627ed65322f6beda Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 30 Jun 2017 14:02:54 +0300 Subject: [PATCH 0676/4375] files: Move pipes into files image Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/files.c | 3 +++ criu/include/image-desc.h | 2 +- criu/pipes.c | 7 ++++++- images/fdinfo.proto | 2 ++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index e173dacaa..737a376b3 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -255,7 +255,6 @@ static int crtools_prepare_shared(void) */ static struct collect_image_info *cinfos[] = { - &pipe_cinfo, &file_locks_cinfo, &pipe_data_cinfo, &fifo_data_cinfo, @@ -265,6 +264,7 @@ static struct collect_image_info *cinfos[] = { static struct collect_image_info *cinfos_files[] = { &unix_sk_cinfo, &fifo_cinfo, + &pipe_cinfo, &nsfile_cinfo, &packet_sk_cinfo, &netlink_sk_cinfo, diff --git a/criu/files.c b/criu/files.c index edcd363b2..088cca136 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1731,6 +1731,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__FIFO: ret = collect_one_file_entry(fe, fe->fifo->id, &fe->fifo->base, &fifo_cinfo); break; + case FD_TYPES__PIPE: + ret = collect_one_file_entry(fe, fe->pipe->id, &fe->pipe->base, &pipe_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index bebee03c1..520f3c360 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -56,7 +56,6 @@ enum { _CR_FD_GLOB_FROM, CR_FD_FILES, CR_FD_SK_QUEUES, - CR_FD_PIPES, CR_FD_PIPES_DATA, CR_FD_FIFO_DATA, CR_FD_TTY_FILES, @@ -106,6 +105,7 @@ enum { CR_FD_EXT_FILES, CR_FD_UNIXSK, CR_FD_FIFO, + CR_FD_PIPES, CR_FD_AUTOFS, diff --git a/criu/pipes.c b/criu/pipes.c index cb150f3d7..f1a66bf5d 100644 --- a/criu/pipes.c +++ b/criu/pipes.c @@ -487,6 +487,7 @@ static struct pipe_data_dump pd_pipes = { .img_type = CR_FD_PIPES_DATA, }; static int dump_one_pipe(int lfd, u32 id, const struct fd_parms *p) { + FileEntry fe = FILE_ENTRY__INIT; PipeEntry pe = PIPE_ENTRY__INIT; pr_info("Dumping pipe %d with id %#x pipe_id %#x\n", @@ -502,7 +503,11 @@ static int dump_one_pipe(int lfd, u32 id, const struct fd_parms *p) pe.flags = p->flags & ~O_DIRECT; pe.fown = (FownEntry *)&p->fown; - if (pb_write_one(img_from_set(glob_imgset, CR_FD_PIPES), &pe, PB_PIPE)) + fe.type = FD_TYPES__PIPE; + fe.id = pe.id; + fe.pipe = &pe; + + if (pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE)) return -1; return dump_one_pipe_data(&pd_pipes, lfd, p); diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 8cbfd5d7f..37318c50d 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -14,6 +14,7 @@ import "fsnotify.proto"; import "ext-file.proto"; import "sk-unix.proto"; import "fifo.proto"; +import "pipe.proto"; enum fd_types { UND = 0; @@ -61,4 +62,5 @@ message file_entry { optional ext_file_entry ext = 15; optional unix_sk_entry usk = 16; optional fifo_entry fifo = 17; + optional pipe_entry pipe = 18; } From 081a3126042de30ec3ebf14d0dc237221b0a163a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 19 Jul 2017 14:19:48 +0300 Subject: [PATCH 0677/4375] tty: Change the order of collection There are two object for TTY files -- the file itself and tty_info. The latter is effectively an inode image. Right now we collect infos before files, so that latter can find former and attach to it. In order to move tty files on generic file entry we need to collect files very early, much earlier, that infos. So here's the patch that changes the order of tty file vs info collection. The general idea is -- when collecting files put them in a list and when an info arrives it walks that list and attaches ttys to self. Next patches will also add some optimization available with that scheme. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/tty.c | 69 +++++++++++++++++++++-------------------------- 2 files changed, 32 insertions(+), 39 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 737a376b3..febf208da 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -283,8 +283,8 @@ static struct collect_image_info *cinfos_files[] = { /* These images are requered to restore namespaces */ static struct collect_image_info *before_ns_cinfos[] = { - &tty_info_cinfo, /* Restore devpts content */ &tty_cinfo, + &tty_info_cinfo, /* Restore devpts content */ &tty_cdata, }; diff --git a/criu/tty.c b/criu/tty.c index 6f359b88e..49d2a275c 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -76,11 +76,6 @@ #undef LOG_PREFIX #define LOG_PREFIX "tty: " -struct tty_info_entry { - struct list_head list; - TtyInfoEntry *tie; -}; - struct tty_data_entry { struct list_head list; TtyDataEntry *tde; @@ -128,7 +123,7 @@ struct tty_dump_info { }; static bool stdin_isatty = false; -static LIST_HEAD(all_tty_info_entries); +static LIST_HEAD(collected_ttys); static LIST_HEAD(all_ttys); /* @@ -1503,29 +1498,19 @@ static int verify_info(struct tty_info *info) return 0; } -static TtyInfoEntry *lookup_tty_info_entry(u32 id) -{ - struct tty_info_entry *e; - - list_for_each_entry(e, &all_tty_info_entries, list) { - if (e->tie->id == id) - return e->tie; - } - - return NULL; -} +static int tty_info_setup(struct tty_info *info); static int collect_one_tty_info_entry(void *obj, ProtobufCMessage *msg, struct cr_img *i) { - struct tty_info_entry *info = obj; + struct tty_info *info, *n; + TtyInfoEntry *tie; - info->tie = pb_msg(msg, TtyInfoEntry); + tie = pb_msg(msg, TtyInfoEntry); - switch (info->tie->type) { + switch (tie->type) { case TTY_TYPE__PTY: - if (!info->tie->pty) { - pr_err("No PTY data found (id %#x), corrupted image?\n", - info->tie->id); + if (!tie->pty) { + pr_err("No PTY data found (id %#x), corrupted image?\n", tie->id); return -1; } break; @@ -1534,20 +1519,26 @@ static int collect_one_tty_info_entry(void *obj, ProtobufCMessage *msg, struct c case TTY_TYPE__SERIAL: case TTY_TYPE__VT: case TTY_TYPE__EXT_TTY: - if (info->tie->pty) { - pr_err("PTY data found (id %#x), corrupted image?\n", - info->tie->id); + if (tie->pty) { + pr_err("PTY data found (id %#x), corrupted image?\n", tie->id); return -1; } break; default: - pr_err("Unexpected TTY type %d (id %#x)\n", - info->tie->type, info->tie->id); + pr_err("Unexpected TTY type %d (id %#x)\n", tie->type, tie->id); return -1; } - INIT_LIST_HEAD(&info->list); - list_add(&info->list, &all_tty_info_entries); + list_for_each_entry_safe(info, n, &collected_ttys, list) { + if (info->tfe->tty_info_id != tie->id) + continue; + + info->tie = tie; + list_move_tail(&info->list, &all_ttys); + + if (tty_info_setup(info)) + return -1; + } return 0; } @@ -1555,12 +1546,16 @@ static int collect_one_tty_info_entry(void *obj, ProtobufCMessage *msg, struct c struct collect_image_info tty_info_cinfo = { .fd_type = CR_FD_TTY_INFO, .pb_type = PB_TTY_INFO, - .priv_size = sizeof(struct tty_info_entry), .collect = collect_one_tty_info_entry, + .flags = COLLECT_NOFREE, }; static int prep_tty_restore_cb(struct pprep_head *ph) { + if (!list_empty(&collected_ttys)) { + pr_err("Not all TTYs got its infos\n"); + return -1; + } if (tty_verify_active_pairs()) return -1; if (tty_setup_slavery()) @@ -1575,14 +1570,13 @@ static int collect_one_tty(void *obj, ProtobufCMessage *msg, struct cr_img *i) struct tty_info *info = obj; info->tfe = pb_msg(msg, TtyFileEntry); + list_add_tail(&info->list, &collected_ttys); - info->tie = lookup_tty_info_entry(info->tfe->tty_info_id); - if (!info->tie) { - pr_err("No tty-info-id %#x found on id %#x\n", - info->tfe->tty_info_id, info->tfe->id); - return -1; - } + return 0; +} +static int tty_info_setup(struct tty_info *info) +{ INIT_LIST_HEAD(&info->sibling); info->driver = get_tty_driver(info->tie->rdev, info->tie->dev); if (info->driver == NULL) { @@ -1650,7 +1644,6 @@ static int collect_one_tty(void *obj, ProtobufCMessage *msg, struct cr_img *i) return -1; info->fdstore_id = -1; - list_add(&info->list, &all_ttys); return file_desc_add(&info->d, info->tfe->id, &tty_desc_ops); } From c93edee2cb69bcd750560f2c8640d30632be8af6 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 19 Jul 2017 14:20:03 +0300 Subject: [PATCH 0678/4375] tty: Get driver for info once Since we need tty driver for info, we may lookup the guy when collecting info, not when attaching it to a file. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/tty.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/criu/tty.c b/criu/tty.c index 49d2a275c..cd49f194f 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -1504,6 +1504,7 @@ static int collect_one_tty_info_entry(void *obj, ProtobufCMessage *msg, struct c { struct tty_info *info, *n; TtyInfoEntry *tie; + struct tty_driver *driver; tie = pb_msg(msg, TtyInfoEntry); @@ -1529,11 +1530,19 @@ static int collect_one_tty_info_entry(void *obj, ProtobufCMessage *msg, struct c return -1; } + driver = get_tty_driver(tie->rdev, tie->dev); + if (driver == NULL) { + pr_err("Unable to find a tty driver (rdev %#x dev %#x)\n", + tie->rdev, tie->dev); + return -1; + } + list_for_each_entry_safe(info, n, &collected_ttys, list) { if (info->tfe->tty_info_id != tie->id) continue; info->tie = tie; + info->driver = driver; list_move_tail(&info->list, &all_ttys); if (tty_info_setup(info)) @@ -1578,12 +1587,6 @@ static int collect_one_tty(void *obj, ProtobufCMessage *msg, struct cr_img *i) static int tty_info_setup(struct tty_info *info) { INIT_LIST_HEAD(&info->sibling); - info->driver = get_tty_driver(info->tie->rdev, info->tie->dev); - if (info->driver == NULL) { - pr_err("Unable to find a tty driver (rdev %#x dev %#x)\n", - info->tie->rdev, info->tie->dev); - return -1; - } info->create = tty_is_master(info); info->inherit = false; info->ctl_tty = NULL; From ce3e40eef455b1e77ecc5e9eb210d5e3e0784d0d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 19 Jul 2017 14:20:17 +0300 Subject: [PATCH 0679/4375] tty: Verify info once Same here -- now when we collect info and driver at the same place late enough we can verify info once, then attach to files. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/tty.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/criu/tty.c b/criu/tty.c index cd49f194f..a813980fd 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -726,12 +726,12 @@ err: return ret ? -1 : 0; } -static bool tty_is_master(struct tty_info *info) +static bool __tty_is_master(struct tty_driver *driver) { - if (info->driver->subtype == TTY_SUBTYPE_MASTER) + if (driver->subtype == TTY_SUBTYPE_MASTER) return true; - switch (info->driver->type) { + switch (driver->type) { case TTY_TYPE__CONSOLE: case TTY_TYPE__CTTY: return true; @@ -747,6 +747,11 @@ static bool tty_is_master(struct tty_info *info) return false; } +static bool tty_is_master(struct tty_info *info) +{ + return __tty_is_master(info->driver); +} + static bool tty_is_hung(struct tty_info *info) { return info->tie->termios == NULL; @@ -1455,10 +1460,10 @@ static int verify_termios(u32 id, TermiosEntry *e) return 0; } -#define term_opts_missing_cmp(p, op) \ - (!(p)->tie->termios op \ - !(p)->tie->termios_locked op \ - !(p)->tie->winsize) +#define term_opts_missing_cmp(tie, op) \ + (!(tie)->termios op \ + !(tie)->termios_locked op \ + !(tie)->winsize) #define term_opts_missing_any(p) \ term_opts_missing_cmp(p, ||) @@ -1466,33 +1471,28 @@ static int verify_termios(u32 id, TermiosEntry *e) #define term_opts_missing_all(p) \ term_opts_missing_cmp(p, &&) -static int verify_info(struct tty_info *info) +static int verify_info(TtyInfoEntry *tie, struct tty_driver *driver) { - if (!info->driver) { - pr_err("Unknown driver master peer %#x\n", info->tfe->id); - return -1; - } - /* * Master peer must have all parameters present, * while slave peer must have either all parameters present * or don't have them at all. */ - if (term_opts_missing_any(info)) { - if (tty_is_master(info)) { - pr_err("Corrupted master peer %#x\n", info->tfe->id); + if (term_opts_missing_any(tie)) { + if (__tty_is_master(driver)) { + pr_err("Corrupted master peer %#x\n", tie->id); return -1; - } else if (!term_opts_missing_all(info)) { - pr_err("Corrupted slave peer %#x\n", info->tfe->id); + } else if (!term_opts_missing_all(tie)) { + pr_err("Corrupted slave peer %#x\n", tie->id); return -1; } } - if (verify_termios(info->tfe->id, info->tie->termios_locked) || - verify_termios(info->tfe->id, info->tie->termios)) + if (verify_termios(tie->id, tie->termios_locked) || + verify_termios(tie->id, tie->termios)) return -1; - if (info->tie->termios && info->tfe->tty_info_id > (MAX_TTYS << 1)) + if (tie->termios && tie->id > (MAX_TTYS << 1)) return -1; return 0; @@ -1537,6 +1537,9 @@ static int collect_one_tty_info_entry(void *obj, ProtobufCMessage *msg, struct c return -1; } + if (verify_info(tie, driver)) + return -1; + list_for_each_entry_safe(info, n, &collected_ttys, list) { if (info->tfe->tty_info_id != tie->id) continue; @@ -1593,9 +1596,6 @@ static int tty_info_setup(struct tty_info *info) info->tty_data = NULL; info->link = NULL; - if (verify_info(info)) - return -1; - /* * The image might have no reg file record in old CRIU, so * lets don't fail for a while. After a couple of releases From a35d37856281bd619cacf31861e3350b28d993ec Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 19 Jul 2017 14:20:32 +0300 Subject: [PATCH 0680/4375] tty: Set active-pairs bit once Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/tty.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/criu/tty.c b/criu/tty.c index a813980fd..5546b1806 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -1552,6 +1552,16 @@ static int collect_one_tty_info_entry(void *obj, ProtobufCMessage *msg, struct c return -1; } + /* + * The tty peers which have no @termios are hung up, + * so don't mark them as active, we create them with + * faked master and they are rather a rudiment which + * can't be used. Most likely they appear if a user has + * dumped program when it was closing a peer. + */ + if (is_pty(driver) && tie->termios) + tty_test_and_set(tie->id, tty_active_pairs); + return 0; } @@ -1625,16 +1635,6 @@ static int tty_info_setup(struct tty_info *info) } } - /* - * The tty peers which have no @termios are hung up, - * so don't mark them as active, we create them with - * faked master and they are rather a rudiment which - * can't be used. Most likely they appear if a user has - * dumped program when it was closing a peer. - */ - if (is_pty(info->driver) && info->tie->termios) - tty_test_and_set(info->tfe->tty_info_id, tty_active_pairs); - pr_info("Collected tty ID %#x (%s)\n", info->tfe->id, info->driver->name); add_post_prepare_cb_once(&prep_tty_restore); From 49d8cd09779b9eb7416b45233a5d3f95a82e0fb6 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 19 Jul 2017 14:20:48 +0300 Subject: [PATCH 0681/4375] tty: Move tty into files image This completes merging files images into one. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 3 ++- criu/files.c | 3 +++ criu/include/image-desc.h | 2 +- criu/tty.c | 11 +++++++++-- images/fdinfo.proto | 2 ++ 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index febf208da..f8f58f50e 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -283,7 +283,6 @@ static struct collect_image_info *cinfos_files[] = { /* These images are requered to restore namespaces */ static struct collect_image_info *before_ns_cinfos[] = { - &tty_cinfo, &tty_info_cinfo, /* Restore devpts content */ &tty_cdata, }; @@ -1513,6 +1512,8 @@ static int restore_task_with_children(void *_arg) if (mount_proc()) goto err; + if (!files_collected() && collect_image(&tty_cinfo)) + goto err; if (collect_images(before_ns_cinfos, ARRAY_SIZE(before_ns_cinfos))) goto err; diff --git a/criu/files.c b/criu/files.c index 088cca136..e084316fd 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1734,6 +1734,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__PIPE: ret = collect_one_file_entry(fe, fe->pipe->id, &fe->pipe->base, &pipe_cinfo); break; + case FD_TYPES__TTY: + ret = collect_one_file_entry(fe, fe->tty->id, &fe->tty->base, &tty_cinfo); + break; } return ret; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 520f3c360..3135f56b4 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -58,7 +58,6 @@ enum { CR_FD_SK_QUEUES, CR_FD_PIPES_DATA, CR_FD_FIFO_DATA, - CR_FD_TTY_FILES, CR_FD_TTY_INFO, CR_FD_TTY_DATA, CR_FD_REMAP_FPATH, @@ -106,6 +105,7 @@ enum { CR_FD_UNIXSK, CR_FD_FIFO, CR_FD_PIPES, + CR_FD_TTY_FILES, CR_FD_AUTOFS, diff --git a/criu/tty.c b/criu/tty.c index 5546b1806..5b0cc841b 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -1919,8 +1919,15 @@ static int dump_one_tty(int lfd, u32 id, const struct fd_parms *p) if (!tty_test_and_set(e.tty_info_id, tty_bitmap)) ret = dump_tty_info(lfd, e.tty_info_id, p, driver, index); - if (!ret) - ret = pb_write_one(img_from_set(glob_imgset, CR_FD_TTY_FILES), &e, PB_TTY_FILE); + if (!ret) { + FileEntry fe = FILE_ENTRY__INIT; + + fe.type = FD_TYPES__TTY; + fe.id = e.id; + fe.tty = &e; + ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); + } + return ret; } diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 37318c50d..0a6f3ee74 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -15,6 +15,7 @@ import "ext-file.proto"; import "sk-unix.proto"; import "fifo.proto"; import "pipe.proto"; +import "tty.proto"; enum fd_types { UND = 0; @@ -63,4 +64,5 @@ message file_entry { optional unix_sk_entry usk = 16; optional fifo_entry fifo = 17; optional pipe_entry pipe = 18; + optional tty_file_entry tty = 19; } From 7ce8f56be27ca372f3ed028ab0cb655dcf0abd62 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 30 Jun 2017 20:31:36 +0200 Subject: [PATCH 0682/4375] s390:compel/arch/s390: Add architecture support to compel tool and libraries This patch only adds the support but does not enable it for building. Reviewed-by: Alice Frosi Signed-off-by: Michael Holzheu Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- .../arch/s390/plugins/include/asm/prologue.h | 1 + .../s390/plugins/include/asm/syscall-types.h | 34 ++ compel/arch/s390/plugins/std/parasite-head.S | 26 + .../plugins/std/syscalls/Makefile.syscalls | 58 ++ .../std/syscalls/syscall-common-s390.S | 37 ++ .../plugins/std/syscalls/syscall-s390.tbl | 108 ++++ .../s390/plugins/std/syscalls/syscalls-s390.c | 26 + compel/arch/s390/scripts/compel-pack.lds.S | 40 ++ compel/arch/s390/src/lib/cpu.c | 42 ++ compel/arch/s390/src/lib/handle-elf-host.c | 1 + compel/arch/s390/src/lib/handle-elf.c | 22 + compel/arch/s390/src/lib/include/handle-elf.h | 13 + compel/arch/s390/src/lib/include/syscall.h | 8 + .../src/lib/include/uapi/asm/breakpoints.h | 15 + .../arch/s390/src/lib/include/uapi/asm/cpu.h | 10 + .../arch/s390/src/lib/include/uapi/asm/fpu.h | 14 + .../src/lib/include/uapi/asm/infect-types.h | 75 +++ .../s390/src/lib/include/uapi/asm/sigframe.h | 75 +++ compel/arch/s390/src/lib/infect.c | 559 ++++++++++++++++++ include/common/arch/s390/asm/atomic.h | 67 +++ include/common/arch/s390/asm/atomic_ops.h | 74 +++ include/common/arch/s390/asm/bitops.h | 164 +++++ include/common/arch/s390/asm/bitsperlong.h | 6 + include/common/arch/s390/asm/linkage.h | 22 + include/common/arch/s390/asm/page.h | 19 + 25 files changed, 1516 insertions(+) create mode 120000 compel/arch/s390/plugins/include/asm/prologue.h create mode 100644 compel/arch/s390/plugins/include/asm/syscall-types.h create mode 100644 compel/arch/s390/plugins/std/parasite-head.S create mode 100644 compel/arch/s390/plugins/std/syscalls/Makefile.syscalls create mode 100644 compel/arch/s390/plugins/std/syscalls/syscall-common-s390.S create mode 100644 compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl create mode 100644 compel/arch/s390/plugins/std/syscalls/syscalls-s390.c create mode 100644 compel/arch/s390/scripts/compel-pack.lds.S create mode 100644 compel/arch/s390/src/lib/cpu.c create mode 120000 compel/arch/s390/src/lib/handle-elf-host.c create mode 100644 compel/arch/s390/src/lib/handle-elf.c create mode 100644 compel/arch/s390/src/lib/include/handle-elf.h create mode 100644 compel/arch/s390/src/lib/include/syscall.h create mode 100644 compel/arch/s390/src/lib/include/uapi/asm/breakpoints.h create mode 100644 compel/arch/s390/src/lib/include/uapi/asm/cpu.h create mode 100644 compel/arch/s390/src/lib/include/uapi/asm/fpu.h create mode 100644 compel/arch/s390/src/lib/include/uapi/asm/infect-types.h create mode 100644 compel/arch/s390/src/lib/include/uapi/asm/sigframe.h create mode 100644 compel/arch/s390/src/lib/infect.c create mode 100644 include/common/arch/s390/asm/atomic.h create mode 100644 include/common/arch/s390/asm/atomic_ops.h create mode 100644 include/common/arch/s390/asm/bitops.h create mode 100644 include/common/arch/s390/asm/bitsperlong.h create mode 100644 include/common/arch/s390/asm/linkage.h create mode 100644 include/common/arch/s390/asm/page.h diff --git a/compel/arch/s390/plugins/include/asm/prologue.h b/compel/arch/s390/plugins/include/asm/prologue.h new file mode 120000 index 000000000..e0275e350 --- /dev/null +++ b/compel/arch/s390/plugins/include/asm/prologue.h @@ -0,0 +1 @@ +../../../../../arch/x86/plugins/include/asm/prologue.h \ No newline at end of file diff --git a/compel/arch/s390/plugins/include/asm/syscall-types.h b/compel/arch/s390/plugins/include/asm/syscall-types.h new file mode 100644 index 000000000..55d7ddb61 --- /dev/null +++ b/compel/arch/s390/plugins/include/asm/syscall-types.h @@ -0,0 +1,34 @@ +#ifndef COMPEL_ARCH_SYSCALL_TYPES_H__ +#define COMPEL_ARCH_SYSCALL_TYPES_H__ + +#define SA_RESTORER 0x04000000U + +typedef void rt_signalfn_t(int, siginfo_t *, void *); +typedef rt_signalfn_t *rt_sighandler_t; + +typedef void rt_restorefn_t(void); +typedef rt_restorefn_t *rt_sigrestore_t; + +#define _KNSIG 64 +#define _NSIG_BPW 64 + +#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) + +typedef struct { + unsigned long sig[_KNSIG_WORDS]; +} k_rtsigset_t; + +/* + * Used for rt_sigaction() system call - see kernel "struct sigaction" in + * include/linux/signal.h. + */ +typedef struct { + rt_sighandler_t rt_sa_handler; + unsigned long rt_sa_flags; + rt_sigrestore_t rt_sa_restorer; + k_rtsigset_t rt_sa_mask; +} rt_sigaction_t; + +struct mmap_arg_struct; + +#endif /* COMPEL_ARCH_SYSCALL_TYPES_H__ */ diff --git a/compel/arch/s390/plugins/std/parasite-head.S b/compel/arch/s390/plugins/std/parasite-head.S new file mode 100644 index 000000000..f4cb37276 --- /dev/null +++ b/compel/arch/s390/plugins/std/parasite-head.S @@ -0,0 +1,26 @@ +#include "common/asm/linkage.h" + + .section .head.text, "ax" + +/* + * Entry point for parasite_service() + * + * Addresses of symbols are exported in auto-generated criu/pie/parasite-blob.h + * + * Function is called via parasite_run(). The command for parasite_service() + * is stored in global variable __export_parasite_cmd. + * + * Load parameters for parasite_service(unsigned int cmd, void *args): + * + * - Parameter 1 (cmd) : %r2 = *(uint32 *)(__export_parasite_cmd + pc) + * - Parameter 2 (args): %r3 = __export_parasite_args + pc + */ +ENTRY(__export_parasite_head_start) + larl %r14,__export_parasite_cmd + llgf %r2,0(%r14) + larl %r3,__export_parasite_args + brasl %r14,parasite_service + .long 0x00010001 /* S390_BREAKPOINT_U16: Generates SIGTRAP */ +__export_parasite_cmd: + .long 0 +END(__export_parasite_head_start) diff --git a/compel/arch/s390/plugins/std/syscalls/Makefile.syscalls b/compel/arch/s390/plugins/std/syscalls/Makefile.syscalls new file mode 100644 index 000000000..f03b7cc43 --- /dev/null +++ b/compel/arch/s390/plugins/std/syscalls/Makefile.syscalls @@ -0,0 +1,58 @@ +ccflags-y += -iquote $(PLUGIN_ARCH_DIR)/std/syscalls/ +asflags-y += -iquote $(PLUGIN_ARCH_DIR)/std/syscalls/ + +sys-types := $(obj)/include/uapi/std/syscall-types.h +sys-codes := $(obj)/include/uapi/std/syscall-codes.h +sys-proto := $(obj)/include/uapi/std/syscall.h + +sys-def := $(PLUGIN_ARCH_DIR)/std/syscalls/syscall-s390.tbl +sys-asm-common-name := std/syscalls/syscall-common-s390.S +sys-asm-common := $(PLUGIN_ARCH_DIR)/$(sys-asm-common-name) +sys-asm-types := $(obj)/include/uapi/std/asm/syscall-types.h +sys-exec-tbl = $(PLUGIN_ARCH_DIR)/std/sys-exec-tbl.c + +sys-asm := ./$(PLUGIN_ARCH_DIR)/std/syscalls/syscalls.S +std-lib-y += $(sys-asm:.S=).o +std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/syscalls/syscalls-s390.o + +$(sys-codes): $(sys-def) + $(E) " GEN " $@ + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_CODES_H__" >> $@ + $(Q) echo "#define __ASM_CR_SYSCALL_CODES_H__" >> $@ + $(Q) cat $< | awk '/^__NR/{SYSN=$$1; sub("^__NR", "SYS", SYSN);'\ + 'print "\n#ifndef ", $$1, "\n#define", $$1, $$2, "\n#endif";'\ + 'print "#ifndef ", SYSN, "\n#define ", SYSN, $$1, "\n#endif"}' >> $@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_CODES_H__ */" >> $@ + +$(sys-proto): $(sys-def) + $(E) " GEN " $@ + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_PROTO_H__" >> $@ + $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H__" >> $@ + $(Q) echo "#include " >> $@ + $(Q) echo "#include " >> $@ + $(Q) cat $< | awk '/^__NR/{print "extern long", $$3, substr($$0, index($$0,$$4)), ";"}' >> $@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H__ */" >> $@ + +$(sys-asm): $(sys-def) $(sys-asm-common) $(sys-codes) $(sys-proto) + $(E) " GEN " $@ + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#include " >> $@ + $(Q) echo "#include \"$(sys-asm-common-name)\"" >> $@ + $(Q) cat $< | awk '/^__NR/{print "SYSCALL(", $$3, ",", $$2, ")"}' >> $@ + +$(sys-exec-tbl): $(sys-def) $(sys-codes) $(sys-proto) + $(E) " GEN " $@ + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "static struct syscall_exec_desc sc_exec_table[] = {" >> $@ + $(Q) cat $< | awk '/^__NR/{print "SYSCALL(", substr($$3, 5), ",", $$2, ")"}' >> $@ + $(Q) echo " { }, /* terminator */" >> $@ + $(Q) echo "};" >> $@ + +$(sys-asm-types): $(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h + $(call msg-gen, $@) + $(Q) ln -s ../../../../../../$(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h $(sys-asm-types) + +std-headers-deps += $(sys-asm) $(sys-codes) $(sys-proto) $(sys-asm-types) +mrproper-y += $(std-headers-deps) diff --git a/compel/arch/s390/plugins/std/syscalls/syscall-common-s390.S b/compel/arch/s390/plugins/std/syscalls/syscall-common-s390.S new file mode 100644 index 000000000..79e3b8e98 --- /dev/null +++ b/compel/arch/s390/plugins/std/syscalls/syscall-common-s390.S @@ -0,0 +1,37 @@ +#include "common/asm/linkage.h" + +/* + * Define a system call + * + * C-ABI on s390: + * - Parameters 1-5 are passed in %r2-%r6 + * - Parameter 6 is passed on the stack 160(%r15) + * - Return value is in %r2 + * - Return address is in %r14 + * - Registers %r0-%r6,%r14 are call-clobbered + * - Registers %r7-%r13,%r15 are call-saved + * + * SVC ABI on s390: + * - For SVC 0 the system call number is passed in %r1 + * - Parameters 1-6 are passed in %r2-%r7 + * - Return value is passed in %r2 + * - Besides of %r2 all registers are call-saved + */ +#define SYSCALL(name, opcode) \ +ENTRY(name); \ + lgr %r0,%r7; /* Save %r7 */ \ + lg %r7,160(%r15); /* Load 6th parameter */ \ + lghi %r1,opcode; /* Load SVC number */ \ + svc 0; /* Issue SVC 0 */ \ + lgr %r7,%r0; /* Restore %r7 */ \ + br %r14; /* Return to caller */ \ +END(name) \ + +/* + * Issue rt_sigreturn system call for sa_restorer + */ +ENTRY(__cr_restore_rt) + lghi %r1,__NR_rt_sigreturn + svc 0 +END(__cr_restore_rt) + diff --git a/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl b/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl new file mode 100644 index 000000000..1670450ce --- /dev/null +++ b/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl @@ -0,0 +1,108 @@ +# +# System calls table, please make sure the table consists of only the syscalls +# really used somewhere in the project. +# +# The template is (name and arguments are optional if you need only __NR_x +# defined, but no real entry point in syscalls lib). +# +# name code name arguments +# ----------------------------------------------------------------------- +# +__NR_read 3 sys_read (int fd, void *buf, unsigned long count) +__NR_write 4 sys_write (int fd, const void *buf, unsigned long count) +__NR_open 5 sys_open (const char *filename, unsigned long flags, unsigned long mode) +__NR_close 6 sys_close (int fd) +__NR_lseek 19 sys_lseek (int fd, unsigned long offset, unsigned long origin) +__NR_mmap 90 sys_old_mmap (struct mmap_arg_struct *) +__NR_mprotect 125 sys_mprotect (const void *addr, unsigned long len, unsigned long prot) +__NR_munmap 91 sys_munmap (void *addr, unsigned long len) +__NR_brk 45 sys_brk (void *addr) +__NR_rt_sigaction 174 sys_sigaction (int signum, const rt_sigaction_t *act, rt_sigaction_t *oldact, size_t sigsetsize) +__NR_rt_sigprocmask 175 sys_sigprocmask (int how, k_rtsigset_t *set, k_rtsigset_t *old, size_t sigsetsize) +__NR_rt_sigreturn 173 sys_rt_sigreturn (void) +__NR_ioctl 54 sys_ioctl (unsigned int fd, unsigned int cmd, unsigned long arg) +__NR_pread64 180 sys_pread (unsigned int fd, char *buf, size_t count, loff_t pos) +__NR_ptrace 26 sys_ptrace (long request, pid_t pid, void *addr, void *data) +__NR_mremap 163 sys_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) +__NR_mincore 218 sys_mincore (void *addr, unsigned long size, unsigned char *vec) +__NR_madvise 219 sys_madvise (unsigned long start, size_t len, int behavior) +__NR_pause 29 sys_pause (void) +__NR_nanosleep 162 sys_nanosleep (struct timespec *req, struct timespec *rem) +__NR_getitimer 105 sys_getitimer (int which, const struct itimerval *val) +__NR_setitimer 104 sys_setitimer (int which, const struct itimerval *val, struct itimerval *old) +__NR_getpid 20 sys_getpid (void) +__NR_socket 359 sys_socket (int domain, int type, int protocol) +__NR_connect 362 sys_connect (int sockfd, struct sockaddr *addr, int addrlen) +__NR_sendto 369 sys_sendto (int sockfd, void *buff, size_t len, unsigned int flags, struct sockaddr *addr, int addr_len) +__NR_recvfrom 371 sys_recvfrom (int sockfd, void *ubuf, size_t size, unsigned int flags, struct sockaddr *addr, int *addr_len) +__NR_sendmsg 370 sys_sendmsg (int sockfd, const struct msghdr *msg, int flags) +__NR_recvmsg 372 sys_recvmsg (int sockfd, struct msghdr *msg, int flags) +__NR_shutdown 373 sys_shutdown (int sockfd, int how) +__NR_bind 361 sys_bind (int sockfd, const struct sockaddr *addr, int addrlen) +__NR_setsockopt 366 sys_setsockopt (int sockfd, int level, int optname, const void *optval, socklen_t optlen) +__NR_getsockopt 365 sys_getsockopt (int sockfd, int level, int optname, const void *optval, socklen_t *optlen) +__NR_clone 120 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, void *child_tid, void *tls) +__NR_exit 1 sys_exit (unsigned long error_code) +__NR_wait4 114 sys_wait4 (int pid, int *status, int options, struct rusage *ru) +__NR_kill 37 sys_kill (long pid, int sig) +__NR_fcntl 55 sys_fcntl (int fd, int type, long arg) +__NR_flock 143 sys_flock (int fd, unsigned long cmd) +__NR_mkdir 39 sys_mkdir (const char *name, int mode) +__NR_rmdir 40 sys_rmdir (const char *name) +__NR_unlink 10 sys_unlink (char *pathname) +__NR_readlinkat 298 sys_readlinkat (int fd, const char *path, char *buf, int bufsize) +__NR_umask 60 sys_umask (int mask) +__NR_getgroups 205 sys_getgroups (int gsize, unsigned int *groups) +__NR_setgroups 206 sys_setgroups (int gsize, unsigned int *groups) +__NR_setresuid 208 sys_setresuid (int uid, int euid, int suid) +__NR_getresuid 209 sys_getresuid (int *uid, int *euid, int *suid) +__NR_setresgid 210 sys_setresgid (int gid, int egid, int sgid) +__NR_getresgid 211 sys_getresgid (int *gid, int *egid, int *sgid) +__NR_getpgid 132 sys_getpgid (pid_t pid) +__NR_setfsuid 215 sys_setfsuid (int fsuid) +__NR_setfsgid 216 sys_setfsgid (int fsgid) +__NR_getsid 147 sys_getsid (void) +__NR_capget 184 sys_capget (struct cap_header *h, struct cap_data *d) +__NR_capset 185 sys_capset (struct cap_header *h, struct cap_data *d) +__NR_rt_sigqueueinfo 178 sys_rt_sigqueueinfo (pid_t pid, int sig, siginfo_t *info) +__NR_sigaltstack 186 sys_sigaltstack (const void *uss, void *uoss) +__NR_personality 136 sys_personality (unsigned int personality) +__NR_setpriority 97 sys_setpriority (int which, int who, int nice) +__NR_sched_setscheduler 156 sys_sched_setscheduler (int pid, int policy, struct sched_param *p) +__NR_prctl 172 sys_prctl (int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) +__NR_setrlimit 75 sys_setrlimit (int resource, struct krlimit *rlim) +__NR_mount 21 sys_mount (char *dev_nmae, char *dir_name, char *type, unsigned long flags, void *data) +__NR_umount2 52 sys_umount2 (char *name, int flags) +__NR_gettid 236 sys_gettid (void) +__NR_futex 238 sys_futex (uint32_t *uaddr, int op, uint32_t val, struct timespec *utime, uint32_t *uaddr2, uint32_t val3) +__NR_set_tid_address 252 sys_set_tid_address (int *tid_addr) +__NR_restart_syscall 7 sys_restart_syscall (void) +__NR_sys_timer_create 254 sys_timer_create (clockid_t which_clock, struct sigevent *timer_event_spec, kernel_timer_t *created_timer_id) +__NR_sys_timer_settime 255 sys_timer_settime (kernel_timer_t timer_id, int flags, const struct itimerspec *new_setting, struct itimerspec *old_setting) +__NR_sys_timer_gettime 256 sys_timer_gettime (int timer_id, const struct itimerspec *setting) +__NR_sys_timer_getoverrun 257 sys_timer_getoverrun (int timer_id) +__NR_sys_timer_delete 258 sys_timer_delete (kernel_timer_t timer_id) +__NR_clock_gettime 260 sys_clock_gettime (const clockid_t which_clock, const struct timespec *tp) +__NR_exit_group 248 sys_exit_group (int error_code) +__NR_waitid 281 sys_waitid (int which, pid_t pid, struct siginfo *infop, int options, struct rusage *ru) +__NR_set_robust_list 304 sys_set_robust_list (struct robust_list_head *head, size_t len) +__NR_get_robust_list 305 sys_get_robust_list (int pid, struct robust_list_head **head_ptr, size_t *len_ptr) +__NR_vmsplice 309 sys_vmsplice (int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags) +__NR_openat 288 sys_openat (int dfd, const char *filename, int flags, int mode) +__NR_timerfd_settime 320 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) +__NR_signalfd4 322 sys_signalfd (int fd, k_rtsigset_t *mask, size_t sizemask, int flags) +__NR_rt_tgsigqueueinfo 330 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *info) +__NR_fanotify_init 332 sys_fanotify_init (unsigned int flags, unsigned int event_f_flags) +__NR_fanotify_mark 333 sys_fanotify_mark (int fanotify_fd, unsigned int flags, uint64_t mask, int dfd, const char *pathname) +__NR_open_by_handle_at 336 sys_open_by_handle_at (int mountdirfd, struct file_handle *handle, int flags) +__NR_setns 339 sys_setns (int fd, int nstype) +__NR_kcmp 343 sys_kcmp (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) +__NR_seccomp 348 sys_seccomp (unsigned int op, unsigned int flags, const char *uargs) +__NR_memfd_create 350 sys_memfd_create (const char *name, unsigned int flags) +__NR_io_setup 243 sys_io_setup (unsigned nr_events, aio_context_t *ctx_idp) +__NR_io_getevents 245 sys_io_getevents (aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout) +__NR_io_submit 246 sys_io_submit (aio_context_t ctx_id, long nr, struct iocb **iocbpp) +__NR_ipc 117 sys_ipc (unsigned int call, int first, unsigned long second, unsigned long third, const void *ptr, long fifth) +__NR_userfaultfd 355 sys_userfaultfd (int flags) +__NR_preadv 328 sys_preadv (int fd, struct iovec *iov, unsigned long nr, loff_t off) +__NR_gettimeofday 78 sys_gettimeofday (struct timeval *tv, struct timezone *tz) diff --git a/compel/arch/s390/plugins/std/syscalls/syscalls-s390.c b/compel/arch/s390/plugins/std/syscalls/syscalls-s390.c new file mode 100644 index 000000000..2b35cca4a --- /dev/null +++ b/compel/arch/s390/plugins/std/syscalls/syscalls-s390.c @@ -0,0 +1,26 @@ +#include "asm/infect-types.h" + +/* + * Define prototype because of compile error if we include uapi/std/syscall.h + */ +long sys_old_mmap (struct mmap_arg_struct *); + +/* + * On s390 we have defined __ARCH_WANT_SYS_OLD_MMAP - Therefore implement + * system call with one parameter "mmap_arg_struct". + */ +unsigned long sys_mmap(void *addr, unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, + unsigned long offset) +{ + struct mmap_arg_struct arg_struct; + + arg_struct.addr = (unsigned long)addr; + arg_struct.len = len; + arg_struct.prot = prot; + arg_struct.flags = flags; + arg_struct.fd = fd; + arg_struct.offset = offset; + + return sys_old_mmap(&arg_struct); +} diff --git a/compel/arch/s390/scripts/compel-pack.lds.S b/compel/arch/s390/scripts/compel-pack.lds.S new file mode 100644 index 000000000..91ffbda3e --- /dev/null +++ b/compel/arch/s390/scripts/compel-pack.lds.S @@ -0,0 +1,40 @@ +OUTPUT_ARCH(s390:64-bit) +EXTERN(__export_parasite_head_start) + +SECTIONS +{ + .text : { + *(.head.text) + ASSERT(DEFINED(__export_parasite_head_start), + "Symbol __export_parasite_head_start is missing"); + *(.text*) + *(.compel.exit) + *(.compel.init) + } + + .data : { + *(.data*) + *(.bss*) + } + + .rodata : { + *(.rodata*) + *(.got*) + } + + .toc : ALIGN(8) { + *(.toc*) + } + + /DISCARD/ : { + *(.debug*) + *(.comment*) + *(.note*) + *(.group*) + *(.eh_frame*) + } + +/* Parasite args should have 4 bytes align, as we have futex inside. */ +. = ALIGN(4); +__export_parasite_args = .; +} diff --git a/compel/arch/s390/src/lib/cpu.c b/compel/arch/s390/src/lib/cpu.c new file mode 100644 index 000000000..174575f93 --- /dev/null +++ b/compel/arch/s390/src/lib/cpu.c @@ -0,0 +1,42 @@ +#include + +#include +#include + +#include "compel-cpu.h" +#include "common/bitops.h" +#include "common/compiler.h" + +#include "log.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "cpu: " + +static compel_cpuinfo_t rt_info; +static bool rt_info_done = false; + +void compel_set_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) { } +void compel_clear_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) { } +int compel_test_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) { return 0; } + +int compel_cpuid(compel_cpuinfo_t *info) +{ + info->hwcap[0] = getauxval(AT_HWCAP); + info->hwcap[1] = getauxval(AT_HWCAP2); + + if (!info->hwcap[0]) { + pr_err("Can't read the hardware capabilities"); + return -1; + } + + return 0; +} + +bool cpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_cpu_cap(&rt_info, feature); +} diff --git a/compel/arch/s390/src/lib/handle-elf-host.c b/compel/arch/s390/src/lib/handle-elf-host.c new file mode 120000 index 000000000..fe4611886 --- /dev/null +++ b/compel/arch/s390/src/lib/handle-elf-host.c @@ -0,0 +1 @@ +handle-elf.c \ No newline at end of file diff --git a/compel/arch/s390/src/lib/handle-elf.c b/compel/arch/s390/src/lib/handle-elf.c new file mode 100644 index 000000000..01a8bf4c8 --- /dev/null +++ b/compel/arch/s390/src/lib/handle-elf.c @@ -0,0 +1,22 @@ +#include + +#include "uapi/compel.h" + +#include "handle-elf.h" +#include "piegen.h" +#include "log.h" + +static const unsigned char __maybe_unused +elf_ident_64[EI_NIDENT] = { + 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x02, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +int handle_binary(void *mem, size_t size) +{ + if (memcmp(mem, elf_ident_64, sizeof(elf_ident_64)) == 0) + return handle_elf_s390(mem, size); + + pr_err("Unsupported Elf format detected\n"); + return -EINVAL; +} diff --git a/compel/arch/s390/src/lib/include/handle-elf.h b/compel/arch/s390/src/lib/include/handle-elf.h new file mode 100644 index 000000000..cd1357401 --- /dev/null +++ b/compel/arch/s390/src/lib/include/handle-elf.h @@ -0,0 +1,13 @@ +#ifndef COMPEL_HANDLE_ELF_H__ +#define COMPEL_HANDLE_ELF_H__ + +#include "elf64-types.h" + +#define ELF_S390 + +#define __handle_elf handle_elf_s390 +#define arch_is_machine_supported(e_machine) (e_machine == EM_S390) + +int handle_elf_s390(void *mem, size_t size); + +#endif /* COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/arch/s390/src/lib/include/syscall.h b/compel/arch/s390/src/lib/include/syscall.h new file mode 100644 index 000000000..57d49121f --- /dev/null +++ b/compel/arch/s390/src/lib/include/syscall.h @@ -0,0 +1,8 @@ +#ifndef __COMPEL_SYSCALL_H__ +#define __COMPEL_SYSCALL_H__ + +unsigned long sys_mmap(void *addr, unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, + unsigned long offset); + +#endif diff --git a/compel/arch/s390/src/lib/include/uapi/asm/breakpoints.h b/compel/arch/s390/src/lib/include/uapi/asm/breakpoints.h new file mode 100644 index 000000000..5f090490d --- /dev/null +++ b/compel/arch/s390/src/lib/include/uapi/asm/breakpoints.h @@ -0,0 +1,15 @@ +#ifndef __COMPEL_BREAKPOINTS_H__ +#define __COMPEL_BREAKPOINTS_H__ +#define ARCH_SI_TRAP TRAP_BRKPT + +static inline int ptrace_set_breakpoint(pid_t pid, void *addr) +{ + return 0; +} + +static inline int ptrace_flush_breakpoints(pid_t pid) +{ + return 0; +} + +#endif diff --git a/compel/arch/s390/src/lib/include/uapi/asm/cpu.h b/compel/arch/s390/src/lib/include/uapi/asm/cpu.h new file mode 100644 index 000000000..b01db511d --- /dev/null +++ b/compel/arch/s390/src/lib/include/uapi/asm/cpu.h @@ -0,0 +1,10 @@ +#ifndef UAPI_COMPEL_ASM_CPU_H__ +#define UAPI_COMPEL_ASM_CPU_H__ + +#include + +typedef struct { + uint64_t hwcap[2]; +} compel_cpuinfo_t; + +#endif /* __CR_ASM_CPU_H__ */ diff --git a/compel/arch/s390/src/lib/include/uapi/asm/fpu.h b/compel/arch/s390/src/lib/include/uapi/asm/fpu.h new file mode 100644 index 000000000..49c907866 --- /dev/null +++ b/compel/arch/s390/src/lib/include/uapi/asm/fpu.h @@ -0,0 +1,14 @@ +#ifndef __CR_ASM_FPU_H__ +#define __CR_ASM_FPU_H__ + +#include +#include + +/* + * This one is used in restorer + */ +typedef struct { + bool has_fpu; +} fpu_state_t; + +#endif /* __CR_ASM_FPU_H__ */ diff --git a/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h b/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h new file mode 100644 index 000000000..84edea5d7 --- /dev/null +++ b/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h @@ -0,0 +1,75 @@ +#ifndef UAPI_COMPEL_ASM_TYPES_H__ +#define UAPI_COMPEL_ASM_TYPES_H__ + +#include +#include +#include +#include +#include "common/page.h" + +#define SIGMAX 64 +#define SIGMAX_OLD 31 + +/* + * Definitions from /usr/include/asm/ptrace.h: + * + * typedef struct + * { + * __u32 fpc; + * freg_t fprs[NUM_FPRS]; + * } s390_fp_regs; + * + * typedef struct + * { + * psw_t psw; + * unsigned long gprs[NUM_GPRS]; + * unsigned int acrs[NUM_ACRS]; + * unsigned long orig_gpr2; + * } s390_regs; + */ +typedef struct { + uint64_t part1; + uint64_t part2; +} vector128_t; + +struct prfpreg { + uint32_t fpc; + uint64_t fprs[16]; +}; + +#define USER_FPREGS_VXRS 0x000000001 + +typedef struct { + uint32_t flags; + struct prfpreg prfpreg; + uint64_t vxrs_low[16]; + vector128_t vxrs_high[16]; +} user_fpregs_struct_t; + +typedef struct { + s390_regs prstatus; + uint32_t system_call; +} user_regs_struct_t; + +#define REG_RES(r) ((uint64_t)(r).prstatus.gprs[2]) +#define REG_IP(r) ((uint64_t)(r).prstatus.psw.addr) +/* + * We assume that REG_SYSCALL_NR() is only used for pie code where we + * always use svc 0 with opcode in %r1. + */ +#define REG_SYSCALL_NR(r) ((uint64_t)(r).prstatus.gprs[1]) + +#define user_regs_native(pregs) true + +#define __NR(syscall, compat) __NR_##syscall + +struct mmap_arg_struct { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +#endif /* UAPI_COMPEL_ASM_TYPES_H__ */ diff --git a/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h b/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h new file mode 100644 index 000000000..d04320241 --- /dev/null +++ b/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h @@ -0,0 +1,75 @@ + +#ifndef UAPI_COMPEL_ASM_SIGFRAME_H__ +#define UAPI_COMPEL_ASM_SIGFRAME_H__ + +#include +#include + +#include +#include + +// XXX: the identifier rt_sigcontext is expected to be struct by the CRIU code +#define rt_sigcontext sigcontext + +#include + +#define RT_SIGFRAME_OFFSET(rt_sigframe) 0 + +/* + * From /usr/include/asm/sigcontext.h + * + * Redefine _sigregs_ext to be able to compile on older systems + */ +#ifndef __NUM_VXRS_LOW +typedef struct { + __u32 u[4]; +} __vector128; + +typedef struct { + unsigned long long vxrs_low[16]; + __vector128 vxrs_high[16]; + unsigned char __reserved[128]; +} _sigregs_ext; +#endif + +/* + * From /usr/include/uapi/asm/ucontext.h + */ +struct ucontext_extended { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + _sigregs uc_mcontext; + sigset_t uc_sigmask; + /* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */ + unsigned char __unused[128 - sizeof(sigset_t)]; + _sigregs_ext uc_mcontext_ext; +}; + +/* + * Signal stack frame for RT sigreturn + */ +struct rt_sigframe { + uint8_t callee_used_stack[160]; + uint8_t retcode[2]; + siginfo_t info; + struct ucontext_extended uc; +}; + +/* + * Do rt_sigreturn SVC + */ +#define ARCH_RT_SIGRETURN(new_sp, rt_sigframe) \ + asm volatile( \ + "lgr %%r15,%0\n" \ + "lghi %%r1,173\n" \ + "svc 0\n" \ + : \ + : "d" (new_sp) \ + : "15", "memory") + +#define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->uc) +#define RT_SIGFRAME_REGIP(rt_sigframe) (rt_sigframe)->uc.uc_mcontext.regs.psw.addr +#define RT_SIGFRAME_HAS_FPU(rt_sigframe) (1) + +#endif /* UAPI_COMPEL_ASM_SIGFRAME_H__ */ diff --git a/compel/arch/s390/src/lib/infect.c b/compel/arch/s390/src/lib/infect.c new file mode 100644 index 000000000..fcad33896 --- /dev/null +++ b/compel/arch/s390/src/lib/infect.c @@ -0,0 +1,559 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "uapi/compel/asm/infect-types.h" +#include "errno.h" +#include "log.h" +#include "common/bug.h" +#include "infect.h" +#include "ptrace.h" +#include "infect-priv.h" + +#define NT_PRFPREG 2 +#define NT_S390_VXRS_LOW 0x309 +#define NT_S390_VXRS_HIGH 0x30a + +/* + * Print general purpose and access registers + */ +static void print_user_regs_struct(const char *msg, int pid, + user_regs_struct_t *regs) +{ + int i; + + pr_debug("%s: Registers for pid=%d\n", msg, pid); + pr_debug("system_call %08lx\n", (unsigned long) regs->system_call); + pr_debug(" psw %016lx %016lx\n", regs->prstatus.psw.mask, + regs->prstatus.psw.addr); + pr_debug(" orig_gpr2 %016lx\n", regs->prstatus.orig_gpr2); + for (i = 0; i < 16; i++) + pr_debug(" g%02d %016lx\n", i, regs->prstatus.gprs[i]); + for (i = 0; i < 16; i++) + pr_debug(" a%02d %08x\n", i, regs->prstatus.acrs[i]); +} + +/* + * Print floating point and vector registers + */ +static void print_user_fpregs_struct(const char *msg, int pid, + user_fpregs_struct_t *fpregs) +{ + int i; + + pr_debug("%s: FP registers for pid=%d\n", msg, pid); + pr_debug(" fpc %08x\n", fpregs->prfpreg.fpc); + for (i = 0; i < 16; i++) + pr_debug(" f%02d %016lx\n", i, fpregs->prfpreg.fprs[i]); + if (!(fpregs->flags & USER_FPREGS_VXRS)) { + pr_debug(" No VXRS\n"); + return; + } + for (i = 0; i < 16; i++) + pr_debug(" vx_low%02d %016lx\n", i, fpregs->vxrs_low[i]); + for (i = 0; i < 16; i++) + pr_debug(" vx_high%02d %016lx %016lx\n", i, + fpregs->vxrs_high[i].part1, + fpregs->vxrs_high[i].part2); +} + +int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, + user_regs_struct_t *regs, + user_fpregs_struct_t *fpregs) +{ + _sigregs_ext *dst_ext = &sigframe->uc.uc_mcontext_ext; + _sigregs *dst = &sigframe->uc.uc_mcontext; + + memcpy(dst->regs.gprs, regs->prstatus.gprs, + sizeof(regs->prstatus.gprs)); + memcpy(dst->regs.acrs, regs->prstatus.acrs, + sizeof(regs->prstatus.acrs)); + memcpy(&dst->regs.psw, ®s->prstatus.psw, + sizeof(regs->prstatus.psw)); + memcpy(&dst->fpregs.fpc, &fpregs->prfpreg.fpc, + sizeof(fpregs->prfpreg.fpc)); + memcpy(&dst->fpregs.fprs, &fpregs->prfpreg.fprs, + sizeof(fpregs->prfpreg.fprs)); + if (fpregs->flags & USER_FPREGS_VXRS) { + memcpy(&dst_ext->vxrs_low, &fpregs->vxrs_low, + sizeof(fpregs->vxrs_low)); + memcpy(&dst_ext->vxrs_high, &fpregs->vxrs_high, + sizeof(fpregs->vxrs_high)); + } else { + memset(&dst_ext->vxrs_low, 0, + sizeof(sizeof(fpregs->vxrs_low))); + memset(&dst_ext->vxrs_high, 0, + sizeof(sizeof(fpregs->vxrs_high))); + } + return 0; +} + +int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, + struct rt_sigframe *rsigframe) +{ + return 0; +} + +/* + * Rewind the psw for 'bytes' bytes + */ +static inline void rewind_psw(psw_t *psw, unsigned long bytes) +{ + unsigned long mask; + + pr_debug("Rewind psw: %016lx bytes=%lu\n", psw->addr, bytes); + mask = (psw->mask & PSW_MASK_EA) ? -1UL : + (psw->mask & PSW_MASK_BA) ? (1UL << 31) - 1 : + (1UL << 24) - 1; + psw->addr = (psw->addr - bytes) & mask; +} + +/* + * Get vector registers + */ +int get_vx_regs(pid_t pid, user_fpregs_struct_t *fpregs) +{ + struct iovec iov; + + fpregs->flags &= ~USER_FPREGS_VXRS; + iov.iov_base = &fpregs->vxrs_low; + iov.iov_len = sizeof(fpregs->vxrs_low); + if (ptrace(PTRACE_GETREGSET, pid, NT_S390_VXRS_LOW, &iov) < 0) { + /* + * If the kernel does not support vector registers, we get + * EINVAL. With kernel support and old hardware, we get ENODEV. + */ + if (errno == EINVAL || errno == ENODEV) { + memset(fpregs->vxrs_low, 0, sizeof(fpregs->vxrs_low)); + memset(fpregs->vxrs_high, 0, sizeof(fpregs->vxrs_high)); + pr_debug("VXRS registers not supported\n"); + return 0; + } + pr_perror("Couldn't get VXRS_LOW\n"); + return -1; + } + iov.iov_base = &fpregs->vxrs_high; + iov.iov_len = sizeof(fpregs->vxrs_high); + if (ptrace(PTRACE_GETREGSET, pid, NT_S390_VXRS_HIGH, &iov) < 0) { + pr_perror("Couldn't get VXRS_HIGH\n"); + return -1; + } + fpregs->flags |= USER_FPREGS_VXRS; + return 0; +} + +/* + * Set vector registers + */ +int set_vx_regs(pid_t pid, user_fpregs_struct_t *fpregs) +{ + struct iovec iov; + int rc; + + if (!(fpregs->flags & USER_FPREGS_VXRS)) + return 0; + + iov.iov_base = &fpregs->vxrs_low; + iov.iov_len = sizeof(fpregs->vxrs_low); + rc = ptrace(PTRACE_SETREGSET, pid, NT_S390_VXRS_LOW, &iov); + if (rc) { + pr_perror("Couldn't set VXRS_LOW registers\n"); + return rc; + } + + iov.iov_base = &fpregs->vxrs_high; + iov.iov_len = sizeof(fpregs->vxrs_high); + rc = ptrace(PTRACE_SETREGSET, pid, NT_S390_VXRS_HIGH, &iov); + if (rc) + pr_perror("Couldn't set VXRS_HIGH registers\n"); + return rc; +} + +/* + * Prepare task registers for restart + */ +int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, + void *arg) +{ + user_fpregs_struct_t fpregs; + struct iovec iov; + int rewind; + + print_user_regs_struct("get_task_regs", pid, regs); + + memset(&fpregs, 0, sizeof(fpregs)); + iov.iov_base = &fpregs.prfpreg; + iov.iov_len = sizeof(fpregs.prfpreg); + if (ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov) < 0) { + pr_perror("Couldn't get floating-point registers"); + return -1; + } + if (get_vx_regs(pid, &fpregs)) { + pr_perror("Couldn't get vector registers"); + return -1; + } + print_user_fpregs_struct("get_task_regs", pid, &fpregs); + /* Check for system call restarting. */ + if (regs->system_call) { + rewind = regs->system_call >> 16; + /* see arch/s390/kernel/signal.c: do_signal() */ + switch ((long)regs->prstatus.gprs[2]) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + regs->prstatus.gprs[2] = regs->prstatus.orig_gpr2; + rewind_psw(®s->prstatus.psw, rewind); + pr_debug("New gpr2: %016lx\n", regs->prstatus.gprs[2]); + break; + case -ERESTART_RESTARTBLOCK: + pr_warn("Will restore %d with interrupted system call\n", pid); + regs->prstatus.gprs[2] = -EINTR; + break; + } + } + /* Call save_task_regs() */ + return save(arg, regs, &fpregs); +} + +/* + * Injected syscall instruction + */ +const char code_syscall[] = { + 0x0a, 0x00, /* sc 0 */ + 0x00, 0x01, /* S390_BREAKPOINT_U16 */ + 0x00, 0x01, /* S390_BREAKPOINT_U16 */ + 0x00, 0x01, /* S390_BREAKPOINT_U16 */ +}; + +static inline void __check_code_syscall(void) +{ + BUILD_BUG_ON(sizeof(code_syscall) != BUILTIN_SYSCALL_SIZE); + BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); +} + +/* + * Issue s390 system call + */ +int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5, + unsigned long arg6) +{ + user_regs_struct_t regs = ctl->orig.regs; + int err; + + /* Load syscall number into %r1 */ + regs.prstatus.gprs[1] = (unsigned long) nr; + /* Load parameter registers %r2-%r7 */ + regs.prstatus.gprs[2] = arg1; + regs.prstatus.gprs[3] = arg2; + regs.prstatus.gprs[4] = arg3; + regs.prstatus.gprs[5] = arg4; + regs.prstatus.gprs[6] = arg5; + regs.prstatus.gprs[7] = arg6; + + err = compel_execute_syscall(ctl, ®s, (char *) code_syscall); + + /* Return code from system is in %r2 */ + if (ret) + *ret = regs.prstatus.gprs[2]; + return err; +} + +/* + * Issue s390 mmap call + */ +void *remote_mmap(struct parasite_ctl *ctl, + void *addr, size_t length, int prot, + int flags, int fd, off_t offset) +{ + void *where = (void *)ctl->ictx.syscall_ip + BUILTIN_SYSCALL_SIZE; + struct mmap_arg_struct arg_struct; + pid_t pid = ctl->rpid; + long map = 0; + int err; + + /* Setup s390 mmap data */ + arg_struct.addr = (unsigned long)addr; + arg_struct.len = length; + arg_struct.prot = prot; + arg_struct.flags = flags; + arg_struct.fd = fd; + arg_struct.offset = offset; + + /* Move args to process */ + if (ptrace_swap_area(pid, where, &arg_struct, sizeof(arg_struct))) { + pr_err("Can't inject memfd args (pid: %d)\n", pid); + return NULL; + } + + /* Do syscall */ + err = compel_syscall(ctl, __NR_mmap, &map, (unsigned long) where, + 0, 0, 0, 0, 0); + if (err < 0 || (long)map < 0) + map = 0; + + /* Restore data */ + if (ptrace_poke_area(pid, &arg_struct, where, sizeof(arg_struct))) { + pr_err("Can't restore mmap args (pid: %d)\n", pid); + if (map != 0) { + err = compel_syscall(ctl, __NR_munmap, NULL, map, + length, 0, 0, 0, 0); + map = 0; + } + } + + return (void *)map; +} + +/* + * Setup registers for parasite call + */ +void parasite_setup_regs(unsigned long new_ip, void *stack, + user_regs_struct_t *regs) +{ + regs->prstatus.psw.addr = new_ip; + if (!stack) + return; + regs->prstatus.gprs[15] = ((unsigned long) stack) - + STACK_FRAME_OVERHEAD; +} + +/* + * We don't support 24 and 31 bit mode - only 64 bit + */ +bool arch_can_dump_task(struct parasite_ctl *ctl) +{ + user_regs_struct_t regs; + pid_t pid = ctl->rpid; + char str[8]; + psw_t *psw; + + if (ptrace_get_regs(pid, ®s)) + return false; + psw = ®s.prstatus.psw; + if (psw->mask & PSW_MASK_EA) { + if (psw->mask & PSW_MASK_BA) + return true; + else + sprintf(str, "??"); + } else { + if (psw->mask & PSW_MASK_BA) + sprintf(str, "31"); + else + sprintf(str, "24"); + } + pr_err("Pid %d is %s bit: Only 64 bit tasks are supported\n", pid, str); + return false; +} + +/* + * Return current alternate signal stack + */ +int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s) +{ + long ret; + int err; + + err = compel_syscall(ctl, __NR_sigaltstack, + &ret, 0, (unsigned long)&s->uc.uc_stack, + 0, 0, 0, 0); + return err ? err : ret; +} + +/* + * Find last mapped address of current process + */ +static unsigned long max_mapped_addr(void) +{ + unsigned long addr_end, addr_max = 0; + char line[128]; + FILE *fp; + + fp = fopen("/proc/self/maps", "r"); + if (!fp) + goto out; + + /* Parse lines like: 3fff415f000-3fff4180000 rw-p 00000000 00:00 0 */ + while (fgets(line, sizeof(line), fp)) { + char *ptr; + /* First skip start address */ + strtoul(&line[0], &ptr, 16); + addr_end = strtoul(ptr + 1, NULL, 16); + addr_max = max(addr_max, addr_end); + } + fclose(fp); +out: + return addr_max; +} + +/* + * Kernel task size level + * + * We have (dynamic) 4 level page tables for 64 bit since linux 2.6.25: + * + * 5a216a2083 ("[S390] Add four level page tables for CONFIG_64BIT=y.") + * 6252d702c5 ("[S390] dynamic page tables.") + * + * The code below is already prepared for future (dynamic) 5 level page tables. + * + * Besides that there is one problematic kernel bug that has been fixed for + * linux 4.11 by the following commit: + * + * ee71d16d22 ("s390/mm: make TASK_SIZE independent from the number + * of page table levels") + * + * A 64 bit process on s390x always starts with 3 levels and upgrades to 4 + * levels for mmap(> 4 TB) and to 5 levels for mmap(> 16 EB). + * + * Unfortunately before fix ee71d16d22 for a 3 level process munmap() + * and mremap() fail for addresses > 4 TB. CRIU uses the task size, + * to unmap() all memory from a starting point to task size to get rid of + * unwanted mappings. CRIU uses mremap() to establish the final mappings + * which also fails if we want to restore mappings > 4 TB and the initial + * restore process still runs with 3 levels. + * + * To support the current CRIU design on s390 we return task size = 4 TB when + * a kernel without fix ee71d16d22 is detected. In this case we can dump at + * least processes with < 4 TB which is the most likely case anyway. + * + * For kernels with fix ee71d16d22 we are fully functional. + */ +enum kernel_ts_level { + /* Kernel with 4 level page tables without fix ee71d16d22 */ + KERNEL_TS_LEVEL_4_FIX_NO, + /* Kernel with 4 level page tables with fix ee71d16d22 */ + KERNEL_TS_LEVEL_4_FIX_YES, + /* Kernel with 4 level page tables with or without fix ee71d16d22 */ + KERNEL_TS_LEVEL_4_FIX_UNKN, + /* Kernel with 5 level page tables */ + KERNEL_TS_LEVEL_5, +}; + +/* See arch/s390/include/asm/processor.h */ +#define TASK_SIZE_LEVEL_3 0x40000000000UL /* 4 TB */ +#define TASK_SIZE_LEVEL_4 0x20000000000000UL /* 8 PB */ +#define TASK_SIZE_LEVEL_5 0xffffffffffffefffUL /* 16 EB - 0x1000 */ + +/* + * Return detected kernel version regarding task size level + * + * We use unmap() to probe the maximum possible page table level of kernel + */ +static enum kernel_ts_level get_kernel_ts_level(void) +{ + unsigned long criu_end_addr = max_mapped_addr(); + + /* Check for 5 levels */ + if (criu_end_addr > TASK_SIZE_LEVEL_4) + return KERNEL_TS_LEVEL_5; + else if (munmap((void *) TASK_SIZE_LEVEL_4, 0x1000) == 0) + return KERNEL_TS_LEVEL_5; + + if (criu_end_addr < TASK_SIZE_LEVEL_3) { + /* Check for 4 level kernel with fix */ + if (munmap((void *) TASK_SIZE_LEVEL_3, 0x1000) == 0) + return KERNEL_TS_LEVEL_4_FIX_YES; + else + return KERNEL_TS_LEVEL_4_FIX_NO; + } + /* We can't find out if kernel has the fix */ + return KERNEL_TS_LEVEL_4_FIX_UNKN; +} + +/* + * Log detected level + */ +static void pr_levels(const char *str) +{ + pr_debug("Max user page table levels (task size): %s\n", str); +} + +/* + * Return last address (+1) of biggest possible user address space for + * current kernel + */ +unsigned long compel_task_size(void) +{ + switch (get_kernel_ts_level()) { + case KERNEL_TS_LEVEL_4_FIX_NO: + pr_levels("KERNEL_TS_LEVEL_4_FIX_NO"); + return TASK_SIZE_LEVEL_3; + case KERNEL_TS_LEVEL_4_FIX_YES: + pr_levels("KERNEL_TS_LEVEL_4_FIX_YES"); + return TASK_SIZE_LEVEL_4; + case KERNEL_TS_LEVEL_4_FIX_UNKN: + pr_levels("KERNEL_TS_LEVEL_4_FIX_UNKN"); + return TASK_SIZE_LEVEL_3; + default: /* KERNEL_TS_LEVEL_5 */ + pr_levels("KERNEL_TS_LEVEL_5"); + return TASK_SIZE_LEVEL_5; + } +} + +/* + * Get task registers (overwrites weak function) + * + * We don't store floating point and vector registers here because we + * assue that compel/pie code does not change them. + * + * For verification issue: + * + * $ objdump -S criu/pie/parasite.built-in.bin.o | grep "%f" + * $ objdump -S criu/pie/restorer.built-in.bin.o | grep "%f" + */ +int ptrace_get_regs(int pid, user_regs_struct_t *regs) +{ + struct iovec iov; + int rc; + + pr_debug("ptrace_get_regs: pid=%d\n", pid); + + iov.iov_base = ®s->prstatus; + iov.iov_len = sizeof(regs->prstatus); + rc = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov); + if (rc != 0) + return rc; + + iov.iov_base = ®s->system_call; + iov.iov_len = sizeof(regs->system_call); + return ptrace(PTRACE_GETREGSET, pid, NT_S390_SYSTEM_CALL, &iov); +} + +/* + * Set task registers (overwrites weak function) + */ +int ptrace_set_regs(int pid, user_regs_struct_t *regs) +{ + uint32_t system_call = 0; + struct iovec iov; + int rc; + + pr_debug("ptrace_set_regs: pid=%d\n", pid); + + iov.iov_base = ®s->prstatus; + iov.iov_len = sizeof(regs->prstatus); + rc = ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov); + if (rc) + return rc; + + /* + * If we attached to an inferior that is sleeping in a restarting + * system call like futex_wait(), we have to reset the system_call + * to 0. Otherwise the kernel would try to finish the interrupted + * system call after PTRACE_CONT and we could not run the + * parasite code. + */ + iov.iov_base = &system_call; + iov.iov_len = sizeof(system_call); + return ptrace(PTRACE_SETREGSET, pid, NT_S390_SYSTEM_CALL, &iov); +} diff --git a/include/common/arch/s390/asm/atomic.h b/include/common/arch/s390/asm/atomic.h new file mode 100644 index 000000000..dfdba1296 --- /dev/null +++ b/include/common/arch/s390/asm/atomic.h @@ -0,0 +1,67 @@ +#ifndef __ARCH_S390_ATOMIC__ +#define __ARCH_S390_ATOMIC__ + +#include "common/arch/s390/asm/atomic_ops.h" +#include "common/compiler.h" + +#define ATOMIC_INIT(i) { (i) } + +typedef struct { + int counter; +} atomic_t; + +static inline int atomic_read(const atomic_t *v) +{ + int c; + + asm volatile( + " l %0,%1\n" + : "=d" (c) : "Q" (v->counter)); + return c; +} + +static inline void atomic_set(atomic_t *v, int i) +{ + asm volatile( + " st %1,%0\n" + : "=Q" (v->counter) : "d" (i)); +} + +static inline int atomic_add_return(int i, atomic_t *v) +{ + return __atomic_add_barrier(i, &v->counter) + i; +} + + +static inline void atomic_add(int i, atomic_t *v) +{ + __atomic_add(i, &v->counter); +} + +#define atomic_inc(_v) atomic_add(1, _v) +#define atomic_inc_return(_v) atomic_add_return(1, _v) +#define atomic_sub(_i, _v) atomic_add(-(int)(_i), _v) +#define atomic_sub_return(_i, _v) atomic_add_return(-(int)(_i), _v) +#define atomic_dec(_v) atomic_sub(1, _v) +#define atomic_dec_return(_v) atomic_sub_return(1, _v) +#define atomic_dec_and_test(_v) (atomic_sub_return(1, _v) == 0) + +#define ATOMIC_OPS(op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + __atomic_##op(i, &v->counter); \ +} \ + +ATOMIC_OPS(and) +ATOMIC_OPS(or) +ATOMIC_OPS(xor) + +#undef ATOMIC_OPS + +static inline int atomic_cmpxchg(atomic_t *v, int old, int new) +{ + return __atomic_cmpxchg(&v->counter, old, new); +} + +#endif /* __ARCH_S390_ATOMIC__ */ + diff --git a/include/common/arch/s390/asm/atomic_ops.h b/include/common/arch/s390/asm/atomic_ops.h new file mode 100644 index 000000000..ff0e1e3da --- /dev/null +++ b/include/common/arch/s390/asm/atomic_ops.h @@ -0,0 +1,74 @@ +#ifndef __ARCH_S390_ATOMIC_OPS__ +#define __ARCH_S390_ATOMIC_OPS__ + +#define __ATOMIC_OP(op_name, op_string) \ +static inline int op_name(int val, int *ptr) \ +{ \ + int old, new; \ + \ + asm volatile( \ + "0: lr %[new],%[old]\n" \ + op_string " %[new],%[val]\n" \ + " cs %[old],%[new],%[ptr]\n" \ + " jl 0b" \ + : [old] "=d" (old), [new] "=&d" (new), [ptr] "+Q" (*ptr)\ + : [val] "d" (val), "0" (*ptr) : "cc", "memory"); \ + return old; \ +} + +#define __ATOMIC_OPS(op_name, op_string) \ + __ATOMIC_OP(op_name, op_string) \ + __ATOMIC_OP(op_name##_barrier, op_string) + +__ATOMIC_OPS(__atomic_add, "ar") +__ATOMIC_OPS(__atomic_and, "nr") +__ATOMIC_OPS(__atomic_or, "or") +__ATOMIC_OPS(__atomic_xor, "xr") + +#undef __ATOMIC_OPS + +#define __ATOMIC64_OP(op_name, op_string) \ +static inline long op_name(long val, long *ptr) \ +{ \ + long old, new; \ + \ + asm volatile( \ + "0: lgr %[new],%[old]\n" \ + op_string " %[new],%[val]\n" \ + " csg %[old],%[new],%[ptr]\n" \ + " jl 0b" \ + : [old] "=d" (old), [new] "=&d" (new), [ptr] "+Q" (*ptr)\ + : [val] "d" (val), "0" (*ptr) : "cc", "memory"); \ + return old; \ +} + +#define __ATOMIC64_OPS(op_name, op_string) \ + __ATOMIC64_OP(op_name, op_string) \ + __ATOMIC64_OP(op_name##_barrier, op_string) + +__ATOMIC64_OPS(__atomic64_add, "agr") +__ATOMIC64_OPS(__atomic64_and, "ngr") +__ATOMIC64_OPS(__atomic64_or, "ogr") +__ATOMIC64_OPS(__atomic64_xor, "xgr") + +#undef __ATOMIC64_OPS + +static inline int __atomic_cmpxchg(int *ptr, int old, int new) +{ + asm volatile( + " cs %[old],%[new],%[ptr]" + : [old] "+d" (old), [ptr] "+Q" (*ptr) + : [new] "d" (new) : "cc", "memory"); + return old; +} + +static inline long __atomic64_cmpxchg(long *ptr, long old, long new) +{ + asm volatile( + " csg %[old],%[new],%[ptr]" + : [old] "+d" (old), [ptr] "+Q" (*ptr) + : [new] "d" (new) : "cc", "memory"); + return old; +} + +#endif /* __ARCH_S390_ATOMIC_OPS__ */ diff --git a/include/common/arch/s390/asm/bitops.h b/include/common/arch/s390/asm/bitops.h new file mode 100644 index 000000000..13d832380 --- /dev/null +++ b/include/common/arch/s390/asm/bitops.h @@ -0,0 +1,164 @@ +#ifndef _S390_BITOPS_H +#define _S390_BITOPS_H + +#include "common/asm/bitsperlong.h" +#include "common/compiler.h" +#include "common/arch/s390/asm/atomic_ops.h" + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG) +#define __BITOPS_WORDS(bits) (((bits) + BITS_PER_LONG - 1) / BITS_PER_LONG) + +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] + +static inline unsigned long * +__bitops_word(unsigned long nr, volatile unsigned long *ptr) +{ + unsigned long addr; + + addr = (unsigned long)ptr + ((nr ^ (nr & (BITS_PER_LONG - 1))) >> 3); + return (unsigned long *)addr; +} + +static inline unsigned char * +__bitops_byte(unsigned long nr, volatile unsigned long *ptr) +{ + return ((unsigned char *)ptr) + ((nr ^ (BITS_PER_LONG - 8)) >> 3); +} + +static inline void set_bit(unsigned long nr, volatile unsigned long *ptr) +{ + unsigned long *addr = __bitops_word(nr, ptr); + unsigned long mask; + + mask = 1UL << (nr & (BITS_PER_LONG - 1)); + __atomic64_or((long) mask, (long *) addr); +} + +static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr) +{ + unsigned long *addr = __bitops_word(nr, ptr); + unsigned long mask; + + mask = ~(1UL << (nr & (BITS_PER_LONG - 1))); + __atomic64_and((long) mask, (long *) addr); +} + +static inline void change_bit(unsigned long nr, volatile unsigned long *ptr) +{ + unsigned long *addr = __bitops_word(nr, ptr); + unsigned long mask; + + mask = 1UL << (nr & (BITS_PER_LONG - 1)); + __atomic64_xor((long) mask, (long *) addr); +} + +static inline int +test_and_set_bit(unsigned long nr, volatile unsigned long *ptr) +{ + unsigned long *addr = __bitops_word(nr, ptr); + unsigned long old, mask; + + mask = 1UL << (nr & (BITS_PER_LONG - 1)); + old = __atomic64_or_barrier((long) mask, (long *) addr); + return (old & mask) != 0; +} + +static inline int test_bit(unsigned long nr, const volatile unsigned long *ptr) +{ + const volatile unsigned char *addr; + + addr = ((const volatile unsigned char *)ptr); + addr += (nr ^ (BITS_PER_LONG - 8)) >> 3; + return (*addr >> (nr & 7)) & 1; +} + +static inline unsigned char __flogr(unsigned long word) +{ + if (__builtin_constant_p(word)) { + unsigned long bit = 0; + + if (!word) + return 64; + if (!(word & 0xffffffff00000000UL)) { + word <<= 32; + bit += 32; + } + if (!(word & 0xffff000000000000UL)) { + word <<= 16; + bit += 16; + } + if (!(word & 0xff00000000000000UL)) { + word <<= 8; + bit += 8; + } + if (!(word & 0xf000000000000000UL)) { + word <<= 4; + bit += 4; + } + if (!(word & 0xc000000000000000UL)) { + word <<= 2; + bit += 2; + } + if (!(word & 0x8000000000000000UL)) { + word <<= 1; + bit += 1; + } + return bit; + } else { + register unsigned long bit asm("4") = word; + register unsigned long out asm("5"); + + asm volatile( + " flogr %[bit],%[bit]\n" + : [bit] "+d" (bit), [out] "=d" (out) : : "cc"); + return bit; + } +} + +static inline unsigned long __ffs(unsigned long word) +{ + return __flogr(-word & word) ^ (BITS_PER_LONG - 1); +} + +#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) + +static inline unsigned long _find_next_bit(const unsigned long *addr, + unsigned long nbits, unsigned long start, + unsigned long invert) +{ + unsigned long tmp; + + if (!nbits || start >= nbits) + return nbits; + + tmp = addr[start / BITS_PER_LONG] ^ invert; + + tmp &= BITMAP_FIRST_WORD_MASK(start); + start = round_down(start, BITS_PER_LONG); + + while (!tmp) { + start += BITS_PER_LONG; + if (start >= nbits) + return nbits; + + tmp = addr[start / BITS_PER_LONG] ^ invert; + } + + return min(start + __ffs(tmp), nbits); +} + +static inline unsigned long find_next_bit(const unsigned long *addr, + unsigned long size, + unsigned long offset) +{ + return _find_next_bit(addr, size, offset, 0UL); +} + +#define for_each_bit(i, bitmask) \ + for (i = find_next_bit(bitmask, sizeof(bitmask), 0); \ + i < sizeof(bitmask); \ + i = find_next_bit(bitmask, sizeof(bitmask), i + 1)) + +#endif /* _S390_BITOPS_H */ diff --git a/include/common/arch/s390/asm/bitsperlong.h b/include/common/arch/s390/asm/bitsperlong.h new file mode 100644 index 000000000..d95727d19 --- /dev/null +++ b/include/common/arch/s390/asm/bitsperlong.h @@ -0,0 +1,6 @@ +#ifndef __CR_BITSPERLONG_H__ +#define __CR_BITSPERLONG_H__ + +#define BITS_PER_LONG 64 + +#endif /* __CR_BITSPERLONG_H__ */ diff --git a/include/common/arch/s390/asm/linkage.h b/include/common/arch/s390/asm/linkage.h new file mode 100644 index 000000000..99895ced5 --- /dev/null +++ b/include/common/arch/s390/asm/linkage.h @@ -0,0 +1,22 @@ +#ifndef __ASM_LINKAGE_H +#define __ASM_LINKAGE_H + +#ifdef __ASSEMBLY__ + +#define __ALIGN .align 4, 0x07 + +#define GLOBAL(name) \ + .globl name; \ + name: + +#define ENTRY(name) \ + .globl name; \ + .type name, @function; \ + __ALIGN; \ + name: + +#define END(name) \ + .size name, . - name + +#endif /* __ASSEMBLY__ */ +#endif diff --git a/include/common/arch/s390/asm/page.h b/include/common/arch/s390/asm/page.h new file mode 100644 index 000000000..8e8c6491b --- /dev/null +++ b/include/common/arch/s390/asm/page.h @@ -0,0 +1,19 @@ +#ifndef __CR_ASM_PAGE_H__ +#define __CR_ASM_PAGE_H__ + +#ifndef PAGE_SHIFT +#define PAGE_SHIFT 12 +#endif + +#ifndef PAGE_SIZE +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#endif + +#ifndef PAGE_MASK +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#endif + +#define PAGE_PFN(addr) ((addr) / PAGE_SIZE) +#define page_size() PAGE_SIZE + +#endif /* __CR_ASM_PAGE_H__ */ From 8b23923640caa575874dfff8a5d05ca60617b42f Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 30 Jun 2017 20:31:37 +0200 Subject: [PATCH 0683/4375] s390:compel: Enable s390 in compel/ Add s390 parts to common code files. Patch history ------------- v2->v3: * Add: s390: Consolidate -msoft-float into Makefile.compel Reviewed-by: Alice Frosi Signed-off-by: Michael Holzheu Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile.compel | 8 ++++++++ compel/.gitignore | 1 + compel/src/lib/handle-elf.c | 25 +++++++++++++++++++++++++ compel/src/main.c | 3 +++ 4 files changed, 37 insertions(+) diff --git a/Makefile.compel b/Makefile.compel index 1ef7f8cb2..9b40079b3 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -70,3 +70,11 @@ compel/$(LIBCOMPEL_SO): compel/$(LIBCOMPEL_A) compel-install-targets += compel/$(LIBCOMPEL_SO) compel-install-targets += compel/compel compel-install-targets += $(compel-plugins) + +# We assume that compel code does not change floating point registers. +# On s390 gcc uses fprs to cache gprs. Therefore disable floating point +# with -msoft-float. +ifeq ($(ARCH),s390) +CFLAGS += -msoft-float +HOSTCFLAGS += -msoft-float +endif diff --git a/compel/.gitignore b/compel/.gitignore index 5b6886325..e959dc5ef 100644 --- a/compel/.gitignore +++ b/compel/.gitignore @@ -1,6 +1,7 @@ arch/x86/plugins/std/sys-exec-tbl-64.c arch/x86/plugins/std/syscalls-64.S arch/arm/plugins/std/syscalls/syscalls.S +arch/s390/plugins/std/syscalls/syscalls.S include/version.h plugins/include/uapi/std/asm/syscall-types.h plugins/include/uapi/std/syscall-64.h diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index 41633e99c..bf94d93b6 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -542,6 +542,31 @@ int __handle_elf(void *mem, size_t size) break; #endif +#ifdef ELF_S390 + /* + * See also arch/s390/kernel/module.c/apply_rela(): + * A PLT reads the GOT (global offest table). We can handle it like + * R_390_PC32DBL because we have linked statically. + */ + case R_390_PLT32DBL: /* PC relative on a PLT (predure link table) */ + pr_debug("\t\t\t\tR_390_PLT32DBL at 0x%-4lx val 0x%x\n", place, value32 + addend32); + *((int32_t *)where) = (value64 + addend64 - place) >> 1; + break; + case R_390_PC32DBL: /* PC relative on a symbol */ + pr_debug("\t\t\t\tR_390_PC32DBL at 0x%-4lx val 0x%x\n", place, value32 + addend32); + *((int32_t *)where) = (value64 + addend64 - place) >> 1; + break; + case R_390_64: /* 64 bit absolute address */ + pr_debug("\t\t\t\tR_390_64 at 0x%-4lx val 0x%lx\n", place, (long)value64); + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_LONG, " + ".addend = %-8ld, .value = 0x%-16lx, }, /* R_390_64 */\n", + (unsigned int)place, (long)addend64, (long)value64); + break; + case R_390_PC64: /* 64 bit relative address */ + *((int64_t *)where) = value64 + addend64 - place; + pr_debug("\t\t\t\tR_390_PC64 at 0x%-4lx val 0x%lx\n", place, (long)value64); + break; +#endif default: pr_err("Unsupported relocation of type %lu\n", (unsigned long)ELF_R_TYPE(r->rel.r_info)); diff --git a/compel/src/main.c b/compel/src/main.c index 1171478cb..86d22abd3 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -52,6 +52,9 @@ static const flags_t flags = { #elif defined CONFIG_PPC64 .arch = "ppc64", .cflags = COMPEL_CFLAGS_PIE, +#elif defined CONFIG_S390 + .arch = "s390", + .cflags = COMPEL_CFLAGS_PIE, #else #error "CONFIG_ not defined, or unsupported ARCH" #endif From 343b5f53ef071a225aab8fa5e8c7d305b5dacd62 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 30 Jun 2017 20:31:38 +0200 Subject: [PATCH 0684/4375] s390:proto: Add s390 to protocol buffer files Reviewed-by: Alice Frosi Signed-off-by: Michael Holzheu Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- images/Makefile | 1 + images/core-s390.proto | 39 +++++++++++++++++++++++++++++++++++++++ images/core.proto | 3 +++ images/cpuinfo.proto | 5 +++++ 4 files changed, 48 insertions(+) create mode 100644 images/core-s390.proto diff --git a/images/Makefile b/images/Makefile index c46eb2b87..5f0ed6488 100644 --- a/images/Makefile +++ b/images/Makefile @@ -4,6 +4,7 @@ proto-obj-y += core-x86.o proto-obj-y += core-arm.o proto-obj-y += core-aarch64.o proto-obj-y += core-ppc64.o +proto-obj-y += core-s390.o proto-obj-y += cpuinfo.o proto-obj-y += inventory.o proto-obj-y += fdinfo.o diff --git a/images/core-s390.proto b/images/core-s390.proto new file mode 100644 index 000000000..78d3e1447 --- /dev/null +++ b/images/core-s390.proto @@ -0,0 +1,39 @@ +syntax = "proto2"; + +import "opts.proto"; + +message user_s390_regs_entry { + required uint64 psw_mask = 1; + required uint64 psw_addr = 2; + repeated uint64 gprs = 3; + repeated uint32 acrs = 4; + required uint64 orig_gpr2 = 5; + required uint32 system_call = 6; +} + +message user_s390_vxrs_low_entry { + repeated uint64 regs = 1; +} + +/* + * The vxrs_high registers have 128 bit: + * + * vxrs_high_0 = regs[0] << 64 | regs[1]; + * vxrs_high_1 = regs[2] << 64 | regs[3]; + */ +message user_s390_vxrs_high_entry { + repeated uint64 regs = 1; +} + +message user_s390_fpregs_entry { + required uint32 fpc = 1; + repeated uint64 fprs = 2; +} + +message thread_info_s390 { + required uint64 clear_tid_addr = 1[(criu).hex = true]; + required user_s390_regs_entry gpregs = 2[(criu).hex = true]; + required user_s390_fpregs_entry fpregs = 3[(criu).hex = true]; + optional user_s390_vxrs_low_entry vxrs_low = 4[(criu).hex = true]; + optional user_s390_vxrs_high_entry vxrs_high = 5[(criu).hex = true]; +} diff --git a/images/core.proto b/images/core.proto index 1f13d4484..983998392 100644 --- a/images/core.proto +++ b/images/core.proto @@ -4,6 +4,7 @@ import "core-x86.proto"; import "core-arm.proto"; import "core-aarch64.proto"; import "core-ppc64.proto"; +import "core-s390.proto"; import "rlimit.proto"; import "timer.proto"; @@ -94,6 +95,7 @@ message core_entry { ARM = 2; AARCH64 = 3; PPC64 = 4; + S390 = 5; } required march mtype = 1; @@ -101,6 +103,7 @@ message core_entry { optional thread_info_arm ti_arm = 6; optional thread_info_aarch64 ti_aarch64 = 8; optional thread_info_ppc64 ti_ppc64 = 9; + optional thread_info_s390 ti_s390 = 10; optional task_core_entry tc = 3; optional task_kobj_ids_entry ids = 4; diff --git a/images/cpuinfo.proto b/images/cpuinfo.proto index 9fa34fbcb..a8cb8de34 100644 --- a/images/cpuinfo.proto +++ b/images/cpuinfo.proto @@ -27,6 +27,10 @@ message cpuinfo_ppc64_entry { repeated uint64 hwcap = 2; } +message cpuinfo_s390_entry { + repeated uint64 hwcap = 2; +} + message cpuinfo_entry { /* * Usually on SMP system there should be same CPUs @@ -35,4 +39,5 @@ message cpuinfo_entry { */ repeated cpuinfo_x86_entry x86_entry = 1; repeated cpuinfo_ppc64_entry ppc64_entry = 2; + repeated cpuinfo_s390_entry s390_entry = 3; } From dc927a20c54a9048cdcbd297e94300c9d49f38a4 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 30 Jun 2017 20:31:39 +0200 Subject: [PATCH 0685/4375] s390:criu/arch/s390: Add s390 parts to criu Reviewed-by: Alice Frosi Signed-off-by: Michael Holzheu Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/s390/Makefile | 10 + criu/arch/s390/cpu.c | 158 ++++++++ criu/arch/s390/crtools.c | 341 ++++++++++++++++++ criu/arch/s390/include/asm/dump.h | 12 + criu/arch/s390/include/asm/int.h | 6 + criu/arch/s390/include/asm/parasite-syscall.h | 6 + criu/arch/s390/include/asm/parasite.h | 7 + criu/arch/s390/include/asm/restore.h | 29 ++ criu/arch/s390/include/asm/restorer.h | 65 ++++ criu/arch/s390/include/asm/types.h | 37 ++ criu/arch/s390/include/asm/vdso.h | 23 ++ criu/arch/s390/restorer.c | 37 ++ criu/arch/s390/sigframe.c | 20 + criu/arch/s390/vdso-pie.c | 65 ++++ 14 files changed, 816 insertions(+) create mode 100644 criu/arch/s390/Makefile create mode 100644 criu/arch/s390/cpu.c create mode 100644 criu/arch/s390/crtools.c create mode 100644 criu/arch/s390/include/asm/dump.h create mode 100644 criu/arch/s390/include/asm/int.h create mode 100644 criu/arch/s390/include/asm/parasite-syscall.h create mode 100644 criu/arch/s390/include/asm/parasite.h create mode 100644 criu/arch/s390/include/asm/restore.h create mode 100644 criu/arch/s390/include/asm/restorer.h create mode 100644 criu/arch/s390/include/asm/types.h create mode 100644 criu/arch/s390/include/asm/vdso.h create mode 100644 criu/arch/s390/restorer.c create mode 100644 criu/arch/s390/sigframe.c create mode 100644 criu/arch/s390/vdso-pie.c diff --git a/criu/arch/s390/Makefile b/criu/arch/s390/Makefile new file mode 100644 index 000000000..ff0a71207 --- /dev/null +++ b/criu/arch/s390/Makefile @@ -0,0 +1,10 @@ +builtin-name := crtools.built-in.o + +ccflags-y += -iquote $(obj)/include +ccflags-y += -iquote criu/include -iquote include +ccflags-y += $(COMPEL_UAPI_INCLUDES) +ldflags-y += -r + +obj-y += cpu.o +obj-y += crtools.o +obj-y += sigframe.o diff --git a/criu/arch/s390/cpu.c b/criu/arch/s390/cpu.c new file mode 100644 index 000000000..0c32de5ab --- /dev/null +++ b/criu/arch/s390/cpu.c @@ -0,0 +1,158 @@ +#undef LOG_PREFIX +#define LOG_PREFIX "cpu: " + +#include +#include + +#include "asm/types.h" + +#include "cr_options.h" +#include "image.h" +#include "util.h" +#include "log.h" +#include "cpu.h" + +#include "protobuf.h" +#include "images/cpuinfo.pb-c.h" + +static compel_cpuinfo_t rt_cpuinfo; + +static const char *hwcap_str1[64] = { + "HWCAP_S390_ESAN3", + "HWCAP_S390_ZARCH", + "HWCAP_S390_STFLE", + "HWCAP_S390_MSA", + "HWCAP_S390_LDISP", + "HWCAP_S390_EIMM", + "HWCAP_S390_DFP", + "HWCAP_S390_HPAGE", + "HWCAP_S390_ETF3EH", + "HWCAP_S390_HIGH_GPRS", + "HWCAP_S390_TE", + "HWCAP_S390_VXRS", + "HWCAP_S390_VXRS_BCD", + "HWCAP_S390_VXRS_EXT", +}; +static const char *hwcap_str2[64] = { }; + +static const char **hwcap_str[2] = { hwcap_str1, hwcap_str2 }; + +static void print_hwcaps(const char *msg, unsigned long hwcap[2]) +{ + int nr, cap; + + pr_debug("%s: Capabilities: %016lx %016lx\n", msg, hwcap[0], hwcap[1]); + for (nr = 0; nr < 2; nr++) { + for (cap = 0; cap < 64; cap++) { + if (!(hwcap[nr] & (1 << cap))) + continue; + if (hwcap_str[nr][cap]) + pr_debug("%s\n", hwcap_str[nr][cap]); + else + pr_debug("Capability %d/0x%x\n", nr, 1 << cap); + } + } +} + +int cpu_init(void) +{ + int ret; + + ret = compel_cpuid(&rt_cpuinfo); + print_hwcaps("Host (init)", rt_cpuinfo.hwcap); + return ret; +} + +int cpu_dump_cpuinfo(void) +{ + CpuinfoS390Entry cpu_s390_info = CPUINFO_S390_ENTRY__INIT; + CpuinfoS390Entry *cpu_s390_info_ptr = &cpu_s390_info; + CpuinfoEntry cpu_info = CPUINFO_ENTRY__INIT; + struct cr_img *img; + int ret = -1; + + img = open_image(CR_FD_CPUINFO, O_DUMP); + if (!img) + return -1; + + cpu_info.s390_entry = &cpu_s390_info_ptr; + cpu_info.n_s390_entry = 1; + + cpu_s390_info.n_hwcap = 2; + cpu_s390_info.hwcap = rt_cpuinfo.hwcap; + + ret = pb_write_one(img, &cpu_info, PB_CPUINFO); + + close_image(img); + return ret; +} + +int cpu_validate_cpuinfo(void) +{ + CpuinfoS390Entry *cpu_s390_entry; + CpuinfoEntry *cpu_info; + struct cr_img *img; + int cap, nr, ret; + + img = open_image(CR_FD_CPUINFO, O_RSTR); + if (!img) + return -1; + + ret = 0; + if (pb_read_one(img, &cpu_info, PB_CPUINFO) < 0) + goto error; + + if (cpu_info->n_s390_entry != 1) { + pr_err("No S390 related entry in image"); + goto error; + } + cpu_s390_entry = cpu_info->s390_entry[0]; + + if (cpu_s390_entry->n_hwcap != 2) { + pr_err("Hardware capabilities information missing\n"); + ret = -1; + goto error; + } + + print_hwcaps("Host", rt_cpuinfo.hwcap); + print_hwcaps("Image", cpu_s390_entry->hwcap); + + for (nr = 0; nr < 2; nr++) { + for (cap = 0; cap < 64; cap++) { + if (!(cpu_s390_entry->hwcap[nr] & (1 << cap))) + continue; + if (rt_cpuinfo.hwcap[nr] & (1 << cap)) + continue; + if (hwcap_str[nr][cap]) + pr_err("CPU Feature %s not supported on host\n", + hwcap_str[nr][cap]); + else + pr_err("CPU Feature %d/%x not supported on host\n", + nr, 1 << cap); + ret = -1; + } + } + if (ret == -1) + pr_err("See also: /usr/include/bits/hwcap.h\n"); +error: + close_image(img); + return ret; +} + +int cpuinfo_dump(void) +{ + if (cpu_init()) + return -1; + if (cpu_dump_cpuinfo()) + return -1; + return 0; +} + +int cpuinfo_check(void) +{ + if (cpu_init()) + return 1; + if (cpu_validate_cpuinfo()) + return 1; + return 0; +} diff --git a/criu/arch/s390/crtools.c b/criu/arch/s390/crtools.c new file mode 100644 index 000000000..4bd21ec97 --- /dev/null +++ b/criu/arch/s390/crtools.c @@ -0,0 +1,341 @@ +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include +#include "asm/restorer.h" +#include "asm/dump.h" + +#include "cr_options.h" +#include "common/compiler.h" +#include +#include "parasite-syscall.h" +#include "log.h" +#include "util.h" +#include "cpu.h" +#include + +#include "protobuf.h" +#include "images/core.pb-c.h" +#include "images/creds.pb-c.h" + +/* + * Print general purpose and access registers + */ +static void print_core_gpregs(const char *msg, UserS390RegsEntry *gpregs) +{ + int i; + + pr_debug("%s: General purpose registers\n", msg); + pr_debug(" psw %016lx %016lx\n", + gpregs->psw_mask, gpregs->psw_addr); + pr_debug(" orig_gpr2 %016lx\n", gpregs->orig_gpr2); + for (i = 0; i < 16; i++) + pr_debug(" g%02d %016lx\n", i, gpregs->gprs[i]); + for (i = 0; i < 16; i++) + pr_debug(" a%02d %08x\n", i, gpregs->acrs[i]); +} + +/* + * Print floating point and vector registers + */ +static void print_core_fp_regs(const char *msg, CoreEntry *core) +{ + UserS390VxrsHighEntry *vxrs_high; + UserS390VxrsLowEntry *vxrs_low; + UserS390FpregsEntry *fpregs; + int i; + + vxrs_high = CORE_THREAD_ARCH_INFO(core)->vxrs_high; + vxrs_low = CORE_THREAD_ARCH_INFO(core)->vxrs_low; + fpregs = CORE_THREAD_ARCH_INFO(core)->fpregs; + + pr_debug("%s: Floating point registers\n", msg); + pr_debug(" fpc %08x\n", fpregs->fpc); + for (i = 0; i < 16; i++) + pr_debug(" f%02d %016lx\n", i, fpregs->fprs[i]); + if (!vxrs_low) { + pr_debug(" No VXRS\n"); + return; + } + for (i = 0; i < 16; i++) + pr_debug(" vx_low%02d %016lx\n", i, vxrs_low->regs[i]); + for (i = 0; i < 32; i += 2) + pr_debug(" vx_high%02d %016lx %016lx\n", i / 2, + vxrs_high->regs[i], vxrs_high->regs[i + 1]); +} + +/* + * Allocate VxrsLow registers + */ +static UserS390VxrsLowEntry *allocate_vxrs_low_regs(void) +{ + UserS390VxrsLowEntry *vxrs_low; + + vxrs_low = xmalloc(sizeof(*vxrs_low)); + if (!vxrs_low) + return NULL; + user_s390_vxrs_low_entry__init(vxrs_low); + + vxrs_low->n_regs = 16; + vxrs_low->regs = xzalloc(16 * sizeof(uint64_t)); + if (!vxrs_low->regs) + goto fail_free_vxrs_low; + return vxrs_low; + +fail_free_vxrs_low: + xfree(vxrs_low); + return NULL; +} + +/* + * Free VxrsLow registers + */ +static void free_vxrs_low_regs(UserS390VxrsLowEntry *vxrs_low) +{ + if (vxrs_low) { + xfree(vxrs_low->regs); + xfree(vxrs_low); + } +} + +/* + * Allocate VxrsHigh registers + */ +static UserS390VxrsHighEntry *allocate_vxrs_high_regs(void) +{ + UserS390VxrsHighEntry *vxrs_high; + + vxrs_high = xmalloc(sizeof(*vxrs_high)); + if (!vxrs_high) + return NULL; + user_s390_vxrs_high_entry__init(vxrs_high); + + vxrs_high->n_regs = 32; + vxrs_high->regs = xzalloc(32 * sizeof(uint64_t)); + if (!vxrs_high->regs) + goto fail_free_vxrs_high; + return vxrs_high; + +fail_free_vxrs_high: + xfree(vxrs_high); + return NULL; +} + +/* + * Free VxrsHigh registers + */ +static void free_vxrs_high_regs(UserS390VxrsHighEntry *vxrs_high) +{ + if (vxrs_high) { + xfree(vxrs_high->regs); + xfree(vxrs_high); + } +} + +/* + * Copy internal structures into Google Protocol Buffers + */ +int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f) +{ + UserS390VxrsHighEntry *vxrs_high; + UserS390VxrsLowEntry *vxrs_low; + UserS390FpregsEntry *fpregs; + UserS390RegsEntry *gpregs; + CoreEntry *core = arg; + + gpregs = CORE_THREAD_ARCH_INFO(core)->gpregs; + fpregs = CORE_THREAD_ARCH_INFO(core)->fpregs; + + /* Vector registers */ + if (f->flags & USER_FPREGS_VXRS) { + vxrs_low = allocate_vxrs_low_regs(); + if (!vxrs_low) + return -1; + vxrs_high = allocate_vxrs_high_regs(); + if (!vxrs_high) { + free_vxrs_low_regs(vxrs_low); + return -1; + } + memcpy(vxrs_low->regs, &f->vxrs_low, sizeof(f->vxrs_low)); + memcpy(vxrs_high->regs, &f->vxrs_high, sizeof(f->vxrs_high)); + CORE_THREAD_ARCH_INFO(core)->vxrs_low = vxrs_low; + CORE_THREAD_ARCH_INFO(core)->vxrs_high = vxrs_high; + } + /* General purpose registers */ + memcpy(gpregs->gprs, u->prstatus.gprs, sizeof(u->prstatus.gprs)); + gpregs->psw_mask = u->prstatus.psw.mask; + gpregs->psw_addr = u->prstatus.psw.addr; + /* Access registers */ + memcpy(gpregs->acrs, u->prstatus.acrs, sizeof(u->prstatus.acrs)); + /* System call */ + gpregs->system_call = u->system_call; + /* Floating point registers */ + fpregs->fpc = f->prfpreg.fpc; + memcpy(fpregs->fprs, f->prfpreg.fprs, sizeof(f->prfpreg.fprs)); + return 0; +} + +/* + * Copy general and access registers to signal frame + */ +int restore_gpregs(struct rt_sigframe *f, UserS390RegsEntry *src) +{ + _sigregs *dst = &f->uc.uc_mcontext; + + dst->regs.psw.mask = src->psw_mask; + dst->regs.psw.addr = src->psw_addr; + memcpy(dst->regs.gprs, src->gprs, sizeof(dst->regs.gprs)); + memcpy(dst->regs.acrs, src->acrs, sizeof(dst->regs.acrs)); + + print_core_gpregs("restore_gpregs_regs", src); + return 0; +} + +/* + * Copy floating point and vector registers to mcontext + */ +int restore_fpu(struct rt_sigframe *f, CoreEntry *core) +{ + UserS390VxrsHighEntry *vxrs_high; + UserS390VxrsLowEntry *vxrs_low; + UserS390FpregsEntry *fpregs; + _sigregs *dst = &f->uc.uc_mcontext; + _sigregs_ext *dst_ext = &f->uc.uc_mcontext_ext; + + fpregs = CORE_THREAD_ARCH_INFO(core)->fpregs; + vxrs_high = CORE_THREAD_ARCH_INFO(core)->vxrs_high; + vxrs_low = CORE_THREAD_ARCH_INFO(core)->vxrs_low; + + dst->fpregs.fpc = fpregs->fpc; + memcpy(dst->fpregs.fprs, fpregs->fprs, sizeof(dst->fpregs.fprs)); + if (vxrs_low) { + memcpy(&dst_ext->vxrs_low, vxrs_low->regs, + sizeof(dst_ext->vxrs_low)); + memcpy(&dst_ext->vxrs_high, vxrs_high->regs, + sizeof(dst_ext->vxrs_high)); + } + print_core_fp_regs("restore_fp_regs", core); + return 0; +} + +/* + * Allocate floating point registers + */ +static UserS390FpregsEntry *allocate_fp_regs(void) +{ + UserS390FpregsEntry *fpregs; + + fpregs = xmalloc(sizeof(*fpregs)); + if (!fpregs) + return NULL; + user_s390_fpregs_entry__init(fpregs); + + fpregs->n_fprs = 16; + fpregs->fprs = xzalloc(16 * sizeof(uint64_t)); + if (!fpregs->fprs) + goto fail_free_fpregs; + return fpregs; + +fail_free_fpregs: + xfree(fpregs); + return NULL; +} + +/* + * Free floating point registers + */ +static void free_fp_regs(UserS390FpregsEntry *fpregs) +{ + xfree(fpregs->fprs); + xfree(fpregs); +} + +/* + * Allocate general purpose and access registers + */ +static UserS390RegsEntry *allocate_gp_regs(void) +{ + UserS390RegsEntry *gpregs; + + gpregs = xmalloc(sizeof(*gpregs)); + if (!gpregs) + return NULL; + user_s390_regs_entry__init(gpregs); + + gpregs->n_gprs = 16; + gpregs->gprs = xzalloc(16 * sizeof(uint64_t)); + if (!gpregs->gprs) + goto fail_free_gpregs; + + gpregs->n_acrs = 16; + gpregs->acrs = xzalloc(16 * sizeof(uint32_t)); + if (!gpregs->acrs) + goto fail_free_gprs; + return gpregs; + +fail_free_gprs: + xfree(gpregs->gprs); +fail_free_gpregs: + xfree(gpregs); + return NULL; +} + +/* + * Free general purpose and access registers + */ +static void free_gp_regs(UserS390RegsEntry *gpregs) +{ + xfree(gpregs->gprs); + xfree(gpregs->acrs); + xfree(gpregs); +} + +/* + * Allocate thread info + */ +int arch_alloc_thread_info(CoreEntry *core) +{ + ThreadInfoS390 *ti_s390; + + ti_s390 = xmalloc(sizeof(*ti_s390)); + if (!ti_s390) + return -1; + + thread_info_s390__init(ti_s390); + + ti_s390->gpregs = allocate_gp_regs(); + if (!ti_s390->gpregs) + goto fail_free_ti_s390; + ti_s390->fpregs = allocate_fp_regs(); + if (!ti_s390->fpregs) + goto fail_free_gp_regs; + + CORE_THREAD_ARCH_INFO(core) = ti_s390; + return 0; + +fail_free_gp_regs: + free_gp_regs(ti_s390->gpregs); +fail_free_ti_s390: + xfree(ti_s390); + return -1; +} + +/* + * Free thread info + */ +void arch_free_thread_info(CoreEntry *core) +{ + if (!CORE_THREAD_ARCH_INFO(core)) + return; + free_gp_regs(CORE_THREAD_ARCH_INFO(core)->gpregs); + free_fp_regs(CORE_THREAD_ARCH_INFO(core)->fpregs); + free_vxrs_low_regs(CORE_THREAD_ARCH_INFO(core)->vxrs_low); + free_vxrs_high_regs(CORE_THREAD_ARCH_INFO(core)->vxrs_high); + xfree(CORE_THREAD_ARCH_INFO(core)); + CORE_THREAD_ARCH_INFO(core) = NULL; +} diff --git a/criu/arch/s390/include/asm/dump.h b/criu/arch/s390/include/asm/dump.h new file mode 100644 index 000000000..53aaac9c4 --- /dev/null +++ b/criu/arch/s390/include/asm/dump.h @@ -0,0 +1,12 @@ +#ifndef __CR_ASM_DUMP_H__ +#define __CR_ASM_DUMP_H__ + +int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f); +int arch_alloc_thread_info(CoreEntry *core); +void arch_free_thread_info(CoreEntry *core); + +static inline void core_put_tls(CoreEntry *core, tls_t tls) { } + +#define get_task_futex_robust_list_compat(pid, info) -1 + +#endif diff --git a/criu/arch/s390/include/asm/int.h b/criu/arch/s390/include/asm/int.h new file mode 100644 index 000000000..642804e9b --- /dev/null +++ b/criu/arch/s390/include/asm/int.h @@ -0,0 +1,6 @@ +#ifndef __CR_ASM_INT_H__ +#define __CR_ASM_INT_H__ + +#include "asm-generic/int.h" + +#endif /* __CR_ASM_INT_H__ */ diff --git a/criu/arch/s390/include/asm/parasite-syscall.h b/criu/arch/s390/include/asm/parasite-syscall.h new file mode 100644 index 000000000..6008c3792 --- /dev/null +++ b/criu/arch/s390/include/asm/parasite-syscall.h @@ -0,0 +1,6 @@ +#ifndef __CR_ASM_PARASITE_SYSCALL_H__ +#define __CR_ASM_PARASITE_SYSCALL_H__ + +struct parasite_ctl; + +#endif diff --git a/criu/arch/s390/include/asm/parasite.h b/criu/arch/s390/include/asm/parasite.h new file mode 100644 index 000000000..0b0268936 --- /dev/null +++ b/criu/arch/s390/include/asm/parasite.h @@ -0,0 +1,7 @@ +#ifndef __ASM_PARASITE_H__ +#define __ASM_PARASITE_H__ + +/* TLS is accessed through %a01, which is already processed */ +static inline void arch_get_tls(tls_t *ptls) { (void)ptls; } + +#endif diff --git a/criu/arch/s390/include/asm/restore.h b/criu/arch/s390/include/asm/restore.h new file mode 100644 index 000000000..96358ffc3 --- /dev/null +++ b/criu/arch/s390/include/asm/restore.h @@ -0,0 +1,29 @@ +#ifndef __CR_ASM_RESTORE_H__ +#define __CR_ASM_RESTORE_H__ + +#include "asm/restorer.h" + +#include "images/core.pb-c.h" + +/* + * Load stack to %r15, return address in %r14 and argument 1 into %r2 + */ +#define JUMP_TO_RESTORER_BLOB(new_sp, restore_task_exec_start, \ + task_args) \ + asm volatile( \ + "lgr %%r15,%0\n" \ + "lgr %%r14,%1\n" \ + "lgr %%r2,%2\n" \ + "basr %%r14,%%r14\n" \ + : \ + : "d" (new_sp), \ + "d"((unsigned long)restore_task_exec_start), \ + "d" (task_args) \ + : "2", "14", "15", "memory") + +/* There is nothing to do since TLS is accessed through %a01 */ +#define core_get_tls(pcore, ptls) + +int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core); + +#endif diff --git a/criu/arch/s390/include/asm/restorer.h b/criu/arch/s390/include/asm/restorer.h new file mode 100644 index 000000000..0fd23cff1 --- /dev/null +++ b/criu/arch/s390/include/asm/restorer.h @@ -0,0 +1,65 @@ +#ifndef __CR_ASM_RESTORER_H__ +#define __CR_ASM_RESTORER_H__ + +#include +#include + +#include "asm/types.h" + +#include "sigframe.h" + +/* + * Clone trampoline - see glibc sysdeps/unix/sysv/linux/s390/s390-64/clone.S + */ +#define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \ + thread_args, clone_restore_fn) \ + asm volatile( \ + "lgr %%r0,%6\n" /* Save thread_args in %r0 */ \ + "lgr %%r1,%5\n" /* Save clone_restore_fn in %r1 */ \ + "lgr %%r2,%2\n" /* Parm 1: new_sp (child stack) */ \ + "lgr %%r3,%1\n" /* Parm 2: clone_flags */ \ + "lgr %%r4,%3\n" /* Parm 3: &parent_tid */ \ + "lgr %%r5,%4\n" /* Parm 4: &thread_args[i].pid */ \ + "lghi %%r6,0\n" /* Parm 5: tls = 0 */ \ + "svc "__stringify(__NR_clone)"\n" \ + "ltgr %0,%%r2\n" /* Set and check "ret" */ \ + "jnz 0f\n" /* ret != 0: Continue caller */ \ + "lgr %%r2,%%r0\n" /* Parm 1: &thread_args */ \ + "aghi %%r15,-160\n" /* Prepare stack frame */ \ + "xc 0(8,%%r15),0(%%r15)\n" \ + "basr %%r14,%%r1\n" /* Jump to clone_restore_fn() */ \ + "j .+2\n" /* BUG(): Force PGM check */ \ +"0:\n" /* Continue caller */ \ + : "=d"(ret) \ + : "d"(clone_flags), \ + "a"(new_sp), \ + "d"(&parent_tid), \ + "d"(&thread_args[i].pid), \ + "d"(clone_restore_fn), \ + "d"(&thread_args[i]) \ + : "0", "1", "2", "3", "4", "5", "6", "cc", "memory") + +#define kdat_compatible_cr() 0 + +int restore_gpregs(struct rt_sigframe *f, UserS390RegsEntry *r); +int restore_nonsigframe_gpregs(UserS390RegsEntry *r); + +unsigned long sys_shmat(int shmid, const void *shmaddr, int shmflg); +unsigned long sys_mmap(void *addr, unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, + unsigned long offset); + +static inline void restore_tls(tls_t *ptls) { (void)ptls; } +static inline void *alloc_compat_syscall_stack(void) { return NULL; } +static inline void free_compat_syscall_stack(void *stack32) { } +static inline int arch_compat_rt_sigaction(void *stack, int sig, void *act) +{ + return -1; +} + +static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) +{ + return -1; +} + +#endif /*__CR_ASM_RESTORER_H__*/ diff --git a/criu/arch/s390/include/asm/types.h b/criu/arch/s390/include/asm/types.h new file mode 100644 index 000000000..4f36c1309 --- /dev/null +++ b/criu/arch/s390/include/asm/types.h @@ -0,0 +1,37 @@ +#ifndef _UAPI_S390_TYPES_H +#define _UAPI_S390_TYPES_H + +#include +#include +#include "images/core.pb-c.h" + +#include "page.h" +#include "bitops.h" +#include "asm/int.h" + +#include + +typedef UserS390RegsEntry UserRegsEntry; + +#define CORE_ENTRY__MARCH CORE_ENTRY__MARCH__S390 + +#define core_is_compat(core) false + +#define CORE_THREAD_ARCH_INFO(core) core->ti_s390 + +static inline u64 encode_pointer(void *p) { return (u64) p; } +static inline void *decode_pointer(u64 v) { return (void *) v; } + +/* + * See also: + * * arch/s390/include/uapi/asm/auxvec.h + * * include/linux/auxvec.h + */ +#define AT_VECTOR_SIZE_BASE 20 +#define AT_VECTOR_SIZE_ARCH 1 +#define AT_VECTOR_SIZE (2*(AT_VECTOR_SIZE_ARCH + AT_VECTOR_SIZE_BASE + 1)) + +typedef uint64_t auxv_t; +typedef uint64_t tls_t; + +#endif /* _UAPI_S390_TYPES_H */ diff --git a/criu/arch/s390/include/asm/vdso.h b/criu/arch/s390/include/asm/vdso.h new file mode 100644 index 000000000..63e7e0464 --- /dev/null +++ b/criu/arch/s390/include/asm/vdso.h @@ -0,0 +1,23 @@ +#ifndef __CR_ASM_VDSO_H__ +#define __CR_ASM_VDSO_H__ + +#include "asm/int.h" +#include "asm-generic/vdso.h" + +/* + * This is a minimal amount of symbols + * we should support at the moment. + */ +#define VDSO_SYMBOL_MAX 4 + +/* + * This definition is used in pie/util-vdso.c to initialize the vdso symbol + * name string table 'vdso_symbols' + */ +#define ARCH_VDSO_SYMBOLS \ + "__kernel_gettimeofday", \ + "__kernel_clock_gettime", \ + "__kernel_clock_getres", \ + "__kernel_getcpu" + +#endif /* __CR_ASM_VDSO_H__ */ diff --git a/criu/arch/s390/restorer.c b/criu/arch/s390/restorer.c new file mode 100644 index 000000000..3823fda98 --- /dev/null +++ b/criu/arch/s390/restorer.c @@ -0,0 +1,37 @@ +#include + +#include "restorer.h" +#include "asm/restorer.h" +#include + +#include +#include "log.h" + +/* + * All registers are restored by sigreturn - nothing to do here + */ +int restore_nonsigframe_gpregs(UserS390RegsEntry *r) +{ + return 0; +} + +/* + * Call underlying ipc system call for shmat + */ +unsigned long sys_shmat(int shmid, const void *shmaddr, int shmflg) +{ + unsigned long raddr; + int ret; + + ret = sys_ipc(21 /*SHMAT */, + shmid, /* first */ + shmflg, /* second */ + (unsigned long)&raddr, /* third */ + shmaddr, /* ptr */ + 0 /* fifth not used */); + + if (ret) + raddr = (unsigned long) ret; + + return raddr; +} diff --git a/criu/arch/s390/sigframe.c b/criu/arch/s390/sigframe.c new file mode 100644 index 000000000..03f206a8d --- /dev/null +++ b/criu/arch/s390/sigframe.c @@ -0,0 +1,20 @@ +#include +#include + +#include "asm/sigframe.h" +#include "asm/types.h" + +#include "log.h" + +/* + * Nothing to do since we don't have any pointers to adjust + * in the signal frame. + * + * - sigframe : Pointer to local signal frame + * - rsigframe: Pointer to remote signal frame of inferior + */ +int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, + struct rt_sigframe *rsigframe) +{ + return 0; +} diff --git a/criu/arch/s390/vdso-pie.c b/criu/arch/s390/vdso-pie.c new file mode 100644 index 000000000..0667668ee --- /dev/null +++ b/criu/arch/s390/vdso-pie.c @@ -0,0 +1,65 @@ +#include + +#include "asm/types.h" + +#include +#include +#include "parasite-vdso.h" +#include "log.h" +#include "common/bug.h" + +#ifdef LOG_PREFIX +# undef LOG_PREFIX +#endif +#define LOG_PREFIX "vdso: " + +/* + * Trampoline instruction sequence + */ +typedef struct { + u8 larl[6]; /* Load relative address of imm64 */ + u8 lg[6]; /* Load %r1 with imm64 */ + u8 br[2]; /* Branch to %r1 */ + u64 addr; /* Jump address */ + u32 guards; /* Guard bytes */ +} __packed jmp_t; + +/* + * Trampoline template: Use %r1 to jump + */ +jmp_t jmp = { + /* larl %r1,e (addr) */ + .larl = {0xc0, 0x10, 0x00, 0x00, 0x00, 0x07}, + /* lg %r1,0(%r1) */ + .lg = {0xe3, 0x10, 0x10, 0x00, 0x00, 0x04}, + /* br %r1 */ + .br = {0x07, 0xf1}, + .guards = 0xcccccccc, +}; + +/* + * Insert trampoline code into old vdso entry points to + * jump to new vdso functions. + */ +int vdso_redirect_calls(unsigned long base_to, unsigned long base_from, + struct vdso_symtable *to, struct vdso_symtable *from, + bool __always_unused compat_vdso) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(to->symbols); i++) { + if (vdso_symbol_empty(&from->symbols[i])) + continue; + + pr_debug("jmp: %s: %lx/%lx -> %lx/%lx (index %d)\n", + from->symbols[i].name, base_from, + from->symbols[i].offset, + base_to, to->symbols[i].offset, i); + + jmp.addr = base_to + to->symbols[i].offset; + memcpy((void *)(base_from + from->symbols[i].offset), &jmp, + sizeof(jmp)); + } + + return 0; +} From 500977101e5a3e065b7b69f3cc82907d410fc022 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 30 Jun 2017 20:31:40 +0200 Subject: [PATCH 0686/4375] s390:criu: Enable s390 in criu Add s390 parts to common code files. Patch history ------------- v2->v3: * Add: Fix big endian byte order checks Reviewed-by: Alice Frosi Signed-off-by: Michael Holzheu Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 7 +++++++ criu/pie/Makefile.library | 6 ++++++ criu/pie/util-vdso.c | 25 +++++++++++++++++++------ criu/sk-netlink.c | 16 ++++++++++++++++ 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 73d95d5f1..76c35352c 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -16,6 +16,13 @@ ifeq ($(SRCARCH),arm) ccflags-y += -marm endif +# We assume that compel code does not change floating point registers. +# On s390 gcc uses fprs to cache gprs. Therefore disable floating point +# with -msoft-float. +ifeq ($(SRCARCH),s390) + ccflags-y += -msoft-float +endif + asflags-y += -D__ASSEMBLY__ LDS := compel/arch/$(SRCARCH)/scripts/compel-pack.lds.S diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index f58933313..ceadc1d66 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -41,3 +41,9 @@ ccflags-y += $(COMPEL_UAPI_INCLUDES) ifeq ($(SRCARCH),arm) ccflags-y += -marm endif +# We assume that compel code does not change floating point registers. +# On s390 gcc uses fprs to cache gprs. Therefore disable floating point +# with -msoft-float. +ifeq ($(SRCARCH),s390) + ccflags-y += -msoft-float +endif diff --git a/criu/pie/util-vdso.c b/criu/pie/util-vdso.c index 51fea56a3..6213df9a4 100644 --- a/criu/pie/util-vdso.c +++ b/criu/pie/util-vdso.c @@ -68,6 +68,12 @@ static unsigned long elf_hash(const unsigned char *name) return h; } +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define BORD ELFDATA2MSB /* 0x02 */ +#else +#define BORD ELFDATA2LSB /* 0x01 */ +#endif + static int has_elf_identity(Ehdr_t *ehdr) { /* @@ -75,12 +81,12 @@ static int has_elf_identity(Ehdr_t *ehdr) */ #if defined(CONFIG_VDSO_32) static const char elf_ident[] = { - 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, + 0x7f, 0x45, 0x4c, 0x46, 0x01, BORD, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #else static const char elf_ident[] = { - 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, + 0x7f, 0x45, 0x4c, 0x46, 0x02, BORD, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #endif @@ -202,17 +208,24 @@ err_oob: return -EFAULT; } +/* On s390x Hash_t is 64 bit */ +#ifdef __s390x__ +typedef unsigned long Hash_t; +#else +typedef Word_t Hash_t; +#endif + static void parse_elf_symbols(uintptr_t mem, size_t size, Phdr_t *load, struct vdso_symtable *t, uintptr_t dynsymbol_names, - Word_t *hash, Dyn_t *dyn_symtab) + Hash_t *hash, Dyn_t *dyn_symtab) { const char *vdso_symbols[VDSO_SYMBOL_MAX] = { ARCH_VDSO_SYMBOLS }; const size_t vdso_symbol_length = sizeof(t->symbols[0].name); - Word_t nbucket, nchain; - Word_t *bucket, *chain; + Hash_t nbucket, nchain; + Hash_t *bucket, *chain; unsigned int i, j, k; uintptr_t addr; @@ -264,7 +277,7 @@ int vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t) Dyn_t *dyn_strtab = NULL; Dyn_t *dyn_symtab = NULL; Dyn_t *dyn_hash = NULL; - Word_t *hash = NULL; + Hash_t *hash = NULL; uintptr_t dynsymbol_names; uintptr_t addr; diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c index 6ab2685f0..e15dc0884 100644 --- a/criu/sk-netlink.c +++ b/criu/sk-netlink.c @@ -105,6 +105,22 @@ static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p) * On 64-bit sk->gsize is multiple to 8 bytes (sizeof(long)), * so remove the last 4 bytes if they are empty. */ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + /* + * Big endian swap: Ugly hack for zdtm/static/sk-netlink + * + * For big endian systems: + * + * - sk->groups[0] are bits 32-64 + * - sk->groups[1] are bits 0-32 + */ + if (ne.n_groups == 2) { + uint32_t tmp = sk->groups[1]; + + sk->groups[1] = sk->groups[0]; + sk->groups[0] = tmp; + } +#endif if (ne.n_groups && sk->groups[ne.n_groups - 1] == 0) ne.n_groups -= 1; From 01ee29702efadcddc52c31508a3ad65014c5fb61 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 30 Jun 2017 20:31:41 +0200 Subject: [PATCH 0687/4375] s390:zdtm: Enable zdtm for s390 Reviewed-by: Alice Frosi Signed-off-by: Michael Holzheu Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/lib/arch/s390/include/asm/atomic.h | 66 +++++++++++++++++++ test/zdtm/static/fanotify00.c | 3 + test/zdtm/static/mntns-deleted-dst | 0 test/zdtm/static/netns-nf.desc | 2 +- test/zdtm/static/rtc.desc | 2 +- .../static/socket-tcp-closed-last-ack.desc | 4 +- 6 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 test/zdtm/lib/arch/s390/include/asm/atomic.h create mode 100644 test/zdtm/static/mntns-deleted-dst diff --git a/test/zdtm/lib/arch/s390/include/asm/atomic.h b/test/zdtm/lib/arch/s390/include/asm/atomic.h new file mode 100644 index 000000000..9cf7236e6 --- /dev/null +++ b/test/zdtm/lib/arch/s390/include/asm/atomic.h @@ -0,0 +1,66 @@ +#ifndef __ARCH_S390_ATOMIC__ +#define __ARCH_S390_ATOMIC__ + +#include + +typedef uint32_t atomic_t; + +#define __ATOMIC_OP(op_name, op_type, op_string, op_barrier) \ +static inline op_type op_name(op_type val, op_type *ptr) \ +{ \ + op_type old; \ + \ + asm volatile( \ + op_string " %[old],%[val],%[ptr]\n" \ + op_barrier \ + : [old] "=d" (old), [ptr] "+Q" (*ptr) \ + : [val] "d" (val) : "cc", "memory"); \ + return old; \ +} \ + +#define __ATOMIC_OPS(op_name, op_type, op_string) \ + __ATOMIC_OP(op_name, op_type, op_string, "\n") \ + __ATOMIC_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n") + +__ATOMIC_OPS(__atomic_add, uint32_t, "laa") + +#undef __ATOMIC_OPS +#undef __ATOMIC_OP + +static inline int atomic_get(const atomic_t *v) +{ + int c; + + asm volatile( + " l %0,%1\n" + : "=d" (c) : "Q" (*v)); + return c; +} + +static inline void atomic_set(atomic_t *v, int i) +{ + asm volatile( + " st %1,%0\n" + : "=Q" (*v) : "d" (i)); +} + +static inline int atomic_add_return(int i, atomic_t *v) +{ + return __atomic_add_barrier(i, v) + i; +} + +static inline void atomic_add(int i, atomic_t *v) +{ + __atomic_add(i, v); +} + +#define atomic_sub(_i, _v) atomic_add(-(int)(_i), _v) + +static inline int atomic_inc(atomic_t *v) +{ + return atomic_add_return(1, v) - 1; +} + +#define atomic_dec(_v) atomic_sub(1, _v) + +#endif /* __ARCH_S390_ATOMIC__ */ diff --git a/test/zdtm/static/fanotify00.c b/test/zdtm/static/fanotify00.c index 9fc3d7a3b..e948a63aa 100644 --- a/test/zdtm/static/fanotify00.c +++ b/test/zdtm/static/fanotify00.c @@ -25,6 +25,9 @@ #elif __aarch64__ # define __NR_fanotify_init 262 # define __NR_fanotify_mark 263 +#elif __s390x__ +# define __NR_fanotify_init 332 +# define __NR_fanotify_mark 333 #else # define __NR_fanotify_init 338 # define __NR_fanotify_mark 339 diff --git a/test/zdtm/static/mntns-deleted-dst b/test/zdtm/static/mntns-deleted-dst new file mode 100644 index 000000000..e69de29bb diff --git a/test/zdtm/static/netns-nf.desc b/test/zdtm/static/netns-nf.desc index 23496bbe7..618e256e6 100644 --- a/test/zdtm/static/netns-nf.desc +++ b/test/zdtm/static/netns-nf.desc @@ -1,6 +1,6 @@ { 'deps': [ '/bin/sh', '/sbin/iptables', - '/usr/lib64/xtables/libxt_standard.so|/usr/lib/iptables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so', + '/usr/lib64/xtables/libxt_standard.so|/usr/lib/iptables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so|/usr/lib/s390x-linux-gnu/xtables/libxt_standard.so', '/usr/bin/diff'], 'flags': 'suid', 'flavor': 'ns uns'} diff --git a/test/zdtm/static/rtc.desc b/test/zdtm/static/rtc.desc index 80094be09..2c9c7e582 100644 --- a/test/zdtm/static/rtc.desc +++ b/test/zdtm/static/rtc.desc @@ -1 +1 @@ -{'flavor': 'h', 'flags': 'suid crlib'} +{'flavor': 'h', 'flags': 'suid crlib','arch': 'x86_64 aarch64 arm ppc64'} diff --git a/test/zdtm/static/socket-tcp-closed-last-ack.desc b/test/zdtm/static/socket-tcp-closed-last-ack.desc index bc56073ef..590bc5848 100644 --- a/test/zdtm/static/socket-tcp-closed-last-ack.desc +++ b/test/zdtm/static/socket-tcp-closed-last-ack.desc @@ -1,7 +1,7 @@ { 'deps': [ '/bin/sh', '/sbin/iptables', - '/usr/lib64/xtables/libxt_tcp.so|/lib/xtables/libxt_tcp.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_tcp.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so', - '/usr/lib64/xtables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so', + '/usr/lib64/xtables/libxt_tcp.so|/lib/xtables/libxt_tcp.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_tcp.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so|/usr/lib/s390x-linux-gnu/xtables/libxt_tcp.so', + '/usr/lib64/xtables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so|/usr/lib/s390x-linux-gnu/xtables/libxt_standard.so', ], 'opts': '--tcp-established', 'flags': 'suid nouser samens', From 2ced0450b2a3bf064a69708e969353061fcba3a6 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 30 Jun 2017 20:31:43 +0200 Subject: [PATCH 0688/4375] s390: Enable s390 build in Makefile Reviewed-by: Alice Frosi Signed-off-by: Michael Holzheu Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e2d89e3e4..7f03b6e1f 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ UNAME-M := $(shell uname -m) # # Supported Architectures -ifneq ($(filter-out x86 arm aarch64 ppc64,$(ARCH)),) +ifneq ($(filter-out x86 arm aarch64 ppc64 s390,$(ARCH)),) $(error "The architecture $(ARCH) isn't supported") endif @@ -65,6 +65,13 @@ ifeq ($(ARCH),x86) DEFINES := -DCONFIG_X86_64 endif +ifeq ($(ARCH),s390) + ARCH := s390 + SRCARCH := s390 + VDSO := y + DEFINES := -DCONFIG_S390 +endif + LDARCH ?= $(SRCARCH) export LDARCH VDSO export PROTOUFIX DEFINES From 27db1d9a0452201ac17cd427b95a107e381aa7af Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 30 Jun 2017 20:31:44 +0200 Subject: [PATCH 0689/4375] s390:zdtm: Add test for tasks > 4TB If the kernel contains patch ee71d16d22 ("s390/mm: make TASK_SIZE independent from the number of page table levels") we are able to checkpoint tasks > 4TB. Add a testcase to verify this. Signed-off-by: Michael Holzheu Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/s390x_mmap_high.c | 64 +++++++++++++++++++++++++++ test/zdtm/static/s390x_mmap_high.desc | 1 + 3 files changed, 66 insertions(+) create mode 100644 test/zdtm/static/s390x_mmap_high.c create mode 100644 test/zdtm/static/s390x_mmap_high.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 08cc3d9cc..0dba4b454 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -171,6 +171,7 @@ TST_NOFILE := \ macvlan \ cr_veth \ sock_peercred \ + s390x_mmap_high \ # jobctl00 \ ifneq ($(SRCARCH),arm) diff --git a/test/zdtm/static/s390x_mmap_high.c b/test/zdtm/static/s390x_mmap_high.c new file mode 100644 index 000000000..5eb06e6bc --- /dev/null +++ b/test/zdtm/static/s390x_mmap_high.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" + +#define TASK_SIZE_LEVEL_4 0x20000000000000UL /* 8 PB */ +#define MAP_SIZE 0x1000 +#define VAL 0x77 + +const char *test_doc = "Verify that tasks > 4TB can be checkpointed"; +const char *test_author = "Michael Holzheu "; + +/* + * Map memory at the very end of the 8 PB address space + */ +int main(int argc, char **argv) +{ + void *addr = (void *) TASK_SIZE_LEVEL_4 - MAP_SIZE; + char *buf; + int i; + + + test_init(argc, argv); + + /* + * Skip test if kernel does not have the following fix: + * + * ee71d16d22 ("s390/mm: make TASK_SIZE independent from the number + * of page table levels") + */ + if (munmap(addr, MAP_SIZE) == -1) { + test_daemon(); + test_waitsig(); + skip("Detected kernel without 4 level TASK_SIZE fix"); + pass(); + return 0; + } + + /* Map memory at the very end of the 8 PB address space */ + buf = mmap(addr, MAP_SIZE, PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + if (buf == MAP_FAILED) { + pr_perror("Could not create mapping"); + exit(1); + } + /* Initialize buffer with data */ + memset(buf, VAL, MAP_SIZE); + + test_daemon(); + test_waitsig(); + + /* Verify that we restored the data correctly */ + for (i = 0; i < MAP_SIZE; i++) { + if (buf[i] == VAL) + continue; + fail("%d: %d != %d\n", i, buf[i], VAL); + goto out; + } + pass(); +out: + return 0; +} diff --git a/test/zdtm/static/s390x_mmap_high.desc b/test/zdtm/static/s390x_mmap_high.desc new file mode 100644 index 000000000..8621263f2 --- /dev/null +++ b/test/zdtm/static/s390x_mmap_high.desc @@ -0,0 +1 @@ +{'arch': 's390x'} From c2f30337a57e5c71cf3864441059d29b821f2398 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 30 Jun 2017 20:31:45 +0200 Subject: [PATCH 0690/4375] s390:criu: Add support for s390 consoles On s390 we have special console drivers with minors 64 and 65. Add support for them in criu code and in zdtm testsuite. Reviewed-by: Alice Frosi Signed-off-by: Michael Holzheu Signed-off-by: Andrei Vagin --- criu/tty.c | 11 +++++++++++ test/zdtm/static/vt.c | 8 +++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/criu/tty.c b/criu/tty.c index 5b0cc841b..f5f4ef9c0 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -295,6 +295,17 @@ struct tty_driver *get_tty_driver(dev_t rdev, dev_t dev) * of kernel). */ return &vt_driver; +#ifdef __s390x__ + /* + * On s390 we have the following consoles: + * - tty3215 : ttyS0 , minor = 64, linemode console + * - sclp_line : ttyS0 , minor = 64, linemode console + * - sclp_vt220 : ttysclp0, minor = 65, vt220 console + * See also "drivers/s390/char" + */ + else if (minor == 64 || minor == 65) + return &vt_driver; +#endif /* Other minors points to UART serial ports */ break; case USB_SERIAL_MAJOR: diff --git a/test/zdtm/static/vt.c b/test/zdtm/static/vt.c index 0db0f2cd8..0d843c4cf 100644 --- a/test/zdtm/static/vt.c +++ b/test/zdtm/static/vt.c @@ -15,6 +15,12 @@ const char *test_author = "Ruslan Kuprieiev "; char *filename; TEST_OPTION(filename, string, "file name", 1); +#ifdef __s390x__ +#define MINOR 64 /* ttyS0 */ +#else +#define MINOR 5 +#endif + int main(int argc, char **argv) { struct stat st1, st2; @@ -22,7 +28,7 @@ int main(int argc, char **argv) test_init(argc, argv); - if (mknod(filename, S_IFCHR | S_IRUSR | S_IWUSR, makedev(4, 5))) { + if (mknod(filename, S_IFCHR | S_IRUSR | S_IWUSR, makedev(4, MINOR))) { pr_perror("Can't create virtual terminal %s", filename); return 1; } From 6603b419c76730458d8994cad35f4fc374f63d50 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 30 Jun 2017 20:31:46 +0200 Subject: [PATCH 0691/4375] s390:criu: Add TASK_SIZE check for dump and restore For kernels that don't have commit ee71d16d22 ("s390/mm: make TASK_SIZE independent from the number of page table levels") criu sets TASK_SIZE to 4 TB on s390 (see compel_task_size()). When dumping tasks >= 4 TB on such systems, we would silently loose memory >= 4TB. So add a check and refuse to dump the task in that case. When restoring tasks >= 4 TB on such systems, the remap() call for moving the vmas at the end of the restor process would fail and a very unclear error message is printed. So add a check and write a more speaking error message in that case. Reviewed-by: Alice Frosi Signed-off-by: Michael Holzheu Signed-off-by: Andrei Vagin --- criu/mem.c | 19 +++++++++++++++++++ criu/proc_parse.c | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/criu/mem.c b/criu/mem.c index cd41829b2..697920f47 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -741,6 +741,21 @@ static inline bool vma_force_premap(struct vma_area *vma, struct list_head *head return false; } +/* + * Ensure for s390x that vma is below task size on restore system + */ +static int task_size_check(pid_t pid, VmaEntry *entry) +{ +#ifdef __s390x__ + if (entry->end <= kdat.task_size) + return 0; + pr_err("Can't restore high memory region %lx-%lx because kernel does only support vmas up to %lx\n", entry->start, entry->end, kdat.task_size); + return -1; +#else + return 0; +#endif +} + static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, void **at, struct page_read *pr) { @@ -752,6 +767,10 @@ static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, filemap_ctx_init(true); list_for_each_entry(vma, &vmas->h, list) { + if (task_size_check(vpid(t), vma->e)) { + ret = -1; + break; + } if (pstart > vma->e->start) { ret = -1; pr_err("VMA-s are not sorted in the image file\n"); diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 5da8a47d3..ed313fc92 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -665,6 +665,22 @@ static int vma_list_add(struct vma_area *vma_area, return 0; } +/* + * On s390 we have old kernels where the global task size assumption of + * criu does not work. See also compel_task_size() for s390. + */ +static int task_size_check(pid_t pid, VmaEntry *entry) +{ +#ifdef __s390x__ + if (entry->end <= kdat.task_size) + return 0; + pr_err("Can't dump high memory region %lx-%lx of task %d because kernel commit ee71d16d22bb is missing\n", entry->start, entry->end, pid); + return -1; +#else + return 0; +#endif +} + int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, dump_filemap_t dump_filemap) { @@ -750,6 +766,9 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, vma_area->e->pgoff = pgoff; vma_area->e->prot = PROT_NONE; + if (task_size_check(pid, vma_area->e)) + goto err; + if (r == 'r') vma_area->e->prot |= PROT_READ; if (w == 'w') From 254094d66fea22ec36733e8a7d7b4c7d97bfded7 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 14 Jul 2017 11:23:26 +0200 Subject: [PATCH 0692/4375] s390: Prevent GOT relocations Use the "-fno-optimize-sibling-calls" gcc option to prevent GOT relocations caused by gcc versions without the commit "S/390: Fix 64 bit sibcall": * https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=233169 Otherwise we get compile errors like: GEN criu/pie/parasite-blob.h Error (compel/src/lib/handle-elf-host.c:572): Unsupported relocation of type 26 Those can be caused by the following relocation types: * R_390_GOTENT (e.g. RHEL7 based systems) * R_390_GOTPCDBL (e.g. Debian Jessie) * R_390_GOT12 (e.g. Debian Jessie) Signed-off-by: Michael Holzheu Signed-off-by: Andrei Vagin --- Makefile.compel | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Makefile.compel b/Makefile.compel index 9b40079b3..5c854e3dc 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -71,10 +71,12 @@ compel-install-targets += compel/$(LIBCOMPEL_SO) compel-install-targets += compel/compel compel-install-targets += $(compel-plugins) -# We assume that compel code does not change floating point registers. -# On s390 gcc uses fprs to cache gprs. Therefore disable floating point -# with -msoft-float. +# +# Also ensure with -fno-optimize-sibling-calls that we don't create GOT +# (Global Offset Table) relocations with gcc compilers that don't have +# commit "S/390: Fix 64 bit sibcall". +# ifeq ($(ARCH),s390) -CFLAGS += -msoft-float -HOSTCFLAGS += -msoft-float +CFLAGS += -msoft-float -fno-optimize-sibling-calls +HOSTCFLAGS += -msoft-float -fno-optimize-sibling-calls endif From a04dc883cb22376f3c87c18a9e5073cec3442080 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 14 Jul 2017 15:41:12 +0200 Subject: [PATCH 0693/4375] s390: Replace flogr instruction with __builtin_clzl() The flogr instruction not supported by debian jessie (z900). So replace it by the gcc built-in. Signed-off-by: Michael Holzheu Signed-off-by: Andrei Vagin --- include/common/arch/s390/asm/bitops.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/include/common/arch/s390/asm/bitops.h b/include/common/arch/s390/asm/bitops.h index 13d832380..648d898d1 100644 --- a/include/common/arch/s390/asm/bitops.h +++ b/include/common/arch/s390/asm/bitops.h @@ -107,13 +107,7 @@ static inline unsigned char __flogr(unsigned long word) } return bit; } else { - register unsigned long bit asm("4") = word; - register unsigned long out asm("5"); - - asm volatile( - " flogr %[bit],%[bit]\n" - : [bit] "+d" (bit), [out] "=d" (out) : : "cc"); - return bit; + return __builtin_clzl(word); } } From 9c94ed9669b334cc61d0462d2267d58d6de67424 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 14 Jul 2017 15:41:13 +0200 Subject: [PATCH 0694/4375] s390/zdtm: Also support z900 (debian) Debian is compiled for z900 - therefore we can't use the "laa" instruction. Fix this and replace "laa" by the older "cs" (compare and swap) loop. Signed-off-by: Michael Holzheu Signed-off-by: Andrei Vagin --- test/zdtm/lib/arch/s390/include/asm/atomic.h | 22 +++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/test/zdtm/lib/arch/s390/include/asm/atomic.h b/test/zdtm/lib/arch/s390/include/asm/atomic.h index 9cf7236e6..b7c4b2c53 100644 --- a/test/zdtm/lib/arch/s390/include/asm/atomic.h +++ b/test/zdtm/lib/arch/s390/include/asm/atomic.h @@ -5,24 +5,26 @@ typedef uint32_t atomic_t; -#define __ATOMIC_OP(op_name, op_type, op_string, op_barrier) \ +#define __ATOMIC_OP(op_name, op_type, op_string) \ static inline op_type op_name(op_type val, op_type *ptr) \ { \ - op_type old; \ + op_type old, new; \ \ asm volatile( \ - op_string " %[old],%[val],%[ptr]\n" \ - op_barrier \ - : [old] "=d" (old), [ptr] "+Q" (*ptr) \ - : [val] "d" (val) : "cc", "memory"); \ + "0: lr %[new],%[old]\n" \ + op_string " %[new],%[val]\n" \ + " cs %[old],%[new],%[ptr]\n" \ + " jl 0b" \ + : [old] "=d" (old), [new] "=&d" (new), [ptr] "+Q" (*ptr)\ + : [val] "d" (val), "0" (*ptr) : "cc", "memory"); \ return old; \ -} \ +} #define __ATOMIC_OPS(op_name, op_type, op_string) \ - __ATOMIC_OP(op_name, op_type, op_string, "\n") \ - __ATOMIC_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n") + __ATOMIC_OP(op_name, op_type, op_string) \ + __ATOMIC_OP(op_name##_barrier, op_type, op_string) -__ATOMIC_OPS(__atomic_add, uint32_t, "laa") +__ATOMIC_OPS(__atomic_add, uint32_t, "ar") #undef __ATOMIC_OPS #undef __ATOMIC_OP From 602a948ddda17a3c8e146352a8c34c41a0ca8c40 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 14 Jul 2017 15:41:14 +0200 Subject: [PATCH 0695/4375] s390: Enable travis We have to use "debian.jessie" instead of "ubuntu.xenial" because qemu-s390x-static can only run z900 instructions and Ubuntu is built with a more recent architecture level set. We first enable only gcc because there are still some issues with clang. Signed-off-by: Michael Holzheu Signed-off-by: Andrei Vagin --- .travis.yml | 1 + scripts/build/Dockerfile.s390x.hdr | 4 ++++ scripts/build/Makefile | 2 +- scripts/build/binfmt_misc | 3 +++ 4 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 scripts/build/Dockerfile.s390x.hdr diff --git a/.travis.yml b/.travis.yml index d4d53e434..eaa8401cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ env: - TR_ARCH=armv7hf - TR_ARCH=aarch64 - TR_ARCH=ppc64le + - TR_ARCH=s390x - TR_ARCH=armv7hf CLANG=1 - TR_ARCH=aarch64 CLANG=1 - TR_ARCH=ppc64le CLANG=1 diff --git a/scripts/build/Dockerfile.s390x.hdr b/scripts/build/Dockerfile.s390x.hdr new file mode 100644 index 000000000..be75712f4 --- /dev/null +++ b/scripts/build/Dockerfile.s390x.hdr @@ -0,0 +1,4 @@ +FROM s390x/debian:jessie + +ENV QEMU_CPU z900 +COPY scripts/build/qemu-user-static/usr/bin/qemu-s390x-static /usr/bin/qemu-s390x-static diff --git a/scripts/build/Makefile b/scripts/build/Makefile index 53087111e..234649afa 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -1,4 +1,4 @@ -QEMU_ARCHES := armv7hf aarch64 ppc64le # require qemu +QEMU_ARCHES := armv7hf aarch64 ppc64le s390x # require qemu ARCHES := $(QEMU_ARCHES) x86_64 TARGETS := $(ARCHES) alpine fedora-asan TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) diff --git a/scripts/build/binfmt_misc b/scripts/build/binfmt_misc index a5c922eb5..3e76b660e 100755 --- a/scripts/build/binfmt_misc +++ b/scripts/build/binfmt_misc @@ -8,3 +8,6 @@ test -f /proc/sys/fs/binfmt_misc/aarch64 || test -f /proc/sys/fs/binfmt_misc/ppc64le || echo ':ppc64le:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00:/usr/bin/qemu-ppc64le-static:' > /proc/sys/fs/binfmt_misc/register + +test -f /proc/sys/fs/binfmt_misc/s390x || + echo ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-s390x-static:' > /proc/sys/fs/binfmt_misc/register From 61e6c01d0964d45c1e49aafb7ba369e7cd2f9180 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 21 Jul 2017 19:26:09 +0200 Subject: [PATCH 0696/4375] s390: Move -msoft-float/-fno-optimize-sibling-calls into compel Makefiles We currently define "CFLAGS += -msoft-float -fno-optimize-sibling-calls" in Makefile.compel. Makefile.compel is included into the toplevel Makefile and so changes CFLAGS which are exported to all criu and zdtm Makefiles. We must not use -msoft-float outside the compel files. E.g. otherwise for zdtm we get the following build error: uptime_grow.o: In function `main': /tmp/2/criu/test/zdtm/static/uptime_grow.c:36: undefined reference to `__floatdidf' /tmp/2/criu/test/zdtm/static/uptime_grow.c:36: undefined reference to `__muldf3' /tmp/2/criu/test/zdtm/static/uptime_grow.c:36: undefined reference to `__floatdidf' /tmp/2/criu/test/zdtm/static/uptime_grow.c:36: undefined reference to `__adddf3 Fix this and move the CFLAGS definition to the compel Makefiles. We do this by defining a new flag CFLAGS_PIE that is only used for pie code. Reported-by: Adrian Reber Suggested-by: Dmitry Safonov Signed-off-by: Michael Holzheu Reviewed-by: Dmitry Safonov Tested-by: Adrian Reber Signed-off-by: Andrei Vagin --- Makefile | 12 ++++++++++++ Makefile.compel | 10 ---------- compel/Makefile | 1 + compel/plugins/Makefile | 4 +++- criu/pie/Makefile | 8 +------- criu/pie/Makefile.library | 8 ++------ 6 files changed, 19 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index 7f03b6e1f..ad052f158 100644 --- a/Makefile +++ b/Makefile @@ -65,12 +65,24 @@ ifeq ($(ARCH),x86) DEFINES := -DCONFIG_X86_64 endif +# +# CFLAGS_PIE: +# +# We assume that compel code does not change floating point registers. +# On s390 gcc uses fprs to cache gprs. Therefore disable floating point +# with -msoft-float. +# +# Also ensure with -fno-optimize-sibling-calls that we don't create GOT +# (Global Offset Table) relocations with gcc compilers that don't have +# commit "S/390: Fix 64 bit sibcall". ifeq ($(ARCH),s390) ARCH := s390 SRCARCH := s390 VDSO := y DEFINES := -DCONFIG_S390 + CFLAGS_PIE := -msoft-float -fno-optimize-sibling-calls endif +export CFLAGS_PIE LDARCH ?= $(SRCARCH) export LDARCH VDSO diff --git a/Makefile.compel b/Makefile.compel index 5c854e3dc..1ef7f8cb2 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -70,13 +70,3 @@ compel/$(LIBCOMPEL_SO): compel/$(LIBCOMPEL_A) compel-install-targets += compel/$(LIBCOMPEL_SO) compel-install-targets += compel/compel compel-install-targets += $(compel-plugins) - -# -# Also ensure with -fno-optimize-sibling-calls that we don't create GOT -# (Global Offset Table) relocations with gcc compilers that don't have -# commit "S/390: Fix 64 bit sibcall". -# -ifeq ($(ARCH),s390) -CFLAGS += -msoft-float -fno-optimize-sibling-calls -HOSTCFLAGS += -msoft-float -fno-optimize-sibling-calls -endif diff --git a/compel/Makefile b/compel/Makefile index 43d27f55d..7ef01aa01 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -11,6 +11,7 @@ ccflags-y += -iquote compel/arch/$(ARCH)/src/lib/include ccflags-y += -iquote compel/include ccflags-y += -fno-strict-aliasing ccflags-y += -fPIC +ccflags-y += $(CFLAGS_PIE) ldflags-y += -r # diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 7127425af..82c35be6a 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -7,7 +7,9 @@ PLUGIN_ARCH_DIR := compel/arch/$(ARCH)/plugins # # CFLAGS, ASFLAGS, LDFLAGS -# +# Required for pie code +ccflags-y += $(CFLAGS_PIE) + # UAPI inclusion, referred as ccflags-y += -I compel/include/uapi asflags-y += -I compel/include/uapi diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 76c35352c..de4d667a5 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -2,6 +2,7 @@ target := parasite restorer CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) ccflags-y += $(COMPEL_UAPI_INCLUDES) +ccflags-y += $(CFLAGS_PIE) ccflags-y += -DCR_NOGLIBC ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 @@ -16,13 +17,6 @@ ifeq ($(SRCARCH),arm) ccflags-y += -marm endif -# We assume that compel code does not change floating point registers. -# On s390 gcc uses fprs to cache gprs. Therefore disable floating point -# with -msoft-float. -ifeq ($(SRCARCH),s390) - ccflags-y += -msoft-float -endif - asflags-y += -D__ASSEMBLY__ LDS := compel/arch/$(SRCARCH)/scripts/compel-pack.lds.S diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index ceadc1d66..f268b5ded 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -37,13 +37,9 @@ CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) asflags-y := -D__ASSEMBLY__ ccflags-y += $(COMPEL_UAPI_INCLUDES) +ccflags-y += $(CFLAGS_PIE) ifeq ($(SRCARCH),arm) ccflags-y += -marm endif -# We assume that compel code does not change floating point registers. -# On s390 gcc uses fprs to cache gprs. Therefore disable floating point -# with -msoft-float. -ifeq ($(SRCARCH),s390) - ccflags-y += -msoft-float -endif + From a5e2605e7a6d74dc957a2299d7ecdf2ab022b004 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Mon, 7 Aug 2017 14:56:52 +0200 Subject: [PATCH 0697/4375] s390: Fix off-by-one error for task size detection The entries in /proc//maps look like the following: 3fffffdf000-40000000000 rw-p 00000000 00:00 0 The upper address is the first address that is *not* included in the address range. Our function max_mapped_addr() should return the last valid address for a process, but currently returns the first invalid address. This can lead to the following error message on kernel that have kernel commit ee71d16d22bb: Error (criu/proc_parse.c:694): Can't dump high memory region 1ffffffffff000-20000000000000 of task 24 because kernel commit ee71d16d22bb is missing Fix this and make max_mapped_addr() the last valid address (first invalid address - 1). Reported-by: Adrian Reber Signed-off-by: Michael Holzheu Signed-off-by: Andrei Vagin --- compel/arch/s390/src/lib/infect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/arch/s390/src/lib/infect.c b/compel/arch/s390/src/lib/infect.c index fcad33896..1614fa60e 100644 --- a/compel/arch/s390/src/lib/infect.c +++ b/compel/arch/s390/src/lib/infect.c @@ -393,7 +393,7 @@ static unsigned long max_mapped_addr(void) } fclose(fp); out: - return addr_max; + return addr_max - 1; } /* @@ -454,7 +454,7 @@ static enum kernel_ts_level get_kernel_ts_level(void) unsigned long criu_end_addr = max_mapped_addr(); /* Check for 5 levels */ - if (criu_end_addr > TASK_SIZE_LEVEL_4) + if (criu_end_addr >= TASK_SIZE_LEVEL_4) return KERNEL_TS_LEVEL_5; else if (munmap((void *) TASK_SIZE_LEVEL_4, 0x1000) == 0) return KERNEL_TS_LEVEL_5; From 7e5b5f3128f75fb61fb0c3f4d8ca56a033beb4e9 Mon Sep 17 00:00:00 2001 From: Gianfranco Costamagna Date: Wed, 5 Jul 2017 12:50:07 +0200 Subject: [PATCH 0698/4375] Fix ppc64el build failure, by not redefining AT_VECTOR_SIZE_ARCH This fixes the ppc64el build failure CC criu/arch/ppc64/sigframe.o In file included from criu/arch/ppc64/sigframe.c:5:0: criu/arch/ppc64/include/asm/types.h:32:0: error: "AT_VECTOR_SIZE_ARCH" redefined [-Werror] #define AT_VECTOR_SIZE_ARCH 6 Signed-off-by: Andrei Vagin --- criu/arch/ppc64/include/asm/types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/arch/ppc64/include/asm/types.h b/criu/arch/ppc64/include/asm/types.h index a82bc71a8..8f3af86a9 100644 --- a/criu/arch/ppc64/include/asm/types.h +++ b/criu/arch/ppc64/include/asm/types.h @@ -29,7 +29,9 @@ static inline uint64_t encode_pointer(void *p) { return (uint64_t)p; } * include/linux/mm_types.h */ #define AT_VECTOR_SIZE_BASE 20 +#if !defined AT_VECTOR_SIZE_ARCH #define AT_VECTOR_SIZE_ARCH 6 +#endif #define AT_VECTOR_SIZE (2*(AT_VECTOR_SIZE_ARCH + AT_VECTOR_SIZE_BASE + 1)) typedef uint64_t auxv_t; From 3ef506befcdf12eb9b7b5a55383d18086baafb1b Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 20 Jul 2017 12:06:04 -0400 Subject: [PATCH 0699/4375] compel: adapt .gitgnore for aarch64 and ppc64le Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- compel/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compel/.gitignore b/compel/.gitignore index e959dc5ef..eab3337d6 100644 --- a/compel/.gitignore +++ b/compel/.gitignore @@ -1,7 +1,9 @@ arch/x86/plugins/std/sys-exec-tbl-64.c arch/x86/plugins/std/syscalls-64.S arch/arm/plugins/std/syscalls/syscalls.S +arch/aarch64/plugins/std/syscalls/syscalls.S arch/s390/plugins/std/syscalls/syscalls.S +arch/ppc64/plugins/std/syscalls/syscalls.S include/version.h plugins/include/uapi/std/asm/syscall-types.h plugins/include/uapi/std/syscall-64.h From 36576e20960406e678caa3c460dc41192f480083 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 20 Jul 2017 12:08:35 -0400 Subject: [PATCH 0700/4375] compel/ppc64: glibc renamed ucontext to ucontext_t The upcoming glibc release renamed 'struct ucontext' to 'struct ucontext_t': https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=251287734e89a52da3db682a8241eb6bccc050c9;hp=c86ed71d633c22d6f638576f7660c52a5f783d66 Instead of using 'struct ucontext' this patch changes it to the typedef ucontext_t which already exists in older and new versions of glibc. Signed-off-by: Adrian Reber Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h | 6 +++--- criu/arch/ppc64/crtools.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h b/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h index bfaee8784..6f8b6ec54 100644 --- a/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h @@ -28,12 +28,12 @@ #define TRAMP_SIZE 6 /* - * ucontext defined in /usr/include/powerpc64le-linux-gnu/sys/ucontext.h + * ucontext_t defined in /usr/include/powerpc64le-linux-gnu/sys/ucontext.h */ struct rt_sigframe { /* sys_rt_sigreturn requires the ucontext be the first field */ - struct ucontext uc; - struct ucontext uc_transact; /* Transactional state */ + ucontext_t uc; + ucontext_t uc_transact; /* Transactional state */ unsigned long _unused[2]; unsigned int tramp[TRAMP_SIZE]; struct rt_siginfo *pinfo; diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index ecda5ce93..5a5966ad4 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -259,7 +259,7 @@ static int put_tm_regs(struct rt_sigframe *f, UserPpc64TmRegsEntry *tme) * For the case of getting a signal and simply returning from it, * we don't need to re-copy them here. */ - struct ucontext *tm_uc = &f->uc_transact; + ucontext_t *tm_uc = &f->uc_transact; pr_debug("Restoring TM registers FP:%d VR:%d VSX:%d\n", !!(tme->fpstate), !!(tme->vrstate), !!(tme->vsxstate)); From f2899a728cf2baf79655b5b2559f826af7c8452d Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 20 Jul 2017 12:08:34 -0400 Subject: [PATCH 0701/4375] compel/aarch64: glibc renamed ucontext to ucontext_t The upcoming glibc release renamed 'struct ucontext' to 'struct ucontext_t': https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=251287734e89a52da3db682a8241eb6bccc050c9;hp=c86ed71d633c22d6f638576f7660c52a5f783d66 Instead of using 'struct ucontext' this patch changes it to the typedef ucontext_t which already exists in older and new versions of glibc. Signed-off-by: Adrian Reber Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h b/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h index c890d1034..22246b8fa 100644 --- a/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h @@ -27,7 +27,7 @@ struct aux_context { struct rt_sigframe { siginfo_t info; - struct ucontext uc; + ucontext_t uc; uint64_t fp; uint64_t lr; }; From f07adae6905d10533928209637f003d025bf8140 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 20 Jul 2017 12:08:36 -0400 Subject: [PATCH 0702/4375] compel/s390: glibc renamed ucontext to ucontext_t The upcoming glibc release renamed 'struct ucontext' to 'struct ucontext_t': https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=251287734e89a52da3db682a8241eb6bccc050c9;hp=c86ed71d633c22d6f638576f7660c52a5f783d66 Instead of using 'struct ucontext' this patch changes it to the typedef ucontext_t which already exists in older and new versions of glibc. Signed-off-by: Adrian Reber Reviewed-by: Dmitry Safonov Reviewed-by: Michael Holzheu Signed-off-by: Andrei Vagin --- compel/arch/s390/src/lib/include/uapi/asm/sigframe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h b/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h index d04320241..47c39f642 100644 --- a/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h @@ -37,7 +37,7 @@ typedef struct { */ struct ucontext_extended { unsigned long uc_flags; - struct ucontext *uc_link; + ucontext_t *uc_link; stack_t uc_stack; _sigregs uc_mcontext; sigset_t uc_sigmask; From 7083f15351215eda1484f2509d1da36cb174bd86 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Thu, 10 Aug 2017 18:04:50 +0200 Subject: [PATCH 0703/4375] zdtm: Move include of Makefile.inc to right place We have to include Makefile.inc earlier in order to use SRCARCH. Signed-off-by: Michael Holzheu Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov --- test/zdtm/static/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 0dba4b454..cc1f348fe 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -174,6 +174,8 @@ TST_NOFILE := \ s390x_mmap_high \ # jobctl00 \ +include ../Makefile.inc + ifneq ($(SRCARCH),arm) ifneq ($(COMPAT_TEST),y) TST_NOFILE += maps03 @@ -315,8 +317,6 @@ OUT = $(TST:%=%.out) STATE = $(TST_STATE:%=%.state) STATE_OUT = $(TST_STATE:%=%.out) -include ../Makefile.inc - all: $(TST) criu-rtc.so install: all .PHONY: all install From 43ad17578075b6f1cec0431ba8542f6238f6226b Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Thu, 10 Aug 2017 18:04:51 +0200 Subject: [PATCH 0704/4375] s390/zdtm: Add s390x_reg_check test case This test can be used to verify FP and VX registers on s390: - Verify that "criu restore" sets the correct register sets from "criu dump": $ zdtmp.py run -t zdtm/static/s390x_regs_check - Verify that dumpee continues running with correct registers after parasite injection: $ zdtm.py run --norst -t zdtm/static/s390x_regs_check $ zdtm.py run --norst --pre 2 -t zdtm/static/s390x_regs_check $ zdtm.py run --check-only -t zdtm/static/s390x_regs_check Reviewed-by: Alice Frosi Signed-off-by: Michael Holzheu Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov --- test/zdtm/static/Makefile | 6 + test/zdtm/static/s390x_regs_check.c | 494 +++++++++++++++++++++++++ test/zdtm/static/s390x_regs_check.desc | 1 + 3 files changed, 501 insertions(+) create mode 100644 test/zdtm/static/s390x_regs_check.c create mode 100644 test/zdtm/static/s390x_regs_check.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index cc1f348fe..55f7b896d 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -182,6 +182,10 @@ ifneq ($(COMPAT_TEST),y) endif endif +ifeq ($(SRCARCH),s390) + TST_NOFILE += s390x_regs_check +endif + TST_FILE = \ maps06 \ write_read00 \ @@ -462,6 +466,8 @@ pty-console: CFLAGS += -D ZDTM_DEV_CONSOLE shm-unaligned: CFLAGS += -DZDTM_SHM_UNALIGNED +s390x_regs_check: LDFLAGS += -pthread + $(LIB): force $(Q) $(MAKE) -C $(LIBDIR) diff --git a/test/zdtm/static/s390x_regs_check.c b/test/zdtm/static/s390x_regs_check.c new file mode 100644 index 000000000..a92679ab0 --- /dev/null +++ b/test/zdtm/static/s390x_regs_check.c @@ -0,0 +1,494 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check that FP and VX registers do not change"; +const char *test_author = "Michael Holzheu "; + +/* + * This test case executes the following procedure: + * + * 1) Set registers to defined values + * The main process creates one child process and within that process + * NR_THREADS threads. Then the main process uses ptrace(SETREGS) to + * set the registers in the child process and in all threads. + * + * 2) Detach from child and threads + * Do this in order to allow criu to use ptrace for dumping. + * + * 3) Issue criu commands + * Useful tests are: dump, dump --check-only, dump --leave-running + * + * 4) Check registers + * Use ptrace(GETREGS) and compare with original values from step 1. + * + * This test can be used for two purposes: + * + * - Verify that "criu restore" sets the correct register sets + * from "criu dump": + * $ zdtmp.py run -t zdtm/static/s390x_regs_check + * + * - Verify that dumpee continues running with correct registers after + * parasite injection: + * $ zdtmp.py run --norst -t zdtm/static/s390x_regs_check + * $ zdtmp.py run --norst --pre 2 -t zdtm/static/s390x_regs_check + * $ zdtmp.py run --check-only -t zdtm/static/s390x_regs_check + */ +#define NR_THREADS 2 +#define NR_THREADS_ALL (NR_THREADS + 1) + +static pid_t thread_pids[NR_THREADS_ALL]; +static int pipefd[2]; + +/* + * Generic structure to define a register set and test data + */ +struct reg_set { + const char *name; /* Name of regset */ + int nr; /* Number of regset */ + void *data; /* Test data */ + int len; /* Number of bytes of test data */ + bool optional; /* Not all kernels/machines have this reg set */ + bool available; /* Current kernel/machine has this reg set */ +}; + +/* + * s390 floating point registers + */ +struct prfpreg { + uint32_t fpc; + uint64_t fprs[16]; +}; + +struct prfpreg prfpreg_data = { + .fpc = 0, + .fprs = { + 0x0000000000000000, + 0x1111111111111110, + 0x2222222222222220, + 0x3333333333333330, + 0x4444444444444440, + 0x5555555555555550, + 0x6666666666666660, + 0x7777777777777770, + 0x8888888888888880, + 0x9999999999999990, + 0xaaaaaaaaaaaaaaa0, + 0xbbbbbbbbbbbbbbb0, + 0xccccccccccccccc0, + 0xddddddddddddddd0, + 0xeeeeeeeeeeeeeee0, + 0xfffffffffffffff0, + } +}; + +struct reg_set reg_set_prfpreg = { + .name = "PRFPREG", + .nr = NT_PRFPREG, + .data = &prfpreg_data, + .len = sizeof(prfpreg_data), + .optional = false, +}; + +/* + * s390 vector VXRS_LOW registers + */ + +#define NT_S390_VXRS_LOW 0x309 + +struct vxrs_low { + uint64_t regs[16]; +}; + +struct vxrs_low vxrs_low_data = { + .regs = { + 0x0000000000000001, + 0x1111111111111111, + 0x2222222222222221, + 0x3333333333333331, + 0x4444444444444441, + 0x5555555555555551, + 0x6666666666666661, + 0x7777777777777771, + 0x8888888888888881, + 0x9999999999999991, + 0xaaaaaaaaaaaaaaa1, + 0xbbbbbbbbbbbbbbb1, + 0xccccccccccccccc1, + 0xddddddddddddddd1, + 0xeeeeeeeeeeeeeee1, + 0xfffffffffffffff1, + } +}; + +struct reg_set reg_set_vxrs_low = { + .name = "VXRS_LOW", + .nr = NT_S390_VXRS_LOW, + .data = &vxrs_low_data, + .len = sizeof(vxrs_low_data), + .optional = true, +}; + +/* + * s390 vector VXRS_HIGH registers + */ + +#define NT_S390_VXRS_HIGH 0x30a + +struct vxrs_high { + uint64_t regs[32]; +}; + +struct vxrs_high vxrs_high_data = { + .regs = { + 0x0000000000000002, 0x0000000000000002, + 0x1111111111111112, 0x1111111111111112, + 0x2222222222222222, 0x2222222222222222, + 0x3333333333333332, 0x3333333333333332, + 0x4444444444444442, 0x4444444444444442, + 0x5555555555555552, 0x5555555555555552, + 0x6666666666666662, 0x6666666666666662, + 0x7777777777777772, 0x7777777777777772, + 0x8888888888888882, 0x8888888888888882, + 0x9999999999999992, 0x9999999999999992, + 0xaaaaaaaaaaaaaaa2, 0xaaaaaaaaaaaaaaa2, + 0xbbbbbbbbbbbbbbb2, 0xbbbbbbbbbbbbbbb2, + 0xccccccccccccccc2, 0xccccccccccccccc2, + 0xddddddddddddddd2, 0xddddddddddddddd2, + 0xeeeeeeeeeeeeeee2, 0xeeeeeeeeeeeeeee2, + 0xfffffffffffffff2, 0xfffffffffffffff2, + } +}; + +struct reg_set reg_set_vxrs_high = { + .name = "VXRS_HIGH", + .nr = NT_S390_VXRS_HIGH, + .data = &vxrs_high_data, + .len = sizeof(vxrs_high_data), + .optional = true, +}; + +/* + * Vector with all regsets + */ +struct reg_set *reg_set_vec[] = { + ®_set_prfpreg, + ®_set_vxrs_low, + ®_set_vxrs_high, + NULL, +}; + +/* + * Print hexdump for buffer with variable group parameter + */ +void util_hexdump_grp(const char *tag, const void *data, int grp, + int count, int indent) +{ + const char *buf = data; + char str[1024], *ptr; + int i, first = 1; + + for (i = 0; i < count; i++) { + if (first) { + ptr = str; + ptr += sprintf(ptr, "%*s", indent, " "); + if (tag) + ptr += sprintf(ptr, "%s: ", tag); + ptr += sprintf(ptr, "%08x: ", i); + first = 0; + } + ptr += sprintf(ptr, "%02x", buf[i]); + if (i % 16 == 15 || i + 1 == count) { + test_msg("%s\n", str); + first = 1; + } else if (i % grp == grp - 1) { + ptr += sprintf(ptr, " "); + } + } +} + +/* + * Print hexdump for buffer with fix grp parameter + */ +void util_hexdump(const char *tag, const void *data, int count) +{ + util_hexdump_grp(tag, data, sizeof(long), count, 0); +} + +/* + * Set regset for pid + */ +static int set_regset(pid_t pid, struct reg_set *reg_set) +{ + struct iovec iov; + + iov.iov_base = reg_set->data; + iov.iov_len = reg_set->len; + + if (ptrace(PTRACE_SETREGSET, pid, reg_set->nr, iov) == 0) { + test_msg(" REGSET: %12s -> DONE\n", reg_set->name); + reg_set->available = true; + return 0; + } + if (reg_set->optional) { + switch (errno) { + case ENODEV: + test_msg(" REGSET: %12s -> not supported by machine\n", + reg_set->name); + return 0; + case EINVAL: + test_msg(" REGSET: %12s -> not supported by kernel\n", + reg_set->name); + return 0; + default: + break; + } + } + pr_perror("PTRACE_SETREGSET for %s failed for pid %d", + reg_set->name, pid); + return -1; +} + +/* + * Apply all regsets + */ +static int set_regset_all(pid_t pid) +{ + int i; + + for (i = 0; reg_set_vec[i] != NULL; i++) { + if (set_regset(pid, reg_set_vec[i])) + return -1; + } + return 0; +} + +/* + * Check if regset for pid has changed + */ +static int check_regset(pid_t pid, struct reg_set *reg_set) +{ + struct iovec iov; + char *data; + + if (!reg_set->available) + return 0; + data = calloc(reg_set->len, 1); + if (!data) + return -1; + + iov.iov_base = data; + iov.iov_len = reg_set->len; + + if (ptrace(PTRACE_GETREGSET, pid, reg_set->nr, iov) != 0) { + pr_perror("PTRACE_SETREGSET for %s failed for pid %d", + reg_set->name, pid); + free(data); + return -1; + } + if (memcmp(data, reg_set->data, reg_set->len) != 0) { + test_msg("RegSet %s changed for pid=%d\n", reg_set->name, pid); + test_msg("Original values:\n"); + util_hexdump(reg_set->name, reg_set->data, reg_set->len); + test_msg("New values:\n"); + util_hexdump(reg_set->name, data, reg_set->len); + free(data); + return -1; + } + free(data); + return 0; +} + +/* + * Check all regsets + */ +static int check_regset_all(pid_t pid) +{ + int i; + + for (i = 0; reg_set_vec[i] != NULL; i++) { + if (check_regset(pid, reg_set_vec[i])) + return -1; + } + return 0; +} + +/* + * Send error to father + */ +static void send_error(void) +{ + int val = 0; + + if (write(pipefd[1], &val, sizeof(val)) == -1) + pr_perror("write failed"); +} + +/* + * Write tid to pipe and then loop without changing registers + */ +static inline void send_tid_and_loop(int fd) +{ + int tid = syscall(__NR_gettid); + + asm volatile( + "lgr 2,%0\n" /* Arg 1: fd */ + "la 3,%1\n" /* Arg 2: &tid */ + "lghi 4,4\n" /* Arg 3: sizeof(int) */ + "svc 4\n" /* __NR_write SVC: */ + /* After SVC no more registers are changed */ + "0: j 0b\n" /* Loop here */ + : : "d" (fd), "Q" (tid) : "2", "3", "4"); +} + +/* + * Function for threads + */ +static void *thread_func(void *fd) +{ + send_tid_and_loop(pipefd[1]); + return NULL; +} + +/* + * Function executed by the child + */ +static void child_func(void) +{ + pthread_t thread; + int i; + + /* Close read end of pipe */ + close(pipefd[0]); + /* Create threads and send TID */ + for (i = 0; i < NR_THREADS; i++) { + if (pthread_create(&thread, NULL, thread_func, NULL) != 0) { + pr_perror("Error create thread: %d", i); + send_error(); + } + } + /* Send tid and wait until get killed */ + send_tid_and_loop(pipefd[1]); +} + +/* + * Attach to a thread + */ +static int ptrace_attach(pid_t pid) +{ + if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) { + wait(NULL); + return 0; + } + pr_perror("Attach to thread %d failed", pid); + return -1; +} + +/* + * Detach from a thread + */ +static int ptrace_detach(pid_t pid) +{ + if (ptrace(PTRACE_DETACH, pid, 0, 0) == 0) + return 0; + pr_perror("Detach from thread %d failed", pid); + return -1; +} + +/* + * Create child with threads and verify that registers are not corrupted + */ +int main(int argc, char *argv[]) +{ + bool failed = false; + pid_t child, pid; + int i; + + test_init(argc, argv); + + test_msg("------------- START 1 PROCESS + %d THREADS ---------------\n", + NR_THREADS); + if (pipe(pipefd) == -1) { + perror("pipe failed"); + exit(EXIT_FAILURE); + } + child = fork(); + + if (child == 0) + child_func(); + + /* Parent */ + for (i = 0; i < NR_THREADS_ALL; i++) { + if (read(pipefd[0], &pid, sizeof(pid_t)) == -1) { + perror("Read from pipe failed"); + failed = true; + goto kill_all_threads; + } + if (pid == 0) { + pr_err("Not all threads are started\n"); + failed = true; + goto kill_all_threads; + } + test_msg("STARTED: pid = %d\n", pid); + thread_pids[i] = pid; + } + + /* Close write end */ + close(pipefd[1]); + test_msg("---------------------- SET REGISTERS --------------------\n"); + for (i = 0; i < NR_THREADS_ALL; i++) { + pid = thread_pids[i]; + test_msg("SET: pid = %d\n", pid); + ptrace_attach(pid); + set_regset_all(pid); + ptrace_detach(pid); + } + + test_daemon(); + test_waitsig(); + + test_msg("-------------------- CHECK REGISTERS --------------------\n"); + for (i = 0; i < NR_THREADS_ALL; i++) { + pid = thread_pids[i]; + test_msg("CHECK: pid = %d:\n", pid); + ptrace_attach(pid); + if (check_regset_all(pid) == 0) { + test_msg(" -> OK\n"); + } else { + test_msg(" -> FAIL\n"); + failed = true; + } + ptrace_detach(pid); + } + test_msg("----------------------- CLEANUP ------------------------\n"); + +kill_all_threads: + for (i = 0; i < NR_THREADS_ALL; i++) { + pid = thread_pids[i]; + if (pid == 0) + continue; + test_msg("KILL: pid = %d\n", pid); + kill(pid, SIGTERM); + } + + if (failed) { + fail("Registers changed"); + return 1; + } + pass(); + return 0; +} diff --git a/test/zdtm/static/s390x_regs_check.desc b/test/zdtm/static/s390x_regs_check.desc new file mode 100644 index 000000000..8621263f2 --- /dev/null +++ b/test/zdtm/static/s390x_regs_check.desc @@ -0,0 +1 @@ +{'arch': 's390x'} From 1ea1fdde45653833ddf35faedd583bac12156206 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Thu, 10 Aug 2017 18:04:52 +0200 Subject: [PATCH 0705/4375] compel: Save thread registers before executing parasite code For dumping threads we execute parasite code before we collect the floating point registers with get_task_regs(). The following describes the code path were this is done: dump_task_threads() for (i = 0; i < item->nr_threads; i++) dump_task_thread() parasite_dump_thread_seized() compel_prepare_thread() prepare_thread() ### Get general purpose registers ### ptrace_get_regs(ctx->regs) ### parasite code is executed in thread ### compel_run_in_thread(tctl, PARASITE_CMD_DUMP_THREAD) compel_get_thread_regs() ### Get FP and VX registers ### get_task_regs() Since on s390 gcc uses floating point registers to cache general purpose without the -msoft-float option the floating point registers would have been clobbered after compel_run_in_thread(). With this patch we first save all thread registers with task_get_regs() and then call the parasite code. We introduce a new function arch_set_thread_regs() that restores the saved registers for all threads. This is necessary for criu dump --leave-running, --check-only, and error handling. Pre-dump does not require to save the registers for the threads because because only the main thread (task) is used for parsite code execution. The above changes allow us to use all register sets in the parasite code - therefore we can remove -msoft-float on s390. Reviewed-by: Michael Holzheu Signed-off-by: Alice Frosi Reviewed-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov --- Makefile | 8 +- compel/arch/s390/src/lib/infect.c | 26 ------- criu/arch/s390/crtools.c | 109 +++++++++++++++++++++++++++ criu/arch/s390/include/asm/restore.h | 2 - criu/cr-dump.c | 10 +++ criu/parasite-syscall.c | 11 ++- 6 files changed, 126 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index ad052f158..f2583a272 100644 --- a/Makefile +++ b/Makefile @@ -68,11 +68,7 @@ endif # # CFLAGS_PIE: # -# We assume that compel code does not change floating point registers. -# On s390 gcc uses fprs to cache gprs. Therefore disable floating point -# with -msoft-float. -# -# Also ensure with -fno-optimize-sibling-calls that we don't create GOT +# Ensure with -fno-optimize-sibling-calls that we don't create GOT # (Global Offset Table) relocations with gcc compilers that don't have # commit "S/390: Fix 64 bit sibcall". ifeq ($(ARCH),s390) @@ -80,7 +76,7 @@ ifeq ($(ARCH),s390) SRCARCH := s390 VDSO := y DEFINES := -DCONFIG_S390 - CFLAGS_PIE := -msoft-float -fno-optimize-sibling-calls + CFLAGS_PIE := -fno-optimize-sibling-calls endif export CFLAGS_PIE diff --git a/compel/arch/s390/src/lib/infect.c b/compel/arch/s390/src/lib/infect.c index 1614fa60e..3c1fff68c 100644 --- a/compel/arch/s390/src/lib/infect.c +++ b/compel/arch/s390/src/lib/infect.c @@ -148,32 +148,6 @@ int get_vx_regs(pid_t pid, user_fpregs_struct_t *fpregs) return 0; } -/* - * Set vector registers - */ -int set_vx_regs(pid_t pid, user_fpregs_struct_t *fpregs) -{ - struct iovec iov; - int rc; - - if (!(fpregs->flags & USER_FPREGS_VXRS)) - return 0; - - iov.iov_base = &fpregs->vxrs_low; - iov.iov_len = sizeof(fpregs->vxrs_low); - rc = ptrace(PTRACE_SETREGSET, pid, NT_S390_VXRS_LOW, &iov); - if (rc) { - pr_perror("Couldn't set VXRS_LOW registers\n"); - return rc; - } - - iov.iov_base = &fpregs->vxrs_high; - iov.iov_len = sizeof(fpregs->vxrs_high); - rc = ptrace(PTRACE_SETREGSET, pid, NT_S390_VXRS_HIGH, &iov); - if (rc) - pr_perror("Couldn't set VXRS_HIGH registers\n"); - return rc; -} /* * Prepare task registers for restart diff --git a/criu/arch/s390/crtools.c b/criu/arch/s390/crtools.c index 4bd21ec97..cfab50868 100644 --- a/criu/arch/s390/crtools.c +++ b/criu/arch/s390/crtools.c @@ -22,6 +22,12 @@ #include "protobuf.h" #include "images/core.pb-c.h" #include "images/creds.pb-c.h" +#include "ptrace.h" +#include "pstree.h" + +#define NT_PRFPREG 2 +#define NT_S390_VXRS_LOW 0x309 +#define NT_S390_VXRS_HIGH 0x30a /* * Print general purpose and access registers @@ -339,3 +345,106 @@ void arch_free_thread_info(CoreEntry *core) xfree(CORE_THREAD_ARCH_INFO(core)); CORE_THREAD_ARCH_INFO(core) = NULL; } + +/* + * Set regset for pid + */ +static int setregset(int pid, int set, const char *set_str, struct iovec *iov) +{ + if (ptrace(PTRACE_SETREGSET, pid, set, iov) == 0) + return 0; + pr_perror("Couldn't set %s registers for pid %d", set_str, pid); + return -1; +} + +/* + * Set floating point registers for pid from fpregs + */ +static int set_fp_regs(pid_t pid, user_fpregs_struct_t *fpregs) +{ + struct iovec iov; + + iov.iov_base = &fpregs->prfpreg; + iov.iov_len = sizeof(fpregs->prfpreg); + return setregset(pid, NT_PRFPREG, "PRFPREG", &iov); +} + +/* + * Set vector registers + */ +static int set_vx_regs(pid_t pid, user_fpregs_struct_t *fpregs) +{ + struct iovec iov; + + if (!(fpregs->flags & USER_FPREGS_VXRS)) + return 0; + + iov.iov_base = &fpregs->vxrs_low; + iov.iov_len = sizeof(fpregs->vxrs_low); + if (setregset(pid, NT_S390_VXRS_LOW, "S390_VXRS_LOW", &iov)) + return -1; + + iov.iov_base = &fpregs->vxrs_high; + iov.iov_len = sizeof(fpregs->vxrs_high); + return setregset(pid, NT_S390_VXRS_HIGH, "S390_VXRS_HIGH", &iov); +} + +/* + * Restore registers for pid from core + */ +static int set_task_regs(pid_t pid, CoreEntry *core) +{ + UserS390VxrsHighEntry *cvxrs_high; + UserS390VxrsLowEntry *cvxrs_low; + UserS390FpregsEntry *cfpregs; + user_fpregs_struct_t fpregs; + + memset(&fpregs, 0, sizeof(fpregs)); + /* Floating point registers */ + cfpregs = CORE_THREAD_ARCH_INFO(core)->fpregs; + if (!cfpregs) + return -1; + fpregs.prfpreg.fpc = cfpregs->fpc; + memcpy(fpregs.prfpreg.fprs, cfpregs->fprs, sizeof(fpregs.prfpreg.fprs)); + if (set_fp_regs(pid, &fpregs) < 0) + return -1; + /* Vector registers (optional) */ + cvxrs_low = CORE_THREAD_ARCH_INFO(core)->vxrs_low; + if (!cvxrs_low) + return 0; + cvxrs_high = CORE_THREAD_ARCH_INFO(core)->vxrs_high; + if (!cvxrs_high) + return -1; + fpregs.flags |= USER_FPREGS_VXRS; + memcpy(&fpregs.vxrs_low, cvxrs_low->regs, sizeof(fpregs.vxrs_low)); + memcpy(&fpregs.vxrs_high, cvxrs_high->regs, sizeof(fpregs.vxrs_high)); + + return set_vx_regs(pid, &fpregs); +} + +/* + * Restore vector and floating point registers for all threads + */ +int arch_set_thread_regs(struct pstree_item *item) +{ + int i; + + for_each_pstree_item(item) { + if (item->pid->state == TASK_DEAD || + item->pid->state == TASK_ZOMBIE || + item->pid->state == TASK_HELPER) + continue; + for (i = 0; i < item->nr_threads; i++) { + if (item->threads[i]->state == TASK_DEAD || + item->threads[i]->state == TASK_ZOMBIE) + continue; + if (set_task_regs(item->threads[i]->real, + item->core[i])) { + pr_perror("Not set registers for task %d", + item->threads[i]->real); + return -1; + } + } + } + return 0; +} diff --git a/criu/arch/s390/include/asm/restore.h b/criu/arch/s390/include/asm/restore.h index 96358ffc3..6463d8e62 100644 --- a/criu/arch/s390/include/asm/restore.h +++ b/criu/arch/s390/include/asm/restore.h @@ -4,7 +4,6 @@ #include "asm/restorer.h" #include "images/core.pb-c.h" - /* * Load stack to %r15, return address in %r14 and argument 1 into %r2 */ @@ -25,5 +24,4 @@ #define core_get_tls(pcore, ptls) int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core); - #endif diff --git a/criu/cr-dump.c b/criu/cr-dump.c index a5682df99..f9ff0f468 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -83,6 +83,15 @@ #include "fault-injection.h" #include "dump.h" +/* + * Architectures can overwrite this function to restore register sets that + * are not covered by ptrace_set/get_regs(). + */ +int __attribute__((weak)) arch_set_thread_regs(struct pstree_item *item) +{ + return 0; +} + static char loc_buf[PAGE_SIZE]; void free_mappings(struct vm_area_list *vma_area_list) @@ -1641,6 +1650,7 @@ static int cr_dump_finish(int ret) delete_link_remaps(); clean_cr_time_mounts(); } + arch_set_thread_regs(root_item); pstree_switch_state(root_item, (ret || post_dump_ret) ? TASK_ALIVE : opts.final_state); diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 3afc7b651..8ace6ad66 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -186,6 +186,11 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, tc->has_blk_sigset = true; memcpy(&tc->blk_sigset, compel_thread_sigmask(tctl), sizeof(k_rtsigset_t)); + ret = compel_get_thread_regs(tctl, save_task_regs, core); + if (ret) { + pr_err("Can't obtain regs for thread %d\n", pid); + goto err_rth; + } ret = compel_run_in_thread(tctl, PARASITE_CMD_DUMP_THREAD); if (ret) { @@ -199,12 +204,6 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, goto err_rth; } - ret = compel_get_thread_regs(tctl, save_task_regs, core); - if (ret) { - pr_err("Can't obtain regs for thread %d\n", pid); - goto err_rth; - } - compel_release_thread(tctl); tid->ns[0].virt = args->tid; From 3842c6341da9b12103681a19835bf3c28c3eba1c Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 5 Jun 2017 20:24:09 +0300 Subject: [PATCH 0706/4375] shmem: Remove pid argument of shmem_wait_and_open() It's unused and it's rewritten in shmem_wait_and_open(), and it just confuses a reader. So, kill it. Signed-off-by: Kirill Tkhai --- criu/shmem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/shmem.c b/criu/shmem.c index 69165b64c..af3b4c8f5 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -436,7 +436,7 @@ int collect_shmem(int pid, struct vma_area *vma) return 0; } -static int shmem_wait_and_open(int pid, struct shmem_info *si, VmaEntry *vi) +static int shmem_wait_and_open(struct shmem_info *si, VmaEntry *vi) { char path[128]; int ret; @@ -515,7 +515,7 @@ static int open_shmem(int pid, struct vma_area *vma) BUG_ON(si->pid == SYSVIPC_SHMEM_PID); if (si->pid != pid) - return shmem_wait_and_open(pid, si, vi); + return shmem_wait_and_open(si, vi); if (si->fd != -1) { f = dup(si->fd); From a7b381d1fc4c85260333cd38aaa5211609af30a2 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 16 Jun 2017 18:19:04 +0300 Subject: [PATCH 0707/4375] net: Relax xmalloc-ing (and fix NULL deref) There's potential NULL-derefernece in dump_netns_con() -- two xmalloc results are not checked. However, since there's a huge set of these xmallocs, I propose to relax the whole thing with one big xmalloc and xptr_pull() helper. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/net.c | 50 ++++++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/criu/net.c b/criu/net.c index e4bb9b203..936611de8 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1394,6 +1394,7 @@ static inline int dump_iptables(struct cr_imgset *fds) static int dump_netns_conf(struct cr_imgset *fds) { + void *buf, *o_buf; int ret = -1; int i; NetnsEntry netns = NETNS_ENTRY__INIT; @@ -1404,20 +1405,19 @@ static int dump_netns_conf(struct cr_imgset *fds) char def_stable_secret[MAX_STR_CONF_LEN + 1] = {}; char all_stable_secret[MAX_STR_CONF_LEN + 1] = {}; + o_buf = buf = xmalloc( + size4 * (sizeof(SysctlEntry*) + sizeof(SysctlEntry)) * 2 + + size6 * (sizeof(SysctlEntry*) + sizeof(SysctlEntry)) * 2 + ); + if (!buf) + goto out; + netns.n_def_conf4 = size4; netns.n_all_conf4 = size4; - netns.def_conf4 = xmalloc(sizeof(SysctlEntry *) * size4); - if (!netns.def_conf4) - goto err_free; - netns.all_conf4 = xmalloc(sizeof(SysctlEntry *) * size4); - if (!netns.all_conf4) - goto err_free; - def_confs4 = xmalloc(sizeof(SysctlEntry) * size4); - if (!def_confs4) - goto err_free; - all_confs4 = xmalloc(sizeof(SysctlEntry) * size4); - if (!all_confs4) - goto err_free; + netns.def_conf4 = xptr_pull_s(&buf, size4 * sizeof(SysctlEntry*)); + netns.all_conf4 = xptr_pull_s(&buf, size4 * sizeof(SysctlEntry*)); + def_confs4 = xptr_pull_s(&buf, size4 * sizeof(SysctlEntry)); + all_confs4 = xptr_pull_s(&buf, size4 * sizeof(SysctlEntry)); for (i = 0; i < size4; i++) { sysctl_entry__init(&def_confs4[i]); @@ -1430,18 +1430,10 @@ static int dump_netns_conf(struct cr_imgset *fds) netns.n_def_conf6 = size6; netns.n_all_conf6 = size6; - netns.def_conf6 = xmalloc(sizeof(SysctlEntry *) * size6); - if (!netns.def_conf6) - goto err_free; - netns.all_conf6 = xmalloc(sizeof(SysctlEntry *) * size6); - if (!netns.all_conf6) - goto err_free; - def_confs6 = xmalloc(sizeof(SysctlEntry) * size6); - if (!def_confs6) - goto err_free; - all_confs6 = xmalloc(sizeof(SysctlEntry) * size6); - if (!all_confs6) - goto err_free; + netns.def_conf6 = xptr_pull_s(&buf, size6 * sizeof(SysctlEntry*)); + netns.all_conf6 = xptr_pull_s(&buf, size6 * sizeof(SysctlEntry*)); + def_confs6 = xptr_pull_s(&buf, size6 * sizeof(SysctlEntry)); + all_confs6 = xptr_pull_s(&buf, size6 * sizeof(SysctlEntry)); for (i = 0; i < size6; i++) { sysctl_entry__init(&def_confs6[i]); @@ -1475,14 +1467,8 @@ static int dump_netns_conf(struct cr_imgset *fds) ret = pb_write_one(img_from_set(fds, CR_FD_NETNS), &netns, PB_NETNS); err_free: - xfree(netns.def_conf4); - xfree(netns.all_conf4); - xfree(def_confs4); - xfree(all_confs4); - xfree(netns.def_conf6); - xfree(netns.all_conf6); - xfree(def_confs6); - xfree(all_confs6); + xfree(o_buf); +out: return ret; } From d1bc0b85f04ef608ce6762520be32a8a8b24fd71 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 27 Jun 2017 06:50:43 +0300 Subject: [PATCH 0708/4375] kerndat: include config.h before using CONFIG_* contants Otherwise someone can include kerndat.h before config.h and get another kerndat structure. For example, proc_parse doesn't include config.h and Cyrill met this problem. Cc: Dmitry Safonov Cc: Cyrill Gorcunov Signed-off-by: Andrei Vagin Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/kerndat.h | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 295fcd473..c27ece017 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -4,6 +4,7 @@ #include #include "int.h" +#include "config.h" struct stat; From a6543ce2bbca02720feba8c9a3ce8254d116b8e6 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 28 Jun 2017 09:43:23 +0300 Subject: [PATCH 0709/4375] mem: kill trailing whitespace Acked-by: Pavel Emelyanov Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/mem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/mem.c b/criu/mem.c index 697920f47..f88aaca27 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -662,7 +662,7 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void /* * All mappings here get PROT_WRITE regardless of whether we * put any data into it or not, because this area will get - * mremap()-ed (branch below) so we MIGHT need to have WRITE + * mremap()-ed (branch below) so we MIGHT need to have WRITE * bits there. Ideally we'd check for the whole COW-chain * having any data in. */ @@ -680,8 +680,8 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void /* * The area in question can be COWed with the parent. Remap the - * parent area. Note, that it has already being passed through - * the restore_priv_vma_content() call and thus may have some + * parent area. Note, that it has already being passed through + * the restore_priv_vma_content() call and thus may have some * pages in it. */ From 1db93b6ea9e1a045482141173c98519c1761344c Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 12 Jul 2017 20:30:26 +0300 Subject: [PATCH 0710/4375] files: Add comments about FLE_* stages Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/include/files.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/criu/include/files.h b/criu/include/files.h index 9f65fa634..419e50dd3 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -66,7 +66,16 @@ struct file_desc; enum { FLE_INITIALIZED, + /* + * FLE is open (via open() or socket() or etc syscalls), and + * common file setting are set up (type-specific are not yet). + * Most possible, the master was already served out. + */ FLE_OPEN, + /* + * File-type specific settings and preparations are finished, + * and FLE is completely restored. + */ FLE_RESTORED, }; From 5d6392358d29d130615c5c86662dd8bd6b3803b5 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 5 Jul 2017 20:23:48 +0300 Subject: [PATCH 0711/4375] test/zdtm.py: ignore UNIX sockets during report creation When files are added to the report shutil.copytree is unhappy with lazy-pages.socket. Tell shutil.copytree that it should ignore *.socket. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 79f1a099a..5f816034f 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -83,8 +83,9 @@ def add_to_report(path, tgt_name): tgt_path = os.path.join(report_dir, tgt_name + ".%d" % att) att += 1 + ignore = shutil.ignore_patterns('*.socket') if os.path.isdir(path): - shutil.copytree(path, tgt_path) + shutil.copytree(path, tgt_path, ignore = ignore) else: if not os.path.exists(os.path.dirname(tgt_path)): os.mkdir(os.path.dirname(tgt_path)) From 5f09c258d1d7b9dbe4ab68e3e517105d7896bb5b Mon Sep 17 00:00:00 2001 From: Francesco Giancane Date: Tue, 27 Jun 2017 21:28:09 +0200 Subject: [PATCH 0712/4375] make: Makefile variable 'PREFIX' should be configurable. I tried to build and install the criu package from source. All went well, unless for the install part. In particular, PREFIX=/ DESTDIR=~/build_criu PREFIX=${PREFIX} DESTDIR=${DESTDIR} make install resulted in installing criu packages in ~/build_criu/usr/local/, ignoring PREFIX, even if this variable should be configurable as of manual and GCS. Reviewed-by: Dmitry Safonov Signed-off-by: Francesco Giancane Signed-off-by: Andrei Vagin --- Makefile.install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.install b/Makefile.install index 979ef0dc1..3606e1e1c 100644 --- a/Makefile.install +++ b/Makefile.install @@ -1,6 +1,6 @@ # # Installation paths. -PREFIX := /usr/local +PREFIX ?= /usr/local BINDIR := $(PREFIX)/bin SBINDIR := $(PREFIX)/sbin MANDIR := $(PREFIX)/share/man From 833fa4d7db6aed254053f2e675a69d7b17d0b2b9 Mon Sep 17 00:00:00 2001 From: Francesco Giancane Date: Tue, 27 Jun 2017 23:05:57 +0200 Subject: [PATCH 0713/4375] Make the Makefile variables externally configurable. As of manual page INSTALL.md, it is stated that those variables can be overridden by means of environmental variables. export BINDIR="somedir" export SBINDIR="somedir" export LIBDIR="somedir" export MANDIR="somedir" export INCLUDEDIR="somedir" export LIBEXECDIR="somedir" make install But those settings will not be honored, sticking to default Makefile values. This patch fixes the issue. Signed-off-by: Francesco Giancane Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile.install | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Makefile.install b/Makefile.install index 3606e1e1c..3987bcc6f 100644 --- a/Makefile.install +++ b/Makefile.install @@ -1,27 +1,30 @@ # # Installation paths. PREFIX ?= /usr/local -BINDIR := $(PREFIX)/bin -SBINDIR := $(PREFIX)/sbin -MANDIR := $(PREFIX)/share/man -LIBDIR := $(PREFIX)/lib -INCLUDEDIR := $(PREFIX)/include -LIBEXECDIR := $(PREFIX)/libexec +BINDIR ?= $(PREFIX)/bin +SBINDIR ?= $(PREFIX)/sbin +MANDIR ?= $(PREFIX)/share/man +INCLUDEDIR ?= $(PREFIX)/include +LIBEXECDIR ?= $(PREFIX)/libexec RUNDIR ?= /run # # For recent Debian/Ubuntu with multiarch support. DEB_HOST_MULTIARCH := $(shell dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null) ifneq "$(DEB_HOST_MULTIARCH)" "" - LIBDIR := $(PREFIX)/lib/$(DEB_HOST_MULTIARCH) + LIBDIR ?= $(PREFIX)/lib/$(DEB_HOST_MULTIARCH) else # # For most other systems ifeq "$(shell uname -m)" "x86_64" - LIBDIR := $(PREFIX)/lib64 + LIBDIR ?= $(PREFIX)/lib64 endif endif +# +# LIBDIR falls back to the standard path. +LIBDIR ?= $(PREFIX)/lib + export PREFIX BINDIR SBINDIR MANDIR RUNDIR export LIBDIR INCLUDEDIR LIBEXECDIR From 9152dd219813438addd34d4924f8f62af6499800 Mon Sep 17 00:00:00 2001 From: Vitaly Ostrosablin Date: Thu, 20 Jul 2017 18:04:01 +0300 Subject: [PATCH 0714/4375] test: remap_dead_pid.c: Fix child PID not being printed There's two issues with this code: 1. Child task is killed by parent faster, than it could print the line. 2. Even if it had time to print it - there would always be 0, because it's called from child process. Obviously, this print was meant to be in parent process. So, let's move it there. Signed-off-by: Vitaly Ostrosablin Signed-off-by: Andrei Vagin --- test/zdtm/static/remap_dead_pid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/remap_dead_pid.c b/test/zdtm/static/remap_dead_pid.c index 1ee61a9d0..261c591b7 100644 --- a/test/zdtm/static/remap_dead_pid.c +++ b/test/zdtm/static/remap_dead_pid.c @@ -35,12 +35,13 @@ int main(int argc, char **argv) } if (pid == 0) { - test_msg("child is %d\n", pid); /* Child process just sleeps until it is killed. All we need * here is a process to open the mountinfo of. */ while(1) sleep(10); } else { + test_msg("child is %d\n", pid); + int fd, ret; char path[PATH_MAX]; pid_t result; From b34efd5591279f41816277b40348be29696befe8 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 26 Jul 2017 18:06:25 +0300 Subject: [PATCH 0715/4375] test/zdtm.py: allow setting test timeout in the test description Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 5f816034f..3a546c5cd 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -364,6 +364,7 @@ class zdtm_test: self._env = {} self._deps = desc.get('deps', []) self.auto_reap = True + self.__timeout = int(self.__desc.get('timeout') or 30) def __make_action(self, act, env = None, root = None): sys.stdout.flush() # Not to let make's messages appear before ours @@ -388,7 +389,7 @@ class zdtm_test: return self.__name + '.pid' def __wait_task_die(self): - wait_pid_die(int(self.__pid), self.__name) + wait_pid_die(int(self.__pid), self.__name, self.__timeout) def __add_wperms(self): # Add write perms for .out and .pid files From ae7a9a0758030731b15e563fef4ee2c40857da0d Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 26 Jul 2017 18:06:26 +0300 Subject: [PATCH 0716/4375] test/zdtm: set maps04 timeout to 60 seconds Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm/static/maps04.desc | 1 + 1 file changed, 1 insertion(+) create mode 100644 test/zdtm/static/maps04.desc diff --git a/test/zdtm/static/maps04.desc b/test/zdtm/static/maps04.desc new file mode 100644 index 000000000..02c30c4c3 --- /dev/null +++ b/test/zdtm/static/maps04.desc @@ -0,0 +1 @@ +{'timeout': '60'} From ac05c73a7b45f5923cc41708fb92bb940a2f6f9b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 14 Jul 2017 18:30:57 +0300 Subject: [PATCH 0717/4375] page-server: Fix incompatibility of page server protocol It turned out (surprise surprise) that page server exchanges CR_FD_PAGEMAP and CR_FD_SHMEM_PAGEMAP values in ps_iov_msg. The problem is that these constants sit in enum and change their values from version to version %) So here's the fixed version of the protocol including the backward compat checks on all the values that could be met from older CRIUs (we're lucky and they didn't intersect). Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 436c41c2c..5a3b2790c 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -45,14 +45,61 @@ static void psi2iovec(struct page_server_iov *ps, struct iovec *iov) #define PS_TYPE_BITS 8 #define PS_TYPE_MASK ((1 << PS_TYPE_BITS) - 1) +#define PS_TYPE_PID (1) +#define PS_TYPE_SHMEM (2) +/* + * XXX: When adding new types here check decode_pm_type for legacy + * numbers that can be met from older CRIUs + */ + static inline u64 encode_pm_id(int type, long id) { + if (type == CR_FD_PAGEMAP) + type = PS_TYPE_PID; + else if (type == CR_FD_SHMEM_PAGEMAP) + type = PS_TYPE_SHMEM; + else { + BUG(); + return 0; + } + return ((u64)id) << PS_TYPE_BITS | type; } static int decode_pm_type(u64 dst_id) { - return dst_id & PS_TYPE_MASK; + int type; + + /* + * Magic numbers below came from the older CRIU versions that + * errorneously used the changing CR_FD_* constants. The + * changes were made when we merged images together and moved + * the CR_FD_-s at the tail of the enum + */ + type = dst_id & PS_TYPE_MASK; + switch (type) { + case 10: /* 3.1 3.2 */ + case 11: /* 1.3 1.4 1.5 1.6 1.7 1.8 2.* 3.0 */ + case 16: /* 1.2 */ + case 17: /* 1.0 1.1 */ + case PS_TYPE_PID: + type = CR_FD_PAGEMAP; + break; + case 27: /* 1.3 */ + case 28: /* 1.4 1.5 */ + case 29: /* 1.6 1.7 */ + case 32: /* 1.2 1.8 */ + case 33: /* 1.0 1.1 3.1 3.2 */ + case 34: /* 2.* 3.0 */ + case PS_TYPE_SHMEM: + type = CR_FD_SHMEM_PAGEMAP; + break; + default: + type = -1; + break; + } + + return type; } static long decode_pm_id(u64 dst_id) @@ -435,6 +482,11 @@ static int page_server_check_parent(int sk, struct page_server_iov *pi) type = decode_pm_type(pi->dst_id); id = decode_pm_id(pi->dst_id); + if (type == -1) { + pr_err("Unknown pagemap type received\n"); + return -1; + } + ret = check_parent_local_xfer(type, id); if (ret < 0) return -1; @@ -502,6 +554,11 @@ static int page_server_open(int sk, struct page_server_iov *pi) type = decode_pm_type(pi->dst_id); id = decode_pm_id(pi->dst_id); + if (type == -1) { + pr_err("Unknown pagemap type received\n"); + return -1; + } + pr_info("Opening %d/%ld\n", type, id); page_server_close(); From 943df7d6121f17f3a723956bcd4756f6282a1bc8 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 14 Jul 2017 18:31:22 +0300 Subject: [PATCH 0718/4375] page-server: Tune up the encode/decode helpers Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 5a3b2790c..7ee606344 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -48,11 +48,11 @@ static void psi2iovec(struct page_server_iov *ps, struct iovec *iov) #define PS_TYPE_PID (1) #define PS_TYPE_SHMEM (2) /* - * XXX: When adding new types here check decode_pm_type for legacy + * XXX: When adding new types here check decode_pm for legacy * numbers that can be met from older CRIUs */ -static inline u64 encode_pm_id(int type, long id) +static inline u64 encode_pm(int type, long id) { if (type == CR_FD_PAGEMAP) type = PS_TYPE_PID; @@ -66,7 +66,7 @@ static inline u64 encode_pm_id(int type, long id) return ((u64)id) << PS_TYPE_BITS | type; } -static int decode_pm_type(u64 dst_id) +static int decode_pm(u64 dst_id, long *id) { int type; @@ -83,6 +83,7 @@ static int decode_pm_type(u64 dst_id) case 16: /* 1.2 */ case 17: /* 1.0 1.1 */ case PS_TYPE_PID: + *id = dst_id >> PS_TYPE_BITS; type = CR_FD_PAGEMAP; break; case 27: /* 1.3 */ @@ -92,6 +93,7 @@ static int decode_pm_type(u64 dst_id) case 33: /* 1.0 1.1 3.1 3.2 */ case 34: /* 2.* 3.0 */ case PS_TYPE_SHMEM: + *id = dst_id >> PS_TYPE_BITS; type = CR_FD_SHMEM_PAGEMAP; break; default: @@ -102,11 +104,6 @@ static int decode_pm_type(u64 dst_id) return type; } -static long decode_pm_id(u64 dst_id) -{ - return (long)(dst_id >> PS_TYPE_BITS); -} - static inline int send_psi(int sk, u32 cmd, u32 nr_pages, u64 vaddr, u64 dst_id) { struct page_server_iov pi = { @@ -171,7 +168,7 @@ static int open_page_server_xfer(struct page_xfer *xfer, int fd_type, long id) xfer->write_pages = write_pages_to_server; xfer->write_hole = write_hole_to_server; xfer->close = close_server_xfer; - xfer->dst_id = encode_pm_id(fd_type, id); + xfer->dst_id = encode_pm(fd_type, id); xfer->parent = NULL; if (send_psi(xfer->sk, PS_IOV_OPEN2, 0, 0, xfer->dst_id)) { @@ -479,9 +476,7 @@ static int page_server_check_parent(int sk, struct page_server_iov *pi) int type, ret; long id; - type = decode_pm_type(pi->dst_id); - id = decode_pm_id(pi->dst_id); - + type = decode_pm(pi->dst_id, &id); if (type == -1) { pr_err("Unknown pagemap type received\n"); return -1; @@ -505,7 +500,7 @@ static int check_parent_server_xfer(int fd_type, long id) int has_parent; pi.cmd = PS_IOV_PARENT; - pi.dst_id = encode_pm_id(fd_type, id); + pi.dst_id = encode_pm(fd_type, id); if (write(page_server_sk, &pi, sizeof(pi)) != sizeof(pi)) { pr_perror("Can't write to page server"); @@ -552,8 +547,7 @@ static int page_server_open(int sk, struct page_server_iov *pi) int type; long id; - type = decode_pm_type(pi->dst_id); - id = decode_pm_id(pi->dst_id); + type = decode_pm(pi->dst_id, &id); if (type == -1) { pr_err("Unknown pagemap type received\n"); return -1; From e2e1dbf4907dd21deaf832331ca7814b567d1827 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 10 Aug 2017 02:21:00 +0300 Subject: [PATCH 0719/4375] util: report a command name in error messages for cr_system() It is good to know what command were executed. https://github.com/xemul/criu/issues/371 Signed-off-by: Andrei Vagin Signed-off-by: Pavel Emelyanov --- criu/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/util.c b/criu/util.c index da78d8d30..9521eac0b 100644 --- a/criu/util.c +++ b/criu/util.c @@ -652,7 +652,7 @@ int cr_system_userns(int in, int out, int err, char *cmd, execvp(cmd, argv); - pr_perror("exec failed"); + pr_perror("exec(%s, ...) failed", cmd); out_chld: _exit(1); } From 181c44aa3f8b6f615f80b11d62bf502b45faca5e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 15 Aug 2017 15:46:04 +0300 Subject: [PATCH 0720/4375] compel,s390: Fix setting regs for tasks Item's thread struct pid is not a pointer in master. Signed-off-by: Pavel Emelyanov --- criu/arch/s390/crtools.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/criu/arch/s390/crtools.c b/criu/arch/s390/crtools.c index cfab50868..27b19f76f 100644 --- a/criu/arch/s390/crtools.c +++ b/criu/arch/s390/crtools.c @@ -435,13 +435,13 @@ int arch_set_thread_regs(struct pstree_item *item) item->pid->state == TASK_HELPER) continue; for (i = 0; i < item->nr_threads; i++) { - if (item->threads[i]->state == TASK_DEAD || - item->threads[i]->state == TASK_ZOMBIE) + if (item->threads[i].state == TASK_DEAD || + item->threads[i].state == TASK_ZOMBIE) continue; - if (set_task_regs(item->threads[i]->real, + if (set_task_regs(item->threads[i].real, item->core[i])) { pr_perror("Not set registers for task %d", - item->threads[i]->real); + item->threads[i].real); return -1; } } From 89d10280e5fa64660b410ccc0428e25dd6d62847 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 20 Jun 2017 23:49:03 +0300 Subject: [PATCH 0721/4375] restore: handle errors of restore_wait_other_tasks In a error case, task_entries->nr_in_progress is set to -1 and we have to handle this case. Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index f8f58f50e..3b353205a 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -162,12 +162,12 @@ static inline int stage_current_participants(int next_stage) return -1; } -static int restore_wait_inprogress_tasks() +static int __restore_wait_inprogress_tasks(int participants) { int ret; futex_t *np = &task_entries->nr_in_progress; - futex_wait_while_gt(np, 0); + futex_wait_while_gt(np, participants); ret = (int)futex_get(np); if (ret < 0) { set_cr_errno(get_task_cr_err()); @@ -177,6 +177,22 @@ static int restore_wait_inprogress_tasks() return 0; } +static int restore_wait_inprogress_tasks() +{ + return __restore_wait_inprogress_tasks(0); +} + +/* Wait all tasks except the current one */ +static int restore_wait_other_tasks() +{ + int participants, stage; + + stage = futex_get(&task_entries->start); + participants = stage_current_participants(stage); + + return __restore_wait_inprogress_tasks(participants); +} + static inline void __restore_switch_stage_nw(int next_stage) { futex_set(&task_entries->nr_in_progress, @@ -198,18 +214,6 @@ static int restore_switch_stage(int next_stage) return restore_wait_inprogress_tasks(); } -/* Wait all tasks except the current one */ -static void restore_wait_other_tasks() -{ - int participants, stage; - - stage = futex_get(&task_entries->start); - participants = stage_current_participants(stage); - - futex_wait_while_gt(&task_entries->nr_in_progress, - participants); -} - static int restore_finish_ns_stage(int from, int to) { if (root_ns_mask) @@ -1565,7 +1569,8 @@ static int restore_task_with_children(void *_arg) * * It means that all tasks entered into their namespaces. */ - restore_wait_other_tasks(); + if (restore_wait_other_tasks()) + goto err; fini_restore_mntns(); __restore_switch_stage(CR_STATE_RESTORE); } else { From 625552f0e99bcb57774a14c0fbe70ca2f9a10822 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 20 Jul 2017 05:31:43 +0300 Subject: [PATCH 0722/4375] page-xfer: handle a case when splice returns zero A return value of 0 means end of input, so we need to stop reading from this descriptor. Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 7ee606344..f6b1d9012 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -222,6 +222,10 @@ static int write_pages_loc(struct page_xfer *xfer, pr_perror("Unable to spice data"); return -1; } + if (ret == 0) { + pr_err("A pipe was closed unexpectedly"); + return -1; + } curr += ret; if (curr == len) break; @@ -626,6 +630,10 @@ static int page_server_add(int sk, struct page_server_iov *pi) pr_perror("Can't read from socket"); return -1; } + if (chunk == 0) { + pr_err("A socket was closed unexpectedly"); + return -1; + } if (lxfer->write_pages(lxfer, cxfer.p[0], chunk)) return -1; From 59c9583992da89a8aa382b93d5a9f6c7fd3ca364 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 17 Mar 2017 18:41:01 +0300 Subject: [PATCH 0723/4375] images: netdev -- Adjust venet comment venet is not virtuozzo specific but rather came from openvz, make it so. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- images/netdev.proto | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/images/netdev.proto b/images/netdev.proto index 2f2f3d132..d3fde30b7 100644 --- a/images/netdev.proto +++ b/images/netdev.proto @@ -16,10 +16,7 @@ enum nd_type { * by the setup-namespaces script. */ EXTLINK = 4; - /* - * Virtuozzo specific device. - */ - VENET = 5; + VENET = 5; /* OpenVZ device */ BRIDGE = 6; MACVLAN = 7; } From 96602ba854ad3a72a45e2bc2f2d6dd7ff6bfcd12 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 5 Jun 2017 22:23:58 +0300 Subject: [PATCH 0724/4375] restorer: Report child's death reason correctly E.g, if child was killed by SIGSEGV, this message previously was "exited, status=11", as si_code == CLD_DUMPED == 3 in this case will result in (si_code & CLD_KILLED) == (si_code & 1). Which is misleading as you may try to look for exit() calls with 11 arg. Correct if to compare si_code with CLD_*. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 6216e43e7..d43da92a6 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -102,12 +102,18 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) if (siginfo->si_pid == zombies[i]) return; - if (siginfo->si_code & CLD_EXITED) - r = " exited, status="; - else if (siginfo->si_code & CLD_KILLED) - r = " killed by signal "; + if (siginfo->si_code == CLD_EXITED) + r = "exited, status="; + else if (siginfo->si_code == CLD_KILLED) + r = "killed by signal"; + else if (siginfo->si_code == CLD_DUMPED) + r = "terminated abnormally with"; + else if (siginfo->si_code == CLD_TRAPPED) + r = "trapped with"; + else if (siginfo->si_code == CLD_STOPPED) + r = "stopped with"; else - r = "disappeared with "; + r = "disappeared with"; pr_info("Task %d %s %d\n", siginfo->si_pid, r, siginfo->si_status); From 8a270e58074b406a192210cc792bf456629e57c9 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Aug 2017 13:18:39 +0300 Subject: [PATCH 0725/4375] util: Add block_sigmask/unblock_sigmask helpers This is an extract from Kirill Tkhai's patch 87464739 (restore: Block SIGCHLD during root_item initialization) Signed-off-by: Pavel Emelyanov --- criu/include/util.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/criu/include/util.h b/criu/include/util.h index 277edc142..b3c669428 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -290,4 +290,25 @@ int setup_tcp_client(char *addr); #define LAST_PID_PATH "sys/kernel/ns_last_pid" #define PID_MAX_PATH "sys/kernel/pid_max" +#define block_sigmask(saved_mask, sig_mask) ({ \ + sigset_t ___blocked_mask; \ + int ___ret = 0; \ + sigemptyset(&___blocked_mask); \ + sigaddset(&___blocked_mask, sig_mask); \ + if (sigprocmask(SIG_BLOCK, &___blocked_mask, saved_mask) == -1) { \ + pr_perror("Can not set mask of blocked signals"); \ + ___ret = -1; \ + } \ + ___ret; \ + }) + +#define restore_sigmask(saved_mask) ({ \ + int ___ret = 0; \ + if (sigprocmask(SIG_SETMASK, saved_mask, NULL) == -1) { \ + pr_perror("Can not unset mask of blocked signals"); \ + ___ret = -1; \ + } \ + ___ret; \ + }) + #endif /* __CR_UTIL_H__ */ From 204c1ef9e03bbfa210c63dfa00b2272cb6918451 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 20 Jul 2017 18:21:21 +0300 Subject: [PATCH 0726/4375] restore: Fix deadlock when helper's child dies Since commit ced9c529f687 ("restore: fix race with helpers' kids dying too early"), we block SIGCHLD in helper tasks before CR_STATE_RESTORE. This way we avoided default criu sighandler as it doesn't expect that childs may die. This is very racy as we wait on futex for another stage to be started, but the next stage may start only when all the tasks complete previous stage. If some children of helper dies, the helper may already have blocked SIGCHLD and have started sleeping on the futex. Then the next stage never comes and no one reads a pending SIGCHLD for helper. A customer met this situation on the node, where the following (non-related) problem has occured: Unable to send a fin packet: libnet_write_raw_ipv6(): -1 bytes written (Network is unreachable) Then child criu of the helper has exited with error-code and the lockup has happened. While we could fix it by aborting futex in the end of restore_task_with_children() for each (non-root also) tasks, that would be not completely correct: 1. All futex-waiting tasks will wake up after that and they may not expect that some tasks are on the previous stage, so they will spam into logs with unrelated errors and may also die painfully. 2. Child may die and miss aborting of the futex due to: o segfault o OOM killer o User-sended SIGKILL o Other error-path we forgot to cover with abort futex To fix this deadlock in TASK_HELPER, as suggested-by Kirill, let's check if there are children deaths expected - if there isn't any, don't block SIGCHLD, otherwise wait() and check if death was on expected stage of restore (not CR_STATE_RESTORE). Reviewed-by: Kirill Tkhai Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin Conflicts: criu/cr-restore.c --- criu/cr-restore.c | 91 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 17 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 3b353205a..0e83d8fed 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1002,6 +1002,79 @@ out: return ret; } +/* + * Find if there are children which are zombies or helpers - processes + * which are expected to die during the restore. + */ +static bool child_death_expected(void) +{ + struct pstree_item *pi; + + list_for_each_entry(pi, ¤t->children, sibling) { + switch (pi->pid->state) { + case TASK_DEAD: + case TASK_HELPER: + return true; + } + } + + return false; +} + +/* + * Restore a helper process - artificially created by criu + * to restore attributes of process tree. + * - sessions for each leaders are dead + * - process groups with dead leaders + * - dead tasks for which /proc//... is opened by restoring task + * - whatnot + */ +static int restore_one_helper(void) +{ + siginfo_t info; + + if (!child_death_expected()) { + /* + * Restoree has no children that should die, during restore, + * wait for the next stage on futex. + * The default SIGCHLD handler will handle an unexpected + * child's death and abort the restore if someone dies. + */ + restore_finish_stage(task_entries, CR_STATE_RESTORE); + return 0; + } + + /* + * The restoree has children which will die - decrement itself from + * nr. of tasks processing the stage and wait for anyone to die. + * Tasks may die only when they're on the following stage. + * If one dies earlier - that's unexpected - treat it as an error + * and abort the restore. + */ + if (block_sigmask(NULL, SIGCHLD)) + return -1; + + /* Finish CR_STATE_RESTORE, but do not wait for the next stage. */ + futex_dec_and_wake(&task_entries->nr_in_progress); + + if (waitid(P_ALL, 0, &info, WEXITED | WNOWAIT)) { + pr_perror("Failed to wait\n"); + return -1; + } + + if (futex_get(&task_entries->start) == CR_STATE_RESTORE) { + pr_err("Child %d died too early\n", info.si_pid); + return -1; + } + + if (wait_on_helpers_zombies()) { + pr_err("Failed to wait on helpers and zombies\n"); + return -1; + } + + return 0; +} + static int restore_one_task(int pid, CoreEntry *core) { int ret; @@ -1013,23 +1086,7 @@ static int restore_one_task(int pid, CoreEntry *core) else if (current->pid->state == TASK_DEAD) ret = restore_one_zombie(core); else if (current->pid->state == TASK_HELPER) { - sigset_t blockmask, oldmask; - - sigemptyset(&blockmask); - sigaddset(&blockmask, SIGCHLD); - - if (sigprocmask(SIG_BLOCK, &blockmask, &oldmask) == -1) { - pr_perror("Can not set mask of blocked signals"); - return -1; - } - - restore_finish_stage(task_entries, CR_STATE_RESTORE); - if (wait_on_helpers_zombies()) { - pr_err("failed to wait on helpers and zombies\n"); - ret = -1; - } else { - ret = 0; - } + ret = restore_one_helper(); } else { pr_err("Unknown state in code %d\n", (int)core->tc->task_state); ret = -1; From 84492ae27c575bb7a314c45ec7daf249f40bbcea Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 17 Aug 2017 17:13:17 +0300 Subject: [PATCH 0727/4375] Added badges to the title page Travis statues for master and criu-dev and codacy grade. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 0c122bec2..42ff4b5bf 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +[![master](https://travis-ci.org/xemul/criu.svg?branch=master)](https://travis-ci.org/xemul/criu) +[![development](https://travis-ci.org/xemul/criu.svg?branch=criu-dev)](https://travis-ci.org/xemul/criu) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/55251ec7db28421da4481fc7c1cb0cee)](https://www.codacy.com/app/xemul/criu?utm_source=github.com&utm_medium=referral&utm_content=xemul/criu&utm_campaign=Badge_Grade)

## CRIU -- A project to implement checkpoint/restore functionality for Linux From a31c1854e10580a09621e539c3ec052b875a8e06 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 21 Aug 2017 16:27:57 +0300 Subject: [PATCH 0728/4375] criu: Version 3.4 The biggest new thing this time is s390x arch support! Also we have several improvements and a set of bugfixes as usual. Signed-off-by: Pavel Emelyanov --- Makefile.versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index 397416308..475e9e207 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 3 +CRIU_VERSION_MINOR := 4 CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Crystal Pelican +CRIU_VERSION_NAME := Cobalt Swan CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From 835e252b096da5d2fb551805041e5d6d74deedef Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 12 Aug 2017 08:58:19 +0300 Subject: [PATCH 0729/4375] test/ptrace_sig: wait children before calling test_daemon A static test has to do nothing after test_daemon(). Signed-off-by: Andrei Vagin --- test/zdtm/static/ptrace_sig.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/test/zdtm/static/ptrace_sig.c b/test/zdtm/static/ptrace_sig.c index 299605de8..f71517717 100644 --- a/test/zdtm/static/ptrace_sig.c +++ b/test/zdtm/static/ptrace_sig.c @@ -59,8 +59,8 @@ int main(int argc, char ** argv) { int ret, status = 0; pid_t pid, spid, cpid; - int signal_pipe[2]; int child_pipe[2]; + siginfo_t siginfo; test_init(argc, argv); @@ -81,9 +81,10 @@ int main(int argc, char ** argv) } close(child_pipe[1]); - ret = pipe(signal_pipe); - if (ret < 0) { - pr_perror("pipe failed"); + test_msg("wait while child initialized"); + ret = read(child_pipe[0], &status, sizeof(status)); + if (ret != sizeof(status)) { + pr_perror("read from child process failed"); return 1; } @@ -92,12 +93,6 @@ int main(int argc, char ** argv) pr_perror("Can't fork signal process"); return 1; } else if (spid == 0) { - close(signal_pipe[1]); - ret = read(signal_pipe[0], &status, sizeof(status)); - if (ret != sizeof(status)) { - pr_perror("read"); - return 1; - } test_msg("send signal to %d\n", cpid); ret = kill(cpid, SIGUSR2); if (ret < 0) { @@ -105,20 +100,15 @@ int main(int argc, char ** argv) } return 0; } - close(signal_pipe[0]); - test_msg("wait while child initialized"); - ret = read(child_pipe[0], &status, sizeof(status)); - if (ret != sizeof(status)) { - pr_perror("read from child process failed"); + if (waitid(P_PID, spid, &siginfo, WEXITED | WNOWAIT)) { + pr_perror("Unable to wait spid"); return 1; } - - ret = write(signal_pipe[1], &status, sizeof(status)); - if (ret != sizeof(status)) { - pr_perror("write to signal process failed"); + if (waitid(P_PID, cpid, &siginfo, WSTOPPED | WNOWAIT)) { + pr_perror("Unable to wait cpid"); + return 1; } - close(signal_pipe[1]); test_daemon(); test_waitsig(); @@ -133,7 +123,6 @@ int main(int argc, char ** argv) } if (WIFSTOPPED(status)) { - siginfo_t siginfo; test_msg("pid=%d stopsig=%d\n", pid, WSTOPSIG(status)); From 98ac646f868d97b621c81939a8139e7a63d37393 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 24 Aug 2017 11:13:05 +0300 Subject: [PATCH 0730/4375] ppc64le: travis: fixup Ubuntu repositories The ppc64le docker image has broken /etc/apt/sources.list. A small fixup to it allows running ppc64le tests. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.ppc64le.hdr | 1 + scripts/travis/travis-tests | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/scripts/build/Dockerfile.ppc64le.hdr b/scripts/build/Dockerfile.ppc64le.hdr index 6c4b22e49..6b3c6592c 100644 --- a/scripts/build/Dockerfile.ppc64le.hdr +++ b/scripts/build/Dockerfile.ppc64le.hdr @@ -2,3 +2,4 @@ FROM ppc64le/ubuntu:trusty ENV QEMU_CPU POWER8 COPY scripts/build/qemu-user-static/usr/bin/qemu-ppc64le-static /usr/bin/qemu-ppc64le-static +RUN sed -i '/security/ d' /etc/apt/sources.list diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 90f5f346e..8800d5f04 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -30,6 +30,12 @@ travis_prep () { CC="ccache $CC" fi + # The /etc/apt/sources.list in the current trusty image for ppc64le is + # broken and needs to be fixed + if [ "$TR_ARCH" = "ppc64le" ] ; then + sed -i '/security/ d' /etc/apt/sources.list + fi + apt-get update -qq apt-get install -qq --no-install-recommends $TRAVIS_PKGS chmod a+x $HOME From 27e601790ec9b8da570946315e5d18e88cbf8ce1 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 15 Mar 2016 13:21:11 +0000 Subject: [PATCH 0731/4375] Remove static from prepare_task_entries function For the upcoming userfaultfd integration the lazy-pages mode needs to setup the criu infrastructure to read the pages files. Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/cr-restore.c | 2 +- criu/include/pstree.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 0e83d8fed..d24c16492 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2146,7 +2146,7 @@ out: return -1; } -static int prepare_task_entries(void) +int prepare_task_entries(void) { task_entries_pos = rst_mem_align_cpos(RM_SHREMAP); task_entries = rst_mem_alloc(sizeof(*task_entries), RM_SHREMAP); diff --git a/criu/include/pstree.h b/criu/include/pstree.h index 99b890220..b7299c313 100644 --- a/criu/include/pstree.h +++ b/criu/include/pstree.h @@ -110,6 +110,7 @@ extern int pid_to_virt(pid_t pid); struct task_entries; extern struct task_entries *task_entries; +extern int prepare_task_entries(void); extern int get_task_ids(struct pstree_item *); extern struct _TaskKobjIdsEntry *root_ids; From e2268aa39ce8b0d558ac5d3855ea5b8eb352a583 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 15 Mar 2016 13:21:12 +0000 Subject: [PATCH 0732/4375] Try to include userfaultfd with criu (part 1) This is a first try to include userfaultfd with criu. Right now it still requires a "normal" checkpoint. After checkpointing the application it can be restored with the help of userfaultfd. All restored pages with MAP_ANONYMOUS and MAP_PRIVATE set are marked as being handled by userfaultfd. As soon as the process is restored it blocks on the first memory access and waits for pages being transferred by userfaultfd. To handle the required pages a new criu command has been added. For a userfaultfd supported restore the first step is to start the 'lazy-pages' server: criu lazy-pages -v4 -D /tmp/3/ --address /tmp/userfault.socket This is part 1 of the userfaultfd integration which provides the 'lazy-pages' server implementation. v2: * provide option '--lazy-pages' to enable uffd style restore * use send_fd()/recv_fd() provided by criu (instead of own implementation) * do not install the uffd as service_fd * use named constants for MAP_ANONYMOUS * do not restore memory pages and then later mark them as uffd handled * remove function find_pages() to search in pages-.img; now using criu functions to find the necessary pages; for each new page search the pages-.img file is opened * only check the UFFDIO_API once * trying to protect uffd code by CONFIG_UFFD; use make UFFD=1 to compile criu with this patch v3: * renamed the server mode from 'uffd' -> 'lazy-pages' * switched client and server roles transferring the UFFD FD * the criu part running in lazy-pages server mode is now waiting for connections * the criu restore process connects to the lazy-pages server to pass the UFFD FD * before UFFD copying anything else the VDSO pages are copied as it fails to copy unused VDSO pages once the process is running. this was necessary to be able to copy all pages. * if there are no more UFFD messages for 5 seconds the lazy-pages server switches in copy mode to copy all remaining pages, which have not been requested yet, into the restored process * check the UFFDIO_API at the correct place * close UFFD FD in the restorer to remove open UFFD FD in the restored process v4: * removed unnecessary madvise() calls ; it seemed necessary when first running tests with uffd; it actually is not necessary * auto-detect if build-system provides linux/userfaultfd.h header * simplify unix domain socket setup and communication. * use --address to specify the location of the used unix domain socket v5: * split the userfaultfd patch in multiple smaller patches * introduced vma_can_be_lazy() function to check if a page can be handled by uffd * moved uffd related code from cr-restore.c to uffd.c * handle failure to register a memory page of the restored process with userfaultfd v6: * get PID of to be restored process from the 'criu restore' process; first the PID is transferred and then the UFFD * code has been re-ordered to be better prepared for lazy-restore from remote host * compile test for UFFD availability only once Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- Makefile.config | 8 + criu/Makefile.crtools | 4 + criu/crtools.c | 6 + criu/include/crtools.h | 5 + criu/include/uffd.h | 16 ++ criu/uffd.c | 547 ++++++++++++++++++++++++++++++++++++++ scripts/feature-tests.mak | 15 ++ 7 files changed, 601 insertions(+) create mode 100644 criu/include/uffd.h create mode 100644 criu/uffd.c diff --git a/Makefile.config b/Makefile.config index 0e557805c..8fb4e6b69 100644 --- a/Makefile.config +++ b/Makefile.config @@ -35,6 +35,10 @@ endif export DEFINES += $(FEATURE_DEFINES) export CFLAGS += $(FEATURE_DEFINES) +ifeq ($(call try-cc,$(FEATURE_TEST_UFFD)),y) + export UFFD := 1 +endif + FEATURES_LIST := TCP_REPAIR STRLCPY STRLCAT PTRACE_PEEKSIGINFO \ SETPROCTITLE_INIT MEMFD TCP_REPAIR_WINDOW @@ -57,6 +61,10 @@ $(call map,gen-feature-test,$(FEATURES_LIST)) ifeq ($$(VDSO),y) $(Q) @echo '#define CONFIG_VDSO' >> $$@ $(Q) @echo '' >> $$@ +endif +ifeq ($$(UFFD),1) + $(Q) @echo '#define CONFIG_HAS_UFFD' >> $$@ + $(Q) @echo '' >> $$@ endif $(Q) @echo '#endif /* __CR_CONFIG_H__ */' >> $$@ endef diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 6b3fbdfb6..d86814a5e 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -92,6 +92,10 @@ obj-$(CONFIG_COMPAT) += vdso-compat.o CFLAGS_REMOVE_vdso-compat.o += $(CFLAGS-ASAN) $(CFLAGS-GCOV) endif +ifeq ($(UFFD),1) +obj-y += uffd.o +endif + PROTOBUF_GEN := scripts/protobuf-gen.sh $(obj)/protobuf-desc.d: $(obj)/protobuf-desc-gen.h diff --git a/criu/crtools.c b/criu/crtools.c index e7a21ad61..2cd231e05 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -733,6 +733,9 @@ int main(int argc, char *argv[], char *envp[]) return -1; } + if (!strcmp(argv[optind], "lazy-pages")) + return uffd_listen() != 0; + if (!strcmp(argv[optind], "check")) return cr_check() != 0; @@ -766,6 +769,9 @@ usage: " criu page-server\n" " criu service []\n" " criu dedup\n" +#ifdef CONFIG_HAS_UFFD +" criu lazy-pages -D DIR []\n" +#endif "\n" "Commands:\n" " dump checkpoint a process/tree identified by pid\n" diff --git a/criu/include/crtools.h b/criu/include/crtools.h index ec2ca9c7d..c0f51bce3 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -25,6 +25,11 @@ extern int cr_restore_tasks(void); extern int convert_to_elf(char *elf_path, int fd_core); extern int cr_check(void); extern int cr_dedup(void); +#ifdef CONFIG_HAS_UFFD +extern int uffd_listen(void); +#else +static inline int uffd_listen() { return 0; }; +#endif /* CONFIG_HAS_UFFD */ extern int check_add_feature(char *arg); extern void pr_check_features(const char *offset, const char *sep, int width); diff --git a/criu/include/uffd.h b/criu/include/uffd.h new file mode 100644 index 000000000..d5a043b0c --- /dev/null +++ b/criu/include/uffd.h @@ -0,0 +1,16 @@ +#ifndef __CR_UFFD_H_ +#define __CR_UFFD_H_ + +#include "config.h" + +#ifdef CONFIG_HAS_UFFD + +#include +#include + +#ifndef __NR_userfaultfd +#error "missing __NR_userfaultfd definition" +#endif +#endif /* CONFIG_HAS_UFFD */ + +#endif /* __CR_UFFD_H_ */ diff --git a/criu/uffd.c b/criu/uffd.c new file mode 100644 index 000000000..1f20faf79 --- /dev/null +++ b/criu/uffd.c @@ -0,0 +1,547 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "int.h" +#include "page.h" +#include "include/log.h" +#include "include/criu-plugin.h" +#include "include/pagemap.h" +#include "include/files-reg.h" +#include "include/mem.h" +#include "include/uffd.h" +#include "include/util-pie.h" +#include "include/protobuf.h" +#include "include/pstree.h" +#include "include/crtools.h" +#include "include/cr_options.h" +#include "xmalloc.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "lazy-pages: " + +static int server_listen(struct sockaddr_un *saddr) +{ + int fd; + int len; + + if (strlen(opts.addr) >= sizeof(saddr->sun_path)) { + return -1; + } + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return -1; + + unlink(opts.addr); + + memset(saddr, 0, sizeof(struct sockaddr_un)); + saddr->sun_family = AF_UNIX; + strcpy(saddr->sun_path, opts.addr); + len = offsetof(struct sockaddr_un, sun_path) + strlen(opts.addr); + + if (bind(fd, (struct sockaddr *) saddr, len) < 0) { + goto out; + } + + if (listen(fd, 10) < 0) { + goto out; + } + + return fd; + +out: + close(fd); + return -1; +} + +static int pid; + +static int ud_open() +{ + int client; + int listen; + int newfd; + int ret = -1; + struct sockaddr_un saddr; + socklen_t len; + + if ((listen = server_listen(&saddr)) < 0) { + pr_perror("server_listen error"); + return -1; + } + + /* accept new client request */ + len = sizeof(struct sockaddr_un); + if ((client = accept(listen, (struct sockaddr *)&saddr, &len)) < 0) { + pr_perror("server_accept error: %d", client); + close(listen); + return -1; + } + + pr_debug("client fd %d\n", client); + + /* The "transfer protocol" is first the pid as int and then + * the FD for UFFD */ + ret = recv(client, &pid, sizeof(pid), 0); + if (ret != sizeof(pid)) { + pr_perror("PID recv error:"); + ret = -1; + goto out; + } + pr_debug("received PID: %d\n", pid); + + newfd = recv_fd(client); + if (newfd < 0) { + pr_perror("recv_fd error:"); + goto out; + } + pr_debug("newfd %d\n", newfd); + close(client); + + return newfd; +out: + close(listen); + close(client); + return ret; +} + +static int get_page(unsigned long addr, void *dest) +{ + struct iovec iov; + int ret; + unsigned char buf[PAGE_SIZE]; + struct page_read pr; + + ret = open_page_read(pid, &pr, PR_TASK | PR_MOD); + pr_debug("get_page ret %d\n", ret); + + ret = pr.get_pagemap(&pr, &iov); + pr_debug("get_pagemap ret %d\n", ret); + if (ret <= 0) + return ret; + + ret = pr.seek_page(&pr, addr); + pr_debug("seek_pagemap_page ret 0x%x\n", ret); + if (ret <= 0) + return ret; + + if (pr.pe->zero) + return 0; + + ret = pr.read_pages(&pr, addr, 1, buf, 0); + pr_debug("read_pages ret %d\n", ret); + if (ret <= 0) + return ret; + + memcpy(dest, buf, PAGE_SIZE); + + if (pr.close) + pr.close(&pr); + + return 1; +} + +#define UFFD_FLAG_SENT 0x1 +#define UFFD_FLAG_VDSO 0x2 + +struct uffd_pages_struct { + struct list_head list; + unsigned long addr; + int flags; +}; + +static int uffd_copy_page(int uffd, __u64 address, void *dest) +{ + struct uffdio_copy uffdio_copy; + int rc; + + rc = get_page(address, dest); + if (rc <= 0) + return -1; + + uffdio_copy.dst = address; + uffdio_copy.src = (unsigned long) dest; + uffdio_copy.len = page_size(); + uffdio_copy.mode = 0; + uffdio_copy.copy = 0; + + pr_debug("uffdio_copy.dst 0x%llx\n", uffdio_copy.dst); + rc = ioctl(uffd, UFFDIO_COPY, &uffdio_copy); + pr_debug("ioctl UFFDIO_COPY rc 0x%x\n", rc); + pr_debug("uffdio_copy.copy 0x%llx\n", uffdio_copy.copy); + if (rc) { + /* real retval in ufdio_copy.copy */ + if (uffdio_copy.copy != -EEXIST) { + pr_err("UFFDIO_COPY error %Ld\n", uffdio_copy.copy); + return -1; + } + } else if (uffdio_copy.copy != page_size()) { + pr_err("UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy); + return -1; + } + + + return uffdio_copy.copy; + +} + +static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list, + unsigned long *vma_size) +{ + unsigned long base; + int i; + struct iovec iov; + unsigned long nr_pages; + unsigned long ps; + int rc; + struct uffd_pages_struct *uffd_pages; + struct vma_area *vma; + struct vm_area_list *vmas = &rsti(root_item)->vmas; + + rc = pr->get_pagemap(pr, &iov); + if (rc <= 0) + return 0; + + ps = page_size(); + nr_pages = iov.iov_len / ps; + base = (unsigned long) iov.iov_base; + pr_debug("iov.iov_base 0x%lx (%ld pages)\n", base, nr_pages); + + for (i = 0; i < nr_pages; i++) { + bool uffd_page = false; + bool uffd_vdso = false; + base = (unsigned long) iov.iov_base + (i * ps); + /* + * Only pages which are MAP_ANONYMOUS and MAP_PRIVATE + * are relevant for userfaultfd handling. + * Loop over all VMAs to see if the flags matching. + */ + list_for_each_entry(vma, &vmas->h, list) { + /* + * This loop assumes that base can actually be found + * in the VMA list. + */ + if (base >= vma->e->start && base < vma->e->end) { + if ((vma->e->flags & MAP_ANONYMOUS) && + (vma->e->flags & MAP_PRIVATE) && + !(vma_area_is(vma, VMA_AREA_VSYSCALL))) { + uffd_page = true; + if (vma_area_is(vma, VMA_AREA_VDSO)) + uffd_vdso = true; + break; + } + } + } + + /* This is not a page we are looking for. Move along */ + if (!uffd_page) + continue; + + pr_debug("Adding 0x%lx to our list\n", base); + + *vma_size += ps; + uffd_pages = xzalloc(sizeof(struct uffd_pages_struct)); + if (!uffd_pages) + return -1; + uffd_pages->addr = base; + if (uffd_vdso) + uffd_pages->flags |= UFFD_FLAG_VDSO; + list_add(&uffd_pages->list, uffd_list); + } + + return 1; +} + +static int handle_remaining_pages(int uffd, struct list_head *uffd_list, unsigned long *vma_size, + void *dest) +{ + unsigned long uffd_copied_pages = 0; + struct uffd_pages_struct *uffd_pages; + int rc; + + pr_debug("remaining vma_size: 0x%lx\n", *vma_size); + pr_debug("uffd_copied_pages: %ld\n", uffd_copied_pages); + + list_for_each_entry(uffd_pages, uffd_list, list) { + pr_debug("Checking remaining pages 0x%lx (flags 0x%x)\n", + uffd_pages->addr, uffd_pages->flags); + if (uffd_pages->flags & UFFD_FLAG_SENT) + continue; + + rc = uffd_copy_page(uffd, uffd_pages->addr, dest); + if (rc < 0) { + pr_err("Error during UFFD copy\n"); + return -1; + } + *vma_size -= rc; + + pr_debug("remaining vma_size: 0x%lx\n", *vma_size); + uffd_copied_pages++; + uffd_pages->flags |= UFFD_FLAG_SENT; + } + + return uffd_copied_pages; +} + + +static int handle_regular_pages(int uffd, struct list_head *uffd_list, unsigned long *vma_size, + void *dest, __u64 address) +{ + int rc; + struct uffd_pages_struct *uffd_pages; + + rc = uffd_copy_page(uffd, address, dest); + if (rc < 0) { + pr_err("Error during UFFD copy\n"); + return -1; + } + *vma_size -= rc; + + /* + * Mark this page as having been already transferred, so + * that it has not to be copied again later. + */ + list_for_each_entry(uffd_pages, uffd_list, list) { + if (uffd_pages->addr == address) + uffd_pages->flags |= UFFD_FLAG_SENT; + } + + + return 1; +} + +static int handle_vdso_pages(int uffd, struct list_head *uffd_list, unsigned long *vma_size, + void *dest) +{ + int rc; + struct uffd_pages_struct *uffd_pages; + int uffd_copied_pages = 0; + + list_for_each_entry(uffd_pages, uffd_list, list) { + if (!(uffd_pages->flags & UFFD_FLAG_VDSO)) + continue; + rc = uffd_copy_page(uffd, uffd_pages->addr, dest); + if (rc < 0) { + pr_err("Error during UFFD copy\n"); + return -1; + } + *vma_size -= rc; + uffd_copied_pages++; + uffd_pages->flags |= UFFD_FLAG_SENT; + } + return uffd_copied_pages; +} + +/* + * Setting up criu infrastructure to easily + * access the dump results. + */ +static void criu_init() +{ + /* TODO: return code checking */ + check_img_inventory(); + prepare_task_entries(); + prepare_pstree(); + collect_remaps_and_regfiles(); + prepare_shared_reg_files(); + prepare_mm_pid(root_item); +} + +int uffd_listen() +{ + __u64 address; + void *dest; + __u64 flags; + struct uffd_msg msg; + struct page_read pr; + unsigned long ps; + int rc; + fd_set set; + struct timeval timeout; + int uffd; + unsigned long uffd_copied_pages = 0; + unsigned long total_pages = 0; + int uffd_flags; + struct uffd_pages_struct *uffd_pages; + bool vdso_sent = false; + unsigned long vma_size = 0; + + LIST_HEAD(uffd_list); + + if (!opts.addr) { + pr_info("Please specify a file name for the unix domain socket\n"); + pr_info("used to communicate between the lazy-pages server\n"); + pr_info("and the restore process. Use the --address option like\n"); + pr_info("criu --lazy-pages --address /tmp/userfault.socket\n"); + return -1; + } + + pr_debug("Waiting for incoming connections on %s\n", opts.addr); + if ((uffd = ud_open()) < 0) + exit(0); + + pr_debug("uffd is 0x%d\n", uffd); + uffd_flags = fcntl(uffd, F_GETFD, NULL); + pr_debug("uffd_flags are 0x%x\n", uffd_flags); + + /* Setting up criu infrastructure to easily access the dump results */ + criu_init(); + + /* Initialize FD sets for read() with timeouts (using select()) */ + FD_ZERO(&set); + FD_SET(uffd, &set); + + /* All operations will be done on page size */ + ps = page_size(); + dest = xmalloc(ps); + if (!dest) + goto out; + + rc = open_page_read(pid, &pr, PR_TASK); + if (rc <= 0) { + rc = 1; + goto out; + } + /* + * This puts all pages which should be handled by userfaultfd + * in the list uffd_list. This list is later used to detect if + * a page has already been transferred or if it needs to be + * pushed into the process using userfaultfd. + */ + do { + rc = collect_uffd_pages(&pr, &uffd_list, &vma_size); + if (rc == -1) { + rc = 1; + goto out; + } + } while (rc); + + if (pr.close) + pr.close(&pr); + + + /* Count detected pages */ + list_for_each_entry(uffd_pages, &uffd_list, list) + total_pages++; + + pr_debug("Found %ld pages to be handled by UFFD\n", total_pages); + + while (1) { + bool page_sent = false; + /* + * Setting the timeout to 5 seconds. If after this time + * no uffd pages are requested the code switches to + * copying the remaining pages. + * + * Timeout is re-defined every time select() is run as + * select(2) says: + * Consider timeout to be undefined after select() returns. + */ + timeout.tv_sec = 5; + timeout.tv_usec = 0; + rc = select(uffd + 1, &set, NULL, NULL, &timeout); + pr_debug("select() rc: 0x%x\n", rc); + if (rc == 0) { + pr_debug("read timeout\n"); + pr_debug("switching from request to copy mode\n"); + break; + } + rc = read(uffd, &msg, sizeof(msg)); + pr_debug("read() rc: 0x%x\n", rc); + + if (rc != sizeof(msg)) { + if (rc < 0) + pr_perror("read error"); + else + pr_debug("short read\n"); + continue; + } + + /* Align requested address to the next page boundary */ + address = msg.arg.pagefault.address & ~(ps - 1); + pr_debug("msg.arg.pagefault.address 0x%llx\n", address); + + /* + * At this point the process on the other side waits for the first page. + * In the first step we will force the vdso pages into the new process. + */ + if (!vdso_sent) { + pr_debug("Pushing VDSO pages once\n"); + rc = handle_vdso_pages(uffd, &uffd_list, &vma_size, dest); + if (rc < 0) { + pr_err("Error during VDSO handling\n"); + rc = 1; + goto out; + } + uffd_copied_pages += rc; + vdso_sent = true; + } + + /* Make sure to not transfer a page twice */ + list_for_each_entry(uffd_pages, &uffd_list, list) { + if ((uffd_pages->addr == address) && (uffd_pages->flags & UFFD_FLAG_SENT)) { + page_sent = true; + break; + } + } + + if (page_sent) + continue; + + /* Now handle the pages actually requested. */ + + flags = msg.arg.pagefault.flags; + pr_debug("msg.arg.pagefault.flags 0x%llx\n", flags); + + if (msg.event != UFFD_EVENT_PAGEFAULT) { + pr_err("unexpected msg event %u\n", msg.event); + rc = 1; + goto out; + } + + rc = handle_regular_pages(uffd, &uffd_list, &vma_size, dest, address); + if (rc < 0) { + pr_err("Error during regular page copy\n"); + rc = 1; + goto out; + } + + uffd_copied_pages += rc; + + } + pr_debug("Handle remaining pages\n"); + rc = handle_remaining_pages(uffd, &uffd_list, &vma_size, dest); + if (rc < 0) { + pr_err("Error during remaining page copy\n"); + rc = 1; + goto out; + } + + uffd_copied_pages += rc; + pr_debug("With UFFD transferred pages: (%ld/%ld)\n", uffd_copied_pages, total_pages); + if (uffd_copied_pages != total_pages) { + pr_warn("Only %ld of %ld pages transferred via UFFD\n", uffd_copied_pages, + total_pages); + pr_warn("Something probably went wrong.\n"); + rc = 1; + goto out; + } + rc = 0; + +out: + free(dest); + close(uffd); + return rc; +} diff --git a/scripts/feature-tests.mak b/scripts/feature-tests.mak index 12bf54181..77f671a90 100644 --- a/scripts/feature-tests.mak +++ b/scripts/feature-tests.mak @@ -123,3 +123,18 @@ ENTRY(main) nop END(main) endef + +define FEATURE_TEST_UFFD + +#include +#include + +int main(void) +{ +#ifndef __NR_userfaultfd +#error "missing __NR_userfaultfd definition" +#endif + return 0; +} + +endef From 57891afcb2b09414064a18612eef8b975c339c4c Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 15 Mar 2016 13:21:13 +0000 Subject: [PATCH 0733/4375] Try to include userfaultfd with criu (part 2) This is a first try to include userfaultfd with criu. Right now it still requires a "normal" checkpoint. After checkpointing the application it can be restored with the help of userfaultfd. All restored pages with MAP_ANONYMOUS and MAP_PRIVATE set are marked as being handled by userfaultfd. As soon as the process is restored it blocks on the first memory access and waits for pages being transferred by userfaultfd. To handle the required pages a new criu command has been added. For a userfaultfd supported restore the first step is to start the 'lazy-pages' server: criu lazy-pages -v4 -D /tmp/3/ --address /tmp/userfault.socket This waits on a unix domain socket (defined using the --address option) to receive a userfaultfd file descriptor from a '--lazy-pages' enabled 'criu restore': criu restore -D /tmp/3 -j -v4 --lazy-pages \ --address /tmp/userfault.socket In the first step the VDSO pages are pushed from the lazy-pages server into the restored process. After that the lazy-pages server waits on the UFFD FD for a UFFD requested page. If there are no requests received during a period of 5 seconds the lazy-pages server switches into a mode where the remaining, non-transferred pages are copied into the destination process. After all remaining pages have been copied the lazy-pages server exits. The first page that usually is requested is a VDSO page. The process currently used for restoring has two VDSO pages, but only one is requested via userfaultfd. In the second part where the remaining pages are copied into the process, the second VDSO page is also copied into the process as it has not been requested previously. Unfortunately, even as this page has not been requested before, it is not accepted by userfaultfd. EINVAL is returned. The reason for EINVAL is not understood and therefore the VDSO pages are copied first into the process, then switching to request mode and copying the pages which are requested via userfaultfd. To decide at which point the VDSO pages can be copied into the process, the lazy-pages server is currently waiting for the first page requested via userfaultfd. This is one of the VDSO pages. To not copy a page a second time, which is unnecessary and not possible, there is now a check to see if the page has been transferred previously. The use case to use usefaultfd with a checkpointed process on a remote machine will probably benefit from the current work related to image-cache and image-proxy. For the final implementation it would be nice to have a restore running in uffd mode on one system which requests the memory pages over the network from another system which is running 'criu checkpoint' also in uffd mode. This way the pages need to be copied only 'once' from the checkpoint process to the uffd restore process. TODO: * Contains still many debug outputs which need to be cleaned up. * Maybe transfer the dump directory FD also via unix domain sockets so that the 'uffd'/'lazy-pages' server can keep running without the need to specify the dump directory with '-D' * Keep the lazy-pages server running after all pages have been transferred and start waiting for new connections to serve. * Resurrect the non-cooperative patch set, as once the restored task fork()'s or calls mremap() the whole thing becomes broken. * Figure out if current VDSO handling is correct. * Figure out when and how zero pages need to be inserted via uffd. v2: * provide option '--lazy-pages' to enable uffd style restore * use send_fd()/recv_fd() provided by criu (instead of own implementation) * do not install the uffd as service_fd * use named constants for MAP_ANONYMOUS * do not restore memory pages and then later mark them as uffd handled * remove function find_pages() to search in pages-.img; now using criu functions to find the necessary pages; for each new page search the pages-.img file is opened * only check the UFFDIO_API once * trying to protect uffd code by CONFIG_UFFD; use make UFFD=1 to compile criu with this patch v3: * renamed the server mode from 'uffd' -> 'lazy-pages' * switched client and server roles transferring the UFFD FD * the criu part running in lazy-pages server mode is now waiting for connections * the criu restore process connects to the lazy-pages server to pass the UFFD FD * before UFFD copying anything else the VDSO pages are copied as it fails to copy unused VDSO pages once the process is running. this was necessary to be able to copy all pages. * if there are no more UFFD messages for 5 seconds the lazy-pages server switches in copy mode to copy all remaining pages, which have not been requested yet, into the restored process * check the UFFDIO_API at the correct place * close UFFD FD in the restorer to remove open UFFD FD in the restored process v4: * removed unnecessary madvise() calls ; it seemed necessary when first running tests with uffd; it actually is not necessary * auto-detect if build-system provides linux/userfaultfd.h header. * simplify unix domain socket setup and communication. * use --address to specify the location of the used unix domain socket. v5: * split the userfaultfd patch in multiple smaller patches * introduced vma_can_be_lazy() function to check if a page can be handled by uffd * moved uffd related code from cr-restore.c to uffd.c * handle failure to register a memory page of the restored process with userfaultfd v6: * get PID of to be restored process from the 'criu restore' process; first the PID is transferred and then the UFFD Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/cr-restore.c | 6 +++ criu/crtools.c | 14 +++++++ criu/include/cr_options.h | 1 + criu/include/restorer.h | 2 + criu/include/uffd.h | 6 +++ criu/include/vma.h | 9 ++++ criu/mem.c | 15 +++++++ criu/pie/restorer.c | 77 +++++++++++++++++++++++++++++++--- criu/uffd.c | 88 +++++++++++++++++++++++++++++++++++++-- 9 files changed, 210 insertions(+), 8 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index d24c16492..fd03eb1e3 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -49,6 +49,7 @@ #include "proc_parse.h" #include "pie/restorer-blob.h" #include "crtools.h" +#include "uffd.h" #include "namespaces.h" #include "mem.h" #include "mount.h" @@ -3204,6 +3205,11 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns strncpy(task_args->comm, core->tc->comm, sizeof(task_args->comm)); + if (!opts.lazy_pages) + task_args->uffd = -1; + else + if (setup_uffd(task_args, pid) != 0) + goto err; /* * Fill up per-thread data. diff --git a/criu/crtools.c b/criu/crtools.c index 2cd231e05..57433cffa 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -279,6 +279,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 }, +#ifdef CONFIG_HAS_UFFD + { "lazy-pages", no_argument, 0, 1076 }, +#endif BOOL_OPT("extra", &opts.check_extra_features), BOOL_OPT("experimental", &opts.check_experimental_features), { "all", no_argument, 0, 1079 }, @@ -519,6 +522,11 @@ int main(int argc, char *argv[], char *envp[]) case 1072: opts.timeout = atoi(optarg); break; +#ifdef CONFIG_HAS_UFFD + case 1076: + opts.lazy_pages = true; + break; +#endif case 'M': { char *aux; @@ -815,6 +823,12 @@ usage: " restore making it the parent of the restored process\n" " --freeze-cgroup use cgroup freezer to collect processes\n" " --weak-sysctls skip restoring sysctls that are not available\n" +#ifdef CONFIG_HAS_UFFD +" --lazy-pages restore pages on demand\n" +" this requires running a second instance of criu\n" +" in lazy-pages mode: 'criu lazy-pages -D DIR'\n" +" --lazy-pages and lazy-pages mode require userfaultfd\n" +#endif "\n" "* External resources support:\n" " --external RES dump objects from this list as external resources:\n" diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index b66742f9b..af530e9be 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -107,6 +107,7 @@ struct cr_options { unsigned int timeout; unsigned int empty_ns; int tcp_skip_in_flight; + bool lazy_pages; char *work_dir; /* diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 2748544c9..57b53e849 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -117,6 +117,8 @@ struct task_restore_args { unsigned int loglevel; struct timeval logstart; + int uffd; + /* threads restoration */ int nr_threads; /* number of threads */ thread_restore_fcall_t clone_restore_fn; /* helper address for clone() call */ diff --git a/criu/include/uffd.h b/criu/include/uffd.h index d5a043b0c..6c931e2b9 100644 --- a/criu/include/uffd.h +++ b/criu/include/uffd.h @@ -2,6 +2,7 @@ #define __CR_UFFD_H_ #include "config.h" +#include "restorer.h" #ifdef CONFIG_HAS_UFFD @@ -11,6 +12,11 @@ #ifndef __NR_userfaultfd #error "missing __NR_userfaultfd definition" #endif + +extern int setup_uffd(struct task_restore_args *task_args, int pid); +#else +static inline int setup_uffd(struct task_restore_args *task_args, int pid) { return 0; } + #endif /* CONFIG_HAS_UFFD */ #endif /* __CR_UFFD_H_ */ diff --git a/criu/include/vma.h b/criu/include/vma.h index ddffb7c86..7f38eeaa0 100644 --- a/criu/include/vma.h +++ b/criu/include/vma.h @@ -6,6 +6,8 @@ #include "images/vma.pb-c.h" +#include + struct vm_area_list { struct list_head h; unsigned nr; @@ -123,4 +125,11 @@ static inline struct vma_area *vma_next(struct vma_area *vma) return list_entry(vma->list.next, struct vma_area, list); } +static inline bool vma_entry_can_be_lazy(VmaEntry *e) +{ + return ((e->flags & MAP_ANONYMOUS) && + (e->flags & MAP_PRIVATE) && + !(vma_entry_is(e, VMA_AREA_VSYSCALL))); +} + #endif /* __CR_VMA_H__ */ diff --git a/criu/mem.c b/criu/mem.c index f88aaca27..9bd5a6aa4 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "types.h" #include "cr_options.h" @@ -17,6 +18,7 @@ #include "stats.h" #include "vma.h" #include "shmem.h" +#include "uffd.h" #include "pstree.h" #include "restorer.h" #include "rst-malloc.h" @@ -821,6 +823,7 @@ static int restore_priv_vma_content(struct pstree_item *t, struct page_read *pr) unsigned int nr_shared = 0; unsigned int nr_droped = 0; unsigned int nr_compared = 0; + unsigned int nr_lazy = 0; unsigned long va; vma = list_first_entry(vmas, struct vma_area, list); @@ -898,6 +901,17 @@ static int restore_priv_vma_content(struct pstree_item *t, struct page_read *pr) p = decode_pointer((off) * PAGE_SIZE + vma->premmaped_addr); + /* + * This means that userfaultfd is used to load the pages + * on demand. + */ + if (opts.lazy_pages && vma_entry_can_be_lazy(vma->e)) { + pr_debug("Lazy restore skips %#016"PRIx64"\n", vma->e->start); + pr.skip_pages(&pr, PAGE_SIZE); + nr_lazy++; + continue; + } + set_bit(off, vma->page_bitmap); if (vma_inherited(vma)) { clear_bit(off, vma->pvma->page_bitmap); @@ -986,6 +1000,7 @@ err_read: pr_info("nr_restored_pages: %d\n", nr_restored); pr_info("nr_shared_pages: %d\n", nr_shared); pr_info("nr_droped_pages: %d\n", nr_droped); + pr_info("nr_lazy: %d\n", nr_lazy); return 0; diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index d43da92a6..8e9059095 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -31,6 +31,7 @@ #include "image.h" #include "sk-inet.h" #include "vma.h" +#include "uffd.h" #include "common/lock.h" #include "restorer.h" @@ -783,8 +784,50 @@ static void rst_tcp_socks_all(struct task_restore_args *ta) rst_tcp_repair_off(&ta->tcp_socks[i]); } -static int vma_remap(unsigned long src, unsigned long dst, unsigned long len) + + + +static int enable_uffd(int uffd, unsigned long addr, unsigned long len) { + /* + * If uffd == -1, this means that userfaultfd is not enabled + * or it is not available. + */ + if (uffd == -1) + return 0; +#ifdef CONFIG_HAS_UFFD + int rc; + struct uffdio_register uffdio_register; + unsigned long expected_ioctls; + + uffdio_register.range.start = addr; + uffdio_register.range.len = len; + uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; + pr_info("lazy-pages: uffdio_register.range.start 0x%lx\n", (unsigned long) uffdio_register.range.start); + pr_info("lazy-pages: uffdio_register.len 0x%llx\n", uffdio_register.range.len); + rc = sys_ioctl(uffd, UFFDIO_REGISTER, &uffdio_register); + pr_info("lazy-pages: ioctl UFFDIO_REGISTER rc %d\n", rc); + pr_info("lazy-pages: uffdio_register.range.start 0x%lx\n", (unsigned long) uffdio_register.range.start); + pr_info("lazy-pages: uffdio_register.len 0x%llx\n", uffdio_register.range.len); + if (rc != 0) + return -1; + + expected_ioctls = (1 << _UFFDIO_WAKE) | (1 << _UFFDIO_COPY) | (1 << _UFFDIO_ZEROPAGE); + + if ((uffdio_register.ioctls & expected_ioctls) != expected_ioctls) { + pr_err("lazy-pages: unexpected missing uffd ioctl for anon memory\n"); + } + +#endif + return 0; +} + + +static int vma_remap(VmaEntry *vma_entry, int uffd) +{ + unsigned long src = vma_premmaped_start(vma_entry); + unsigned long dst = vma_entry->start; + unsigned long len = vma_entry_len(vma_entry); unsigned long guard = 0, tmp; pr_info("Remap %lx->%lx len %lx\n", src, dst, len); @@ -856,6 +899,18 @@ static int vma_remap(unsigned long src, unsigned long dst, unsigned long len) return -1; } + /* + * If running in userfaultfd/lazy-pages mode pages with + * MAP_ANONYMOUS and MAP_PRIVATE are remapped but without the + * real content. + * The function enable_uffd() marks the page(s) as userfaultfd + * pages, so that the processes will hang until the memory is + * injected via userfaultfd. + */ + if (vma_entry_can_be_lazy(vma_entry)) + if (enable_uffd(uffd, dst, len) != 0) + return -1; + return 0; } @@ -1134,6 +1189,10 @@ long __export_restore_task(struct task_restore_args *args) pr_info("Switched to the restorer %d\n", my_pid); + if (args->uffd > -1) { + pr_debug("lazy-pages: uffd %d\n", args->uffd); + } + if (!args->compatible_mode) { /* Compatible vDSO will be mapped, not moved */ if (vdso_do_park(&args->vdso_sym_rt, @@ -1162,8 +1221,7 @@ long __export_restore_task(struct task_restore_args *args) if (vma_entry->start > vma_entry->shmid) break; - if (vma_remap(vma_premmaped_start(vma_entry), - vma_entry->start, vma_entry_len(vma_entry))) + if (vma_remap(vma_entry, args->uffd)) goto core_restore_end; } @@ -1180,11 +1238,20 @@ long __export_restore_task(struct task_restore_args *args) if (vma_entry->start < vma_entry->shmid) break; - if (vma_remap(vma_premmaped_start(vma_entry), - vma_entry->start, vma_entry_len(vma_entry))) + if (vma_remap(vma_entry, args->uffd)) goto core_restore_end; } + if (args->uffd > -1) { + pr_debug("lazy-pages: closing uffd %d\n", args->uffd); + /* + * All userfaultfd configuration has finished at this point. + * Let's close the UFFD file descriptor, so that the restored + * process does not have an opened UFFD FD for ever. + */ + sys_close(args->uffd); + } + /* * OK, lets try to map new one. */ diff --git a/criu/uffd.c b/criu/uffd.c index 1f20faf79..c8e480506 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -32,6 +32,90 @@ #undef LOG_PREFIX #define LOG_PREFIX "lazy-pages: " +static int send_uffd(int sendfd, int pid) +{ + int fd; + int len; + int ret = -1; + struct sockaddr_un sun; + + if (!opts.addr) { + pr_info("Please specify a file name for the unix domain socket\n"); + pr_info("used to communicate between the lazy-pages server\n"); + pr_info("and the restore process. Use the --address option like\n"); + pr_info("criu restore --lazy-pages --address /tmp/userfault.socket\n"); + return -1; + } + + if (sendfd < 0) + return -1; + + if (strlen(opts.addr) >= sizeof(sun.sun_path)) { + return -1; + } + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return -1; + + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + strcpy(sun.sun_path, opts.addr); + len = offsetof(struct sockaddr_un, sun_path) + strlen(opts.addr); + if (connect(fd, (struct sockaddr *) &sun, len) < 0) { + pr_perror("connect to %s failed", opts.addr); + goto out; + } + + /* The "transfer protocol" is first the pid as int and then + * the FD for UFFD */ + pr_debug("Sending PID %d\n", pid); + if (send(fd, &pid, sizeof(pid), 0) < 0) { + pr_perror("PID sending error:"); + goto out; + } + + if (send_fd(fd, NULL, 0, sendfd) < 0) { + pr_perror("send_fd error:"); + goto out; + } + ret = 0; +out: + close(fd); + return ret; +} + +/* This function is used by 'criu restore --lazy-pages' */ +int setup_uffd(struct task_restore_args *task_args, int pid) +{ + struct uffdio_api uffdio_api; + /* + * Open userfaulfd FD which is passed to the restorer blob and + * to a second process handling the userfaultfd page faults. + */ + task_args->uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); + + /* + * Check if the UFFD_API is the one which is expected + */ + uffdio_api.api = UFFD_API; + uffdio_api.features = 0; + if (ioctl(task_args->uffd, UFFDIO_API, &uffdio_api)) { + pr_err("Checking for UFFDIO_API failed.\n"); + return -1; + } + if (uffdio_api.api != UFFD_API) { + pr_err("Result of looking up UFFDIO_API does not match: %Lu\n", uffdio_api.api); + return -1; + } + + if (send_uffd(task_args->uffd, pid) < 0) { + close(task_args->uffd); + return -1; + } + + return 0; +} + static int server_listen(struct sockaddr_un *saddr) { int fd; @@ -234,9 +318,7 @@ static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list, * in the VMA list. */ if (base >= vma->e->start && base < vma->e->end) { - if ((vma->e->flags & MAP_ANONYMOUS) && - (vma->e->flags & MAP_PRIVATE) && - !(vma_area_is(vma, VMA_AREA_VSYSCALL))) { + if (vma_entry_can_be_lazy(vma->e)) { uffd_page = true; if (vma_area_is(vma, VMA_AREA_VDSO)) uffd_vdso = true; From b8f46c368be115176d29145032759813de5dcaee Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 17 Mar 2016 17:13:00 +0300 Subject: [PATCH 0734/4375] Fix userfaultfd code with newer compilers Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/pie/restorer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 8e9059095..b4ec6cdfe 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -805,7 +805,7 @@ static int enable_uffd(int uffd, unsigned long addr, unsigned long len) uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; pr_info("lazy-pages: uffdio_register.range.start 0x%lx\n", (unsigned long) uffdio_register.range.start); pr_info("lazy-pages: uffdio_register.len 0x%llx\n", uffdio_register.range.len); - rc = sys_ioctl(uffd, UFFDIO_REGISTER, &uffdio_register); + rc = sys_ioctl(uffd, UFFDIO_REGISTER, (unsigned long) &uffdio_register); pr_info("lazy-pages: ioctl UFFDIO_REGISTER rc %d\n", rc); pr_info("lazy-pages: uffdio_register.range.start 0x%lx\n", (unsigned long) uffdio_register.range.start); pr_info("lazy-pages: uffdio_register.len 0x%llx\n", uffdio_register.range.len); From 33696ceba94cceb16ca123312b18cb3ad3a95af3 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Fri, 18 Mar 2016 14:27:00 +0300 Subject: [PATCH 0735/4375] uffd.c: do not call unneeded functions For a lazy restore via userfaultfd the lazy-pages daemon needs to know which pages exist, so that it knows when all pages have finally been migrated so that the restored process has all of its memory. Therefore it needs to know which pages exist and it needs to parse the files in the dump result directory. The existing criu functions are designed to be used by a 'normal' restore and thus a lot of assumptions are made what has to be set up. For the lazy-pages restore the complete 'restore' initialization is not necessary and therefore the criu common code dependencies are minimized with this commit. Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 80 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index c8e480506..ed47edd08 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -20,6 +20,7 @@ #include "include/criu-plugin.h" #include "include/pagemap.h" #include "include/files-reg.h" +#include "include/kerndat.h" #include "include/mem.h" #include "include/uffd.h" #include "include/util-pie.h" @@ -427,18 +428,69 @@ static int handle_vdso_pages(int uffd, struct list_head *uffd_list, unsigned lon } /* - * Setting up criu infrastructure to easily - * access the dump results. + * Setting up criu infrastructure and scan for VMAs. */ -static void criu_init() +static int find_vmas() { - /* TODO: return code checking */ - check_img_inventory(); - prepare_task_entries(); - prepare_pstree(); - collect_remaps_and_regfiles(); - prepare_shared_reg_files(); - prepare_mm_pid(root_item); + struct cr_img *img; + int ret; + struct vm_area_list vmas; + int vn = 0; + struct rst_info *ri; + + LIST_HEAD(uffd_list); + + if (check_img_inventory() == -1) + return -1; + + vm_area_list_init(&vmas); + + /* Allocate memory for task_entries */ + if (prepare_task_entries() == -1) + return -1; + + if (prepare_pstree() == -1) + return -1; + + ri = rsti(root_item); + if (!ri) + return -1; + + img = open_image(CR_FD_MM, O_RSTR, pid); + if (!img) + return -1; + + ret = pb_read_one_eof(img, &ri->mm, PB_MM); + close_image(img); + if (ret == -1) + return -1; + + pr_debug("Found %zd VMAs in image\n", ri->mm->n_vmas); + + while (vn < ri->mm->n_vmas) { + struct vma_area *vma; + + ret = -1; + vma = alloc_vma_area(); + if (!vma) + break; + + ret = 0; + ri->vmas.nr++; + vma->e = ri->mm->vmas[vn++]; + + list_add_tail(&vma->list, &ri->vmas.h); + + if (vma_area_is_private(vma, kdat.task_size)) { + vmas.priv_size += vma_area_len(vma); + if (vma->e->flags & MAP_GROWSDOWN) + vmas.priv_size += PAGE_SIZE; + } + + pr_info("vma 0x%"PRIx64" 0x%"PRIx64"\n", vma->e->start, vma->e->end); + } + + return ret; } int uffd_listen() @@ -478,8 +530,12 @@ int uffd_listen() uffd_flags = fcntl(uffd, F_GETFD, NULL); pr_debug("uffd_flags are 0x%x\n", uffd_flags); - /* Setting up criu infrastructure to easily access the dump results */ - criu_init(); + /* + * Find the memory pages belonging to the restored process + * so that it is trackable when all pages have been transferred. + */ + if (find_vmas() == -1) + return -1; /* Initialize FD sets for read() with timeouts (using select()) */ FD_ZERO(&set); From 9c7970c2ae3b2d53bb80cd2816dcc1a4db602dc2 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 23 Mar 2016 15:48:42 +0200 Subject: [PATCH 0736/4375] uffd: do not treat VDSO pages as lazy VDSO is just a few pages and they can be loaded directly rather than go through userfaultfd to save some complexity on the lazy-pages daemon side. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/vma.h | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/include/vma.h b/criu/include/vma.h index 7f38eeaa0..204f2d00b 100644 --- a/criu/include/vma.h +++ b/criu/include/vma.h @@ -129,6 +129,7 @@ static inline bool vma_entry_can_be_lazy(VmaEntry *e) { return ((e->flags & MAP_ANONYMOUS) && (e->flags & MAP_PRIVATE) && + !(vma_entry_is(e, VMA_AREA_VDSO)) && !(vma_entry_is(e, VMA_AREA_VSYSCALL))); } From fcaf36f52c9dbd5e76581a348589fd0f474b06d7 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 23 Mar 2016 15:48:43 +0200 Subject: [PATCH 0737/4375] uffd: remove handling of VDSO pages Since VDSO pages cannot be lazy, no need to take care of them in lazy-pages daemon. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 45 --------------------------------------------- 1 file changed, 45 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index ed47edd08..c4725e965 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -239,7 +239,6 @@ static int get_page(unsigned long addr, void *dest) } #define UFFD_FLAG_SENT 0x1 -#define UFFD_FLAG_VDSO 0x2 struct uffd_pages_struct { struct list_head list; @@ -306,7 +305,6 @@ static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list, for (i = 0; i < nr_pages; i++) { bool uffd_page = false; - bool uffd_vdso = false; base = (unsigned long) iov.iov_base + (i * ps); /* * Only pages which are MAP_ANONYMOUS and MAP_PRIVATE @@ -321,8 +319,6 @@ static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list, if (base >= vma->e->start && base < vma->e->end) { if (vma_entry_can_be_lazy(vma->e)) { uffd_page = true; - if (vma_area_is(vma, VMA_AREA_VDSO)) - uffd_vdso = true; break; } } @@ -339,8 +335,6 @@ static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list, if (!uffd_pages) return -1; uffd_pages->addr = base; - if (uffd_vdso) - uffd_pages->flags |= UFFD_FLAG_VDSO; list_add(&uffd_pages->list, uffd_list); } @@ -405,28 +399,6 @@ static int handle_regular_pages(int uffd, struct list_head *uffd_list, unsigned return 1; } -static int handle_vdso_pages(int uffd, struct list_head *uffd_list, unsigned long *vma_size, - void *dest) -{ - int rc; - struct uffd_pages_struct *uffd_pages; - int uffd_copied_pages = 0; - - list_for_each_entry(uffd_pages, uffd_list, list) { - if (!(uffd_pages->flags & UFFD_FLAG_VDSO)) - continue; - rc = uffd_copy_page(uffd, uffd_pages->addr, dest); - if (rc < 0) { - pr_err("Error during UFFD copy\n"); - return -1; - } - *vma_size -= rc; - uffd_copied_pages++; - uffd_pages->flags |= UFFD_FLAG_SENT; - } - return uffd_copied_pages; -} - /* * Setting up criu infrastructure and scan for VMAs. */ @@ -509,7 +481,6 @@ int uffd_listen() unsigned long total_pages = 0; int uffd_flags; struct uffd_pages_struct *uffd_pages; - bool vdso_sent = false; unsigned long vma_size = 0; LIST_HEAD(uffd_list); @@ -611,22 +582,6 @@ int uffd_listen() address = msg.arg.pagefault.address & ~(ps - 1); pr_debug("msg.arg.pagefault.address 0x%llx\n", address); - /* - * At this point the process on the other side waits for the first page. - * In the first step we will force the vdso pages into the new process. - */ - if (!vdso_sent) { - pr_debug("Pushing VDSO pages once\n"); - rc = handle_vdso_pages(uffd, &uffd_list, &vma_size, dest); - if (rc < 0) { - pr_err("Error during VDSO handling\n"); - rc = 1; - goto out; - } - uffd_copied_pages += rc; - vdso_sent = true; - } - /* Make sure to not transfer a page twice */ list_for_each_entry(uffd_pages, &uffd_list, list) { if ((uffd_pages->addr == address) && (uffd_pages->flags & UFFD_FLAG_SENT)) { From c3abfff0adfe38b2147114a7ee14d8c335268181 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 24 Mar 2016 15:52:50 +0000 Subject: [PATCH 0738/4375] uffd.c: remove unused variable vma_size The variable vma_size was used for early debugging of lazy restore and has no significance now. Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index c4725e965..f277ed1dd 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -281,8 +281,7 @@ static int uffd_copy_page(int uffd, __u64 address, void *dest) } -static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list, - unsigned long *vma_size) +static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list) { unsigned long base; int i; @@ -330,7 +329,6 @@ static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list, pr_debug("Adding 0x%lx to our list\n", base); - *vma_size += ps; uffd_pages = xzalloc(sizeof(struct uffd_pages_struct)); if (!uffd_pages) return -1; @@ -341,14 +339,12 @@ static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list, return 1; } -static int handle_remaining_pages(int uffd, struct list_head *uffd_list, unsigned long *vma_size, - void *dest) +static int handle_remaining_pages(int uffd, struct list_head *uffd_list, void *dest) { unsigned long uffd_copied_pages = 0; struct uffd_pages_struct *uffd_pages; int rc; - pr_debug("remaining vma_size: 0x%lx\n", *vma_size); pr_debug("uffd_copied_pages: %ld\n", uffd_copied_pages); list_for_each_entry(uffd_pages, uffd_list, list) { @@ -362,9 +358,7 @@ static int handle_remaining_pages(int uffd, struct list_head *uffd_list, unsigne pr_err("Error during UFFD copy\n"); return -1; } - *vma_size -= rc; - pr_debug("remaining vma_size: 0x%lx\n", *vma_size); uffd_copied_pages++; uffd_pages->flags |= UFFD_FLAG_SENT; } @@ -373,8 +367,7 @@ static int handle_remaining_pages(int uffd, struct list_head *uffd_list, unsigne } -static int handle_regular_pages(int uffd, struct list_head *uffd_list, unsigned long *vma_size, - void *dest, __u64 address) +static int handle_regular_pages(int uffd, struct list_head *uffd_list, void *dest, __u64 address) { int rc; struct uffd_pages_struct *uffd_pages; @@ -384,7 +377,6 @@ static int handle_regular_pages(int uffd, struct list_head *uffd_list, unsigned pr_err("Error during UFFD copy\n"); return -1; } - *vma_size -= rc; /* * Mark this page as having been already transferred, so @@ -481,7 +473,6 @@ int uffd_listen() unsigned long total_pages = 0; int uffd_flags; struct uffd_pages_struct *uffd_pages; - unsigned long vma_size = 0; LIST_HEAD(uffd_list); @@ -530,7 +521,7 @@ int uffd_listen() * pushed into the process using userfaultfd. */ do { - rc = collect_uffd_pages(&pr, &uffd_list, &vma_size); + rc = collect_uffd_pages(&pr, &uffd_list); if (rc == -1) { rc = 1; goto out; @@ -604,7 +595,7 @@ int uffd_listen() goto out; } - rc = handle_regular_pages(uffd, &uffd_list, &vma_size, dest, address); + rc = handle_regular_pages(uffd, &uffd_list, dest, address); if (rc < 0) { pr_err("Error during regular page copy\n"); rc = 1; @@ -615,7 +606,7 @@ int uffd_listen() } pr_debug("Handle remaining pages\n"); - rc = handle_remaining_pages(uffd, &uffd_list, &vma_size, dest); + rc = handle_remaining_pages(uffd, &uffd_list, dest); if (rc < 0) { pr_err("Error during remaining page copy\n"); rc = 1; From 048b31b24ca22a19c414ed7f0d3208f31a36df0d Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 24 Mar 2016 15:52:51 +0000 Subject: [PATCH 0739/4375] uffd.c: move code into subfunctions uffd_listen() is a rather large function and this starts to move code into subfunctions. Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 67 ++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index f277ed1dd..4b28a7347 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -394,15 +394,16 @@ static int handle_regular_pages(int uffd, struct list_head *uffd_list, void *des /* * Setting up criu infrastructure and scan for VMAs. */ -static int find_vmas() +static int find_vmas(struct list_head *uffd_list) { struct cr_img *img; int ret; struct vm_area_list vmas; int vn = 0; struct rst_info *ri; + struct page_read pr; + struct uffd_pages_struct *uffd_pages; - LIST_HEAD(uffd_list); if (check_img_inventory() == -1) return -1; @@ -437,7 +438,7 @@ static int find_vmas() ret = -1; vma = alloc_vma_area(); if (!vma) - break; + goto out; ret = 0; ri->vmas.nr++; @@ -454,6 +455,34 @@ static int find_vmas() pr_info("vma 0x%"PRIx64" 0x%"PRIx64"\n", vma->e->start, vma->e->end); } + ret = open_page_read(pid, &pr, PR_TASK); + if (ret <= 0) { + ret = -1; + goto out; + } + /* + * This puts all pages which should be handled by userfaultfd + * in the list uffd_list. This list is later used to detect if + * a page has already been transferred or if it needs to be + * pushed into the process using userfaultfd. + */ + do { + ret = collect_uffd_pages(&pr, uffd_list); + if (ret == -1) { + goto out; + } + } while (ret); + + if (pr.close) + pr.close(&pr); + + /* Count detected pages */ + list_for_each_entry(uffd_pages, uffd_list, list) + ret++; + + pr_debug("Found %d pages to be handled by UFFD\n", ret); + +out: return ret; } @@ -463,7 +492,6 @@ int uffd_listen() void *dest; __u64 flags; struct uffd_msg msg; - struct page_read pr; unsigned long ps; int rc; fd_set set; @@ -496,7 +524,7 @@ int uffd_listen() * Find the memory pages belonging to the restored process * so that it is trackable when all pages have been transferred. */ - if (find_vmas() == -1) + if ((total_pages = find_vmas(&uffd_list)) == -1) return -1; /* Initialize FD sets for read() with timeouts (using select()) */ @@ -509,35 +537,6 @@ int uffd_listen() if (!dest) goto out; - rc = open_page_read(pid, &pr, PR_TASK); - if (rc <= 0) { - rc = 1; - goto out; - } - /* - * This puts all pages which should be handled by userfaultfd - * in the list uffd_list. This list is later used to detect if - * a page has already been transferred or if it needs to be - * pushed into the process using userfaultfd. - */ - do { - rc = collect_uffd_pages(&pr, &uffd_list); - if (rc == -1) { - rc = 1; - goto out; - } - } while (rc); - - if (pr.close) - pr.close(&pr); - - - /* Count detected pages */ - list_for_each_entry(uffd_pages, &uffd_list, list) - total_pages++; - - pr_debug("Found %ld pages to be handled by UFFD\n", total_pages); - while (1) { bool page_sent = false; /* From b3ae1cc20bc3a5df9f5e79bfa06a9987541d8248 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 24 Mar 2016 15:52:52 +0000 Subject: [PATCH 0740/4375] uffd.c: make some variable static global To better track how many pages have been handled by UFFD a few variables have been made static global to easier access them and to reduce the number of parameters passed around. Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 4b28a7347..3869a0f48 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -246,6 +246,9 @@ struct uffd_pages_struct { int flags; }; +static unsigned long total_pages; +static unsigned long uffd_copied_pages; + static int uffd_copy_page(int uffd, __u64 address, void *dest) { struct uffdio_copy uffdio_copy; @@ -341,12 +344,9 @@ static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list) static int handle_remaining_pages(int uffd, struct list_head *uffd_list, void *dest) { - unsigned long uffd_copied_pages = 0; struct uffd_pages_struct *uffd_pages; int rc; - pr_debug("uffd_copied_pages: %ld\n", uffd_copied_pages); - list_for_each_entry(uffd_pages, uffd_list, list) { pr_debug("Checking remaining pages 0x%lx (flags 0x%x)\n", uffd_pages->addr, uffd_pages->flags); @@ -363,7 +363,7 @@ static int handle_remaining_pages(int uffd, struct list_head *uffd_list, void *d uffd_pages->flags |= UFFD_FLAG_SENT; } - return uffd_copied_pages; + return 0; } @@ -378,6 +378,7 @@ static int handle_regular_pages(int uffd, struct list_head *uffd_list, void *des return -1; } + uffd_copied_pages++; /* * Mark this page as having been already transferred, so * that it has not to be copied again later. @@ -387,8 +388,7 @@ static int handle_regular_pages(int uffd, struct list_head *uffd_list, void *des uffd_pages->flags |= UFFD_FLAG_SENT; } - - return 1; + return 0; } /* @@ -497,8 +497,6 @@ int uffd_listen() fd_set set; struct timeval timeout; int uffd; - unsigned long uffd_copied_pages = 0; - unsigned long total_pages = 0; int uffd_flags; struct uffd_pages_struct *uffd_pages; @@ -600,9 +598,6 @@ int uffd_listen() rc = 1; goto out; } - - uffd_copied_pages += rc; - } pr_debug("Handle remaining pages\n"); rc = handle_remaining_pages(uffd, &uffd_list, dest); @@ -612,7 +607,6 @@ int uffd_listen() goto out; } - uffd_copied_pages += rc; pr_debug("With UFFD transferred pages: (%ld/%ld)\n", uffd_copied_pages, total_pages); if (uffd_copied_pages != total_pages) { pr_warn("Only %ld of %ld pages transferred via UFFD\n", uffd_copied_pages, From a7004002b5800eac0f01d8c7f3e3a407404bf055 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 24 Mar 2016 15:52:53 +0000 Subject: [PATCH 0741/4375] uffd.c: move the code out of the 'main' function Most of the UFFD logic was in the function uffd_listen() which was directly called from crtools.c. In preparation for the remote lazy restore most of the code has been moved to separate function for better integration of the network functionality. Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 109 ++++++++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 3869a0f48..7c565676b 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -486,38 +486,20 @@ out: return ret; } -int uffd_listen() +static int handle_requests(int fd) { - __u64 address; - void *dest; - __u64 flags; - struct uffd_msg msg; - unsigned long ps; - int rc; fd_set set; + int ret = -1; + struct uffd_msg msg; + __u64 flags; + __u64 address; + unsigned long ps; struct timeval timeout; - int uffd; - int uffd_flags; struct uffd_pages_struct *uffd_pages; + void *dest; LIST_HEAD(uffd_list); - if (!opts.addr) { - pr_info("Please specify a file name for the unix domain socket\n"); - pr_info("used to communicate between the lazy-pages server\n"); - pr_info("and the restore process. Use the --address option like\n"); - pr_info("criu --lazy-pages --address /tmp/userfault.socket\n"); - return -1; - } - - pr_debug("Waiting for incoming connections on %s\n", opts.addr); - if ((uffd = ud_open()) < 0) - exit(0); - - pr_debug("uffd is 0x%d\n", uffd); - uffd_flags = fcntl(uffd, F_GETFD, NULL); - pr_debug("uffd_flags are 0x%x\n", uffd_flags); - /* * Find the memory pages belonging to the restored process * so that it is trackable when all pages have been transferred. @@ -527,13 +509,13 @@ int uffd_listen() /* Initialize FD sets for read() with timeouts (using select()) */ FD_ZERO(&set); - FD_SET(uffd, &set); + FD_SET(fd, &set); /* All operations will be done on page size */ ps = page_size(); dest = xmalloc(ps); if (!dest) - goto out; + return ret; while (1) { bool page_sent = false; @@ -548,24 +530,25 @@ int uffd_listen() */ timeout.tv_sec = 5; timeout.tv_usec = 0; - rc = select(uffd + 1, &set, NULL, NULL, &timeout); - pr_debug("select() rc: 0x%x\n", rc); - if (rc == 0) { + ret = select(fd + 1, &set, NULL, NULL, &timeout); + pr_debug("select() rc: 0x%x\n", ret); + if (ret == 0) { pr_debug("read timeout\n"); pr_debug("switching from request to copy mode\n"); break; } - rc = read(uffd, &msg, sizeof(msg)); - pr_debug("read() rc: 0x%x\n", rc); + ret = read(fd, &msg, sizeof(msg)); + pr_debug("read() ret: 0x%x\n", ret); + if (!ret) + break; - if (rc != sizeof(msg)) { - if (rc < 0) - pr_perror("read error"); - else - pr_debug("short read\n"); - continue; + if (ret != sizeof(msg)) { + pr_perror("Can't read userfaultfd message from socket"); + ret = -1; + break; } + ret = 0; /* Align requested address to the next page boundary */ address = msg.arg.pagefault.address & ~(ps - 1); pr_debug("msg.arg.pagefault.address 0x%llx\n", address); @@ -588,37 +571,63 @@ int uffd_listen() if (msg.event != UFFD_EVENT_PAGEFAULT) { pr_err("unexpected msg event %u\n", msg.event); - rc = 1; + ret = -1; goto out; } - rc = handle_regular_pages(uffd, &uffd_list, dest, address); - if (rc < 0) { + ret = handle_regular_pages(fd, &uffd_list, dest, address); + if (ret < 0) { pr_err("Error during regular page copy\n"); - rc = 1; + ret = -1; goto out; } } pr_debug("Handle remaining pages\n"); - rc = handle_remaining_pages(uffd, &uffd_list, dest); - if (rc < 0) { + ret = handle_remaining_pages(fd, &uffd_list, dest); + if (ret < 0) { pr_err("Error during remaining page copy\n"); - rc = 1; + ret = 1; goto out; } pr_debug("With UFFD transferred pages: (%ld/%ld)\n", uffd_copied_pages, total_pages); - if (uffd_copied_pages != total_pages) { + if ((uffd_copied_pages != total_pages) && (total_pages > 0)) { pr_warn("Only %ld of %ld pages transferred via UFFD\n", uffd_copied_pages, total_pages); pr_warn("Something probably went wrong.\n"); - rc = 1; + ret = 1; goto out; } - rc = 0; + ret = 0; out: free(dest); - close(uffd); - return rc; + close(fd); + return ret; + +} +int uffd_listen() +{ + int uffd; + int uffd_flags; + + LIST_HEAD(uffd_list); + + if (!opts.addr) { + pr_info("Please specify a file name for the unix domain socket\n"); + pr_info("used to communicate between the lazy-pages server\n"); + pr_info("and the restore process. Use the --address option like\n"); + pr_info("criu --lazy-pages --address /tmp/userfault.socket\n"); + return -1; + } + + pr_debug("Waiting for incoming connections on %s\n", opts.addr); + if ((uffd = ud_open()) < 0) + exit(0); + + pr_debug("uffd is 0x%d\n", uffd); + uffd_flags = fcntl(uffd, F_GETFD, NULL); + pr_debug("uffd_flags are 0x%x\n", uffd_flags); + + return handle_requests(uffd); } From e3f05ea0ca1b9ac240c86df3b429a249afc6bb47 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 31 Mar 2016 14:39:19 +0300 Subject: [PATCH 0742/4375] uffd: increment uffd_copied_pages only in one place The uffd_copied_pages can be incremented in uffd_copy_page function rather than in its callers Signed-off-by: Mike Rapoport Acked-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 7c565676b..02ca198ba 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -279,6 +279,7 @@ static int uffd_copy_page(int uffd, __u64 address, void *dest) return -1; } + uffd_copied_pages++; return uffdio_copy.copy; @@ -359,7 +360,6 @@ static int handle_remaining_pages(int uffd, struct list_head *uffd_list, void *d return -1; } - uffd_copied_pages++; uffd_pages->flags |= UFFD_FLAG_SENT; } @@ -378,7 +378,6 @@ static int handle_regular_pages(int uffd, struct list_head *uffd_list, void *des return -1; } - uffd_copied_pages++; /* * Mark this page as having been already transferred, so * that it has not to be copied again later. From 58edba63f9ea8555300f9be623e8da4f125386f0 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 31 Mar 2016 14:39:20 +0300 Subject: [PATCH 0743/4375] uffd: introduce uffd_handle_page so that it'll be able to handle both UFFDIO_COPY and UFFDIO_ZEROPAGE Signed-off-by: Mike Rapoport Acked-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 02ca198ba..4764522b9 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -285,6 +285,11 @@ static int uffd_copy_page(int uffd, __u64 address, void *dest) } +static int uffd_handle_page(int uffd, __u64 address, void *dest) +{ + return uffd_copy_page(uffd, address, dest); +} + static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list) { unsigned long base; @@ -354,7 +359,7 @@ static int handle_remaining_pages(int uffd, struct list_head *uffd_list, void *d if (uffd_pages->flags & UFFD_FLAG_SENT) continue; - rc = uffd_copy_page(uffd, uffd_pages->addr, dest); + rc = uffd_handle_page(uffd, uffd_pages->addr, dest); if (rc < 0) { pr_err("Error during UFFD copy\n"); return -1; @@ -372,7 +377,7 @@ static int handle_regular_pages(int uffd, struct list_head *uffd_list, void *des int rc; struct uffd_pages_struct *uffd_pages; - rc = uffd_copy_page(uffd, address, dest); + rc = uffd_handle_page(uffd, address, dest); if (rc < 0) { pr_err("Error during UFFD copy\n"); return -1; From 6273fc971aec6fbe5f191b7253cec8c00df74913 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 31 Mar 2016 14:39:21 +0300 Subject: [PATCH 0744/4375] uffd: add handling of zero pages When get_page returns 0, it means that a page is mapped by a vma but it is not found in the pagemap. This happens when a page is a zero page and threofre skipped by dump. Use UFFDIO_ZEROMAP to create a zero page in the restored process address space. Signed-off-by: Mike Rapoport Acked-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 4764522b9..fdd5f2b78 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -256,7 +256,7 @@ static int uffd_copy_page(int uffd, __u64 address, void *dest) rc = get_page(address, dest); if (rc <= 0) - return -1; + return rc; uffdio_copy.dst = address; uffdio_copy.src = (unsigned long) dest; @@ -285,9 +285,37 @@ static int uffd_copy_page(int uffd, __u64 address, void *dest) } +static int uffd_zero_page(int uffd, __u64 address) +{ + struct uffdio_zeropage uffdio_zeropage; + unsigned long ps = page_size(); + int rc; + + uffdio_zeropage.range.start = address; + uffdio_zeropage.range.len = ps; + uffdio_zeropage.mode = 0; + + pr_debug("uffdio_zeropage.range.start 0x%llx\n", uffdio_zeropage.range.start); + rc = ioctl(uffd, UFFDIO_ZEROPAGE, &uffdio_zeropage); + pr_debug("ioctl UFFDIO_ZEROPAGE rc 0x%x\n", rc); + pr_debug("uffdio_zeropage.zeropage 0x%llx\n", uffdio_zeropage.zeropage); + if (rc) { + pr_err("UFFDIO_ZEROPAGE error %d\n", rc); + return -1; + } + + return ps; +} + static int uffd_handle_page(int uffd, __u64 address, void *dest) { - return uffd_copy_page(uffd, address, dest); + int rc; + + rc = uffd_copy_page(uffd, address, dest); + if (rc == 0) + rc = uffd_zero_page(uffd, address); + + return rc; } static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list) From 8337e99857130fbee325f12a837382935af0331d Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 12 Apr 2016 20:52:00 +0300 Subject: [PATCH 0745/4375] ppc64le: fix build with UFFD The __u64 is 'unsigned long' on Power and 'unsigned long long' on x86_64. Using PRI?64 does not help because, for instance, PRIu64 is 'lu'. According to [1] the solution is to define __SANE_USERSPACE_TYPES__ for Power builds [1] http://thread.gmane.org/gmane.linux.kernel/1425475/focus=1427433 Signed-off-by: Mike Rapoport Acked-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f2583a272..0dd5e8374 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ endif ifeq ($(ARCH),ppc64) LDARCH := powerpc:common64 VDSO := y - DEFINES := -DCONFIG_PPC64 + DEFINES := -DCONFIG_PPC64 -D__SANE_USERSPACE_TYPES__ endif ifeq ($(ARCH),x86) From 34693cb44443b0460c5c9bab5d2c2ed5046658da Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 11 Apr 2016 09:19:44 +0300 Subject: [PATCH 0746/4375] Rename uffd_listen to cr_lazy_pages Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/crtools.c | 2 +- criu/include/crtools.h | 4 ++-- criu/uffd.c | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index 57433cffa..0792e958a 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -742,7 +742,7 @@ int main(int argc, char *argv[], char *envp[]) } if (!strcmp(argv[optind], "lazy-pages")) - return uffd_listen() != 0; + return cr_lazy_pages() != 0; if (!strcmp(argv[optind], "check")) return cr_check() != 0; diff --git a/criu/include/crtools.h b/criu/include/crtools.h index c0f51bce3..09645ce41 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -26,9 +26,9 @@ extern int convert_to_elf(char *elf_path, int fd_core); extern int cr_check(void); extern int cr_dedup(void); #ifdef CONFIG_HAS_UFFD -extern int uffd_listen(void); +extern int cr_lazy_pages(void); #else -static inline int uffd_listen() { return 0; }; +static inline int cr_lazy_pages() { return 0; }; #endif /* CONFIG_HAS_UFFD */ extern int check_add_feature(char *arg); diff --git a/criu/uffd.c b/criu/uffd.c index fdd5f2b78..0d3f1c202 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -638,7 +638,8 @@ out: return ret; } -int uffd_listen() + +int cr_lazy_pages() { int uffd; int uffd_flags; From d08ea98bd7bcf494ed442a7b4ce4707a7e88281f Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 11 Apr 2016 09:19:45 +0300 Subject: [PATCH 0747/4375] lazy-pages: always compile uffd.c If CONFIG_HAS_UFFD is not defined an attempt to run the lazy pages daemon will result in error message Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/Makefile.crtools | 2 -- criu/crtools.c | 8 -------- criu/include/crtools.h | 4 ---- criu/uffd.c | 12 ++++++++++++ 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index d86814a5e..75f043a15 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -92,9 +92,7 @@ obj-$(CONFIG_COMPAT) += vdso-compat.o CFLAGS_REMOVE_vdso-compat.o += $(CFLAGS-ASAN) $(CFLAGS-GCOV) endif -ifeq ($(UFFD),1) obj-y += uffd.o -endif PROTOBUF_GEN := scripts/protobuf-gen.sh diff --git a/criu/crtools.c b/criu/crtools.c index 0792e958a..8e3784aa4 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -279,9 +279,7 @@ int main(int argc, char *argv[], char *envp[]) { "timeout", required_argument, 0, 1072 }, { "external", required_argument, 0, 1073 }, { "empty-ns", required_argument, 0, 1074 }, -#ifdef CONFIG_HAS_UFFD { "lazy-pages", no_argument, 0, 1076 }, -#endif BOOL_OPT("extra", &opts.check_extra_features), BOOL_OPT("experimental", &opts.check_experimental_features), { "all", no_argument, 0, 1079 }, @@ -522,11 +520,9 @@ int main(int argc, char *argv[], char *envp[]) case 1072: opts.timeout = atoi(optarg); break; -#ifdef CONFIG_HAS_UFFD case 1076: opts.lazy_pages = true; break; -#endif case 'M': { char *aux; @@ -777,9 +773,7 @@ usage: " criu page-server\n" " criu service []\n" " criu dedup\n" -#ifdef CONFIG_HAS_UFFD " criu lazy-pages -D DIR []\n" -#endif "\n" "Commands:\n" " dump checkpoint a process/tree identified by pid\n" @@ -823,12 +817,10 @@ usage: " restore making it the parent of the restored process\n" " --freeze-cgroup use cgroup freezer to collect processes\n" " --weak-sysctls skip restoring sysctls that are not available\n" -#ifdef CONFIG_HAS_UFFD " --lazy-pages restore pages on demand\n" " this requires running a second instance of criu\n" " in lazy-pages mode: 'criu lazy-pages -D DIR'\n" " --lazy-pages and lazy-pages mode require userfaultfd\n" -#endif "\n" "* External resources support:\n" " --external RES dump objects from this list as external resources:\n" diff --git a/criu/include/crtools.h b/criu/include/crtools.h index 09645ce41..15d6d732f 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -25,11 +25,7 @@ extern int cr_restore_tasks(void); extern int convert_to_elf(char *elf_path, int fd_core); extern int cr_check(void); extern int cr_dedup(void); -#ifdef CONFIG_HAS_UFFD extern int cr_lazy_pages(void); -#else -static inline int cr_lazy_pages() { return 0; }; -#endif /* CONFIG_HAS_UFFD */ extern int check_add_feature(char *arg); extern void pr_check_features(const char *offset, const char *sep, int width); diff --git a/criu/uffd.c b/criu/uffd.c index 0d3f1c202..78d4ee598 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -30,6 +30,8 @@ #include "include/cr_options.h" #include "xmalloc.h" +#ifdef CONFIG_HAS_UFFD + #undef LOG_PREFIX #define LOG_PREFIX "lazy-pages: " @@ -664,3 +666,13 @@ int cr_lazy_pages() return handle_requests(uffd); } + +#else /* CONFIG_HAS_UFFD */ + +int cr_lazy_pages() +{ + pr_msg("userfaultfd system call is not supported, cannot start lazy-pages daemon\n"); + return -1; +} + +#endif /* CONFIG_HAS_UFFD */ From 1c54c0034ec9da40f7a26d1c6ea5ae7d00a61bb8 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 11 Apr 2016 09:19:46 +0300 Subject: [PATCH 0748/4375] lazy-pages: refactor unix socket initializaton so that listenning file descriptor might be used in select/poll Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 78d4ee598..f89e2fb26 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -155,23 +155,16 @@ out: static int pid; -static int ud_open() +static int ud_open(int listen, struct sockaddr_un *saddr) { int client; - int listen; int newfd; int ret = -1; - struct sockaddr_un saddr; socklen_t len; - if ((listen = server_listen(&saddr)) < 0) { - pr_perror("server_listen error"); - return -1; - } - /* accept new client request */ len = sizeof(struct sockaddr_un); - if ((client = accept(listen, (struct sockaddr *)&saddr, &len)) < 0) { + if ((client = accept(listen, (struct sockaddr *)saddr, &len)) < 0) { pr_perror("server_accept error: %d", client); close(listen); return -1; @@ -199,7 +192,6 @@ static int ud_open() return newfd; out: - close(listen); close(client); return ret; } @@ -643,10 +635,11 @@ out: int cr_lazy_pages() { + int listen; int uffd; int uffd_flags; - - LIST_HEAD(uffd_list); + int ret; + struct sockaddr_un saddr; if (!opts.addr) { pr_info("Please specify a file name for the unix domain socket\n"); @@ -657,14 +650,25 @@ int cr_lazy_pages() } pr_debug("Waiting for incoming connections on %s\n", opts.addr); - if ((uffd = ud_open()) < 0) - exit(0); + if ((listen = server_listen(&saddr)) < 0) { + pr_perror("server_listen error"); + return -1; + } + + uffd = ud_open(listen, &saddr); + if (uffd < 0) { + pr_perror("uffd open error"); + return -1; + } pr_debug("uffd is 0x%d\n", uffd); uffd_flags = fcntl(uffd, F_GETFD, NULL); pr_debug("uffd_flags are 0x%x\n", uffd_flags); - return handle_requests(uffd); + ret = handle_requests(uffd); + close(listen); + + return ret; } #else /* CONFIG_HAS_UFFD */ From 7c78a48b068296ea3dc670798beb1a4fb35856fc Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 11 Apr 2016 09:19:47 +0300 Subject: [PATCH 0749/4375] lazy-pages: initialize process tree early Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index f89e2fb26..212d00638 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -430,19 +431,8 @@ static int find_vmas(struct list_head *uffd_list) struct page_read pr; struct uffd_pages_struct *uffd_pages; - - if (check_img_inventory() == -1) - return -1; - vm_area_list_init(&vmas); - /* Allocate memory for task_entries */ - if (prepare_task_entries() == -1) - return -1; - - if (prepare_pstree() == -1) - return -1; - ri = rsti(root_item); if (!ri) return -1; @@ -633,6 +623,27 @@ out: } +static int lazy_pages_prepare_pstree(void) +{ + if (check_img_inventory() == -1) + return -1; + + /* Allocate memory for task_entries */ + if (prepare_task_entries() == -1) + return -1; + + if (prepare_pstree() == -1) + return -1; + + /* bail out early until we know how to handle multiple tasks */ + if (task_entries->nr_tasks > 1) { + pr_msg("lazy-pages cannot restore more than one task, sorry\n"); + return -1; + } + + return 0; +} + int cr_lazy_pages() { int listen; @@ -649,6 +660,9 @@ int cr_lazy_pages() return -1; } + if (lazy_pages_prepare_pstree()) + return -1; + pr_debug("Waiting for incoming connections on %s\n", opts.addr); if ((listen = server_listen(&saddr)) < 0) { pr_perror("server_listen error"); From 10ef42762337bb15f46d9ab44d6fd903f1ea8ef1 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 18 Apr 2016 16:34:32 +0300 Subject: [PATCH 0750/4375] UFFD related makefiles cleanup Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- Makefile.config | 10 +--------- criu/Makefile.crtools | 3 +-- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/Makefile.config b/Makefile.config index 8fb4e6b69..7851f826f 100644 --- a/Makefile.config +++ b/Makefile.config @@ -35,12 +35,8 @@ endif export DEFINES += $(FEATURE_DEFINES) export CFLAGS += $(FEATURE_DEFINES) -ifeq ($(call try-cc,$(FEATURE_TEST_UFFD)),y) - export UFFD := 1 -endif - FEATURES_LIST := TCP_REPAIR STRLCPY STRLCAT PTRACE_PEEKSIGINFO \ - SETPROCTITLE_INIT MEMFD TCP_REPAIR_WINDOW + SETPROCTITLE_INIT MEMFD TCP_REPAIR_WINDOW UFFD # $1 - config name define gen-feature-test @@ -61,10 +57,6 @@ $(call map,gen-feature-test,$(FEATURES_LIST)) ifeq ($$(VDSO),y) $(Q) @echo '#define CONFIG_VDSO' >> $$@ $(Q) @echo '' >> $$@ -endif -ifeq ($$(UFFD),1) - $(Q) @echo '#define CONFIG_HAS_UFFD' >> $$@ - $(Q) @echo '' >> $$@ endif $(Q) @echo '#endif /* __CR_CONFIG_H__ */' >> $$@ endef diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 75f043a15..0d28dee3e 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -82,6 +82,7 @@ obj-y += uts_ns.o obj-y += path.o obj-y += autofs.o obj-y += fdstore.o +obj-y += uffd.o ifeq ($(VDSO),y) obj-y += pie-util-vdso.o @@ -92,8 +93,6 @@ obj-$(CONFIG_COMPAT) += vdso-compat.o CFLAGS_REMOVE_vdso-compat.o += $(CFLAGS-ASAN) $(CFLAGS-GCOV) endif -obj-y += uffd.o - PROTOBUF_GEN := scripts/protobuf-gen.sh $(obj)/protobuf-desc.d: $(obj)/protobuf-desc-gen.h From 0b9014511e06fbfce975a2fbdfac25a0df2802a7 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 18 Apr 2016 16:34:33 +0300 Subject: [PATCH 0751/4375] lazy-pages: introduce handle_user_fault It will handle page fault notifications from userfaultfd Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 94 ++++++++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 212d00638..2f66b8274 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -502,16 +502,57 @@ out: return ret; } +static int handle_user_fault(int fd, struct list_head *uffd_list, void *dest) +{ + struct uffd_msg msg; + __u64 flags; + __u64 address; + struct uffd_pages_struct *uffd_pages; + int ret; + + ret = read(fd, &msg, sizeof(msg)); + pr_debug("read() ret: 0x%x\n", ret); + if (!ret) + return 1; + + if (ret != sizeof(msg)) { + pr_perror("Can't read userfaultfd message"); + return -1; + } + + /* Align requested address to the next page boundary */ + address = msg.arg.pagefault.address & ~(page_size() - 1); + pr_debug("msg.arg.pagefault.address 0x%llx\n", address); + + /* Make sure to not transfer a page twice */ + list_for_each_entry(uffd_pages, uffd_list, list) + if ((uffd_pages->addr == address) && (uffd_pages->flags & UFFD_FLAG_SENT)) + return 0; + + /* Now handle the pages actually requested. */ + flags = msg.arg.pagefault.flags; + pr_debug("msg.arg.pagefault.flags 0x%llx\n", flags); + + if (msg.event != UFFD_EVENT_PAGEFAULT) { + pr_err("unexpected msg event %u\n", msg.event); + return -1; + } + + ret = handle_regular_pages(fd, uffd_list, dest, address); + if (ret < 0) { + pr_err("Error during regular page copy\n"); + return -1; + } + + return 0; +} + static int handle_requests(int fd) { fd_set set; int ret = -1; - struct uffd_msg msg; - __u64 flags; - __u64 address; unsigned long ps; struct timeval timeout; - struct uffd_pages_struct *uffd_pages; void *dest; LIST_HEAD(uffd_list); @@ -534,7 +575,6 @@ static int handle_requests(int fd) return ret; while (1) { - bool page_sent = false; /* * Setting the timeout to 5 seconds. If after this time * no uffd pages are requested the code switches to @@ -553,50 +593,10 @@ static int handle_requests(int fd) pr_debug("switching from request to copy mode\n"); break; } - ret = read(fd, &msg, sizeof(msg)); - pr_debug("read() ret: 0x%x\n", ret); - if (!ret) - break; - if (ret != sizeof(msg)) { - pr_perror("Can't read userfaultfd message from socket"); - ret = -1; - break; - } - - ret = 0; - /* Align requested address to the next page boundary */ - address = msg.arg.pagefault.address & ~(ps - 1); - pr_debug("msg.arg.pagefault.address 0x%llx\n", address); - - /* Make sure to not transfer a page twice */ - list_for_each_entry(uffd_pages, &uffd_list, list) { - if ((uffd_pages->addr == address) && (uffd_pages->flags & UFFD_FLAG_SENT)) { - page_sent = true; - break; - } - } - - if (page_sent) - continue; - - /* Now handle the pages actually requested. */ - - flags = msg.arg.pagefault.flags; - pr_debug("msg.arg.pagefault.flags 0x%llx\n", flags); - - if (msg.event != UFFD_EVENT_PAGEFAULT) { - pr_err("unexpected msg event %u\n", msg.event); - ret = -1; + ret = handle_user_fault(fd, &uffd_list, dest); + if (ret < 0) goto out; - } - - ret = handle_regular_pages(fd, &uffd_list, dest, address); - if (ret < 0) { - pr_err("Error during regular page copy\n"); - ret = -1; - goto out; - } } pr_debug("Handle remaining pages\n"); ret = handle_remaining_pages(fd, &uffd_list, dest); From 6490d5d347c27e06ca30f1531abd8052c231db6d Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 18 Apr 2016 16:34:34 +0300 Subject: [PATCH 0752/4375] lazy-pages: introduce lazy_pages_summary It verifies that amount of collected and transferred pages is consitent and prints a summary Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 2f66b8274..e07675f9b 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -547,6 +547,20 @@ static int handle_user_fault(int fd, struct list_head *uffd_list, void *dest) return 0; } +static int lazy_pages_summary(void) +{ + pr_debug("With UFFD transferred pages: (%ld/%ld)\n", uffd_copied_pages, total_pages); + + if ((uffd_copied_pages != total_pages) && (total_pages > 0)) { + pr_warn("Only %ld of %ld pages transferred via UFFD\n", uffd_copied_pages, + total_pages); + pr_warn("Something probably went wrong.\n"); + return 1; + } + + return 0; +} + static int handle_requests(int fd) { fd_set set; @@ -606,15 +620,7 @@ static int handle_requests(int fd) goto out; } - pr_debug("With UFFD transferred pages: (%ld/%ld)\n", uffd_copied_pages, total_pages); - if ((uffd_copied_pages != total_pages) && (total_pages > 0)) { - pr_warn("Only %ld of %ld pages transferred via UFFD\n", uffd_copied_pages, - total_pages); - pr_warn("Something probably went wrong.\n"); - ret = 1; - goto out; - } - ret = 0; + ret = lazy_pages_summary(); out: free(dest); From b9596b5635466269b99a7f3766a070cb87e30a90 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 18 Apr 2016 16:34:35 +0300 Subject: [PATCH 0753/4375] lazy-pages: introduce struct lazy_pages_info for holding state related to userfaultfd handling Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 183 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 109 insertions(+), 74 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index e07675f9b..b915dd4b0 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -36,6 +36,16 @@ #undef LOG_PREFIX #define LOG_PREFIX "lazy-pages: " +struct lazy_pages_info { + int pid; + int uffd; + + struct list_head pages; + + unsigned long total_pages; + unsigned long copied_pages; +}; + static int send_uffd(int sendfd, int pid) { int fd; @@ -197,14 +207,14 @@ out: return ret; } -static int get_page(unsigned long addr, void *dest) +static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest) { struct iovec iov; int ret; unsigned char buf[PAGE_SIZE]; struct page_read pr; - ret = open_page_read(pid, &pr, PR_TASK | PR_MOD); + ret = open_page_read(lpi->pid, &pr, PR_TASK | PR_MOD); pr_debug("get_page ret %d\n", ret); ret = pr.get_pagemap(&pr, &iov); @@ -241,15 +251,13 @@ struct uffd_pages_struct { int flags; }; -static unsigned long total_pages; -static unsigned long uffd_copied_pages; - -static int uffd_copy_page(int uffd, __u64 address, void *dest) +static int uffd_copy_page(struct lazy_pages_info *lpi, __u64 address, + void *dest) { struct uffdio_copy uffdio_copy; int rc; - rc = get_page(address, dest); + rc = get_page(lpi, address, dest); if (rc <= 0) return rc; @@ -260,7 +268,7 @@ static int uffd_copy_page(int uffd, __u64 address, void *dest) uffdio_copy.copy = 0; pr_debug("uffdio_copy.dst 0x%llx\n", uffdio_copy.dst); - rc = ioctl(uffd, UFFDIO_COPY, &uffdio_copy); + rc = ioctl(lpi->uffd, UFFDIO_COPY, &uffdio_copy); pr_debug("ioctl UFFDIO_COPY rc 0x%x\n", rc); pr_debug("uffdio_copy.copy 0x%llx\n", uffdio_copy.copy); if (rc) { @@ -274,13 +282,13 @@ static int uffd_copy_page(int uffd, __u64 address, void *dest) return -1; } - uffd_copied_pages++; + lpi->copied_pages++; return uffdio_copy.copy; } -static int uffd_zero_page(int uffd, __u64 address) +static int uffd_zero_page(struct lazy_pages_info *lpi, __u64 address) { struct uffdio_zeropage uffdio_zeropage; unsigned long ps = page_size(); @@ -291,7 +299,7 @@ static int uffd_zero_page(int uffd, __u64 address) uffdio_zeropage.mode = 0; pr_debug("uffdio_zeropage.range.start 0x%llx\n", uffdio_zeropage.range.start); - rc = ioctl(uffd, UFFDIO_ZEROPAGE, &uffdio_zeropage); + rc = ioctl(lpi->uffd, UFFDIO_ZEROPAGE, &uffdio_zeropage); pr_debug("ioctl UFFDIO_ZEROPAGE rc 0x%x\n", rc); pr_debug("uffdio_zeropage.zeropage 0x%llx\n", uffdio_zeropage.zeropage); if (rc) { @@ -302,18 +310,19 @@ static int uffd_zero_page(int uffd, __u64 address) return ps; } -static int uffd_handle_page(int uffd, __u64 address, void *dest) +static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address, + void *dest) { int rc; - rc = uffd_copy_page(uffd, address, dest); + rc = uffd_copy_page(lpi, address, dest); if (rc == 0) - rc = uffd_zero_page(uffd, address); + rc = uffd_zero_page(lpi, address); return rc; } -static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list) +static int collect_uffd_pages(struct page_read *pr, struct lazy_pages_info *lpi) { unsigned long base; int i; @@ -323,7 +332,12 @@ static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list) int rc; struct uffd_pages_struct *uffd_pages; struct vma_area *vma; - struct vm_area_list *vmas = &rsti(root_item)->vmas; + struct vm_area_list *vmas; + struct pstree_item *item = pstree_item_by_virt(lpi->pid); + + BUG_ON(!item); + + vmas = &rsti(item)->vmas; rc = pr->get_pagemap(pr, &iov); if (rc <= 0) @@ -365,24 +379,24 @@ static int collect_uffd_pages(struct page_read *pr, struct list_head *uffd_list) if (!uffd_pages) return -1; uffd_pages->addr = base; - list_add(&uffd_pages->list, uffd_list); + list_add(&uffd_pages->list, &lpi->pages); } return 1; } -static int handle_remaining_pages(int uffd, struct list_head *uffd_list, void *dest) +static int handle_remaining_pages(struct lazy_pages_info *lpi, void *dest) { struct uffd_pages_struct *uffd_pages; int rc; - list_for_each_entry(uffd_pages, uffd_list, list) { + list_for_each_entry(uffd_pages, &lpi->pages, list) { pr_debug("Checking remaining pages 0x%lx (flags 0x%x)\n", uffd_pages->addr, uffd_pages->flags); if (uffd_pages->flags & UFFD_FLAG_SENT) continue; - rc = uffd_handle_page(uffd, uffd_pages->addr, dest); + rc = uffd_handle_page(lpi, uffd_pages->addr, dest); if (rc < 0) { pr_err("Error during UFFD copy\n"); return -1; @@ -395,12 +409,13 @@ static int handle_remaining_pages(int uffd, struct list_head *uffd_list, void *d } -static int handle_regular_pages(int uffd, struct list_head *uffd_list, void *dest, __u64 address) +static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest, + __u64 address) { int rc; struct uffd_pages_struct *uffd_pages; - rc = uffd_handle_page(uffd, address, dest); + rc = uffd_handle_page(lpi, address, dest); if (rc < 0) { pr_err("Error during UFFD copy\n"); return -1; @@ -410,7 +425,7 @@ static int handle_regular_pages(int uffd, struct list_head *uffd_list, void *des * Mark this page as having been already transferred, so * that it has not to be copied again later. */ - list_for_each_entry(uffd_pages, uffd_list, list) { + list_for_each_entry(uffd_pages, &lpi->pages, list) { if (uffd_pages->addr == address) uffd_pages->flags |= UFFD_FLAG_SENT; } @@ -421,7 +436,7 @@ static int handle_regular_pages(int uffd, struct list_head *uffd_list, void *des /* * Setting up criu infrastructure and scan for VMAs. */ -static int find_vmas(struct list_head *uffd_list) +static int find_vmas(struct lazy_pages_info *lpi) { struct cr_img *img; int ret; @@ -430,14 +445,17 @@ static int find_vmas(struct list_head *uffd_list) struct rst_info *ri; struct page_read pr; struct uffd_pages_struct *uffd_pages; + struct pstree_item *item = pstree_item_by_virt(lpi->pid); + + BUG_ON(!item); vm_area_list_init(&vmas); - ri = rsti(root_item); + ri = rsti(item); if (!ri) return -1; - img = open_image(CR_FD_MM, O_RSTR, pid); + img = open_image(CR_FD_MM, O_RSTR, lpi->pid); if (!img) return -1; @@ -471,7 +489,7 @@ static int find_vmas(struct list_head *uffd_list) pr_info("vma 0x%"PRIx64" 0x%"PRIx64"\n", vma->e->start, vma->e->end); } - ret = open_page_read(pid, &pr, PR_TASK); + ret = open_page_read(lpi->pid, &pr, PR_TASK); if (ret <= 0) { ret = -1; goto out; @@ -483,7 +501,7 @@ static int find_vmas(struct list_head *uffd_list) * pushed into the process using userfaultfd. */ do { - ret = collect_uffd_pages(&pr, uffd_list); + ret = collect_uffd_pages(&pr, lpi); if (ret == -1) { goto out; } @@ -493,7 +511,7 @@ static int find_vmas(struct list_head *uffd_list) pr.close(&pr); /* Count detected pages */ - list_for_each_entry(uffd_pages, uffd_list, list) + list_for_each_entry(uffd_pages, &lpi->pages, list) ret++; pr_debug("Found %d pages to be handled by UFFD\n", ret); @@ -502,7 +520,7 @@ out: return ret; } -static int handle_user_fault(int fd, struct list_head *uffd_list, void *dest) +static int handle_user_fault(struct lazy_pages_info *lpi, void *dest) { struct uffd_msg msg; __u64 flags; @@ -510,7 +528,7 @@ static int handle_user_fault(int fd, struct list_head *uffd_list, void *dest) struct uffd_pages_struct *uffd_pages; int ret; - ret = read(fd, &msg, sizeof(msg)); + ret = read(lpi->uffd, &msg, sizeof(msg)); pr_debug("read() ret: 0x%x\n", ret); if (!ret) return 1; @@ -525,7 +543,7 @@ static int handle_user_fault(int fd, struct list_head *uffd_list, void *dest) pr_debug("msg.arg.pagefault.address 0x%llx\n", address); /* Make sure to not transfer a page twice */ - list_for_each_entry(uffd_pages, uffd_list, list) + list_for_each_entry(uffd_pages, &lpi->pages, list) if ((uffd_pages->addr == address) && (uffd_pages->flags & UFFD_FLAG_SENT)) return 0; @@ -538,7 +556,7 @@ static int handle_user_fault(int fd, struct list_head *uffd_list, void *dest) return -1; } - ret = handle_regular_pages(fd, uffd_list, dest, address); + ret = handle_regular_pages(lpi, dest, address); if (ret < 0) { pr_err("Error during regular page copy\n"); return -1; @@ -547,13 +565,13 @@ static int handle_user_fault(int fd, struct list_head *uffd_list, void *dest) return 0; } -static int lazy_pages_summary(void) +static int lazy_pages_summary(struct lazy_pages_info *lpi) { - pr_debug("With UFFD transferred pages: (%ld/%ld)\n", uffd_copied_pages, total_pages); + pr_debug("With UFFD transferred pages: (%ld/%ld)\n", lpi->copied_pages, lpi->total_pages); - if ((uffd_copied_pages != total_pages) && (total_pages > 0)) { - pr_warn("Only %ld of %ld pages transferred via UFFD\n", uffd_copied_pages, - total_pages); + if ((lpi->copied_pages != lpi->total_pages) && (lpi->total_pages > 0)) { + pr_warn("Only %ld of %ld pages transferred via UFFD\n", lpi->copied_pages, + lpi->total_pages); pr_warn("Something probably went wrong.\n"); return 1; } @@ -561,7 +579,7 @@ static int lazy_pages_summary(void) return 0; } -static int handle_requests(int fd) +static int handle_requests(struct lazy_pages_info *lpi) { fd_set set; int ret = -1; @@ -569,18 +587,9 @@ static int handle_requests(int fd) struct timeval timeout; void *dest; - LIST_HEAD(uffd_list); - - /* - * Find the memory pages belonging to the restored process - * so that it is trackable when all pages have been transferred. - */ - if ((total_pages = find_vmas(&uffd_list)) == -1) - return -1; - /* Initialize FD sets for read() with timeouts (using select()) */ FD_ZERO(&set); - FD_SET(fd, &set); + FD_SET(lpi->uffd, &set); /* All operations will be done on page size */ ps = page_size(); @@ -600,7 +609,7 @@ static int handle_requests(int fd) */ timeout.tv_sec = 5; timeout.tv_usec = 0; - ret = select(fd + 1, &set, NULL, NULL, &timeout); + ret = select(lpi->uffd + 1, &set, NULL, NULL, &timeout); pr_debug("select() rc: 0x%x\n", ret); if (ret == 0) { pr_debug("read timeout\n"); @@ -608,23 +617,23 @@ static int handle_requests(int fd) break; } - ret = handle_user_fault(fd, &uffd_list, dest); + ret = handle_user_fault(lpi, dest); if (ret < 0) goto out; } pr_debug("Handle remaining pages\n"); - ret = handle_remaining_pages(fd, &uffd_list, dest); + ret = handle_remaining_pages(lpi, dest); if (ret < 0) { pr_err("Error during remaining page copy\n"); ret = 1; goto out; } - ret = lazy_pages_summary(); + ret = lazy_pages_summary(lpi); out: free(dest); - close(fd); + close(lpi->uffd); return ret; } @@ -650,14 +659,56 @@ static int lazy_pages_prepare_pstree(void) return 0; } -int cr_lazy_pages() +static int prepare_uffds(struct lazy_pages_info *lpi) { int listen; int uffd; int uffd_flags; - int ret; struct sockaddr_un saddr; + memset(lpi, 0, sizeof(*lpi)); + INIT_LIST_HEAD(&lpi->pages); + + pr_debug("Waiting for incoming connections on %s\n", opts.addr); + if ((listen = server_listen(&saddr)) < 0) { + pr_perror("server_listen error"); + return -1; + } + + uffd = ud_open(listen, &saddr); + if (uffd < 0) { + pr_perror("uffd open error"); + goto close_unix_sock; + } + + pr_debug("uffd is 0x%d\n", uffd); + uffd_flags = fcntl(uffd, F_GETFD, NULL); + pr_debug("uffd_flags are 0x%x\n", uffd_flags); + + lpi->uffd = uffd; + lpi->pid = pid; + + /* + * Find the memory pages belonging to the restored process + * so that it is trackable when all pages have been transferred. + */ + if ((lpi->total_pages = find_vmas(lpi)) == -1) + goto close_uffd; + + close(listen); + return 0; + +close_uffd: + close(uffd); +close_unix_sock: + close(listen); + return -1; +} + +int cr_lazy_pages() +{ + struct lazy_pages_info lpi; + if (!opts.addr) { pr_info("Please specify a file name for the unix domain socket\n"); pr_info("used to communicate between the lazy-pages server\n"); @@ -669,26 +720,10 @@ int cr_lazy_pages() if (lazy_pages_prepare_pstree()) return -1; - pr_debug("Waiting for incoming connections on %s\n", opts.addr); - if ((listen = server_listen(&saddr)) < 0) { - pr_perror("server_listen error"); + if (prepare_uffds(&lpi)) return -1; - } - uffd = ud_open(listen, &saddr); - if (uffd < 0) { - pr_perror("uffd open error"); - return -1; - } - - pr_debug("uffd is 0x%d\n", uffd); - uffd_flags = fcntl(uffd, F_GETFD, NULL); - pr_debug("uffd_flags are 0x%x\n", uffd_flags); - - ret = handle_requests(uffd); - close(listen); - - return ret; + return handle_requests(&lpi); } #else /* CONFIG_HAS_UFFD */ From a20e5305035b4d6d0f52e9de8ab96b667cd04eb5 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 18 Apr 2016 16:34:36 +0300 Subject: [PATCH 0754/4375] lazy-pages: use epoll instead of select Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 78 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index b915dd4b0..9e63d71f7 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "int.h" #include "page.h" @@ -579,18 +580,16 @@ static int lazy_pages_summary(struct lazy_pages_info *lpi) return 0; } -static int handle_requests(struct lazy_pages_info *lpi) +#define POLL_TIMEOUT 5000 + +static int handle_requests(struct lazy_pages_info *lpi, int epollfd, + struct epoll_event *events) { - fd_set set; + int nr_fds = task_entries->nr_tasks; int ret = -1; unsigned long ps; - struct timeval timeout; void *dest; - /* Initialize FD sets for read() with timeouts (using select()) */ - FD_ZERO(&set); - FD_SET(lpi->uffd, &set); - /* All operations will be done on page size */ ps = page_size(); dest = xmalloc(ps); @@ -602,16 +601,13 @@ static int handle_requests(struct lazy_pages_info *lpi) * Setting the timeout to 5 seconds. If after this time * no uffd pages are requested the code switches to * copying the remaining pages. - * - * Timeout is re-defined every time select() is run as - * select(2) says: - * Consider timeout to be undefined after select() returns. */ - timeout.tv_sec = 5; - timeout.tv_usec = 0; - ret = select(lpi->uffd + 1, &set, NULL, NULL, &timeout); - pr_debug("select() rc: 0x%x\n", ret); - if (ret == 0) { + ret = epoll_wait(epollfd, events, nr_fds, POLL_TIMEOUT); + pr_debug("epoll() ret: 0x%x\n", ret); + if (ret < 0) { + pr_perror("polling failed"); + goto out; + } else if (ret == 0) { pr_debug("read timeout\n"); pr_debug("switching from request to copy mode\n"); break; @@ -659,7 +655,42 @@ static int lazy_pages_prepare_pstree(void) return 0; } -static int prepare_uffds(struct lazy_pages_info *lpi) +static int prepare_epoll(int nr_fds, struct epoll_event **events) +{ + int epollfd; + + *events = xmalloc(sizeof(struct epoll_event) * nr_fds); + if (!*events) + return -1; + + epollfd = epoll_create(nr_fds); + if (epollfd == -1) { + pr_perror("epoll_create failed"); + goto free_events; + } + + return epollfd; + +free_events: + free(*events); + return -1; +} + +static int epoll_add_fd(int epollfd, int fd) +{ + struct epoll_event ev; + + ev.events = EPOLLIN; + ev.data.fd = fd; + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) { + pr_perror("epoll_ctl failed"); + return -1; + } + + return 0; +} + +static int prepare_uffds(struct lazy_pages_info *lpi, int epollfd) { int listen; int uffd; @@ -695,6 +726,9 @@ static int prepare_uffds(struct lazy_pages_info *lpi) if ((lpi->total_pages = find_vmas(lpi)) == -1) goto close_uffd; + if (epoll_add_fd(epollfd, uffd)) + goto close_uffd; + close(listen); return 0; @@ -708,6 +742,8 @@ close_unix_sock: int cr_lazy_pages() { struct lazy_pages_info lpi; + struct epoll_event *events; + int epollfd; if (!opts.addr) { pr_info("Please specify a file name for the unix domain socket\n"); @@ -720,10 +756,14 @@ int cr_lazy_pages() if (lazy_pages_prepare_pstree()) return -1; - if (prepare_uffds(&lpi)) + epollfd = prepare_epoll(task_entries->nr_tasks, &events); + if (epollfd < 0) return -1; - return handle_requests(&lpi); + if (prepare_uffds(&lpi, epollfd)) + return -1; + + return handle_requests(&lpi, epollfd, events); } #else /* CONFIG_HAS_UFFD */ From 7f0b075415f8851dc8ac92a3d6124484ef6e08f2 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 18 Apr 2016 16:34:37 +0300 Subject: [PATCH 0755/4375] lazy-pages: move most of lazy_pages_info initialization to ud_open Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 61 ++++++++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 9e63d71f7..dcd2394b1 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -165,14 +165,18 @@ out: return -1; } -static int pid; +static int find_vmas(struct lazy_pages_info *lpi); -static int ud_open(int listen, struct sockaddr_un *saddr) +static int ud_open(struct lazy_pages_info *lpi, int listen, + struct sockaddr_un *saddr) { int client; - int newfd; int ret = -1; socklen_t len; + int uffd_flags; + + memset(lpi, 0, sizeof(*lpi)); + INIT_LIST_HEAD(&lpi->pages); /* accept new client request */ len = sizeof(struct sockaddr_un); @@ -186,23 +190,34 @@ static int ud_open(int listen, struct sockaddr_un *saddr) /* The "transfer protocol" is first the pid as int and then * the FD for UFFD */ - ret = recv(client, &pid, sizeof(pid), 0); - if (ret != sizeof(pid)) { + ret = recv(client, &lpi->pid, sizeof(lpi->pid), 0); + if (ret != sizeof(lpi->pid)) { pr_perror("PID recv error:"); ret = -1; goto out; } - pr_debug("received PID: %d\n", pid); + pr_debug("received PID: %d\n", lpi->pid); - newfd = recv_fd(client); - if (newfd < 0) { + lpi->uffd = recv_fd(client); + if (lpi->uffd < 0) { pr_perror("recv_fd error:"); + ret = -1; goto out; } - pr_debug("newfd %d\n", newfd); + pr_debug("lpi->uffd %d\n", lpi->uffd); close(client); - return newfd; + pr_debug("uffd is 0x%d\n", lpi->uffd); + uffd_flags = fcntl(lpi->uffd, F_GETFD, NULL); + pr_debug("uffd_flags are 0x%x\n", uffd_flags); + + /* + * Find the memory pages belonging to the restored process + * so that it is trackable when all pages have been transferred. + */ + if ((lpi->total_pages = find_vmas(lpi)) == -1) + return -1; + out: close(client); return ret; @@ -693,47 +708,27 @@ static int epoll_add_fd(int epollfd, int fd) static int prepare_uffds(struct lazy_pages_info *lpi, int epollfd) { int listen; - int uffd; - int uffd_flags; struct sockaddr_un saddr; - memset(lpi, 0, sizeof(*lpi)); - INIT_LIST_HEAD(&lpi->pages); - pr_debug("Waiting for incoming connections on %s\n", opts.addr); if ((listen = server_listen(&saddr)) < 0) { pr_perror("server_listen error"); return -1; } - uffd = ud_open(listen, &saddr); - if (uffd < 0) { + if (ud_open(lpi, listen, &saddr) < 0) { pr_perror("uffd open error"); goto close_unix_sock; } - pr_debug("uffd is 0x%d\n", uffd); - uffd_flags = fcntl(uffd, F_GETFD, NULL); - pr_debug("uffd_flags are 0x%x\n", uffd_flags); - - lpi->uffd = uffd; - lpi->pid = pid; - - /* - * Find the memory pages belonging to the restored process - * so that it is trackable when all pages have been transferred. - */ - if ((lpi->total_pages = find_vmas(lpi)) == -1) - goto close_uffd; - - if (epoll_add_fd(epollfd, uffd)) + if (epoll_add_fd(epollfd, lpi->uffd)) goto close_uffd; close(listen); return 0; close_uffd: - close(uffd); + close(lpi->uffd); close_unix_sock: close(listen); return -1; From cefb69c9f24376cf3a455b86061af8d46d63e0cd Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 18 Apr 2016 16:34:38 +0300 Subject: [PATCH 0756/4375] lazy-pages: allow handling multiple processes Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 155 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 114 insertions(+), 41 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index dcd2394b1..4d40f12fc 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -45,8 +45,67 @@ struct lazy_pages_info { unsigned long total_pages; unsigned long copied_pages; + + struct hlist_node hash; }; +#define LPI_HASH_SIZE 16 +static struct hlist_head lpi_hash[LPI_HASH_SIZE]; + +static struct lazy_pages_info *lpi_init(void) +{ + struct lazy_pages_info *lpi = NULL; + + lpi = xmalloc(sizeof(*lpi)); + if (!lpi) + return NULL; + + memset(lpi, 0, sizeof(*lpi)); + INIT_LIST_HEAD(&lpi->pages); + INIT_HLIST_NODE(&lpi->hash); + + return lpi; +} + +static void lpi_fini(struct lazy_pages_info *lpi) +{ + if (lpi->uffd > 0) + close(lpi->uffd); + free(lpi); +} + +static void lpi_hash_init(void) +{ + int i; + + for (i = 0; i < LPI_HASH_SIZE; i++) + INIT_HLIST_HEAD(&lpi_hash[i]); +} + +struct lazy_pages_info *uffd_to_lpi(int uffd) +{ + struct lazy_pages_info *lpi; + struct hlist_head *head; + + head = &lpi_hash[uffd % LPI_HASH_SIZE]; + hlist_for_each_entry(lpi, head, hash) + if (lpi->uffd == uffd) + return lpi; + + return NULL; +} + +static void lpi_hash_fini(void) +{ + struct lazy_pages_info *p; + struct hlist_node *n; + int i; + + for (i = 0; i < LPI_HASH_SIZE; i++) + hlist_for_each_entry_safe(p, n, &lpi_hash[i], hash) + lpi_fini(p); +} + static int send_uffd(int sendfd, int pid) { int fd; @@ -167,33 +226,33 @@ out: static int find_vmas(struct lazy_pages_info *lpi); -static int ud_open(struct lazy_pages_info *lpi, int listen, - struct sockaddr_un *saddr) +static struct lazy_pages_info *ud_open(int listen, struct sockaddr_un *saddr) { + struct lazy_pages_info *lpi; int client; int ret = -1; socklen_t len; int uffd_flags; - memset(lpi, 0, sizeof(*lpi)); - INIT_LIST_HEAD(&lpi->pages); - /* accept new client request */ len = sizeof(struct sockaddr_un); if ((client = accept(listen, (struct sockaddr *)saddr, &len)) < 0) { pr_perror("server_accept error: %d", client); close(listen); - return -1; + return NULL; } pr_debug("client fd %d\n", client); + lpi = lpi_init(); + if (!lpi) + goto out; + /* The "transfer protocol" is first the pid as int and then * the FD for UFFD */ ret = recv(client, &lpi->pid, sizeof(lpi->pid), 0); if (ret != sizeof(lpi->pid)) { pr_perror("PID recv error:"); - ret = -1; goto out; } pr_debug("received PID: %d\n", lpi->pid); @@ -201,7 +260,6 @@ static int ud_open(struct lazy_pages_info *lpi, int listen, lpi->uffd = recv_fd(client); if (lpi->uffd < 0) { pr_perror("recv_fd error:"); - ret = -1; goto out; } pr_debug("lpi->uffd %d\n", lpi->uffd); @@ -216,11 +274,16 @@ static int ud_open(struct lazy_pages_info *lpi, int listen, * so that it is trackable when all pages have been transferred. */ if ((lpi->total_pages = find_vmas(lpi)) == -1) - return -1; + goto out; + + hlist_add_head(&lpi->hash, &lpi_hash[lpi->uffd % LPI_HASH_SIZE]); + + return lpi; out: + lpi_fini(lpi); close(client); - return ret; + return NULL; } static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest) @@ -583,7 +646,8 @@ static int handle_user_fault(struct lazy_pages_info *lpi, void *dest) static int lazy_pages_summary(struct lazy_pages_info *lpi) { - pr_debug("With UFFD transferred pages: (%ld/%ld)\n", lpi->copied_pages, lpi->total_pages); + pr_debug("Process %d: with UFFD transferred pages: (%ld/%ld)\n", + lpi->pid, lpi->copied_pages, lpi->total_pages); if ((lpi->copied_pages != lpi->total_pages) && (lpi->total_pages > 0)) { pr_warn("Only %ld of %ld pages transferred via UFFD\n", lpi->copied_pages, @@ -597,13 +661,14 @@ static int lazy_pages_summary(struct lazy_pages_info *lpi) #define POLL_TIMEOUT 5000 -static int handle_requests(struct lazy_pages_info *lpi, int epollfd, - struct epoll_event *events) +static int handle_requests(int epollfd, struct epoll_event *events) { int nr_fds = task_entries->nr_tasks; + struct lazy_pages_info *lpi; int ret = -1; unsigned long ps; void *dest; + int i; /* All operations will be done on page size */ ps = page_size(); @@ -628,23 +693,31 @@ static int handle_requests(struct lazy_pages_info *lpi, int epollfd, break; } - ret = handle_user_fault(lpi, dest); - if (ret < 0) - goto out; + for (i = 0; i < ret; i++) { + lpi = uffd_to_lpi(events[i].data.fd); + ret = handle_user_fault(lpi, dest); + if (ret < 0) + goto out; + } } pr_debug("Handle remaining pages\n"); - ret = handle_remaining_pages(lpi, dest); - if (ret < 0) { - pr_err("Error during remaining page copy\n"); - ret = 1; - goto out; + for (i = 0; i < LPI_HASH_SIZE; i++) { + hlist_for_each_entry(lpi, &lpi_hash[i], hash) { + ret = handle_remaining_pages(lpi, dest); + if (ret < 0) { + pr_err("Error during remaining page copy\n"); + ret = 1; + goto out; + } + } } - ret = lazy_pages_summary(lpi); + for (i = 0; i < LPI_HASH_SIZE; i++) + hlist_for_each_entry(lpi, &lpi_hash[i], hash) + ret += lazy_pages_summary(lpi); out: free(dest); - close(lpi->uffd); return ret; } @@ -661,12 +734,6 @@ static int lazy_pages_prepare_pstree(void) if (prepare_pstree() == -1) return -1; - /* bail out early until we know how to handle multiple tasks */ - if (task_entries->nr_tasks > 1) { - pr_msg("lazy-pages cannot restore more than one task, sorry\n"); - return -1; - } - return 0; } @@ -705,8 +772,9 @@ static int epoll_add_fd(int epollfd, int fd) return 0; } -static int prepare_uffds(struct lazy_pages_info *lpi, int epollfd) +static int prepare_uffds(int epollfd) { + int i; int listen; struct sockaddr_un saddr; @@ -716,29 +784,29 @@ static int prepare_uffds(struct lazy_pages_info *lpi, int epollfd) return -1; } - if (ud_open(lpi, listen, &saddr) < 0) { - pr_perror("uffd open error"); - goto close_unix_sock; + for (i = 0; i < task_entries->nr_tasks; i++) { + struct lazy_pages_info *lpi; + lpi = ud_open(listen, &saddr); + if (!lpi) + goto close_uffd; + if (epoll_add_fd(epollfd, lpi->uffd)) + goto close_uffd; } - if (epoll_add_fd(epollfd, lpi->uffd)) - goto close_uffd; - close(listen); return 0; close_uffd: - close(lpi->uffd); -close_unix_sock: + lpi_hash_fini(); close(listen); return -1; } int cr_lazy_pages() { - struct lazy_pages_info lpi; struct epoll_event *events; int epollfd; + int ret; if (!opts.addr) { pr_info("Please specify a file name for the unix domain socket\n"); @@ -748,6 +816,8 @@ int cr_lazy_pages() return -1; } + lpi_hash_init(); + if (lazy_pages_prepare_pstree()) return -1; @@ -755,10 +825,13 @@ int cr_lazy_pages() if (epollfd < 0) return -1; - if (prepare_uffds(&lpi, epollfd)) + if (prepare_uffds(epollfd)) return -1; - return handle_requests(&lpi, epollfd, events); + ret = handle_requests(epollfd, events); + lpi_hash_fini(); + + return ret; } #else /* CONFIG_HAS_UFFD */ From f68e5a6b3dd669cafab3cd3e5c556363d6ac357b Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Wed, 27 Apr 2016 22:45:00 +0300 Subject: [PATCH 0757/4375] criu: always enable the userfaultfd support Add linux/userfaultfd.h to criu sources. This header is a part of the kernel API and I see nothing wrong to have in the repo. Why we want to do this: * to check that criu works correctly if a kernel doesn't support userfaultfd. * to check compilation of the userfaultfd part in travis-ci. v2: remove UFFD from FEATURES_LIST Acked-by: Mike Rapoport Acked-by: Adrian Reber Cc: Mike Rapoport Cc: Adrian Reber Signed-off-by: Andrew Vagin Signed-off-by: Pavel Emelyanov --- Makefile.config | 2 +- .../arch/arm/plugins/std/syscalls/syscall.def | 1 + .../plugins/std/syscalls/syscall-ppc64.tbl | 1 + criu/include/linux/userfaultfd.h | 167 ++++++++++++++++++ criu/include/uffd.h | 17 +- criu/pie/restorer.c | 11 +- criu/uffd.c | 42 ++--- scripts/feature-tests.mak | 15 -- 8 files changed, 194 insertions(+), 62 deletions(-) create mode 100644 criu/include/linux/userfaultfd.h diff --git a/Makefile.config b/Makefile.config index 7851f826f..0e557805c 100644 --- a/Makefile.config +++ b/Makefile.config @@ -36,7 +36,7 @@ export DEFINES += $(FEATURE_DEFINES) export CFLAGS += $(FEATURE_DEFINES) FEATURES_LIST := TCP_REPAIR STRLCPY STRLCAT PTRACE_PEEKSIGINFO \ - SETPROCTITLE_INIT MEMFD TCP_REPAIR_WINDOW UFFD + SETPROCTITLE_INIT MEMFD TCP_REPAIR_WINDOW # $1 - config name define gen-feature-test diff --git a/compel/arch/arm/plugins/std/syscalls/syscall.def b/compel/arch/arm/plugins/std/syscalls/syscall.def index 91213e0e7..ba541ec14 100644 --- a/compel/arch/arm/plugins/std/syscalls/syscall.def +++ b/compel/arch/arm/plugins/std/syscalls/syscall.def @@ -108,3 +108,4 @@ io_getevents 4 245 (aio_context_t ctx, long min_nr, long nr, struct io_event * seccomp 277 383 (unsigned int op, unsigned int flags, const char *uargs) gettimeofday 169 78 (struct timeval *tv, struct timezone *tz) preadv 69 361 (int fd, struct iovec *iov, unsigned long nr, loff_t off) +userfaultfd 282 388 (int flags) diff --git a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl index 9cb2fb6ea..68411745a 100644 --- a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl +++ b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl @@ -105,3 +105,4 @@ __NR_io_submit 230 sys_io_submit (aio_context_t ctx_id, long nr, struct iocb __NR_ipc 117 sys_ipc (unsigned int call, int first, unsigned long second, unsigned long third, const void *ptr, long fifth) __NR_gettimeofday 78 sys_gettimeofday (struct timeval *tv, struct timezone *tz) __NR_preadv 320 sys_preadv (int fd, struct iovec *iov, unsigned long nr, loff_t off) +__NR_userfaultfd 364 sys_userfaultfd (int flags) diff --git a/criu/include/linux/userfaultfd.h b/criu/include/linux/userfaultfd.h new file mode 100644 index 000000000..9057d7af3 --- /dev/null +++ b/criu/include/linux/userfaultfd.h @@ -0,0 +1,167 @@ +/* + * include/linux/userfaultfd.h + * + * Copyright (C) 2007 Davide Libenzi + * Copyright (C) 2015 Red Hat, Inc. + * + */ + +#ifndef _LINUX_USERFAULTFD_H +#define _LINUX_USERFAULTFD_H + +#include + +#define UFFD_API ((__u64)0xAA) +/* + * After implementing the respective features it will become: + * #define UFFD_API_FEATURES (UFFD_FEATURE_PAGEFAULT_FLAG_WP | \ + * UFFD_FEATURE_EVENT_FORK) + */ +#define UFFD_API_FEATURES (0) +#define UFFD_API_IOCTLS \ + ((__u64)1 << _UFFDIO_REGISTER | \ + (__u64)1 << _UFFDIO_UNREGISTER | \ + (__u64)1 << _UFFDIO_API) +#define UFFD_API_RANGE_IOCTLS \ + ((__u64)1 << _UFFDIO_WAKE | \ + (__u64)1 << _UFFDIO_COPY | \ + (__u64)1 << _UFFDIO_ZEROPAGE) + +/* + * Valid ioctl command number range with this API is from 0x00 to + * 0x3F. UFFDIO_API is the fixed number, everything else can be + * changed by implementing a different UFFD_API. If sticking to the + * same UFFD_API more ioctl can be added and userland will be aware of + * which ioctl the running kernel implements through the ioctl command + * bitmask written by the UFFDIO_API. + */ +#define _UFFDIO_REGISTER (0x00) +#define _UFFDIO_UNREGISTER (0x01) +#define _UFFDIO_WAKE (0x02) +#define _UFFDIO_COPY (0x03) +#define _UFFDIO_ZEROPAGE (0x04) +#define _UFFDIO_API (0x3F) + +/* userfaultfd ioctl ids */ +#define UFFDIO 0xAA +#define UFFDIO_API _IOWR(UFFDIO, _UFFDIO_API, \ + struct uffdio_api) +#define UFFDIO_REGISTER _IOWR(UFFDIO, _UFFDIO_REGISTER, \ + struct uffdio_register) +#define UFFDIO_UNREGISTER _IOR(UFFDIO, _UFFDIO_UNREGISTER, \ + struct uffdio_range) +#define UFFDIO_WAKE _IOR(UFFDIO, _UFFDIO_WAKE, \ + struct uffdio_range) +#define UFFDIO_COPY _IOWR(UFFDIO, _UFFDIO_COPY, \ + struct uffdio_copy) +#define UFFDIO_ZEROPAGE _IOWR(UFFDIO, _UFFDIO_ZEROPAGE, \ + struct uffdio_zeropage) + +/* read() structure */ +struct uffd_msg { + __u8 event; + + __u8 reserved1; + __u16 reserved2; + __u32 reserved3; + + union { + struct { + __u64 flags; + __u64 address; + } pagefault; + + struct { + /* unused reserved fields */ + __u64 reserved1; + __u64 reserved2; + __u64 reserved3; + } reserved; + } arg; +} __packed; + +/* + * Start at 0x12 and not at 0 to be more strict against bugs. + */ +#define UFFD_EVENT_PAGEFAULT 0x12 +#if 0 /* not available yet */ +#define UFFD_EVENT_FORK 0x13 +#endif + +/* flags for UFFD_EVENT_PAGEFAULT */ +#define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */ +#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */ + +struct uffdio_api { + /* userland asks for an API number and the features to enable */ + __u64 api; + /* + * Kernel answers below with the all available features for + * the API, this notifies userland of which events and/or + * which flags for each event are enabled in the current + * kernel. + * + * Note: UFFD_EVENT_PAGEFAULT and UFFD_PAGEFAULT_FLAG_WRITE + * are to be considered implicitly always enabled in all kernels as + * long as the uffdio_api.api requested matches UFFD_API. + */ +#if 0 /* not available yet */ +#define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0) +#define UFFD_FEATURE_EVENT_FORK (1<<1) +#endif + __u64 features; + + __u64 ioctls; +}; + +struct uffdio_range { + __u64 start; + __u64 len; +}; + +struct uffdio_register { + struct uffdio_range range; +#define UFFDIO_REGISTER_MODE_MISSING ((__u64)1<<0) +#define UFFDIO_REGISTER_MODE_WP ((__u64)1<<1) + __u64 mode; + + /* + * kernel answers which ioctl commands are available for the + * range, keep at the end as the last 8 bytes aren't read. + */ + __u64 ioctls; +}; + +struct uffdio_copy { + __u64 dst; + __u64 src; + __u64 len; + /* + * There will be a wrprotection flag later that allows to map + * pages wrprotected on the fly. And such a flag will be + * available if the wrprotection ioctl are implemented for the + * range according to the uffdio_register.ioctls. + */ +#define UFFDIO_COPY_MODE_DONTWAKE ((__u64)1<<0) + __u64 mode; + + /* + * "copy" is written by the ioctl and must be at the end: the + * copy_from_user will not read the last 8 bytes. + */ + __s64 copy; +}; + +struct uffdio_zeropage { + struct uffdio_range range; +#define UFFDIO_ZEROPAGE_MODE_DONTWAKE ((__u64)1<<0) + __u64 mode; + + /* + * "zeropage" is written by the ioctl and must be at the end: + * the copy_from_user will not read the last 8 bytes. + */ + __s64 zeropage; +}; + +#endif /* _LINUX_USERFAULTFD_H */ diff --git a/criu/include/uffd.h b/criu/include/uffd.h index 6c931e2b9..4e1ba4ab8 100644 --- a/criu/include/uffd.h +++ b/criu/include/uffd.h @@ -1,22 +1,7 @@ #ifndef __CR_UFFD_H_ #define __CR_UFFD_H_ -#include "config.h" -#include "restorer.h" - -#ifdef CONFIG_HAS_UFFD - -#include -#include - -#ifndef __NR_userfaultfd -#error "missing __NR_userfaultfd definition" -#endif - +struct task_restore_args; extern int setup_uffd(struct task_restore_args *task_args, int pid); -#else -static inline int setup_uffd(struct task_restore_args *task_args, int pid) { return 0; } - -#endif /* CONFIG_HAS_UFFD */ #endif /* __CR_UFFD_H_ */ diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index b4ec6cdfe..d478aa5bd 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -17,6 +17,8 @@ #include #include +#include "linux/userfaultfd.h" + #include "int.h" #include "types.h" #include "common/compiler.h" @@ -789,16 +791,16 @@ static void rst_tcp_socks_all(struct task_restore_args *ta) static int enable_uffd(int uffd, unsigned long addr, unsigned long len) { + int rc; + struct uffdio_register uffdio_register; + unsigned long expected_ioctls; + /* * If uffd == -1, this means that userfaultfd is not enabled * or it is not available. */ if (uffd == -1) return 0; -#ifdef CONFIG_HAS_UFFD - int rc; - struct uffdio_register uffdio_register; - unsigned long expected_ioctls; uffdio_register.range.start = addr; uffdio_register.range.len = len; @@ -818,7 +820,6 @@ static int enable_uffd(int uffd, unsigned long addr, unsigned long len) pr_err("lazy-pages: unexpected missing uffd ioctl for anon memory\n"); } -#endif return 0; } diff --git a/criu/uffd.c b/criu/uffd.c index 4d40f12fc..9a19a8aba 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -16,23 +16,25 @@ #include #include +#include "linux/userfaultfd.h" + #include "int.h" #include "page.h" -#include "include/log.h" -#include "include/criu-plugin.h" -#include "include/pagemap.h" -#include "include/files-reg.h" -#include "include/kerndat.h" -#include "include/mem.h" -#include "include/uffd.h" -#include "include/util-pie.h" -#include "include/protobuf.h" -#include "include/pstree.h" -#include "include/crtools.h" -#include "include/cr_options.h" +#include "log.h" +#include "criu-plugin.h" +#include "pagemap.h" +#include "files-reg.h" +#include "kerndat.h" +#include "mem.h" +#include "uffd.h" +#include "util-pie.h" +#include "protobuf.h" +#include "pstree.h" +#include "crtools.h" +#include "cr_options.h" #include "xmalloc.h" - -#ifdef CONFIG_HAS_UFFD +#include +#include "restorer.h" #undef LOG_PREFIX #define LOG_PREFIX "lazy-pages: " @@ -166,7 +168,7 @@ int setup_uffd(struct task_restore_args *task_args, int pid) * Open userfaulfd FD which is passed to the restorer blob and * to a second process handling the userfaultfd page faults. */ - task_args->uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); + task_args->uffd = syscall(SYS_userfaultfd, O_CLOEXEC | O_NONBLOCK); /* * Check if the UFFD_API is the one which is expected @@ -833,13 +835,3 @@ int cr_lazy_pages() return ret; } - -#else /* CONFIG_HAS_UFFD */ - -int cr_lazy_pages() -{ - pr_msg("userfaultfd system call is not supported, cannot start lazy-pages daemon\n"); - return -1; -} - -#endif /* CONFIG_HAS_UFFD */ diff --git a/scripts/feature-tests.mak b/scripts/feature-tests.mak index 77f671a90..12bf54181 100644 --- a/scripts/feature-tests.mak +++ b/scripts/feature-tests.mak @@ -123,18 +123,3 @@ ENTRY(main) nop END(main) endef - -define FEATURE_TEST_UFFD - -#include -#include - -int main(void) -{ -#ifndef __NR_userfaultfd -#error "missing __NR_userfaultfd definition" -#endif - return 0; -} - -endef From c443faca3fa8c06b94b3b67be5b6a12d71ef0b3e Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 4 May 2016 11:22:00 +0300 Subject: [PATCH 0758/4375] criu: uffd runtime detection Now that userfaultfd/lazy-pages support is enable all the time, this adds runtime detection of userfaultfd. On a system without the userfaultfd syscall following is printed: uffd daemon: (00.000004) Error (uffd.c:176): lazy-pages: Runtime detection of userfaultfd failed on this system. (00.000024) Error (uffd.c:177): lazy-pages: Processes cannot be lazy-restored on this system. or criu restore (00.457047) 6858: Error (uffd.c:176): lazy-pages: Runtime detection of userfaultfd failed on this system. (00.457049) 6858: Error (uffd.c:177): lazy-pages: Processes cannot be lazy-restored on this system. Signed-off-by: Adrian Reber Acked-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/criu/uffd.c b/criu/uffd.c index 9a19a8aba..c3f62424a 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -160,10 +160,33 @@ out: return ret; } +/* Runtime detection if userfaultfd can be used */ + +static int check_for_uffd() +{ + int uffd; + + uffd = syscall(SYS_userfaultfd, 0); + /* + * uffd == -1 is probably enough to not use lazy-restore + * on this system. Additionally checking for ENOSYS + * makes sure it is actually not implemented. + */ + if ((uffd == -1) && (errno == ENOSYS)) { + pr_err("Runtime detection of userfaultfd failed on this system.\n"); + pr_err("Processes cannot be lazy-restored on this system.\n"); + return -1; + } + close(uffd); + return 0; +} + /* This function is used by 'criu restore --lazy-pages' */ int setup_uffd(struct task_restore_args *task_args, int pid) { struct uffdio_api uffdio_api; + if (check_for_uffd()) + return -1; /* * Open userfaulfd FD which is passed to the restorer blob and * to a second process handling the userfaultfd page faults. @@ -810,6 +833,9 @@ int cr_lazy_pages() int epollfd; int ret; + if (check_for_uffd()) + return -1; + if (!opts.addr) { pr_info("Please specify a file name for the unix domain socket\n"); pr_info("used to communicate between the lazy-pages server\n"); From d1f657ef83dc9382b0125d7c5eb1b338f05a90b2 Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Sat, 14 May 2016 00:42:00 +0300 Subject: [PATCH 0759/4375] uffd: don't close the same descriptor twice >>> >>> CID 161322: API usage errors (USE_AFTER_FREE) >>> >>> Calling "close(int)" closes handle "client" which has already been closed. Signed-off-by: Andrew Vagin Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index c3f62424a..e1680dcb4 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -288,7 +288,7 @@ static struct lazy_pages_info *ud_open(int listen, struct sockaddr_un *saddr) goto out; } pr_debug("lpi->uffd %d\n", lpi->uffd); - close(client); + close_safe(&client); pr_debug("uffd is 0x%d\n", lpi->uffd); uffd_flags = fcntl(lpi->uffd, F_GETFD, NULL); @@ -307,7 +307,7 @@ static struct lazy_pages_info *ud_open(int listen, struct sockaddr_un *saddr) out: lpi_fini(lpi); - close(client); + close_safe(&client); return NULL; } From a263aec6434809b3b612484cdf7eb8db0ea803dc Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Sat, 14 May 2016 00:43:00 +0300 Subject: [PATCH 0760/4375] uffd: handle errors from userfaultfd() >>> >>> CID 161312: Error handling issues (NEGATIVE_RETURNS) >>> >>> "task_args->uffd" is passed to a parameter that cannot be negative. Signed-off-by: Andrew Vagin Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index e1680dcb4..2b8a0be3b 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -192,6 +192,10 @@ int setup_uffd(struct task_restore_args *task_args, int pid) * to a second process handling the userfaultfd page faults. */ task_args->uffd = syscall(SYS_userfaultfd, O_CLOEXEC | O_NONBLOCK); + if (task_args->uffd < 0) { + pr_perror("Unable to open an userfaultfd descriptor"); + return -1; + } /* * Check if the UFFD_API is the one which is expected @@ -200,19 +204,20 @@ int setup_uffd(struct task_restore_args *task_args, int pid) uffdio_api.features = 0; if (ioctl(task_args->uffd, UFFDIO_API, &uffdio_api)) { pr_err("Checking for UFFDIO_API failed.\n"); - return -1; + goto err; } if (uffdio_api.api != UFFD_API) { pr_err("Result of looking up UFFDIO_API does not match: %Lu\n", uffdio_api.api); - return -1; + goto err; } - if (send_uffd(task_args->uffd, pid) < 0) { - close(task_args->uffd); - return -1; - } + if (send_uffd(task_args->uffd, pid) < 0) + goto err; return 0; +err: + close(task_args->uffd); + return -1; } static int server_listen(struct sockaddr_un *saddr) From 3df6627ef8906cf2f92e3f64ee21ab89eb11016d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 24 May 2016 14:37:18 +0300 Subject: [PATCH 0761/4375] restore: Move uffd setup out of sigreturn_restore Signed-off-by: Pavel Emelyanov Reviewed-by: Cyrill Gorcunov --- criu/cr-restore.c | 9 +++------ criu/include/uffd.h | 2 +- criu/uffd.c | 8 +++++++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index fd03eb1e3..3a48532f1 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -848,6 +848,9 @@ static int restore_one_alive_task(int pid, CoreEntry *core) if (prepare_vmas(current, ta)) return -1; + if (setup_uffd(pid, ta)) + return -1; + return sigreturn_restore(pid, ta, args_len, core); } @@ -3205,12 +3208,6 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns strncpy(task_args->comm, core->tc->comm, sizeof(task_args->comm)); - if (!opts.lazy_pages) - task_args->uffd = -1; - else - if (setup_uffd(task_args, pid) != 0) - goto err; - /* * Fill up per-thread data. */ diff --git a/criu/include/uffd.h b/criu/include/uffd.h index 4e1ba4ab8..66ce4594b 100644 --- a/criu/include/uffd.h +++ b/criu/include/uffd.h @@ -2,6 +2,6 @@ #define __CR_UFFD_H_ struct task_restore_args; -extern int setup_uffd(struct task_restore_args *task_args, int pid); +extern int setup_uffd(int pid, struct task_restore_args *task_args); #endif /* __CR_UFFD_H_ */ diff --git a/criu/uffd.c b/criu/uffd.c index 2b8a0be3b..60d737b92 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -182,9 +182,15 @@ static int check_for_uffd() } /* This function is used by 'criu restore --lazy-pages' */ -int setup_uffd(struct task_restore_args *task_args, int pid) +int setup_uffd(int pid, struct task_restore_args *task_args) { struct uffdio_api uffdio_api; + + if (!opts.lazy_pages) { + task_args->uffd = -1; + return 0; + } + if (check_for_uffd()) return -1; /* From e3fec3af05f2c6e8a6a5d244d9e746c67b99fd5e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Jun 2016 09:27:35 +0300 Subject: [PATCH 0762/4375] criu: page_pipe_buf: add PPB_LAZY flag for buffers that contain potentially lazy pages Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/page-pipe.h | 5 ++++- criu/mem.c | 6 +++++- criu/page-pipe.c | 35 +++++++++++++++++++++-------------- criu/shmem.c | 2 +- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h index b8fdfdeb7..95e31bc85 100644 --- a/criu/include/page-pipe.h +++ b/criu/include/page-pipe.h @@ -95,6 +95,8 @@ struct page_pipe_buf { unsigned int pipe_size; /* how many pages can be fit into pipe */ unsigned int pages_in; /* how many pages are there */ unsigned int nr_segs; /* how many iov-s are busy */ +#define PPB_LAZY (1 << 0) + unsigned int flags; struct iovec *iov; /* vaddr:len map */ struct list_head l; /* links into page_pipe->bufs */ }; @@ -120,7 +122,8 @@ struct page_pipe { struct page_pipe *create_page_pipe(unsigned int nr_segs, struct iovec *iovs, unsigned flags); extern void destroy_page_pipe(struct page_pipe *p); -extern int page_pipe_add_page(struct page_pipe *p, unsigned long addr); +extern int page_pipe_add_page(struct page_pipe *p, unsigned long addr, + unsigned int flags); extern int page_pipe_add_hole(struct page_pipe *p, unsigned long addr); extern void debug_show_page_pipe(struct page_pipe *pp); diff --git a/criu/mem.c b/criu/mem.c index 9bd5a6aa4..19f753f25 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -146,6 +146,7 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u for (pfn = 0; pfn < nr_to_scan; pfn++) { unsigned long vaddr; + unsigned int ppb_flags = 0; int ret; if (!should_dump_page(vma->e, at[pfn])) @@ -153,6 +154,9 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u vaddr = vma->e->start + *off + pfn * PAGE_SIZE; + if (vma_entry_can_be_lazy(vma->e)) + ppb_flags |= PPB_LAZY; + /* * If we're doing incremental dump (parent images * specified) and page is not soft-dirty -- we dump @@ -164,7 +168,7 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u ret = page_pipe_add_hole(pp, vaddr); pages[0]++; } else { - ret = page_pipe_add_page(pp, vaddr); + ret = page_pipe_add_page(pp, vaddr, ppb_flags); pages[1]++; } diff --git a/criu/page-pipe.c b/criu/page-pipe.c index c80f73236..d0fdf03a1 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -57,10 +57,12 @@ static void ppb_destroy(struct page_pipe_buf *ppb) } static void ppb_init(struct page_pipe_buf *ppb, unsigned int pages_in, - unsigned int nr_segs, struct iovec *iov) + unsigned int nr_segs, unsigned int flags, + struct iovec *iov) { ppb->pages_in = pages_in; ppb->nr_segs = nr_segs; + ppb->flags = flags; ppb->iov = iov; } @@ -81,7 +83,7 @@ static int ppb_resize_pipe(struct page_pipe_buf *ppb, unsigned long new_size) return 0; } -static int page_pipe_grow(struct page_pipe *pp) +static int page_pipe_grow(struct page_pipe *pp, unsigned int flags) { struct page_pipe_buf *ppb; struct iovec *free_iov; @@ -103,7 +105,7 @@ static int page_pipe_grow(struct page_pipe *pp) out: free_iov = &pp->iovs[pp->free_iov]; - ppb_init(ppb, 0, 0, free_iov); + ppb_init(ppb, 0, 0, flags, free_iov); return 0; } @@ -139,7 +141,7 @@ struct page_pipe *create_page_pipe(unsigned int nr_segs, struct iovec *iovs, uns pp->free_hole = 0; pp->holes = NULL; - if (page_pipe_grow(pp)) + if (page_pipe_grow(pp, 0)) goto err_free_iovs; return pp; @@ -180,13 +182,16 @@ void page_pipe_reinit(struct page_pipe *pp) pp->free_hole = 0; - if (page_pipe_grow(pp)) + if (page_pipe_grow(pp, 0)) BUG(); /* It can't fail, because ppb is in free_bufs */ } static inline int try_add_page_to(struct page_pipe *pp, struct page_pipe_buf *ppb, - unsigned long addr) + unsigned long addr, unsigned int flags) { + if (ppb->flags != flags) + return 1; + if (ppb->pages_in == ppb->pipe_size) { unsigned long new_size = ppb->pipe_size << 1; int ret; @@ -218,25 +223,27 @@ out: return 0; } -static inline int try_add_page(struct page_pipe *pp, unsigned long addr) +static inline int try_add_page(struct page_pipe *pp, unsigned long addr, + unsigned int flags) { BUG_ON(list_empty(&pp->bufs)); - return try_add_page_to(pp, list_entry(pp->bufs.prev, struct page_pipe_buf, l), addr); + return try_add_page_to(pp, list_entry(pp->bufs.prev, struct page_pipe_buf, l), addr, flags); } -int page_pipe_add_page(struct page_pipe *pp, unsigned long addr) +int page_pipe_add_page(struct page_pipe *pp, unsigned long addr, + unsigned int flags) { int ret; - ret = try_add_page(pp, addr); + ret = try_add_page(pp, addr, flags); if (ret <= 0) return ret; - ret = page_pipe_grow(pp); + ret = page_pipe_grow(pp, flags); if (ret < 0) return ret; - ret = try_add_page(pp, addr); + ret = try_add_page(pp, addr, flags); BUG_ON(ret > 0); return ret; } @@ -277,8 +284,8 @@ void debug_show_page_pipe(struct page_pipe *pp) pr_debug("* %u pipes %u/%u iovs:\n", pp->nr_pipes, pp->free_iov, pp->nr_iovs); list_for_each_entry(ppb, &pp->bufs, l) { - pr_debug("\tbuf %u pages, %u iovs:\n", - ppb->pages_in, ppb->nr_segs); + pr_debug("\tbuf %u pages, %u iovs, flags: %x :\n", + ppb->pages_in, ppb->nr_segs, ppb->flags); for (i = 0; i < ppb->nr_segs; i++) { iov = &ppb->iov[i]; pr_debug("\t\t%p %lu\n", iov->iov_base, diff --git a/criu/shmem.c b/criu/shmem.c index af3b4c8f5..270507a92 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -713,7 +713,7 @@ again: else if (xfer.parent && page_in_parent(pgstate == PST_DIRTY)) ret = page_pipe_add_hole(pp, pgaddr); else - ret = page_pipe_add_page(pp, pgaddr); + ret = page_pipe_add_page(pp, pgaddr, 0); if (ret == -EAGAIN) { ret = dump_pages(pp, &xfer, addr); From dce7ce1e03b3df8b14f42a5fa39b644581b485b4 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Jun 2016 09:27:36 +0300 Subject: [PATCH 0763/4375] criu: page-pipe: introduce page_pipe_split This will allow to split a ppb so that data residing at specified address will be immediately available Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/page-pipe.h | 3 + criu/page-pipe.c | 174 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h index 95e31bc85..a35d4794c 100644 --- a/criu/include/page-pipe.h +++ b/criu/include/page-pipe.h @@ -129,4 +129,7 @@ extern int page_pipe_add_hole(struct page_pipe *p, unsigned long addr); extern void debug_show_page_pipe(struct page_pipe *pp); void page_pipe_reinit(struct page_pipe *pp); +extern int page_pipe_split(struct page_pipe *pp, unsigned long addr, + unsigned int *nr_pages); + #endif /* __CR_PAGE_PIPE_H__ */ diff --git a/criu/page-pipe.c b/criu/page-pipe.c index d0fdf03a1..71bec268b 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -83,6 +83,25 @@ static int ppb_resize_pipe(struct page_pipe_buf *ppb, unsigned long new_size) return 0; } +static struct page_pipe_buf *ppb_alloc_resize(struct page_pipe *pp, int size) +{ + struct page_pipe_buf *ppb; + int nr_pages = size / PAGE_SIZE; + + ppb = ppb_alloc(pp); + if (!ppb) + return NULL; + + if (ppb->pipe_size < nr_pages) { + if (ppb_resize_pipe(ppb, nr_pages)) { + ppb_destroy(ppb); + return NULL; + } + } + + return ppb; +} + static int page_pipe_grow(struct page_pipe *pp, unsigned int flags) { struct page_pipe_buf *ppb; @@ -271,6 +290,161 @@ out: return 0; } +/* + * Get ppb and iov that contain addr and count amount of data between + * beginning of the pipe belonging to the ppb and addr + */ +static struct page_pipe_buf *get_ppb(struct page_pipe *pp, unsigned long addr, + struct iovec **iov_ret, + unsigned long *len) +{ + struct page_pipe_buf *ppb; + int i; + + list_for_each_entry(ppb, &pp->bufs, l) { + for (i = 0, *len = 0; i < ppb->nr_segs; i++) { + struct iovec *iov = &ppb->iov[i]; + unsigned long base = (unsigned long)iov->iov_base; + + if (addr < base || addr >= base + iov->iov_len) { + *len += iov->iov_len; + continue; + } + + /* got iov that contains the addr */ + *len += (addr - base); + *iov_ret = iov; + + list_move(&ppb->l, &pp->bufs); + return ppb; + } + } + + return NULL; +} + +static int page_pipe_split_iov(struct page_pipe *pp, struct page_pipe_buf *ppb, + struct iovec *iov, unsigned long addr, + bool popup_new) +{ + unsigned long len = addr - (unsigned long)iov->iov_base; + struct page_pipe_buf *ppb_new; + struct iovec *iov_new; + int ret; + + if (len == iov->iov_len) + return 0; + + ppb_new = ppb_alloc_resize(pp, len); + if (!ppb_new) + return -1; + + ret = splice(ppb->p[0], NULL, ppb_new->p[1], NULL, len, SPLICE_F_MOVE); + if (ret != len) + return -1; + + iov_new = &pp->iovs[pp->free_iov++]; + BUG_ON(pp->free_iov > pp->nr_iovs); + iov_new->iov_base = iov->iov_base; + iov_new->iov_len = len; + + ppb_init(ppb_new, len / PAGE_SIZE, 1, ppb->flags, iov_new); + + ppb->pages_in -= len / PAGE_SIZE; + + iov->iov_base += len; + iov->iov_len -= len; + + if (popup_new) + ppb = ppb_new; + list_move(&ppb->l, &pp->bufs); + + return 0; +} + +static int page_pipe_split_ppb(struct page_pipe *pp, struct page_pipe_buf *ppb, + struct iovec *iov, unsigned long len) +{ + struct page_pipe_buf *ppb_new; + int ret; + + ppb_new = ppb_alloc_resize(pp, len); + if (!ppb_new) + return -1; + + ret = splice(ppb->p[0], NULL, ppb_new->p[1], NULL, len, SPLICE_F_MOVE); + if (ret != len) + return -1; + + ppb_init(ppb_new, len / PAGE_SIZE, iov - ppb->iov, ppb->flags, ppb->iov); + + ppb->iov += ppb_new->nr_segs; + ppb->nr_segs -= ppb_new->nr_segs; + ppb->pages_in -= len / PAGE_SIZE; + + list_move(&ppb->l, &pp->bufs); + + return 0; +} + +/* + * Find the ppb containing addr and split so that we can splice + * nr_pages starting from addr. Make the ppb containing relavant pages + * the first entry in bb->bufs list + */ +int page_pipe_split(struct page_pipe *pp, unsigned long addr, + unsigned int *nr_pages) +{ + struct page_pipe_buf *ppb; + struct iovec *iov = NULL; + unsigned long len = 0; + int ret; + + /* + * Get ppb that contains addr and count length of data between + * the beginning of the pipe and addr. If no ppb is found, the + * requested page is mapped to zero pfn + */ + ppb = get_ppb(pp, addr, &iov, &len); + if (!ppb) { + *nr_pages = 0; + return 0; + } + + /* split origingal ppb on boundary of iov that contains addr */ + if (iov != ppb->iov) { + len -= (addr - (unsigned long)iov->iov_base); + ret = page_pipe_split_ppb(pp, ppb, iov, len); + if (ret) + return -1; + } + + + /* + * if address does not match iov base, split the iov and + * create a new ppb pointing to the new iov + */ + if (addr != (unsigned long)iov->iov_base) { + ret = page_pipe_split_iov(pp, ppb, iov, addr, false); + if (ret) + return -1; + } + + /* + * at this point iov_base points to addr, so we need to split + * the part after addr + requested pages to a separate iov + */ + len = min((unsigned long)iov->iov_base + iov->iov_len - addr, + (unsigned long)(*nr_pages) * PAGE_SIZE); + ret = page_pipe_split_iov(pp, ppb, iov, addr + len, true); + if (ret) + return -1; + + *nr_pages = len / PAGE_SIZE; + + return 0; +} + void debug_show_page_pipe(struct page_pipe *pp) { struct page_pipe_buf *ppb; From b6cad30524c2641ade33acce7ead7a05fb1d8a9c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Jun 2016 09:27:37 +0300 Subject: [PATCH 0764/4375] criu: page-pipe: introduce page_pipe_destroy_ppb Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/page-pipe.h | 2 ++ criu/page-pipe.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h index a35d4794c..36562806c 100644 --- a/criu/include/page-pipe.h +++ b/criu/include/page-pipe.h @@ -132,4 +132,6 @@ void page_pipe_reinit(struct page_pipe *pp); extern int page_pipe_split(struct page_pipe *pp, unsigned long addr, unsigned int *nr_pages); +extern void page_pipe_destroy_ppb(struct page_pipe_buf *ppb); + #endif /* __CR_PAGE_PIPE_H__ */ diff --git a/criu/page-pipe.c b/criu/page-pipe.c index 71bec268b..fbad211f7 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -445,6 +445,12 @@ int page_pipe_split(struct page_pipe *pp, unsigned long addr, return 0; } +void page_pipe_destroy_ppb(struct page_pipe_buf *ppb) +{ + list_del(&ppb->l); + ppb_destroy(ppb); +} + void debug_show_page_pipe(struct page_pipe *pp) { struct page_pipe_buf *ppb; From 6f7f11e3b3d9c7888bf66f83760eaffb4b214e67 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 16 Jun 2016 08:06:00 +0300 Subject: [PATCH 0765/4375] criu: lazy-pages: take care of possible NULL pointer dereference Fix CID 163485 (#2 of 2): Dereference null return value (NULL_RETURNS) 7. dereference: Dereferencing a pointer that might be null dest when calling handle_user_fault. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/uffd.c b/criu/uffd.c index 60d737b92..3a4be4785 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -731,6 +731,7 @@ static int handle_requests(int epollfd, struct epoll_event *events) for (i = 0; i < ret; i++) { lpi = uffd_to_lpi(events[i].data.fd); + BUG_ON(!lpi); ret = handle_user_fault(lpi, dest); if (ret < 0) goto out; From a2c1affc1826f71962aa6c492ee89e0a0745bcf9 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 16 Jun 2016 12:02:00 +0300 Subject: [PATCH 0766/4375] criu: lazy-pages: don't modify variable used in a loop Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 3a4be4785..01b50ea58 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -730,10 +730,11 @@ static int handle_requests(int epollfd, struct epoll_event *events) } for (i = 0; i < ret; i++) { + int err; lpi = uffd_to_lpi(events[i].data.fd); BUG_ON(!lpi); - ret = handle_user_fault(lpi, dest); - if (ret < 0) + err = handle_user_fault(lpi, dest); + if (err < 0) goto out; } } From c12477da94fa88e9ce0bc2698fb4ca1dec9b404a Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 19 Jun 2016 16:35:26 +0300 Subject: [PATCH 0767/4375] criu: lazy-pages: create UNIX socket for lazy-pages daemon in work_dir Signed-off-by: Mike Rapoport Acked-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 62 +++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 01b50ea58..0cb436624 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -39,6 +39,8 @@ #undef LOG_PREFIX #define LOG_PREFIX "lazy-pages: " +#define LAZY_PAGES_SOCK_NAME "lazy-pages.socket" + struct lazy_pages_info { int pid; int uffd; @@ -108,6 +110,24 @@ static void lpi_hash_fini(void) lpi_fini(p); } +static int prepare_sock_addr(struct sockaddr_un *saddr) +{ + int len; + + memset(saddr, 0, sizeof(struct sockaddr_un)); + + saddr->sun_family = AF_UNIX; + len = snprintf(saddr->sun_path, sizeof(saddr->sun_path), + "%s/%s", opts.work_dir, LAZY_PAGES_SOCK_NAME); + if (len >= sizeof(saddr->sun_path)) { + pr_err("Wrong UNIX socket name: %s/%s\n", + opts.work_dir, LAZY_PAGES_SOCK_NAME); + return -1; + } + + return 0; +} + static int send_uffd(int sendfd, int pid) { int fd; @@ -115,30 +135,18 @@ static int send_uffd(int sendfd, int pid) int ret = -1; struct sockaddr_un sun; - if (!opts.addr) { - pr_info("Please specify a file name for the unix domain socket\n"); - pr_info("used to communicate between the lazy-pages server\n"); - pr_info("and the restore process. Use the --address option like\n"); - pr_info("criu restore --lazy-pages --address /tmp/userfault.socket\n"); - return -1; - } - if (sendfd < 0) return -1; - if (strlen(opts.addr) >= sizeof(sun.sun_path)) { + if (prepare_sock_addr(&sun)) return -1; - } if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) return -1; - memset(&sun, 0, sizeof(sun)); - sun.sun_family = AF_UNIX; - strcpy(sun.sun_path, opts.addr); - len = offsetof(struct sockaddr_un, sun_path) + strlen(opts.addr); + len = offsetof(struct sockaddr_un, sun_path) + strlen(sun.sun_path); if (connect(fd, (struct sockaddr *) &sun, len) < 0) { - pr_perror("connect to %s failed", opts.addr); + pr_perror("connect to %s failed", sun.sun_path); goto out; } @@ -231,19 +239,12 @@ static int server_listen(struct sockaddr_un *saddr) int fd; int len; - if (strlen(opts.addr) >= sizeof(saddr->sun_path)) { - return -1; - } - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) return -1; - unlink(opts.addr); + unlink(saddr->sun_path); - memset(saddr, 0, sizeof(struct sockaddr_un)); - saddr->sun_family = AF_UNIX; - strcpy(saddr->sun_path, opts.addr); - len = offsetof(struct sockaddr_un, sun_path) + strlen(opts.addr); + len = offsetof(struct sockaddr_un, sun_path) + strlen(saddr->sun_path); if (bind(fd, (struct sockaddr *) saddr, len) < 0) { goto out; @@ -816,7 +817,10 @@ static int prepare_uffds(int epollfd) int listen; struct sockaddr_un saddr; - pr_debug("Waiting for incoming connections on %s\n", opts.addr); + if (prepare_sock_addr(&saddr)) + return -1; + + pr_debug("Waiting for incoming connections on %s\n", saddr.sun_path); if ((listen = server_listen(&saddr)) < 0) { pr_perror("server_listen error"); return -1; @@ -849,14 +853,6 @@ int cr_lazy_pages() if (check_for_uffd()) return -1; - if (!opts.addr) { - pr_info("Please specify a file name for the unix domain socket\n"); - pr_info("used to communicate between the lazy-pages server\n"); - pr_info("and the restore process. Use the --address option like\n"); - pr_info("criu --lazy-pages --address /tmp/userfault.socket\n"); - return -1; - } - lpi_hash_init(); if (lazy_pages_prepare_pstree()) From b2dafe74d0a85b44d72348285d106f110bad5e92 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 27 Jun 2016 07:53:22 +0300 Subject: [PATCH 0768/4375] criu: lazy-pages: use new pagemap features Pagemap now is more friendly to random accesses, enable use of new APIs. Signed-off-by: Mike Rapoport Acked-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 0cb436624..262ee383e 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -47,6 +47,8 @@ struct lazy_pages_info { struct list_head pages; + struct page_read pr; + unsigned long total_pages; unsigned long copied_pages; @@ -75,6 +77,8 @@ static void lpi_fini(struct lazy_pages_info *lpi) { if (lpi->uffd > 0) close(lpi->uffd); + if (lpi->pr.close) + lpi->pr.close(&lpi->pr); free(lpi); } @@ -325,37 +329,26 @@ out: static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest) { - struct iovec iov; int ret; unsigned char buf[PAGE_SIZE]; - struct page_read pr; - ret = open_page_read(lpi->pid, &pr, PR_TASK | PR_MOD); - pr_debug("get_page ret %d\n", ret); + lpi->pr.reset(&lpi->pr); - ret = pr.get_pagemap(&pr, &iov); - pr_debug("get_pagemap ret %d\n", ret); - if (ret <= 0) - return ret; - - ret = pr.seek_page(&pr, addr); + ret = lpi->pr.seek_page(&lpi->pr, addr); pr_debug("seek_pagemap_page ret 0x%x\n", ret); if (ret <= 0) return ret; - if (pr.pe->zero) + if (lpi->pr.pe->zero) return 0; - ret = pr.read_pages(&pr, addr, 1, buf, 0); + ret = lpi->pr.read_pages(&lpi->pr, addr, 1, buf, 0); pr_debug("read_pages ret %d\n", ret); if (ret <= 0) return ret; memcpy(dest, buf, PAGE_SIZE); - if (pr.close) - pr.close(&pr); - return 1; } @@ -559,7 +552,6 @@ static int find_vmas(struct lazy_pages_info *lpi) struct vm_area_list vmas; int vn = 0; struct rst_info *ri; - struct page_read pr; struct uffd_pages_struct *uffd_pages; struct pstree_item *item = pstree_item_by_virt(lpi->pid); @@ -605,7 +597,7 @@ static int find_vmas(struct lazy_pages_info *lpi) pr_info("vma 0x%"PRIx64" 0x%"PRIx64"\n", vma->e->start, vma->e->end); } - ret = open_page_read(lpi->pid, &pr, PR_TASK); + ret = open_page_read(lpi->pid, &lpi->pr, PR_TASK); if (ret <= 0) { ret = -1; goto out; @@ -617,15 +609,12 @@ static int find_vmas(struct lazy_pages_info *lpi) * pushed into the process using userfaultfd. */ do { - ret = collect_uffd_pages(&pr, lpi); + ret = collect_uffd_pages(&lpi->pr, lpi); if (ret == -1) { goto out; } } while (ret); - if (pr.close) - pr.close(&pr); - /* Count detected pages */ list_for_each_entry(uffd_pages, &lpi->pages, list) ret++; From a1ed9e0992835037994aa43b246adff86ca76b63 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 14 Jul 2016 15:49:33 +0300 Subject: [PATCH 0769/4375] criu: pagemap: add entries for zero pages The pages that are mapped to zero_page_pfn are not dumped but information where are they located is required for lazy restore. Note that get_pagemap users presumed that zero pages are not a part of the pagemap and these pages were just silently skipped during memory restore. At the moment I preserve this semantics and force get_pagemap to skip zero pages. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/page-pipe.h | 7 +++- criu/include/page-xfer.h | 2 +- criu/include/stats.h | 1 + criu/mem.c | 28 ++++++++++------ criu/page-pipe.c | 13 ++++++-- criu/page-xfer.c | 71 ++++++++++++++++++++++++++++------------ criu/pagemap.c | 19 ++++++++--- criu/shmem.c | 6 ++-- criu/stats.c | 1 + images/pagemap.proto | 1 + images/stats.proto | 2 ++ 11 files changed, 109 insertions(+), 42 deletions(-) diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h index 36562806c..ea91dac1e 100644 --- a/criu/include/page-pipe.h +++ b/criu/include/page-pipe.h @@ -101,6 +101,9 @@ struct page_pipe_buf { struct list_head l; /* links into page_pipe->bufs */ }; +#define PP_HOLE_PARENT (1 << 0) +#define PP_HOLE_ZERO (1 << 1) + struct page_pipe { unsigned int nr_pipes; /* how many page_pipe_bufs in there */ struct list_head bufs; /* list of bufs */ @@ -113,6 +116,7 @@ struct page_pipe { unsigned int nr_holes; /* number of holes allocated */ unsigned int free_hole; /* number of holes in use */ struct iovec *holes; /* holes */ + unsigned int *hole_flags; unsigned flags; /* PP_FOO flags below */ }; @@ -124,7 +128,8 @@ struct page_pipe *create_page_pipe(unsigned int nr_segs, struct iovec *iovs, uns extern void destroy_page_pipe(struct page_pipe *p); extern int page_pipe_add_page(struct page_pipe *p, unsigned long addr, unsigned int flags); -extern int page_pipe_add_hole(struct page_pipe *p, unsigned long addr); +extern int page_pipe_add_hole(struct page_pipe *pp, unsigned long addr, + unsigned int flags); extern void debug_show_page_pipe(struct page_pipe *pp); void page_pipe_reinit(struct page_pipe *pp); diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index d19671beb..3ba61ed74 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -16,7 +16,7 @@ struct page_xfer { /* transfers pages related to previous pagemap */ int (*write_pages)(struct page_xfer *self, int pipe, unsigned long len); /* transfers one hole -- vaddr:len entry w/o pages */ - int (*write_hole)(struct page_xfer *self, struct iovec *iov); + int (*write_hole)(struct page_xfer *self, struct iovec *iov, int type); void (*close)(struct page_xfer *self); /* private data for every page-xfer engine */ diff --git a/criu/include/stats.h b/criu/include/stats.h index e417636e6..c0effa7a1 100644 --- a/criu/include/stats.h +++ b/criu/include/stats.h @@ -25,6 +25,7 @@ enum { CNT_PAGES_SCANNED, CNT_PAGES_SKIPPED_PARENT, CNT_PAGES_WRITTEN, + CNT_PAGES_ZERO, DUMP_CNT_NR_STATS, }; diff --git a/criu/mem.c b/criu/mem.c index 19f753f25..afdce7352 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -109,14 +109,17 @@ bool should_dump_page(VmaEntry *vmae, u64 pme) return false; if (vma_entry_is(vmae, VMA_AREA_AIORING)) return true; - if (pme & PME_SWAP) - return true; - if ((pme & PME_PRESENT) && ((pme & PME_PFRAME_MASK) != kdat.zero_page_pfn)) + if (pme & (PME_PRESENT | PME_SWAP)) return true; return false; } +static inline bool page_is_zero(u64 pme) +{ + return (pme & PME_PFRAME_MASK) == kdat.zero_page_pfn; +} + bool page_in_parent(bool dirty) { /* @@ -140,7 +143,7 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u { u64 *at = &map[PAGE_PFN(*off)]; unsigned long pfn, nr_to_scan; - unsigned long pages[2] = {}; + unsigned long pages[3] = {}; nr_to_scan = (vma_area_len(vma) - *off) / PAGE_SIZE; @@ -164,12 +167,15 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u * page. The latter would be checked in page-xfer. */ - if (has_parent && page_in_parent(at[pfn] & PME_SOFT_DIRTY)) { - ret = page_pipe_add_hole(pp, vaddr); + if (page_is_zero(at[pfn])) { + ret = page_pipe_add_hole(pp, vaddr, PP_HOLE_ZERO); pages[0]++; + } else if (has_parent && page_in_parent(at[pfn] & PME_SOFT_DIRTY)) { + ret = page_pipe_add_hole(pp, vaddr, PP_HOLE_PARENT); + pages[1]++; } else { ret = page_pipe_add_page(pp, vaddr, ppb_flags); - pages[1]++; + pages[2]++; } if (ret) { @@ -181,10 +187,12 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u *off += pfn * PAGE_SIZE; cnt_add(CNT_PAGES_SCANNED, nr_to_scan); - cnt_add(CNT_PAGES_SKIPPED_PARENT, pages[0]); - cnt_add(CNT_PAGES_WRITTEN, pages[1]); + cnt_add(CNT_PAGES_ZERO, pages[0]); + cnt_add(CNT_PAGES_SKIPPED_PARENT, pages[1]); + cnt_add(CNT_PAGES_WRITTEN, pages[2]); - pr_info("Pagemap generated: %lu pages %lu holes\n", pages[1], pages[0]); + pr_info("Pagemap generated: %lu pages %lu holes %lu zeros\n", + pages[2], pages[1], pages[0]); return 0; } diff --git a/criu/page-pipe.c b/criu/page-pipe.c index fbad211f7..8ea6f33fe 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -269,7 +269,8 @@ int page_pipe_add_page(struct page_pipe *pp, unsigned long addr, #define PP_HOLES_BATCH 32 -int page_pipe_add_hole(struct page_pipe *pp, unsigned long addr) +int page_pipe_add_hole(struct page_pipe *pp, unsigned long addr, + unsigned int flags) { if (pp->free_hole >= pp->nr_holes) { pp->holes = xrealloc(pp->holes, @@ -277,15 +278,23 @@ int page_pipe_add_hole(struct page_pipe *pp, unsigned long addr) if (!pp->holes) return -1; + pp->hole_flags = xrealloc(pp->hole_flags, + (pp->nr_holes + PP_HOLES_BATCH) * sizeof(unsigned int)); + if(!pp->hole_flags) + return -1; + pp->nr_holes += PP_HOLES_BATCH; } if (pp->free_hole && - iov_grow_page(&pp->holes[pp->free_hole - 1], addr)) + pp->hole_flags[pp->free_hole - 1] == flags && + iov_grow_page(&pp->holes[pp->free_hole - 1], addr)) goto out; iov_init(&pp->holes[pp->free_hole++], addr); + pp->hole_flags[pp->free_hole - 1] = flags; + out: return 0; } diff --git a/criu/page-xfer.c b/criu/page-xfer.c index f6b1d9012..23e00853b 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -38,6 +38,7 @@ static void psi2iovec(struct page_server_iov *ps, struct iovec *iov) #define PS_IOV_OPEN 3 #define PS_IOV_OPEN2 4 #define PS_IOV_PARENT 5 +#define PS_IOV_ZERO 6 #define PS_IOV_FLUSH 0x1023 #define PS_IOV_FLUSH_N_CLOSE 0x1024 @@ -149,9 +150,10 @@ static int write_pages_to_server(struct page_xfer *xfer, return 0; } -static int write_hole_to_server(struct page_xfer *xfer, struct iovec *iov) +static int write_hole_to_server(struct page_xfer *xfer, struct iovec *iov, + int type) { - return send_iov(xfer->sk, PS_IOV_HOLE, xfer->dst_id, iov); + return send_iov(xfer->sk, type, xfer->dst_id, iov); } static void close_server_xfer(struct page_xfer *xfer) @@ -276,25 +278,36 @@ static int check_pagehole_in_parent(struct page_read *p, struct iovec *iov) } } -static int write_pagehole_loc(struct page_xfer *xfer, struct iovec *iov) +static int write_hole_loc(struct page_xfer *xfer, struct iovec *iov, int type) { PagemapEntry pe = PAGEMAP_ENTRY__INIT; - if (xfer->parent != NULL) { - int ret; - - ret = check_pagehole_in_parent(xfer->parent, iov); - if (ret) { - pr_err("Hole %p/%zu not found in parent\n", - iov->iov_base, iov->iov_len); - return -1; - } - } - pe.vaddr = encode_pointer(iov->iov_base); pe.nr_pages = iov->iov_len / PAGE_SIZE; - pe.has_in_parent = true; - pe.in_parent = true; + + switch (type) { + case PS_IOV_HOLE: + if (xfer->parent != NULL) { + int ret; + + ret = check_pagehole_in_parent(xfer->parent, iov); + if (ret) { + pr_err("Hole %p/%zu not found in parent\n", + iov->iov_base, iov->iov_len); + return -1; + } + } + + pe.has_in_parent = true; + pe.in_parent = true; + break; + case PS_IOV_ZERO: + pe.has_zero = true; + pe.zero = true; + break; + default: + return -1; + } if (pb_write_one(xfer->pmi, &pe, PB_PAGEMAP) < 0) return -1; @@ -364,7 +377,7 @@ static int open_page_local_xfer(struct page_xfer *xfer, int fd_type, long id) out: xfer->write_pagemap = write_pagemap_loc; xfer->write_pages = write_pages_loc; - xfer->write_hole = write_pagehole_loc; + xfer->write_hole = write_hole_loc; xfer->close = close_page_xfer; return 0; } @@ -378,19 +391,33 @@ int open_page_xfer(struct page_xfer *xfer, int fd_type, long id) } static int page_xfer_dump_hole(struct page_xfer *xfer, - struct iovec *hole, unsigned long off) + struct iovec *hole, unsigned long off, int type) { BUG_ON(hole->iov_base < (void *)off); hole->iov_base -= off; pr_debug("\th %p [%u]\n", hole->iov_base, (unsigned int)(hole->iov_len / PAGE_SIZE)); - if (xfer->write_hole(xfer, hole)) + if (xfer->write_hole(xfer, hole, type)) return -1; return 0; } +static int get_hole_type(struct page_pipe *pp, int n) +{ + unsigned int hole_flags = pp->hole_flags[n]; + + if (hole_flags == PP_HOLE_PARENT) + return PS_IOV_HOLE; + if (hole_flags == PP_HOLE_ZERO) + return PS_IOV_ZERO; + else + BUG(); + + return -1; +} + static int dump_holes(struct page_xfer *xfer, struct page_pipe *pp, unsigned int *cur_hole, void *limit, unsigned long off) { @@ -398,11 +425,12 @@ static int dump_holes(struct page_xfer *xfer, struct page_pipe *pp, for (; *cur_hole < pp->free_hole ; (*cur_hole)++) { struct iovec hole = pp->holes[*cur_hole]; + int hole_type = get_hole_type(pp, *cur_hole); if (limit && hole.iov_base >= limit) break; - ret = page_xfer_dump_hole(xfer, &hole, off); + ret = page_xfer_dump_hole(xfer, &hole, off, hole_type); if (ret) return ret; } @@ -655,7 +683,7 @@ static int page_server_hole(int sk, struct page_server_iov *pi) return -1; psi2iovec(pi, &iov); - if (lxfer->write_hole(lxfer, &iov)) + if (lxfer->write_hole(lxfer, &iov, pi->cmd)) return -1; return 0; @@ -711,6 +739,7 @@ static int page_server_serve(int sk) ret = page_server_add(sk, &pi); break; case PS_IOV_HOLE: + case PS_IOV_ZERO: ret = page_server_hole(sk, &pi); break; case PS_IOV_FLUSH: diff --git a/criu/pagemap.c b/criu/pagemap.c index dc42731ae..a2c07de3c 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -123,13 +123,19 @@ int dedup_one_iovec(struct page_read *pr, unsigned long off, unsigned long len) static int advance(struct page_read *pr) { - pr->curr_pme++; - if (pr->curr_pme >= pr->nr_pmes) - return 0; + for (;;) { + pr->curr_pme++; + if (pr->curr_pme >= pr->nr_pmes) + return 0; + + pe = pr->pmes[pr->curr_pme]; + + if (!pe->zero) + break; + } pr->pe = pr->pmes[pr->curr_pme]; pr->cvaddr = pr->pe->vaddr; - return 1; } @@ -138,7 +144,7 @@ static void skip_pagemap_pages(struct page_read *pr, unsigned long len) if (!len) return; - if (!pr->pe->in_parent) + if (!pr->pe->in_parent && !pr->pe->zero) pr->pi_off += len; pr->cvaddr += len; } @@ -412,6 +418,9 @@ static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, int nr, if (pr->pe->in_parent) { if (read_parent_page(pr, vaddr, nr, buf, flags) < 0) return -1; + } else if (pr->pe->zero) { + /* zero mappings should be skipped by get_pagemap */ + BUG(); } else { if (maybe_read_page(pr, vaddr, nr, buf, flags) < 0) return -1; diff --git a/criu/shmem.c b/criu/shmem.c index 270507a92..6facf0621 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -218,6 +218,8 @@ static void update_shmem_pmaps(struct shmem_info *si, u64 *map, VmaEntry *vma) shmem_pfn = vma_pfn + DIV_ROUND_UP(vma->pgoff, PAGE_SIZE); if (map[vma_pfn] & PME_SOFT_DIRTY) set_pstate(si->pstate_map, shmem_pfn, PST_DIRTY); + else if (page_is_zero(map[vma_pfn])) + set_pstate(si->pstate_map, shmem_pfn, PST_ZERO); else set_pstate(si->pstate_map, shmem_pfn, PST_DUMP); } @@ -709,9 +711,9 @@ static int do_dump_one_shmem(int fd, void *addr, struct shmem_info *si) pgaddr = (unsigned long)addr + pfn * PAGE_SIZE; again: if (pgstate == PST_ZERO) - ret = 0; + ret = page_pipe_add_hole(pp, pgaddr, PP_HOLE_ZERO); else if (xfer.parent && page_in_parent(pgstate == PST_DIRTY)) - ret = page_pipe_add_hole(pp, pgaddr); + ret = page_pipe_add_hole(pp, pgaddr, PP_HOLE_PARENT); else ret = page_pipe_add_page(pp, pgaddr, 0); diff --git a/criu/stats.c b/criu/stats.c index 7e62d7ae8..7caabf18c 100644 --- a/criu/stats.c +++ b/criu/stats.c @@ -157,6 +157,7 @@ void write_stats(int what) ds_entry.pages_scanned = dstats->counts[CNT_PAGES_SCANNED]; ds_entry.pages_skipped_parent = dstats->counts[CNT_PAGES_SKIPPED_PARENT]; ds_entry.pages_written = dstats->counts[CNT_PAGES_WRITTEN]; + ds_entry.pages_zero = dstats->counts[CNT_PAGES_ZERO]; name = "dump"; } else if (what == RESTORE_STATS) { diff --git a/images/pagemap.proto b/images/pagemap.proto index e45549cd6..00081620c 100644 --- a/images/pagemap.proto +++ b/images/pagemap.proto @@ -10,4 +10,5 @@ message pagemap_entry { required uint64 vaddr = 1 [(criu).hex = true]; required uint32 nr_pages = 2; optional bool in_parent = 3; + optional bool zero = 4; } diff --git a/images/stats.proto b/images/stats.proto index 81887669b..c099eb1e9 100644 --- a/images/stats.proto +++ b/images/stats.proto @@ -12,6 +12,8 @@ message dump_stats_entry { required uint64 pages_written = 7; optional uint32 irmap_resolve = 8; + + required uint64 pages_zero = 9; } message restore_stats_entry { From a9a973da77dab9ad6f3741fd8a2cfd7ea614186e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 14 Jul 2016 15:49:34 +0300 Subject: [PATCH 0770/4375] criu: add ability to skip writing lazy pages When appropriate, the lazy pages will no be written to the destination. Instead, a pagemap entry for range of such pages will be marked with 'lazy' flag. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-dump.c | 2 +- criu/include/page-xfer.h | 2 +- criu/include/stats.h | 1 + criu/mem.c | 16 ++++++++++------ criu/page-xfer.c | 14 +++++++++++++- criu/pagemap.c | 2 +- criu/shmem.c | 2 +- criu/stats.c | 1 + images/pagemap.proto | 1 + images/stats.proto | 1 + 10 files changed, 31 insertions(+), 11 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index f9ff0f468..7a5eecee8 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1483,7 +1483,7 @@ static int cr_pre_dump_finish(int ret) goto err; mem_pp = dmpi(item)->mem_pp; - ret = page_xfer_dump_pages(&xfer, mem_pp, 0); + ret = page_xfer_dump_pages(&xfer, mem_pp, 0, true); xfer.close(&xfer); diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index 3ba61ed74..f92d357b7 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -38,7 +38,7 @@ struct page_xfer { extern int open_page_xfer(struct page_xfer *xfer, int fd_type, long id); struct page_pipe; extern int page_xfer_dump_pages(struct page_xfer *, struct page_pipe *, - unsigned long off); + unsigned long off, bool dump_lazy); extern int connect_to_page_server(void); extern int disconnect_from_page_server(void); diff --git a/criu/include/stats.h b/criu/include/stats.h index c0effa7a1..5d7177815 100644 --- a/criu/include/stats.h +++ b/criu/include/stats.h @@ -26,6 +26,7 @@ enum { CNT_PAGES_SKIPPED_PARENT, CNT_PAGES_WRITTEN, CNT_PAGES_ZERO, + CNT_PAGES_LAZY, DUMP_CNT_NR_STATS, }; diff --git a/criu/mem.c b/criu/mem.c index afdce7352..49e58cbd8 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -143,7 +143,7 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u { u64 *at = &map[PAGE_PFN(*off)]; unsigned long pfn, nr_to_scan; - unsigned long pages[3] = {}; + unsigned long pages[4] = {}; nr_to_scan = (vma_area_len(vma) - *off) / PAGE_SIZE; @@ -175,7 +175,10 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u pages[1]++; } else { ret = page_pipe_add_page(pp, vaddr, ppb_flags); - pages[2]++; + if (ppb_flags & PPB_LAZY) + pages[2]++; + else + pages[3]++; } if (ret) { @@ -189,10 +192,11 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u cnt_add(CNT_PAGES_SCANNED, nr_to_scan); cnt_add(CNT_PAGES_ZERO, pages[0]); cnt_add(CNT_PAGES_SKIPPED_PARENT, pages[1]); - cnt_add(CNT_PAGES_WRITTEN, pages[2]); + cnt_add(CNT_PAGES_LAZY, pages[2]); + cnt_add(CNT_PAGES_WRITTEN, pages[3]); - pr_info("Pagemap generated: %lu pages %lu holes %lu zeros\n", - pages[2], pages[1], pages[0]); + pr_info("Pagemap generated: %lu pages (%lu lazy) %lu holes %lu zeros\n", + pages[3] + pages[2], pages[2], pages[1], pages[0]); return 0; } @@ -272,7 +276,7 @@ static int xfer_pages(struct page_pipe *pp, struct page_xfer *xfer) * pre-dump action (see pre_dump_one_task) */ timing_start(TIME_MEMWRITE); - ret = page_xfer_dump_pages(xfer, pp, 0); + ret = page_xfer_dump_pages(xfer, pp, 0, true); timing_stop(TIME_MEMWRITE); return ret; diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 23e00853b..c77b2d0e8 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -39,6 +39,7 @@ static void psi2iovec(struct page_server_iov *ps, struct iovec *iov) #define PS_IOV_OPEN2 4 #define PS_IOV_PARENT 5 #define PS_IOV_ZERO 6 +#define PS_IOV_LAZY 7 #define PS_IOV_FLUSH 0x1023 #define PS_IOV_FLUSH_N_CLOSE 0x1024 @@ -305,6 +306,10 @@ static int write_hole_loc(struct page_xfer *xfer, struct iovec *iov, int type) pe.has_zero = true; pe.zero = true; break; + case PS_IOV_LAZY: + pe.has_lazy = true; + pe.lazy = true; + break; default: return -1; } @@ -439,7 +444,7 @@ static int dump_holes(struct page_xfer *xfer, struct page_pipe *pp, } int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, - unsigned long off) + unsigned long off, bool dump_lazy) { struct page_pipe_buf *ppb; unsigned int cur_hole = 0; @@ -464,6 +469,12 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, pr_debug("\tp %p [%u]\n", iov.iov_base, (unsigned int)(iov.iov_len / PAGE_SIZE)); + if (!dump_lazy && ppb->flags & PPB_LAZY) { + if (xfer->write_hole(xfer, &iov, PS_IOV_LAZY)) + return -1; + continue; + } + if (xfer->write_pagemap(xfer, &iov)) return -1; if (xfer->write_pages(xfer, ppb->p[0], iov.iov_len)) @@ -740,6 +751,7 @@ static int page_server_serve(int sk) break; case PS_IOV_HOLE: case PS_IOV_ZERO: + case PS_IOV_LAZY: ret = page_server_hole(sk, &pi); break; case PS_IOV_FLUSH: diff --git a/criu/pagemap.c b/criu/pagemap.c index a2c07de3c..206fcd376 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -144,7 +144,7 @@ static void skip_pagemap_pages(struct page_read *pr, unsigned long len) if (!len) return; - if (!pr->pe->in_parent && !pr->pe->zero) + if (!pr->pe->in_parent && !pr->pe->zero && !pr->pe->lazy) pr->pi_off += len; pr->cvaddr += len; } diff --git a/criu/shmem.c b/criu/shmem.c index 6facf0621..e8aeee867 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -640,7 +640,7 @@ static int dump_pages(struct page_pipe *pp, struct page_xfer *xfer, void *addr) return -1; } - return page_xfer_dump_pages(xfer, pp, (unsigned long)addr); + return page_xfer_dump_pages(xfer, pp, (unsigned long)addr, true); } static int next_data_segment(int fd, unsigned long pfn, diff --git a/criu/stats.c b/criu/stats.c index 7caabf18c..3fef9c472 100644 --- a/criu/stats.c +++ b/criu/stats.c @@ -158,6 +158,7 @@ void write_stats(int what) ds_entry.pages_skipped_parent = dstats->counts[CNT_PAGES_SKIPPED_PARENT]; ds_entry.pages_written = dstats->counts[CNT_PAGES_WRITTEN]; ds_entry.pages_zero = dstats->counts[CNT_PAGES_ZERO]; + ds_entry.pages_lazy = dstats->counts[CNT_PAGES_LAZY]; name = "dump"; } else if (what == RESTORE_STATS) { diff --git a/images/pagemap.proto b/images/pagemap.proto index 00081620c..8b0092f72 100644 --- a/images/pagemap.proto +++ b/images/pagemap.proto @@ -11,4 +11,5 @@ message pagemap_entry { required uint32 nr_pages = 2; optional bool in_parent = 3; optional bool zero = 4; + optional bool lazy = 5; } diff --git a/images/stats.proto b/images/stats.proto index c099eb1e9..f926a5a89 100644 --- a/images/stats.proto +++ b/images/stats.proto @@ -14,6 +14,7 @@ message dump_stats_entry { optional uint32 irmap_resolve = 8; required uint64 pages_zero = 9; + required uint64 pages_lazy = 10; } message restore_stats_entry { From 9982fc9e686b4667e05c5f24908e6792a8e3cf2d Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 14 Jul 2016 15:49:35 +0300 Subject: [PATCH 0771/4375] criu: page-xfer: add PS_IOV_GET interface Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/page-xfer.h | 2 + criu/page-xfer.c | 111 ++++++++++++++++++++++++++++++++++----- 2 files changed, 99 insertions(+), 14 deletions(-) diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index f92d357b7..007733eed 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -44,4 +44,6 @@ extern int disconnect_from_page_server(void); extern int check_parent_page_xfer(int fd_type, long id); +extern int get_remote_pages(int pid, unsigned long addr, int nr_pages, void *dest); + #endif /* __CR_PAGE_XFER__H__ */ diff --git a/criu/page-xfer.c b/criu/page-xfer.c index c77b2d0e8..fb3252dc9 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -17,6 +17,8 @@ #include "protobuf.h" #include "images/pagemap.pb-c.h" #include "fcntl.h" +#include "pstree.h" +#include "parasite-syscall.h" static int page_server_sk = -1; @@ -40,6 +42,7 @@ static void psi2iovec(struct page_server_iov *ps, struct iovec *iov) #define PS_IOV_PARENT 5 #define PS_IOV_ZERO 6 #define PS_IOV_LAZY 7 +#define PS_IOV_GET 8 #define PS_IOV_FLUSH 0x1023 #define PS_IOV_FLUSH_N_CLOSE 0x1024 @@ -700,27 +703,73 @@ static int page_server_hole(int sk, struct page_server_iov *pi) return 0; } +static int page_server_get_pages(int sk, struct page_server_iov *pi) +{ + struct pstree_item *item; + struct page_pipe *pp; + struct page_pipe_buf *ppb; + struct iovec *iov; + int ret; + + item = pstree_item_by_virt(pi->dst_id); + pp = dmpi(item)->mem_pp; + + ret = page_pipe_split(pp, pi->vaddr, &pi->nr_pages); + if (ret) + return ret; + + if (pi->nr_pages == 0) { + /* no iovs found means we've hit a zero page */ + pr_debug("no iovs found, zero pages\n"); + return send_psi(sk, PS_IOV_ZERO, 0, 0, 0); + } + + ppb = list_first_entry(&pp->bufs, struct page_pipe_buf, l); + iov = &ppb->iov[0]; + + BUG_ON(!(ppb->flags & PPB_LAZY)); + BUG_ON(iov->iov_len != pi->nr_pages * PAGE_SIZE); + BUG_ON(pi->vaddr != encode_pointer(iov->iov_base)); + + if (send_psi(sk, PS_IOV_ADD, pi->nr_pages, pi->vaddr, pi->dst_id)) + return -1; + + ret = splice(ppb->p[0], NULL, sk, NULL, iov->iov_len, SPLICE_F_MOVE); + if (ret != iov->iov_len) + return -1; + + tcp_nodelay(sk, true); + + page_pipe_destroy_ppb(ppb); + + return 0; +} + static int page_server_serve(int sk) { int ret = -1; bool flushed = false; - /* - * This socket only accepts data except one thing -- it - * writes back the has_parent bit from time to time, so - * make it NODELAY all the time. - */ - tcp_nodelay(sk, true); + if (!opts.lazy_pages) { + /* + * This socket only accepts data except one thing -- it + * writes back the has_parent bit from time to time, so + * make it NODELAY all the time. + */ + tcp_nodelay(sk, true); - if (pipe(cxfer.p)) { - pr_perror("Can't make pipe for xfer"); - close(sk); - return -1; + if (pipe(cxfer.p)) { + pr_perror("Can't make pipe for xfer"); + close(sk); + return -1; + } + + cxfer.pipe_size = fcntl(cxfer.p[0], F_GETPIPE_SZ, 0); + pr_debug("Created xfer pipe size %u\n", cxfer.pipe_size); + } else { + tcp_cork(sk, true); } - cxfer.pipe_size = fcntl(cxfer.p[0], F_GETPIPE_SZ, 0); - pr_debug("Created xfer pipe size %u\n", cxfer.pipe_size); - while (1) { struct page_server_iov pi; @@ -773,6 +822,10 @@ static int page_server_serve(int sk) flushed = true; break; } + case PS_IOV_GET: + flushed = true; + ret = page_server_get_pages(sk, &pi); + break; default: pr_err("Unknown command %u\n", pi.cmd); ret = -1; @@ -815,7 +868,8 @@ int cr_page_server(bool daemon_mode, int cfd) int sk = -1; int ret; - up_page_ids_base(); + if (!opts.lazy_pages) + up_page_ids_base(); if (opts.ps_socket != -1) { ret = 0; @@ -905,3 +959,32 @@ out: close_safe(&page_server_sk); return ret ? : status; } + +int get_remote_pages(int pid, unsigned long addr, int nr_pages, void *dest) +{ + int ret; + + struct page_server_iov pi; + + if (send_psi(page_server_sk, PS_IOV_GET, nr_pages, addr, pid)) + return -1; + + tcp_nodelay(page_server_sk, true); + + ret = recv(page_server_sk, &pi, sizeof(pi), MSG_WAITALL); + if (ret != sizeof(pi)) + return -1; + + /* zero page */ + if (pi.cmd == PS_IOV_ZERO) + return 0; + + if (pi.nr_pages > nr_pages) + return -1; + + ret = recv(page_server_sk, dest, PAGE_SIZE, MSG_WAITALL); + if (ret != PAGE_SIZE) + return -1; + + return 1; +} From 5ad71a890165eb3fa9f4fc1973f0ff0bdb0d4ef5 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 14 Jul 2016 15:49:36 +0300 Subject: [PATCH 0772/4375] criu: lazy-pages: enable remoting of lazy pages The remote lazy pages variant can be run as follows: src# criu dump -t --lazy-pages --port 9876 -D /tmp/1 & src# while ! sudo fuser 9876/tcp ; do sleep 1; done src# scp -r /tmp/1/ dst:/tmp/ dst# criu lazy-pages --page-server --address dst --port 9876 -D /tmp/1 & dst# criu restore --lazy-pages -D /tmp/1 In a nutshell, this implementation of remote lazy pages does the following: - dump collects the process memory into the pipes, transfers non-lazy pages to the images or to the page-server on the restore side. The lazy pages are kept in pipes for later transfer - when the dump creates the page_pipe_bufs, it marks the buffers containing potentially lazy pages with PPB_LAZY - at the dump_finish stage, the dump side starts TCP server that will handle page requests from the restore side - the checkpoint directory is transferred to the restore side - on the restore side lazy-pages daemon is started, it creates UNIX socket to receive uffd's from the restore and a TCP socket to forward page requests to the dump side - restore creates memory mappings and fills the VMAs that cannot be handled by uffd with the contents of the pages*img. - restore registers lazy VMAs with uffd and sends the userfault file descriptors to the lazy-pages daemon - when a #PF occurs, the lazy-pages daemon sends PS_IOV_GET command to the dump side; the command contains PID, the faulting address and amount of pages (always 1 at the moment) - the dump side extracts the requested pages from the pipe and splices them into the TCP socket. - the lazy-pages daemon copies the received pages into the restored process address space Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-dump.c | 32 +++++++++++++++++++++++++++++++- criu/include/mem.h | 1 + criu/mem.c | 18 +++++++++++------- criu/uffd.c | 9 ++++++++- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 7a5eecee8..47e8cf95f 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1187,6 +1187,7 @@ static int pre_dump_one_task(struct pstree_item *item) item->pid->ns[0].virt = misc.pid; mdc.pre_dump = true; + mdc.lazy = false; ret = parasite_dump_pages_seized(item, &vmas, &mdc, parasite_ctl); if (ret) @@ -1346,6 +1347,7 @@ static int dump_one_task(struct pstree_item *item) } mdc.pre_dump = false; + mdc.lazy = opts.lazy_pages; ret = parasite_dump_pages_seized(item, &vmas, &mdc, parasite_ctl); if (ret) @@ -1387,7 +1389,10 @@ static int dump_one_task(struct pstree_item *item) goto err; } - ret = compel_cure(parasite_ctl); + if (opts.lazy_pages) + ret = compel_cure_remote(parasite_ctl); + else + ret = compel_cure(parasite_ctl); if (ret) { pr_err("Can't cure (pid: %d) from parasite\n", pid); goto err; @@ -1591,6 +1596,27 @@ err: return cr_pre_dump_finish(ret); } +static int cr_lazy_mem_dump(void) +{ + struct pstree_item *item; + int ret = 0; + + pr_info("Starting lazy pages server\n"); + ret = cr_page_server(false, -1); + + for_each_pstree_item(item) { + destroy_page_pipe(dmpi(item)->mem_pp); + compel_cure_local(dmpi(item)->parasite_ctl); + } + + if (ret) + pr_err("Lazy pages transfer FAILED.\n"); + else + pr_info("Lazy pages transfer finished successfully\n"); + + return ret; +} + static int cr_dump_finish(int ret) { int post_dump_ret = 0; @@ -1650,6 +1676,10 @@ static int cr_dump_finish(int ret) delete_link_remaps(); clean_cr_time_mounts(); } + + if (opts.lazy_pages) + ret = cr_lazy_mem_dump(); + arch_set_thread_regs(root_item); pstree_switch_state(root_item, (ret || post_dump_ret) ? diff --git a/criu/include/mem.h b/criu/include/mem.h index 2fc8e1e0e..bbe0b766a 100644 --- a/criu/include/mem.h +++ b/criu/include/mem.h @@ -13,6 +13,7 @@ struct vma_area; struct mem_dump_ctl { bool pre_dump; + bool lazy; }; extern bool vma_has_guard_gap_hidden(struct vma_area *vma); diff --git a/criu/mem.c b/criu/mem.c index 49e58cbd8..71237ac5e 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -267,7 +267,7 @@ static int drain_pages(struct page_pipe *pp, struct parasite_ctl *ctl, return 0; } -static int xfer_pages(struct page_pipe *pp, struct page_xfer *xfer) +static int xfer_pages(struct page_pipe *pp, struct page_xfer *xfer, bool lazy) { int ret; @@ -276,7 +276,7 @@ static int xfer_pages(struct page_pipe *pp, struct page_xfer *xfer) * pre-dump action (see pre_dump_one_task) */ timing_start(TIME_MEMWRITE); - ret = page_xfer_dump_pages(xfer, pp, 0, true); + ret = page_xfer_dump_pages(xfer, pp, 0, !lazy); timing_stop(TIME_MEMWRITE); return ret; @@ -316,7 +316,7 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, return -1; ret = -1; - if (!mdc->pre_dump) + if (!(mdc->pre_dump || mdc->lazy)) /* * Chunk mode pushes pages portion by portion. This mode * only works when we don't need to keep pp for later @@ -324,7 +324,8 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, */ cpp_flags |= PP_CHUNK_MODE; pp = create_page_pipe(vma_area_list->priv_size, - pargs_iovs(args), cpp_flags); + mdc->lazy ? NULL : pargs_iovs(args), + cpp_flags); if (!pp) goto out; @@ -378,7 +379,7 @@ again: ret = drain_pages(pp, ctl, args); if (!ret) - ret = xfer_pages(pp, &xfer); + ret = xfer_pages(pp, &xfer, mdc->lazy /* false actually */); if (!ret) { page_pipe_reinit(pp); goto again; @@ -389,9 +390,12 @@ again: goto out_xfer; } + if (mdc->lazy) + memcpy(pargs_iovs(args), pp->iovs, + sizeof(struct iovec) * pp->nr_iovs); ret = drain_pages(pp, ctl, args); if (!ret && !mdc->pre_dump) - ret = xfer_pages(pp, &xfer); + ret = xfer_pages(pp, &xfer, mdc->lazy); if (ret) goto out_xfer; @@ -406,7 +410,7 @@ out_xfer: if (!mdc->pre_dump) xfer.close(&xfer); out_pp: - if (ret || !mdc->pre_dump) + if (ret || !(mdc->pre_dump || mdc->lazy)) destroy_page_pipe(pp); else dmpi(item)->mem_pp = pp; diff --git a/criu/uffd.c b/criu/uffd.c index 262ee383e..6830af6fe 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -35,6 +35,7 @@ #include "xmalloc.h" #include #include "restorer.h" +#include "page-xfer.h" #undef LOG_PREFIX #define LOG_PREFIX "lazy-pages: " @@ -366,7 +367,10 @@ static int uffd_copy_page(struct lazy_pages_info *lpi, __u64 address, struct uffdio_copy uffdio_copy; int rc; - rc = get_page(lpi, address, dest); + if (opts.use_page_server) + rc = get_remote_pages(lpi->pid, address, 1, dest); + else + rc = get_page(lpi, address, dest); if (rc <= 0) return rc; @@ -854,6 +858,9 @@ int cr_lazy_pages() if (prepare_uffds(epollfd)) return -1; + if (connect_to_page_server()) + return -1; + ret = handle_requests(epollfd, events); lpi_hash_fini(); From 0f60684b8fc5bef4a9717cfb6d1beff9a6a884c0 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 21 Jul 2016 14:37:00 +0300 Subject: [PATCH 0773/4375] make lpi_fini handle NULL to allow it after failed lpi_init in ud_open https://github.com/xemul/criu/issues/187 Signed-off-by: Pavel Tikhomirov Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/uffd.c b/criu/uffd.c index 6830af6fe..b81947293 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -76,6 +76,8 @@ static struct lazy_pages_info *lpi_init(void) static void lpi_fini(struct lazy_pages_info *lpi) { + if (!lpi) + return; if (lpi->uffd > 0) close(lpi->uffd); if (lpi->pr.close) From a405d25b6056b92a4fde525ce4cb752f0e0140d9 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 7 Aug 2016 17:22:51 +0300 Subject: [PATCH 0774/4375] criu/lazy-pages: fix socket creation with relative images-dir The UNIX sockets do not like relative paths. Assuming both lazy-pages daemon and restore use the same opts.work_dir, their working directory full path will be the same. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index b81947293..a55a69d72 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -119,16 +119,22 @@ static void lpi_hash_fini(void) static int prepare_sock_addr(struct sockaddr_un *saddr) { + char cwd[PATH_MAX]; int len; + if (!getcwd(cwd, PATH_MAX)) { + pr_perror("Cannot get CWD\n"); + return -1; + } + memset(saddr, 0, sizeof(struct sockaddr_un)); saddr->sun_family = AF_UNIX; len = snprintf(saddr->sun_path, sizeof(saddr->sun_path), - "%s/%s", opts.work_dir, LAZY_PAGES_SOCK_NAME); + "%s/%s", cwd, LAZY_PAGES_SOCK_NAME); if (len >= sizeof(saddr->sun_path)) { pr_err("Wrong UNIX socket name: %s/%s\n", - opts.work_dir, LAZY_PAGES_SOCK_NAME); + cwd, LAZY_PAGES_SOCK_NAME); return -1; } From b929e86c835ddd06ba0f09311f4b440ff60a322e Mon Sep 17 00:00:00 2001 From: Eugene Batalov Date: Sun, 7 Aug 2016 16:11:12 +0300 Subject: [PATCH 0775/4375] mem: make page_is_zero externally linked We'll use it in anon shmem dedup so we need to have access to it in shmem.c Signed-off-by: Eugene Batalov Signed-off-by: Pavel Emelyanov --- criu/include/mem.h | 1 + criu/mem.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/include/mem.h b/criu/include/mem.h index bbe0b766a..bb897c599 100644 --- a/criu/include/mem.h +++ b/criu/include/mem.h @@ -17,6 +17,7 @@ struct mem_dump_ctl { }; extern bool vma_has_guard_gap_hidden(struct vma_area *vma); +extern bool page_is_zero(u64 pme); extern bool page_in_parent(bool dirty); extern int prepare_mm_pid(struct pstree_item *i); extern void prepare_cow_vmas(void); diff --git a/criu/mem.c b/criu/mem.c index 71237ac5e..a8521b77f 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -115,7 +115,7 @@ bool should_dump_page(VmaEntry *vmae, u64 pme) return false; } -static inline bool page_is_zero(u64 pme) +bool page_is_zero(u64 pme) { return (pme & PME_PFRAME_MASK) == kdat.zero_page_pfn; } From f59b45fba2ce1315cb52a572171795634ffebf0f Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Sun, 7 Aug 2016 17:22:52 +0300 Subject: [PATCH 0776/4375] zdtm: check lazy-pages Cc: Adrian Reber Signed-off-by: Andrew Vagin Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- test/zdtm.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 3a546c5cd..4b064bc28 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -775,6 +775,7 @@ class criu: self.__iter = 0 self.__prev_dump_iter = None self.__page_server = (opts['page_server'] and True or False) + self.__lazy_pages = (opts['lazy_pages'] and True or False) self.__restore_sibling = (opts['sibling'] and True or False) self.__join_ns = (opts['join_ns'] and True or False) self.__empty_ns = (opts['empty_ns'] and True or False) @@ -961,6 +962,12 @@ class criu: r_opts.append('--external') r_opts.append('mnt[zdtm]:%s' % criu_dir) + lazy_pages_p = None + if self.__lazy_pages: + lazy_pages_p = self.__criu_act("lazy-pages", opts = [], nowait = True) + r_opts += ["--lazy-pages"] + time.sleep(1) # FIXME wait user fault fd socket + if self.__leave_stopped: r_opts += ['--leave-stopped'] @@ -982,6 +989,9 @@ class criu: pstree_check_stopped(self.__test.getpid()) pstree_signal(self.__test.getpid(), signal.SIGCONT) + if lazy_pages_p and lazy_pages_p.wait(): + raise test_fail_exc("CRIU lazy-pages") + @staticmethod def check(feature): return criu_cli.run("check", ["-v0", "--feature", feature]) == 0 @@ -1426,7 +1436,7 @@ class launcher: self.__show_progress(name) nd = ('nocr', 'norst', 'pre', 'iters', 'page_server', 'sibling', 'stop', 'empty_ns', - 'fault', 'keep_img', 'report', 'snaps', 'sat', 'script', 'rpc', + 'fault', 'keep_img', 'report', 'snaps', 'sat', 'script', 'rpc', 'lazy_pages', 'join_ns', 'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup') arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd})) @@ -1706,6 +1716,8 @@ def run_tests(opts): run_flavs -= set(['ns', 'uns']) if opts['empty_ns']: run_flavs -= set(['h']) + if opts['lazy_pages']: + run_flavs -= set(['ns', 'uns']) if run_flavs: l.run_test(t, tdesc, run_flavs) @@ -1923,6 +1935,7 @@ rp.add_argument("-k", "--keep-img", help = "Whether or not to keep images after rp.add_argument("--report", help = "Generate summary report in directory") rp.add_argument("--keep-going", help = "Keep running tests in spite of failures", action = 'store_true') rp.add_argument("--ignore-taint", help = "Don't care about a non-zero kernel taint flag", action = 'store_true') +rp.add_argument("--lazy-pages", help = "restore pages on demand", action = 'store_true') lp = sp.add_parser("list", help = "List tests") lp.set_defaults(action = list_tests) From 4bb1272ba52681ad83632422a1daac4c4d0ef75e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 7 Aug 2016 17:22:53 +0300 Subject: [PATCH 0777/4375] test: add scripts to allow Mr. Jenkins check lazy-pages Very minimalistic at the moment, no remote pages and namesapces. Still better than nothing :) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- test/jenkins/criu-lazy-pages.sh | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 test/jenkins/criu-lazy-pages.sh diff --git a/test/jenkins/criu-lazy-pages.sh b/test/jenkins/criu-lazy-pages.sh new file mode 100644 index 000000000..e3c62cfb4 --- /dev/null +++ b/test/jenkins/criu-lazy-pages.sh @@ -0,0 +1,5 @@ +# Check lazy-pages +set -e +source `dirname $0`/criu-lib.sh +prep +./test/zdtm.py run --all --keep-going --report report --parallel 4 --lazy-pages || fail From c95226054e7e9b52fda4575cb1024d602371ef00 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 15 Aug 2016 10:21:50 +0300 Subject: [PATCH 0778/4375] criu: lazy-pages: refactor UNIX socket initialization Create the socket early so that it will be available after restoring the namespaces Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-restore.c | 3 ++ criu/include/servicefd.h | 1 + criu/include/uffd.h | 1 + criu/uffd.c | 90 ++++++++++++++++++++++++++++------------ 4 files changed, 68 insertions(+), 27 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 3a48532f1..176383111 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2212,6 +2212,9 @@ int cr_restore_tasks(void) if (criu_signals_setup() < 0) goto err; + if (prepare_lazy_pages_socket() < 0) + goto err; + ret = restore_root_task(root_item); err: cr_plugin_fini(CR_PLUGIN_STAGE__RESTORE, ret); diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h index 39afd59c2..d47ab665a 100644 --- a/criu/include/servicefd.h +++ b/criu/include/servicefd.h @@ -22,6 +22,7 @@ enum sfd_type { TRANSPORT_FD_OFF, /* to transfer file descriptors */ RPC_SK_OFF, FDSTORE_SK_OFF, + LAZY_PAGES_SK_OFF, /* socket for communication with lazy-pages daemon */ SERVICE_FD_MAX }; diff --git a/criu/include/uffd.h b/criu/include/uffd.h index 66ce4594b..d8cf0d050 100644 --- a/criu/include/uffd.h +++ b/criu/include/uffd.h @@ -3,5 +3,6 @@ struct task_restore_args; extern int setup_uffd(int pid, struct task_restore_args *task_args); +extern int prepare_lazy_pages_socket(void); #endif /* __CR_UFFD_H_ */ diff --git a/criu/uffd.c b/criu/uffd.c index a55a69d72..292c4c05b 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -36,12 +36,16 @@ #include #include "restorer.h" #include "page-xfer.h" +#include "common/lock.h" +#include "rst-malloc.h" #undef LOG_PREFIX #define LOG_PREFIX "lazy-pages: " #define LAZY_PAGES_SOCK_NAME "lazy-pages.socket" +static mutex_t *lazy_sock_mutex; + struct lazy_pages_info { int pid; int uffd; @@ -144,25 +148,19 @@ static int prepare_sock_addr(struct sockaddr_un *saddr) static int send_uffd(int sendfd, int pid) { int fd; - int len; int ret = -1; - struct sockaddr_un sun; if (sendfd < 0) return -1; - if (prepare_sock_addr(&sun)) + fd = get_service_fd(LAZY_PAGES_SK_OFF); + if (fd < 0) { + pr_err("%s: get_service_fd\n", __func__); return -1; - - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - return -1; - - len = offsetof(struct sockaddr_un, sun_path) + strlen(sun.sun_path); - if (connect(fd, (struct sockaddr *) &sun, len) < 0) { - pr_perror("connect to %s failed", sun.sun_path); - goto out; } + mutex_lock(lazy_sock_mutex); + /* The "transfer protocol" is first the pid as int and then * the FD for UFFD */ pr_debug("Sending PID %d\n", pid); @@ -175,6 +173,9 @@ static int send_uffd(int sendfd, int pid) pr_perror("send_fd error:"); goto out; } + + mutex_unlock(lazy_sock_mutex); + ret = 0; out: close(fd); @@ -247,6 +248,42 @@ err: return -1; } +int prepare_lazy_pages_socket(void) +{ + int fd, new_fd; + int len; + struct sockaddr_un sun; + + if (!opts.lazy_pages) + return 0; + + if (prepare_sock_addr(&sun)) + return -1; + + lazy_sock_mutex = shmalloc(sizeof(*lazy_sock_mutex)); + if (!lazy_sock_mutex) + return -1; + + mutex_init(lazy_sock_mutex); + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return -1; + + new_fd = install_service_fd(LAZY_PAGES_SK_OFF, fd); + close(fd); + if (new_fd < 0) + return -1; + + len = offsetof(struct sockaddr_un, sun_path) + strlen(sun.sun_path); + if (connect(new_fd, (struct sockaddr *) &sun, len) < 0) { + pr_perror("connect to %s failed", sun.sun_path); + close(new_fd); + return -1; + } + + return 0; +} + static int server_listen(struct sockaddr_un *saddr) { int fd; @@ -276,24 +313,12 @@ out: static int find_vmas(struct lazy_pages_info *lpi); -static struct lazy_pages_info *ud_open(int listen, struct sockaddr_un *saddr) +static struct lazy_pages_info *ud_open(int client) { struct lazy_pages_info *lpi; - int client; int ret = -1; - socklen_t len; int uffd_flags; - /* accept new client request */ - len = sizeof(struct sockaddr_un); - if ((client = accept(listen, (struct sockaddr *)saddr, &len)) < 0) { - pr_perror("server_accept error: %d", client); - close(listen); - return NULL; - } - - pr_debug("client fd %d\n", client); - lpi = lpi_init(); if (!lpi) goto out; @@ -313,7 +338,6 @@ static struct lazy_pages_info *ud_open(int listen, struct sockaddr_un *saddr) goto out; } pr_debug("lpi->uffd %d\n", lpi->uffd); - close_safe(&client); pr_debug("uffd is 0x%d\n", lpi->uffd); uffd_flags = fcntl(lpi->uffd, F_GETFD, NULL); @@ -332,7 +356,6 @@ static struct lazy_pages_info *ud_open(int listen, struct sockaddr_un *saddr) out: lpi_fini(lpi); - close_safe(&client); return NULL; } @@ -816,6 +839,8 @@ static int prepare_uffds(int epollfd) { int i; int listen; + int client; + socklen_t len; struct sockaddr_un saddr; if (prepare_sock_addr(&saddr)) @@ -827,20 +852,31 @@ static int prepare_uffds(int epollfd) return -1; } + /* accept new client request */ + len = sizeof(struct sockaddr_un); + if ((client = accept(listen, (struct sockaddr *) &saddr, &len)) < 0) { + pr_perror("server_accept error: %d", client); + close(listen); + return -1; + } + pr_debug("client fd %d\n", client); + for (i = 0; i < task_entries->nr_tasks; i++) { struct lazy_pages_info *lpi; - lpi = ud_open(listen, &saddr); + lpi = ud_open(client); if (!lpi) goto close_uffd; if (epoll_add_fd(epollfd, lpi->uffd)) goto close_uffd; } + close_safe(&client); close(listen); return 0; close_uffd: lpi_hash_fini(); + close_safe(&client); close(listen); return -1; } From b711f89cf4709c3212141849ba96a4dcd2ad622d Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 15 Aug 2016 10:21:51 +0300 Subject: [PATCH 0779/4375] test: allow lazy-pages tests in namespaces Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- test/zdtm.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 4b064bc28..835b7809d 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1716,8 +1716,6 @@ def run_tests(opts): run_flavs -= set(['ns', 'uns']) if opts['empty_ns']: run_flavs -= set(['h']) - if opts['lazy_pages']: - run_flavs -= set(['ns', 'uns']) if run_flavs: l.run_test(t, tdesc, run_flavs) From 9bc9fcb0cebc6c9a6cb6fc4c2711be4a93035652 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 8 Sep 2016 10:39:09 +0300 Subject: [PATCH 0780/4375] criu: pagemap: replace 'zero' and 'lazy' booleans with 'flags' Having three booleans in pagemap entry clues for usage of good old flags. Replace 'zero' and 'lazy' booleans with flags and use flags for internal tracking of in_parent value. Eventually, in_parent may be deprecated. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-dedup.c | 2 +- criu/include/pagemap.h | 21 +++++++++++++++++++++ criu/page-xfer.c | 12 +++++------- criu/pagemap.c | 18 +++++++++++++----- criu/uffd.c | 2 +- images/pagemap.proto | 3 +-- 6 files changed, 42 insertions(+), 16 deletions(-) diff --git a/criu/cr-dedup.c b/criu/cr-dedup.c index d103ddf19..e84303f2c 100644 --- a/criu/cr-dedup.c +++ b/criu/cr-dedup.c @@ -89,7 +89,7 @@ static int cr_dedup_one_pagemap(int id, int flags) pr_debug("dedup iovec base=%"PRIx64", len=%lu\n", pr.pe->vaddr, pagemap_len(pr.pe)); - if (!pr.pe->in_parent) { + if (!pagemap_in_parent(pr.pe)) { ret = dedup_one_iovec(prp, pr.pe->vaddr, pagemap_len(pr.pe)); if (ret) diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index b993c4759..f58a576e7 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -113,4 +113,25 @@ static inline unsigned long pagemap_len(PagemapEntry *pe) { return pe->nr_pages * PAGE_SIZE; } + +/* Pagemap flags */ +#define PE_PARENT (1 << 0) /* pages are in parent snapshot */ +#define PE_ZERO (1 << 1) /* pages can be lazily restored */ +#define PE_LAZY (1 << 2) /* pages are mapped to zero pfn */ + +static inline bool pagemap_in_parent(PagemapEntry *pe) +{ + return !!(pe->flags & PE_PARENT); +} + +static inline bool pagemap_zero(PagemapEntry *pe) +{ + return !!(pe->flags & PE_ZERO); +} + +static inline bool pagemap_lazy(PagemapEntry *pe) +{ + return !!(pe->flags & PE_LAZY); +} + #endif /* __CR_PAGE_READ_H__ */ diff --git a/criu/page-xfer.c b/criu/page-xfer.c index fb3252dc9..7cd2a69eb 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -205,6 +205,7 @@ static int write_pagemap_loc(struct page_xfer *xfer, pe.vaddr = encode_pointer(iov->iov_base); pe.nr_pages = iov->iov_len / PAGE_SIZE; + pe.has_flags = true; if (opts.auto_dedup && xfer->parent != NULL) { ret = dedup_one_iovec(xfer->parent, pe.vaddr, pagemap_len(&pe)); @@ -288,6 +289,7 @@ static int write_hole_loc(struct page_xfer *xfer, struct iovec *iov, int type) pe.vaddr = encode_pointer(iov->iov_base); pe.nr_pages = iov->iov_len / PAGE_SIZE; + pe.has_flags = true; switch (type) { case PS_IOV_HOLE: @@ -301,17 +303,13 @@ static int write_hole_loc(struct page_xfer *xfer, struct iovec *iov, int type) return -1; } } - - pe.has_in_parent = true; - pe.in_parent = true; + pe.flags |= PE_PARENT; break; case PS_IOV_ZERO: - pe.has_zero = true; - pe.zero = true; + pe.flags |= PE_ZERO; break; case PS_IOV_LAZY: - pe.has_lazy = true; - pe.lazy = true; + pe.flags |= PE_LAZY; break; default: return -1; diff --git a/criu/pagemap.c b/criu/pagemap.c index 206fcd376..fa7e1c288 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -96,7 +96,7 @@ int dedup_one_iovec(struct page_read *pr, unsigned long off, unsigned long len) if (!pr->pe) return -1; piov_end = pr->pe->vaddr + pagemap_len(pr->pe); - if (!pr->pe->in_parent) { + if (!pagemap_in_parent(pr->pe)) { ret = punch_hole(pr, pr->pi_off, min(piov_end, iov_end) - off, false); if (ret == -1) return ret; @@ -130,7 +130,7 @@ static int advance(struct page_read *pr) pe = pr->pmes[pr->curr_pme]; - if (!pe->zero) + if (!pagemap_zero(pe)) break; } @@ -144,7 +144,7 @@ static void skip_pagemap_pages(struct page_read *pr, unsigned long len) if (!len) return; - if (!pr->pe->in_parent && !pr->pe->zero && !pr->pe->lazy) + if (!pagemap_in_parent(pr->pe) && !pagemap_zero(pr->pe) && !pagemap_lazy(pr->pe)) pr->pi_off += len; pr->cvaddr += len; } @@ -415,10 +415,10 @@ static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, int nr, pr_info("pr%u Read %lx %u pages\n", pr->id, vaddr, nr); pagemap_bound_check(pr->pe, vaddr, nr); - if (pr->pe->in_parent) { + if (pagemap_in_parent(pr->pe)) { if (read_parent_page(pr, vaddr, nr, buf, flags) < 0) return -1; - } else if (pr->pe->zero) { + } else if (pagemap_zero(pr->pe)) { /* zero mappings should be skipped by get_pagemap */ BUG(); } else { @@ -603,6 +603,12 @@ err_cl: return -1; } +static void init_compat_pagemap_entry(PagemapEntry *pe) +{ + if (pe->has_in_parent && pe->in_parent) + pe->flags |= PE_PARENT; +} + /* * The pagemap entry size is at least 8 bytes for small mappings with * low address and may get to 18 bytes or even more for large mappings @@ -638,6 +644,8 @@ static int init_pagemaps(struct page_read *pr) if (ret == 0) break; + init_compat_pagemap_entry(pr->pmes[pr->nr_pmes]); + pr->nr_pmes++; if (pr->nr_pmes >= nr_pmes) { nr_pmes += nr_realloc; diff --git a/criu/uffd.c b/criu/uffd.c index 292c4c05b..eb44fc916 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -371,7 +371,7 @@ static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest) if (ret <= 0) return ret; - if (lpi->pr.pe->zero) + if (pagemap_zero(lpi->pr.pe)) return 0; ret = lpi->pr.read_pages(&lpi->pr, addr, 1, buf, 0); diff --git a/images/pagemap.proto b/images/pagemap.proto index 8b0092f72..d5b343396 100644 --- a/images/pagemap.proto +++ b/images/pagemap.proto @@ -10,6 +10,5 @@ message pagemap_entry { required uint64 vaddr = 1 [(criu).hex = true]; required uint32 nr_pages = 2; optional bool in_parent = 3; - optional bool zero = 4; - optional bool lazy = 5; + optional uint32 flags = 4 [(criu).hex = true]; } From ea99b7007273ac962a9a9c35adf6e75abeee7caa Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 13 Sep 2016 18:59:00 +0300 Subject: [PATCH 0781/4375] criu: page-xfer: add ability to write pagemap flags With 'zero' and 'lazy' booleans replaced by the flags field in PagemapEntry, it is required that page-xfer will be aware of the change. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/page-xfer.h | 2 +- criu/page-xfer.c | 40 ++++++++++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index 007733eed..bf4900f02 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -12,7 +12,7 @@ extern int cr_page_server(bool daemon_mode, int cfd); struct page_xfer { /* transfers one vaddr:len entry */ - int (*write_pagemap)(struct page_xfer *self, struct iovec *iov); + int (*write_pagemap)(struct page_xfer *self, struct iovec *iov, u32 flags); /* transfers pages related to previous pagemap */ int (*write_pages)(struct page_xfer *self, int pipe, unsigned long len); /* transfers one hole -- vaddr:len entry w/o pages */ diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 7cd2a69eb..c7d1e5a03 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -47,6 +47,9 @@ static void psi2iovec(struct page_server_iov *ps, struct iovec *iov) #define PS_IOV_FLUSH 0x1023 #define PS_IOV_FLUSH_N_CLOSE 0x1024 +#define PS_CMD_BITS 16 +#define PS_CMD_MASK ((1 << PS_CMD_BITS) - 1) + #define PS_TYPE_BITS 8 #define PS_TYPE_MASK ((1 << PS_TYPE_BITS) - 1) @@ -109,6 +112,21 @@ static int decode_pm(u64 dst_id, long *id) return type; } +static inline u32 encode_ps_cmd(u32 cmd, u32 flags) +{ + return flags << PS_CMD_BITS | cmd; +} + +static inline u32 decode_ps_cmd(u32 cmd) +{ + return cmd & PS_CMD_MASK; +} + +static inline u32 decode_ps_flags(u32 cmd) +{ + return cmd >> PS_CMD_BITS; +} + static inline int send_psi(int sk, u32 cmd, u32 nr_pages, u64 vaddr, u64 dst_id) { struct page_server_iov pi = { @@ -135,10 +153,11 @@ static inline int send_iov(int sk, u32 cmd, u64 dst_id, struct iovec *iov) } /* page-server xfer */ -static int write_pagemap_to_server(struct page_xfer *xfer, - struct iovec *iov) +static int write_pagemap_to_server(struct page_xfer *xfer, struct iovec *iov, + u32 flags) { - return send_iov(xfer->sk, PS_IOV_ADD, xfer->dst_id, iov); + return send_iov(xfer->sk, encode_ps_cmd(PS_IOV_ADD, flags), + xfer->dst_id, iov); } static int write_pages_to_server(struct page_xfer *xfer, @@ -197,8 +216,8 @@ static int open_page_server_xfer(struct page_xfer *xfer, int fd_type, long id) } /* local xfer */ -static int write_pagemap_loc(struct page_xfer *xfer, - struct iovec *iov) +static int write_pagemap_loc(struct page_xfer *xfer, struct iovec *iov, + u32 flags) { int ret; PagemapEntry pe = PAGEMAP_ENTRY__INIT; @@ -206,6 +225,7 @@ static int write_pagemap_loc(struct page_xfer *xfer, pe.vaddr = encode_pointer(iov->iov_base); pe.nr_pages = iov->iov_len / PAGE_SIZE; pe.has_flags = true; + pe.flags = flags; if (opts.auto_dedup && xfer->parent != NULL) { ret = dedup_one_iovec(xfer->parent, pe.vaddr, pagemap_len(&pe)); @@ -476,7 +496,7 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, continue; } - if (xfer->write_pagemap(xfer, &iov)) + if (xfer->write_pagemap(xfer, &iov, 0)) return -1; if (xfer->write_pages(xfer, ppb->p[0], iov.iov_len)) return -1; @@ -633,6 +653,7 @@ static int page_server_add(int sk, struct page_server_iov *pi) size_t len; struct page_xfer *lxfer = &cxfer.loc_xfer; struct iovec iov; + u32 flags; pr_debug("Adding %"PRIx64"/%u\n", pi->vaddr, pi->nr_pages); @@ -640,7 +661,8 @@ static int page_server_add(int sk, struct page_server_iov *pi) return -1; psi2iovec(pi, &iov); - if (lxfer->write_pagemap(lxfer, &iov)) + flags = decode_ps_flags(pi->cmd); + if (lxfer->write_pagemap(lxfer, &iov, flags)) return -1; len = iov.iov_len; @@ -770,6 +792,7 @@ static int page_server_serve(int sk) while (1) { struct page_server_iov pi; + u32 cmd; ret = recv(sk, &pi, sizeof(pi), MSG_WAITALL); if (!ret) @@ -782,8 +805,9 @@ static int page_server_serve(int sk) } flushed = false; + cmd = decode_ps_cmd(pi.cmd); - switch (pi.cmd) { + switch (cmd) { case PS_IOV_OPEN: ret = page_server_open(-1, &pi); break; From 96dd5298e51942215f84af9261d05b167ed8b1d8 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 8 Sep 2016 10:39:11 +0300 Subject: [PATCH 0782/4375] criu: pagemap: add PE_PRESENT flag The PE_PRESENT flags is always set for pagemap entries that have corresponding pages in the pages*img. Pagemap entries describing a hole either with zero page or with pages in the parent snapshot will no have PE_PRESENT flag set. Pagemap entry that may be lazily restored is a special case. For the lazy restore from disk case, both PE_LAZY and PE_PRESENT will be set in the pagemap, but for the remote lazy pages case only PE_LAZY will be set. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/pagemap.h | 6 ++++++ criu/page-xfer.c | 16 +++++++++++----- criu/pagemap.c | 10 +++++++++- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index f58a576e7..00479f069 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -118,6 +118,7 @@ static inline unsigned long pagemap_len(PagemapEntry *pe) #define PE_PARENT (1 << 0) /* pages are in parent snapshot */ #define PE_ZERO (1 << 1) /* pages can be lazily restored */ #define PE_LAZY (1 << 2) /* pages are mapped to zero pfn */ +#define PE_PRESENT (1 << 3) /* pages are present in pages*img */ static inline bool pagemap_in_parent(PagemapEntry *pe) { @@ -134,4 +135,9 @@ static inline bool pagemap_lazy(PagemapEntry *pe) return !!(pe->flags & PE_LAZY); } +static inline bool pagemap_present(PagemapEntry *pe) +{ + return !!(pe->flags & PE_PRESENT); +} + #endif /* __CR_PAGE_READ_H__ */ diff --git a/criu/page-xfer.c b/criu/page-xfer.c index c7d1e5a03..90f024931 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -480,6 +480,7 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, for (i = 0; i < ppb->nr_segs; i++) { struct iovec iov = ppb->iov[i]; + u32 flags = PE_PRESENT; ret = dump_holes(xfer, pp, &cur_hole, iov.iov_base, off); if (ret) @@ -490,13 +491,18 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, pr_debug("\tp %p [%u]\n", iov.iov_base, (unsigned int)(iov.iov_len / PAGE_SIZE)); - if (!dump_lazy && ppb->flags & PPB_LAZY) { - if (xfer->write_hole(xfer, &iov, PS_IOV_LAZY)) - return -1; - continue; + if (ppb->flags & PPB_LAZY) { + if (!dump_lazy) { + if (xfer->write_hole(xfer, &iov, + PS_IOV_LAZY)) + return -1; + continue; + } else { + flags |= PE_LAZY; + } } - if (xfer->write_pagemap(xfer, &iov, 0)) + if (xfer->write_pagemap(xfer, &iov, flags)) return -1; if (xfer->write_pages(xfer, ppb->p[0], iov.iov_len)) return -1; diff --git a/criu/pagemap.c b/criu/pagemap.c index fa7e1c288..7b119f774 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -144,7 +144,7 @@ static void skip_pagemap_pages(struct page_read *pr, unsigned long len) if (!len) return; - if (!pagemap_in_parent(pr->pe) && !pagemap_zero(pr->pe) && !pagemap_lazy(pr->pe)) + if (pagemap_present(pr->pe)) pr->pi_off += len; pr->cvaddr += len; } @@ -605,8 +605,16 @@ err_cl: static void init_compat_pagemap_entry(PagemapEntry *pe) { + /* + * pagemap image generated with older version will either + * contain a hole because the pages are in the parent + * shanpshot or a pagemap that should be marked with + * PE_PRESENT + */ if (pe->has_in_parent && pe->in_parent) pe->flags |= PE_PARENT; + else if (!pe->has_flags) + pe->flags = PE_PRESENT; } /* From d7105cce15efa094c378c55a1c2f5f966f217bfe Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 8 Sep 2016 10:39:12 +0300 Subject: [PATCH 0783/4375] criu: mem: skip lazy pages during restore based on pagemap info Instead of checking whether the VMA containing a page can be lazy for each page, skip the entire parts of pagemap that have PE_LAZY flag set. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/mem.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/criu/mem.c b/criu/mem.c index a8521b77f..de3d3c359 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -862,6 +862,17 @@ static int restore_priv_vma_content(struct pstree_item *t, struct page_read *pr) va = (unsigned long)decode_pointer(pr->pe->vaddr); nr_pages = pr->pe->nr_pages; + /* + * This means that userfaultfd is used to load the pages + * on demand. + */ + if (opts.lazy_pages && pagemap_lazy(pr->pe)) { + pr_debug("Lazy restore skips %ld pages at %lx\n", nr_pages, va); + pr->skip_pages(pr, nr_pages * PAGE_SIZE); + nr_lazy += nr_pages; + continue; + } + for (i = 0; i < nr_pages; i++) { unsigned char buf[PAGE_SIZE]; void *p; @@ -921,17 +932,6 @@ static int restore_priv_vma_content(struct pstree_item *t, struct page_read *pr) p = decode_pointer((off) * PAGE_SIZE + vma->premmaped_addr); - /* - * This means that userfaultfd is used to load the pages - * on demand. - */ - if (opts.lazy_pages && vma_entry_can_be_lazy(vma->e)) { - pr_debug("Lazy restore skips %#016"PRIx64"\n", vma->e->start); - pr.skip_pages(&pr, PAGE_SIZE); - nr_lazy++; - continue; - } - set_bit(off, vma->page_bitmap); if (vma_inherited(vma)) { clear_bit(off, vma->pvma->page_bitmap); From 6d2b35ceefd19dbe350580716afe8dbb22034d0b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 19 Sep 2016 14:16:51 +0300 Subject: [PATCH 0784/4375] xfer: Change ->write_hole's type to flags The ->write_hole and ->write_pagemap now look very much alike, so let's merge them. This is preparatory patch that makes holy type decision based on PE_FOO flags. Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/include/page-xfer.h | 2 +- criu/page-xfer.c | 63 ++++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index bf4900f02..e500e6a34 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -16,7 +16,7 @@ struct page_xfer { /* transfers pages related to previous pagemap */ int (*write_pages)(struct page_xfer *self, int pipe, unsigned long len); /* transfers one hole -- vaddr:len entry w/o pages */ - int (*write_hole)(struct page_xfer *self, struct iovec *iov, int type); + int (*write_hole)(struct page_xfer *self, struct iovec *iov, u32 flags); void (*close)(struct page_xfer *self); /* private data for every page-xfer engine */ diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 90f024931..0db1f3aaf 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -173,10 +173,21 @@ static int write_pages_to_server(struct page_xfer *xfer, return 0; } -static int write_hole_to_server(struct page_xfer *xfer, struct iovec *iov, - int type) +static int write_hole_to_server(struct page_xfer *xfer, struct iovec *iov, u32 flags) { - return send_iov(xfer->sk, type, xfer->dst_id, iov); + u32 cmd = 0; + BUG_ON(flags & PE_PRESENT); + + if (flags & PE_PARENT) + cmd = PS_IOV_HOLE; + else if (flags & PE_LAZY) + cmd = PS_IOV_LAZY; + else if (flags & PE_ZERO) + cmd = PS_IOV_ZERO; + else + BUG(); + + return send_iov(xfer->sk, cmd, xfer->dst_id, iov); } static void close_server_xfer(struct page_xfer *xfer) @@ -303,16 +314,18 @@ static int check_pagehole_in_parent(struct page_read *p, struct iovec *iov) } } -static int write_hole_loc(struct page_xfer *xfer, struct iovec *iov, int type) +static int write_hole_loc(struct page_xfer *xfer, struct iovec *iov, u32 flags) { PagemapEntry pe = PAGEMAP_ENTRY__INIT; + BUG_ON(flags & PE_PRESENT); + pe.vaddr = encode_pointer(iov->iov_base); pe.nr_pages = iov->iov_len / PAGE_SIZE; pe.has_flags = true; + pe.flags = flags; - switch (type) { - case PS_IOV_HOLE: + if (flags & PE_PARENT) { if (xfer->parent != NULL) { int ret; @@ -323,16 +336,6 @@ static int write_hole_loc(struct page_xfer *xfer, struct iovec *iov, int type) return -1; } } - pe.flags |= PE_PARENT; - break; - case PS_IOV_ZERO: - pe.flags |= PE_ZERO; - break; - case PS_IOV_LAZY: - pe.flags |= PE_LAZY; - break; - default: - return -1; } if (pb_write_one(xfer->pmi, &pe, PB_PAGEMAP) < 0) @@ -417,27 +420,27 @@ int open_page_xfer(struct page_xfer *xfer, int fd_type, long id) } static int page_xfer_dump_hole(struct page_xfer *xfer, - struct iovec *hole, unsigned long off, int type) + struct iovec *hole, unsigned long off, u32 flags) { BUG_ON(hole->iov_base < (void *)off); hole->iov_base -= off; pr_debug("\th %p [%u]\n", hole->iov_base, (unsigned int)(hole->iov_len / PAGE_SIZE)); - if (xfer->write_hole(xfer, hole, type)) + if (xfer->write_hole(xfer, hole, flags)) return -1; return 0; } -static int get_hole_type(struct page_pipe *pp, int n) +static int get_hole_flags(struct page_pipe *pp, int n) { unsigned int hole_flags = pp->hole_flags[n]; if (hole_flags == PP_HOLE_PARENT) - return PS_IOV_HOLE; + return PE_PARENT; if (hole_flags == PP_HOLE_ZERO) - return PS_IOV_ZERO; + return PE_ZERO; else BUG(); @@ -451,12 +454,13 @@ static int dump_holes(struct page_xfer *xfer, struct page_pipe *pp, for (; *cur_hole < pp->free_hole ; (*cur_hole)++) { struct iovec hole = pp->holes[*cur_hole]; - int hole_type = get_hole_type(pp, *cur_hole); + u32 hole_flags; if (limit && hole.iov_base >= limit) break; - ret = page_xfer_dump_hole(xfer, &hole, off, hole_type); + hole_flags = get_hole_flags(pp, *cur_hole); + ret = page_xfer_dump_hole(xfer, &hole, off, hole_flags); if (ret) return ret; } @@ -493,8 +497,7 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, if (ppb->flags & PPB_LAZY) { if (!dump_lazy) { - if (xfer->write_hole(xfer, &iov, - PS_IOV_LAZY)) + if (xfer->write_hole(xfer, &iov, PE_LAZY)) return -1; continue; } else { @@ -712,7 +715,7 @@ static int page_server_add(int sk, struct page_server_iov *pi) return 0; } -static int page_server_hole(int sk, struct page_server_iov *pi) +static int page_server_hole(int sk, struct page_server_iov *pi, u32 flags) { struct page_xfer *lxfer = &cxfer.loc_xfer; struct iovec iov; @@ -723,7 +726,7 @@ static int page_server_hole(int sk, struct page_server_iov *pi) return -1; psi2iovec(pi, &iov); - if (lxfer->write_hole(lxfer, &iov, pi->cmd)) + if (lxfer->write_hole(lxfer, &iov, flags)) return -1; return 0; @@ -827,9 +830,13 @@ static int page_server_serve(int sk) ret = page_server_add(sk, &pi); break; case PS_IOV_HOLE: + ret = page_server_hole(sk, &pi, PE_PARENT); + break; case PS_IOV_ZERO: + ret = page_server_hole(sk, &pi, PE_ZERO); + break; case PS_IOV_LAZY: - ret = page_server_hole(sk, &pi); + ret = page_server_hole(sk, &pi, PE_LAZY); break; case PS_IOV_FLUSH: case PS_IOV_FLUSH_N_CLOSE: From 4ea4653ce10cbe7fcc0c0262f80e7c9a4305ad36 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 19 Sep 2016 14:17:11 +0300 Subject: [PATCH 0785/4375] xfer: Merge write_hole and _pagemap callbacks They are now the same and PE_PRESENT bit helps us distinguish holes from pagemaps having pages inside. Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/include/page-xfer.h | 2 -- criu/page-xfer.c | 73 ++++++++++++---------------------------- 2 files changed, 22 insertions(+), 53 deletions(-) diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index e500e6a34..fdda10519 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -15,8 +15,6 @@ struct page_xfer { int (*write_pagemap)(struct page_xfer *self, struct iovec *iov, u32 flags); /* transfers pages related to previous pagemap */ int (*write_pages)(struct page_xfer *self, int pipe, unsigned long len); - /* transfers one hole -- vaddr:len entry w/o pages */ - int (*write_hole)(struct page_xfer *self, struct iovec *iov, u32 flags); void (*close)(struct page_xfer *self); /* private data for every page-xfer engine */ diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 0db1f3aaf..9960c6464 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -144,22 +144,7 @@ static inline int send_psi(int sk, u32 cmd, u32 nr_pages, u64 vaddr, u64 dst_id) return 0; } -static inline int send_iov(int sk, u32 cmd, u64 dst_id, struct iovec *iov) -{ - u64 vaddr = encode_pointer(iov->iov_base); - u32 nr_pages = iov->iov_len / PAGE_SIZE; - - return send_psi(sk, cmd, nr_pages, vaddr, dst_id); -} - /* page-server xfer */ -static int write_pagemap_to_server(struct page_xfer *xfer, struct iovec *iov, - u32 flags) -{ - return send_iov(xfer->sk, encode_ps_cmd(PS_IOV_ADD, flags), - xfer->dst_id, iov); -} - static int write_pages_to_server(struct page_xfer *xfer, int p, unsigned long len) { @@ -173,12 +158,13 @@ static int write_pages_to_server(struct page_xfer *xfer, return 0; } -static int write_hole_to_server(struct page_xfer *xfer, struct iovec *iov, u32 flags) +static int write_pagemap_to_server(struct page_xfer *xfer, struct iovec *iov, u32 flags) { u32 cmd = 0; - BUG_ON(flags & PE_PRESENT); - if (flags & PE_PARENT) + if (flags & PE_PRESENT) + cmd = encode_ps_cmd(PS_IOV_ADD, flags); + else if (flags & PE_PARENT) cmd = PS_IOV_HOLE; else if (flags & PE_LAZY) cmd = PS_IOV_LAZY; @@ -187,7 +173,9 @@ static int write_hole_to_server(struct page_xfer *xfer, struct iovec *iov, u32 f else BUG(); - return send_iov(xfer->sk, cmd, xfer->dst_id, iov); + return send_psi(xfer->sk, cmd, + iov->iov_len / PAGE_SIZE, encode_pointer(iov->iov_base), + xfer->dst_id); } static void close_server_xfer(struct page_xfer *xfer) @@ -202,7 +190,6 @@ static int open_page_server_xfer(struct page_xfer *xfer, int fd_type, long id) xfer->sk = page_server_sk; xfer->write_pagemap = write_pagemap_to_server; xfer->write_pages = write_pages_to_server; - xfer->write_hole = write_hole_to_server; xfer->close = close_server_xfer; xfer->dst_id = encode_pm(fd_type, id); xfer->parent = NULL; @@ -227,27 +214,6 @@ static int open_page_server_xfer(struct page_xfer *xfer, int fd_type, long id) } /* local xfer */ -static int write_pagemap_loc(struct page_xfer *xfer, struct iovec *iov, - u32 flags) -{ - int ret; - PagemapEntry pe = PAGEMAP_ENTRY__INIT; - - pe.vaddr = encode_pointer(iov->iov_base); - pe.nr_pages = iov->iov_len / PAGE_SIZE; - pe.has_flags = true; - pe.flags = flags; - if (opts.auto_dedup && xfer->parent != NULL) { - ret = dedup_one_iovec(xfer->parent, pe.vaddr, - pagemap_len(&pe)); - if (ret == -1) { - pr_perror("Auto-deduplication failed"); - return ret; - } - } - return pb_write_one(xfer->pmi, &pe, PB_PAGEMAP); -} - static int write_pages_loc(struct page_xfer *xfer, int p, unsigned long len) { @@ -314,21 +280,27 @@ static int check_pagehole_in_parent(struct page_read *p, struct iovec *iov) } } -static int write_hole_loc(struct page_xfer *xfer, struct iovec *iov, u32 flags) +static int write_pagemap_loc(struct page_xfer *xfer, struct iovec *iov, u32 flags) { + int ret; PagemapEntry pe = PAGEMAP_ENTRY__INIT; - BUG_ON(flags & PE_PRESENT); - pe.vaddr = encode_pointer(iov->iov_base); pe.nr_pages = iov->iov_len / PAGE_SIZE; pe.has_flags = true; pe.flags = flags; - if (flags & PE_PARENT) { + if (flags & PE_PRESENT) { + if (opts.auto_dedup && xfer->parent != NULL) { + ret = dedup_one_iovec(xfer->parent, pe.vaddr, + pagemap_len(&pe)); + if (ret == -1) { + pr_perror("Auto-deduplication failed"); + return ret; + } + } + } else if (flags & PE_PARENT) { if (xfer->parent != NULL) { - int ret; - ret = check_pagehole_in_parent(xfer->parent, iov); if (ret) { pr_err("Hole %p/%zu not found in parent\n", @@ -406,7 +378,6 @@ static int open_page_local_xfer(struct page_xfer *xfer, int fd_type, long id) out: xfer->write_pagemap = write_pagemap_loc; xfer->write_pages = write_pages_loc; - xfer->write_hole = write_hole_loc; xfer->close = close_page_xfer; return 0; } @@ -427,7 +398,7 @@ static int page_xfer_dump_hole(struct page_xfer *xfer, pr_debug("\th %p [%u]\n", hole->iov_base, (unsigned int)(hole->iov_len / PAGE_SIZE)); - if (xfer->write_hole(xfer, hole, flags)) + if (xfer->write_pagemap(xfer, hole, flags)) return -1; return 0; @@ -497,7 +468,7 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, if (ppb->flags & PPB_LAZY) { if (!dump_lazy) { - if (xfer->write_hole(xfer, &iov, PE_LAZY)) + if (xfer->write_pagemap(xfer, &iov, PE_LAZY)) return -1; continue; } else { @@ -726,7 +697,7 @@ static int page_server_hole(int sk, struct page_server_iov *pi, u32 flags) return -1; psi2iovec(pi, &iov); - if (lxfer->write_hole(lxfer, &iov, flags)) + if (lxfer->write_pagemap(lxfer, &iov, flags)) return -1; return 0; From 8505a8ccfd96e1f95fc300c46bd4c09c5af44361 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 19 Sep 2016 14:17:28 +0300 Subject: [PATCH 0786/4375] pageserver: Merge page_server_add with page_server_hole Do the same here, the flags is now enough to tell hole from pagemap. Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/page-xfer.c | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 9960c6464..aedb142b9 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -628,12 +628,11 @@ static int prep_loc_xfer(struct page_server_iov *pi) return 0; } -static int page_server_add(int sk, struct page_server_iov *pi) +static int page_server_add(int sk, struct page_server_iov *pi, u32 flags) { size_t len; struct page_xfer *lxfer = &cxfer.loc_xfer; struct iovec iov; - u32 flags; pr_debug("Adding %"PRIx64"/%u\n", pi->vaddr, pi->nr_pages); @@ -641,10 +640,12 @@ static int page_server_add(int sk, struct page_server_iov *pi) return -1; psi2iovec(pi, &iov); - flags = decode_ps_flags(pi->cmd); if (lxfer->write_pagemap(lxfer, &iov, flags)) return -1; + if (!(flags & PE_PRESENT)) + return 0; + len = iov.iov_len; while (len > 0) { ssize_t chunk; @@ -686,23 +687,6 @@ static int page_server_add(int sk, struct page_server_iov *pi) return 0; } -static int page_server_hole(int sk, struct page_server_iov *pi, u32 flags) -{ - struct page_xfer *lxfer = &cxfer.loc_xfer; - struct iovec iov; - - pr_debug("Adding %"PRIx64"/%u hole\n", pi->vaddr, pi->nr_pages); - - if (prep_loc_xfer(pi)) - return -1; - - psi2iovec(pi, &iov); - if (lxfer->write_pagemap(lxfer, &iov, flags)) - return -1; - - return 0; -} - static int page_server_get_pages(int sk, struct page_server_iov *pi) { struct pstree_item *item; @@ -798,16 +782,16 @@ static int page_server_serve(int sk) ret = page_server_check_parent(sk, &pi); break; case PS_IOV_ADD: - ret = page_server_add(sk, &pi); + ret = page_server_add(sk, &pi, PE_PRESENT | decode_ps_flags(pi.cmd)); break; case PS_IOV_HOLE: - ret = page_server_hole(sk, &pi, PE_PARENT); + ret = page_server_add(sk, &pi, PE_PARENT); break; case PS_IOV_ZERO: - ret = page_server_hole(sk, &pi, PE_ZERO); + ret = page_server_add(sk, &pi, PE_ZERO); break; case PS_IOV_LAZY: - ret = page_server_hole(sk, &pi, PE_LAZY); + ret = page_server_add(sk, &pi, PE_LAZY); break; case PS_IOV_FLUSH: case PS_IOV_FLUSH_N_CLOSE: From 2ce576e646b4965479b9b849c0aa9f57b079dbf1 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 22 Sep 2016 10:38:00 +0300 Subject: [PATCH 0787/4375] crit: translate pagemap flags into strings This translates pagemap flags into strings for easier readability. Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- images/pagemap.proto | 2 +- lib/py/images/pb2dict.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/images/pagemap.proto b/images/pagemap.proto index d5b343396..42ed5ebb9 100644 --- a/images/pagemap.proto +++ b/images/pagemap.proto @@ -10,5 +10,5 @@ message pagemap_entry { required uint64 vaddr = 1 [(criu).hex = true]; required uint32 nr_pages = 2; optional bool in_parent = 3; - optional uint32 flags = 4 [(criu).hex = true]; + optional uint32 flags = 4 [(criu).flags = "pmap.flags" ]; } diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index 4e89e8e04..f2d26fb26 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -105,11 +105,19 @@ rfile_flags_map = [ ('O_LARGEFILE', 0100000), ]; +pmap_flags_map = [ + ('PE_PARENT', 1 << 0), + ('PE_ZERO', 1 << 1), + ('PE_LAZY', 1 << 2), + ('PE_PRESENT', 1 << 3), +]; + flags_maps = { 'mmap.prot' : mmap_prot_map, 'mmap.flags' : mmap_flags_map, 'mmap.status' : mmap_status_map, 'rfile.flags' : rfile_flags_map, + 'pmap.flags' : pmap_flags_map, } gen_maps = { From 976cb5f841030a55be6f43676e21194f469ff952 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 6 Oct 2016 13:08:00 +0300 Subject: [PATCH 0788/4375] criu: mem: count all pages actually written to image as "pages_written" Currently potentially lazy pages are not counted as written even if they are dump into pages*img. Count these pages as "pages_written" when dump is not going to skip writing lazy pages to disk. travis-ci: success for criu: mem: count all pages actually written to image as "pages_written" Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/mem.c b/criu/mem.c index de3d3c359..cb880cf81 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -175,7 +175,7 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u pages[1]++; } else { ret = page_pipe_add_page(pp, vaddr, ppb_flags); - if (ppb_flags & PPB_LAZY) + if (ppb_flags & PPB_LAZY && opts.lazy_pages) pages[2]++; else pages[3]++; From c1f0b1f5a210ac71225b98d9f2c03aa2aec35043 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 22 Sep 2016 10:45:00 +0300 Subject: [PATCH 0789/4375] page-pipe: correctly split page-pipe-buffers Combining pre-copy (pre-dump) and post-copy (lazy-pages) mode showed a problem in the function page_pipe_split_ppb(). The function is used to split the page-pipe-buffer so that it only contains the IOVs request from the restore side during lazy restore. Unfortunately it only splits the leading IOVs out of the page-pipe-buffer and not the trailing: Before split for requested address 0x7f27284d1000: page-pipe: ppb->iov 0x7f0f74d93040 page-pipe: 0x7f27282bb000 1 page-pipe: 0x7f27284d1000 1 page-pipe: 0x7f27284dd000 2 After split: page-pipe: ppb->iov 0x7f0f74d93050 page-pipe: 0x7f27284d1000 1 page-pipe: 0x7f27284dd000 2 and: page-pipe: ppb->iov 0x7f0f74d93040 page-pipe: 0x7f27282bb000 1 This patch keeps on splitting the page-pipe-buffer until it contains only the requested address with the requested length. After split (still trying to load 0x7f27284d1000): page-pipe: ppb->iov 0x7f0f74d93050 page-pipe: 0x7f27284d1000 1 and: page-pipe: ppb->iov 0x7f0f74d93040 page-pipe: 0x7f27282bb000 1 and: page-pipe: ppb->iov 0x7f0f74d93060 page-pipe: 0x7f27284dd000 2 v2: - moved declarations to the declaration block Signed-off-by: Adrian Reber Acked-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/page-pipe.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/criu/page-pipe.c b/criu/page-pipe.c index 8ea6f33fe..eae1cbbff 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -374,6 +374,8 @@ static int page_pipe_split_iov(struct page_pipe *pp, struct page_pipe_buf *ppb, static int page_pipe_split_ppb(struct page_pipe *pp, struct page_pipe_buf *ppb, struct iovec *iov, unsigned long len) { + struct page_pipe_buf *ppb_tmp; + struct iovec *iov_tmp = iov; struct page_pipe_buf *ppb_new; int ret; @@ -393,6 +395,34 @@ static int page_pipe_split_ppb(struct page_pipe *pp, struct page_pipe_buf *ppb, list_move(&ppb->l, &pp->bufs); + /* + * Only the leading iov's are split from the page_pipe_buffer. + * The complete page_pipe_buffer at the start of the page_pipe + * list will be deleted and therefore it is necessary to also + * move unrelated iov's to their own page_pipe_buffers. + */ + + if (ppb->nr_segs <= len / PAGE_SIZE) + return 0; + + /* Move to the iov after the current request */ + iov += len / PAGE_SIZE; + ret = page_pipe_split_ppb(pp, ppb, iov, len); + if (ret) + return -1; + + /* + * Rotate until correct head pointer. The function transmitting + * the page data expects that the head points to the right + * page_pipe_buffer. The complete first page_pipe_buffer is + * deleted even it contains additional elements. + */ + ppb_tmp = list_first_entry(&pp->bufs, struct page_pipe_buf, l); + while (ppb_tmp->iov != iov_tmp) { + list_rotate_left(&pp->bufs); + ppb_tmp = list_first_entry(&pp->bufs, struct page_pipe_buf, l); + } + return 0; } From e3fb9bd9c40c6115cd62e529d2220040389ecb02 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 22 Sep 2016 10:45:00 +0300 Subject: [PATCH 0790/4375] lazy-pages: add support to combine pre-copy and post-copy Only the UFFD daemon is aware if pages are in the parent or not. The restore will continue to work as any lazy-restore except that pages from parent checkpoints will be pre-populated by the restorer. The restorer will still register the whole memory region as being handled by userfaultfd even if it contains pages from parent checkpoints. Userfaultfd page faults will only happen on pages which contain no data. This means from the parent pre-populated pages will not trigger a userfaultfd message even if marked as being handled by userfaultfd. The UFFD daemon knows about pages which are available in the parent checkpoints and will not push those pages unnecessarily to userfaultfd. Following steps to migrate a process are now possible: Source system: * criu pre-dump -D /tmp/cp/1 -t * rsync -a /tmp/cp :/tmp * criu dump -D /tmp/cp/2 -t --port 27 --lazy-pages \ --prev-images-dir ../1/ --track-mem Destination system: * rsync -a :/tmp/cp /tmp/ * criu lazy-pages --page-server --address --port 27 \ -D /tmp/cp/2 & * criu restore --lazy-pages -D /tmp/cp/2 This will now restore all pages from the parent checkpoint if they are not marked as lazy in the second checkpoint. v2: - changed parent detection to use pagemap_in_parent() v3: - unfortunately this reverts c11cf95afbe023a2816a3afaecb65cc4fee670d7 "criu: mem: skip lazy pages during restore based on pagemap info" To be able to split the VMA-s in the right chunks for the restorer it is necessary to make the decision lazy or not on the VmaEntry level. v4: - everything has changed thanks to Mike Rapoport's suggestion - the VMA-s are no longer touched or split - instead of over 100 lines of changes this is now two line patch Signed-off-by: Adrian Reber Acked-by: Mike Rapoprot Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index eb44fc916..a839088bf 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -507,7 +507,8 @@ static int collect_uffd_pages(struct page_read *pr, struct lazy_pages_info *lpi) */ if (base >= vma->e->start && base < vma->e->end) { if (vma_entry_can_be_lazy(vma->e)) { - uffd_page = true; + if(!pagemap_in_parent(pr->pe)) + uffd_page = true; break; } } From 7d88ee579967fd5ac1edd1df5d1e4a149ef9ad58 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 10 Oct 2016 18:26:00 +0300 Subject: [PATCH 0791/4375] Added option to display dump/restore lazy and zero pages stats # criu dump --display-stats -D /tmp/cp -t Displaying dump stats: ... Zero memory pages: 0 (0x0) Lazy memory pages: 0 (0x0) travis-ci: success for Added option to display dump/restore stats (rev2) Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/stats.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/criu/stats.c b/criu/stats.c index 3fef9c472..7f0e154a1 100644 --- a/criu/stats.c +++ b/criu/stats.c @@ -120,6 +120,10 @@ static void display_stats(int what, StatsEntry *stats) stats->dump->pages_skipped_parent); pr_msg("Memory pages written: %" PRIu64 " (0x%" PRIx64 ")\n", stats->dump->pages_written, stats->dump->pages_written); + pr_msg("Zero memory pages: %" PRIu64 " (0x%" PRIx64 ")\n", stats->dump->pages_zero, + stats->dump->pages_zero); + pr_msg("Lazy memory pages: %" PRIu64 " (0x%" PRIx64 ")\n", stats->dump->pages_lazy, + stats->dump->pages_lazy); } else if (what == RESTORE_STATS) { pr_msg("Displaying restore stats:\n"); pr_msg("Pages compared: %" PRIu64 " (0x%" PRIx64 ")\n", stats->restore->pages_compared, From a29f84a4ab4da69627dfdcf5a606e054632f346f Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 16 Oct 2016 11:08:00 +0300 Subject: [PATCH 0792/4375] jenkins: fix criu-lazy-pages.sh permissions Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- test/jenkins/criu-lazy-pages.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test/jenkins/criu-lazy-pages.sh diff --git a/test/jenkins/criu-lazy-pages.sh b/test/jenkins/criu-lazy-pages.sh old mode 100644 new mode 100755 From 14dbe3a7a890692f50eb85a629354b8a1d290032 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 3 Nov 2016 02:01:00 +0300 Subject: [PATCH 0793/4375] lazy-pages: do not treat VMAs that have MAP_LOCKED as lazy When a VMA is mapped with MAP_LOCKED it is address space is populated with pages which causes UFFDIO_COPY to return -EXISTS. Until we can find some better solution let's avoid marking VMAs with MAP_LOCKED as lazy. Fixes: #238 travis-ci: success for lazy-pages: misc fixes (rev3) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/vma.h | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/include/vma.h b/criu/include/vma.h index 204f2d00b..779466c21 100644 --- a/criu/include/vma.h +++ b/criu/include/vma.h @@ -129,6 +129,7 @@ static inline bool vma_entry_can_be_lazy(VmaEntry *e) { return ((e->flags & MAP_ANONYMOUS) && (e->flags & MAP_PRIVATE) && + !(e->flags & MAP_LOCKED) && !(vma_entry_is(e, VMA_AREA_VDSO)) && !(vma_entry_is(e, VMA_AREA_VSYSCALL))); } From ec71c1daa4606463626f3884ef725526efbdc0ad Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Fri, 4 Nov 2016 09:08:02 -0600 Subject: [PATCH 0794/4375] lazy-pages: make ud_open return int To properly handle zombie processes we will need to distinguish failures coming from socket communications from absent userfault file descriptor travis-ci: success for lazy-pages: misc fixes (rev4) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index a839088bf..5e36b66c6 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -313,7 +313,7 @@ out: static int find_vmas(struct lazy_pages_info *lpi); -static struct lazy_pages_info *ud_open(int client) +static int ud_open(int client, struct lazy_pages_info **_lpi) { struct lazy_pages_info *lpi; int ret = -1; @@ -351,12 +351,13 @@ static struct lazy_pages_info *ud_open(int client) goto out; hlist_add_head(&lpi->hash, &lpi_hash[lpi->uffd % LPI_HASH_SIZE]); + *_lpi = lpi; - return lpi; + return 0; out: lpi_fini(lpi); - return NULL; + return -1; } static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest) @@ -863,9 +864,8 @@ static int prepare_uffds(int epollfd) pr_debug("client fd %d\n", client); for (i = 0; i < task_entries->nr_tasks; i++) { - struct lazy_pages_info *lpi; - lpi = ud_open(client); - if (!lpi) + struct lazy_pages_info *lpi = NULL; + if (ud_open(client, &lpi)) goto close_uffd; if (epoll_add_fd(epollfd, lpi->uffd)) goto close_uffd; From 1a92e78911000b7e4d739d01d5ae7d9f3ff88c79 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Fri, 4 Nov 2016 09:08:03 -0600 Subject: [PATCH 0795/4375] lazy-pages: send_uffd: make sure mutex is unlocked on error paths travis-ci: success for lazy-pages: misc fixes (rev4) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 5e36b66c6..a8a108146 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -174,10 +174,9 @@ static int send_uffd(int sendfd, int pid) goto out; } - mutex_unlock(lazy_sock_mutex); - ret = 0; out: + mutex_unlock(lazy_sock_mutex); close(fd); return ret; } From 428226a8ac7959bff7130ce1f39d7dd2c769c5f7 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Fri, 4 Nov 2016 09:08:04 -0600 Subject: [PATCH 0796/4375] lazy-pages: handle zombie processes Restore of a zombie process does not call setup_uffd which causes lazy-pages daemon to stuck forever waiting for (pid, uffd) pair to arrive. Let's extend the protocol between restore and lazy-pages so that for zombie process a (0, -1) pair will be sent instead of actual (uffd, pid). travis-ci: success for lazy-pages: misc fixes (rev4) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-restore.c | 3 +++ criu/include/uffd.h | 1 + criu/uffd.c | 24 ++++++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 176383111..10413f5a9 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -942,6 +942,9 @@ static int restore_one_zombie(CoreEntry *core) if (inherit_fd_fini() < 0) return -1; + if (lazy_pages_setup_zombie()) + return -1; + prctl(PR_SET_NAME, (long)(void *)core->tc->comm, 0, 0, 0); if (task_entries != NULL) { diff --git a/criu/include/uffd.h b/criu/include/uffd.h index d8cf0d050..8adf2f0f7 100644 --- a/criu/include/uffd.h +++ b/criu/include/uffd.h @@ -3,6 +3,7 @@ struct task_restore_args; extern int setup_uffd(int pid, struct task_restore_args *task_args); +extern int lazy_pages_setup_zombie(void); extern int prepare_lazy_pages_socket(void); #endif /* __CR_UFFD_H_ */ diff --git a/criu/uffd.c b/criu/uffd.c index a8a108146..d5e706299 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -169,6 +169,12 @@ static int send_uffd(int sendfd, int pid) goto out; } + /* for a zombie process pid will be -1 */ + if (pid == -1) { + ret = 0; + goto out; + } + if (send_fd(fd, NULL, 0, sendfd) < 0) { pr_perror("send_fd error:"); goto out; @@ -202,6 +208,17 @@ static int check_for_uffd() return 0; } +int lazy_pages_setup_zombie(void) +{ + if (!opts.lazy_pages) + return 0; + + if (send_uffd(0, -1)) + return -1; + + return 0; +} + /* This function is used by 'criu restore --lazy-pages' */ int setup_uffd(int pid, struct task_restore_args *task_args) { @@ -331,6 +348,11 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) } pr_debug("received PID: %d\n", lpi->pid); + if (lpi->pid == -1) { + lpi_fini(lpi); + return 0; + } + lpi->uffd = recv_fd(client); if (lpi->uffd < 0) { pr_perror("recv_fd error:"); @@ -866,6 +888,8 @@ static int prepare_uffds(int epollfd) struct lazy_pages_info *lpi = NULL; if (ud_open(client, &lpi)) goto close_uffd; + if (lpi == NULL) + continue; if (epoll_add_fd(epollfd, lpi->uffd)) goto close_uffd; } From 145c5094957447e9795b678b0ec469522ab41c8b Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Fri, 4 Nov 2016 23:02:00 +0300 Subject: [PATCH 0797/4375] lazy-pages: use relative path for UNIX socket Use relative path for UNIX socket instead of absolute one. This ensures we won't run into problems with invalid socket names. travis-ci: success for lazy-pages: use relative path for UNIX socket Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index d5e706299..3e09df55a 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -123,22 +123,15 @@ static void lpi_hash_fini(void) static int prepare_sock_addr(struct sockaddr_un *saddr) { - char cwd[PATH_MAX]; int len; - if (!getcwd(cwd, PATH_MAX)) { - pr_perror("Cannot get CWD\n"); - return -1; - } - memset(saddr, 0, sizeof(struct sockaddr_un)); saddr->sun_family = AF_UNIX; len = snprintf(saddr->sun_path, sizeof(saddr->sun_path), - "%s/%s", cwd, LAZY_PAGES_SOCK_NAME); + "%s", LAZY_PAGES_SOCK_NAME); if (len >= sizeof(saddr->sun_path)) { - pr_err("Wrong UNIX socket name: %s/%s\n", - cwd, LAZY_PAGES_SOCK_NAME); + pr_err("Wrong UNIX socket name: %s\n", LAZY_PAGES_SOCK_NAME); return -1; } From 82c8229100cd0b50cf01b651521d1897535ca806 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Mon, 7 Nov 2016 13:37:52 -0800 Subject: [PATCH 0798/4375] uffd.c: error logging nitpicks In cases errno is being set, we need to use pr_perror() to print it. In cases errno is not set, we should use pr_err(). pr_perror() doesn't need a colon or a newline. pr_err() needs a newline. Cc: Adrian Reber Cc: Mike Rapoport travis-ci: success for Assorted nitpicks Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 3e09df55a..dd9843d56 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -158,7 +158,7 @@ static int send_uffd(int sendfd, int pid) * the FD for UFFD */ pr_debug("Sending PID %d\n", pid); if (send(fd, &pid, sizeof(pid), 0) < 0) { - pr_perror("PID sending error:"); + pr_perror("PID sending error"); goto out; } @@ -169,7 +169,7 @@ static int send_uffd(int sendfd, int pid) } if (send_fd(fd, NULL, 0, sendfd) < 0) { - pr_perror("send_fd error:"); + pr_err("send_fd error\n"); goto out; } @@ -336,7 +336,10 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) * the FD for UFFD */ ret = recv(client, &lpi->pid, sizeof(lpi->pid), 0); if (ret != sizeof(lpi->pid)) { - pr_perror("PID recv error:"); + if (ret < 0) + pr_perror("PID recv error"); + else + pr_err("PID recv: short read\n"); goto out; } pr_debug("received PID: %d\n", lpi->pid); @@ -348,7 +351,7 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) lpi->uffd = recv_fd(client); if (lpi->uffd < 0) { - pr_perror("recv_fd error:"); + pr_err("recv_fd error\n"); goto out; } pr_debug("lpi->uffd %d\n", lpi->uffd); @@ -690,7 +693,10 @@ static int handle_user_fault(struct lazy_pages_info *lpi, void *dest) return 1; if (ret != sizeof(msg)) { - pr_perror("Can't read userfaultfd message"); + if (ret < 0) + pr_perror("Can't read userfaultfd message"); + else + pr_err("Can't read userfaultfd message: short read"); return -1; } @@ -871,7 +877,7 @@ static int prepare_uffds(int epollfd) /* accept new client request */ len = sizeof(struct sockaddr_un); if ((client = accept(listen, (struct sockaddr *) &saddr, &len)) < 0) { - pr_perror("server_accept error: %d", client); + pr_perror("server_accept error"); close(listen); return -1; } From 345b4e77efdf4a39907538fbfcd9aa5a0dda908b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 12 Nov 2016 08:23:00 +0300 Subject: [PATCH 0799/4375] uffdd: Read pages directly into destination buffer This avoids excessive memcpy() one instruction below. travis-ci: success for uffd: A set of improvements over criu/uffd.c Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/uffd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index dd9843d56..765d40d8d 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -380,7 +380,6 @@ out: static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest) { int ret; - unsigned char buf[PAGE_SIZE]; lpi->pr.reset(&lpi->pr); @@ -392,13 +391,11 @@ static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest) if (pagemap_zero(lpi->pr.pe)) return 0; - ret = lpi->pr.read_pages(&lpi->pr, addr, 1, buf, 0); + ret = lpi->pr.read_pages(&lpi->pr, addr, 1, dest, 0); pr_debug("read_pages ret %d\n", ret); if (ret <= 0) return ret; - memcpy(dest, buf, PAGE_SIZE); - return 1; } From 6f4c60c611f6fa7a731b03c9c1df7ce56d31d4d3 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 12 Nov 2016 08:24:00 +0300 Subject: [PATCH 0800/4375] uffd: Keep lpi pointer on epoll_event, not fd This helps us get lpi MUCH faster on #PF. travis-ci: success for uffd: A set of improvements over criu/uffd.c Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/uffd.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 765d40d8d..580409887 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -97,19 +97,6 @@ static void lpi_hash_init(void) INIT_HLIST_HEAD(&lpi_hash[i]); } -struct lazy_pages_info *uffd_to_lpi(int uffd) -{ - struct lazy_pages_info *lpi; - struct hlist_head *head; - - head = &lpi_hash[uffd % LPI_HASH_SIZE]; - hlist_for_each_entry(lpi, head, hash) - if (lpi->uffd == uffd) - return lpi; - - return NULL; -} - static void lpi_hash_fini(void) { struct lazy_pages_info *p; @@ -775,8 +762,8 @@ static int handle_requests(int epollfd, struct epoll_event *events) for (i = 0; i < ret; i++) { int err; - lpi = uffd_to_lpi(events[i].data.fd); - BUG_ON(!lpi); + + lpi = (struct lazy_pages_info *)events[i].data.ptr; err = handle_user_fault(lpi, dest); if (err < 0) goto out; @@ -840,13 +827,13 @@ free_events: return -1; } -static int epoll_add_fd(int epollfd, int fd) +static int epoll_add_lpi(int epollfd, struct lazy_pages_info *lpi) { struct epoll_event ev; ev.events = EPOLLIN; - ev.data.fd = fd; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) { + ev.data.ptr = lpi; + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, lpi->uffd, &ev) == -1) { pr_perror("epoll_ctl failed"); return -1; } @@ -886,7 +873,7 @@ static int prepare_uffds(int epollfd) goto close_uffd; if (lpi == NULL) continue; - if (epoll_add_fd(epollfd, lpi->uffd)) + if (epoll_add_lpi(epollfd, lpi)) goto close_uffd; } From 51e6e19d117bb54c0e15e817e4f898eeb9220d82 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 12 Nov 2016 08:25:00 +0300 Subject: [PATCH 0801/4375] uffd: Turn lpi_hash into list After previous patch we no longer need this hash since we don't need fd -> lpi conversion. travis-ci: success for uffd: A set of improvements over criu/uffd.c Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/uffd.c | 51 ++++++++++++--------------------------------------- 1 file changed, 12 insertions(+), 39 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 580409887..e335bd811 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -57,11 +57,10 @@ struct lazy_pages_info { unsigned long total_pages; unsigned long copied_pages; - struct hlist_node hash; + struct list_head l; }; -#define LPI_HASH_SIZE 16 -static struct hlist_head lpi_hash[LPI_HASH_SIZE]; +static LIST_HEAD(lpis); static struct lazy_pages_info *lpi_init(void) { @@ -73,7 +72,7 @@ static struct lazy_pages_info *lpi_init(void) memset(lpi, 0, sizeof(*lpi)); INIT_LIST_HEAD(&lpi->pages); - INIT_HLIST_NODE(&lpi->hash); + INIT_LIST_HEAD(&lpi->l); return lpi; } @@ -89,25 +88,6 @@ static void lpi_fini(struct lazy_pages_info *lpi) free(lpi); } -static void lpi_hash_init(void) -{ - int i; - - for (i = 0; i < LPI_HASH_SIZE; i++) - INIT_HLIST_HEAD(&lpi_hash[i]); -} - -static void lpi_hash_fini(void) -{ - struct lazy_pages_info *p; - struct hlist_node *n; - int i; - - for (i = 0; i < LPI_HASH_SIZE; i++) - hlist_for_each_entry_safe(p, n, &lpi_hash[i], hash) - lpi_fini(p); -} - static int prepare_sock_addr(struct sockaddr_un *saddr) { int len; @@ -354,7 +334,7 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) if ((lpi->total_pages = find_vmas(lpi)) == -1) goto out; - hlist_add_head(&lpi->hash, &lpi_hash[lpi->uffd % LPI_HASH_SIZE]); + list_add_tail(&lpi->l, &lpis); *_lpi = lpi; return 0; @@ -770,20 +750,17 @@ static int handle_requests(int epollfd, struct epoll_event *events) } } pr_debug("Handle remaining pages\n"); - for (i = 0; i < LPI_HASH_SIZE; i++) { - hlist_for_each_entry(lpi, &lpi_hash[i], hash) { - ret = handle_remaining_pages(lpi, dest); - if (ret < 0) { - pr_err("Error during remaining page copy\n"); - ret = 1; - goto out; - } + list_for_each_entry(lpi, &lpis, l) { + ret = handle_remaining_pages(lpi, dest); + if (ret < 0) { + pr_err("Error during remaining page copy\n"); + ret = 1; + goto out; } } - for (i = 0; i < LPI_HASH_SIZE; i++) - hlist_for_each_entry(lpi, &lpi_hash[i], hash) - ret += lazy_pages_summary(lpi); + list_for_each_entry(lpi, &lpis, l) + ret += lazy_pages_summary(lpi); out: free(dest); @@ -882,7 +859,6 @@ static int prepare_uffds(int epollfd) return 0; close_uffd: - lpi_hash_fini(); close_safe(&client); close(listen); return -1; @@ -897,8 +873,6 @@ int cr_lazy_pages() if (check_for_uffd()) return -1; - lpi_hash_init(); - if (lazy_pages_prepare_pstree()) return -1; @@ -913,7 +887,6 @@ int cr_lazy_pages() return -1; ret = handle_requests(epollfd, events); - lpi_hash_fini(); return ret; } From 6d405370da6cf3702913a37892faece5aefc654f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 12 Nov 2016 08:25:00 +0300 Subject: [PATCH 0802/4375] uffd: Check for uffd event being PF early The event received should be checked to be #PF before accessing its other arguments. [ Mike: Well, looking forward to see non-cooperative userfaultfd patches in kernel we should have something like static int handle_uffd_enent(struct lazy_pages_info *lpi) { read(&msg...); switch (msg.event) { case UFFD_EVENT_PAGEFAULT: handle_pagefault(lpi, msg); break; default: return -1; } } But since this patch is anyway is a bugfix: ] travis-ci: success for uffd: A set of improvements over criu/uffd.c Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/uffd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index e335bd811..838eaa85c 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -664,6 +664,11 @@ static int handle_user_fault(struct lazy_pages_info *lpi, void *dest) return -1; } + if (msg.event != UFFD_EVENT_PAGEFAULT) { + pr_err("unexpected msg event %u\n", msg.event); + return -1; + } + /* Align requested address to the next page boundary */ address = msg.arg.pagefault.address & ~(page_size() - 1); pr_debug("msg.arg.pagefault.address 0x%llx\n", address); @@ -677,11 +682,6 @@ static int handle_user_fault(struct lazy_pages_info *lpi, void *dest) flags = msg.arg.pagefault.flags; pr_debug("msg.arg.pagefault.flags 0x%llx\n", flags); - if (msg.event != UFFD_EVENT_PAGEFAULT) { - pr_err("unexpected msg event %u\n", msg.event); - return -1; - } - ret = handle_regular_pages(lpi, dest, address); if (ret < 0) { pr_err("Error during regular page copy\n"); From c00dd3459f75f1d6f9b0fd75ed51e033aa14ddc9 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 13 Nov 2016 11:52:35 +0200 Subject: [PATCH 0803/4375] criu: lazy-pages: move find_vmas and related code around Moving the find_vmas and collect_uffd_pages functions before they are actually used. This allows to drop forward declaration of find_vmas and will make subsequent refactoring cleaner. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 400 ++++++++++++++++++++++++++-------------------------- 1 file changed, 199 insertions(+), 201 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 838eaa85c..41192a6cc 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -287,85 +287,6 @@ out: return -1; } -static int find_vmas(struct lazy_pages_info *lpi); - -static int ud_open(int client, struct lazy_pages_info **_lpi) -{ - struct lazy_pages_info *lpi; - int ret = -1; - int uffd_flags; - - lpi = lpi_init(); - if (!lpi) - goto out; - - /* The "transfer protocol" is first the pid as int and then - * the FD for UFFD */ - ret = recv(client, &lpi->pid, sizeof(lpi->pid), 0); - if (ret != sizeof(lpi->pid)) { - if (ret < 0) - pr_perror("PID recv error"); - else - pr_err("PID recv: short read\n"); - goto out; - } - pr_debug("received PID: %d\n", lpi->pid); - - if (lpi->pid == -1) { - lpi_fini(lpi); - return 0; - } - - lpi->uffd = recv_fd(client); - if (lpi->uffd < 0) { - pr_err("recv_fd error\n"); - goto out; - } - pr_debug("lpi->uffd %d\n", lpi->uffd); - - pr_debug("uffd is 0x%d\n", lpi->uffd); - uffd_flags = fcntl(lpi->uffd, F_GETFD, NULL); - pr_debug("uffd_flags are 0x%x\n", uffd_flags); - - /* - * Find the memory pages belonging to the restored process - * so that it is trackable when all pages have been transferred. - */ - if ((lpi->total_pages = find_vmas(lpi)) == -1) - goto out; - - list_add_tail(&lpi->l, &lpis); - *_lpi = lpi; - - return 0; - -out: - lpi_fini(lpi); - return -1; -} - -static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest) -{ - int ret; - - lpi->pr.reset(&lpi->pr); - - ret = lpi->pr.seek_page(&lpi->pr, addr); - pr_debug("seek_pagemap_page ret 0x%x\n", ret); - if (ret <= 0) - return ret; - - if (pagemap_zero(lpi->pr.pe)) - return 0; - - ret = lpi->pr.read_pages(&lpi->pr, addr, 1, dest, 0); - pr_debug("read_pages ret %d\n", ret); - if (ret <= 0) - return ret; - - return 1; -} - #define UFFD_FLAG_SENT 0x1 struct uffd_pages_struct { @@ -374,80 +295,6 @@ struct uffd_pages_struct { int flags; }; -static int uffd_copy_page(struct lazy_pages_info *lpi, __u64 address, - void *dest) -{ - struct uffdio_copy uffdio_copy; - int rc; - - if (opts.use_page_server) - rc = get_remote_pages(lpi->pid, address, 1, dest); - else - rc = get_page(lpi, address, dest); - if (rc <= 0) - return rc; - - uffdio_copy.dst = address; - uffdio_copy.src = (unsigned long) dest; - uffdio_copy.len = page_size(); - uffdio_copy.mode = 0; - uffdio_copy.copy = 0; - - pr_debug("uffdio_copy.dst 0x%llx\n", uffdio_copy.dst); - rc = ioctl(lpi->uffd, UFFDIO_COPY, &uffdio_copy); - pr_debug("ioctl UFFDIO_COPY rc 0x%x\n", rc); - pr_debug("uffdio_copy.copy 0x%llx\n", uffdio_copy.copy); - if (rc) { - /* real retval in ufdio_copy.copy */ - if (uffdio_copy.copy != -EEXIST) { - pr_err("UFFDIO_COPY error %Ld\n", uffdio_copy.copy); - return -1; - } - } else if (uffdio_copy.copy != page_size()) { - pr_err("UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy); - return -1; - } - - lpi->copied_pages++; - - return uffdio_copy.copy; - -} - -static int uffd_zero_page(struct lazy_pages_info *lpi, __u64 address) -{ - struct uffdio_zeropage uffdio_zeropage; - unsigned long ps = page_size(); - int rc; - - uffdio_zeropage.range.start = address; - uffdio_zeropage.range.len = ps; - uffdio_zeropage.mode = 0; - - pr_debug("uffdio_zeropage.range.start 0x%llx\n", uffdio_zeropage.range.start); - rc = ioctl(lpi->uffd, UFFDIO_ZEROPAGE, &uffdio_zeropage); - pr_debug("ioctl UFFDIO_ZEROPAGE rc 0x%x\n", rc); - pr_debug("uffdio_zeropage.zeropage 0x%llx\n", uffdio_zeropage.zeropage); - if (rc) { - pr_err("UFFDIO_ZEROPAGE error %d\n", rc); - return -1; - } - - return ps; -} - -static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address, - void *dest) -{ - int rc; - - rc = uffd_copy_page(lpi, address, dest); - if (rc == 0) - rc = uffd_zero_page(lpi, address); - - return rc; -} - static int collect_uffd_pages(struct page_read *pr, struct lazy_pages_info *lpi) { unsigned long base; @@ -512,54 +359,6 @@ static int collect_uffd_pages(struct page_read *pr, struct lazy_pages_info *lpi) return 1; } -static int handle_remaining_pages(struct lazy_pages_info *lpi, void *dest) -{ - struct uffd_pages_struct *uffd_pages; - int rc; - - list_for_each_entry(uffd_pages, &lpi->pages, list) { - pr_debug("Checking remaining pages 0x%lx (flags 0x%x)\n", - uffd_pages->addr, uffd_pages->flags); - if (uffd_pages->flags & UFFD_FLAG_SENT) - continue; - - rc = uffd_handle_page(lpi, uffd_pages->addr, dest); - if (rc < 0) { - pr_err("Error during UFFD copy\n"); - return -1; - } - - uffd_pages->flags |= UFFD_FLAG_SENT; - } - - return 0; -} - - -static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest, - __u64 address) -{ - int rc; - struct uffd_pages_struct *uffd_pages; - - rc = uffd_handle_page(lpi, address, dest); - if (rc < 0) { - pr_err("Error during UFFD copy\n"); - return -1; - } - - /* - * Mark this page as having been already transferred, so - * that it has not to be copied again later. - */ - list_for_each_entry(uffd_pages, &lpi->pages, list) { - if (uffd_pages->addr == address) - uffd_pages->flags |= UFFD_FLAG_SENT; - } - - return 0; -} - /* * Setting up criu infrastructure and scan for VMAs. */ @@ -643,6 +442,205 @@ out: return ret; } +static int ud_open(int client, struct lazy_pages_info **_lpi) +{ + struct lazy_pages_info *lpi; + int ret = -1; + int uffd_flags; + + lpi = lpi_init(); + if (!lpi) + goto out; + + /* The "transfer protocol" is first the pid as int and then + * the FD for UFFD */ + ret = recv(client, &lpi->pid, sizeof(lpi->pid), 0); + if (ret != sizeof(lpi->pid)) { + if (ret < 0) + pr_perror("PID recv error"); + else + pr_err("PID recv: short read\n"); + goto out; + } + pr_debug("received PID: %d\n", lpi->pid); + + if (lpi->pid == -1) { + lpi_fini(lpi); + return 0; + } + + lpi->uffd = recv_fd(client); + if (lpi->uffd < 0) { + pr_err("recv_fd error\n"); + goto out; + } + pr_debug("lpi->uffd %d\n", lpi->uffd); + + pr_debug("uffd is 0x%d\n", lpi->uffd); + uffd_flags = fcntl(lpi->uffd, F_GETFD, NULL); + pr_debug("uffd_flags are 0x%x\n", uffd_flags); + + /* + * Find the memory pages belonging to the restored process + * so that it is trackable when all pages have been transferred. + */ + if ((lpi->total_pages = find_vmas(lpi)) == -1) + goto out; + + list_add_tail(&lpi->l, &lpis); + *_lpi = lpi; + + return 0; + +out: + lpi_fini(lpi); + return -1; +} + +static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest) +{ + int ret; + + lpi->pr.reset(&lpi->pr); + + ret = lpi->pr.seek_page(&lpi->pr, addr); + pr_debug("seek_pagemap_page ret 0x%x\n", ret); + if (ret <= 0) + return ret; + + if (pagemap_zero(lpi->pr.pe)) + return 0; + + ret = lpi->pr.read_pages(&lpi->pr, addr, 1, dest, 0); + pr_debug("read_pages ret %d\n", ret); + if (ret <= 0) + return ret; + + return 1; +} + +static int uffd_copy_page(struct lazy_pages_info *lpi, __u64 address, + void *dest) +{ + struct uffdio_copy uffdio_copy; + int rc; + + if (opts.use_page_server) + rc = get_remote_pages(lpi->pid, address, 1, dest); + else + rc = get_page(lpi, address, dest); + if (rc <= 0) + return rc; + + uffdio_copy.dst = address; + uffdio_copy.src = (unsigned long) dest; + uffdio_copy.len = page_size(); + uffdio_copy.mode = 0; + uffdio_copy.copy = 0; + + pr_debug("uffdio_copy.dst 0x%llx\n", uffdio_copy.dst); + rc = ioctl(lpi->uffd, UFFDIO_COPY, &uffdio_copy); + pr_debug("ioctl UFFDIO_COPY rc 0x%x\n", rc); + pr_debug("uffdio_copy.copy 0x%llx\n", uffdio_copy.copy); + if (rc) { + /* real retval in ufdio_copy.copy */ + if (uffdio_copy.copy != -EEXIST) { + pr_err("UFFDIO_COPY error %Ld\n", uffdio_copy.copy); + return -1; + } + } else if (uffdio_copy.copy != page_size()) { + pr_err("UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy); + return -1; + } + + lpi->copied_pages++; + + return uffdio_copy.copy; + +} + +static int uffd_zero_page(struct lazy_pages_info *lpi, __u64 address) +{ + struct uffdio_zeropage uffdio_zeropage; + unsigned long ps = page_size(); + int rc; + + uffdio_zeropage.range.start = address; + uffdio_zeropage.range.len = ps; + uffdio_zeropage.mode = 0; + + pr_debug("uffdio_zeropage.range.start 0x%llx\n", uffdio_zeropage.range.start); + rc = ioctl(lpi->uffd, UFFDIO_ZEROPAGE, &uffdio_zeropage); + pr_debug("ioctl UFFDIO_ZEROPAGE rc 0x%x\n", rc); + pr_debug("uffdio_zeropage.zeropage 0x%llx\n", uffdio_zeropage.zeropage); + if (rc) { + pr_err("UFFDIO_ZEROPAGE error %d\n", rc); + return -1; + } + + return ps; +} + +static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address, + void *dest) +{ + int rc; + + rc = uffd_copy_page(lpi, address, dest); + if (rc == 0) + rc = uffd_zero_page(lpi, address); + + return rc; +} + +static int handle_remaining_pages(struct lazy_pages_info *lpi, void *dest) +{ + struct uffd_pages_struct *uffd_pages; + int rc; + + list_for_each_entry(uffd_pages, &lpi->pages, list) { + pr_debug("Checking remaining pages 0x%lx (flags 0x%x)\n", + uffd_pages->addr, uffd_pages->flags); + if (uffd_pages->flags & UFFD_FLAG_SENT) + continue; + + rc = uffd_handle_page(lpi, uffd_pages->addr, dest); + if (rc < 0) { + pr_err("Error during UFFD copy\n"); + return -1; + } + + uffd_pages->flags |= UFFD_FLAG_SENT; + } + + return 0; +} + + +static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest, + __u64 address) +{ + int rc; + struct uffd_pages_struct *uffd_pages; + + rc = uffd_handle_page(lpi, address, dest); + if (rc < 0) { + pr_err("Error during UFFD copy\n"); + return -1; + } + + /* + * Mark this page as having been already transferred, so + * that it has not to be copied again later. + */ + list_for_each_entry(uffd_pages, &lpi->pages, list) { + if (uffd_pages->addr == address) + uffd_pages->flags |= UFFD_FLAG_SENT; + } + + return 0; +} + static int handle_user_fault(struct lazy_pages_info *lpi, void *dest) { struct uffd_msg msg; From fe53a87f702b1475e07002ed8850daaad70e86f4 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 13 Nov 2016 11:52:36 +0200 Subject: [PATCH 0804/4375] criu: lazy-pages: simplify intialization of lazy pages list Instead of creating mm-related parts of restore info in process tree we can directly use MmEntry for VMA traversals. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 62 ++++++++++------------------------------------------- 1 file changed, 11 insertions(+), 51 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 41192a6cc..2b3098b16 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -295,22 +295,16 @@ struct uffd_pages_struct { int flags; }; -static int collect_uffd_pages(struct page_read *pr, struct lazy_pages_info *lpi) +static int collect_uffd_pages(struct lazy_pages_info *lpi, MmEntry *mm) { unsigned long base; - int i; + int i, j; struct iovec iov; unsigned long nr_pages; unsigned long ps; int rc; struct uffd_pages_struct *uffd_pages; - struct vma_area *vma; - struct vm_area_list *vmas; - struct pstree_item *item = pstree_item_by_virt(lpi->pid); - - BUG_ON(!item); - - vmas = &rsti(item)->vmas; + struct page_read *pr = &lpi->pr; rc = pr->get_pagemap(pr, &iov); if (rc <= 0) @@ -329,13 +323,14 @@ static int collect_uffd_pages(struct page_read *pr, struct lazy_pages_info *lpi) * are relevant for userfaultfd handling. * Loop over all VMAs to see if the flags matching. */ - list_for_each_entry(vma, &vmas->h, list) { + for (j = 0; j < mm->n_vmas; j++) { + VmaEntry *vma = mm->vmas[j]; /* * This loop assumes that base can actually be found * in the VMA list. */ - if (base >= vma->e->start && base < vma->e->end) { - if (vma_entry_can_be_lazy(vma->e)) { + if (base >= vma->start && base < vma->end) { + if (vma_entry_can_be_lazy(vma)) { if(!pagemap_in_parent(pr->pe)) uffd_page = true; break; @@ -366,53 +361,18 @@ static int find_vmas(struct lazy_pages_info *lpi) { struct cr_img *img; int ret; - struct vm_area_list vmas; - int vn = 0; - struct rst_info *ri; + MmEntry *mm; struct uffd_pages_struct *uffd_pages; - struct pstree_item *item = pstree_item_by_virt(lpi->pid); - - BUG_ON(!item); - - vm_area_list_init(&vmas); - - ri = rsti(item); - if (!ri) - return -1; img = open_image(CR_FD_MM, O_RSTR, lpi->pid); if (!img) return -1; - ret = pb_read_one_eof(img, &ri->mm, PB_MM); + ret = pb_read_one_eof(img, &mm, PB_MM); close_image(img); if (ret == -1) return -1; - - pr_debug("Found %zd VMAs in image\n", ri->mm->n_vmas); - - while (vn < ri->mm->n_vmas) { - struct vma_area *vma; - - ret = -1; - vma = alloc_vma_area(); - if (!vma) - goto out; - - ret = 0; - ri->vmas.nr++; - vma->e = ri->mm->vmas[vn++]; - - list_add_tail(&vma->list, &ri->vmas.h); - - if (vma_area_is_private(vma, kdat.task_size)) { - vmas.priv_size += vma_area_len(vma); - if (vma->e->flags & MAP_GROWSDOWN) - vmas.priv_size += PAGE_SIZE; - } - - pr_info("vma 0x%"PRIx64" 0x%"PRIx64"\n", vma->e->start, vma->e->end); - } + pr_debug("Found %zd VMAs in image\n", mm->n_vmas); ret = open_page_read(lpi->pid, &lpi->pr, PR_TASK); if (ret <= 0) { @@ -426,7 +386,7 @@ static int find_vmas(struct lazy_pages_info *lpi) * pushed into the process using userfaultfd. */ do { - ret = collect_uffd_pages(&lpi->pr, lpi); + ret = collect_uffd_pages(lpi, mm); if (ret == -1) { goto out; } From 0086dca47d1240c5eee84fbce488fd5534c8c511 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 13 Nov 2016 11:52:38 +0200 Subject: [PATCH 0805/4375] uffdd: Implement --daemon mode Right now the zdtm.py hacks around core code and waits for a second for the socket to appear. Let's better make proper --daemon mode for lazy-pages daemon and pidfile generation. Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/crtools.c | 2 +- criu/include/crtools.h | 2 +- criu/uffd.c | 50 ++++++++++++++++++++++++++++++++++++------ test/zdtm.py | 8 +++---- 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index 8e3784aa4..06471f179 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -738,7 +738,7 @@ int main(int argc, char *argv[], char *envp[]) } if (!strcmp(argv[optind], "lazy-pages")) - return cr_lazy_pages() != 0; + return cr_lazy_pages(opts.daemon_mode) != 0; if (!strcmp(argv[optind], "check")) return cr_check() != 0; diff --git a/criu/include/crtools.h b/criu/include/crtools.h index 15d6d732f..a78a577cd 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -25,7 +25,7 @@ extern int cr_restore_tasks(void); extern int convert_to_elf(char *elf_path, int fd_core); extern int cr_check(void); extern int cr_dedup(void); -extern int cr_lazy_pages(void); +extern int cr_lazy_pages(bool daemon); extern int check_add_feature(char *arg); extern void pr_check_features(const char *offset, const char *sep, int width); diff --git a/criu/uffd.c b/criu/uffd.c index 2b3098b16..bd68a9202 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -15,12 +15,13 @@ #include #include #include +#include #include "linux/userfaultfd.h" #include "int.h" #include "page.h" -#include "log.h" +#include "criu-log.h" #include "criu-plugin.h" #include "pagemap.h" #include "files-reg.h" @@ -776,12 +777,9 @@ static int epoll_add_lpi(int epollfd, struct lazy_pages_info *lpi) return 0; } -static int prepare_uffds(int epollfd) +static int prepare_lazy_socket(void) { - int i; int listen; - int client; - socklen_t len; struct sockaddr_un saddr; if (prepare_sock_addr(&saddr)) @@ -793,6 +791,16 @@ static int prepare_uffds(int epollfd) return -1; } + return listen; +} + +static int prepare_uffds(int listen, int epollfd) +{ + int i; + int client; + socklen_t len; + struct sockaddr_un saddr; + /* accept new client request */ len = sizeof(struct sockaddr_un); if ((client = accept(listen, (struct sockaddr *) &saddr, &len)) < 0) { @@ -822,10 +830,11 @@ close_uffd: return -1; } -int cr_lazy_pages() +int cr_lazy_pages(bool daemon) { struct epoll_event *events; int epollfd; + int lazy_sk; int ret; if (check_for_uffd()) @@ -834,11 +843,38 @@ int cr_lazy_pages() if (lazy_pages_prepare_pstree()) return -1; + lazy_sk = prepare_lazy_socket(); + if (lazy_sk < 0) + return -1; + + if (daemon) { + ret = cr_daemon(1, 0, &lazy_sk, -1); + if (ret == -1) { + pr_err("Can't run in the background\n"); + return -1; + } + if (ret > 0) { /* parent task, daemon started */ + if (opts.pidfile) { + if (write_pidfile(ret) == -1) { + pr_perror("Can't write pidfile"); + kill(ret, SIGKILL); + waitpid(ret, NULL, 0); + return -1; + } + } + + return 0; + } + } + + if (close_status_fd()) + return -1; + epollfd = prepare_epoll(task_entries->nr_tasks, &events); if (epollfd < 0) return -1; - if (prepare_uffds(epollfd)) + if (prepare_uffds(lazy_sk, epollfd)) return -1; if (connect_to_page_server()) diff --git a/test/zdtm.py b/test/zdtm.py index 835b7809d..43b306a6f 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -962,11 +962,9 @@ class criu: r_opts.append('--external') r_opts.append('mnt[zdtm]:%s' % criu_dir) - lazy_pages_p = None if self.__lazy_pages: - lazy_pages_p = self.__criu_act("lazy-pages", opts = [], nowait = True) + self.__criu_act("lazy-pages", opts = ["--daemon", "--pidfile", "lp.pid"]) r_opts += ["--lazy-pages"] - time.sleep(1) # FIXME wait user fault fd socket if self.__leave_stopped: r_opts += ['--leave-stopped'] @@ -989,8 +987,8 @@ class criu: pstree_check_stopped(self.__test.getpid()) pstree_signal(self.__test.getpid(), signal.SIGCONT) - if lazy_pages_p and lazy_pages_p.wait(): - raise test_fail_exc("CRIU lazy-pages") + if self.__lazy_pages: + wait_pid_die(int(rpidfile(self.__ddir() + "/lp.pid")), "lazy pages daemon") @staticmethod def check(feature): From 700419bc7e82e5122d7b1fbb7719332d1ff596ba Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:11 +0200 Subject: [PATCH 0806/4375] criu: lazy-pages: replace page list with IOVs list Instead of tracking memory handled by userfaultfd on the page basis we can use IOVs for continious chunks. travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 282 ++++++++++++++++++++++++++++------------------------ 1 file changed, 154 insertions(+), 128 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index bd68a9202..c65b4c884 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -47,11 +47,17 @@ static mutex_t *lazy_sock_mutex; +struct lazy_iovec { + struct list_head l; + unsigned long base; + unsigned long len; +}; + struct lazy_pages_info { int pid; int uffd; - struct list_head pages; + struct list_head iovs; struct page_read pr; @@ -72,7 +78,7 @@ static struct lazy_pages_info *lpi_init(void) return NULL; memset(lpi, 0, sizeof(*lpi)); - INIT_LIST_HEAD(&lpi->pages); + INIT_LIST_HEAD(&lpi->iovs); INIT_LIST_HEAD(&lpi->l); return lpi; @@ -80,8 +86,12 @@ static struct lazy_pages_info *lpi_init(void) static void lpi_fini(struct lazy_pages_info *lpi) { + struct lazy_iovec *p, *n; + if (!lpi) return; + list_for_each_entry_safe(p, n, &lpi->iovs, l) + xfree(p); if (lpi->uffd > 0) close(lpi->uffd); if (lpi->pr.close) @@ -288,118 +298,135 @@ out: return -1; } -#define UFFD_FLAG_SENT 0x1 - -struct uffd_pages_struct { - struct list_head list; - unsigned long addr; - int flags; -}; - -static int collect_uffd_pages(struct lazy_pages_info *lpi, MmEntry *mm) -{ - unsigned long base; - int i, j; - struct iovec iov; - unsigned long nr_pages; - unsigned long ps; - int rc; - struct uffd_pages_struct *uffd_pages; - struct page_read *pr = &lpi->pr; - - rc = pr->get_pagemap(pr, &iov); - if (rc <= 0) - return 0; - - ps = page_size(); - nr_pages = iov.iov_len / ps; - base = (unsigned long) iov.iov_base; - pr_debug("iov.iov_base 0x%lx (%ld pages)\n", base, nr_pages); - - for (i = 0; i < nr_pages; i++) { - bool uffd_page = false; - base = (unsigned long) iov.iov_base + (i * ps); - /* - * Only pages which are MAP_ANONYMOUS and MAP_PRIVATE - * are relevant for userfaultfd handling. - * Loop over all VMAs to see if the flags matching. - */ - for (j = 0; j < mm->n_vmas; j++) { - VmaEntry *vma = mm->vmas[j]; - /* - * This loop assumes that base can actually be found - * in the VMA list. - */ - if (base >= vma->start && base < vma->end) { - if (vma_entry_can_be_lazy(vma)) { - if(!pagemap_in_parent(pr->pe)) - uffd_page = true; - break; - } - } - } - - /* This is not a page we are looking for. Move along */ - if (!uffd_page) - continue; - - pr_debug("Adding 0x%lx to our list\n", base); - - uffd_pages = xzalloc(sizeof(struct uffd_pages_struct)); - if (!uffd_pages) - return -1; - uffd_pages->addr = base; - list_add(&uffd_pages->list, &lpi->pages); - } - - return 1; -} - -/* - * Setting up criu infrastructure and scan for VMAs. - */ -static int find_vmas(struct lazy_pages_info *lpi) +static MmEntry *init_mm_entry(struct lazy_pages_info *lpi) { struct cr_img *img; - int ret; MmEntry *mm; - struct uffd_pages_struct *uffd_pages; + int ret; img = open_image(CR_FD_MM, O_RSTR, lpi->pid); if (!img) - return -1; + return NULL; ret = pb_read_one_eof(img, &mm, PB_MM); close_image(img); if (ret == -1) - return -1; + return NULL; pr_debug("Found %zd VMAs in image\n", mm->n_vmas); - ret = open_page_read(lpi->pid, &lpi->pr, PR_TASK); - if (ret <= 0) { - ret = -1; - goto out; - } - /* - * This puts all pages which should be handled by userfaultfd - * in the list uffd_list. This list is later used to detect if - * a page has already been transferred or if it needs to be - * pushed into the process using userfaultfd. - */ - do { - ret = collect_uffd_pages(lpi, mm); - if (ret == -1) { - goto out; + return mm; +} + +static int update_lazy_iovecs(struct lazy_pages_info *lpi, unsigned long addr, + int len) +{ + struct lazy_iovec *lazy_iov, *n; + + list_for_each_entry_safe(lazy_iov, n, &lpi->iovs, l) { + unsigned long start = lazy_iov->base; + unsigned long end = start + lazy_iov->len; + + if (len <= 0) + break; + + if (addr < start || addr >= end) + continue; + + if (addr + len < end) { + if (addr == start) { + lazy_iov->base += len; + lazy_iov->len -= len; + } else { + struct lazy_iovec *new_iov; + + lazy_iov->len -= (end - addr); + + new_iov = xzalloc(sizeof(*new_iov)); + if (!new_iov) + return -1; + + new_iov->base = addr + len; + new_iov->len = end - (addr + len); + + list_add(&new_iov->l, &lazy_iov->l); + } + break; } - } while (ret); - /* Count detected pages */ - list_for_each_entry(uffd_pages, &lpi->pages, list) - ret++; + if (addr == start) { + list_del(&lazy_iov->l); + xfree(lazy_iov); + } else { + lazy_iov->len -= (end - addr); + } - pr_debug("Found %d pages to be handled by UFFD\n", ret); + len -= (end - addr); + addr = end; + } + + return 0; +} + +/* + * Create a list of IOVs that can be handled using userfaultfd. The + * IOVs generally correspond to lazy pagemap entries, except the cases + * when a single pagemap entry covers several VMAs. In those cases + * IOVs are split at VMA boundaries because UFFDIO_COPY may be done + * only inside a single VMA. + * We assume here that pagemaps and VMAs are sorted. + */ +static int collect_lazy_iovecs(struct lazy_pages_info *lpi) +{ + struct page_read *pr = &lpi->pr; + struct lazy_iovec *lazy_iov, *n; + MmEntry *mm; + int nr_pages = 0, n_vma = 0; + int ret = -1; + unsigned long start, end, len; + + mm = init_mm_entry(lpi); + if (!mm) + return -1; + + while (pr->advance(pr)) { + if (!pagemap_lazy(pr->pe)) + continue; + + start = pr->pe->vaddr; + end = start + pr->pe->nr_pages * page_size(); + nr_pages += pr->pe->nr_pages; + + for (; n_vma < mm->n_vmas; n_vma++) { + VmaEntry *vma = mm->vmas[n_vma]; + + if (start >= vma->end) + continue; + + lazy_iov = xzalloc(sizeof(*lazy_iov)); + if (!lazy_iov) + goto free_iovs; + + len = min_t(uint64_t, end, vma->end) - start; + lazy_iov->base = start; + lazy_iov->len = len; + list_add_tail(&lazy_iov->l, &lpi->iovs); + + if (end <= vma->end) + break; + + start = vma->end; + } + } + + ret = nr_pages; + goto free_mm; + +free_iovs: + list_for_each_entry_safe(lazy_iov, n, &lpi->iovs, l) + xfree(lazy_iov); +free_mm: + mm_entry__free_unpacked(mm, NULL); -out: return ret; } @@ -441,12 +468,22 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) uffd_flags = fcntl(lpi->uffd, F_GETFD, NULL); pr_debug("uffd_flags are 0x%x\n", uffd_flags); + ret = open_page_read(lpi->pid, &lpi->pr, PR_TASK); + if (ret <= 0) { + ret = -1; + goto out; + } + /* * Find the memory pages belonging to the restored process * so that it is trackable when all pages have been transferred. */ - if ((lpi->total_pages = find_vmas(lpi)) == -1) + ret = collect_lazy_iovecs(lpi); + if (ret < 0) goto out; + lpi->total_pages = ret; + + pr_debug("Found %ld pages to be handled by UFFD\n", lpi->total_pages); list_add_tail(&lpi->l, &lpis); *_lpi = lpi; @@ -556,33 +593,33 @@ static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address, static int handle_remaining_pages(struct lazy_pages_info *lpi, void *dest) { - struct uffd_pages_struct *uffd_pages; - int rc; + struct lazy_iovec *lazy_iov; + int nr_pages, i, err; + unsigned long addr; - list_for_each_entry(uffd_pages, &lpi->pages, list) { - pr_debug("Checking remaining pages 0x%lx (flags 0x%x)\n", - uffd_pages->addr, uffd_pages->flags); - if (uffd_pages->flags & UFFD_FLAG_SENT) - continue; + lpi->pr.reset(&lpi->pr); - rc = uffd_handle_page(lpi, uffd_pages->addr, dest); - if (rc < 0) { - pr_err("Error during UFFD copy\n"); - return -1; + list_for_each_entry(lazy_iov, &lpi->iovs, l) { + nr_pages = lazy_iov->len / PAGE_SIZE; + + for (i = 0; i < nr_pages; i++) { + addr = lazy_iov->base + i * PAGE_SIZE; + + err = uffd_handle_page(lpi, addr, dest); + if (err < 0) { + pr_err("Error during UFFD copy\n"); + return -1; + } } - - uffd_pages->flags |= UFFD_FLAG_SENT; } return 0; } - static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest, __u64 address) { int rc; - struct uffd_pages_struct *uffd_pages; rc = uffd_handle_page(lpi, address, dest); if (rc < 0) { @@ -590,14 +627,9 @@ static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest, return -1; } - /* - * Mark this page as having been already transferred, so - * that it has not to be copied again later. - */ - list_for_each_entry(uffd_pages, &lpi->pages, list) { - if (uffd_pages->addr == address) - uffd_pages->flags |= UFFD_FLAG_SENT; - } + rc = update_lazy_iovecs(lpi, address, PAGE_SIZE); + if (rc < 0) + return -1; return 0; } @@ -607,7 +639,6 @@ static int handle_user_fault(struct lazy_pages_info *lpi, void *dest) struct uffd_msg msg; __u64 flags; __u64 address; - struct uffd_pages_struct *uffd_pages; int ret; ret = read(lpi->uffd, &msg, sizeof(msg)); @@ -632,11 +663,6 @@ static int handle_user_fault(struct lazy_pages_info *lpi, void *dest) address = msg.arg.pagefault.address & ~(page_size() - 1); pr_debug("msg.arg.pagefault.address 0x%llx\n", address); - /* Make sure to not transfer a page twice */ - list_for_each_entry(uffd_pages, &lpi->pages, list) - if ((uffd_pages->addr == address) && (uffd_pages->flags & UFFD_FLAG_SENT)) - return 0; - /* Now handle the pages actually requested. */ flags = msg.arg.pagefault.flags; pr_debug("msg.arg.pagefault.flags 0x%llx\n", flags); From 7c6f72cf4dde70af5dd4acdc4a90a0fed269f2ed Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 15 Nov 2016 18:57:12 +0200 Subject: [PATCH 0807/4375] uffd: Introduce lazy_pages_fd as preparation for socket polling We will want to poll not only a bunch of uffd-s, but also the lazy socket, so here's "an fd and a callback" object to be pushed into epoll. travis-ci: success for uffd: A new set of improvements Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/uffd.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index c65b4c884..be4300406 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -53,9 +53,13 @@ struct lazy_iovec { unsigned long len; }; +struct lazy_pages_fd { + int fd; + int (*event)(struct lazy_pages_fd *, void *dest); +}; + struct lazy_pages_info { int pid; - int uffd; struct list_head iovs; @@ -64,10 +68,13 @@ struct lazy_pages_info { unsigned long total_pages; unsigned long copied_pages; + struct lazy_pages_fd lpfd; + struct list_head l; }; static LIST_HEAD(lpis); +static int handle_user_fault(struct lazy_pages_fd *lpfd, void *dest); static struct lazy_pages_info *lpi_init(void) { @@ -80,6 +87,7 @@ static struct lazy_pages_info *lpi_init(void) memset(lpi, 0, sizeof(*lpi)); INIT_LIST_HEAD(&lpi->iovs); INIT_LIST_HEAD(&lpi->l); + lpi->lpfd.event = handle_user_fault; return lpi; } @@ -92,8 +100,8 @@ static void lpi_fini(struct lazy_pages_info *lpi) return; list_for_each_entry_safe(p, n, &lpi->iovs, l) xfree(p); - if (lpi->uffd > 0) - close(lpi->uffd); + if (lpi->lpfd.fd > 0) + close(lpi->lpfd.fd); if (lpi->pr.close) lpi->pr.close(&lpi->pr); free(lpi); @@ -457,15 +465,15 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) return 0; } - lpi->uffd = recv_fd(client); - if (lpi->uffd < 0) { + lpi->lpfd.fd = recv_fd(client); + if (lpi->lpfd.fd < 0) { pr_err("recv_fd error\n"); goto out; } - pr_debug("lpi->uffd %d\n", lpi->uffd); + pr_debug("lpi->uffd %d\n", lpi->lpfd.fd); - pr_debug("uffd is 0x%d\n", lpi->uffd); - uffd_flags = fcntl(lpi->uffd, F_GETFD, NULL); + pr_debug("uffd is 0x%d\n", lpi->lpfd.fd); + uffd_flags = fcntl(lpi->lpfd.fd, F_GETFD, NULL); pr_debug("uffd_flags are 0x%x\n", uffd_flags); ret = open_page_read(lpi->pid, &lpi->pr, PR_TASK); @@ -537,7 +545,7 @@ static int uffd_copy_page(struct lazy_pages_info *lpi, __u64 address, uffdio_copy.copy = 0; pr_debug("uffdio_copy.dst 0x%llx\n", uffdio_copy.dst); - rc = ioctl(lpi->uffd, UFFDIO_COPY, &uffdio_copy); + rc = ioctl(lpi->lpfd.fd, UFFDIO_COPY, &uffdio_copy); pr_debug("ioctl UFFDIO_COPY rc 0x%x\n", rc); pr_debug("uffdio_copy.copy 0x%llx\n", uffdio_copy.copy); if (rc) { @@ -568,7 +576,7 @@ static int uffd_zero_page(struct lazy_pages_info *lpi, __u64 address) uffdio_zeropage.mode = 0; pr_debug("uffdio_zeropage.range.start 0x%llx\n", uffdio_zeropage.range.start); - rc = ioctl(lpi->uffd, UFFDIO_ZEROPAGE, &uffdio_zeropage); + rc = ioctl(lpi->lpfd.fd, UFFDIO_ZEROPAGE, &uffdio_zeropage); pr_debug("ioctl UFFDIO_ZEROPAGE rc 0x%x\n", rc); pr_debug("uffdio_zeropage.zeropage 0x%llx\n", uffdio_zeropage.zeropage); if (rc) { @@ -634,14 +642,17 @@ static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest, return 0; } -static int handle_user_fault(struct lazy_pages_info *lpi, void *dest) +static int handle_user_fault(struct lazy_pages_fd *lpfd, void *dest) { + struct lazy_pages_info *lpi; struct uffd_msg msg; __u64 flags; __u64 address; int ret; - ret = read(lpi->uffd, &msg, sizeof(msg)); + lpi = container_of(lpfd, struct lazy_pages_info, lpfd); + + ret = read(lpfd->fd, &msg, sizeof(msg)); pr_debug("read() ret: 0x%x\n", ret); if (!ret) return 1; @@ -709,6 +720,8 @@ static int handle_requests(int epollfd, struct epoll_event *events) return ret; while (1) { + struct lazy_pages_fd *lpfd; + /* * Setting the timeout to 5 seconds. If after this time * no uffd pages are requested the code switches to @@ -728,8 +741,8 @@ static int handle_requests(int epollfd, struct epoll_event *events) for (i = 0; i < ret; i++) { int err; - lpi = (struct lazy_pages_info *)events[i].data.ptr; - err = handle_user_fault(lpi, dest); + lpfd = (struct lazy_pages_fd *)events[i].data.ptr; + err = lpfd->event(lpfd, dest); if (err < 0) goto out; } @@ -789,13 +802,13 @@ free_events: return -1; } -static int epoll_add_lpi(int epollfd, struct lazy_pages_info *lpi) +static int epoll_add_lpfd(int epollfd, struct lazy_pages_fd *lpfd) { struct epoll_event ev; ev.events = EPOLLIN; - ev.data.ptr = lpi; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, lpi->uffd, &ev) == -1) { + ev.data.ptr = lpfd; + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, lpfd->fd, &ev) == -1) { pr_perror("epoll_ctl failed"); return -1; } @@ -842,7 +855,7 @@ static int prepare_uffds(int listen, int epollfd) goto close_uffd; if (lpi == NULL) continue; - if (epoll_add_lpi(epollfd, lpi)) + if (epoll_add_lpfd(epollfd, &lpi->lpfd)) goto close_uffd; } From a98eed95fa2fc077bdb2386e48565c293461b833 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:13 +0200 Subject: [PATCH 0808/4375] lazy-pages: refactor uffd_handle_page Inline relevant parts of get_page inside uffd_handle_page and call uffd_{copy,zero}_page after we've got the data. travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 56 +++++++++++++++++++++-------------------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index be4300406..c55b1ebb0 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -503,41 +503,12 @@ out: return -1; } -static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest) -{ - int ret; - - lpi->pr.reset(&lpi->pr); - - ret = lpi->pr.seek_page(&lpi->pr, addr); - pr_debug("seek_pagemap_page ret 0x%x\n", ret); - if (ret <= 0) - return ret; - - if (pagemap_zero(lpi->pr.pe)) - return 0; - - ret = lpi->pr.read_pages(&lpi->pr, addr, 1, dest, 0); - pr_debug("read_pages ret %d\n", ret); - if (ret <= 0) - return ret; - - return 1; -} - static int uffd_copy_page(struct lazy_pages_info *lpi, __u64 address, void *dest) { struct uffdio_copy uffdio_copy; int rc; - if (opts.use_page_server) - rc = get_remote_pages(lpi->pid, address, 1, dest); - else - rc = get_page(lpi, address, dest); - if (rc <= 0) - return rc; - uffdio_copy.dst = address; uffdio_copy.src = (unsigned long) dest; uffdio_copy.len = page_size(); @@ -590,13 +561,30 @@ static int uffd_zero_page(struct lazy_pages_info *lpi, __u64 address) static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address, void *dest) { - int rc; + int ret; - rc = uffd_copy_page(lpi, address, dest); - if (rc == 0) - rc = uffd_zero_page(lpi, address); + lpi->pr.reset(&lpi->pr); - return rc; + ret = lpi->pr.seek_page(&lpi->pr, address); + if (ret < 0) { + pr_err("%d: no pagemap containing %llx\n", lpi->pid, address); + return ret; + } + + if (pagemap_zero(lpi->pr.pe)) + return uffd_zero_page(lpi, address); + + if (opts.use_page_server) + ret = get_remote_pages(lpi->pid, address, 1, dest); + else + ret = lpi->pr.read_pages(&lpi->pr, address, 1, dest, 0); + + if (ret <= 0) { + pr_err("%d: failed reading pages at %llx\n", lpi->pid, address); + return ret; + } + + return uffd_copy_page(lpi, address, dest); } static int handle_remaining_pages(struct lazy_pages_info *lpi, void *dest) From ec585622ef244a37a5387c44892a620c00cd9354 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:14 +0200 Subject: [PATCH 0809/4375] lazy-pages: fix zero pages handling page_read->seek_page was restored to skip zero pagemaps, therefore we should check its return value rather than underlying PME. travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index c55b1ebb0..93b53efab 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -565,11 +565,9 @@ static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address, lpi->pr.reset(&lpi->pr); - ret = lpi->pr.seek_page(&lpi->pr, address); - if (ret < 0) { - pr_err("%d: no pagemap containing %llx\n", lpi->pid, address); - return ret; - } + ret = lpi->pr.seek_pagemap(&lpi->pr, address); + if (!ret) + return 0; if (pagemap_zero(lpi->pr.pe)) return uffd_zero_page(lpi, address); From 1bdd3e46eb4e15afea64891f77d15e7e6e90a53f Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:15 +0200 Subject: [PATCH 0810/4375] criu: lazy_pages: make buffer for copying pages per-process Currently we allocate a single page to use as intermediate buffer for holding data that will be used in UFFDIO_COPY. Let's allocate a buffer per process and make that buffer large enough to hold the largest continuos chunk. travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 55 +++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 93b53efab..b8eed4045 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -55,7 +55,7 @@ struct lazy_iovec { struct lazy_pages_fd { int fd; - int (*event)(struct lazy_pages_fd *, void *dest); + int (*event)(struct lazy_pages_fd *); }; struct lazy_pages_info { @@ -71,10 +71,12 @@ struct lazy_pages_info { struct lazy_pages_fd lpfd; struct list_head l; + + void *buf; }; static LIST_HEAD(lpis); -static int handle_user_fault(struct lazy_pages_fd *lpfd, void *dest); +static int handle_user_fault(struct lazy_pages_fd *lpfd); static struct lazy_pages_info *lpi_init(void) { @@ -98,6 +100,7 @@ static void lpi_fini(struct lazy_pages_info *lpi) if (!lpi) return; + free(lpi->buf); list_for_each_entry_safe(p, n, &lpi->iovs, l) xfree(p); if (lpi->lpfd.fd > 0) @@ -388,7 +391,7 @@ static int collect_lazy_iovecs(struct lazy_pages_info *lpi) struct page_read *pr = &lpi->pr; struct lazy_iovec *lazy_iov, *n; MmEntry *mm; - int nr_pages = 0, n_vma = 0; + int nr_pages = 0, n_vma = 0, max_iov_len = 0; int ret = -1; unsigned long start, end, len; @@ -419,6 +422,9 @@ static int collect_lazy_iovecs(struct lazy_pages_info *lpi) lazy_iov->len = len; list_add_tail(&lazy_iov->l, &lpi->iovs); + if (len > max_iov_len) + max_iov_len = len; + if (end <= vma->end) break; @@ -426,6 +432,9 @@ static int collect_lazy_iovecs(struct lazy_pages_info *lpi) } } + if (posix_memalign(&lpi->buf, PAGE_SIZE, max_iov_len)) + goto free_iovs; + ret = nr_pages; goto free_mm; @@ -503,14 +512,13 @@ out: return -1; } -static int uffd_copy_page(struct lazy_pages_info *lpi, __u64 address, - void *dest) +static int uffd_copy_page(struct lazy_pages_info *lpi, __u64 address) { struct uffdio_copy uffdio_copy; int rc; uffdio_copy.dst = address; - uffdio_copy.src = (unsigned long) dest; + uffdio_copy.src = (unsigned long)lpi->buf; uffdio_copy.len = page_size(); uffdio_copy.mode = 0; uffdio_copy.copy = 0; @@ -558,8 +566,7 @@ static int uffd_zero_page(struct lazy_pages_info *lpi, __u64 address) return ps; } -static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address, - void *dest) +static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address) { int ret; @@ -573,19 +580,19 @@ static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address, return uffd_zero_page(lpi, address); if (opts.use_page_server) - ret = get_remote_pages(lpi->pid, address, 1, dest); + ret = get_remote_pages(lpi->pid, address, 1, lpi->buf); else - ret = lpi->pr.read_pages(&lpi->pr, address, 1, dest, 0); + ret = lpi->pr.read_pages(&lpi->pr, address, 1, lpi->buf, 0); if (ret <= 0) { pr_err("%d: failed reading pages at %llx\n", lpi->pid, address); return ret; } - return uffd_copy_page(lpi, address, dest); + return uffd_copy_page(lpi, address); } -static int handle_remaining_pages(struct lazy_pages_info *lpi, void *dest) +static int handle_remaining_pages(struct lazy_pages_info *lpi) { struct lazy_iovec *lazy_iov; int nr_pages, i, err; @@ -599,7 +606,7 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi, void *dest) for (i = 0; i < nr_pages; i++) { addr = lazy_iov->base + i * PAGE_SIZE; - err = uffd_handle_page(lpi, addr, dest); + err = uffd_handle_page(lpi, addr); if (err < 0) { pr_err("Error during UFFD copy\n"); return -1; @@ -610,12 +617,11 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi, void *dest) return 0; } -static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest, - __u64 address) +static int handle_regular_pages(struct lazy_pages_info *lpi, __u64 address) { int rc; - rc = uffd_handle_page(lpi, address, dest); + rc = uffd_handle_page(lpi, address); if (rc < 0) { pr_err("Error during UFFD copy\n"); return -1; @@ -628,7 +634,7 @@ static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest, return 0; } -static int handle_user_fault(struct lazy_pages_fd *lpfd, void *dest) +static int handle_user_fault(struct lazy_pages_fd *lpfd) { struct lazy_pages_info *lpi; struct uffd_msg msg; @@ -664,7 +670,7 @@ static int handle_user_fault(struct lazy_pages_fd *lpfd, void *dest) flags = msg.arg.pagefault.flags; pr_debug("msg.arg.pagefault.flags 0x%llx\n", flags); - ret = handle_regular_pages(lpi, dest, address); + ret = handle_regular_pages(lpi, address); if (ret < 0) { pr_err("Error during regular page copy\n"); return -1; @@ -695,16 +701,8 @@ static int handle_requests(int epollfd, struct epoll_event *events) int nr_fds = task_entries->nr_tasks; struct lazy_pages_info *lpi; int ret = -1; - unsigned long ps; - void *dest; int i; - /* All operations will be done on page size */ - ps = page_size(); - dest = xmalloc(ps); - if (!dest) - return ret; - while (1) { struct lazy_pages_fd *lpfd; @@ -728,14 +726,14 @@ static int handle_requests(int epollfd, struct epoll_event *events) int err; lpfd = (struct lazy_pages_fd *)events[i].data.ptr; - err = lpfd->event(lpfd, dest); + err = lpfd->event(lpfd); if (err < 0) goto out; } } pr_debug("Handle remaining pages\n"); list_for_each_entry(lpi, &lpis, l) { - ret = handle_remaining_pages(lpi, dest); + ret = handle_remaining_pages(lpi); if (ret < 0) { pr_err("Error during remaining page copy\n"); ret = 1; @@ -747,7 +745,6 @@ static int handle_requests(int epollfd, struct epoll_event *events) ret += lazy_pages_summary(lpi); out: - free(dest); return ret; } From f45229886e0d003bb6e18156b4d762bcc32c50e6 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:16 +0200 Subject: [PATCH 0811/4375] lazy-pages: drop _page suffix from uffd_{copy,zero}_page travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index b8eed4045..876d0a076 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -512,7 +512,7 @@ out: return -1; } -static int uffd_copy_page(struct lazy_pages_info *lpi, __u64 address) +static int uffd_copy(struct lazy_pages_info *lpi, __u64 address) { struct uffdio_copy uffdio_copy; int rc; @@ -544,7 +544,7 @@ static int uffd_copy_page(struct lazy_pages_info *lpi, __u64 address) } -static int uffd_zero_page(struct lazy_pages_info *lpi, __u64 address) +static int uffd_zero(struct lazy_pages_info *lpi, __u64 address) { struct uffdio_zeropage uffdio_zeropage; unsigned long ps = page_size(); @@ -577,7 +577,7 @@ static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address) return 0; if (pagemap_zero(lpi->pr.pe)) - return uffd_zero_page(lpi, address); + return uffd_zero(lpi, address); if (opts.use_page_server) ret = get_remote_pages(lpi->pid, address, 1, lpi->buf); @@ -589,7 +589,7 @@ static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address) return ret; } - return uffd_copy_page(lpi, address); + return uffd_copy(lpi, address); } static int handle_remaining_pages(struct lazy_pages_info *lpi) From 2ce10690c73923b73fcfb781e3879f7c8d7db3ed Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:17 +0200 Subject: [PATCH 0812/4375] criu: lazy-pages: add nr_pages parameter to uffd_{copy,zero} travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 876d0a076..c74668998 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -512,14 +512,15 @@ out: return -1; } -static int uffd_copy(struct lazy_pages_info *lpi, __u64 address) +static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) { struct uffdio_copy uffdio_copy; + unsigned long len = nr_pages * page_size(); int rc; uffdio_copy.dst = address; uffdio_copy.src = (unsigned long)lpi->buf; - uffdio_copy.len = page_size(); + uffdio_copy.len = len; uffdio_copy.mode = 0; uffdio_copy.copy = 0; @@ -533,25 +534,24 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address) pr_err("UFFDIO_COPY error %Ld\n", uffdio_copy.copy); return -1; } - } else if (uffdio_copy.copy != page_size()) { + } else if (uffdio_copy.copy != len) { pr_err("UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy); return -1; } - lpi->copied_pages++; + lpi->copied_pages += nr_pages; return uffdio_copy.copy; - } -static int uffd_zero(struct lazy_pages_info *lpi, __u64 address) +static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) { struct uffdio_zeropage uffdio_zeropage; - unsigned long ps = page_size(); + unsigned long len = page_size() * nr_pages; int rc; uffdio_zeropage.range.start = address; - uffdio_zeropage.range.len = ps; + uffdio_zeropage.range.len = len; uffdio_zeropage.mode = 0; pr_debug("uffdio_zeropage.range.start 0x%llx\n", uffdio_zeropage.range.start); @@ -563,7 +563,7 @@ static int uffd_zero(struct lazy_pages_info *lpi, __u64 address) return -1; } - return ps; + return len; } static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address) @@ -577,7 +577,7 @@ static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address) return 0; if (pagemap_zero(lpi->pr.pe)) - return uffd_zero(lpi, address); + return uffd_zero(lpi, address, 1); if (opts.use_page_server) ret = get_remote_pages(lpi->pid, address, 1, lpi->buf); @@ -589,7 +589,7 @@ static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address) return ret; } - return uffd_copy(lpi, address); + return uffd_copy(lpi, address, 1); } static int handle_remaining_pages(struct lazy_pages_info *lpi) From 0d5d286febe1f65ba3f28972ee03a2aa05e21ead Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:18 +0200 Subject: [PATCH 0813/4375] criu: lazy-pages: add nr (of pages) parameter to handle_regular_pages travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index c74668998..426a18d85 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -566,7 +566,7 @@ static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) return len; } -static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address) +static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr) { int ret; @@ -577,19 +577,19 @@ static int uffd_handle_page(struct lazy_pages_info *lpi, __u64 address) return 0; if (pagemap_zero(lpi->pr.pe)) - return uffd_zero(lpi, address, 1); + return uffd_zero(lpi, address, nr); if (opts.use_page_server) - ret = get_remote_pages(lpi->pid, address, 1, lpi->buf); + ret = get_remote_pages(lpi->pid, address, nr, lpi->buf); else - ret = lpi->pr.read_pages(&lpi->pr, address, 1, lpi->buf, 0); + ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, 0); if (ret <= 0) { pr_err("%d: failed reading pages at %llx\n", lpi->pid, address); return ret; } - return uffd_copy(lpi, address, 1); + return uffd_copy(lpi, address, nr); } static int handle_remaining_pages(struct lazy_pages_info *lpi) @@ -606,7 +606,7 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) for (i = 0; i < nr_pages; i++) { addr = lazy_iov->base + i * PAGE_SIZE; - err = uffd_handle_page(lpi, addr); + err = uffd_handle_pages(lpi, addr, 1); if (err < 0) { pr_err("Error during UFFD copy\n"); return -1; @@ -617,17 +617,18 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) return 0; } -static int handle_regular_pages(struct lazy_pages_info *lpi, __u64 address) +static int handle_regular_pages(struct lazy_pages_info *lpi, __u64 address, + int nr) { int rc; - rc = uffd_handle_page(lpi, address); + rc = uffd_handle_pages(lpi, address, nr); if (rc < 0) { pr_err("Error during UFFD copy\n"); return -1; } - rc = update_lazy_iovecs(lpi, address, PAGE_SIZE); + rc = update_lazy_iovecs(lpi, address, PAGE_SIZE * nr); if (rc < 0) return -1; @@ -670,7 +671,7 @@ static int handle_user_fault(struct lazy_pages_fd *lpfd) flags = msg.arg.pagefault.flags; pr_debug("msg.arg.pagefault.flags 0x%llx\n", flags); - ret = handle_regular_pages(lpi, address); + ret = handle_regular_pages(lpi, address, 1); if (ret < 0) { pr_err("Error during regular page copy\n"); return -1; From 20d7eb4c56c84c7f90d4e8869e3ae21fce3ad8ac Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:19 +0200 Subject: [PATCH 0814/4375] criu: lazy-pages: copy remaining IOVs in chunks travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 426a18d85..518ae5ccf 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -595,22 +595,17 @@ static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr) static int handle_remaining_pages(struct lazy_pages_info *lpi) { struct lazy_iovec *lazy_iov; - int nr_pages, i, err; - unsigned long addr; + int nr_pages, err; lpi->pr.reset(&lpi->pr); list_for_each_entry(lazy_iov, &lpi->iovs, l) { nr_pages = lazy_iov->len / PAGE_SIZE; - for (i = 0; i < nr_pages; i++) { - addr = lazy_iov->base + i * PAGE_SIZE; - - err = uffd_handle_pages(lpi, addr, 1); - if (err < 0) { - pr_err("Error during UFFD copy\n"); - return -1; - } + err = uffd_handle_pages(lpi, lazy_iov->base, nr_pages); + if (err < 0) { + pr_err("Error during UFFD copy\n"); + return -1; } } From c23b83ce3a4acd4943fdbf188c86e1c49e0be8ef Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:20 +0200 Subject: [PATCH 0815/4375] criu: page-xfer: get_remote_page: respect nr_pages parameter travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/page-xfer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index aedb142b9..af02a3468 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -953,6 +953,7 @@ out: int get_remote_pages(int pid, unsigned long addr, int nr_pages, void *dest) { int ret; + int len = PAGE_SIZE * nr_pages; struct page_server_iov pi; @@ -972,8 +973,8 @@ int get_remote_pages(int pid, unsigned long addr, int nr_pages, void *dest) if (pi.nr_pages > nr_pages) return -1; - ret = recv(page_server_sk, dest, PAGE_SIZE, MSG_WAITALL); - if (ret != PAGE_SIZE) + ret = recv(page_server_sk, dest, len, MSG_WAITALL); + if (ret != len) return -1; return 1; From b72d5f2dca3093f81ac0fccb7e2d2d4b49330634 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:21 +0200 Subject: [PATCH 0816/4375] lazy-pages: extend the page_read with ability to read remote pages Currently lazy-pages daemon uses either pr->read_pages or get_remote_pages to get actual page data from local images or remote server. From now on, page_read will be completely responsible for getting the page data. travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/pagemap.h | 6 +++++- criu/pagemap.c | 38 +++++++++++++++++++++++++++++++------- criu/uffd.c | 11 +++++------ 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index 00479f069..22314d710 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -53,6 +53,8 @@ struct page_read { int (*sync)(struct page_read *pr); int (*seek_pagemap)(struct page_read *pr, unsigned long vaddr); void (*reset)(struct page_read *pr); + int (*maybe_read_page)(struct page_read *pr, unsigned long vaddr, + int nr, void *buf, unsigned flags); /* Whether or not pages can be read in PIE code */ bool pieok; @@ -72,7 +74,8 @@ struct page_read { struct iovec bunch; /* record consequent neighbour iovecs to punch together */ - unsigned id; /* for logging */ + unsigned id; /* for logging */ + int pid; /* PID of the process */ PagemapEntry **pmes; int nr_pmes; @@ -90,6 +93,7 @@ struct page_read { #define PR_TYPE_MASK 0x3 #define PR_MOD 0x4 /* Will need to modify */ +#define PR_REMOTE 0x8 /* * -1 -- error diff --git a/criu/pagemap.c b/criu/pagemap.c index 7b119f774..3f53d69d3 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -12,6 +12,8 @@ #include "pagemap.h" #include "restorer.h" #include "rst-malloc.h" +#include "page-xfer.h" + #include "fault-injection.h" #include "xmalloc.h" #include "protobuf.h" @@ -393,8 +395,8 @@ int pagemap_enqueue_iovec(struct page_read *pr, void *buf, return 0; } -static int maybe_read_page(struct page_read *pr, unsigned long vaddr, - int nr, void *buf, unsigned flags) +static int maybe_read_page_local(struct page_read *pr, unsigned long vaddr, + int nr, void *buf, unsigned flags) { int ret; unsigned long len = nr * PAGE_SIZE; @@ -409,6 +411,19 @@ static int maybe_read_page(struct page_read *pr, unsigned long vaddr, return ret; } +static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, + int nr, void *buf, unsigned flags) +{ + int ret; + + if (flags & PR_ASYNC) + ret = -1; /* not yet supported */ + else + ret = get_remote_pages(pr->pid, vaddr, nr, buf); + + return ret; +} + static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, int nr, void *buf, unsigned flags) { @@ -422,7 +437,7 @@ static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, int nr, /* zero mappings should be skipped by get_pagemap */ BUG(); } else { - if (maybe_read_page(pr, vaddr, nr, buf, flags) < 0) + if (pr->maybe_read_page(pr, vaddr, nr, buf, flags) < 0) return -1; } @@ -678,6 +693,7 @@ int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) { int flags, i_typ; static unsigned ids = 1; + bool remote = pr_flags & PR_REMOTE; if (opts.auto_dedup) pr_flags |= PR_MOD; @@ -741,11 +757,19 @@ int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) pr->seek_pagemap = seek_pagemap; pr->reset = reset_pagemap; pr->id = ids++; - if (!pr->parent) - pr->pieok = true; + pr->pid = pid; - pr_debug("Opened page read %u (parent %u)\n", - pr->id, pr->parent ? pr->parent->id : 0); + if (remote) + pr->maybe_read_page = maybe_read_page_remote; + else { + pr->maybe_read_page = maybe_read_page_local; + if (!pr->parent && !opts.lazy_pages) + pr->pieok = true; + } + + pr_debug("Opened %s page read %u (parent %u)\n", + remote ? "remote" : "local", pr->id, + pr->parent ? pr->parent->id : 0); return 1; } diff --git a/criu/uffd.c b/criu/uffd.c index 518ae5ccf..58d1d3b4b 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -452,6 +452,7 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) struct lazy_pages_info *lpi; int ret = -1; int uffd_flags; + int pr_flags = PR_TASK; lpi = lpi_init(); if (!lpi) @@ -485,7 +486,9 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) uffd_flags = fcntl(lpi->lpfd.fd, F_GETFD, NULL); pr_debug("uffd_flags are 0x%x\n", uffd_flags); - ret = open_page_read(lpi->pid, &lpi->pr, PR_TASK); + if (opts.use_page_server) + pr_flags |= PR_REMOTE; + ret = open_page_read(lpi->pid, &lpi->pr, pr_flags); if (ret <= 0) { ret = -1; goto out; @@ -579,11 +582,7 @@ static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr) if (pagemap_zero(lpi->pr.pe)) return uffd_zero(lpi, address, nr); - if (opts.use_page_server) - ret = get_remote_pages(lpi->pid, address, nr, lpi->buf); - else - ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, 0); - + ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, 0); if (ret <= 0) { pr_err("%d: failed reading pages at %llx\n", lpi->pid, address); return ret; From c907796dc6a1e91fe999b1ced37e067fdba6bee8 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:22 +0200 Subject: [PATCH 0817/4375] lazy-pages: make uffd_{copy,zero} return 0 on success In early days of uffd.c return value from uffd_copy was used to count transferred pages. Since this is not the case anymore we can use 0 as success. travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 58d1d3b4b..afad95208 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -544,7 +544,7 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) lpi->copied_pages += nr_pages; - return uffdio_copy.copy; + return 0; } static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) @@ -566,7 +566,7 @@ static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) return -1; } - return len; + return 0; } static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr) From 57d341f1056c53225fc1a2cfe6fb0ce6ea6959e8 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:23 +0200 Subject: [PATCH 0818/4375] page-xfer: make connect_to_page_server return socket fd It will used by lazy-pages daemon to enable polling for reception of page data from remote dump travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-dump.c | 4 ++-- criu/page-xfer.c | 2 +- criu/uffd.c | 13 ++++++++++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 47e8cf95f..37084f0e8 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1565,7 +1565,7 @@ int cr_pre_dump_tasks(pid_t pid) if (vdso_init()) goto err; - if (connect_to_page_server()) + if (connect_to_page_server() < 0) goto err; if (setup_alarm_handler()) @@ -1761,7 +1761,7 @@ int cr_dump_tasks(pid_t pid) goto err; } - if (connect_to_page_server()) + if (connect_to_page_server() < 0) goto err; if (setup_alarm_handler()) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index af02a3468..41aea4ee5 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -906,7 +906,7 @@ out: * on urgent data is the smartest mode ever. */ tcp_cork(page_server_sk, true); - return 0; + return page_server_sk; } int disconnect_from_page_server(void) diff --git a/criu/uffd.c b/criu/uffd.c index afad95208..cec4c214d 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -847,6 +847,17 @@ close_uffd: return -1; } +static int prepare_page_server_socket(void) +{ + int sk; + + sk = connect_to_page_server(); + if (sk < 0) + return -1; + + return 0; +} + int cr_lazy_pages(bool daemon) { struct epoll_event *events; @@ -894,7 +905,7 @@ int cr_lazy_pages(bool daemon) if (prepare_uffds(lazy_sk, epollfd)) return -1; - if (connect_to_page_server()) + if (prepare_page_server_socket()) return -1; ret = handle_requests(epollfd, events); From 250448559f94a067ede11b602ee0a84cd225b5e3 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:24 +0200 Subject: [PATCH 0819/4375] page-xfer: add methods for requesting and receiving remote pages For asynchrounous page transfers in post-copy migration we need to be able to request a remote pages, receive back information about the data is going to arrive and receive the page data itself. travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/page-xfer.h | 17 +++++++++++++++ criu/page-xfer.c | 45 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index fdda10519..7cd00553d 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -42,6 +42,23 @@ extern int disconnect_from_page_server(void); extern int check_parent_page_xfer(int fd_type, long id); +/* + * The post-copy migration makes it necessary to receive pages from + * remote dump. The protocol we use for that is quite simple: + * - lazy-pages sedns request containing PS_IOV_GET(nr_pages, vaddr, pid) + * - dump-side page server responds with PS_IOV_ADD(nr_pages, vaddr, + pid) or PS_IOV_ADD(0, 0, 0) if it failed to locate the required + pages + * - dump-side page server sends the raw page data + */ + +/* sync receive of remote pages */ extern int get_remote_pages(int pid, unsigned long addr, int nr_pages, void *dest); +/* async request/receive of remote pages */ +extern int request_remote_pages(int pid, unsigned long addr, int nr_pages); +extern int receive_remote_pages_info(int *nr_pages, unsigned long *addr, int *pid); +extern int receive_remote_pages(int len, void *buf); + + #endif /* __CR_PAGE_XFER__H__ */ diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 41aea4ee5..2c89ded8a 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -979,3 +979,48 @@ int get_remote_pages(int pid, unsigned long addr, int nr_pages, void *dest) return 1; } + +int request_remote_pages(int pid, unsigned long addr, int nr_pages) +{ + struct page_server_iov pi = { + .cmd = PS_IOV_GET, + .nr_pages = nr_pages, + .vaddr = addr, + .dst_id = pid, + }; + + /* We cannot use send_psi here because we have to use MSG_DONTWAIT */ + if (send(page_server_sk, &pi, sizeof(pi), MSG_DONTWAIT) != sizeof(pi)) { + pr_perror("Can't write PSI to server"); + return -1; + } + + tcp_nodelay(page_server_sk, true); + return 0; +} + +int receive_remote_pages_info(int *nr_pages, unsigned long *addr, int *pid) +{ + struct page_server_iov pi; + + if (recv(page_server_sk, &pi, sizeof(pi), MSG_WAITALL) != sizeof(pi)) { + pr_perror("Failed to receive page metadata"); + return -1; + } + + *nr_pages = pi.nr_pages; + *addr = pi.vaddr; + *pid = pi.dst_id; + + return 0; +} + +int receive_remote_pages(int len, void *buf) +{ + if (recv(page_server_sk, buf, len, MSG_WAITALL) != len) { + pr_perror("Failed to receive page data"); + return -1; + } + + return 0; +} From d4edd9bf566b5e90d848667e64f0863d6c978bd4 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:25 +0200 Subject: [PATCH 0820/4375] lazy-pages: introduce uffd_seek_or_zero_pages This part of code is responsible for reseting pagemap to proper locatation, and mapping requested address to zero pfn if needed. The upcoming addtions to uffd.c will reuse this code. travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index cec4c214d..e4d2a780a 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -569,7 +569,17 @@ static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) return 0; } -static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr) +/* + * Seek for the requested address in the pagemap. If it is found, the + * subsequent call to pr->page_read will bring us the data. If the + * address is not found in the pagemap, but no error occured, the + * address should be mapped to zero pfn. + * + * Returns 0 for zero pages, 1 for "real" pages and negative value on + * error + */ +static int uffd_seek_or_zero_pages(struct lazy_pages_info *lpi, __u64 address, + int nr) { int ret; @@ -582,6 +592,17 @@ static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr) if (pagemap_zero(lpi->pr.pe)) return uffd_zero(lpi, address, nr); + return 1; +} + +static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr) +{ + int ret; + + ret = uffd_seek_or_zero_pages(lpi, address, nr); + if (ret <= 0) + return ret; + ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, 0); if (ret <= 0) { pr_err("%d: failed reading pages at %llx\n", lpi->pid, address); From 9537433fae8ae52aa7f2b01572a1b26543ba40c3 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:26 +0200 Subject: [PATCH 0821/4375] pagemap: add ability to request remote pages The asynchronous version of remote page_read will send the request to the dump side and return happily. The response will be handled by the uffd.c because it's epoll loop is the only place where we can handle events. travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/pagemap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/criu/pagemap.c b/criu/pagemap.c index 3f53d69d3..76e27884e 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -417,7 +417,11 @@ static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, int ret; if (flags & PR_ASYNC) - ret = -1; /* not yet supported */ + /* + * Note, that for async remote page_read, the actual + * transfer happens in the lazy-pages daemon + */ + ret = request_remote_pages(pr->pid, vaddr, len / PAGE_SIZE); else ret = get_remote_pages(pr->pid, vaddr, nr, buf); From 0b27e6520e0a17ab65e611cfc7f2c4d6dd7e5feb Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:27 +0200 Subject: [PATCH 0822/4375] lazy-pages: implement semi-async remote page transfer The synchronous remote page transfer prevents reception of uffd events during the communications with the page server on the dump side. Adding socket file descriptor to epoll_wait allows processing of incoming uffd events after non-blocking request for remote page is issued and before the dump side page server replies. travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 110 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 94 insertions(+), 16 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index e4d2a780a..1a4d4e15b 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -110,6 +110,25 @@ static void lpi_fini(struct lazy_pages_info *lpi) free(lpi); } +static struct lazy_pages_info *pid2lpi(int pid) +{ + struct lazy_pages_info *lpi; + + list_for_each_entry(lpi, &lpis, l) { + if (lpi->pid == pid) + return lpi; + } + + return NULL; +} + +static int epoll_nr_fds(int nr_tasks) +{ + if (opts.use_page_server) + return nr_tasks + 1; + return nr_tasks; +} + static int prepare_sock_addr(struct sockaddr_un *saddr) { int len; @@ -632,24 +651,45 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) return 0; } -static int handle_regular_pages(struct lazy_pages_info *lpi, __u64 address, - int nr) +static int page_fault_common(struct lazy_pages_info *lpi, __u64 address, int nr, + int pr_flags) { - int rc; + int ret; - rc = uffd_handle_pages(lpi, address, nr); - if (rc < 0) { - pr_err("Error during UFFD copy\n"); - return -1; + ret = uffd_seek_or_zero_pages(lpi, address, nr); + if (ret <= 0) + return ret; + + ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, pr_flags); + if (ret <= 0) { + pr_err("%d: failed reading pages at %llx\n", lpi->pid, address); + return ret; } - rc = update_lazy_iovecs(lpi, address, PAGE_SIZE * nr); - if (rc < 0) + return 0; +} + +static int page_fault_local(struct lazy_pages_info *lpi, __u64 address, int nr) +{ + if (page_fault_common(lpi, address, nr, 0)) + return -1; + + if (uffd_copy(lpi, address, nr)) + return -1; + + if (update_lazy_iovecs(lpi, address, PAGE_SIZE * nr)) return -1; return 0; } +static int page_fault_remote(struct lazy_pages_info *lpi, __u64 address, int nr) +{ + return page_fault_common(lpi, address, nr, PR_ASYNC); +} + +static int (*pf_handler)(struct lazy_pages_info *lpi, __u64 address, int nr); + static int handle_user_fault(struct lazy_pages_fd *lpfd) { struct lazy_pages_info *lpi; @@ -686,7 +726,7 @@ static int handle_user_fault(struct lazy_pages_fd *lpfd) flags = msg.arg.pagefault.flags; pr_debug("msg.arg.pagefault.flags 0x%llx\n", flags); - ret = handle_regular_pages(lpi, address, 1); + ret = pf_handler(lpi, address, 1); if (ret < 0) { pr_err("Error during regular page copy\n"); return -1; @@ -714,7 +754,7 @@ static int lazy_pages_summary(struct lazy_pages_info *lpi) static int handle_requests(int epollfd, struct epoll_event *events) { - int nr_fds = task_entries->nr_tasks; + int nr_fds = epoll_nr_fds(task_entries->nr_tasks); struct lazy_pages_info *lpi; int ret = -1; int i; @@ -868,7 +908,36 @@ close_uffd: return -1; } -static int prepare_page_server_socket(void) +static int page_server_event(struct lazy_pages_fd *lpfd) +{ + struct lazy_pages_info *lpi; + int pid, nr_pages; + unsigned long addr; + + if (receive_remote_pages_info(&nr_pages, &addr, &pid)) + return -1; + + lpi = pid2lpi(pid); + if (!lpi) + return -1; + + if (receive_remote_pages(nr_pages * PAGE_SIZE, lpi->buf)) + return -1; + + if (uffd_copy(lpi, addr, nr_pages)) + return -1; + + if (update_lazy_iovecs(lpi, addr, PAGE_SIZE * nr_pages)) + return -1; + + return 0; +} + +static struct lazy_pages_fd page_server_sk_fd = { + .event = page_server_event, +}; + +static int prepare_page_server_socket(int epollfd) { int sk; @@ -876,13 +945,16 @@ static int prepare_page_server_socket(void) if (sk < 0) return -1; - return 0; + page_server_sk_fd.fd = sk; + + return epoll_add_lpfd(epollfd, &page_server_sk_fd); } int cr_lazy_pages(bool daemon) { struct epoll_event *events; int epollfd; + int nr_fds; int lazy_sk; int ret; @@ -919,15 +991,21 @@ int cr_lazy_pages(bool daemon) if (close_status_fd()) return -1; - epollfd = prepare_epoll(task_entries->nr_tasks, &events); + nr_fds = epoll_nr_fds(task_entries->nr_tasks); + epollfd = prepare_epoll(nr_fds, &events); if (epollfd < 0) return -1; if (prepare_uffds(lazy_sk, epollfd)) return -1; - if (prepare_page_server_socket()) - return -1; + if (opts.use_page_server) { + if (prepare_page_server_socket(epollfd)) + return -1; + pf_handler = page_fault_remote; + } else { + pf_handler = page_fault_local; + } ret = handle_requests(epollfd, events); From 4d9d7ae7e561595d8d6d5da35a9c6f7f94629e58 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Nov 2016 18:57:28 +0200 Subject: [PATCH 0823/4375] lazy-pages: unblock second receive in page_server_event The page transfer protocol is completely synchronous on the dump side, therefore we can presume that when we get POLLIN event on the page server socket it is either page info response for the last sent page request or the page data following the last page info. In the first case we set ev_data associated with page server socket events to values received in receive_remote_page_info and in the second case we reset ev_data to zero. This allows us to distinguish what was the reason page_server_event have been called. travis-ci: success for uffd: A new set of improvements Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 61 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 1a4d4e15b..4f366fd89 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -53,9 +53,18 @@ struct lazy_iovec { unsigned long len; }; +struct lazy_pages_info; + +struct sk_event_data { + int nr_pages; + unsigned long addr; + struct lazy_pages_info *lpi; +}; + struct lazy_pages_fd { int fd; int (*event)(struct lazy_pages_fd *); + struct sk_event_data *ev_data; }; struct lazy_pages_info { @@ -908,33 +917,61 @@ close_uffd: return -1; } +/* + * There are two possible event types we need to handle: + * - page info is available as a reply to request_remote_page + * - page data is available, and it follows page info we've just received + * Since the on dump side communications are completely synchronous, + * we can return to epoll right after the reception of page info and + * for sure the next time socket event will occur we'll get page data + * related to info we've just received + */ static int page_server_event(struct lazy_pages_fd *lpfd) { struct lazy_pages_info *lpi; int pid, nr_pages; unsigned long addr; - if (receive_remote_pages_info(&nr_pages, &addr, &pid)) - return -1; + lpi = lpfd->ev_data->lpi; - lpi = pid2lpi(pid); - if (!lpi) - return -1; + if (!lpi) { + if (receive_remote_pages_info(&nr_pages, &addr, &pid)) + return -1; - if (receive_remote_pages(nr_pages * PAGE_SIZE, lpi->buf)) - return -1; + lpi = pid2lpi(pid); + if (!lpi) + return -1; - if (uffd_copy(lpi, addr, nr_pages)) - return -1; + lpfd->ev_data->lpi = lpi; + lpfd->ev_data->nr_pages = nr_pages; + lpfd->ev_data->addr = addr; - if (update_lazy_iovecs(lpi, addr, PAGE_SIZE * nr_pages)) - return -1; + return 0; + } else { + lpi = lpfd->ev_data->lpi; + nr_pages = lpfd->ev_data->nr_pages; + addr = lpfd->ev_data->addr; - return 0; + memset(lpfd->ev_data, 0, sizeof(*lpfd->ev_data)); + + if (receive_remote_pages(nr_pages * PAGE_SIZE, lpi->buf)) + return -1; + + if (uffd_copy(lpi, addr, nr_pages)) + return -1; + + if (update_lazy_iovecs(lpi, addr, PAGE_SIZE * nr_pages)) + return -1; + + return 0; + } } +static struct sk_event_data sk_event_data; + static struct lazy_pages_fd page_server_sk_fd = { .event = page_server_event, + .ev_data = &sk_event_data, }; static int prepare_page_server_socket(int epollfd) From edf5809f57a0e105a85c38383be82af97030ef0e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Nov 2016 12:38:40 +0300 Subject: [PATCH 0824/4375] page-read: Only the top-most can be remote All the "lower" page-read-s should have already arrived with pre-dump. This fixes the combined scheme. Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/pagemap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/criu/pagemap.c b/criu/pagemap.c index 76e27884e..51639a4c5 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -699,6 +699,11 @@ int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) static unsigned ids = 1; bool remote = pr_flags & PR_REMOTE; + /* + * Only the top-most page-read can be remote, all the + * others are always local. + */ + pr_flags &= ~PR_REMOTE; if (opts.auto_dedup) pr_flags |= PR_MOD; if (pr_flags & PR_MOD) From 275f81bcb532e1c99e78729ce00db732ba1ccbc6 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Nov 2016 12:39:08 +0300 Subject: [PATCH 0825/4375] page-read: Drop get_remote_pages We already have routines that do send-req, recv-info and recv-page, so no need in yet another one. Signed-off-by: Pavel Emelyanov --- criu/include/page-xfer.h | 3 --- criu/page-xfer.c | 34 ++++------------------------------ criu/pagemap.c | 21 ++++++++++++--------- 3 files changed, 16 insertions(+), 42 deletions(-) diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index 7cd00553d..5b7ec21f2 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -52,9 +52,6 @@ extern int check_parent_page_xfer(int fd_type, long id); * - dump-side page server sends the raw page data */ -/* sync receive of remote pages */ -extern int get_remote_pages(int pid, unsigned long addr, int nr_pages, void *dest); - /* async request/receive of remote pages */ extern int request_remote_pages(int pid, unsigned long addr, int nr_pages); extern int receive_remote_pages_info(int *nr_pages, unsigned long *addr, int *pid); diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 2c89ded8a..f0da4e34c 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -950,36 +950,6 @@ out: return ret ? : status; } -int get_remote_pages(int pid, unsigned long addr, int nr_pages, void *dest) -{ - int ret; - int len = PAGE_SIZE * nr_pages; - - struct page_server_iov pi; - - if (send_psi(page_server_sk, PS_IOV_GET, nr_pages, addr, pid)) - return -1; - - tcp_nodelay(page_server_sk, true); - - ret = recv(page_server_sk, &pi, sizeof(pi), MSG_WAITALL); - if (ret != sizeof(pi)) - return -1; - - /* zero page */ - if (pi.cmd == PS_IOV_ZERO) - return 0; - - if (pi.nr_pages > nr_pages) - return -1; - - ret = recv(page_server_sk, dest, len, MSG_WAITALL); - if (ret != len) - return -1; - - return 1; -} - int request_remote_pages(int pid, unsigned long addr, int nr_pages) { struct page_server_iov pi = { @@ -1008,6 +978,10 @@ int receive_remote_pages_info(int *nr_pages, unsigned long *addr, int *pid) return -1; } + if (pi.cmd == PS_IOV_ZERO) + pr_warn("Unexpected ZERO page received for %d.%lx\n", + (int)pi.dst_id, (unsigned long)pi.vaddr); + *nr_pages = pi.nr_pages; *addr = pi.vaddr; *pid = pi.dst_id; diff --git a/criu/pagemap.c b/criu/pagemap.c index 51639a4c5..16958acfd 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -414,16 +414,19 @@ static int maybe_read_page_local(struct page_read *pr, unsigned long vaddr, static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, int nr, void *buf, unsigned flags) { - int ret; + int ret, pid; - if (flags & PR_ASYNC) - /* - * Note, that for async remote page_read, the actual - * transfer happens in the lazy-pages daemon - */ - ret = request_remote_pages(pr->pid, vaddr, len / PAGE_SIZE); - else - ret = get_remote_pages(pr->pid, vaddr, nr, buf); + ret = request_remote_pages(pr->pid, vaddr, nr); + if ((ret < 0) || (flags & PR_ASYNC)) + return ret; + + /* + * Note, that for async remote page_read, the actual + * transfer happens in the lazy-pages daemon + */ + ret = receive_remote_pages_info(&nr, &vaddr, &pid); + if (ret == 0) + ret = receive_remote_pages(nr * PAGE_SIZE, buf); return ret; } From eb0e0426661a17525dbbfcd68c034e00067d9300 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Nov 2016 12:39:22 +0300 Subject: [PATCH 0826/4375] page-read: Introduce PR_ASAP flag for read_pages This flag means, that the PR_ASYNC is valid, but the IO should be started ASAP. This is how remote reader works, so this flag is mostly for the local reader. It will let us unify page-fault handlers for local and remote cases. Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/include/pagemap.h | 1 + criu/pagemap.c | 9 ++++++++- criu/uffd.c | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index 22314d710..580c9b5ab 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -86,6 +86,7 @@ struct page_read { /* flags for ->read_pages */ #define PR_ASYNC 0x1 /* may exit w/o data in the buffer */ +#define PR_ASAP 0x2 /* PR_ASYNC, but start the IO right now */ /* flags for open_page_read */ #define PR_SHMEM 0x1 diff --git a/criu/pagemap.c b/criu/pagemap.c index 16958acfd..31e78b332 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -401,7 +401,13 @@ static int maybe_read_page_local(struct page_read *pr, unsigned long vaddr, int ret; unsigned long len = nr * PAGE_SIZE; - if (flags & PR_ASYNC) + /* + * There's no API in the kernel to start asynchronous + * cached read (or write), so in case someone is asking + * for us for urgent async read, just do the regular + * cached read. + */ + if ((flags & (PR_ASYNC|PR_ASAP)) == PR_ASYNC) ret = pagemap_enqueue_iovec(pr, buf, len, &pr->async); else ret = read_local_page(pr, vaddr, len, buf); @@ -416,6 +422,7 @@ static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, { int ret, pid; + /* We always do PR_ASAP mode here (FIXME?) */ ret = request_remote_pages(pr->pid, vaddr, nr); if ((ret < 0) || (flags & PR_ASYNC)) return ret; diff --git a/criu/uffd.c b/criu/uffd.c index 4f366fd89..23bbced97 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -680,7 +680,7 @@ static int page_fault_common(struct lazy_pages_info *lpi, __u64 address, int nr, static int page_fault_local(struct lazy_pages_info *lpi, __u64 address, int nr) { - if (page_fault_common(lpi, address, nr, 0)) + if (page_fault_common(lpi, address, nr, PR_ASYNC | PR_ASAP)) return -1; if (uffd_copy(lpi, address, nr)) @@ -694,7 +694,7 @@ static int page_fault_local(struct lazy_pages_info *lpi, __u64 address, int nr) static int page_fault_remote(struct lazy_pages_info *lpi, __u64 address, int nr) { - return page_fault_common(lpi, address, nr, PR_ASYNC); + return page_fault_common(lpi, address, nr, PR_ASYNC | PR_ASAP); } static int (*pf_handler)(struct lazy_pages_info *lpi, __u64 address, int nr); From c9d374bb0149569a5836e2d57fd78d10d0c8ed5b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Nov 2016 12:39:35 +0300 Subject: [PATCH 0827/4375] uffd: Helper to complete the #PF The _copy and _update_lazy_iovecs are both called by hands once the data is ready. Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/uffd.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 23bbced97..6557ce97e 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -82,6 +82,7 @@ struct lazy_pages_info { struct list_head l; void *buf; + bool remaining; }; static LIST_HEAD(lpis); @@ -575,6 +576,17 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) return 0; } +static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long vaddr, int nr) +{ + if (uffd_copy(lpi, vaddr, nr)) + return -1; + + if (lpi->remaining) + return 0; + + return update_lazy_iovecs(lpi, vaddr, nr * PAGE_SIZE); +} + static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) { struct uffdio_zeropage uffdio_zeropage; @@ -637,7 +649,7 @@ static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr) return ret; } - return uffd_copy(lpi, address, nr); + return complete_page_fault(lpi, address, nr); } static int handle_remaining_pages(struct lazy_pages_info *lpi) @@ -645,6 +657,8 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) struct lazy_iovec *lazy_iov; int nr_pages, err; + lpi->remaining = true; + lpi->pr.reset(&lpi->pr); list_for_each_entry(lazy_iov, &lpi->iovs, l) { @@ -683,13 +697,7 @@ static int page_fault_local(struct lazy_pages_info *lpi, __u64 address, int nr) if (page_fault_common(lpi, address, nr, PR_ASYNC | PR_ASAP)) return -1; - if (uffd_copy(lpi, address, nr)) - return -1; - - if (update_lazy_iovecs(lpi, address, PAGE_SIZE * nr)) - return -1; - - return 0; + return complete_page_fault(lpi, address, nr); } static int page_fault_remote(struct lazy_pages_info *lpi, __u64 address, int nr) @@ -957,13 +965,7 @@ static int page_server_event(struct lazy_pages_fd *lpfd) if (receive_remote_pages(nr_pages * PAGE_SIZE, lpi->buf)) return -1; - if (uffd_copy(lpi, addr, nr_pages)) - return -1; - - if (update_lazy_iovecs(lpi, addr, PAGE_SIZE * nr_pages)) - return -1; - - return 0; + return complete_page_fault(lpi, addr, nr_pages); } } From 76bf7d4571213094baa1ffceefc1650b0ade7d77 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Nov 2016 12:39:48 +0300 Subject: [PATCH 0828/4375] page-read: Callback on io completion This one is called by PR once IO is complete (right now for sync cases only, more work is required here) and lets us unify local and remote PF code in uffd. Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/include/pagemap.h | 1 + criu/pagemap.c | 11 ++++++++++- criu/uffd.c | 19 ++++++++++++++----- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index 580c9b5ab..549e9d388 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -53,6 +53,7 @@ struct page_read { int (*sync)(struct page_read *pr); int (*seek_pagemap)(struct page_read *pr, unsigned long vaddr); void (*reset)(struct page_read *pr); + int (*io_complete)(struct page_read *, unsigned long vaddr, int nr); int (*maybe_read_page)(struct page_read *pr, unsigned long vaddr, int nr, void *buf, unsigned flags); diff --git a/criu/pagemap.c b/criu/pagemap.c index 31e78b332..9118ead10 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -409,8 +409,11 @@ static int maybe_read_page_local(struct page_read *pr, unsigned long vaddr, */ if ((flags & (PR_ASYNC|PR_ASAP)) == PR_ASYNC) ret = pagemap_enqueue_iovec(pr, buf, len, &pr->async); - else + else { ret = read_local_page(pr, vaddr, len, buf); + if (ret == 0 && pr->io_complete) + ret = pr->io_complete(pr, vaddr, nr); + } pr->pi_off += len; @@ -435,6 +438,9 @@ static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, if (ret == 0) ret = receive_remote_pages(nr * PAGE_SIZE, buf); + if (ret == 0 && pr->io_complete) + ret = pr->io_complete(pr, vaddr, nr); + return ret; } @@ -546,6 +552,8 @@ more: if (opts.auto_dedup && punch_hole(pr, start, ret, false)) return -1; + BUG_ON(pr->io_complete); /* FIXME -- implement once needed */ + list_del(&piov->l); xfree(iovs); xfree(piov); @@ -775,6 +783,7 @@ int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) pr->sync = process_async_reads; pr->seek_pagemap = seek_pagemap; pr->reset = reset_pagemap; + pr->io_complete = NULL; /* set up by the client if needed */ pr->id = ids++; pr->pid = pid; diff --git a/criu/uffd.c b/criu/uffd.c index 6557ce97e..0a7bb7e5a 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -476,6 +476,8 @@ free_mm: return ret; } +static int uffd_io_complete(struct page_read *pr, unsigned long vaddr, int nr); + static int ud_open(int client, struct lazy_pages_info **_lpi) { struct lazy_pages_info *lpi; @@ -523,6 +525,8 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) goto out; } + lpi->pr.io_complete = uffd_io_complete; + /* * Find the memory pages belonging to the restored process * so that it is trackable when all pages have been transferred. @@ -587,6 +591,14 @@ static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long vaddr, return update_lazy_iovecs(lpi, vaddr, nr * PAGE_SIZE); } +static int uffd_io_complete(struct page_read *pr, unsigned long vaddr, int nr) +{ + struct lazy_pages_info *lpi; + + lpi = container_of(pr, struct lazy_pages_info, pr); + return complete_page_fault(lpi, vaddr, nr); +} + static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) { struct uffdio_zeropage uffdio_zeropage; @@ -649,7 +661,7 @@ static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr) return ret; } - return complete_page_fault(lpi, address, nr); + return 0; } static int handle_remaining_pages(struct lazy_pages_info *lpi) @@ -694,10 +706,7 @@ static int page_fault_common(struct lazy_pages_info *lpi, __u64 address, int nr, static int page_fault_local(struct lazy_pages_info *lpi, __u64 address, int nr) { - if (page_fault_common(lpi, address, nr, PR_ASYNC | PR_ASAP)) - return -1; - - return complete_page_fault(lpi, address, nr); + return page_fault_common(lpi, address, nr, PR_ASYNC | PR_ASAP); } static int page_fault_remote(struct lazy_pages_info *lpi, __u64 address, int nr) From adea705b29e4ddc6ce2a918ed875fd0ad0697c51 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Nov 2016 12:40:03 +0300 Subject: [PATCH 0829/4375] uffd: Unify local and remote PF handlers Finally, page_fault_local and page_fault_remote are absolutely identical, so we can just merge them. Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/uffd.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 0a7bb7e5a..f0bf77f71 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -686,8 +686,7 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) return 0; } -static int page_fault_common(struct lazy_pages_info *lpi, __u64 address, int nr, - int pr_flags) +static int handle_page_fault(struct lazy_pages_info *lpi, __u64 address, int nr) { int ret; @@ -695,7 +694,7 @@ static int page_fault_common(struct lazy_pages_info *lpi, __u64 address, int nr, if (ret <= 0) return ret; - ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, pr_flags); + ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, PR_ASYNC | PR_ASAP); if (ret <= 0) { pr_err("%d: failed reading pages at %llx\n", lpi->pid, address); return ret; @@ -704,18 +703,6 @@ static int page_fault_common(struct lazy_pages_info *lpi, __u64 address, int nr, return 0; } -static int page_fault_local(struct lazy_pages_info *lpi, __u64 address, int nr) -{ - return page_fault_common(lpi, address, nr, PR_ASYNC | PR_ASAP); -} - -static int page_fault_remote(struct lazy_pages_info *lpi, __u64 address, int nr) -{ - return page_fault_common(lpi, address, nr, PR_ASYNC | PR_ASAP); -} - -static int (*pf_handler)(struct lazy_pages_info *lpi, __u64 address, int nr); - static int handle_user_fault(struct lazy_pages_fd *lpfd) { struct lazy_pages_info *lpi; @@ -752,7 +739,7 @@ static int handle_user_fault(struct lazy_pages_fd *lpfd) flags = msg.arg.pagefault.flags; pr_debug("msg.arg.pagefault.flags 0x%llx\n", flags); - ret = pf_handler(lpi, address, 1); + ret = handle_page_fault(lpi, address, 1); if (ret < 0) { pr_err("Error during regular page copy\n"); return -1; @@ -1050,9 +1037,6 @@ int cr_lazy_pages(bool daemon) if (opts.use_page_server) { if (prepare_page_server_socket(epollfd)) return -1; - pf_handler = page_fault_remote; - } else { - pf_handler = page_fault_local; } ret = handle_requests(epollfd, events); From 479c778a2429415dd3aa3b7cfc47fb3732656b5e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Nov 2016 16:19:49 +0300 Subject: [PATCH 0830/4375] page-xfer: Introduce fully asynchronous read Add a queue of async-read jobs into page-xfer. When the page_server_sk gets a read event from epoll it reads as many bytes into page_server_iov + page buffer as recv allows and returns. Once the full iov+data is ready the requestor is notified and the next async read is started. This patch removes calls to recv(...MSG_WAITALL) from all remote async paths. Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/include/page-xfer.h | 4 ++ criu/page-xfer.c | 85 ++++++++++++++++++++++++++++++++++++++++ criu/pagemap.c | 21 +++++++++- criu/uffd.c | 68 ++------------------------------ 4 files changed, 112 insertions(+), 66 deletions(-) diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index 5b7ec21f2..35425f1c0 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -57,5 +57,9 @@ extern int request_remote_pages(int pid, unsigned long addr, int nr_pages); extern int receive_remote_pages_info(int *nr_pages, unsigned long *addr, int *pid); extern int receive_remote_pages(int len, void *buf); +typedef int (*ps_async_read_complete)(int pid, unsigned long vaddr, int nr_pages, void *); +extern int page_server_start_async_read(void *buf, int nr_pages, + ps_async_read_complete complete, void *priv); +extern int page_server_async_read(void); #endif /* __CR_PAGE_XFER__H__ */ diff --git a/criu/page-xfer.c b/criu/page-xfer.c index f0da4e34c..9bfdeb886 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -950,6 +950,91 @@ out: return ret ? : status; } +struct ps_async_read { + unsigned long rb; /* read bytes */ + unsigned long goal; + + struct page_server_iov pi; + void *pages; + + ps_async_read_complete complete; + void *priv; + + struct list_head l; +}; + +static LIST_HEAD(async_reads); + +int page_server_start_async_read(void *buf, int nr_pages, + ps_async_read_complete complete, void *priv) +{ + struct ps_async_read *ar; + + ar = xmalloc(sizeof(*ar)); + if (ar == NULL) + return -1; + + ar->pages = buf; + ar->rb = 0; + ar->goal = sizeof(ar->pi) + nr_pages * PAGE_SIZE; + ar->complete = complete; + ar->priv = priv; + + list_add_tail(&ar->l, &async_reads); + return 0; +} + +/* + * There are two possible event types we need to handle: + * - page info is available as a reply to request_remote_page + * - page data is available, and it follows page info we've just received + * Since the on dump side communications are completely synchronous, + * we can return to epoll right after the reception of page info and + * for sure the next time socket event will occur we'll get page data + * related to info we've just received + */ +int page_server_async_read(void) +{ + struct ps_async_read *ar; + int ret, need; + void *buf; + + BUG_ON(list_empty(&async_reads)); + ar = list_first_entry(&async_reads, struct ps_async_read, l); + + if (ar->rb < sizeof(ar->pi)) { + /* Header */ + buf = ((void *)&ar->pi) + ar->rb; + need = sizeof(ar->pi) - ar->rb; + } else { + /* Page(s) data itself */ + buf = ar->pages + (ar->rb - sizeof(ar->pi)); + need = ar->goal - ar->rb; + } + + ret = recv(page_server_sk, buf, need, MSG_DONTWAIT); + if (ret < 0) { + pr_perror("Error reading async data from page server\n"); + return -1; + } + + ar->rb += ret; + if (ar->rb < ar->goal) + return 0; + + /* + * IO complete -- notify the caller and drop the request + */ + BUG_ON(ar->rb > ar->goal); + ret = ar->complete((int)ar->pi.dst_id, (unsigned long)ar->pi.vaddr, + (int)ar->pi.nr_pages, ar->priv); + + list_del(&ar->l); + xfree(ar); + + return ret; +} + int request_remote_pages(int pid, unsigned long addr, int nr_pages) { struct page_server_iov pi = { diff --git a/criu/pagemap.c b/criu/pagemap.c index 9118ead10..7fbe503fd 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -420,6 +420,23 @@ static int maybe_read_page_local(struct page_read *pr, unsigned long vaddr, return ret; } +static int read_page_complete(int pid, unsigned long vaddr, int nr_pages, void *priv) +{ + int ret = 0; + struct page_read *pr = priv; + + if (pr->pid != pid) { + pr_err("Out of order read completed (want %d have %d)\n", + pr->pid, pid); + return -1; + } + + if (pr->io_complete) + ret = pr->io_complete(pr, vaddr, nr_pages); + + return ret; +} + static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, int nr, void *buf, unsigned flags) { @@ -427,8 +444,10 @@ static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, /* We always do PR_ASAP mode here (FIXME?) */ ret = request_remote_pages(pr->pid, vaddr, nr); - if ((ret < 0) || (flags & PR_ASYNC)) + if (ret < 0) return ret; + if (flags & PR_ASYNC) + return page_server_start_async_read(buf, nr, read_page_complete, pr); /* * Note, that for async remote page_read, the actual diff --git a/criu/uffd.c b/criu/uffd.c index f0bf77f71..8b1774107 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -55,16 +55,9 @@ struct lazy_iovec { struct lazy_pages_info; -struct sk_event_data { - int nr_pages; - unsigned long addr; - struct lazy_pages_info *lpi; -}; - struct lazy_pages_fd { int fd; int (*event)(struct lazy_pages_fd *); - struct sk_event_data *ev_data; }; struct lazy_pages_info { @@ -120,18 +113,6 @@ static void lpi_fini(struct lazy_pages_info *lpi) free(lpi); } -static struct lazy_pages_info *pid2lpi(int pid) -{ - struct lazy_pages_info *lpi; - - list_for_each_entry(lpi, &lpis, l) { - if (lpi->pid == pid) - return lpi; - } - - return NULL; -} - static int epoll_nr_fds(int nr_tasks) { if (opts.use_page_server) @@ -921,56 +902,12 @@ close_uffd: return -1; } -/* - * There are two possible event types we need to handle: - * - page info is available as a reply to request_remote_page - * - page data is available, and it follows page info we've just received - * Since the on dump side communications are completely synchronous, - * we can return to epoll right after the reception of page info and - * for sure the next time socket event will occur we'll get page data - * related to info we've just received - */ static int page_server_event(struct lazy_pages_fd *lpfd) { - struct lazy_pages_info *lpi; - int pid, nr_pages; - unsigned long addr; - - lpi = lpfd->ev_data->lpi; - - if (!lpi) { - if (receive_remote_pages_info(&nr_pages, &addr, &pid)) - return -1; - - lpi = pid2lpi(pid); - if (!lpi) - return -1; - - lpfd->ev_data->lpi = lpi; - lpfd->ev_data->nr_pages = nr_pages; - lpfd->ev_data->addr = addr; - - return 0; - } else { - lpi = lpfd->ev_data->lpi; - nr_pages = lpfd->ev_data->nr_pages; - addr = lpfd->ev_data->addr; - - memset(lpfd->ev_data, 0, sizeof(*lpfd->ev_data)); - - if (receive_remote_pages(nr_pages * PAGE_SIZE, lpi->buf)) - return -1; - - return complete_page_fault(lpi, addr, nr_pages); - } + return page_server_async_read(); } -static struct sk_event_data sk_event_data; - -static struct lazy_pages_fd page_server_sk_fd = { - .event = page_server_event, - .ev_data = &sk_event_data, -}; +static struct lazy_pages_fd page_server_sk_fd; static int prepare_page_server_socket(int epollfd) { @@ -980,6 +917,7 @@ static int prepare_page_server_socket(int epollfd) if (sk < 0) return -1; + page_server_sk_fd.event = page_server_event; page_server_sk_fd.fd = sk; return epoll_add_lpfd(epollfd, &page_server_sk_fd); From 7999c84265c0c51abb39abbc57f8df06cd3c7fa6 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 18 Nov 2016 11:41:29 -0800 Subject: [PATCH 0831/4375] page_server_async_read: fix pr_perror usage Le sigh. travis-ci: success for more pr_perror() usage fixes Signed-off-by: Kir Kolyshkin Signed-off-by: Pavel Emelyanov --- criu/page-xfer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 9bfdeb886..998cc9e13 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -1014,7 +1014,7 @@ int page_server_async_read(void) ret = recv(page_server_sk, buf, need, MSG_DONTWAIT); if (ret < 0) { - pr_perror("Error reading async data from page server\n"); + pr_perror("Error reading async data from page server"); return -1; } From d66d5cdde8bf77c5a580010ca78905660a91f3ac Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 20 Nov 2016 11:50:04 +0200 Subject: [PATCH 0832/4375] lazy-dump: do not start page server if there were errors Currently, lazy dump starts page server regardless of errors that might have been encountered at earlier stages. Fix it. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 37084f0e8..7d3fe689b 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1677,7 +1677,7 @@ static int cr_dump_finish(int ret) clean_cr_time_mounts(); } - if (opts.lazy_pages) + if (!ret && opts.lazy_pages) ret = cr_lazy_mem_dump(); arch_set_thread_regs(root_item); From 8cf8ddfb33e66c2763e0da1fa1bff2bcfe305262 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 20 Nov 2016 11:50:05 +0200 Subject: [PATCH 0833/4375] lazy-pages: use -PID instead of -1 for zombie processes This gives somewhat saner debug messages Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-restore.c | 2 +- criu/include/uffd.h | 2 +- criu/uffd.c | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 10413f5a9..053a2c755 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -942,7 +942,7 @@ static int restore_one_zombie(CoreEntry *core) if (inherit_fd_fini() < 0) return -1; - if (lazy_pages_setup_zombie()) + if (lazy_pages_setup_zombie(current->pid.virt)) return -1; prctl(PR_SET_NAME, (long)(void *)core->tc->comm, 0, 0, 0); diff --git a/criu/include/uffd.h b/criu/include/uffd.h index 8adf2f0f7..4d790cebf 100644 --- a/criu/include/uffd.h +++ b/criu/include/uffd.h @@ -3,7 +3,7 @@ struct task_restore_args; extern int setup_uffd(int pid, struct task_restore_args *task_args); -extern int lazy_pages_setup_zombie(void); +extern int lazy_pages_setup_zombie(int pid); extern int prepare_lazy_pages_socket(void); #endif /* __CR_UFFD_H_ */ diff --git a/criu/uffd.c b/criu/uffd.c index 8b1774107..476371a88 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -161,8 +161,8 @@ static int send_uffd(int sendfd, int pid) goto out; } - /* for a zombie process pid will be -1 */ - if (pid == -1) { + /* for a zombie process pid will be negative */ + if (pid < 0) { ret = 0; goto out; } @@ -200,12 +200,12 @@ static int check_for_uffd() return 0; } -int lazy_pages_setup_zombie(void) +int lazy_pages_setup_zombie(int pid) { if (!opts.lazy_pages) return 0; - if (send_uffd(0, -1)) + if (send_uffd(0, -pid)) return -1; return 0; @@ -482,7 +482,7 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) } pr_debug("received PID: %d\n", lpi->pid); - if (lpi->pid == -1) { + if (lpi->pid < 0) { lpi_fini(lpi); return 0; } From 3fdf7c02d52acd104522c8bcb19402fd105e44dd Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 20 Nov 2016 11:50:06 +0200 Subject: [PATCH 0834/4375] lazy-pages: reduce amount of debug printouts Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 476371a88..526390766 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -463,7 +463,6 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) { struct lazy_pages_info *lpi; int ret = -1; - int uffd_flags; int pr_flags = PR_TASK; lpi = lpi_init(); @@ -480,9 +479,9 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) pr_err("PID recv: short read\n"); goto out; } - pr_debug("received PID: %d\n", lpi->pid); if (lpi->pid < 0) { + pr_debug("Zombie PID: %d\n", lpi->pid); lpi_fini(lpi); return 0; } @@ -492,11 +491,7 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) pr_err("recv_fd error\n"); goto out; } - pr_debug("lpi->uffd %d\n", lpi->lpfd.fd); - - pr_debug("uffd is 0x%d\n", lpi->lpfd.fd); - uffd_flags = fcntl(lpi->lpfd.fd, F_GETFD, NULL); - pr_debug("uffd_flags are 0x%x\n", uffd_flags); + pr_debug("Received PID: %d, uffd: %d\n", lpi->pid, lpi->lpfd.fd); if (opts.use_page_server) pr_flags |= PR_REMOTE; @@ -541,16 +536,14 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) uffdio_copy.mode = 0; uffdio_copy.copy = 0; - pr_debug("uffdio_copy.dst 0x%llx\n", uffdio_copy.dst); + pr_debug("%d: uffd_copy: 0x%llx/%ld\n", lpi->pid, uffdio_copy.dst, len); rc = ioctl(lpi->lpfd.fd, UFFDIO_COPY, &uffdio_copy); - pr_debug("ioctl UFFDIO_COPY rc 0x%x\n", rc); - pr_debug("uffdio_copy.copy 0x%llx\n", uffdio_copy.copy); if (rc) { /* real retval in ufdio_copy.copy */ - if (uffdio_copy.copy != -EEXIST) { - pr_err("UFFDIO_COPY error %Ld\n", uffdio_copy.copy); + pr_err("%d: UFFDIO_COPY failed: rc:%d copy:%Ld\n", lpi->pid, rc, + uffdio_copy.copy); + if (uffdio_copy.copy != -EEXIST) return -1; - } } else if (uffdio_copy.copy != len) { pr_err("UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy); return -1; @@ -590,10 +583,8 @@ static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) uffdio_zeropage.range.len = len; uffdio_zeropage.mode = 0; - pr_debug("uffdio_zeropage.range.start 0x%llx\n", uffdio_zeropage.range.start); + pr_debug("%d: zero page at 0x%llx\n", lpi->pid, address); rc = ioctl(lpi->lpfd.fd, UFFDIO_ZEROPAGE, &uffdio_zeropage); - pr_debug("ioctl UFFDIO_ZEROPAGE rc 0x%x\n", rc); - pr_debug("uffdio_zeropage.zeropage 0x%llx\n", uffdio_zeropage.zeropage); if (rc) { pr_err("UFFDIO_ZEROPAGE error %d\n", rc); return -1; @@ -688,14 +679,12 @@ static int handle_user_fault(struct lazy_pages_fd *lpfd) { struct lazy_pages_info *lpi; struct uffd_msg msg; - __u64 flags; __u64 address; int ret; lpi = container_of(lpfd, struct lazy_pages_info, lpfd); ret = read(lpfd->fd, &msg, sizeof(msg)); - pr_debug("read() ret: 0x%x\n", ret); if (!ret) return 1; @@ -714,11 +703,22 @@ static int handle_user_fault(struct lazy_pages_fd *lpfd) /* Align requested address to the next page boundary */ address = msg.arg.pagefault.address & ~(page_size() - 1); - pr_debug("msg.arg.pagefault.address 0x%llx\n", address); + pr_debug("%d: pagefalt at 0x%llx\n", lpi->pid, address); + +#if 0 + /* + * Until uffd in kernel gets support for write protection, + * flags are always 0, so there is no point to read and print + * them + */ + { + __u64 flags; /* Now handle the pages actually requested. */ flags = msg.arg.pagefault.flags; pr_debug("msg.arg.pagefault.flags 0x%llx\n", flags); + } +#endif ret = handle_page_fault(lpi, address, 1); if (ret < 0) { @@ -762,12 +762,10 @@ static int handle_requests(int epollfd, struct epoll_event *events) * copying the remaining pages. */ ret = epoll_wait(epollfd, events, nr_fds, POLL_TIMEOUT); - pr_debug("epoll() ret: 0x%x\n", ret); if (ret < 0) { pr_perror("polling failed"); goto out; } else if (ret == 0) { - pr_debug("read timeout\n"); pr_debug("switching from request to copy mode\n"); break; } @@ -781,6 +779,7 @@ static int handle_requests(int epollfd, struct epoll_event *events) goto out; } } + pr_debug("Handle remaining pages\n"); list_for_each_entry(lpi, &lpis, l) { ret = handle_remaining_pages(lpi); @@ -880,7 +879,6 @@ static int prepare_uffds(int listen, int epollfd) close(listen); return -1; } - pr_debug("client fd %d\n", client); for (i = 0; i < task_entries->nr_tasks; i++) { struct lazy_pages_info *lpi = NULL; From e82f03e1eb419906b5683e6e65ce2b7ada81858b Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 8 Mar 2017 16:32:37 +0100 Subject: [PATCH 0835/4375] cr-service: add lazy-pages RPC feature check Extend the RPC feature check functionality to also test for lazy-pages support. This does not check for certain UFFD features (yet). Right now it only checks if kerndat_uffd() returns non-zero. The RPC response is now transmitted from the forked process instead of encoding all the results into the return code. The parent RPC process now only sends an RPC message in the case of a failure. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-service.c | 87 +++++++++++++++++++++++++++++++++-------------- images/rpc.proto | 1 + 2 files changed, 62 insertions(+), 26 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 49cbe682f..b93d55345 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -852,33 +852,22 @@ static int handle_feature_check(int sk, CriuReq * msg) { CriuResp resp = CRIU_RESP__INIT; CriuFeatures feat = CRIU_FEATURES__INIT; - bool success = false; int pid, status; + int ret; /* enable setting of an optional message */ feat.has_mem_track = 1; feat.mem_track = false; + feat.has_lazy_pages = 1; + feat.lazy_pages = false; - /* - * Check if the requested feature check can be answered. - * - * This function is right now hard-coded to memory - * tracking detection and needs other/better logic to - * handle multiple feature checks. - */ - if (msg->features->has_mem_track != 1) { + /* Check if the requested feature check can be answered. */ + if ((msg->features->has_mem_track != 1) || + (msg->features->has_lazy_pages != 1)) { pr_warn("Feature checking for unknown feature.\n"); goto out; } - /* - * From this point on the function will always - * 'succeed'. If the requested features are supported - * can be seen if the requested optional parameters are - * set in the message 'criu_features'. - */ - success = true; - pid = fork(); if (pid < 0) { pr_perror("Can't fork"); @@ -886,27 +875,73 @@ static int handle_feature_check(int sk, CriuReq * msg) } if (pid == 0) { - int ret = 1; setproctitle("feature-check --rpc"); - kerndat_get_dirty_track(); + if ((msg->features->has_mem_track == 1) && + (msg->features->mem_track == true)) { - if (kdat.has_dirty_track) - ret = 0; + feat.mem_track = true; + ret = kerndat_get_dirty_track(); + + if (ret) + feat.mem_track = false; + + if (!kdat.has_dirty_track) + feat.mem_track = false; + } + + if ((msg->features->has_lazy_pages == 1) && + (msg->features->lazy_pages == true)) { + ret = kerndat_uffd(true); + + /* + * Not checking for specific UFFD features yet. + * If no error is returned it is probably + * enough for basic UFFD functionality. This can + * be extended in the future for a more detailed + * UFFD feature check. + */ + if (ret) + feat.lazy_pages = false; + else + feat.lazy_pages = true; + } + + resp.features = &feat; + resp.type = msg->type; + /* The feature check is working, actual results are in resp.features */ + resp.success = true; + + /* + * If this point is reached the information about the features + * is transmitted from the forked CRIU process (here). + * If an error occured earlier, the feature check response will be + * be send from the parent process. + */ + ret = send_criu_msg(sk, &resp); exit(ret); } - wait(&status); - if (!WIFEXITED(status) || WEXITSTATUS(status)) + ret = waitpid(pid, &status, 0); + if (ret == -1) goto out; - feat.mem_track = true; + if (WIFEXITED(status) && !WEXITSTATUS(status)) + /* + * The child process exited was able to send the answer. + * Nothing more to do here. + */ + return 0; + + /* + * The child process was not able to send an answer. Tell + * the RPC client that something did not work as expected. + */ out: - resp.features = &feat; resp.type = msg->type; - resp.success = success; + resp.success = false; return send_criu_msg(sk, &resp); } diff --git a/images/rpc.proto b/images/rpc.proto index 2c65617aa..cdd186b13 100644 --- a/images/rpc.proto +++ b/images/rpc.proto @@ -149,6 +149,7 @@ enum criu_req_type { */ message criu_features { optional bool mem_track = 1; + optional bool lazy_pages = 2; } /* From 12c0f452fe0b00955b977d11b82a4bff16c76e2f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 22 Nov 2016 15:10:09 +0300 Subject: [PATCH 0836/4375] uffd: Unify page handling in normal and remaining modes (v2) This run away from previous set :) Two routines are now identical, only page-read flags differ. v2: Keep the uffd_hanle_pages() name travis-ci: success for Some more cleanups over uffd.c (rev3) Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/uffd.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 526390766..cb6e9e203 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -619,7 +619,7 @@ static int uffd_seek_or_zero_pages(struct lazy_pages_info *lpi, __u64 address, return 1; } -static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr) +static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr, unsigned flags) { int ret; @@ -627,7 +627,7 @@ static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr) if (ret <= 0) return ret; - ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, 0); + ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, flags); if (ret <= 0) { pr_err("%d: failed reading pages at %llx\n", lpi->pid, address); return ret; @@ -648,7 +648,7 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) list_for_each_entry(lazy_iov, &lpi->iovs, l) { nr_pages = lazy_iov->len / PAGE_SIZE; - err = uffd_handle_pages(lpi, lazy_iov->base, nr_pages); + err = uffd_handle_pages(lpi, lazy_iov->base, nr_pages, 0); if (err < 0) { pr_err("Error during UFFD copy\n"); return -1; @@ -658,23 +658,6 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) return 0; } -static int handle_page_fault(struct lazy_pages_info *lpi, __u64 address, int nr) -{ - int ret; - - ret = uffd_seek_or_zero_pages(lpi, address, nr); - if (ret <= 0) - return ret; - - ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, PR_ASYNC | PR_ASAP); - if (ret <= 0) { - pr_err("%d: failed reading pages at %llx\n", lpi->pid, address); - return ret; - } - - return 0; -} - static int handle_user_fault(struct lazy_pages_fd *lpfd) { struct lazy_pages_info *lpi; @@ -720,7 +703,7 @@ static int handle_user_fault(struct lazy_pages_fd *lpfd) } #endif - ret = handle_page_fault(lpi, address, 1); + ret = uffd_handle_pages(lpi, address, 1, PR_ASYNC | PR_ASAP); if (ret < 0) { pr_err("Error during regular page copy\n"); return -1; From f30cca66ecbaa3f5d13f6d172b46a7128d43a01e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 22 Nov 2016 15:10:35 +0300 Subject: [PATCH 0837/4375] uffd: Relax reading the pstree image (v2) The uffd code only needs the pstree items themselves, not any IDs and relations they might have. travis-ci: success for Some more cleanups over uffd.c (rev3) Signed-off-by: Pavel Emelyanov Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/pstree.h | 1 + criu/pstree.c | 17 +++++++++++++++++ criu/uffd.c | 17 +---------------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/criu/include/pstree.h b/criu/include/pstree.h index b7299c313..7cf4be9cf 100644 --- a/criu/include/pstree.h +++ b/criu/include/pstree.h @@ -100,6 +100,7 @@ extern struct pstree_item *pstree_item_next(struct pstree_item *item); extern bool restore_before_setsid(struct pstree_item *child); extern int prepare_pstree(void); +extern int prepare_dummy_pstree(void); extern int dump_pstree(struct pstree_item *root_item); diff --git a/criu/pstree.c b/criu/pstree.c index 9b2d171dc..e9ddc6aeb 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -16,6 +16,7 @@ #include "util.h" #include "protobuf.h" #include "images/pstree.pb-c.h" +#include "crtools.h" struct pstree_item *root_item; static struct rb_root pid_root_rb; @@ -950,6 +951,22 @@ int prepare_pstree(void) return ret; } +int prepare_dummy_pstree(void) +{ + pid_t dummy = 0; + + if (check_img_inventory() == -1) + return -1; + + if (prepare_task_entries() == -1) + return -1; + + if (read_pstree_image(&dummy) == -1) + return -1; + + return 0; +} + bool restore_before_setsid(struct pstree_item *child) { int csid = child->born_sid == -1 ? child->sid : child->born_sid; diff --git a/criu/uffd.c b/criu/uffd.c index cb6e9e203..41ed48062 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -781,21 +781,6 @@ out: } -static int lazy_pages_prepare_pstree(void) -{ - if (check_img_inventory() == -1) - return -1; - - /* Allocate memory for task_entries */ - if (prepare_task_entries() == -1) - return -1; - - if (prepare_pstree() == -1) - return -1; - - return 0; -} - static int prepare_epoll(int nr_fds, struct epoll_event **events) { int epollfd; @@ -915,7 +900,7 @@ int cr_lazy_pages(bool daemon) if (check_for_uffd()) return -1; - if (lazy_pages_prepare_pstree()) + if (prepare_dummy_pstree()) return -1; lazy_sk = prepare_lazy_socket(); From 4cb743e48aa5d71dbddf1b8d29fcb86d47df00b5 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 22 Nov 2016 15:10:54 +0300 Subject: [PATCH 0838/4375] util: Move epoll aux code from uffd to util (v2) v2: Move epoll_prepare() too travis-ci: success for Some more cleanups over uffd.c (rev3) Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/include/util.h | 15 +++++++ criu/uffd.c | 95 ++++++++------------------------------------- criu/util.c | 63 ++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 79 deletions(-) diff --git a/criu/include/util.h b/criu/include/util.h index b3c669428..63810b493 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -311,4 +311,19 @@ int setup_tcp_client(char *addr); ___ret; \ }) +/* + * Helpers to organize asynchronous reading from a bunch + * of file descriptors. + */ +#include + +struct epoll_rfd { + int fd; + int (*revent)(struct epoll_rfd *); +}; + +extern int epoll_add_rfd(int epfd, struct epoll_rfd *); +extern int epoll_run_rfds(int epfd, struct epoll_event *evs, int nr_fds, int tmo); +extern int epoll_prepare(int nr_events, struct epoll_event **evs); + #endif /* __CR_UTIL_H__ */ diff --git a/criu/uffd.c b/criu/uffd.c index 41ed48062..6ee4a3509 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "linux/userfaultfd.h" @@ -39,6 +38,7 @@ #include "page-xfer.h" #include "common/lock.h" #include "rst-malloc.h" +#include "util.h" #undef LOG_PREFIX #define LOG_PREFIX "lazy-pages: " @@ -55,11 +55,6 @@ struct lazy_iovec { struct lazy_pages_info; -struct lazy_pages_fd { - int fd; - int (*event)(struct lazy_pages_fd *); -}; - struct lazy_pages_info { int pid; @@ -70,7 +65,7 @@ struct lazy_pages_info { unsigned long total_pages; unsigned long copied_pages; - struct lazy_pages_fd lpfd; + struct epoll_rfd lpfd; struct list_head l; @@ -79,7 +74,7 @@ struct lazy_pages_info { }; static LIST_HEAD(lpis); -static int handle_user_fault(struct lazy_pages_fd *lpfd); +static int handle_user_fault(struct epoll_rfd *lpfd); static struct lazy_pages_info *lpi_init(void) { @@ -92,7 +87,7 @@ static struct lazy_pages_info *lpi_init(void) memset(lpi, 0, sizeof(*lpi)); INIT_LIST_HEAD(&lpi->iovs); INIT_LIST_HEAD(&lpi->l); - lpi->lpfd.event = handle_user_fault; + lpi->lpfd.revent = handle_user_fault; return lpi; } @@ -658,7 +653,7 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) return 0; } -static int handle_user_fault(struct lazy_pages_fd *lpfd) +static int handle_user_fault(struct epoll_rfd *lpfd) { struct lazy_pages_info *lpi; struct uffd_msg msg; @@ -731,38 +726,15 @@ static int lazy_pages_summary(struct lazy_pages_info *lpi) static int handle_requests(int epollfd, struct epoll_event *events) { - int nr_fds = epoll_nr_fds(task_entries->nr_tasks); struct lazy_pages_info *lpi; - int ret = -1; - int i; + int ret; - while (1) { - struct lazy_pages_fd *lpfd; + ret = epoll_run_rfds(epollfd, events, epoll_nr_fds(task_entries->nr_tasks), POLL_TIMEOUT); + if (ret < 0) + goto out; - /* - * Setting the timeout to 5 seconds. If after this time - * no uffd pages are requested the code switches to - * copying the remaining pages. - */ - ret = epoll_wait(epollfd, events, nr_fds, POLL_TIMEOUT); - if (ret < 0) { - pr_perror("polling failed"); - goto out; - } else if (ret == 0) { - pr_debug("switching from request to copy mode\n"); - break; - } - - for (i = 0; i < ret; i++) { - int err; - - lpfd = (struct lazy_pages_fd *)events[i].data.ptr; - err = lpfd->event(lpfd); - if (err < 0) - goto out; - } - } + pr_debug("switching from request to copy mode\n"); pr_debug("Handle remaining pages\n"); list_for_each_entry(lpi, &lpis, l) { ret = handle_remaining_pages(lpi); @@ -781,41 +753,6 @@ out: } -static int prepare_epoll(int nr_fds, struct epoll_event **events) -{ - int epollfd; - - *events = xmalloc(sizeof(struct epoll_event) * nr_fds); - if (!*events) - return -1; - - epollfd = epoll_create(nr_fds); - if (epollfd == -1) { - pr_perror("epoll_create failed"); - goto free_events; - } - - return epollfd; - -free_events: - free(*events); - return -1; -} - -static int epoll_add_lpfd(int epollfd, struct lazy_pages_fd *lpfd) -{ - struct epoll_event ev; - - ev.events = EPOLLIN; - ev.data.ptr = lpfd; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, lpfd->fd, &ev) == -1) { - pr_perror("epoll_ctl failed"); - return -1; - } - - return 0; -} - static int prepare_lazy_socket(void) { int listen; @@ -854,7 +791,7 @@ static int prepare_uffds(int listen, int epollfd) goto close_uffd; if (lpi == NULL) continue; - if (epoll_add_lpfd(epollfd, &lpi->lpfd)) + if (epoll_add_rfd(epollfd, &lpi->lpfd)) goto close_uffd; } @@ -868,12 +805,12 @@ close_uffd: return -1; } -static int page_server_event(struct lazy_pages_fd *lpfd) +static int page_server_event(struct epoll_rfd *lpfd) { return page_server_async_read(); } -static struct lazy_pages_fd page_server_sk_fd; +static struct epoll_rfd page_server_sk_fd; static int prepare_page_server_socket(int epollfd) { @@ -883,10 +820,10 @@ static int prepare_page_server_socket(int epollfd) if (sk < 0) return -1; - page_server_sk_fd.event = page_server_event; + page_server_sk_fd.revent = page_server_event; page_server_sk_fd.fd = sk; - return epoll_add_lpfd(epollfd, &page_server_sk_fd); + return epoll_add_rfd(epollfd, &page_server_sk_fd); } int cr_lazy_pages(bool daemon) @@ -931,7 +868,7 @@ int cr_lazy_pages(bool daemon) return -1; nr_fds = epoll_nr_fds(task_entries->nr_tasks); - epollfd = prepare_epoll(nr_fds, &events); + epollfd = epoll_prepare(nr_fds, &events); if (epollfd < 0) return -1; diff --git a/criu/util.c b/criu/util.c index 9521eac0b..876ff9577 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1213,3 +1213,66 @@ int setup_tcp_client(char *addr) return sk; } + +int epoll_add_rfd(int epfd, struct epoll_rfd *rfd) +{ + struct epoll_event ev; + + ev.events = EPOLLIN; + ev.data.ptr = rfd; + if (epoll_ctl(epfd, EPOLL_CTL_ADD, rfd->fd, &ev) == -1) { + pr_perror("epoll_ctl failed"); + return -1; + } + + return 0; +} + +int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout) +{ + int ret = 0, i; + + while (1) { + /* FIXME -- timeout should decrease over time... */ + ret = epoll_wait(epollfd, evs, nr_fds, timeout); + if (ret <= 0) { + if (ret < 0) + pr_perror("polling failed"); + else + pr_debug("polling timeout\n"); + break; + } + + for (i = 0; i < ret; i++) { + struct epoll_rfd *rfd; + + rfd = (struct epoll_rfd *)evs[i].data.ptr; + ret = rfd->revent(rfd); + if (ret < 0) + goto out; + } + } +out: + return ret; +} + +int epoll_prepare(int nr_fds, struct epoll_event **events) +{ + int epollfd; + + *events = xmalloc(sizeof(struct epoll_event) * nr_fds); + if (!*events) + return -1; + + epollfd = epoll_create(nr_fds); + if (epollfd == -1) { + pr_perror("epoll_create failed"); + goto free_events; + } + + return epollfd; + +free_events: + xfree(*events); + return -1; +} From 8edb68e9ec17d7e07712989622ddc29de120bbce Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 22 Nov 2016 15:11:12 +0300 Subject: [PATCH 0839/4375] uffd: Hide page server socket back With epoll helpers in util we can stop exposing the page-server socket to the oter world. travis-ci: success for Some more cleanups over uffd.c (rev3) Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/cr-dump.c | 4 ++-- criu/include/page-xfer.h | 4 ++-- criu/page-xfer.c | 24 +++++++++++++++++++++--- criu/uffd.c | 23 +---------------------- 4 files changed, 26 insertions(+), 29 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 7d3fe689b..01063af03 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1565,7 +1565,7 @@ int cr_pre_dump_tasks(pid_t pid) if (vdso_init()) goto err; - if (connect_to_page_server() < 0) + if (connect_to_page_server_to_send() < 0) goto err; if (setup_alarm_handler()) @@ -1761,7 +1761,7 @@ int cr_dump_tasks(pid_t pid) goto err; } - if (connect_to_page_server() < 0) + if (connect_to_page_server_to_send() < 0) goto err; if (setup_alarm_handler()) diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index 35425f1c0..dfe43e5a1 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -37,7 +37,8 @@ extern int open_page_xfer(struct page_xfer *xfer, int fd_type, long id); struct page_pipe; extern int page_xfer_dump_pages(struct page_xfer *, struct page_pipe *, unsigned long off, bool dump_lazy); -extern int connect_to_page_server(void); +extern int connect_to_page_server_to_send(void); +extern int connect_to_page_server_to_recv(int epfd); extern int disconnect_from_page_server(void); extern int check_parent_page_xfer(int fd_type, long id); @@ -60,6 +61,5 @@ extern int receive_remote_pages(int len, void *buf); typedef int (*ps_async_read_complete)(int pid, unsigned long vaddr, int nr_pages, void *); extern int page_server_start_async_read(void *buf, int nr_pages, ps_async_read_complete complete, void *priv); -extern int page_server_async_read(void); #endif /* __CR_PAGE_XFER__H__ */ diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 998cc9e13..c2bcd1dbb 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -885,7 +885,7 @@ no_server: return ret; } -int connect_to_page_server(void) +static int connect_to_page_server(void) { if (!opts.use_page_server) return 0; @@ -906,7 +906,12 @@ out: * on urgent data is the smartest mode ever. */ tcp_cork(page_server_sk, true); - return page_server_sk; + return 0; +} + +int connect_to_page_server_to_send(void) +{ + return connect_to_page_server(); } int disconnect_from_page_server(void) @@ -993,7 +998,7 @@ int page_server_start_async_read(void *buf, int nr_pages, * for sure the next time socket event will occur we'll get page data * related to info we've just received */ -int page_server_async_read(void) +static int page_server_async_read(struct epoll_rfd *f) { struct ps_async_read *ar; int ret, need; @@ -1035,6 +1040,19 @@ int page_server_async_read(void) return ret; } +static struct epoll_rfd ps_rfd; + +int connect_to_page_server_to_recv(int epfd) +{ + if (connect_to_page_server()) + return -1; + + ps_rfd.fd = page_server_sk; + ps_rfd.revent = page_server_async_read; + + return epoll_add_rfd(epfd, &ps_rfd); +} + int request_remote_pages(int pid, unsigned long addr, int nr_pages) { struct page_server_iov pi = { diff --git a/criu/uffd.c b/criu/uffd.c index 6ee4a3509..adfdc1f42 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -805,27 +805,6 @@ close_uffd: return -1; } -static int page_server_event(struct epoll_rfd *lpfd) -{ - return page_server_async_read(); -} - -static struct epoll_rfd page_server_sk_fd; - -static int prepare_page_server_socket(int epollfd) -{ - int sk; - - sk = connect_to_page_server(); - if (sk < 0) - return -1; - - page_server_sk_fd.revent = page_server_event; - page_server_sk_fd.fd = sk; - - return epoll_add_rfd(epollfd, &page_server_sk_fd); -} - int cr_lazy_pages(bool daemon) { struct epoll_event *events; @@ -876,7 +855,7 @@ int cr_lazy_pages(bool daemon) return -1; if (opts.use_page_server) { - if (prepare_page_server_socket(epollfd)) + if (connect_to_page_server_to_recv(epollfd)) return -1; } From 1883b7692f88aaa327c6e5102c17e11d86816a29 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 22 Nov 2016 15:11:29 +0300 Subject: [PATCH 0840/4375] uffd: Relax counting the number of sockets travis-ci: success for Some more cleanups over uffd.c (rev3) Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport --- criu/uffd.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index adfdc1f42..99e6c65f3 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -108,13 +108,6 @@ static void lpi_fini(struct lazy_pages_info *lpi) free(lpi); } -static int epoll_nr_fds(int nr_tasks) -{ - if (opts.use_page_server) - return nr_tasks + 1; - return nr_tasks; -} - static int prepare_sock_addr(struct sockaddr_un *saddr) { int len; @@ -724,12 +717,12 @@ static int lazy_pages_summary(struct lazy_pages_info *lpi) #define POLL_TIMEOUT 5000 -static int handle_requests(int epollfd, struct epoll_event *events) +static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) { struct lazy_pages_info *lpi; int ret; - ret = epoll_run_rfds(epollfd, events, epoll_nr_fds(task_entries->nr_tasks), POLL_TIMEOUT); + ret = epoll_run_rfds(epollfd, events, nr_fds, POLL_TIMEOUT); if (ret < 0) goto out; @@ -846,7 +839,7 @@ int cr_lazy_pages(bool daemon) if (close_status_fd()) return -1; - nr_fds = epoll_nr_fds(task_entries->nr_tasks); + nr_fds = task_entries->nr_tasks + (opts.use_page_server ? 1 : 0); epollfd = epoll_prepare(nr_fds, &events); if (epollfd < 0) return -1; @@ -859,7 +852,7 @@ int cr_lazy_pages(bool daemon) return -1; } - ret = handle_requests(epollfd, events); + ret = handle_requests(epollfd, events, nr_fds); return ret; } From 836b1bc87adcb5ba4f9e60888168d3f7cebbb99c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 23 Nov 2016 15:27:00 +0300 Subject: [PATCH 0841/4375] page-pipe: (yet another) fix for split page-pipe buffers Splitting of the trailing part of page-pipe buffer worked by coincidence for single page requests. Request longer than a single page were not handled correctly. The proper point for splitting the trailing part of the page-pipe buffer is the IOV following the IOV containing the desired page(s). travis-ci: success for page-pipe: (yet another) fix for split page-pipe buffers (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/page-pipe.c | 56 ++++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/criu/page-pipe.c b/criu/page-pipe.c index eae1cbbff..4ebd0cbe8 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -372,10 +372,9 @@ static int page_pipe_split_iov(struct page_pipe *pp, struct page_pipe_buf *ppb, } static int page_pipe_split_ppb(struct page_pipe *pp, struct page_pipe_buf *ppb, - struct iovec *iov, unsigned long len) + struct iovec *iov, unsigned long len, + bool popup_new) { - struct page_pipe_buf *ppb_tmp; - struct iovec *iov_tmp = iov; struct page_pipe_buf *ppb_new; int ret; @@ -393,36 +392,10 @@ static int page_pipe_split_ppb(struct page_pipe *pp, struct page_pipe_buf *ppb, ppb->nr_segs -= ppb_new->nr_segs; ppb->pages_in -= len / PAGE_SIZE; + if (popup_new) + ppb = ppb_new; list_move(&ppb->l, &pp->bufs); - /* - * Only the leading iov's are split from the page_pipe_buffer. - * The complete page_pipe_buffer at the start of the page_pipe - * list will be deleted and therefore it is necessary to also - * move unrelated iov's to their own page_pipe_buffers. - */ - - if (ppb->nr_segs <= len / PAGE_SIZE) - return 0; - - /* Move to the iov after the current request */ - iov += len / PAGE_SIZE; - ret = page_pipe_split_ppb(pp, ppb, iov, len); - if (ret) - return -1; - - /* - * Rotate until correct head pointer. The function transmitting - * the page data expects that the head points to the right - * page_pipe_buffer. The complete first page_pipe_buffer is - * deleted even it contains additional elements. - */ - ppb_tmp = list_first_entry(&pp->bufs, struct page_pipe_buf, l); - while (ppb_tmp->iov != iov_tmp) { - list_rotate_left(&pp->bufs); - ppb_tmp = list_first_entry(&pp->bufs, struct page_pipe_buf, l); - } - return 0; } @@ -450,14 +423,31 @@ int page_pipe_split(struct page_pipe *pp, unsigned long addr, return 0; } - /* split origingal ppb on boundary of iov that contains addr */ + /* + * Split origingal ppb on boundary of iov that contains + * addr. The ppb containing the address will remain at the + * pp->buf list head. + */ if (iov != ppb->iov) { len -= (addr - (unsigned long)iov->iov_base); - ret = page_pipe_split_ppb(pp, ppb, iov, len); + ret = page_pipe_split_ppb(pp, ppb, iov, len, false); if (ret) return -1; } + /* + * Split the tail of the ppb. We presume that requests do not + * cross IOV (that is pagemap entry) boundaries. + * The newly created ppb will contain the desired IOV and will + * be poped to the head of the pp->buf list + */ + if (ppb->nr_segs > 1) { + len = iov->iov_len; + ret = page_pipe_split_ppb(pp, ppb, iov + 1, len, true); + if (ret) + return -1; + ppb = list_first_entry(&pp->bufs, struct page_pipe_buf, l); + } /* * if address does not match iov base, split the iov and From 22b5d5e92d6ac724eb6d3e48dfce4f262b3379f3 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 27 Nov 2016 12:47:00 +0300 Subject: [PATCH 0842/4375] page-xfer: page_server_get_pages: replace BUG_ONs with 'return -1' Instead of crashing dump/page-server when a problem detected after the page-pipe was split, print nice error messages and return error. travis-ci: success for page-xfer: page_server_get_pages: replace BUG_ONs with 'return -1' (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/page-xfer.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index c2bcd1dbb..5bfb137da 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -687,6 +687,31 @@ static int page_server_add(int sk, struct page_server_iov *pi, u32 flags) return 0; } +static bool can_send_pages(struct page_pipe_buf *ppb, struct iovec *iov, + struct page_server_iov *pi) +{ + unsigned long len = pi->nr_pages * PAGE_SIZE; + + if (!(ppb->flags & PPB_LAZY)) { + pr_err("Requested pages are not lazy\n"); + return false; + } + + if (iov->iov_len != len) { + pr_err("IOV len %zu does not match requested %lu\n", + iov->iov_len, len); + return false; + } + + if(pi->vaddr != encode_pointer(iov->iov_base)) { + pr_err("IOV start %p does not match requested addr %"PRIx64"\n", + iov->iov_base, pi->vaddr); + return false; + } + + return true; +} + static int page_server_get_pages(int sk, struct page_server_iov *pi) { struct pstree_item *item; @@ -711,9 +736,8 @@ static int page_server_get_pages(int sk, struct page_server_iov *pi) ppb = list_first_entry(&pp->bufs, struct page_pipe_buf, l); iov = &ppb->iov[0]; - BUG_ON(!(ppb->flags & PPB_LAZY)); - BUG_ON(iov->iov_len != pi->nr_pages * PAGE_SIZE); - BUG_ON(pi->vaddr != encode_pointer(iov->iov_base)); + if (!can_send_pages(ppb, iov, pi)) + return -1; if (send_psi(sk, PS_IOV_ADD, pi->nr_pages, pi->vaddr, pi->dst_id)) return -1; From 8be54383ff400222736812bba22599c13ddfbb47 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 27 Nov 2016 12:52:54 +0200 Subject: [PATCH 0843/4375] page-xfer: add ability to send pages from local dump Currently, standalone page-server can only receive pages from the remote dump. Extend it with the ability to serve local memory dump to a remote lazy-pages daemon. travis-ci: success for lazy-pages: improve testability (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-restore.c | 15 +++++- criu/include/pstree.h | 1 + criu/page-xfer.c | 108 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 053a2c755..fc27dd4fa 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -942,7 +942,7 @@ static int restore_one_zombie(CoreEntry *core) if (inherit_fd_fini() < 0) return -1; - if (lazy_pages_setup_zombie(current->pid.virt)) + if (lazy_pages_setup_zombie(vpid(current))) return -1; prctl(PR_SET_NAME, (long)(void *)core->tc->comm, 0, 0, 0); @@ -2171,6 +2171,19 @@ int prepare_task_entries(void) return 0; } +int prepare_dummy_task_state(struct pstree_item *pi) +{ + CoreEntry *core; + + if (open_core(vpid(pi), &core)) + return -1; + + pi->pid->state = core->tc->task_state; + core_entry__free_unpacked(core, NULL); + + return 0; +} + int cr_restore_tasks(void) { int ret = -1; diff --git a/criu/include/pstree.h b/criu/include/pstree.h index 7cf4be9cf..b082e3586 100644 --- a/criu/include/pstree.h +++ b/criu/include/pstree.h @@ -112,6 +112,7 @@ extern int pid_to_virt(pid_t pid); struct task_entries; extern struct task_entries *task_entries; extern int prepare_task_entries(void); +extern int prepare_dummy_task_state(struct pstree_item *pi); extern int get_task_ids(struct pstree_item *); extern struct _TaskKobjIdsEntry *root_ids; diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 5bfb137da..084d5a7cc 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -19,6 +19,7 @@ #include "fcntl.h" #include "pstree.h" #include "parasite-syscall.h" +#include "rst_info.h" static int page_server_sk = -1; @@ -876,14 +877,119 @@ static int page_server_serve(int sk) return ret; } +static int fill_page_pipe(struct page_read *pr, struct page_pipe *pp) +{ + struct page_pipe_buf *ppb; + int i, ret; + + pr->reset(pr); + + while (pr->advance(pr)) { + unsigned long vaddr = pr->pe->vaddr; + + for (i = 0; i < pr->pe->nr_pages; i++, vaddr += PAGE_SIZE) { + if (pagemap_zero(pr->pe)) + ret = page_pipe_add_hole(pp, vaddr, PP_HOLE_ZERO); + else if (pagemap_in_parent(pr->pe)) + ret = page_pipe_add_hole(pp, vaddr, PP_HOLE_PARENT); + else + ret = page_pipe_add_page(pp, vaddr, pagemap_lazy(pr->pe) ? PPB_LAZY : 0); + if (ret) { + pr_err("Failed adding page at %lx\n", vaddr); + return -1; + } + } + } + + list_for_each_entry(ppb, &pp->bufs, l) { + for (i = 0; i < ppb->nr_segs; i++) { + struct iovec iov = ppb->iov[i]; + + if (splice(img_raw_fd(pr->pi), NULL, ppb->p[1], NULL, + iov.iov_len, SPLICE_F_MOVE) != iov.iov_len) { + pr_perror("Splice failed"); + return -1; + } + } + } + + debug_show_page_pipe(pp); + + return 0; +} + +static int page_pipe_from_pagemap(struct page_pipe **pp, int pid) +{ + struct page_read pr; + int nr_pages = 0; + + if (open_page_read(pid, &pr, PR_TASK) <= 0) { + pr_err("Failed to open page read for %d\n", pid); + return -1; + } + + while (pr.advance(&pr)) + if (pagemap_present(pr.pe)) + nr_pages += pr.pe->nr_pages; + + *pp = create_page_pipe(nr_pages, NULL, 0); + if (!*pp) { + pr_err("Cannot create page pipe for %d\n", pid); + return -1; + } + + if (fill_page_pipe(&pr, *pp)) + return -1; + + return 0; +} + +static int page_server_init_send(void) +{ + struct pstree_item *pi; + struct page_pipe *pp; + + BUILD_BUG_ON(sizeof(struct dmp_info) > sizeof(struct rst_info)); + + if (prepare_dummy_pstree()) + return -1; + + for_each_pstree_item(pi) { + if (prepare_dummy_task_state(pi)) + return -1; + + if (!task_alive(pi)) + continue; + + if (page_pipe_from_pagemap(&pp, vpid(pi))) { + pr_err("%d: failed to open page-read\n", vpid(pi)); + return -1; + } + + /* + * prepare_dummy_pstree presumes 'restore' behaviour, + * but page_server_get_pages uses dmpi() to get access + * to the page-pipe, so we are faking it here. + */ + memset(rsti(pi), 0, sizeof(struct rst_info)); + dmpi(pi)->mem_pp = pp; + } + + return 0; +} + int cr_page_server(bool daemon_mode, int cfd) { int ask = -1; int sk = -1; int ret; - if (!opts.lazy_pages) + if (!opts.lazy_pages) { up_page_ids_base(); + } else { + if (page_server_init_send()) + return -1; + } if (opts.ps_socket != -1) { ret = 0; From ac6b3b0a1e078366316b10469cd4bc79abf7b1bb Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 27 Nov 2016 12:52:56 +0200 Subject: [PATCH 0844/4375] zdtm: add 'nolazy' flag for tests not compatible with lazy pages The kernel support for lazy pages (userfaultfd) lacks many important features which effectively prevents success in certain tests. Allow skipping such test with somewhat informative message travis-ci: success for lazy-pages: improve testability (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- test/zdtm.py | 5 +++++ test/zdtm/static/cow00.desc | 2 +- test/zdtm/static/cow01.desc | 2 +- test/zdtm/transition/fork.desc | 1 + test/zdtm/transition/fork2.desc | 1 + 5 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 test/zdtm/transition/fork.desc create mode 100644 test/zdtm/transition/fork2.desc diff --git a/test/zdtm.py b/test/zdtm.py index 43b306a6f..567428488 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1697,6 +1697,11 @@ def run_tests(opts): l.skip(t, "samens test in the same namespace") continue + if opts['lazy_pages']: + if test_flag(tdesc, 'nolazy'): + l.skip(t, "lazy pages are not supported") + continue + test_flavs = tdesc.get('flavor', 'h ns uns').split() opts_flavs = (opts['flavor'] or 'h,ns,uns').split(',') if opts_flavs != ['best']: diff --git a/test/zdtm/static/cow00.desc b/test/zdtm/static/cow00.desc index c303c117c..654ae750a 100644 --- a/test/zdtm/static/cow00.desc +++ b/test/zdtm/static/cow00.desc @@ -1,2 +1,2 @@ # /proc/pid/pagemap doesn't show phys addr for unprivileged users -{'flavor': 'ns h', 'flags': 'suid'} +{'flavor': 'ns h', 'flags': 'suid nolazy'} diff --git a/test/zdtm/static/cow01.desc b/test/zdtm/static/cow01.desc index d969725f6..24a81422f 100644 --- a/test/zdtm/static/cow01.desc +++ b/test/zdtm/static/cow01.desc @@ -1 +1 @@ -{'flavor': 'h ns', 'flags': 'suid'} +{'flavor': 'h ns', 'flags': 'suid nolazy'} diff --git a/test/zdtm/transition/fork.desc b/test/zdtm/transition/fork.desc new file mode 100644 index 000000000..1ffa341ba --- /dev/null +++ b/test/zdtm/transition/fork.desc @@ -0,0 +1 @@ +{'flags' : 'nolazy'} diff --git a/test/zdtm/transition/fork2.desc b/test/zdtm/transition/fork2.desc new file mode 100644 index 000000000..1ffa341ba --- /dev/null +++ b/test/zdtm/transition/fork2.desc @@ -0,0 +1 @@ +{'flags' : 'nolazy'} From c89a22a8e91ba6ca32657e1517513834af39d986 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 27 Nov 2016 12:52:57 +0200 Subject: [PATCH 0845/4375] zdtm: simulate lazy migration with page server that can send pages Lazy migration requires both dumped and restored processes to coexist at the same time. This breaks some basic assumptions in the zdtm design. Simulation of lazy migration with the page server allows testing most of the involved code paths without major intervention into zdtm infrastructure. travis-ci: success for lazy-pages: improve testability (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- test/zdtm.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 567428488..de4705aa2 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -775,7 +775,9 @@ class criu: self.__iter = 0 self.__prev_dump_iter = None self.__page_server = (opts['page_server'] and True or False) - self.__lazy_pages = (opts['lazy_pages'] and True or False) + self.__remote_lazy_pages = (opts['remote_lazy_pages'] and True or False) + self.__lazy_pages = (self.__remote_lazy_pages or + opts['lazy_pages'] and True or False) self.__restore_sibling = (opts['sibling'] and True or False) self.__join_ns = (opts['join_ns'] and True or False) self.__empty_ns = (opts['empty_ns'] and True or False) @@ -963,7 +965,13 @@ class criu: r_opts.append('mnt[zdtm]:%s' % criu_dir) if self.__lazy_pages: - self.__criu_act("lazy-pages", opts = ["--daemon", "--pidfile", "lp.pid"]) + lp_opts = ["--daemon", "--pidfile", "lp.pid"] + if self.__remote_lazy_pages: + lp_opts += ['--page-server', "--port", "12345"] + ps_opts = ["--daemon", "--pidfile", "ps.pid", + "--port", "12345", "--lazy-pages"] + self.__criu_act("page-server", opts = ps_opts) + self.__criu_act("lazy-pages", opts = lp_opts) r_opts += ["--lazy-pages"] if self.__leave_stopped: @@ -1435,7 +1443,7 @@ class launcher: nd = ('nocr', 'norst', 'pre', 'iters', 'page_server', 'sibling', 'stop', 'empty_ns', 'fault', 'keep_img', 'report', 'snaps', 'sat', 'script', 'rpc', 'lazy_pages', - 'join_ns', 'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup') + 'join_ns', 'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup', 'remote_lazy_pages') arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd})) if self.__use_log: @@ -1697,7 +1705,7 @@ def run_tests(opts): l.skip(t, "samens test in the same namespace") continue - if opts['lazy_pages']: + if opts['lazy_pages'] or opts['remote_lazy_pages']: if test_flag(tdesc, 'nolazy'): l.skip(t, "lazy pages are not supported") continue @@ -1937,6 +1945,7 @@ rp.add_argument("--report", help = "Generate summary report in directory") rp.add_argument("--keep-going", help = "Keep running tests in spite of failures", action = 'store_true') rp.add_argument("--ignore-taint", help = "Don't care about a non-zero kernel taint flag", action = 'store_true') rp.add_argument("--lazy-pages", help = "restore pages on demand", action = 'store_true') +rp.add_argument("--remote-lazy-pages", help = "simulate lazy migration", action = 'store_true') lp = sp.add_parser("list", help = "List tests") lp.set_defaults(action = list_tests) From 450981caf00fced04f39486ec08f0dea67409aec Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 29 Nov 2016 14:45:00 +0300 Subject: [PATCH 0846/4375] lazy-pages: fix searching for the page at #PF time After commit a97d6d3f1609 (pagemap: replace seek_page with seek_pagemap method), uffd only searches the pagemap containing the faulting page, but it not for the page itself. For local restore it causes wrong data to be read from pages*img and subsequent crash of the restored process. Adding a call to pr->skip_pages fixes the problem. travis-ci: success for lazy-pages: fix searching for the page at #PF time Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/uffd.c b/criu/uffd.c index 99e6c65f3..99e16e87f 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -604,6 +604,8 @@ static int uffd_seek_or_zero_pages(struct lazy_pages_info *lpi, __u64 address, if (pagemap_zero(lpi->pr.pe)) return uffd_zero(lpi, address, nr); + lpi->pr.skip_pages(&lpi->pr, address - lpi->pr.pe->vaddr); + return 1; } From bf49af10c58f37391f8aeb8dcc2d090b83f4e009 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 1 Dec 2016 11:09:00 +0300 Subject: [PATCH 0847/4375] lazy-pages: spelling: s/pagefalt/#PF travis-ci: success for lazy-pages: spelling: s/pagefalt/#PF Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index 99e16e87f..d4517819f 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -676,7 +676,7 @@ static int handle_user_fault(struct epoll_rfd *lpfd) /* Align requested address to the next page boundary */ address = msg.arg.pagefault.address & ~(page_size() - 1); - pr_debug("%d: pagefalt at 0x%llx\n", lpi->pid, address); + pr_debug("%d: #PF at 0x%llx\n", lpi->pid, address); #if 0 /* From e91e62b00df43bd6ad4361e1eff3356044cdd5e1 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 1 Dec 2016 11:09:00 +0300 Subject: [PATCH 0848/4375] lazy-pages: interleave #PF handling with transfers of remaining pages Currently we poll userfaultfd for page faults and if there were no page faults during 5 seconds we stop monitoring the userfaultfd and start copying remaining pages chunk by chunk. If a page fault occurs during the copy, the faulting process will be stuck until the page it accessed would be copied to its address space. This patch limits the initial "page fault only" stage to 1 second instead of 5, and interleaves non-blocking poll of userfaultfd with copying of the remaining memory afterwards. travis-ci: success for lazy-pages: interleave #PF handling with transfers of remaining pages Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 56 ++++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index d4517819f..70f527f89 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -70,7 +70,6 @@ struct lazy_pages_info { struct list_head l; void *buf; - bool remaining; }; static LIST_HEAD(lpis); @@ -547,9 +546,6 @@ static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long vaddr, if (uffd_copy(lpi, vaddr, nr)) return -1; - if (lpi->remaining) - return 0; - return update_lazy_iovecs(lpi, vaddr, nr * PAGE_SIZE); } @@ -631,18 +627,16 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) struct lazy_iovec *lazy_iov; int nr_pages, err; - lpi->remaining = true; + if (list_empty(&lpi->iovs)) + return 0; - lpi->pr.reset(&lpi->pr); + lazy_iov = list_first_entry(&lpi->iovs, struct lazy_iovec, l); + nr_pages = lazy_iov->len / PAGE_SIZE; - list_for_each_entry(lazy_iov, &lpi->iovs, l) { - nr_pages = lazy_iov->len / PAGE_SIZE; - - err = uffd_handle_pages(lpi, lazy_iov->base, nr_pages, 0); - if (err < 0) { - pr_err("Error during UFFD copy\n"); - return -1; - } + err = uffd_handle_pages(lpi, lazy_iov->base, nr_pages, 0); + if (err < 0) { + pr_err("Error during UFFD copy\n"); + return -1; } return 0; @@ -717,27 +711,37 @@ static int lazy_pages_summary(struct lazy_pages_info *lpi) return 0; } -#define POLL_TIMEOUT 5000 +#define POLL_TIMEOUT 1000 static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) { struct lazy_pages_info *lpi; + int poll_timeout = POLL_TIMEOUT; int ret; - ret = epoll_run_rfds(epollfd, events, nr_fds, POLL_TIMEOUT); - if (ret < 0) - goto out; + for (;;) { + bool remaining = false; - - pr_debug("switching from request to copy mode\n"); - pr_debug("Handle remaining pages\n"); - list_for_each_entry(lpi, &lpis, l) { - ret = handle_remaining_pages(lpi); - if (ret < 0) { - pr_err("Error during remaining page copy\n"); - ret = 1; + ret = epoll_run_rfds(epollfd, events, nr_fds, poll_timeout); + if (ret < 0) goto out; + + if (poll_timeout) + pr_debug("Start handling remaining pages\n"); + + poll_timeout = 0; + list_for_each_entry(lpi, &lpis, l) { + if (lpi->copied_pages < lpi->total_pages) { + remaining = true; + ret = handle_remaining_pages(lpi); + if (ret < 0) + goto out; + break; + } } + + if (!remaining) + break; } list_for_each_entry(lpi, &lpis, l) From 6de76ba0ac567572c8f8e0c7b2c19bb551cdbd2c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 1 Dec 2016 16:59:00 +0300 Subject: [PATCH 0849/4375] test/jenkins: extend lazy-pages testing Add pre-dump and remote-lazy-pages passes to criu-lazy-pages.sh Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- test/jenkins/criu-lazy-pages.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/jenkins/criu-lazy-pages.sh b/test/jenkins/criu-lazy-pages.sh index e3c62cfb4..4ada97201 100755 --- a/test/jenkins/criu-lazy-pages.sh +++ b/test/jenkins/criu-lazy-pages.sh @@ -2,4 +2,14 @@ set -e source `dirname $0`/criu-lib.sh prep -./test/zdtm.py run --all --keep-going --report report --parallel 4 --lazy-pages || fail + +# FIXME: maps007 is sometimes failing with lazy-pages, exclude it for now + +# lazy restore from images +./test/zdtm.py run --all --keep-going --report report --parallel 4 --lazy-pages -x maps007 || fail + +# lazy restore from images with pre-dumps +./test/zdtm.py run --all --keep-going --report report --parallel 4 --lazy-pages --pre 2 -x maps007 || fail + +# lazy restore from "remote" dump +./test/zdtm.py run --all --keep-going --report report --parallel 4 --remote-lazy-pages -x maps007 || fail From 8dcb4e07e9f996b5b3c8e47a6fb5548f14ee190b Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 8 Dec 2016 15:10:11 +0200 Subject: [PATCH 0850/4375] Update criu/include/linux/userfaultfd.h Use latest version from usefaultfd tree [1]. Judging by comments about the last re-spin of userfaultfd updates, the API will go in "as is", so we can pretty much rely on the current API definitions for proper detection of supported userfaultfd features. [1] https://git.kernel.org/cgit/linux/kernel/git/andrea/aa.git/ Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/linux/userfaultfd.h | 53 ++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/criu/include/linux/userfaultfd.h b/criu/include/linux/userfaultfd.h index 9057d7af3..a9c3389ef 100644 --- a/criu/include/linux/userfaultfd.h +++ b/criu/include/linux/userfaultfd.h @@ -11,13 +11,17 @@ #include -#define UFFD_API ((__u64)0xAA) /* - * After implementing the respective features it will become: - * #define UFFD_API_FEATURES (UFFD_FEATURE_PAGEFAULT_FLAG_WP | \ - * UFFD_FEATURE_EVENT_FORK) + * If the UFFDIO_API is upgraded someday, the UFFDIO_UNREGISTER and + * UFFDIO_WAKE ioctls should be defined as _IOW and not as _IOR. In + * userfaultfd.h we assumed the kernel was reading (instead _IOC_READ + * means the userland is reading). */ -#define UFFD_API_FEATURES (0) +#define UFFD_API ((__u64)0xAA) +#define UFFD_API_FEATURES (UFFD_FEATURE_PAGEFAULT_FLAG_WP | \ + UFFD_FEATURE_EVENT_FORK | \ + UFFD_FEATURE_EVENT_REMAP | \ + UFFD_FEATURE_EVENT_MADVDONTNEED) #define UFFD_API_IOCTLS \ ((__u64)1 << _UFFDIO_REGISTER | \ (__u64)1 << _UFFDIO_UNREGISTER | \ @@ -25,7 +29,11 @@ #define UFFD_API_RANGE_IOCTLS \ ((__u64)1 << _UFFDIO_WAKE | \ (__u64)1 << _UFFDIO_COPY | \ - (__u64)1 << _UFFDIO_ZEROPAGE) + (__u64)1 << _UFFDIO_ZEROPAGE | \ + (__u64)1 << _UFFDIO_WRITEPROTECT) +#define UFFD_API_RANGE_IOCTLS_BASIC \ + ((__u64)1 << _UFFDIO_WAKE | \ + (__u64)1 << _UFFDIO_COPY) /* * Valid ioctl command number range with this API is from 0x00 to @@ -40,6 +48,7 @@ #define _UFFDIO_WAKE (0x02) #define _UFFDIO_COPY (0x03) #define _UFFDIO_ZEROPAGE (0x04) +#define _UFFDIO_WRITEPROTECT (0x05) #define _UFFDIO_API (0x3F) /* userfaultfd ioctl ids */ @@ -56,6 +65,8 @@ struct uffdio_copy) #define UFFDIO_ZEROPAGE _IOWR(UFFDIO, _UFFDIO_ZEROPAGE, \ struct uffdio_zeropage) +#define UFFDIO_WRITEPROTECT _IOWR(UFFDIO, _UFFDIO_WRITEPROTECT, \ + struct uffdio_writeprotect) /* read() structure */ struct uffd_msg { @@ -71,6 +82,21 @@ struct uffd_msg { __u64 address; } pagefault; + struct { + __u32 ufd; + } fork; + + struct { + __u64 from; + __u64 to; + __u64 len; + } remap; + + struct { + __u64 start; + __u64 end; + } madv_dn; + struct { /* unused reserved fields */ __u64 reserved1; @@ -84,9 +110,9 @@ struct uffd_msg { * Start at 0x12 and not at 0 to be more strict against bugs. */ #define UFFD_EVENT_PAGEFAULT 0x12 -#if 0 /* not available yet */ #define UFFD_EVENT_FORK 0x13 -#endif +#define UFFD_EVENT_REMAP 0x14 +#define UFFD_EVENT_MADVDONTNEED 0x15 /* flags for UFFD_EVENT_PAGEFAULT */ #define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */ @@ -105,10 +131,10 @@ struct uffdio_api { * are to be considered implicitly always enabled in all kernels as * long as the uffdio_api.api requested matches UFFD_API. */ -#if 0 /* not available yet */ #define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0) #define UFFD_FEATURE_EVENT_FORK (1<<1) -#endif +#define UFFD_FEATURE_EVENT_REMAP (1<<2) +#define UFFD_FEATURE_EVENT_MADVDONTNEED (1<<3) __u64 features; __u64 ioctls; @@ -164,4 +190,11 @@ struct uffdio_zeropage { __s64 zeropage; }; +struct uffdio_writeprotect { + struct uffdio_range range; + /* !WP means undo writeprotect. DONTWAKE is valid only with !WP */ +#define UFFDIO_WRITEPROTECT_MODE_WP ((__u64)1<<0) +#define UFFDIO_WRITEPROTECT_MODE_DONTWAKE ((__u64)1<<1) + __u64 mode; +}; #endif /* _LINUX_USERFAULTFD_H */ From ce5e19162f80c2bceed3bba4040e2e0cf69c0d3d Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 8 Dec 2016 15:10:12 +0200 Subject: [PATCH 0851/4375] Make userfaultfd detection a part of kerndat Instead of checking for availability of userfaultfd late during the restore process, make the detection of supported userfaultfd functionality part of kerndat. As a bonus, I've extended criu check with ability to verify presence of userfaultfd. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-check.c | 20 ++++++++++++++++++++ criu/include/kerndat.h | 2 ++ criu/kerndat.c | 41 +++++++++++++++++++++++++++++++++++++++++ criu/uffd.c | 25 +------------------------ 4 files changed, 64 insertions(+), 24 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index 1dd887aa0..29e607f76 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -50,6 +50,7 @@ #include "libnetlink.h" #include "net.h" #include "restorer.h" +#include "linux/userfaultfd.h" static char *feature_name(int (*func)()); @@ -1045,6 +1046,23 @@ static int check_compat_cr(void) return -1; } +static int check_uffd(void) +{ + unsigned long features = UFFD_FEATURE_EVENT_FORK | + UFFD_FEATURE_EVENT_REMAP | + UFFD_FEATURE_EVENT_MADVDONTNEED; + + if (kerndat_uffd(true)) + return -1; + + if ((kdat.uffd_features & features) != features) { + pr_err("Userfaultfd missing essential features\n"); + return -1; + } + + return 0; +} + static int (*chk_feature)(void); /* @@ -1156,6 +1174,7 @@ int cr_check(void) if (opts.check_experimental_features) { ret |= check_autofs(); ret |= check_compat_cr(); + ret |= check_uffd(); } print_on_level(DEFAULT_LOGLEVEL, "%s\n", ret ? CHECK_MAYBE : CHECK_GOOD); @@ -1197,6 +1216,7 @@ static struct feature_list feature_list[] = { { "autofs", check_autofs }, { "tcp_half_closed", check_tcp_halt_closed }, { "compat_cr", check_compat_cr }, + { "lazy_pages", check_uffd }, { NULL, NULL }, }; diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index c27ece017..4078f06ce 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -49,6 +49,7 @@ struct kerndat_s { bool has_tcp_half_closed; bool stack_guard_gap_hidden; int lsm; + unsigned long uffd_features; }; extern struct kerndat_s kdat; @@ -70,5 +71,6 @@ enum { extern int kerndat_fs_virtualized(unsigned int which, u32 kdev); extern int kerndat_tcp_repair(); +extern int kerndat_uffd(bool need_uffd); #endif /* __CR_KERNDAT_H__ */ diff --git a/criu/kerndat.c b/criu/kerndat.c index 80ec58bcf..1a40ff035 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -30,6 +30,7 @@ #include #include #include "netfilter.h" +#include "linux/userfaultfd.h" struct kerndat_s kdat = { }; @@ -714,6 +715,44 @@ unl: } } +int kerndat_uffd(bool need_uffd) +{ + struct uffdio_api uffdio_api; + int uffd; + + uffd = syscall(SYS_userfaultfd, 0); + + /* + * uffd == -1 is probably enough to not use lazy-restore + * on this system. Additionally checking for ENOSYS + * makes sure it is actually not implemented. + */ + if (uffd == -1 && errno == ENOSYS) { + if (!need_uffd) + return 0; + + pr_err("Lazy pages are not available\n"); + return -1; + } + + uffdio_api.api = UFFD_API; + uffdio_api.features = 0; + if (ioctl(uffd, UFFDIO_API, &uffdio_api)) { + pr_perror("Failed to get uffd API"); + return -1; + } + if (uffdio_api.api != UFFD_API) { + pr_err("Incompatible uffd API: expected %Lu, got %Lu\n", + UFFD_API, uffdio_api.api); + return -1; + } + + kdat.uffd_features = uffdio_api.features; + + close(uffd); + return 0; +} + int kerndat_init(void) { int ret; @@ -752,6 +791,8 @@ int kerndat_init(void) ret = kerndat_has_memfd_create(); if (!ret) ret = kerndat_detect_stack_guard_gap(); + if (!ret) + ret = kerndat_uffd(opts.lazy_pages); kerndat_lsm(); kerndat_mmap_min_addr(); diff --git a/criu/uffd.c b/criu/uffd.c index 70f527f89..00153f465 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -166,27 +166,6 @@ out: return ret; } -/* Runtime detection if userfaultfd can be used */ - -static int check_for_uffd() -{ - int uffd; - - uffd = syscall(SYS_userfaultfd, 0); - /* - * uffd == -1 is probably enough to not use lazy-restore - * on this system. Additionally checking for ENOSYS - * makes sure it is actually not implemented. - */ - if ((uffd == -1) && (errno == ENOSYS)) { - pr_err("Runtime detection of userfaultfd failed on this system.\n"); - pr_err("Processes cannot be lazy-restored on this system.\n"); - return -1; - } - close(uffd); - return 0; -} - int lazy_pages_setup_zombie(int pid) { if (!opts.lazy_pages) @@ -208,8 +187,6 @@ int setup_uffd(int pid, struct task_restore_args *task_args) return 0; } - if (check_for_uffd()) - return -1; /* * Open userfaulfd FD which is passed to the restorer blob and * to a second process handling the userfaultfd page faults. @@ -812,7 +789,7 @@ int cr_lazy_pages(bool daemon) int lazy_sk; int ret; - if (check_for_uffd()) + if (kerndat_uffd(true)) return -1; if (prepare_dummy_pstree()) From 1e9055944ea00ed5af005bfb4b208bc0d783033a Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 14 Dec 2016 20:25:00 +0300 Subject: [PATCH 0852/4375] lazy-pages: add comments to update_lazy_iovecs This function does weird things, so better have it at least somehow documented. travis-ci: success for lazy-pages: add comments to update_lazy_iovecs Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/criu/uffd.c b/criu/uffd.c index 00153f465..e55a9596c 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -302,6 +302,10 @@ static MmEntry *init_mm_entry(struct lazy_pages_info *lpi) return mm; } +/* + * Purge range (addr, addr + len) from lazy_iovecs. The range may + * cover several continuous IOVs. + */ static int update_lazy_iovecs(struct lazy_pages_info *lpi, unsigned long addr, int len) { @@ -317,6 +321,13 @@ static int update_lazy_iovecs(struct lazy_pages_info *lpi, unsigned long addr, if (addr < start || addr >= end) continue; + /* + * The range completely fits into the current IOV. + * If addr equals iov_base we just "drop" the + * beginning of the IOV. Otherwise, we make the IOV to + * end at addr, and add a new IOV start starts at + * addr + len. + */ if (addr + len < end) { if (addr == start) { lazy_iov->base += len; @@ -338,6 +349,12 @@ static int update_lazy_iovecs(struct lazy_pages_info *lpi, unsigned long addr, break; } + /* + * The range spawns beyond the end of the current IOV. + * If addr equals iov_base we just "drop" the entire + * IOV. Otherwise, we cut the beginning of the IOV + * and continue to the next one with the updated range + */ if (addr == start) { list_del(&lazy_iov->l); xfree(lazy_iov); From 4335be91bf7d232e0be3a6c7221322975fd71685 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 15 Dec 2016 09:42:00 +0300 Subject: [PATCH 0853/4375] pagemap: verify the number of pages returned by receive_remote_pages_info CID 173076, issues/259 travis-ci: success for pagemap: verify the number of pages returned by receive_remote_pages_info Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/pagemap.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/criu/pagemap.c b/criu/pagemap.c index 7fbe503fd..5de026356 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -440,7 +440,7 @@ static int read_page_complete(int pid, unsigned long vaddr, int nr_pages, void * static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, int nr, void *buf, unsigned flags) { - int ret, pid; + int ret, pid, new_nr; /* We always do PR_ASAP mode here (FIXME?) */ ret = request_remote_pages(pr->pid, vaddr, nr); @@ -453,9 +453,12 @@ static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, * Note, that for async remote page_read, the actual * transfer happens in the lazy-pages daemon */ - ret = receive_remote_pages_info(&nr, &vaddr, &pid); - if (ret == 0) + ret = receive_remote_pages_info(&new_nr, &vaddr, &pid); + if (ret == 0) { + if (new_nr < 0 || new_nr > nr) + return -1; ret = receive_remote_pages(nr * PAGE_SIZE, buf); + } if (ret == 0 && pr->io_complete) ret = pr->io_complete(pr, vaddr, nr); From 0019a68ce5dc76e8cfa6d1a683a38737532d8a0e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 15 Dec 2016 14:10:37 +0200 Subject: [PATCH 0854/4375] lazy-pages: zero out pages not covered by the pagemap If a page was not marked "present" at the dump time it will not be covered by the pagemap and it will remain unmapped in the restored process. We should uffdio_zero such pages and let kernel mm to take over. travis-ci: success for revert zero pagemaps Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index e55a9596c..f0fae586a 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -588,10 +588,7 @@ static int uffd_seek_or_zero_pages(struct lazy_pages_info *lpi, __u64 address, lpi->pr.reset(&lpi->pr); ret = lpi->pr.seek_pagemap(&lpi->pr, address); - if (!ret) - return 0; - - if (pagemap_zero(lpi->pr.pe)) + if (!ret || pagemap_zero(lpi->pr.pe)) return uffd_zero(lpi, address, nr); lpi->pr.skip_pages(&lpi->pr, address - lpi->pr.pe->vaddr); From bf63367061484af81c2f4342958e4a66953ffc6c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 15 Dec 2016 14:10:38 +0200 Subject: [PATCH 0855/4375] lazy-pages: stop checking for zero pagemaps A page that explicitly mapped to zero pfn or a page that is not present should be treated in the same way, therefore the zero pagemaps are not required and will be removed by the following commits. travis-ci: success for revert zero pagemaps Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index f0fae586a..fd63de65f 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -588,7 +588,7 @@ static int uffd_seek_or_zero_pages(struct lazy_pages_info *lpi, __u64 address, lpi->pr.reset(&lpi->pr); ret = lpi->pr.seek_pagemap(&lpi->pr, address); - if (!ret || pagemap_zero(lpi->pr.pe)) + if (!ret) return uffd_zero(lpi, address, nr); lpi->pr.skip_pages(&lpi->pr, address - lpi->pr.pe->vaddr); From 48675a3c7ed3f5f00ca38a31205f2b0afbd7daa0 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 15 Dec 2016 14:10:40 +0200 Subject: [PATCH 0856/4375] Drop support for zero pagemap entries The pagemap entries for pages mapped to zero pfn proved to be not useful... travis-ci: success for revert zero pagemaps Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/pagemap.h | 12 +++--------- criu/mem.c | 26 +++++++++++--------------- criu/page-xfer.c | 11 +---------- criu/pagemap.c | 17 ++++------------- criu/shmem.c | 2 +- lib/py/images/pb2dict.py | 5 ++--- 6 files changed, 22 insertions(+), 51 deletions(-) diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index 549e9d388..db9fae53c 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -46,7 +46,7 @@ struct page_read { /* reads page from current pagemap */ int (*read_pages)(struct page_read *, unsigned long vaddr, int nr, void *, unsigned flags); - /* Advance page_read to the next entry (including zero pagemaps) */ + /* Advance page_read to the next entry */ int (*advance)(struct page_read *pr); void (*close)(struct page_read *); void (*skip_pages)(struct page_read *, unsigned long len); @@ -122,20 +122,14 @@ static inline unsigned long pagemap_len(PagemapEntry *pe) /* Pagemap flags */ #define PE_PARENT (1 << 0) /* pages are in parent snapshot */ -#define PE_ZERO (1 << 1) /* pages can be lazily restored */ -#define PE_LAZY (1 << 2) /* pages are mapped to zero pfn */ -#define PE_PRESENT (1 << 3) /* pages are present in pages*img */ +#define PE_LAZY (1 << 1) /* pages can be lazily restored */ +#define PE_PRESENT (1 << 2) /* pages are present in pages*img */ static inline bool pagemap_in_parent(PagemapEntry *pe) { return !!(pe->flags & PE_PARENT); } -static inline bool pagemap_zero(PagemapEntry *pe) -{ - return !!(pe->flags & PE_ZERO); -} - static inline bool pagemap_lazy(PagemapEntry *pe) { return !!(pe->flags & PE_LAZY); diff --git a/criu/mem.c b/criu/mem.c index cb880cf81..4326e5acd 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -109,7 +109,7 @@ bool should_dump_page(VmaEntry *vmae, u64 pme) return false; if (vma_entry_is(vmae, VMA_AREA_AIORING)) return true; - if (pme & (PME_PRESENT | PME_SWAP)) + if ((pme & (PME_PRESENT | PME_SWAP)) && !page_is_zero(pme)) return true; return false; @@ -143,7 +143,7 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u { u64 *at = &map[PAGE_PFN(*off)]; unsigned long pfn, nr_to_scan; - unsigned long pages[4] = {}; + unsigned long pages[3] = {}; nr_to_scan = (vma_area_len(vma) - *off) / PAGE_SIZE; @@ -167,18 +167,15 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u * page. The latter would be checked in page-xfer. */ - if (page_is_zero(at[pfn])) { - ret = page_pipe_add_hole(pp, vaddr, PP_HOLE_ZERO); - pages[0]++; - } else if (has_parent && page_in_parent(at[pfn] & PME_SOFT_DIRTY)) { + if (has_parent && page_in_parent(at[pfn] & PME_SOFT_DIRTY)) { ret = page_pipe_add_hole(pp, vaddr, PP_HOLE_PARENT); - pages[1]++; + pages[0]++; } else { ret = page_pipe_add_page(pp, vaddr, ppb_flags); if (ppb_flags & PPB_LAZY && opts.lazy_pages) - pages[2]++; + pages[1]++; else - pages[3]++; + pages[2]++; } if (ret) { @@ -190,13 +187,12 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u *off += pfn * PAGE_SIZE; cnt_add(CNT_PAGES_SCANNED, nr_to_scan); - cnt_add(CNT_PAGES_ZERO, pages[0]); - cnt_add(CNT_PAGES_SKIPPED_PARENT, pages[1]); - cnt_add(CNT_PAGES_LAZY, pages[2]); - cnt_add(CNT_PAGES_WRITTEN, pages[3]); + cnt_add(CNT_PAGES_SKIPPED_PARENT, pages[0]); + cnt_add(CNT_PAGES_LAZY, pages[1]); + cnt_add(CNT_PAGES_WRITTEN, pages[2]); - pr_info("Pagemap generated: %lu pages (%lu lazy) %lu holes %lu zeros\n", - pages[3] + pages[2], pages[2], pages[1], pages[0]); + pr_info("Pagemap generated: %lu pages (%lu lazy) %lu holes\n", + pages[2] + pages[1], pages[1], pages[0]); return 0; } diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 084d5a7cc..bfe99e43d 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -169,8 +169,6 @@ static int write_pagemap_to_server(struct page_xfer *xfer, struct iovec *iov, u3 cmd = PS_IOV_HOLE; else if (flags & PE_LAZY) cmd = PS_IOV_LAZY; - else if (flags & PE_ZERO) - cmd = PS_IOV_ZERO; else BUG(); @@ -411,8 +409,6 @@ static int get_hole_flags(struct page_pipe *pp, int n) if (hole_flags == PP_HOLE_PARENT) return PE_PARENT; - if (hole_flags == PP_HOLE_ZERO) - return PE_ZERO; else BUG(); @@ -812,9 +808,6 @@ static int page_server_serve(int sk) case PS_IOV_HOLE: ret = page_server_add(sk, &pi, PE_PARENT); break; - case PS_IOV_ZERO: - ret = page_server_add(sk, &pi, PE_ZERO); - break; case PS_IOV_LAZY: ret = page_server_add(sk, &pi, PE_LAZY); break; @@ -888,9 +881,7 @@ static int fill_page_pipe(struct page_read *pr, struct page_pipe *pp) unsigned long vaddr = pr->pe->vaddr; for (i = 0; i < pr->pe->nr_pages; i++, vaddr += PAGE_SIZE) { - if (pagemap_zero(pr->pe)) - ret = page_pipe_add_hole(pp, vaddr, PP_HOLE_ZERO); - else if (pagemap_in_parent(pr->pe)) + if (pagemap_in_parent(pr->pe)) ret = page_pipe_add_hole(pp, vaddr, PP_HOLE_PARENT); else ret = page_pipe_add_page(pp, vaddr, pagemap_lazy(pr->pe) ? PPB_LAZY : 0); diff --git a/criu/pagemap.c b/criu/pagemap.c index 5de026356..3848558ce 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -125,19 +125,13 @@ int dedup_one_iovec(struct page_read *pr, unsigned long off, unsigned long len) static int advance(struct page_read *pr) { - for (;;) { - pr->curr_pme++; - if (pr->curr_pme >= pr->nr_pmes) - return 0; - - pe = pr->pmes[pr->curr_pme]; - - if (!pagemap_zero(pe)) - break; - } + pr->curr_pme++; + if (pr->curr_pme >= pr->nr_pmes) + return 0; pr->pe = pr->pmes[pr->curr_pme]; pr->cvaddr = pr->pe->vaddr; + return 1; } @@ -475,9 +469,6 @@ static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, int nr, if (pagemap_in_parent(pr->pe)) { if (read_parent_page(pr, vaddr, nr, buf, flags) < 0) return -1; - } else if (pagemap_zero(pr->pe)) { - /* zero mappings should be skipped by get_pagemap */ - BUG(); } else { if (pr->maybe_read_page(pr, vaddr, nr, buf, flags) < 0) return -1; diff --git a/criu/shmem.c b/criu/shmem.c index e8aeee867..cc5157d6b 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -711,7 +711,7 @@ static int do_dump_one_shmem(int fd, void *addr, struct shmem_info *si) pgaddr = (unsigned long)addr + pfn * PAGE_SIZE; again: if (pgstate == PST_ZERO) - ret = page_pipe_add_hole(pp, pgaddr, PP_HOLE_ZERO); + ret = 0; else if (xfer.parent && page_in_parent(pgstate == PST_DIRTY)) ret = page_pipe_add_hole(pp, pgaddr, PP_HOLE_PARENT); else diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index f2d26fb26..bf05278ff 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -107,9 +107,8 @@ rfile_flags_map = [ pmap_flags_map = [ ('PE_PARENT', 1 << 0), - ('PE_ZERO', 1 << 1), - ('PE_LAZY', 1 << 2), - ('PE_PRESENT', 1 << 3), + ('PE_LAZY', 1 << 1), + ('PE_PRESENT', 1 << 2), ]; flags_maps = { From 6cac33723deb440a7f75d4ba3c901848e907cc1a Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 15 Dec 2016 14:10:41 +0200 Subject: [PATCH 0857/4375] stats: drop zero pages stats Note, that since zero pages stats never been into master we can make incompatible changes to stats image. travis-ci: success for revert zero pagemaps Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/stats.h | 1 - criu/stats.c | 3 --- images/stats.proto | 3 +-- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/criu/include/stats.h b/criu/include/stats.h index 5d7177815..d30be6a39 100644 --- a/criu/include/stats.h +++ b/criu/include/stats.h @@ -25,7 +25,6 @@ enum { CNT_PAGES_SCANNED, CNT_PAGES_SKIPPED_PARENT, CNT_PAGES_WRITTEN, - CNT_PAGES_ZERO, CNT_PAGES_LAZY, DUMP_CNT_NR_STATS, diff --git a/criu/stats.c b/criu/stats.c index 7f0e154a1..2b0c1a60b 100644 --- a/criu/stats.c +++ b/criu/stats.c @@ -120,8 +120,6 @@ static void display_stats(int what, StatsEntry *stats) stats->dump->pages_skipped_parent); pr_msg("Memory pages written: %" PRIu64 " (0x%" PRIx64 ")\n", stats->dump->pages_written, stats->dump->pages_written); - pr_msg("Zero memory pages: %" PRIu64 " (0x%" PRIx64 ")\n", stats->dump->pages_zero, - stats->dump->pages_zero); pr_msg("Lazy memory pages: %" PRIu64 " (0x%" PRIx64 ")\n", stats->dump->pages_lazy, stats->dump->pages_lazy); } else if (what == RESTORE_STATS) { @@ -161,7 +159,6 @@ void write_stats(int what) ds_entry.pages_scanned = dstats->counts[CNT_PAGES_SCANNED]; ds_entry.pages_skipped_parent = dstats->counts[CNT_PAGES_SKIPPED_PARENT]; ds_entry.pages_written = dstats->counts[CNT_PAGES_WRITTEN]; - ds_entry.pages_zero = dstats->counts[CNT_PAGES_ZERO]; ds_entry.pages_lazy = dstats->counts[CNT_PAGES_LAZY]; name = "dump"; diff --git a/images/stats.proto b/images/stats.proto index f926a5a89..ad6279a81 100644 --- a/images/stats.proto +++ b/images/stats.proto @@ -13,8 +13,7 @@ message dump_stats_entry { optional uint32 irmap_resolve = 8; - required uint64 pages_zero = 9; - required uint64 pages_lazy = 10; + required uint64 pages_lazy = 9; } message restore_stats_entry { From fbb2c72d233a01042961642700097154ce220e05 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 15 Dec 2016 14:10:42 +0200 Subject: [PATCH 0858/4375] mem: provide inline versions for page_{in_parent,is_zero} travis-ci: success for revert zero pagemaps Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/mem.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/criu/mem.c b/criu/mem.c index 4326e5acd..a6ef995db 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -82,6 +82,21 @@ unsigned long dump_pages_args_size(struct vm_area_list *vmas) (vmas->priv_size + 1) * sizeof(struct iovec); } +static inline bool __page_is_zero(u64 pme) +{ + return (pme & PME_PFRAME_MASK) == kdat.zero_page_pfn; +} + +static inline bool __page_in_parent(bool dirty) +{ + /* + * If we do memory tracking, but w/o parent images, + * then we have to dump all memory + */ + + return opts.track_mem && opts.img_parent && !dirty; +} + bool should_dump_page(VmaEntry *vmae, u64 pme) { #ifdef CONFIG_VDSO @@ -109,7 +124,7 @@ bool should_dump_page(VmaEntry *vmae, u64 pme) return false; if (vma_entry_is(vmae, VMA_AREA_AIORING)) return true; - if ((pme & (PME_PRESENT | PME_SWAP)) && !page_is_zero(pme)) + if ((pme & (PME_PRESENT | PME_SWAP)) && !__page_is_zero(pme)) return true; return false; @@ -117,17 +132,12 @@ bool should_dump_page(VmaEntry *vmae, u64 pme) bool page_is_zero(u64 pme) { - return (pme & PME_PFRAME_MASK) == kdat.zero_page_pfn; + return __page_is_zero(pme); } bool page_in_parent(bool dirty) { - /* - * If we do memory tracking, but w/o parent images, - * then we have to dump all memory - */ - - return opts.track_mem && opts.img_parent && !dirty; + return __page_in_parent(dirty); } /* From a3aa27ef665660c6e1b20e81baf8a1c2b14864dd Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 15 Dec 2016 14:10:43 +0200 Subject: [PATCH 0859/4375] page-pipe: drop unused PP_HOLE_ZERO flag travis-ci: success for revert zero pagemaps Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/page-pipe.h | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h index ea91dac1e..10ae87321 100644 --- a/criu/include/page-pipe.h +++ b/criu/include/page-pipe.h @@ -102,7 +102,6 @@ struct page_pipe_buf { }; #define PP_HOLE_PARENT (1 << 0) -#define PP_HOLE_ZERO (1 << 1) struct page_pipe { unsigned int nr_pipes; /* how many page_pipe_bufs in there */ From e5b4fcb6cd21be853d07662faef867cb4d01148d Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 9 Jan 2017 10:23:15 +0200 Subject: [PATCH 0860/4375] zdtm.py: postpone waiting for lazy-pages daemon Currently we are waiting for lazy-pages daemon to finish as a part of .restore method, which may cause filling test process memory before the test process resumed it's execution after call to test_waitsig(). In such case, no page faults occur, but rather all the memory is copied in handle_remaining_pages method in uffd.c. Let's move wait(,..) after call to test.stop(). travis-ci: success for lazy-pages: add non-#PF events handling Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- test/zdtm.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index de4705aa2..08dbc40ec 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -792,6 +792,10 @@ class criu: self.__lazy_pages_p = None self.__page_server_p = None + def fini(self, opts): + if self.__lazy_pages: + wait_pid_die(int(rpidfile(self.__ddir() + "/lp.pid")), "lazy-pages") + def logs(self): return self.__dump_path @@ -995,9 +999,6 @@ class criu: pstree_check_stopped(self.__test.getpid()) pstree_signal(self.__test.getpid(), signal.SIGCONT) - if self.__lazy_pages: - wait_pid_die(int(rpidfile(self.__ddir() + "/lp.pid")), "lazy pages daemon") - @staticmethod def check(feature): return criu_cli.run("check", ["-v0", "--feature", feature]) == 0 @@ -1353,6 +1354,7 @@ def do_run_test(tname, tdesc, flavs, opts): if opts['join_ns']: check_joinns_state(t) t.stop() + cr_api.fini(opts) try_run_hook(t, ["--clean"]) except test_fail_exc as e: print_sep("Test %s FAIL at %s" % (tname, e.step), '#') From 82668f673475916623b0299c5cb0e5ea98ba3e0a Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 9 Jan 2017 10:23:16 +0200 Subject: [PATCH 0861/4375] util: epoll_run: fix event processing loop The number of pending events returned by epoll_wait is overridden by the first call to an event handler. Using an additional local variable resolves this issue. travis-ci: success for lazy-pages: add non-#PF events handling Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/util.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/criu/util.c b/criu/util.c index 876ff9577..82fbb987c 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1230,7 +1230,7 @@ int epoll_add_rfd(int epfd, struct epoll_rfd *rfd) int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout) { - int ret = 0, i; + int ret, i, nr_events; while (1) { /* FIXME -- timeout should decrease over time... */ @@ -1243,7 +1243,8 @@ int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout break; } - for (i = 0; i < ret; i++) { + nr_events = ret; + for (i = 0; i < nr_events; i++) { struct epoll_rfd *rfd; rfd = (struct epoll_rfd *)evs[i].data.ptr; From fcfdc196103bcd6ec8f3549c945c2e6c1bf85bf0 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 9 Jan 2017 10:23:17 +0200 Subject: [PATCH 0862/4375] util: epoll_run: allow interrupting event polling If an event handler returns a positive value, the event polling and handling loop is interrupted after all the pending events indicated by epoll_wait are processed. travis-ci: success for lazy-pages: add non-#PF events handling Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/util.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/criu/util.c b/criu/util.c index 82fbb987c..8be400e37 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1231,6 +1231,7 @@ int epoll_add_rfd(int epfd, struct epoll_rfd *rfd) int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout) { int ret, i, nr_events; + bool have_a_break = false; while (1) { /* FIXME -- timeout should decrease over time... */ @@ -1251,7 +1252,12 @@ int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout ret = rfd->revent(rfd); if (ret < 0) goto out; + if (ret > 0) + have_a_break = true; } + + if (have_a_break) + return 1; } out: return ret; From 39f1388b4f416a703787c1a604b73f589fb3a44b Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 9 Jan 2017 10:23:18 +0200 Subject: [PATCH 0863/4375] lazy-pages: prepare for non-#PF events handling Rename handle_user_fault to handle_uffd_event and split actual page fault handling to a helper function travis-ci: success for lazy-pages: add non-#PF events handling Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 60 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index fd63de65f..d1cae090f 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -73,7 +73,7 @@ struct lazy_pages_info { }; static LIST_HEAD(lpis); -static int handle_user_fault(struct epoll_rfd *lpfd); +static int handle_uffd_event(struct epoll_rfd *lpfd); static struct lazy_pages_info *lpi_init(void) { @@ -86,7 +86,7 @@ static struct lazy_pages_info *lpi_init(void) memset(lpi, 0, sizeof(*lpi)); INIT_LIST_HEAD(&lpi->iovs); INIT_LIST_HEAD(&lpi->l); - lpi->lpfd.revent = handle_user_fault; + lpi->lpfd.revent = handle_uffd_event; return lpi; } @@ -633,34 +633,13 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) return 0; } -static int handle_user_fault(struct epoll_rfd *lpfd) +static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) { - struct lazy_pages_info *lpi; - struct uffd_msg msg; __u64 address; int ret; - lpi = container_of(lpfd, struct lazy_pages_info, lpfd); - - ret = read(lpfd->fd, &msg, sizeof(msg)); - if (!ret) - return 1; - - if (ret != sizeof(msg)) { - if (ret < 0) - pr_perror("Can't read userfaultfd message"); - else - pr_err("Can't read userfaultfd message: short read"); - return -1; - } - - if (msg.event != UFFD_EVENT_PAGEFAULT) { - pr_err("unexpected msg event %u\n", msg.event); - return -1; - } - /* Align requested address to the next page boundary */ - address = msg.arg.pagefault.address & ~(page_size() - 1); + address = msg->arg.pagefault.address & ~(page_size() - 1); pr_debug("%d: #PF at 0x%llx\n", lpi->pid, address); #if 0 @@ -687,6 +666,37 @@ static int handle_user_fault(struct epoll_rfd *lpfd) return 0; } +static int handle_uffd_event(struct epoll_rfd *lpfd) +{ + struct lazy_pages_info *lpi; + struct uffd_msg msg; + int ret; + + lpi = container_of(lpfd, struct lazy_pages_info, lpfd); + + ret = read(lpfd->fd, &msg, sizeof(msg)); + if (!ret) + return 1; + + if (ret != sizeof(msg)) { + if (ret < 0) + pr_perror("Can't read userfaultfd message"); + else + pr_err("Can't read userfaultfd message: short read"); + return -1; + } + + switch (msg.event) { + case UFFD_EVENT_PAGEFAULT: + return handle_page_fault(lpi, &msg); + default: + pr_err("unexpected uffd event %u\n", msg.event); + return -1; + } + + return 0; +} + static int lazy_pages_summary(struct lazy_pages_info *lpi) { pr_debug("Process %d: with UFFD transferred pages: (%ld/%ld)\n", From 6f82f87a44dcf7eb1c7cc4d27d7444a4cd58abed Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Fri, 13 Jan 2017 13:41:00 +0300 Subject: [PATCH 0864/4375] lazy-pages: enable lazy-pages via RPC To use lazy-pages from runc '--lazy-pages' functionality needs to be accessible via RPC. This enables lazy-pages via RPC. The information on which port to listen is taken from the criu_page_server_info protobuf structure. If the user has enabled lazy-pages via RPC only criu_page_server_info.port is evaluated to get the listen port. With additional patches in runc is it possible to use lazy-restore with 'runc checkpoint' and 'runc restore'. travis-ci: success for lazy-pages: enable lazy-pages via RPC Signed-off-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/cr-service.c | 19 +++++++++++++------ images/rpc.proto | 1 + 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index b93d55345..c746e2575 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -371,16 +371,23 @@ static int setup_opts_from_req(int sk, CriuOpts *req) opts.exec_cmd[req->n_exec_cmd] = NULL; } + if (req->has_lazy_pages) { + opts.lazy_pages = req->lazy_pages; + } + if (req->ps) { - opts.use_page_server = true; - opts.addr = req->ps->address; opts.port = htons((short)req->ps->port); - if (req->ps->has_fd) { - if (!opts.swrk_restore) - goto err; + if (!opts.lazy_pages) { + opts.use_page_server = true; + opts.addr = req->ps->address; - opts.ps_socket = req->ps->fd; + if (req->ps->has_fd) { + if (!opts.swrk_restore) + goto err; + + opts.ps_socket = req->ps->fd; + } } } diff --git a/images/rpc.proto b/images/rpc.proto index cdd186b13..48e42e26e 100644 --- a/images/rpc.proto +++ b/images/rpc.proto @@ -108,6 +108,7 @@ message criu_opts { optional uint32 timeout = 45; optional bool tcp_skip_in_flight = 46; optional bool weak_sysctls = 47; + optional bool lazy_pages = 48; optional int32 status_fd = 49; optional bool orphan_pts_master = 50; } From d1051de0213fa8f9f39ee4eae0f68718eeed284c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 11 Jan 2017 11:37:00 +0300 Subject: [PATCH 0865/4375] lazy-pages: fix lazy dump The introduction of page-server send mode have broken the lazy dump because instead of using existing pstree, the page server now tries to recreate the pstree from the images. Adding lazy_dump parameter to cr_page_server resolves this issue. travis-ci: success for lazy-pages: fix lazy dump Signed-off-by: Mike Rapoport Acked-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- criu/cr-dump.c | 2 +- criu/cr-service.c | 2 +- criu/crtools.c | 2 +- criu/include/page-xfer.h | 2 +- criu/page-xfer.c | 7 +++---- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 01063af03..2a5595c97 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1602,7 +1602,7 @@ static int cr_lazy_mem_dump(void) int ret = 0; pr_info("Starting lazy pages server\n"); - ret = cr_page_server(false, -1); + ret = cr_page_server(false, true, -1); for_each_pstree_item(item) { destroy_page_pipe(dmpi(item)->mem_pp); diff --git a/criu/cr-service.c b/criu/cr-service.c index c746e2575..81b0bc632 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -735,7 +735,7 @@ static int start_page_server_req(int sk, CriuOpts *req) pr_debug("Starting page server\n"); - pid = cr_page_server(true, start_pipe[1]); + pid = cr_page_server(true, false, start_pipe[1]); if (pid < 0) goto out_ch; diff --git a/criu/crtools.c b/criu/crtools.c index 06471f179..af1f0c588 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -744,7 +744,7 @@ int main(int argc, char *argv[], char *envp[]) return cr_check() != 0; if (!strcmp(argv[optind], "page-server")) - return cr_page_server(opts.daemon_mode, -1) != 0; + return cr_page_server(opts.daemon_mode, false, -1) != 0; if (!strcmp(argv[optind], "service")) return cr_service(opts.daemon_mode); diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index dfe43e5a1..1f59bdb03 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -2,7 +2,7 @@ #define __CR_PAGE_XFER__H__ #include "pagemap.h" -extern int cr_page_server(bool daemon_mode, int cfd); +extern int cr_page_server(bool daemon_mode, bool lazy_dump, int cfd); /* * page_xfer -- transfer pages into image file. diff --git a/criu/page-xfer.c b/criu/page-xfer.c index bfe99e43d..e282536f2 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -969,18 +969,17 @@ static int page_server_init_send(void) return 0; } -int cr_page_server(bool daemon_mode, int cfd) +int cr_page_server(bool daemon_mode, bool lazy_dump, int cfd) { int ask = -1; int sk = -1; int ret; - if (!opts.lazy_pages) { + if (!opts.lazy_pages) up_page_ids_base(); - } else { + else if (!lazy_dump) if (page_server_init_send()) return -1; - } if (opts.ps_socket != -1) { ret = 0; From f75db3cdc92a62c7a1d74dc2a244c11cc8b4ebe1 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 24 Jan 2017 01:57:42 +0300 Subject: [PATCH 0866/4375] test: check exit codes for criu criu lazy-pages travis-ci: success for crtools: close a signal descriptor after passing a preparation stage (rev6) Cc: Mike Rapoport Signed-off-by: Andrei Vagin Signed-off-by: Pavel Emelyanov --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 08dbc40ec..0db8304fb 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -975,7 +975,7 @@ class criu: ps_opts = ["--daemon", "--pidfile", "ps.pid", "--port", "12345", "--lazy-pages"] self.__criu_act("page-server", opts = ps_opts) - self.__criu_act("lazy-pages", opts = lp_opts) + self.__lazy_pages_p = self.__criu_act("lazy-pages", opts = lp_opts, nowait = True) r_opts += ["--lazy-pages"] if self.__leave_stopped: From 6110ce00a1094579ea80711c6d5ed592788f1baf Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 2 Feb 2017 07:46:38 +0300 Subject: [PATCH 0867/4375] zdtm.py: use --status-fd instead of --daemon for lazy stuff It works faster and allows to check exit codes. travis-ci: success for series starting with [1/2] page-server: don't return a server pid from page-server Signed-off-by: Andrei Vagin Signed-off-by: Pavel Emelyanov --- test/zdtm.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 0db8304fb..d33a5b098 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -793,8 +793,7 @@ class criu: self.__page_server_p = None def fini(self, opts): - if self.__lazy_pages: - wait_pid_die(int(rpidfile(self.__ddir() + "/lp.pid")), "lazy-pages") + return def logs(self): return self.__dump_path @@ -969,12 +968,12 @@ class criu: r_opts.append('mnt[zdtm]:%s' % criu_dir) if self.__lazy_pages: - lp_opts = ["--daemon", "--pidfile", "lp.pid"] + lp_opts = [] if self.__remote_lazy_pages: lp_opts += ['--page-server', "--port", "12345"] - ps_opts = ["--daemon", "--pidfile", "ps.pid", + ps_opts = ["--pidfile", "ps.pid", "--port", "12345", "--lazy-pages"] - self.__criu_act("page-server", opts = ps_opts) + self.__page_server_p = self.__criu_act("page-server", opts = ps_opts, nowait = True) self.__lazy_pages_p = self.__criu_act("lazy-pages", opts = lp_opts, nowait = True) r_opts += ["--lazy-pages"] From 884beaa4289d07b992d34f21072d490a97fb3927 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:43:54 +0200 Subject: [PATCH 0868/4375] lazy-pages: drop code for page fault message flags processing The kernel anyways does not really supports any flags for page fault message and we've used '#if 0' to skip the flags processing. However, we can just drop this chunk as we anyway will have do some more work than simply removing '#if 0' to handle UFFD_WP. travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index d1cae090f..a014d5089 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -642,21 +642,6 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) address = msg->arg.pagefault.address & ~(page_size() - 1); pr_debug("%d: #PF at 0x%llx\n", lpi->pid, address); -#if 0 - /* - * Until uffd in kernel gets support for write protection, - * flags are always 0, so there is no point to read and print - * them - */ - { - __u64 flags; - - /* Now handle the pages actually requested. */ - flags = msg.arg.pagefault.flags; - pr_debug("msg.arg.pagefault.flags 0x%llx\n", flags); - } -#endif - ret = uffd_handle_pages(lpi, address, 1, PR_ASYNC | PR_ASAP); if (ret < 0) { pr_err("Error during regular page copy\n"); From 174525f4ee0e3b0b0e7bc020e220e0a9b7111536 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:43:55 +0200 Subject: [PATCH 0869/4375] lazy-pages: track outstanding page faults Multithreaded applications may concurrently generate page faults at the same address, which will cause creation of multiple requests for remote page, and, consequently, confuse the page server on the dump side. We can keep track on page fault requests in flight and ensure this way that we request a page from the remote side only once. travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/criu/uffd.c b/criu/uffd.c index a014d5089..03ad833d6 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -55,10 +55,16 @@ struct lazy_iovec { struct lazy_pages_info; +struct lp_req { + unsigned long addr; + struct list_head l; +}; + struct lazy_pages_info { int pid; struct list_head iovs; + struct list_head reqs; struct page_read pr; @@ -85,6 +91,7 @@ static struct lazy_pages_info *lpi_init(void) memset(lpi, 0, sizeof(*lpi)); INIT_LIST_HEAD(&lpi->iovs); + INIT_LIST_HEAD(&lpi->reqs); INIT_LIST_HEAD(&lpi->l); lpi->lpfd.revent = handle_uffd_event; @@ -537,9 +544,19 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long vaddr, int nr) { + struct lp_req *req; + if (uffd_copy(lpi, vaddr, nr)) return -1; + list_for_each_entry(req, &lpi->reqs, l) { + if (req->addr == vaddr) { + list_del(&req->l); + xfree(req); + break; + } + } + return update_lazy_iovecs(lpi, vaddr, nr * PAGE_SIZE); } @@ -635,6 +652,7 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) { + struct lp_req *req; __u64 address; int ret; @@ -642,6 +660,16 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) address = msg->arg.pagefault.address & ~(page_size() - 1); pr_debug("%d: #PF at 0x%llx\n", lpi->pid, address); + list_for_each_entry(req, &lpi->reqs, l) + if (req->addr == address) + return 0; + + req = xzalloc(sizeof(*req)); + if (!req) + return -1; + req->addr = address; + list_add(&req->l, &lpi->reqs); + ret = uffd_handle_pages(lpi, address, 1, PR_ASYNC | PR_ASAP); if (ret < 0) { pr_err("Error during regular page copy\n"); @@ -664,6 +692,9 @@ static int handle_uffd_event(struct epoll_rfd *lpfd) return 1; if (ret != sizeof(msg)) { + /* we've already handled the page fault for another thread */ + if (errno == EAGAIN) + return 0; if (ret < 0) pr_perror("Can't read userfaultfd message"); else From 8c496f4f13dad31f86fa433dd03ef3fff6cefb70 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:43:56 +0200 Subject: [PATCH 0870/4375] lazy-pages: s/lazy_iovec/lazy_iov/g Same meaning, less to type. travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 03ad833d6..bb227b20f 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -47,7 +47,7 @@ static mutex_t *lazy_sock_mutex; -struct lazy_iovec { +struct lazy_iov { struct list_head l; unsigned long base; unsigned long len; @@ -100,7 +100,7 @@ static struct lazy_pages_info *lpi_init(void) static void lpi_fini(struct lazy_pages_info *lpi) { - struct lazy_iovec *p, *n; + struct lazy_iov *p, *n; if (!lpi) return; @@ -310,13 +310,13 @@ static MmEntry *init_mm_entry(struct lazy_pages_info *lpi) } /* - * Purge range (addr, addr + len) from lazy_iovecs. The range may + * Purge range (addr, addr + len) from lazy_iovs. The range may * cover several continuous IOVs. */ -static int update_lazy_iovecs(struct lazy_pages_info *lpi, unsigned long addr, - int len) +static int update_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, + int len) { - struct lazy_iovec *lazy_iov, *n; + struct lazy_iov *lazy_iov, *n; list_for_each_entry_safe(lazy_iov, n, &lpi->iovs, l) { unsigned long start = lazy_iov->base; @@ -340,7 +340,7 @@ static int update_lazy_iovecs(struct lazy_pages_info *lpi, unsigned long addr, lazy_iov->base += len; lazy_iov->len -= len; } else { - struct lazy_iovec *new_iov; + struct lazy_iov *new_iov; lazy_iov->len -= (end - addr); @@ -384,10 +384,10 @@ static int update_lazy_iovecs(struct lazy_pages_info *lpi, unsigned long addr, * only inside a single VMA. * We assume here that pagemaps and VMAs are sorted. */ -static int collect_lazy_iovecs(struct lazy_pages_info *lpi) +static int collect_lazy_iovs(struct lazy_pages_info *lpi) { struct page_read *pr = &lpi->pr; - struct lazy_iovec *lazy_iov, *n; + struct lazy_iov *lazy_iov, *n; MmEntry *mm; int nr_pages = 0, n_vma = 0, max_iov_len = 0; int ret = -1; @@ -495,7 +495,7 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) * Find the memory pages belonging to the restored process * so that it is trackable when all pages have been transferred. */ - ret = collect_lazy_iovecs(lpi); + ret = collect_lazy_iovs(lpi); if (ret < 0) goto out; lpi->total_pages = ret; @@ -557,7 +557,7 @@ static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long vaddr, } } - return update_lazy_iovecs(lpi, vaddr, nr * PAGE_SIZE); + return update_lazy_iovs(lpi, vaddr, nr * PAGE_SIZE); } static int uffd_io_complete(struct page_read *pr, unsigned long vaddr, int nr) @@ -632,13 +632,13 @@ static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr, static int handle_remaining_pages(struct lazy_pages_info *lpi) { - struct lazy_iovec *lazy_iov; + struct lazy_iov *lazy_iov; int nr_pages, err; if (list_empty(&lpi->iovs)) return 0; - lazy_iov = list_first_entry(&lpi->iovs, struct lazy_iovec, l); + lazy_iov = list_first_entry(&lpi->iovs, struct lazy_iov, l); nr_pages = lazy_iov->len / PAGE_SIZE; err = uffd_handle_pages(lpi, lazy_iov->base, nr_pages, 0); From d0f53abc596a2b53d50c35a867748ba8b298b841 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:43:57 +0200 Subject: [PATCH 0871/4375] lazy-pages: use iov variable name for lazy_iov travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index bb227b20f..a0884ab1d 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -316,11 +316,11 @@ static MmEntry *init_mm_entry(struct lazy_pages_info *lpi) static int update_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) { - struct lazy_iov *lazy_iov, *n; + struct lazy_iov *iov, *n; - list_for_each_entry_safe(lazy_iov, n, &lpi->iovs, l) { - unsigned long start = lazy_iov->base; - unsigned long end = start + lazy_iov->len; + list_for_each_entry_safe(iov, n, &lpi->iovs, l) { + unsigned long start = iov->base; + unsigned long end = start + iov->len; if (len <= 0) break; @@ -337,12 +337,12 @@ static int update_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, */ if (addr + len < end) { if (addr == start) { - lazy_iov->base += len; - lazy_iov->len -= len; + iov->base += len; + iov->len -= len; } else { struct lazy_iov *new_iov; - lazy_iov->len -= (end - addr); + iov->len -= (end - addr); new_iov = xzalloc(sizeof(*new_iov)); if (!new_iov) @@ -351,7 +351,7 @@ static int update_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, new_iov->base = addr + len; new_iov->len = end - (addr + len); - list_add(&new_iov->l, &lazy_iov->l); + list_add(&new_iov->l, &iov->l); } break; } @@ -363,10 +363,10 @@ static int update_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, * and continue to the next one with the updated range */ if (addr == start) { - list_del(&lazy_iov->l); - xfree(lazy_iov); + list_del(&iov->l); + xfree(iov); } else { - lazy_iov->len -= (end - addr); + iov->len -= (end - addr); } len -= (end - addr); @@ -387,7 +387,7 @@ static int update_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, static int collect_lazy_iovs(struct lazy_pages_info *lpi) { struct page_read *pr = &lpi->pr; - struct lazy_iov *lazy_iov, *n; + struct lazy_iov *iov, *n; MmEntry *mm; int nr_pages = 0, n_vma = 0, max_iov_len = 0; int ret = -1; @@ -411,14 +411,14 @@ static int collect_lazy_iovs(struct lazy_pages_info *lpi) if (start >= vma->end) continue; - lazy_iov = xzalloc(sizeof(*lazy_iov)); - if (!lazy_iov) + iov = xzalloc(sizeof(*iov)); + if (!iov) goto free_iovs; len = min_t(uint64_t, end, vma->end) - start; - lazy_iov->base = start; - lazy_iov->len = len; - list_add_tail(&lazy_iov->l, &lpi->iovs); + iov->base = start; + iov->len = len; + list_add_tail(&iov->l, &lpi->iovs); if (len > max_iov_len) max_iov_len = len; @@ -437,8 +437,8 @@ static int collect_lazy_iovs(struct lazy_pages_info *lpi) goto free_mm; free_iovs: - list_for_each_entry_safe(lazy_iov, n, &lpi->iovs, l) - xfree(lazy_iov); + list_for_each_entry_safe(iov, n, &lpi->iovs, l) + xfree(iov); free_mm: mm_entry__free_unpacked(mm, NULL); @@ -632,16 +632,16 @@ static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr, static int handle_remaining_pages(struct lazy_pages_info *lpi) { - struct lazy_iov *lazy_iov; + struct lazy_iov *iov; int nr_pages, err; if (list_empty(&lpi->iovs)) return 0; - lazy_iov = list_first_entry(&lpi->iovs, struct lazy_iov, l); - nr_pages = lazy_iov->len / PAGE_SIZE; + iov = list_first_entry(&lpi->iovs, struct lazy_iov, l); + nr_pages = iov->len / PAGE_SIZE; - err = uffd_handle_pages(lpi, lazy_iov->base, nr_pages, 0); + err = uffd_handle_pages(lpi, iov->base, nr_pages, 0); if (err < 0) { pr_err("Error during UFFD copy\n"); return -1; From cbeaf61756c79230abe60c74d645406793132906 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:43:58 +0200 Subject: [PATCH 0872/4375] lazy-pages: use lazy_iov'ecs to search for pages Currently we use pagemap to check if we should copy a page into process address space or zero it. The lazy_iov'ecs can be used instead. If a lazy_iov covers the faulting address, we should go ahead and read the page and copy it. If there is not lazy_iov for the faulting address, just zero it immediately. Searching lazy_iov's rather than pagemap will also simplify upcoming handling of UFFD_EVENT_REMAP. travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index a0884ab1d..dc7bf0c8d 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -309,6 +309,18 @@ static MmEntry *init_mm_entry(struct lazy_pages_info *lpi) return mm; } +static struct lazy_iov *find_lazy_iov(struct lazy_pages_info *lpi, + unsigned long addr) +{ + struct lazy_iov *iov; + + list_for_each_entry(iov, &lpi->iovs, l) + if (addr >= iov->base && addr < iov->base + iov->len) + return iov; + + return NULL; +} + /* * Purge range (addr, addr + len) from lazy_iovs. The range may * cover several continuous IOVs. @@ -597,28 +609,29 @@ static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) * Returns 0 for zero pages, 1 for "real" pages and negative value on * error */ -static int uffd_seek_or_zero_pages(struct lazy_pages_info *lpi, __u64 address, - int nr) +static int uffd_seek_pages(struct lazy_pages_info *lpi, __u64 address, int nr) { int ret; lpi->pr.reset(&lpi->pr); ret = lpi->pr.seek_pagemap(&lpi->pr, address); - if (!ret) - return uffd_zero(lpi, address, nr); + if (!ret) { + pr_err("%d: no pagemap covers %llx\n", lpi->pid, address); + return ret; + } lpi->pr.skip_pages(&lpi->pr, address - lpi->pr.pe->vaddr); - return 1; + return 0; } static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr, unsigned flags) { int ret; - ret = uffd_seek_or_zero_pages(lpi, address, nr); - if (ret <= 0) + ret = uffd_seek_pages(lpi, address, nr); + if (ret) return ret; ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, flags); @@ -653,6 +666,7 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) { struct lp_req *req; + struct lazy_iov *iov; __u64 address; int ret; @@ -664,6 +678,10 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) if (req->addr == address) return 0; + iov = find_lazy_iov(lpi, address); + if (!iov) + return uffd_zero(lpi, address, 1); + req = xzalloc(sizeof(*req)); if (!req) return -1; From bb75aad9c706eab1d9078d3b76ce952343188727 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:43:59 +0200 Subject: [PATCH 0873/4375] lazy-pages: introduce lp_{debug,info,warn,err,perror} helper macros When printing a message about particular process events, always prefix it with "-" for better log readability travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index dc7bf0c8d..5706c2795 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -41,7 +41,13 @@ #include "util.h" #undef LOG_PREFIX -#define LOG_PREFIX "lazy-pages: " +#define LOG_PREFIX "uffd: " + +#define lp_debug(lpi, fmt, arg...) pr_debug("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) +#define lp_info(lpi, fmt, arg...) pr_info("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) +#define lp_warn(lpi, fmt, arg...) pr_warn("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) +#define lp_err(lpi, fmt, arg...) pr_err("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) +#define lp_perror(lpi, fmt, arg...) pr_perror("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) #define LAZY_PAGES_SOCK_NAME "lazy-pages.socket" @@ -304,7 +310,7 @@ static MmEntry *init_mm_entry(struct lazy_pages_info *lpi) close_image(img); if (ret == -1) return NULL; - pr_debug("Found %zd VMAs in image\n", mm->n_vmas); + lp_debug(lpi, "Found %zd VMAs in image\n", mm->n_vmas); return mm; } @@ -512,7 +518,7 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) goto out; lpi->total_pages = ret; - pr_debug("Found %ld pages to be handled by UFFD\n", lpi->total_pages); + lp_debug(lpi, "Found %ld pages to be handled by UFFD\n", lpi->total_pages); list_add_tail(&lpi->l, &lpis); *_lpi = lpi; @@ -536,16 +542,16 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) uffdio_copy.mode = 0; uffdio_copy.copy = 0; - pr_debug("%d: uffd_copy: 0x%llx/%ld\n", lpi->pid, uffdio_copy.dst, len); + lp_debug(lpi, "uffd_copy: 0x%llx/%ld\n", uffdio_copy.dst, len); rc = ioctl(lpi->lpfd.fd, UFFDIO_COPY, &uffdio_copy); if (rc) { /* real retval in ufdio_copy.copy */ - pr_err("%d: UFFDIO_COPY failed: rc:%d copy:%Ld\n", lpi->pid, rc, + lp_err(lpi, "UFFDIO_COPY failed: rc:%d copy:%Ld\n", rc, uffdio_copy.copy); if (uffdio_copy.copy != -EEXIST) return -1; } else if (uffdio_copy.copy != len) { - pr_err("UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy); + lp_err(lpi, "UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy); return -1; } @@ -590,10 +596,10 @@ static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) uffdio_zeropage.range.len = len; uffdio_zeropage.mode = 0; - pr_debug("%d: zero page at 0x%llx\n", lpi->pid, address); + lp_debug(lpi, "zero page at 0x%llx\n", address); rc = ioctl(lpi->lpfd.fd, UFFDIO_ZEROPAGE, &uffdio_zeropage); if (rc) { - pr_err("UFFDIO_ZEROPAGE error %d\n", rc); + lp_err(lpi, "UFFDIO_ZEROPAGE error %d\n", rc); return -1; } @@ -617,7 +623,7 @@ static int uffd_seek_pages(struct lazy_pages_info *lpi, __u64 address, int nr) ret = lpi->pr.seek_pagemap(&lpi->pr, address); if (!ret) { - pr_err("%d: no pagemap covers %llx\n", lpi->pid, address); + lp_err(lpi, "no pagemap covers %llx\n", address); return ret; } @@ -636,7 +642,7 @@ static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr, ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, flags); if (ret <= 0) { - pr_err("%d: failed reading pages at %llx\n", lpi->pid, address); + lp_err(lpi, "failed reading pages at %llx\n", address); return ret; } @@ -656,7 +662,7 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) err = uffd_handle_pages(lpi, iov->base, nr_pages, 0); if (err < 0) { - pr_err("Error during UFFD copy\n"); + lp_err(lpi, "Error during UFFD copy\n"); return -1; } @@ -672,7 +678,7 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) /* Align requested address to the next page boundary */ address = msg->arg.pagefault.address & ~(page_size() - 1); - pr_debug("%d: #PF at 0x%llx\n", lpi->pid, address); + lp_debug(lpi, "#PF at 0x%llx\n", address); list_for_each_entry(req, &lpi->reqs, l) if (req->addr == address) @@ -690,7 +696,7 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) ret = uffd_handle_pages(lpi, address, 1, PR_ASYNC | PR_ASAP); if (ret < 0) { - pr_err("Error during regular page copy\n"); + lp_err(lpi, "Error during regular page copy\n"); return -1; } @@ -714,9 +720,9 @@ static int handle_uffd_event(struct epoll_rfd *lpfd) if (errno == EAGAIN) return 0; if (ret < 0) - pr_perror("Can't read userfaultfd message"); + lp_perror(lpi, "Can't read uffd message"); else - pr_err("Can't read userfaultfd message: short read"); + lp_err(lpi, "Can't read uffd message: short read"); return -1; } @@ -724,7 +730,7 @@ static int handle_uffd_event(struct epoll_rfd *lpfd) case UFFD_EVENT_PAGEFAULT: return handle_page_fault(lpi, &msg); default: - pr_err("unexpected uffd event %u\n", msg.event); + lp_err(lpi, "unexpected uffd event %u\n", msg.event); return -1; } @@ -733,13 +739,13 @@ static int handle_uffd_event(struct epoll_rfd *lpfd) static int lazy_pages_summary(struct lazy_pages_info *lpi) { - pr_debug("Process %d: with UFFD transferred pages: (%ld/%ld)\n", - lpi->pid, lpi->copied_pages, lpi->total_pages); + lp_debug(lpi, "UFFD transferred pages: (%ld/%ld)\n", + lpi->copied_pages, lpi->total_pages); if ((lpi->copied_pages != lpi->total_pages) && (lpi->total_pages > 0)) { - pr_warn("Only %ld of %ld pages transferred via UFFD\n", lpi->copied_pages, - lpi->total_pages); - pr_warn("Something probably went wrong.\n"); + lp_warn(lpi, "Only %ld of %ld pages transferred via UFFD\n" + "Something probably went wrong.\n", + lpi->copied_pages, lpi->total_pages); return 1; } From 29fc1ad78ffd9da3dd792ce29e7bb8a1eb240812 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:00 +0200 Subject: [PATCH 0874/4375] lazy-pages: rename update_lazy_iovs to drop_lazy_iovs The function essentially drops a memory range from lazy IOVecs travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 5706c2795..6b8570f9a 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -331,8 +331,8 @@ static struct lazy_iov *find_lazy_iov(struct lazy_pages_info *lpi, * Purge range (addr, addr + len) from lazy_iovs. The range may * cover several continuous IOVs. */ -static int update_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, - int len) +static int drop_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, + int len) { struct lazy_iov *iov, *n; @@ -575,7 +575,7 @@ static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long vaddr, } } - return update_lazy_iovs(lpi, vaddr, nr * PAGE_SIZE); + return drop_lazy_iovs(lpi, vaddr, nr * PAGE_SIZE); } static int uffd_io_complete(struct page_read *pr, unsigned long vaddr, int nr) From 0110f5cfe92b9f47e2e219339ea77b2824452a27 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:01 +0200 Subject: [PATCH 0875/4375] lazy-pages: update drop_lazy_iovs to handle addresses outside IOVs Currently drop_lazy_iovs presumes that the range that should be dropped starts inside an IOV. This works fine with page faults and background pages but will fail for mapping changes. travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 6b8570f9a..b2f7a35b4 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -340,12 +340,17 @@ static int drop_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, unsigned long start = iov->base; unsigned long end = start + iov->len; - if (len <= 0) + if (len <= 0 || addr + len < start) break; - if (addr < start || addr >= end) + if (addr >= end) continue; + if (addr < start) { + len -= (start - addr); + addr = start; + } + /* * The range completely fits into the current IOV. * If addr equals iov_base we just "drop" the From cdeb57a23363a5733a586697acab803ca90a4027 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:02 +0200 Subject: [PATCH 0876/4375] lazy-pages: start handling remaining pages if IOVs list is not empty The copied_pages and total_pages may be different because the process may drop parts of its address space. And the IOVs list will be empty iff we are done with the process. travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index b2f7a35b4..58dcdb947 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -659,9 +659,6 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) struct lazy_iov *iov; int nr_pages, err; - if (list_empty(&lpi->iovs)) - return 0; - iov = list_first_entry(&lpi->iovs, struct lazy_iov, l); nr_pages = iov->len / PAGE_SIZE; @@ -777,7 +774,7 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) poll_timeout = 0; list_for_each_entry(lpi, &lpis, l) { - if (lpi->copied_pages < lpi->total_pages) { + if (!list_empty(&lpi->iovs)) { remaining = true; ret = handle_remaining_pages(lpi); if (ret < 0) From 028a1bc80a274c354211d3d85a3410edb4c85c8c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:03 +0200 Subject: [PATCH 0877/4375] lazy-pages: summary: allow different total and copied pages With address space manipulations, amount of pages that the lazy-pages daemon will copy might differ from amount of pages we had in the dumps. Disable the warning and error retval for now; we can restore the accounting once uffd event handling stabilizes a bit. travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/uffd.c b/criu/uffd.c index 58dcdb947..1066dc1eb 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -744,12 +744,14 @@ static int lazy_pages_summary(struct lazy_pages_info *lpi) lp_debug(lpi, "UFFD transferred pages: (%ld/%ld)\n", lpi->copied_pages, lpi->total_pages); +#if 0 if ((lpi->copied_pages != lpi->total_pages) && (lpi->total_pages > 0)) { lp_warn(lpi, "Only %ld of %ld pages transferred via UFFD\n" "Something probably went wrong.\n", lpi->copied_pages, lpi->total_pages); return 1; } +#endif return 0; } From 2f2f11ad879528e3caf7aed63de0a581b041cebd Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:04 +0200 Subject: [PATCH 0878/4375] Update criu/include/linux/userfaultfd.h This is the version from linux-next at the moment. travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-check.c | 2 +- criu/include/linux/userfaultfd.h | 60 ++++++++++++++++++++++---------- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index 29e607f76..f6b8208ef 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1050,7 +1050,7 @@ static int check_uffd(void) { unsigned long features = UFFD_FEATURE_EVENT_FORK | UFFD_FEATURE_EVENT_REMAP | - UFFD_FEATURE_EVENT_MADVDONTNEED; + UFFD_FEATURE_EVENT_REMOVE; if (kerndat_uffd(true)) return -1; diff --git a/criu/include/linux/userfaultfd.h b/criu/include/linux/userfaultfd.h index a9c3389ef..c055947c5 100644 --- a/criu/include/linux/userfaultfd.h +++ b/criu/include/linux/userfaultfd.h @@ -18,10 +18,13 @@ * means the userland is reading). */ #define UFFD_API ((__u64)0xAA) -#define UFFD_API_FEATURES (UFFD_FEATURE_PAGEFAULT_FLAG_WP | \ - UFFD_FEATURE_EVENT_FORK | \ - UFFD_FEATURE_EVENT_REMAP | \ - UFFD_FEATURE_EVENT_MADVDONTNEED) +#define UFFD_API_FEATURES (UFFD_FEATURE_EVENT_EXIT | \ + UFFD_FEATURE_EVENT_FORK | \ + UFFD_FEATURE_EVENT_REMAP | \ + UFFD_FEATURE_EVENT_REMOVE | \ + UFFD_FEATURE_EVENT_UNMAP | \ + UFFD_FEATURE_MISSING_HUGETLBFS | \ + UFFD_FEATURE_MISSING_SHMEM) #define UFFD_API_IOCTLS \ ((__u64)1 << _UFFDIO_REGISTER | \ (__u64)1 << _UFFDIO_UNREGISTER | \ @@ -29,8 +32,7 @@ #define UFFD_API_RANGE_IOCTLS \ ((__u64)1 << _UFFDIO_WAKE | \ (__u64)1 << _UFFDIO_COPY | \ - (__u64)1 << _UFFDIO_ZEROPAGE | \ - (__u64)1 << _UFFDIO_WRITEPROTECT) + (__u64)1 << _UFFDIO_ZEROPAGE) #define UFFD_API_RANGE_IOCTLS_BASIC \ ((__u64)1 << _UFFDIO_WAKE | \ (__u64)1 << _UFFDIO_COPY) @@ -48,7 +50,6 @@ #define _UFFDIO_WAKE (0x02) #define _UFFDIO_COPY (0x03) #define _UFFDIO_ZEROPAGE (0x04) -#define _UFFDIO_WRITEPROTECT (0x05) #define _UFFDIO_API (0x3F) /* userfaultfd ioctl ids */ @@ -65,8 +66,6 @@ struct uffdio_copy) #define UFFDIO_ZEROPAGE _IOWR(UFFDIO, _UFFDIO_ZEROPAGE, \ struct uffdio_zeropage) -#define UFFDIO_WRITEPROTECT _IOWR(UFFDIO, _UFFDIO_WRITEPROTECT, \ - struct uffdio_writeprotect) /* read() structure */ struct uffd_msg { @@ -95,7 +94,7 @@ struct uffd_msg { struct { __u64 start; __u64 end; - } madv_dn; + } remove; struct { /* unused reserved fields */ @@ -112,7 +111,9 @@ struct uffd_msg { #define UFFD_EVENT_PAGEFAULT 0x12 #define UFFD_EVENT_FORK 0x13 #define UFFD_EVENT_REMAP 0x14 -#define UFFD_EVENT_MADVDONTNEED 0x15 +#define UFFD_EVENT_REMOVE 0x15 +#define UFFD_EVENT_UNMAP 0x16 +#define UFFD_EVENT_EXIT 0x17 /* flags for UFFD_EVENT_PAGEFAULT */ #define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */ @@ -130,11 +131,39 @@ struct uffdio_api { * Note: UFFD_EVENT_PAGEFAULT and UFFD_PAGEFAULT_FLAG_WRITE * are to be considered implicitly always enabled in all kernels as * long as the uffdio_api.api requested matches UFFD_API. + * + * UFFD_FEATURE_MISSING_HUGETLBFS means an UFFDIO_REGISTER + * with UFFDIO_REGISTER_MODE_MISSING mode will succeed on + * hugetlbfs virtual memory ranges. Adding or not adding + * UFFD_FEATURE_MISSING_HUGETLBFS to uffdio_api.features has + * no real functional effect after UFFDIO_API returns, but + * it's only useful for an initial feature set probe at + * UFFDIO_API time. There are two ways to use it: + * + * 1) by adding UFFD_FEATURE_MISSING_HUGETLBFS to the + * uffdio_api.features before calling UFFDIO_API, an error + * will be returned by UFFDIO_API on a kernel without + * hugetlbfs missing support + * + * 2) the UFFD_FEATURE_MISSING_HUGETLBFS can not be added in + * uffdio_api.features and instead it will be set by the + * kernel in the uffdio_api.features if the kernel supports + * it, so userland can later check if the feature flag is + * present in uffdio_api.features after UFFDIO_API + * succeeded. + * + * UFFD_FEATURE_MISSING_SHMEM works the same as + * UFFD_FEATURE_MISSING_HUGETLBFS, but it applies to shmem + * (i.e. tmpfs and other shmem based APIs). */ #define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0) #define UFFD_FEATURE_EVENT_FORK (1<<1) #define UFFD_FEATURE_EVENT_REMAP (1<<2) -#define UFFD_FEATURE_EVENT_MADVDONTNEED (1<<3) +#define UFFD_FEATURE_EVENT_REMOVE (1<<3) +#define UFFD_FEATURE_MISSING_HUGETLBFS (1<<4) +#define UFFD_FEATURE_MISSING_SHMEM (1<<5) +#define UFFD_FEATURE_EVENT_UNMAP (1<<6) +#define UFFD_FEATURE_EVENT_EXIT (1<<7) __u64 features; __u64 ioctls; @@ -190,11 +219,4 @@ struct uffdio_zeropage { __s64 zeropage; }; -struct uffdio_writeprotect { - struct uffdio_range range; - /* !WP means undo writeprotect. DONTWAKE is valid only with !WP */ -#define UFFDIO_WRITEPROTECT_MODE_WP ((__u64)1<<0) -#define UFFDIO_WRITEPROTECT_MODE_DONTWAKE ((__u64)1<<1) - __u64 mode; -}; #endif /* _LINUX_USERFAULTFD_H */ From 7df4f14be69d991aaa45237c2c58a6e69b0b7f0c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:05 +0200 Subject: [PATCH 0879/4375] cr-check: lazy-pages: detect availability of UNMAP and EXIT events travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-check.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/cr-check.c b/criu/cr-check.c index f6b8208ef..dfe3a50ee 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1049,7 +1049,9 @@ static int check_compat_cr(void) static int check_uffd(void) { unsigned long features = UFFD_FEATURE_EVENT_FORK | + UFFD_FEATURE_EVENT_EXIT | UFFD_FEATURE_EVENT_REMAP | + UFFD_FEATURE_EVENT_UNMAP | UFFD_FEATURE_EVENT_REMOVE; if (kerndat_uffd(true)) From ba3d099b74e44f0f310ed705cd2ffde08d11c424 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:06 +0200 Subject: [PATCH 0880/4375] lazy-pages: add handling of UFFD_EVENT_REMOVE When the restored process calls madvise(MADV_DONTNEED) or madvise(MADV_REMOVE) the memory range specified by the madvise() call should be remapped to zero pfn and we should stop monitoring this range in order to avoid its pollution with data the process does not expect. All we need to do here, is to unregister the memory range from userfaultfd and the kernel will take care of the rest. travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/criu/uffd.c b/criu/uffd.c index 1066dc1eb..a96f62e32 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -671,6 +671,24 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) return 0; } +static int handle_remove(struct lazy_pages_info *lpi, struct uffd_msg *msg) +{ + struct uffdio_range unreg; + + unreg.start = msg->arg.remove.start; + unreg.len = msg->arg.remove.end - msg->arg.remove.start; + + lp_debug(lpi, "REMOVE: %Lx(%Lx)\n", unreg.start, unreg.len); + + if (ioctl(lpi->lpfd.fd, UFFDIO_UNREGISTER, &unreg)) { + pr_perror("Failed to unregister (%llx - %llx)", unreg.start, + unreg.start + unreg.len); + return -1; + } + + return drop_lazy_iovs(lpi, unreg.start, unreg.len); +} + static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) { struct lp_req *req; @@ -731,6 +749,8 @@ static int handle_uffd_event(struct epoll_rfd *lpfd) switch (msg.event) { case UFFD_EVENT_PAGEFAULT: return handle_page_fault(lpi, &msg); + case UFFD_EVENT_REMOVE: + return handle_remove(lpi, &msg); default: lp_err(lpi, "unexpected uffd event %u\n", msg.event); return -1; From b2ba8493a83c237a7ca9f4ca2c7c674b00ad2eb3 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:07 +0200 Subject: [PATCH 0881/4375] lazy-pages: add handling of UFFD_EVENT_UNMAP The UNMAP event is generated by userfaultfd when a VMA (or a part of it) is unmapped from the process address space. We won't receive #PF's at the unmapped range, but we need to make sure we are not trying to fill that range at handle_remaining_pages. Note, that the VMA is gone, so there is no sense to unregister uffd from it. travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index a96f62e32..949dc4622 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -678,9 +678,17 @@ static int handle_remove(struct lazy_pages_info *lpi, struct uffd_msg *msg) unreg.start = msg->arg.remove.start; unreg.len = msg->arg.remove.end - msg->arg.remove.start; - lp_debug(lpi, "REMOVE: %Lx(%Lx)\n", unreg.start, unreg.len); + lp_debug(lpi, "%s: %Lx(%Lx)\n", + msg->event == UFFD_EVENT_REMOVE ? "REMOVE" : "UNMAP", + unreg.start, unreg.len); - if (ioctl(lpi->lpfd.fd, UFFDIO_UNREGISTER, &unreg)) { + /* + * The REMOVE event does not change the VMA, so we need to + * make sure that we won't handle #PFs in the removed + * range. With UNMAP, there's no VMA to worry about + */ + if (msg->event == UFFD_EVENT_REMOVE && + ioctl(lpi->lpfd.fd, UFFDIO_UNREGISTER, &unreg)) { pr_perror("Failed to unregister (%llx - %llx)", unreg.start, unreg.start + unreg.len); return -1; @@ -750,6 +758,7 @@ static int handle_uffd_event(struct epoll_rfd *lpfd) case UFFD_EVENT_PAGEFAULT: return handle_page_fault(lpi, &msg); case UFFD_EVENT_REMOVE: + case UFFD_EVENT_UNMAP: return handle_remove(lpi, &msg); default: lp_err(lpi, "unexpected uffd event %u\n", msg.event); From 064917442d9b2c948a347d3ff3238581011a8455 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:08 +0200 Subject: [PATCH 0882/4375] lazy-pages: introduce split_iov travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 949dc4622..4d029b80e 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -327,6 +327,30 @@ static struct lazy_iov *find_lazy_iov(struct lazy_pages_info *lpi, return NULL; } +static int split_iov(struct lazy_iov *iov, unsigned long addr, bool new_below) +{ + struct lazy_iov *new; + + new = xzalloc(sizeof(*new)); + if (!new) + return -1; + + if (new_below) { + new->base = iov->base; + new->len = addr - iov->base; + iov->base = addr; + iov->len -= new->len; + list_add_tail(&new->l, &iov->l); + } else { + new->base = addr; + new->len = iov->len - (addr - iov->base); + iov->len -= new->len; + list_add(&new->l, &iov->l); + } + + return 0; +} + /* * Purge range (addr, addr + len) from lazy_iovs. The range may * cover several continuous IOVs. @@ -363,18 +387,9 @@ static int drop_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, iov->base += len; iov->len -= len; } else { - struct lazy_iov *new_iov; - - iov->len -= (end - addr); - - new_iov = xzalloc(sizeof(*new_iov)); - if (!new_iov) + if (split_iov(iov, addr + len, false)) return -1; - - new_iov->base = addr + len; - new_iov->len = end - (addr + len); - - list_add(&new_iov->l, &iov->l); + iov->len -= len; } break; } From 2c5e635e74456a513c224e7efd9b9f3f4ff96a1b Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:09 +0200 Subject: [PATCH 0883/4375] lazy-pages: add handling of UFFD_EVENT_REMAP When the restored process calls mremap(), we will see #PF's on the new addresses and we have to create a correspondence between the addresses found in the dump and the actual addresses the process uses. For this purpose we distinguish "live" address and "image" address in the lazy IOVs and outstanding requests. The "live" address is used to find the appropriate IOV and in uffd_copy and the "image" address is used to request pages from the page-read. If the mremap() call causes the mapping to grow, the additional part will receive zero pages, as expected. For the shrinking remaps, we will get UFFD_EVENT_UNMAP for the dropped part of the mapping. travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 98 insertions(+), 10 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 4d029b80e..95317348d 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -56,6 +56,7 @@ static mutex_t *lazy_sock_mutex; struct lazy_iov { struct list_head l; unsigned long base; + unsigned long img_base; unsigned long len; }; @@ -63,6 +64,7 @@ struct lazy_pages_info; struct lp_req { unsigned long addr; + unsigned long img_addr; struct list_head l; }; @@ -337,12 +339,15 @@ static int split_iov(struct lazy_iov *iov, unsigned long addr, bool new_below) if (new_below) { new->base = iov->base; + new->img_base = iov->img_base; new->len = addr - iov->base; iov->base = addr; + iov->img_base += new->len; iov->len -= new->len; list_add_tail(&new->l, &iov->l); } else { new->base = addr; + new->img_base = iov->img_base + addr - iov->base; new->len = iov->len - (addr - iov->base); iov->len -= new->len; list_add(&new->l, &iov->l); @@ -385,6 +390,7 @@ static int drop_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, if (addr + len < end) { if (addr == start) { iov->base += len; + iov->img_base += len; iov->len -= len; } else { if (split_iov(iov, addr + len, false)) @@ -414,6 +420,60 @@ static int drop_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, return 0; } +static int remap_lazy_iovs(struct lazy_pages_info *lpi, unsigned long from, + unsigned long to, unsigned long len) +{ + unsigned long off = to - from; + struct lazy_iov *iov, *n, *p; + LIST_HEAD(remaps); + + list_for_each_entry_safe(iov, n, &lpi->iovs, l) { + unsigned long iov_end = iov->base + iov->len; + + if (from > iov_end) + continue; + + if (len <= 0 || from + len < iov->base) + break; + + if (from < iov->base) { + len -= (iov->base - from); + from = iov->base; + } + + if (from > iov->base) + if (split_iov(iov, from, true)) + return -1; + if (from + len < iov_end) + if (split_iov(iov, from + len, false)) + return -1; + + list_safe_reset_next(iov, n, l); + + /* here we have iov->base = from, iov_end <= from + len */ + from = iov_end; + len -= iov->len; + iov->base += off; + list_move_tail(&iov->l, &remaps); + } + + list_for_each_entry_safe(iov, n, &remaps, l) { + list_for_each_entry(p, &lpi->iovs, l) { + if (iov->base < p->base) { + list_move_tail(&iov->l, &p->l); + break; + } + if (list_is_last(&p->l, &lpi->iovs) && + iov->base > p->base) { + list_move(&iov->l, &p->l); + break; + } + } + } + + return 0; +} + /* * Create a list of IOVs that can be handled using userfaultfd. The * IOVs generally correspond to lazy pagemap entries, except the cases @@ -455,6 +515,7 @@ static int collect_lazy_iovs(struct lazy_pages_info *lpi) len = min_t(uint64_t, end, vma->end) - start; iov->base = start; + iov->img_base = start; iov->len = len; list_add_tail(&iov->l, &lpi->iovs); @@ -580,30 +641,34 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) return 0; } -static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long vaddr, int nr) +static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long img_addr, int nr) { + unsigned long addr = 0; struct lp_req *req; - if (uffd_copy(lpi, vaddr, nr)) - return -1; - list_for_each_entry(req, &lpi->reqs, l) { - if (req->addr == vaddr) { + if (req->img_addr == img_addr) { + addr = req->addr; list_del(&req->l); xfree(req); break; } } - return drop_lazy_iovs(lpi, vaddr, nr * PAGE_SIZE); + BUG_ON(!addr); + + if (uffd_copy(lpi, addr, nr)) + return -1; + + return drop_lazy_iovs(lpi, addr, nr * PAGE_SIZE); } -static int uffd_io_complete(struct page_read *pr, unsigned long vaddr, int nr) +static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr) { struct lazy_pages_info *lpi; lpi = container_of(pr, struct lazy_pages_info, pr); - return complete_page_fault(lpi, vaddr, nr); + return complete_page_fault(lpi, img_addr, nr); } static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) @@ -672,12 +737,21 @@ static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr, static int handle_remaining_pages(struct lazy_pages_info *lpi) { struct lazy_iov *iov; + struct lp_req *req; int nr_pages, err; iov = list_first_entry(&lpi->iovs, struct lazy_iov, l); nr_pages = iov->len / PAGE_SIZE; - err = uffd_handle_pages(lpi, iov->base, nr_pages, 0); + req = xzalloc(sizeof(*req)); + if (!req) + return -1; + + req->addr = iov->base; + req->img_addr = iov->img_base; + list_add(&req->l, &lpi->reqs); + + err = uffd_handle_pages(lpi, req->img_addr, nr_pages, 0); if (err < 0) { lp_err(lpi, "Error during UFFD copy\n"); return -1; @@ -712,6 +786,17 @@ static int handle_remove(struct lazy_pages_info *lpi, struct uffd_msg *msg) return drop_lazy_iovs(lpi, unreg.start, unreg.len); } +static int handle_remap(struct lazy_pages_info *lpi, struct uffd_msg *msg) +{ + unsigned long from = msg->arg.remap.from; + unsigned long to = msg->arg.remap.to; + unsigned long len = msg->arg.remap.len; + + lp_debug(lpi, "REMAP: %lx -> %lx (%ld)\n", from , to, len); + + return remap_lazy_iovs(lpi, from, to, len); +} + static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) { struct lp_req *req; @@ -735,9 +820,10 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) if (!req) return -1; req->addr = address; + req->img_addr = iov->img_base + (address - iov->base); list_add(&req->l, &lpi->reqs); - ret = uffd_handle_pages(lpi, address, 1, PR_ASYNC | PR_ASAP); + ret = uffd_handle_pages(lpi, req->img_addr, 1, PR_ASYNC | PR_ASAP); if (ret < 0) { lp_err(lpi, "Error during regular page copy\n"); return -1; @@ -775,6 +861,8 @@ static int handle_uffd_event(struct epoll_rfd *lpfd) case UFFD_EVENT_REMOVE: case UFFD_EVENT_UNMAP: return handle_remove(lpi, &msg); + case UFFD_EVENT_REMAP: + return handle_remap(lpi, &msg); default: lp_err(lpi, "unexpected uffd event %u\n", msg.event); return -1; From 00436b7c2bf9dad88486885301d91d618ba81ec5 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:10 +0200 Subject: [PATCH 0884/4375] page-read: add PID for some debug printouts Replace "pr" with "pr-" when printing information about a particular page-read. travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/pagemap.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/criu/pagemap.c b/criu/pagemap.c index 3848558ce..cb83caa14 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -54,8 +54,8 @@ static int punch_hole(struct page_read *pr, unsigned long off, struct iovec * bunch = &pr->bunch; if (!cleanup && can_extend_bunch(bunch, off, len)) { - pr_debug("pr%d:Extend bunch len from %zu to %lu\n", pr->id, - bunch->iov_len, bunch->iov_len + len); + pr_debug("pr%d-%d:Extend bunch len from %zu to %lu\n", pr->pid, + pr->id, bunch->iov_len, bunch->iov_len + len); bunch->iov_len += len; } else { if (bunch->iov_len > 0) { @@ -69,7 +69,7 @@ static int punch_hole(struct page_read *pr, unsigned long off, } bunch->iov_base = (void *)off; bunch->iov_len = len; - pr_debug("pr%d:New bunch/%p/%zu/\n", pr->id, bunch->iov_base, bunch->iov_len); + pr_debug("pr%d-%d:New bunch/%p/%zu/\n", pr->pid, pr->id, bunch->iov_base, bunch->iov_len); } return 0; } @@ -213,7 +213,7 @@ static int read_parent_page(struct page_read *pr, unsigned long vaddr, do { int p_nr; - pr_debug("\tpr%u Read from parent\n", pr->id); + pr_debug("\tpr%d-%u Read from parent\n", pr->pid, pr->id); ret = seek_pagemap_page(ppr, vaddr); if (ret <= 0) { pr_err("Missing %lx in parent pagemap\n", vaddr); @@ -261,7 +261,7 @@ static int read_local_page(struct page_read *pr, unsigned long vaddr, if (pr->sync(pr)) return -1; - pr_debug("\tpr%u Read page from self %lx/%"PRIx64"\n", pr->id, pr->cvaddr, pr->pi_off); + pr_debug("\tpr%d-%u Read page from self %lx/%"PRIx64"\n", pr->pid, pr->id, pr->cvaddr, pr->pi_off); while (1) { ret = pread(fd, buf + curr, len - curr, pr->pi_off + curr); if (ret < 1) { @@ -463,7 +463,7 @@ static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, int nr, void *buf, unsigned flags) { - pr_info("pr%u Read %lx %u pages\n", pr->id, vaddr, nr); + pr_info("pr%d-%u Read %lx %u pages\n", pr->pid, pr->id, vaddr, nr); pagemap_bound_check(pr->pe, vaddr, nr); if (pagemap_in_parent(pr->pe)) { From fb90982db536e429bffd45d77d5bb6d33c4af9ac Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:11 +0200 Subject: [PATCH 0885/4375] page-read: introduce dup_page_read The dup_page_read performs a shallow copy of a page_read object. It is required for implementation of fork event in lazy-pages daemon. When a restored process fork()'s a child, the lazy-pages daemon will handle page faults of the child process, and it will use the parent process memory dump for that. travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/pagemap.h | 7 +++++++ criu/pagemap.c | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index db9fae53c..d0a28b9f1 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -112,6 +112,13 @@ int pagemap_enqueue_iovec(struct page_read *pr, void *buf, unsigned long len, struct list_head *to); int pagemap_render_iovec(struct list_head *from, struct task_restore_args *ta); +/* + * Create a shallow copy of page_read object. + * The new object shares the pagemap structures with the original, but + * maintains its own set of references to those structures. + */ +extern void dup_page_read(struct page_read *src, struct page_read *dst); + extern int dedup_one_iovec(struct page_read *pr, unsigned long base, unsigned long len); diff --git a/criu/pagemap.c b/criu/pagemap.c index cb83caa14..f4035042d 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -819,3 +819,16 @@ int open_page_read(int pid, struct page_read *pr, int pr_flags) { return open_page_read_at(get_service_fd(IMG_FD_OFF), pid, pr, pr_flags); } + + +#define DUP_IDS_BASE 1000 + +void dup_page_read(struct page_read *src, struct page_read *dst) +{ + static int dup_ids = 1; + + memcpy(dst, src, sizeof(*dst)); + INIT_LIST_HEAD(&dst->async); + dst->id = src->id + DUP_IDS_BASE * dup_ids++; + dst->reset(dst); +} From f10b348e963aaa9514beea0ce7972c0ea3a1c2a4 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:12 +0200 Subject: [PATCH 0886/4375] util: introduce epoll_del_rfd travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/util.h | 1 + criu/util.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/criu/include/util.h b/criu/include/util.h index 63810b493..bf466f5d6 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -323,6 +323,7 @@ struct epoll_rfd { }; extern int epoll_add_rfd(int epfd, struct epoll_rfd *); +extern int epoll_del_rfd(int epfd, struct epoll_rfd *rfd); extern int epoll_run_rfds(int epfd, struct epoll_event *evs, int nr_fds, int tmo); extern int epoll_prepare(int nr_events, struct epoll_event **evs); diff --git a/criu/util.c b/criu/util.c index 8be400e37..b681daf9b 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1228,6 +1228,16 @@ int epoll_add_rfd(int epfd, struct epoll_rfd *rfd) return 0; } +int epoll_del_rfd(int epfd, struct epoll_rfd *rfd) +{ + if (epoll_ctl(epfd, EPOLL_CTL_DEL, rfd->fd, NULL) == -1) { + pr_perror("epoll_ctl failed"); + return -1; + } + + return 0; +} + int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout) { int ret, i, nr_events; From d7c0b1f1a21d2c898f208c486148d3fffaf9b3d9 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:13 +0200 Subject: [PATCH 0887/4375] lazy-pages: handle UFFD_EVENT_EXIT travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 95317348d..5c453f125 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -87,6 +87,8 @@ struct lazy_pages_info { }; static LIST_HEAD(lpis); +static LIST_HEAD(exiting_lpis); + static int handle_uffd_event(struct epoll_rfd *lpfd); static struct lazy_pages_info *lpi_init(void) @@ -106,15 +108,23 @@ static struct lazy_pages_info *lpi_init(void) return lpi; } -static void lpi_fini(struct lazy_pages_info *lpi) +static void free_lazy_iovs(struct lazy_pages_info *lpi) { struct lazy_iov *p, *n; + list_for_each_entry_safe(p, n, &lpi->iovs, l) { + list_del(&p->l); + xfree(p); + } +} + +static void lpi_fini(struct lazy_pages_info *lpi) +{ + if (!lpi) return; free(lpi->buf); - list_for_each_entry_safe(p, n, &lpi->iovs, l) - xfree(p); + free_lazy_iovs(lpi); if (lpi->lpfd.fd > 0) close(lpi->lpfd.fd); if (lpi->pr.close) @@ -797,6 +807,29 @@ static int handle_remap(struct lazy_pages_info *lpi, struct uffd_msg *msg) return remap_lazy_iovs(lpi, from, to, len); } +static int handle_exit(struct lazy_pages_info *lpi, struct uffd_msg *msg) +{ + lp_debug(lpi, "EXIT\n"); + list_move(&lpi->l, &exiting_lpis); + return 1; +} + +static int complete_exits(int epollfd) +{ + struct lazy_pages_info *lpi, *n; + + list_for_each_entry_safe(lpi, n, &exiting_lpis, l) { + if (epoll_del_rfd(epollfd, &lpi->lpfd)) + return -1; + free_lazy_iovs(lpi); + close(lpi->lpfd.fd); + /* keep it for summary */ + list_move_tail(&lpi->l, &lpis); + } + + return 0; +} + static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) { struct lp_req *req; @@ -863,6 +896,8 @@ static int handle_uffd_event(struct epoll_rfd *lpfd) return handle_remove(lpi, &msg); case UFFD_EVENT_REMAP: return handle_remap(lpi, &msg); + case UFFD_EVENT_EXIT: + return handle_exit(lpi, &msg); default: lp_err(lpi, "unexpected uffd event %u\n", msg.event); return -1; @@ -902,6 +937,11 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) ret = epoll_run_rfds(epollfd, events, nr_fds, poll_timeout); if (ret < 0) goto out; + if (ret > 0) { + if (complete_exits(epollfd)) + return -1; + continue; + } if (poll_timeout) pr_debug("Start handling remaining pages\n"); From 371947c17428d3b168287012411d2acc6358c05e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:14 +0200 Subject: [PATCH 0888/4375] lazy-pages: add handling of UFFD_EVENT_FORK travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/criu/uffd.c b/criu/uffd.c index 5c453f125..a8adcff38 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -74,6 +74,8 @@ struct lazy_pages_info { struct list_head iovs; struct list_head reqs; + struct lazy_pages_info *parent; + struct page_read pr; unsigned long total_pages; @@ -88,6 +90,7 @@ struct lazy_pages_info { static LIST_HEAD(lpis); static LIST_HEAD(exiting_lpis); +static LIST_HEAD(pending_lpis); static int handle_uffd_event(struct epoll_rfd *lpfd); @@ -366,6 +369,38 @@ static int split_iov(struct lazy_iov *iov, unsigned long addr, bool new_below) return 0; } +static int copy_lazy_iovs(struct lazy_pages_info *src, + struct lazy_pages_info *dst) +{ + struct lazy_iov *iov, *new, *n; + int max_iov_len = 0; + + list_for_each_entry(iov, &src->iovs, l) { + new = xzalloc(sizeof(*new)); + if (!new) + return -1; + + new->base = iov->base; + new->img_base = iov->img_base; + new->len = iov->len; + + list_add_tail(&new->l, &dst->iovs); + + if (new->len > max_iov_len) + max_iov_len = new->len; + } + + if (posix_memalign(&dst->buf, PAGE_SIZE, max_iov_len)) + goto free_iovs; + + return 0; + +free_iovs: + list_for_each_entry_safe(iov, n, &dst->iovs, l) + xfree(iov); + return -1; +} + /* * Purge range (addr, addr + len) from lazy_iovs. The range may * cover several continuous IOVs. @@ -830,6 +865,58 @@ static int complete_exits(int epollfd) return 0; } +static int handle_fork(struct lazy_pages_info *parent_lpi, struct uffd_msg *msg) +{ + struct lazy_pages_info *lpi; + int uffd = msg->arg.fork.ufd; + + lp_debug(parent_lpi, "FORK: child with ufd=%d\n", uffd); + + lpi = lpi_init(); + if (!lpi) + return -1; + + if (copy_lazy_iovs(parent_lpi, lpi)) + goto out; + + lpi->pid = parent_lpi->pid; + lpi->lpfd.fd = uffd; + lpi->parent = parent_lpi->parent ? parent_lpi->parent : parent_lpi; + lpi->copied_pages = lpi->parent->copied_pages; + lpi->total_pages = lpi->parent->total_pages; + list_add_tail(&lpi->l, &pending_lpis); + + dup_page_read(&lpi->parent->pr, &lpi->pr); + + return 1; + +out: + lpi_fini(lpi); + return -1; +} + +static int complete_forks(int epollfd, struct epoll_event **events, int *nr_fds) +{ + struct lazy_pages_info *lpi, *n; + + list_for_each_entry(lpi, &pending_lpis, l) + (*nr_fds)++; + + *events = xrealloc(*events, sizeof(struct epoll_event) * (*nr_fds)); + if (!*events) + return -1; + + list_for_each_entry_safe(lpi, n, &pending_lpis, l) { + if (epoll_add_rfd(epollfd, &lpi->lpfd)) + return -1; + + list_del_init(&lpi->l); + list_add_tail(&lpi->l, &lpis); + } + + return 0; +} + static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) { struct lp_req *req; @@ -898,6 +985,8 @@ static int handle_uffd_event(struct epoll_rfd *lpfd) return handle_remap(lpi, &msg); case UFFD_EVENT_EXIT: return handle_exit(lpi, &msg); + case UFFD_EVENT_FORK: + return handle_fork(lpi, &msg); default: lp_err(lpi, "unexpected uffd event %u\n", msg.event); return -1; @@ -938,6 +1027,8 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) if (ret < 0) goto out; if (ret > 0) { + if (complete_forks(epollfd, &events, &nr_fds)) + return -1; if (complete_exits(epollfd)) return -1; continue; From de01e0d3dc45ca17cea90bb892c64b67bf0172e4 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 6 Feb 2017 13:44:15 +0200 Subject: [PATCH 0889/4375] lazy-pages: request userfaultfd events during API handshake travis-ci: success for lazy-pages: add non-#PF events handling (rev2) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index a8adcff38..f6ce817d9 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -49,6 +49,12 @@ #define lp_err(lpi, fmt, arg...) pr_err("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) #define lp_perror(lpi, fmt, arg...) pr_perror("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) +#define NEED_UFFD_API_FEATURES (UFFD_FEATURE_EVENT_FORK | \ + UFFD_FEATURE_EVENT_EXIT | \ + UFFD_FEATURE_EVENT_REMAP | \ + UFFD_FEATURE_EVENT_UNMAP | \ + UFFD_FEATURE_EVENT_REMOVE) + #define LAZY_PAGES_SOCK_NAME "lazy-pages.socket" static mutex_t *lazy_sock_mutex; @@ -229,7 +235,7 @@ int setup_uffd(int pid, struct task_restore_args *task_args) * Check if the UFFD_API is the one which is expected */ uffdio_api.api = UFFD_API; - uffdio_api.features = 0; + uffdio_api.features = kdat.uffd_features & NEED_UFFD_API_FEATURES; if (ioctl(task_args->uffd, UFFDIO_API, &uffdio_api)) { pr_err("Checking for UFFDIO_API failed.\n"); goto err; From 8eae2ee8442d2f4e851161e681ec1d2001ea1bd8 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 8 Feb 2017 15:13:00 +0300 Subject: [PATCH 0890/4375] test: add basic test for uffd events The lazy-pages daemon have to properly track changes to virtual memory layout of the restored process. The test verifies that lazy-pages daemon properly reacts to fork(), exit(), madvise(MADV_DONTNEED) and mremap() events. Currently, no zdtm tests would generate UFFD_EVENT_{REMAP,REMOVE}. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- test/zdtm/static/Makefile | 1 + test/zdtm/static/uffd-events.c | 188 +++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 test/zdtm/static/uffd-events.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 55f7b896d..2f26818d2 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -172,6 +172,7 @@ TST_NOFILE := \ cr_veth \ sock_peercred \ s390x_mmap_high \ + uffd-events \ # jobctl00 \ include ../Makefile.inc diff --git a/test/zdtm/static/uffd-events.c b/test/zdtm/static/uffd-events.c new file mode 100644 index 000000000..9939c86b8 --- /dev/null +++ b/test/zdtm/static/uffd-events.c @@ -0,0 +1,188 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "zdtmtst.h" + +const char *test_doc = "Test uffd events"; +const char *test_author = "Mike Rapoport "; + +#define NR_MAPS 5 +#define MAP_SIZE (1 << 20) + +static void *map[NR_MAPS]; + +static int create_mappings(void) +{ + uint32_t crc; + int i; + + for (i = 0; i < NR_MAPS; i++) { + map[i] = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (map[i] == MAP_FAILED) { + fail("mmap failed"); + return 1; + } + + crc = i; + datagen(map[i], MAP_SIZE, &crc); + } + + return 0; +} + +static int verify_zeroes(void *m) +{ + int i; + + for (i = 0; i < MAP_SIZE; i += PAGE_SIZE) { + char *p = m + i; + if (*p != 0) + return 1; + } + + return 0; +} + +static int check_madv_dn(int idx) +{ + void *m = map[idx]; + + if (madvise(m, MAP_SIZE, MADV_DONTNEED)) { + fail("madvise failed"); + return 1; + } + + if (verify_zeroes(m)) { + fail("not zero"); + return 1; + } + + return 0; +} + +static int check_mremap_grow(int idx) +{ + void *m = map[idx]; + uint32_t crc = idx; + + m = mremap(m, MAP_SIZE, MAP_SIZE * 2, MREMAP_MAYMOVE); + if (m == MAP_FAILED) { + fail("mremap failed"); + return 1; + } + + if (datachk(m, MAP_SIZE, &crc)) { + fail("Mem corrupted"); + return 1; + } + + /* the new part of the mapping should be filled with zeroes */ + m += MAP_SIZE; + if (verify_zeroes(m)) { + fail("not zeroes"); + return 1; + } + + return 0; +} + +static int check_swapped_mappings(int idx) +{ + uint32_t crc = idx; + void *m1 = map[idx]; + void *m2 = map[idx + 1]; + void *p = map[0]; + + p = mremap(m1, MAP_SIZE, MAP_SIZE, MREMAP_MAYMOVE | MREMAP_FIXED, p); + if (p == MAP_FAILED) { + fail("mremap failed"); + return 1; + } + + m1 = mremap(m2, MAP_SIZE, MAP_SIZE, MREMAP_MAYMOVE | MREMAP_FIXED, m1); + if (m1 == MAP_FAILED) { + fail("mremap failed"); + return 1; + } + + m2 = mremap(p, MAP_SIZE, MAP_SIZE, MREMAP_MAYMOVE | MREMAP_FIXED, m2); + if (m2 == MAP_FAILED) { + fail("mremap failed"); + return 1; + } + + if (datachk(m2, MAP_SIZE, &crc)) { + fail("Mem corrupted"); + return 1; + } + + crc = idx + 1; + if (datachk(m1, MAP_SIZE, &crc)) { + fail("Mem corrupted"); + return 1; + } + + return 0; +} + +int main(int argc, char ** argv) +{ + uint32_t crc; + int pid; + + test_init(argc, argv); + + if (create_mappings()) + return -1; + + test_daemon(); + test_waitsig(); + + /* run some page faults */ + crc = 0; + if (datachk(map[0], MAP_SIZE, &crc)) { + fail("Mem corrupted"); + return 1; + } + + pid = fork(); + if (pid < 0) { + fail("Can't fork"); + return 1; + } + + /* check madvise(MADV_DONTNEED) */ + if (check_madv_dn(1)) + return 1; + + /* check growing mremap */ + if (check_mremap_grow(2)) + return 1; + + /* check swapped mappings */ + if (check_swapped_mappings(3)) + return 1; + + if (pid) { + int status; + + waitpid(-1, &status, 0); + if (status) { + fail("child failed"); + return status; + } + } + + pass(); + return 0; +} From 985d154ea66df57ffc7c95dd945747ef737f5624 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 8 Feb 2017 14:01:14 +0200 Subject: [PATCH 0891/4375] lazy-pages: add comments about different addresses in lazy_iov and lp_req Both lazy_iov and lp_req have two fields for address/start: the run-time address that tracks remaps, and the "dump time" address, which is required for pagemap accesses. Signed-off-by: Mike Rapoport Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/uffd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index f6ce817d9..6cee7ecb1 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -61,16 +61,16 @@ static mutex_t *lazy_sock_mutex; struct lazy_iov { struct list_head l; - unsigned long base; - unsigned long img_base; + unsigned long base; /* run-time start address, tracks remaps */ + unsigned long img_base; /* start address at the dump time */ unsigned long len; }; struct lazy_pages_info; struct lp_req { - unsigned long addr; - unsigned long img_addr; + unsigned long addr; /* actual #PF (or background) destination */ + unsigned long img_addr; /* the corresponding address at the dump time */ struct list_head l; }; From 6b1dbb1e63263acf26c2aa107de5db22b3ede7be Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 5 Apr 2017 15:28:38 +0300 Subject: [PATCH 0892/4375] lazy-pages: drop unneeded forward declaration Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 6cee7ecb1..021c07bbd 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -66,8 +66,6 @@ struct lazy_iov { unsigned long len; }; -struct lazy_pages_info; - struct lp_req { unsigned long addr; /* actual #PF (or background) destination */ unsigned long img_addr; /* the corresponding address at the dump time */ From 4c0d56f4e79bc52c99cf3db702ad3cf6767e18c8 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 5 Apr 2017 15:28:39 +0300 Subject: [PATCH 0893/4375] lazy-pages: make epollfd part of global daemon state We only use one epoll instance to manage lazy-pages related I/O. Making epollfd file-visible will allow cleaner implementation of the restored process exit() calls tracking. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index 021c07bbd..f8767decb 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -92,9 +92,11 @@ struct lazy_pages_info { void *buf; }; +/* global lazy-pages daemon state */ static LIST_HEAD(lpis); static LIST_HEAD(exiting_lpis); static LIST_HEAD(pending_lpis); +static int epollfd; static int handle_uffd_event(struct epoll_rfd *lpfd); @@ -1119,7 +1121,6 @@ close_uffd: int cr_lazy_pages(bool daemon) { struct epoll_event *events; - int epollfd; int nr_fds; int lazy_sk; int ret; From 27662f2547e2d85feb669a934202dd5a0ed102ff Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 5 Apr 2017 15:28:40 +0300 Subject: [PATCH 0894/4375] lazy-pages: handle exit() based on uffdio_copy return value The UFFDIO_EVENT_EXIT didn't make it upstream because of possible races in exit() syscall [1]. The only way to detect that the monitored process is exited is checking for ENOSPC errno value set by uffdio_copy. [1] http://www.spinics.net/lists/linux-mm/msg122467.html Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 54 ++++++++++++++++++++++------------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index f8767decb..b2cf102fa 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -50,7 +50,6 @@ #define lp_perror(lpi, fmt, arg...) pr_perror("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg) #define NEED_UFFD_API_FEATURES (UFFD_FEATURE_EVENT_FORK | \ - UFFD_FEATURE_EVENT_EXIT | \ UFFD_FEATURE_EVENT_REMAP | \ UFFD_FEATURE_EVENT_UNMAP | \ UFFD_FEATURE_EVENT_REMOVE) @@ -662,6 +661,20 @@ out: return -1; } +static int handle_exit(struct lazy_pages_info *lpi) +{ + lp_debug(lpi, "EXIT\n"); + if (epoll_del_rfd(epollfd, &lpi->lpfd)) + return -1; + free_lazy_iovs(lpi); + close(lpi->lpfd.fd); + + /* keep it for summary */ + list_move_tail(&lpi->l, &lpis); + + return 0; +} + static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) { struct uffdio_copy uffdio_copy; @@ -677,11 +690,15 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) lp_debug(lpi, "uffd_copy: 0x%llx/%ld\n", uffdio_copy.dst, len); rc = ioctl(lpi->lpfd.fd, UFFDIO_COPY, &uffdio_copy); if (rc) { - /* real retval in ufdio_copy.copy */ - lp_err(lpi, "UFFDIO_COPY failed: rc:%d copy:%Ld\n", rc, - uffdio_copy.copy); - if (uffdio_copy.copy != -EEXIST) + if (errno == ENOSPC) { + handle_exit(lpi); + return 0; + } + if (uffdio_copy.copy != -EEXIST) { + lp_debug(lpi, "uffd_copy: rc:%d copy:%Ld, errno:%d\n", + rc, uffdio_copy.copy, errno); return -1; + } } else if (uffdio_copy.copy != len) { lp_err(lpi, "UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy); return -1; @@ -848,29 +865,6 @@ static int handle_remap(struct lazy_pages_info *lpi, struct uffd_msg *msg) return remap_lazy_iovs(lpi, from, to, len); } -static int handle_exit(struct lazy_pages_info *lpi, struct uffd_msg *msg) -{ - lp_debug(lpi, "EXIT\n"); - list_move(&lpi->l, &exiting_lpis); - return 1; -} - -static int complete_exits(int epollfd) -{ - struct lazy_pages_info *lpi, *n; - - list_for_each_entry_safe(lpi, n, &exiting_lpis, l) { - if (epoll_del_rfd(epollfd, &lpi->lpfd)) - return -1; - free_lazy_iovs(lpi); - close(lpi->lpfd.fd); - /* keep it for summary */ - list_move_tail(&lpi->l, &lpis); - } - - return 0; -} - static int handle_fork(struct lazy_pages_info *parent_lpi, struct uffd_msg *msg) { struct lazy_pages_info *lpi; @@ -989,8 +983,6 @@ static int handle_uffd_event(struct epoll_rfd *lpfd) return handle_remove(lpi, &msg); case UFFD_EVENT_REMAP: return handle_remap(lpi, &msg); - case UFFD_EVENT_EXIT: - return handle_exit(lpi, &msg); case UFFD_EVENT_FORK: return handle_fork(lpi, &msg); default: @@ -1035,8 +1027,6 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) if (ret > 0) { if (complete_forks(epollfd, &events, &nr_fds)) return -1; - if (complete_exits(epollfd)) - return -1; continue; } From 583a399732e6985bff19434cb95d42b078f9d35a Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 5 Apr 2017 15:28:41 +0300 Subject: [PATCH 0895/4375] Update criu/include/linux/userfaultfd.h This is the version from v4.11-rc5. Apparently, that would be the userfault ABI for the next few month. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/cr-check.c | 1 - criu/include/linux/userfaultfd.h | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index dfe3a50ee..46ab6f1a9 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1049,7 +1049,6 @@ static int check_compat_cr(void) static int check_uffd(void) { unsigned long features = UFFD_FEATURE_EVENT_FORK | - UFFD_FEATURE_EVENT_EXIT | UFFD_FEATURE_EVENT_REMAP | UFFD_FEATURE_EVENT_UNMAP | UFFD_FEATURE_EVENT_REMOVE; diff --git a/criu/include/linux/userfaultfd.h b/criu/include/linux/userfaultfd.h index c055947c5..3b059530d 100644 --- a/criu/include/linux/userfaultfd.h +++ b/criu/include/linux/userfaultfd.h @@ -18,8 +18,7 @@ * means the userland is reading). */ #define UFFD_API ((__u64)0xAA) -#define UFFD_API_FEATURES (UFFD_FEATURE_EVENT_EXIT | \ - UFFD_FEATURE_EVENT_FORK | \ +#define UFFD_API_FEATURES (UFFD_FEATURE_EVENT_FORK | \ UFFD_FEATURE_EVENT_REMAP | \ UFFD_FEATURE_EVENT_REMOVE | \ UFFD_FEATURE_EVENT_UNMAP | \ @@ -113,7 +112,6 @@ struct uffd_msg { #define UFFD_EVENT_REMAP 0x14 #define UFFD_EVENT_REMOVE 0x15 #define UFFD_EVENT_UNMAP 0x16 -#define UFFD_EVENT_EXIT 0x17 /* flags for UFFD_EVENT_PAGEFAULT */ #define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */ @@ -163,7 +161,6 @@ struct uffdio_api { #define UFFD_FEATURE_MISSING_HUGETLBFS (1<<4) #define UFFD_FEATURE_MISSING_SHMEM (1<<5) #define UFFD_FEATURE_EVENT_UNMAP (1<<6) -#define UFFD_FEATURE_EVENT_EXIT (1<<7) __u64 features; __u64 ioctls; From bd39d5edc5137eb03fad7b68d5cee6c6f810285b Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 20 Apr 2017 19:45:49 +0300 Subject: [PATCH 0896/4375] travis: add lazy-pages run Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 8800d5f04..8c708e90e 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -70,6 +70,7 @@ chmod 0777 test/zdtm/static chmod 0777 test/zdtm/transition ./test/zdtm.py run -a -p 2 +./test/zdtm.py run -a -p 2 --lazy-pages -x maps007 bash ./test/jenkins/criu-fault.sh bash ./test/jenkins/criu-fcg.sh From 516b7795517bfccc1254c7b0e027856c33d75383 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 31 May 2017 12:51:41 +0300 Subject: [PATCH 0897/4375] travis-test: select tests skipped by lazy-pages pass more carefully Most of zdtm test should pass with --lazy-pages with kernels newer than 4.11. Some test excluded for older kernels surprisingly pass even now, mainly becuase they do not actually stress userfaultfd, which will be fixed in the upcoming commits :) The cmdlinenv00 fails even with kernel 4.11 because of a race between uffd and gup in the case external process reads /proc//cmdline before memory containing the command line is populated. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 8c708e90e..8b1a632f1 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -70,7 +70,17 @@ chmod 0777 test/zdtm/static chmod 0777 test/zdtm/transition ./test/zdtm.py run -a -p 2 -./test/zdtm.py run -a -p 2 --lazy-pages -x maps007 + +KERN_MAJ=`uname -r | cut -d. -f1` +KERN_MIN=`uname -r | cut -d. -f2` +if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then + LAZY_EXCLUDE="-x cmdlinenv00" +else + LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns + -x socket_listen -x socket_listen6 -x cmdlinenv00 + -x socket_close_data01 -x file_read" +fi +./test/zdtm.py run -a -p 2 --lazy-pages $LAZY_EXCLUDE --keep-going --report report bash ./test/jenkins/criu-fault.sh bash ./test/jenkins/criu-fcg.sh From a9ea60f8b36dac1f67e0873a114088b266bd5d48 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 31 May 2017 12:51:42 +0300 Subject: [PATCH 0898/4375] zdtm: check lazy-pages and page-server exit status after test is gone When running with --lazy-pages or --remote-lazy-pages, the daemons should run in the background, rather than complete before t.stop() is called. Many tests try to verify things are ok after test_waitsig() and that's exactly the place where they access memory and cause page faults. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index d33a5b098..b07c28db9 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -792,7 +792,17 @@ class criu: self.__lazy_pages_p = None self.__page_server_p = None - def fini(self, opts): + def fini(self): + if self.__lazy_pages_p: + ret = self.__lazy_pages_p.wait() + self.__lazy_pages_p = None + if ret: + raise test_fail_exc("criu lazy-pages exited with %s" % ret) + if self.__page_server_p: + ret = self.__page_server_p.wait() + self.__page_server_p = None + if ret: + raise test_fail_exc("criu page-server exited with %s" % ret) return def logs(self): @@ -982,18 +992,6 @@ class criu: self.__criu_act("restore", opts = r_opts + ["--restore-detached"]) - if self.__lazy_pages_p: - ret = self.__lazy_pages_p.wait() - self.__lazy_pages_p = None - if ret: - raise test_fail_exc("criu lazy-pages exited with %s" % ret) - - if self.__page_server_p: - ret = self.__page_server_p.wait() - self.__page_server_p = None - if ret: - raise test_fail_exc("criu page-server exited with %s" % ret) - if self.__leave_stopped: pstree_check_stopped(self.__test.getpid()) pstree_signal(self.__test.getpid(), signal.SIGCONT) @@ -1353,7 +1351,7 @@ def do_run_test(tname, tdesc, flavs, opts): if opts['join_ns']: check_joinns_state(t) t.stop() - cr_api.fini(opts) + cr_api.fini() try_run_hook(t, ["--clean"]) except test_fail_exc as e: print_sep("Test %s FAIL at %s" % (tname, e.step), '#') From eb261b579d6c8d03cac66bcb7ce81b06eff75dd9 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 31 May 2017 12:51:43 +0300 Subject: [PATCH 0899/4375] zdtm: introduce 'noremotelazy' flag This allows skipping tests that are not yet run with --remote-lazy-pages, but can be run with --lazy-pages Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index b07c28db9..cfa7b2ee1 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1709,6 +1709,11 @@ def run_tests(opts): l.skip(t, "lazy pages are not supported") continue + if opts['remote_lazy_pages']: + if test_flag(tdesc, 'noremotelazy'): + l.skip(t, "remote lazy pages are not supported") + continue + test_flavs = tdesc.get('flavor', 'h ns uns').split() opts_flavs = (opts['flavor'] or 'h,ns,uns').split(',') if opts_flavs != ['best']: From 459b833a8ee87fc7c0310ff3a95346febb5bf564 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 31 May 2017 12:51:44 +0300 Subject: [PATCH 0900/4375] zdtm: enable fork tests with --lazy-pages They still will fail with --remote-lazy-pages, so mark them as 'noremotelazy' Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm/transition/fork.desc | 2 +- test/zdtm/transition/fork2.desc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/zdtm/transition/fork.desc b/test/zdtm/transition/fork.desc index 1ffa341ba..92b7c45d0 100644 --- a/test/zdtm/transition/fork.desc +++ b/test/zdtm/transition/fork.desc @@ -1 +1 @@ -{'flags' : 'nolazy'} +{'flags' : 'noremotelazy'} diff --git a/test/zdtm/transition/fork2.desc b/test/zdtm/transition/fork2.desc index 1ffa341ba..92b7c45d0 100644 --- a/test/zdtm/transition/fork2.desc +++ b/test/zdtm/transition/fork2.desc @@ -1 +1 @@ -{'flags' : 'nolazy'} +{'flags' : 'noremotelazy'} From 9354582fd2b143fb0686852d29db2f439031b8c1 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 4 May 2017 16:32:02 +0300 Subject: [PATCH 0901/4375] kdat: Relax uffd checks (v2) v2: When uffd is present, the reported features may still be 0, so we need one more bool for uffd syscall itself. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-check.c | 7 ++++++- criu/cr-service.c | 4 ++-- criu/include/kerndat.h | 3 ++- criu/kerndat.c | 10 ++++++---- criu/uffd.c | 2 +- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index 46ab6f1a9..029fb4350 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1053,9 +1053,14 @@ static int check_uffd(void) UFFD_FEATURE_EVENT_UNMAP | UFFD_FEATURE_EVENT_REMOVE; - if (kerndat_uffd(true)) + if (kerndat_uffd()) return -1; + if (!kdat.has_uffd) { + pr_err("UFFD is not supported\n"); + return -1; + } + if ((kdat.uffd_features & features) != features) { pr_err("Userfaultfd missing essential features\n"); return -1; diff --git a/criu/cr-service.c b/criu/cr-service.c index 81b0bc632..375b03533 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -900,7 +900,7 @@ static int handle_feature_check(int sk, CriuReq * msg) if ((msg->features->has_lazy_pages == 1) && (msg->features->lazy_pages == true)) { - ret = kerndat_uffd(true); + ret = kerndat_uffd(); /* * Not checking for specific UFFD features yet. @@ -909,7 +909,7 @@ static int handle_feature_check(int sk, CriuReq * msg) * be extended in the future for a more detailed * UFFD feature check. */ - if (ret) + if (ret || !kdat.has_uffd) feat.lazy_pages = false; else feat.lazy_pages = true; diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 4078f06ce..9a50563ca 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -49,6 +49,7 @@ struct kerndat_s { bool has_tcp_half_closed; bool stack_guard_gap_hidden; int lsm; + bool has_uffd; unsigned long uffd_features; }; @@ -71,6 +72,6 @@ enum { extern int kerndat_fs_virtualized(unsigned int which, u32 kdev); extern int kerndat_tcp_repair(); -extern int kerndat_uffd(bool need_uffd); +extern int kerndat_uffd(void); #endif /* __CR_KERNDAT_H__ */ diff --git a/criu/kerndat.c b/criu/kerndat.c index 1a40ff035..4587ed032 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -715,7 +715,7 @@ unl: } } -int kerndat_uffd(bool need_uffd) +int kerndat_uffd(void) { struct uffdio_api uffdio_api; int uffd; @@ -727,14 +727,16 @@ int kerndat_uffd(bool need_uffd) * on this system. Additionally checking for ENOSYS * makes sure it is actually not implemented. */ - if (uffd == -1 && errno == ENOSYS) { - if (!need_uffd) + if (uffd == -1) { + if (errno == ENOSYS) return 0; pr_err("Lazy pages are not available\n"); return -1; } + kdat.has_uffd = true; + uffdio_api.api = UFFD_API; uffdio_api.features = 0; if (ioctl(uffd, UFFDIO_API, &uffdio_api)) { @@ -792,7 +794,7 @@ int kerndat_init(void) if (!ret) ret = kerndat_detect_stack_guard_gap(); if (!ret) - ret = kerndat_uffd(opts.lazy_pages); + ret = kerndat_uffd(); kerndat_lsm(); kerndat_mmap_min_addr(); diff --git a/criu/uffd.c b/criu/uffd.c index b2cf102fa..205045e34 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1115,7 +1115,7 @@ int cr_lazy_pages(bool daemon) int lazy_sk; int ret; - if (kerndat_uffd(true)) + if (kerndat_uffd() || !kdat.has_uffd) return -1; if (prepare_dummy_pstree()) From 7c108b8b8db351c1940a9cde7019e7a67e093dc0 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Fri, 16 Jun 2017 00:13:41 +0300 Subject: [PATCH 0902/4375] lazy-pages: make the check for outstanding request more strict There could be several outstaning requests for the same page, either from page fault handler or from handle_remaining_pages. Verifying that the faulting address is already requested is not enough. We need to check if there any request in flight that covers the faulting address. Signed-off-by: Mike Rapoport Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/uffd.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 205045e34..84fd07bfc 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -68,6 +68,7 @@ struct lazy_iov { struct lp_req { unsigned long addr; /* actual #PF (or background) destination */ unsigned long img_addr; /* the corresponding address at the dump time */ + unsigned long len; struct list_head l; }; @@ -817,6 +818,7 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) req->addr = iov->base; req->img_addr = iov->img_base; + req->len = iov->len; list_add(&req->l, &lpi->reqs); err = uffd_handle_pages(lpi, req->img_addr, nr_pages, 0); @@ -917,6 +919,17 @@ static int complete_forks(int epollfd, struct epoll_event **events, int *nr_fds) return 0; } +static bool is_page_queued(struct lazy_pages_info *lpi, unsigned long addr) +{ + struct lp_req *req; + + list_for_each_entry(req, &lpi->reqs, l) + if (addr >= req->addr && addr < req->addr + req->len) + return true; + + return false; +} + static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) { struct lp_req *req; @@ -928,9 +941,8 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) address = msg->arg.pagefault.address & ~(page_size() - 1); lp_debug(lpi, "#PF at 0x%llx\n", address); - list_for_each_entry(req, &lpi->reqs, l) - if (req->addr == address) - return 0; + if (is_page_queued(lpi, address)) + return 0; iov = find_lazy_iov(lpi, address); if (!iov) @@ -941,6 +953,7 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) return -1; req->addr = address; req->img_addr = iov->img_base + (address - iov->base); + req->len = PAGE_SIZE; list_add(&req->l, &lpi->reqs); ret = uffd_handle_pages(lpi, req->img_addr, 1, PR_ASYNC | PR_ASAP); From a364f05bf9ba1e330ad727f070743aefdfb34d31 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Fri, 16 Jun 2017 00:13:42 +0300 Subject: [PATCH 0903/4375] lazy-pages: handle_remaining_pages: enable asynchronous reads Until now once we've started to fetch an iovec we've been waiting until it's completely copied before returning to event processing loop. Now we can have several request for the remote pages in flight. Signed-off-by: Mike Rapoport Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/uffd.c | 65 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 84fd07bfc..41d5d320b 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -63,6 +63,7 @@ struct lazy_iov { unsigned long base; /* run-time start address, tracks remaps */ unsigned long img_base; /* start address at the dump time */ unsigned long len; + bool queued; }; struct lp_req { @@ -669,8 +670,9 @@ static int handle_exit(struct lazy_pages_info *lpi) return -1; free_lazy_iovs(lpi); close(lpi->lpfd.fd); + lpi->lpfd.fd = 0; - /* keep it for summary */ + /* keep it for tracking in-flight requests and for the summary */ list_move_tail(&lpi->l, &lpis); return 0; @@ -724,6 +726,14 @@ static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long img_ad } } + /* + * The process may exit while we still have requests in + * flight. We just drop the request and the received data in + * this case to avoid making uffd unhappy + */ + if (list_empty(&lpi->iovs)) + return 0; + BUG_ON(!addr); if (uffd_copy(lpi, addr, nr)) @@ -803,13 +813,41 @@ static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr, return 0; } +static struct lazy_iov *first_pending_iov(struct lazy_pages_info *lpi) +{ + struct lazy_iov *iov; + + list_for_each_entry(iov, &lpi->iovs, l) + if (!iov->queued) + return iov; + + return NULL; +} + +static bool is_iov_queued(struct lazy_pages_info *lpi, struct lazy_iov *iov) +{ + struct lp_req *req; + + list_for_each_entry(req, &lpi->reqs, l) + if (req->addr >= iov->base && req->addr < iov->base + iov->len) + return true; + + return false; +} + static int handle_remaining_pages(struct lazy_pages_info *lpi) { struct lazy_iov *iov; struct lp_req *req; int nr_pages, err; - iov = list_first_entry(&lpi->iovs, struct lazy_iov, l); + iov = first_pending_iov(lpi); + if (!iov) + return 0; + + if (is_iov_queued(lpi, iov)) + return 0; + nr_pages = iov->len / PAGE_SIZE; req = xzalloc(sizeof(*req)); @@ -820,8 +858,9 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) req->img_addr = iov->img_base; req->len = iov->len; list_add(&req->l, &lpi->reqs); + iov->queued = true; - err = uffd_handle_pages(lpi, req->img_addr, nr_pages, 0); + err = uffd_handle_pages(lpi, req->img_addr, nr_pages, PR_ASYNC | PR_ASAP); if (err < 0) { lp_err(lpi, "Error during UFFD copy\n"); return -1; @@ -1006,7 +1045,7 @@ static int handle_uffd_event(struct epoll_rfd *lpfd) return 0; } -static int lazy_pages_summary(struct lazy_pages_info *lpi) +static void lazy_pages_summary(struct lazy_pages_info *lpi) { lp_debug(lpi, "UFFD transferred pages: (%ld/%ld)\n", lpi->copied_pages, lpi->total_pages); @@ -1019,15 +1058,13 @@ static int lazy_pages_summary(struct lazy_pages_info *lpi) return 1; } #endif - - return 0; } #define POLL_TIMEOUT 1000 static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) { - struct lazy_pages_info *lpi; + struct lazy_pages_info *lpi, *n; int poll_timeout = POLL_TIMEOUT; int ret; @@ -1047,9 +1084,16 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) pr_debug("Start handling remaining pages\n"); poll_timeout = 0; - list_for_each_entry(lpi, &lpis, l) { + list_for_each_entry_safe(lpi, n, &lpis, l) { + if (list_empty(&lpi->iovs) && list_empty(&lpi->reqs)) { + lazy_pages_summary(lpi); + list_del(&lpi->l); + lpi_fini(lpi); + continue; + } + + remaining = true; if (!list_empty(&lpi->iovs)) { - remaining = true; ret = handle_remaining_pages(lpi); if (ret < 0) goto out; @@ -1061,9 +1105,6 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) break; } - list_for_each_entry(lpi, &lpis, l) - ret += lazy_pages_summary(lpi); - out: return ret; From 1ad1400c8bc6be7a2368f03deef4e6b87bb0f600 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 7 Jun 2017 11:53:56 +0300 Subject: [PATCH 0904/4375] lazy-pages: use random read from page-pipe instead of splitting it For the remote lazy pages case, to access pages in the middle of a pipe we are splitting the page_pipe_buffers and iovecs and use splice() to move the data between the underlying pipes. After the splits we get page_pipe_buffer with single iovec that can be used to splice() the data further into the socket. This patch replaces the splitting and splicing with use of a helper pipe and tee(). We tee() the pages from beginning of the pipe up to the last requested page into a helper pipe, sink the unneeded head part into /dev/null and we get the requested pages ready for splice() into the socket. This allows lazy-pages daemon to request the same page several time, which is required to properly support fork() after the restore. As added bonus we simplify the code and reduce amount of pipes that live in the system. Signed-off-by: Mike Rapoport Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/page-pipe.h | 10 ++++++ criu/page-pipe.c | 73 ++++++++++++++++++++++++++++++++++++++++ criu/page-xfer.c | 59 +++++++++++--------------------- 3 files changed, 102 insertions(+), 40 deletions(-) diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h index 10ae87321..76ec1fd5a 100644 --- a/criu/include/page-pipe.h +++ b/criu/include/page-pipe.h @@ -138,4 +138,14 @@ extern int page_pipe_split(struct page_pipe *pp, unsigned long addr, extern void page_pipe_destroy_ppb(struct page_pipe_buf *ppb); +struct pipe_read_dest { + int p[2]; + int sink_fd; +}; + +extern int pipe_read_dest_init(struct pipe_read_dest *prd); +extern int page_pipe_read(struct page_pipe *pp, struct pipe_read_dest *prd, + unsigned long addr, unsigned int *nr_pages, + unsigned int ppb_flags); + #endif /* __CR_PAGE_PIPE_H__ */ diff --git a/criu/page-pipe.c b/criu/page-pipe.c index 4ebd0cbe8..4b4b3fc2a 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -474,6 +474,79 @@ int page_pipe_split(struct page_pipe *pp, unsigned long addr, return 0; } +int pipe_read_dest_init(struct pipe_read_dest *prd) +{ + int ret; + + if (pipe(prd->p)) { + pr_perror("Cannot create pipe for reading from page-pipe"); + return -1; + } + + ret = fcntl(prd->p[0], F_SETPIPE_SZ, PIPE_MAX_SIZE * PAGE_SIZE); + if (ret < 0) + return -1; + + prd->sink_fd = open("/dev/null", O_WRONLY); + if (prd->sink_fd < 0) { + pr_perror("Cannot open sink for reading from page-pipe"); + return -1; + } + + ret = fcntl(prd->p[0], F_GETPIPE_SZ, 0); + pr_debug("Created tee pipe size %d\n", ret); + + return 0; +} + +int page_pipe_read(struct page_pipe *pp, struct pipe_read_dest *prd, + unsigned long addr, unsigned int *nr_pages, + unsigned int ppb_flags) +{ + struct page_pipe_buf *ppb; + struct iovec *iov = NULL; + unsigned long skip = 0, len; + int ret; + + /* + * Get ppb that contains addr and count length of data between + * the beginning of the pipe and addr. If no ppb is found, the + * requested page is mapped to zero pfn + */ + ppb = get_ppb(pp, addr, &iov, &skip); + if (!ppb) { + *nr_pages = 0; + return 0; + } + + if (!(ppb->flags & ppb_flags)) { + pr_err("PPB flags mismatch: %x %x\n", ppb_flags, ppb->flags); + return false; + } + + /* clamp the request if it passes the end of iovec */ + len = min((unsigned long)iov->iov_base + iov->iov_len - addr, + (unsigned long)(*nr_pages) * PAGE_SIZE); + *nr_pages = len / PAGE_SIZE; + + /* we should tee() the requested lenth + the beginning of the pipe */ + len += skip; + + ret = tee(ppb->p[0], prd->p[1], len, 0); + if (ret != len) { + pr_perror("tee: %d", ret); + return -1; + } + + ret = splice(prd->p[0], NULL, prd->sink_fd, NULL, skip, 0); + if (ret != skip) { + pr_perror("splice: %d", ret); + return -1; + } + + return 0; +} + void page_pipe_destroy_ppb(struct page_pipe_buf *ppb) { list_del(&ppb->l); diff --git a/criu/page-xfer.c b/criu/page-xfer.c index e282536f2..603f77b53 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -577,10 +577,19 @@ static struct page_xfer_job cxfer = { .dst_id = ~0, }; +static struct pipe_read_dest pipe_read_dest = { + .sink_fd = -1, +}; + static void page_server_close(void) { if (cxfer.dst_id != ~0) cxfer.loc_xfer.close(&cxfer.loc_xfer); + if (pipe_read_dest.sink_fd != -1) { + close(pipe_read_dest.sink_fd); + close(pipe_read_dest.p[0]); + close(pipe_read_dest.p[1]); + } } static int page_server_open(int sk, struct page_server_iov *pi) @@ -684,43 +693,18 @@ static int page_server_add(int sk, struct page_server_iov *pi, u32 flags) return 0; } -static bool can_send_pages(struct page_pipe_buf *ppb, struct iovec *iov, - struct page_server_iov *pi) -{ - unsigned long len = pi->nr_pages * PAGE_SIZE; - - if (!(ppb->flags & PPB_LAZY)) { - pr_err("Requested pages are not lazy\n"); - return false; - } - - if (iov->iov_len != len) { - pr_err("IOV len %zu does not match requested %lu\n", - iov->iov_len, len); - return false; - } - - if(pi->vaddr != encode_pointer(iov->iov_base)) { - pr_err("IOV start %p does not match requested addr %"PRIx64"\n", - iov->iov_base, pi->vaddr); - return false; - } - - return true; -} - static int page_server_get_pages(int sk, struct page_server_iov *pi) { struct pstree_item *item; struct page_pipe *pp; - struct page_pipe_buf *ppb; - struct iovec *iov; + unsigned long len; int ret; item = pstree_item_by_virt(pi->dst_id); pp = dmpi(item)->mem_pp; - ret = page_pipe_split(pp, pi->vaddr, &pi->nr_pages); + ret = page_pipe_read(pp, &pipe_read_dest, pi->vaddr, + &pi->nr_pages, PPB_LAZY); if (ret) return ret; @@ -730,23 +714,17 @@ static int page_server_get_pages(int sk, struct page_server_iov *pi) return send_psi(sk, PS_IOV_ZERO, 0, 0, 0); } - ppb = list_first_entry(&pp->bufs, struct page_pipe_buf, l); - iov = &ppb->iov[0]; - - if (!can_send_pages(ppb, iov, pi)) - return -1; + len = pi->nr_pages * PAGE_SIZE; if (send_psi(sk, PS_IOV_ADD, pi->nr_pages, pi->vaddr, pi->dst_id)) return -1; - ret = splice(ppb->p[0], NULL, sk, NULL, iov->iov_len, SPLICE_F_MOVE); - if (ret != iov->iov_len) + ret = splice(pipe_read_dest.p[0], NULL, sk, NULL, len, SPLICE_F_MOVE); + if (ret != len) return -1; tcp_nodelay(sk, true); - page_pipe_destroy_ppb(ppb); - return 0; } @@ -754,8 +732,9 @@ static int page_server_serve(int sk) { int ret = -1; bool flushed = false; + bool receiving_pages = !opts.lazy_pages; - if (!opts.lazy_pages) { + if (receiving_pages) { /* * This socket only accepts data except one thing -- it * writes back the has_parent bit from time to time, so @@ -772,6 +751,7 @@ static int page_server_serve(int sk) cxfer.pipe_size = fcntl(cxfer.p[0], F_GETPIPE_SZ, 0); pr_debug("Created xfer pipe size %u\n", cxfer.pipe_size); } else { + pipe_read_dest_init(&pipe_read_dest); tcp_cork(sk, true); } @@ -831,7 +811,6 @@ static int page_server_serve(int sk) break; } case PS_IOV_GET: - flushed = true; ret = page_server_get_pages(sk, &pi); break; default: @@ -844,7 +823,7 @@ static int page_server_serve(int sk) break; } - if (!ret && !flushed) { + if (receiving_pages && !ret && !flushed) { pr_err("The data were not flushed\n"); ret = -1; } From 5306cd0fe8a1af87ad3afe219b4f113621c593ed Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 25 Jun 2017 09:58:55 +0300 Subject: [PATCH 0905/4375] lazy-pages: don't close page-read for child processes The page-read for child process is a shallow copy of the parent process page-read. They share the open file descriptors and the pagemap. The lpi_fini of the child processes should not release any resources, they all will be released during lpi_fini of the parent process. Fixes: #325 Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 41d5d320b..d631f4b25 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -130,14 +130,13 @@ static void free_lazy_iovs(struct lazy_pages_info *lpi) static void lpi_fini(struct lazy_pages_info *lpi) { - if (!lpi) return; free(lpi->buf); free_lazy_iovs(lpi); if (lpi->lpfd.fd > 0) close(lpi->lpfd.fd); - if (lpi->pr.close) + if (!lpi->parent && lpi->pr.close) lpi->pr.close(&lpi->pr); free(lpi); } From 77c115f3bf024bf0252fc26f5e83a98269ac4578 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 22 Jun 2017 13:29:21 +0300 Subject: [PATCH 0906/4375] test: enable fork* tests for --remote-lazy-pages Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm/transition/fork.desc | 1 - test/zdtm/transition/fork2.desc | 1 - 2 files changed, 2 deletions(-) delete mode 100644 test/zdtm/transition/fork.desc delete mode 100644 test/zdtm/transition/fork2.desc diff --git a/test/zdtm/transition/fork.desc b/test/zdtm/transition/fork.desc deleted file mode 100644 index 92b7c45d0..000000000 --- a/test/zdtm/transition/fork.desc +++ /dev/null @@ -1 +0,0 @@ -{'flags' : 'noremotelazy'} diff --git a/test/zdtm/transition/fork2.desc b/test/zdtm/transition/fork2.desc deleted file mode 100644 index 92b7c45d0..000000000 --- a/test/zdtm/transition/fork2.desc +++ /dev/null @@ -1 +0,0 @@ -{'flags' : 'noremotelazy'} From 0ebf7b81fa26b1abe6b1b727b668d0202a2f5597 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 22 Jun 2017 13:29:22 +0300 Subject: [PATCH 0907/4375] test/jenkins: update lazy-pages testing * select excluded tests based on the kernel version * test local and remote lazy-pages with and withour pre-dump Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/jenkins/criu-lazy-pages.sh | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/test/jenkins/criu-lazy-pages.sh b/test/jenkins/criu-lazy-pages.sh index 4ada97201..ffcc88609 100755 --- a/test/jenkins/criu-lazy-pages.sh +++ b/test/jenkins/criu-lazy-pages.sh @@ -3,13 +3,31 @@ set -e source `dirname $0`/criu-lib.sh prep -# FIXME: maps007 is sometimes failing with lazy-pages, exclude it for now +KERN_MAJ=`uname -r | cut -d. -f1` +KERN_MIN=`uname -r | cut -d. -f2` +if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then + LAZY_EXCLUDE="-x cmdlinenv00" +else + LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns + -x socket_listen -x socket_listen6 -x cmdlinenv00 + -x socket_close_data01 -x file_read" +fi # lazy restore from images -./test/zdtm.py run --all --keep-going --report report --parallel 4 --lazy-pages -x maps007 || fail - -# lazy restore from images with pre-dumps -./test/zdtm.py run --all --keep-going --report report --parallel 4 --lazy-pages --pre 2 -x maps007 || fail +./test/zdtm.py run --all --keep-going --report report --parallel 4 \ + --lazy-pages $LAZY_EXCLUDE || fail # lazy restore from "remote" dump -./test/zdtm.py run --all --keep-going --report report --parallel 4 --remote-lazy-pages -x maps007 || fail +./test/zdtm.py run --all --keep-going --report report --parallel 4 \ + --remote-lazy-pages $LAZY_EXCLUDE || fail + +# During pre-dump + lazy-pages we leave VM_NOHUGEPAGE set +LAZY_EXCLUDE="$LAZY_EXCLUDE -x maps02" + +# lazy restore from images with pre-dumps +./test/zdtm.py run --all --keep-going --report report --parallel 4 \ + --lazy-pages --pre 2 $LAZY_EXCLUDE || fail + +# lazy restore from "remote" dump with pre-dumps +./test/zdtm.py run --all --keep-going --report report --parallel 4 \ + --remote-lazy-pages --pre 2 $LAZY_EXCLUDE || fail From 47b943862823e4dc5576a40cadd2a5a71ce2da7b Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 22 Jun 2017 13:29:23 +0300 Subject: [PATCH 0908/4375] test/travis: update lazy-pages testing * drop --keep-going etc from --lazy-pages pass * add --remote-lazy-pages pass Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 8b1a632f1..065535943 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -80,7 +80,8 @@ else -x socket_listen -x socket_listen6 -x cmdlinenv00 -x socket_close_data01 -x file_read" fi -./test/zdtm.py run -a -p 2 --lazy-pages $LAZY_EXCLUDE --keep-going --report report +./test/zdtm.py run -a -p 2 --lazy-pages $LAZY_EXCLUDE +./test/zdtm.py run -a -p 2 --remote-lazy-pages $LAZY_EXCLUDE bash ./test/jenkins/criu-fault.sh bash ./test/jenkins/criu-fcg.sh From b801cd68d96944c2610136fc8c718a1ad934d49f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 14 Jun 2017 13:14:28 +0300 Subject: [PATCH 0909/4375] page-server: Introduce page_server_start_sync_read There's no need in two API calls to read xfer header and pages themselves, so merge them into one single call. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/page-xfer.h | 3 +-- criu/page-xfer.c | 22 ++++++++++++++++++++-- criu/pagemap.c | 14 ++------------ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index 1f59bdb03..3d65ebd0b 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -55,11 +55,10 @@ extern int check_parent_page_xfer(int fd_type, long id); /* async request/receive of remote pages */ extern int request_remote_pages(int pid, unsigned long addr, int nr_pages); -extern int receive_remote_pages_info(int *nr_pages, unsigned long *addr, int *pid); -extern int receive_remote_pages(int len, void *buf); typedef int (*ps_async_read_complete)(int pid, unsigned long vaddr, int nr_pages, void *); extern int page_server_start_async_read(void *buf, int nr_pages, ps_async_read_complete complete, void *priv); +extern int page_server_start_sync_read(void *buf, int nr_pages, unsigned long *vaddr); #endif /* __CR_PAGE_XFER__H__ */ diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 603f77b53..77e2e00f8 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -1171,7 +1171,7 @@ int request_remote_pages(int pid, unsigned long addr, int nr_pages) return 0; } -int receive_remote_pages_info(int *nr_pages, unsigned long *addr, int *pid) +static int receive_remote_pages_info(int *nr_pages, unsigned long *addr, int *pid) { struct page_server_iov pi; @@ -1191,7 +1191,7 @@ int receive_remote_pages_info(int *nr_pages, unsigned long *addr, int *pid) return 0; } -int receive_remote_pages(int len, void *buf) +static int receive_remote_pages(int len, void *buf) { if (recv(page_server_sk, buf, len, MSG_WAITALL) != len) { pr_perror("Failed to receive page data"); @@ -1200,3 +1200,21 @@ int receive_remote_pages(int len, void *buf) return 0; } + +int page_server_start_sync_read(void *buf, int nr, unsigned long *vaddr) +{ + int ret, pid, new_nr; + + /* + * Note, that for async remote page_read, the actual + * transfer happens in the lazy-pages daemon + */ + ret = receive_remote_pages_info(&new_nr, vaddr, &pid); + if (ret == 0) { + if (new_nr < 0 || new_nr > nr) + return -1; + ret = receive_remote_pages(nr * PAGE_SIZE, buf); + } + + return ret; +} diff --git a/criu/pagemap.c b/criu/pagemap.c index f4035042d..c590d9e1e 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -434,7 +434,7 @@ static int read_page_complete(int pid, unsigned long vaddr, int nr_pages, void * static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, int nr, void *buf, unsigned flags) { - int ret, pid, new_nr; + int ret; /* We always do PR_ASAP mode here (FIXME?) */ ret = request_remote_pages(pr->pid, vaddr, nr); @@ -443,17 +443,7 @@ static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, if (flags & PR_ASYNC) return page_server_start_async_read(buf, nr, read_page_complete, pr); - /* - * Note, that for async remote page_read, the actual - * transfer happens in the lazy-pages daemon - */ - ret = receive_remote_pages_info(&new_nr, &vaddr, &pid); - if (ret == 0) { - if (new_nr < 0 || new_nr > nr) - return -1; - ret = receive_remote_pages(nr * PAGE_SIZE, buf); - } - + ret = page_server_start_sync_read(buf, nr, &vaddr); if (ret == 0 && pr->io_complete) ret = pr->io_complete(pr, vaddr, nr); From 832f3844f6109e3d4eded0a24033a8c74c6db4ba Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 14 Jun 2017 13:14:46 +0300 Subject: [PATCH 0910/4375] page-server: Unify async/sync calls The newly introduced sync-read call may look exactly the same as its async pair by using the respective complete callback. Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/include/page-xfer.h | 3 ++- criu/page-xfer.c | 9 +++++++-- criu/pagemap.c | 8 ++------ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index 3d65ebd0b..41d904152 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -59,6 +59,7 @@ extern int request_remote_pages(int pid, unsigned long addr, int nr_pages); typedef int (*ps_async_read_complete)(int pid, unsigned long vaddr, int nr_pages, void *); extern int page_server_start_async_read(void *buf, int nr_pages, ps_async_read_complete complete, void *priv); -extern int page_server_start_sync_read(void *buf, int nr_pages, unsigned long *vaddr); +extern int page_server_start_sync_read(void *buf, int nr_pages, + ps_async_read_complete complete, void *priv); #endif /* __CR_PAGE_XFER__H__ */ diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 77e2e00f8..b021e59ee 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -1201,20 +1201,25 @@ static int receive_remote_pages(int len, void *buf) return 0; } -int page_server_start_sync_read(void *buf, int nr, unsigned long *vaddr) +int page_server_start_sync_read(void *buf, int nr, + ps_async_read_complete complete, void *priv) { int ret, pid, new_nr; + unsigned long vaddr; /* * Note, that for async remote page_read, the actual * transfer happens in the lazy-pages daemon */ - ret = receive_remote_pages_info(&new_nr, vaddr, &pid); + ret = receive_remote_pages_info(&new_nr, &vaddr, &pid); if (ret == 0) { if (new_nr < 0 || new_nr > nr) return -1; ret = receive_remote_pages(nr * PAGE_SIZE, buf); } + if (ret == 0) + ret = complete(pid, vaddr, nr, priv); + return ret; } diff --git a/criu/pagemap.c b/criu/pagemap.c index c590d9e1e..c148df6e3 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -442,12 +442,8 @@ static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, return ret; if (flags & PR_ASYNC) return page_server_start_async_read(buf, nr, read_page_complete, pr); - - ret = page_server_start_sync_read(buf, nr, &vaddr); - if (ret == 0 && pr->io_complete) - ret = pr->io_complete(pr, vaddr, nr); - - return ret; + else + return page_server_start_sync_read(buf, nr, read_page_complete, pr); } static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, int nr, From 2cc7e90d5bb88ea5da5a9968d606d15e3389c707 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 14 Jun 2017 13:15:06 +0300 Subject: [PATCH 0911/4375] page-server: Merge async and sync read API calls Now these two look exactly the same and we can have only one call with additional sync/async (flags) arg. Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/include/page-xfer.h | 6 ++---- criu/page-xfer.c | 13 +++++++++++-- criu/pagemap.c | 10 ++++------ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index 41d904152..2b806c797 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -57,9 +57,7 @@ extern int check_parent_page_xfer(int fd_type, long id); extern int request_remote_pages(int pid, unsigned long addr, int nr_pages); typedef int (*ps_async_read_complete)(int pid, unsigned long vaddr, int nr_pages, void *); -extern int page_server_start_async_read(void *buf, int nr_pages, - ps_async_read_complete complete, void *priv); -extern int page_server_start_sync_read(void *buf, int nr_pages, - ps_async_read_complete complete, void *priv); +extern int page_server_start_read(void *buf, int nr_pages, + ps_async_read_complete complete, void *priv, unsigned flags); #endif /* __CR_PAGE_XFER__H__ */ diff --git a/criu/page-xfer.c b/criu/page-xfer.c index b021e59ee..977d7fc14 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -1069,7 +1069,7 @@ struct ps_async_read { static LIST_HEAD(async_reads); -int page_server_start_async_read(void *buf, int nr_pages, +static int page_server_start_async_read(void *buf, int nr_pages, ps_async_read_complete complete, void *priv) { struct ps_async_read *ar; @@ -1201,7 +1201,7 @@ static int receive_remote_pages(int len, void *buf) return 0; } -int page_server_start_sync_read(void *buf, int nr, +static int page_server_start_sync_read(void *buf, int nr, ps_async_read_complete complete, void *priv) { int ret, pid, new_nr; @@ -1223,3 +1223,12 @@ int page_server_start_sync_read(void *buf, int nr, return ret; } + +int page_server_start_read(void *buf, int nr, + ps_async_read_complete complete, void *priv, unsigned flags) +{ + if (flags & PR_ASYNC) + return page_server_start_async_read(buf, nr, complete, priv); + else + return page_server_start_sync_read(buf, nr, complete, priv); +} diff --git a/criu/pagemap.c b/criu/pagemap.c index c148df6e3..ef13220e7 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -438,12 +438,10 @@ static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, /* We always do PR_ASAP mode here (FIXME?) */ ret = request_remote_pages(pr->pid, vaddr, nr); - if (ret < 0) - return ret; - if (flags & PR_ASYNC) - return page_server_start_async_read(buf, nr, read_page_complete, pr); - else - return page_server_start_sync_read(buf, nr, read_page_complete, pr); + if (!ret) + ret = page_server_start_read(buf, nr, + read_page_complete, pr, flags); + return ret; } static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, int nr, From b31a5d67b31b9b71faa2e97ea5d11e2607447877 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 15 Jun 2017 12:33:17 +0300 Subject: [PATCH 0912/4375] page-server: Split the code doing async page-read (v2) This is prerequisite for the next patch. v2: spellchecks, code reshuffle Signed-off-by: Pavel Emelyanov Acked-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 977d7fc14..c9f55c9e4 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -1069,6 +1069,16 @@ struct ps_async_read { static LIST_HEAD(async_reads); +static void init_ps_async_read(struct ps_async_read *ar, void *buf, + int nr_pages, ps_async_read_complete complete, void *priv) +{ + ar->pages = buf; + ar->rb = 0; + ar->goal = sizeof(ar->pi) + nr_pages * PAGE_SIZE; + ar->complete = complete; + ar->priv = priv; +} + static int page_server_start_async_read(void *buf, int nr_pages, ps_async_read_complete complete, void *priv) { @@ -1078,12 +1088,7 @@ static int page_server_start_async_read(void *buf, int nr_pages, if (ar == NULL) return -1; - ar->pages = buf; - ar->rb = 0; - ar->goal = sizeof(ar->pi) + nr_pages * PAGE_SIZE; - ar->complete = complete; - ar->priv = priv; - + init_ps_async_read(ar, buf, nr_pages, complete, priv); list_add_tail(&ar->l, &async_reads); return 0; } @@ -1097,15 +1102,11 @@ static int page_server_start_async_read(void *buf, int nr_pages, * for sure the next time socket event will occur we'll get page data * related to info we've just received */ -static int page_server_async_read(struct epoll_rfd *f) +static int page_server_read(struct ps_async_read *ar, int flags) { - struct ps_async_read *ar; int ret, need; void *buf; - BUG_ON(list_empty(&async_reads)); - ar = list_first_entry(&async_reads, struct ps_async_read, l); - if (ar->rb < sizeof(ar->pi)) { /* Header */ buf = ((void *)&ar->pi) + ar->rb; @@ -1116,7 +1117,7 @@ static int page_server_async_read(struct epoll_rfd *f) need = ar->goal - ar->rb; } - ret = recv(page_server_sk, buf, need, MSG_DONTWAIT); + ret = recv(page_server_sk, buf, need, flags); if (ret < 0) { pr_perror("Error reading async data from page server"); return -1; @@ -1124,17 +1125,31 @@ static int page_server_async_read(struct epoll_rfd *f) ar->rb += ret; if (ar->rb < ar->goal) - return 0; + return 1; /* * IO complete -- notify the caller and drop the request */ BUG_ON(ar->rb > ar->goal); - ret = ar->complete((int)ar->pi.dst_id, (unsigned long)ar->pi.vaddr, + return ar->complete((int)ar->pi.dst_id, (unsigned long)ar->pi.vaddr, (int)ar->pi.nr_pages, ar->priv); +} - list_del(&ar->l); - xfree(ar); +static int page_server_async_read(struct epoll_rfd *f) +{ + struct ps_async_read *ar; + int ret; + + BUG_ON(list_empty(&async_reads)); + ar = list_first_entry(&async_reads, struct ps_async_read, l); + ret = page_server_read(ar, MSG_DONTWAIT); + + if (ret > 0) + return 0; + if (!ret) { + list_del(&ar->l); + xfree(ar); + } return ret; } From c8717da44cad4942f2f1e17e7d32010bbd111ee9 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 14 Jun 2017 13:15:42 +0300 Subject: [PATCH 0913/4375] page-server: Make sync-read re-use the async reading code Now we have two separate recv-calling routines, that receive header and pages from page-server. These two can finally be unified. After this the sync-read code looks like -- start async one and wait for it to finish right at once. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 51 +++++------------------------------------------- 1 file changed, 5 insertions(+), 46 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index c9f55c9e4..e653623bd 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -1186,56 +1186,15 @@ int request_remote_pages(int pid, unsigned long addr, int nr_pages) return 0; } -static int receive_remote_pages_info(int *nr_pages, unsigned long *addr, int *pid) -{ - struct page_server_iov pi; - - if (recv(page_server_sk, &pi, sizeof(pi), MSG_WAITALL) != sizeof(pi)) { - pr_perror("Failed to receive page metadata"); - return -1; - } - - if (pi.cmd == PS_IOV_ZERO) - pr_warn("Unexpected ZERO page received for %d.%lx\n", - (int)pi.dst_id, (unsigned long)pi.vaddr); - - *nr_pages = pi.nr_pages; - *addr = pi.vaddr; - *pid = pi.dst_id; - - return 0; -} - -static int receive_remote_pages(int len, void *buf) -{ - if (recv(page_server_sk, buf, len, MSG_WAITALL) != len) { - pr_perror("Failed to receive page data"); - return -1; - } - - return 0; -} - static int page_server_start_sync_read(void *buf, int nr, ps_async_read_complete complete, void *priv) { - int ret, pid, new_nr; - unsigned long vaddr; - - /* - * Note, that for async remote page_read, the actual - * transfer happens in the lazy-pages daemon - */ - ret = receive_remote_pages_info(&new_nr, &vaddr, &pid); - if (ret == 0) { - if (new_nr < 0 || new_nr > nr) - return -1; - ret = receive_remote_pages(nr * PAGE_SIZE, buf); - } - - if (ret == 0) - ret = complete(pid, vaddr, nr, priv); + struct ps_async_read ar; + int ret = 1; + init_ps_async_read(&ar, buf, nr, complete, priv); + while (ret == 1) + ret = page_server_read(&ar, MSG_WAITALL); return ret; } From 9f61de87768b33d9b187ef71a57262a17276ff3b Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 28 Jun 2017 09:43:24 +0300 Subject: [PATCH 0914/4375] proc_parse: make smaps parsing helpers globally available The is_vma_range_fmt and parse_vmflags will be required for detection of availability of PR_SET_THP_DISABLE prctl Acked-by: Pavel Emelyanov Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/include/proc_parse.h | 3 ++ criu/proc_parse.c | 75 +++++++++++++++++++++++---------------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h index 5538757f9..c787cc86b 100644 --- a/criu/include/proc_parse.h +++ b/criu/include/proc_parse.h @@ -105,4 +105,7 @@ extern int parse_threads(int pid, struct pid **_t, int *_n); int parse_children(pid_t pid, pid_t **_c, int *_n); +extern bool is_vma_range_fmt(char *line); +extern void parse_vmflags(char *buf, u32 *flags, u64 *madv, int *io_pf); + #endif /* __CR_PROC_PARSE_H__ */ diff --git a/criu/proc_parse.c b/criu/proc_parse.c index ed313fc92..2d8197aa3 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -77,7 +77,7 @@ static char *buf = __buf.buf; #define AIO_FNAME "/[aio]" /* check the @line starts with "%lx-%lx" format */ -static bool is_vma_range_fmt(char *line) +static bool __is_vma_range_fmt(char *line) { #define ____is_vma_addr_char(__c) \ (((__c) <= '9' && (__c) >= '0') || \ @@ -99,55 +99,54 @@ static bool is_vma_range_fmt(char *line) #undef ____is_vma_addr_char } -static int parse_vmflags(char *buf, struct vma_area *vma_area) +bool is_vma_range_fmt(char *line) +{ + return __is_vma_range_fmt(line); +} + +static void __parse_vmflags(char *buf, u32 *flags, u64 *madv, int *io_pf) { char *tok; if (!buf[0]) - return 0; + return; tok = strtok(buf, " \n"); if (!tok) - return 0; + return; #define _vmflag_match(_t, _s) (_t[0] == _s[0] && _t[1] == _s[1]) do { /* mmap() block */ if (_vmflag_match(tok, "gd")) - vma_area->e->flags |= MAP_GROWSDOWN; + *flags |= MAP_GROWSDOWN; else if (_vmflag_match(tok, "lo")) - vma_area->e->flags |= MAP_LOCKED; + *flags |= MAP_LOCKED; else if (_vmflag_match(tok, "nr")) - vma_area->e->flags |= MAP_NORESERVE; + *flags |= MAP_NORESERVE; else if (_vmflag_match(tok, "ht")) - vma_area->e->flags |= MAP_HUGETLB; + *flags |= MAP_HUGETLB; /* madvise() block */ if (_vmflag_match(tok, "sr")) - vma_area->e->madv |= (1ul << MADV_SEQUENTIAL); + *madv |= (1ul << MADV_SEQUENTIAL); else if (_vmflag_match(tok, "rr")) - vma_area->e->madv |= (1ul << MADV_RANDOM); + *madv |= (1ul << MADV_RANDOM); else if (_vmflag_match(tok, "dc")) - vma_area->e->madv |= (1ul << MADV_DONTFORK); + *madv |= (1ul << MADV_DONTFORK); else if (_vmflag_match(tok, "dd")) - vma_area->e->madv |= (1ul << MADV_DONTDUMP); + *madv |= (1ul << MADV_DONTDUMP); else if (_vmflag_match(tok, "mg")) - vma_area->e->madv |= (1ul << MADV_MERGEABLE); + *madv |= (1ul << MADV_MERGEABLE); else if (_vmflag_match(tok, "hg")) - vma_area->e->madv |= (1ul << MADV_HUGEPAGE); + *madv |= (1ul << MADV_HUGEPAGE); else if (_vmflag_match(tok, "nh")) - vma_area->e->madv |= (1ul << MADV_NOHUGEPAGE); + *madv |= (1ul << MADV_NOHUGEPAGE); /* vmsplice doesn't work for VM_IO and VM_PFNMAP mappings. */ - if (_vmflag_match(tok, "io") || _vmflag_match(tok, "pf")) { - /* - * VVAR area mapped by the kernel as - * VM_IO | VM_PFNMAP| VM_DONTEXPAND | VM_DONTDUMP - */ - if (!vma_area_is(vma_area, VMA_AREA_VVAR)) - vma_area->e->status |= VMA_UNSUPP; - } + if (_vmflag_match(tok, "io") || _vmflag_match(tok, "pf")) + *io_pf = 1; /* * Anything else is just ignored. @@ -155,11 +154,29 @@ static int parse_vmflags(char *buf, struct vma_area *vma_area) } while ((tok = strtok(NULL, " \n"))); #undef _vmflag_match +} + +void parse_vmflags(char *buf, u32 *flags, u64 *madv, int *io_pf) +{ + __parse_vmflags(buf, flags, madv, io_pf); +} + +static void parse_vma_vmflags(char *buf, struct vma_area *vma_area) +{ + int io_pf = 0; + + __parse_vmflags(buf, &vma_area->e->flags, &vma_area->e->madv, &io_pf); + + /* + * vmsplice doesn't work for VM_IO and VM_PFNMAP mappings, the + * only exception is VVAR area that mapped by the kernel as + * VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP + */ + if (io_pf && !vma_area_is(vma_area, VMA_AREA_VVAR)) + vma_area->e->status |= VMA_UNSUPP; if (vma_area->e->madv) vma_area->e->has_madv = true; - - return 0; } static inline int is_anon_shmem_map(dev_t dev) @@ -722,7 +739,7 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, goto err; eof = (str == NULL); - if (!eof && !is_vma_range_fmt(str)) { + if (!eof && !__is_vma_range_fmt(str)) { if (!strncmp(str, "Nonlinear", 9)) { BUG_ON(!vma_area); pr_err("Nonlinear mapping found %016"PRIx64"-%016"PRIx64"\n", @@ -735,8 +752,7 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, goto err; } else if (!strncmp(str, "VmFlags: ", 9)) { BUG_ON(!vma_area); - if (parse_vmflags(&str[9], vma_area)) - goto err; + parse_vma_vmflags(&str[9], vma_area); continue; } else continue; @@ -2491,7 +2507,7 @@ int collect_controllers(struct list_head *cgroups, unsigned int *n_cgroups) nc->controllers[nc->n_controllers-1] = n; } - + skip: if (!off) break; @@ -2598,4 +2614,3 @@ err: xfree(ch); return -1; } - From 5480a2a4068349c911fd78b9a45850b4b8a5596e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 28 Jun 2017 09:43:25 +0300 Subject: [PATCH 0915/4375] kerndat: add test for availability of PR_SET_THP_DISABLE prctl The PR_SET_THP_DISABLE prctl allows control of transparent huge pages on per-process basis. It is available since Linux 3.15, but until recently it set VM_NOHUGEPAGE for all VMAs created after prctl() call, which prevents proper restore for combination of pre- and post-copy. A recent change to prctl(PR_SET_THP_DISABLE) behavior eliminates the use of per-VMA flags and we can use the new version of the prctl() to disable THP. Acked-by: Pavel Emelyanov Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/include/kerndat.h | 1 + criu/include/prctl.h | 8 +++++ criu/kerndat.c | 73 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 9a50563ca..946e81a9a 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -51,6 +51,7 @@ struct kerndat_s { int lsm; bool has_uffd; unsigned long uffd_features; + bool has_thp_disable; }; extern struct kerndat_s kdat; diff --git a/criu/include/prctl.h b/criu/include/prctl.h index 79c3bd897..8e7fef317 100644 --- a/criu/include/prctl.h +++ b/criu/include/prctl.h @@ -74,4 +74,12 @@ struct prctl_mm_map { # define PR_GET_TID_ADDRESS 40 #endif +#ifndef PR_SET_THP_DISABLE +# define PR_SET_THP_DISABLE 41 +#endif + +#ifndef PR_GET_THP_DISABLE +# define PR_GET_THP_DISABLE 42 +#endif + #endif /* __CR_PRCTL_H__ */ diff --git a/criu/kerndat.c b/criu/kerndat.c index 4587ed032..156b5b630 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -12,6 +12,7 @@ #include #include #include /* for sockaddr_in and inet_ntoa() */ +#include #include "int.h" #include "log.h" @@ -31,6 +32,7 @@ #include #include "netfilter.h" #include "linux/userfaultfd.h" +#include "prctl.h" struct kerndat_s kdat = { }; @@ -755,6 +757,75 @@ int kerndat_uffd(void) return 0; } +int kerndat_has_thp_disable(void) +{ + struct bfd f; + void *addr; + char *str; + int ret = -1; + bool vma_match = false; + + if (prctl(PR_SET_THP_DISABLE, 1, 0, 0, 0)) { + if (errno != EINVAL) + return -1; + pr_info("PR_SET_THP_DISABLE is not available\n"); + return 0; + } + + addr = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + if (addr == MAP_FAILED) { + pr_perror("Can't mmap memory for THP disable test"); + return -1; + } + + if (prctl(PR_SET_THP_DISABLE, 0, 0, 0, 0)) + return -1; + + f.fd = open("/proc/self/smaps", O_RDONLY); + if (f.fd < 0) { + pr_perror("Can't open /proc/self/smaps"); + goto out; + } + if (bfdopenr(&f)) + goto out; + + while ((str = breadline(&f)) != NULL) { + if (IS_ERR(str)) + goto out; + + if (is_vma_range_fmt(str)) { + unsigned long vma_addr; + + if (sscanf(str, "%lx-", &vma_addr) != 1) { + pr_err("Can't parse: %s\n", str); + goto out; + } + + if (vma_addr == (unsigned long)addr) + vma_match = true; + } + + if (vma_match && !strncmp(str, "VmFlags: ", 9)) { + u32 flags = 0; + u64 madv = 0; + int io_pf = 0; + + parse_vmflags(str, &flags, &madv, &io_pf); + kdat.has_thp_disable = !(madv & (1 << MADV_NOHUGEPAGE)); + break; + } + } + + ret = 0; + +out: + bclose(&f); + munmap(addr, PAGE_SIZE); + + return ret; +} + int kerndat_init(void) { int ret; @@ -795,6 +866,8 @@ int kerndat_init(void) ret = kerndat_detect_stack_guard_gap(); if (!ret) ret = kerndat_uffd(); + if (!ret) + ret = kerndat_has_thp_disable(); kerndat_lsm(); kerndat_mmap_min_addr(); From bbbd597b4124f1a391d61d246cd1aa3083571997 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 28 Jun 2017 09:43:26 +0300 Subject: [PATCH 0916/4375] mem: add dump state of THP_DISABLED prctl Acked-by: Pavel Emelyanov Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 3 +++ criu/include/parasite.h | 1 + criu/pie/parasite.c | 1 + images/mm.proto | 1 + 4 files changed, 6 insertions(+) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 2a5595c97..0e297acb7 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -515,6 +515,9 @@ static int dump_task_mm(pid_t pid, const struct proc_pid_stat *stat, mme.dumpable = misc->dumpable; mme.has_dumpable = true; + mme.thp_disabled = misc->thp_disabled; + mme.has_thp_disabled = true; + mme.n_mm_saved_auxv = AT_VECTOR_SIZE; mme.mm_saved_auxv = xmalloc(pb_repeated_size(&mme, mm_saved_auxv)); if (!mme.mm_saved_auxv) diff --git a/criu/include/parasite.h b/criu/include/parasite.h index cd6d793f8..115891f3b 100644 --- a/criu/include/parasite.h +++ b/criu/include/parasite.h @@ -124,6 +124,7 @@ struct parasite_dump_misc { u32 umask; int dumpable; + int thp_disabled; }; /* diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index fe08e7252..78bbe9e3b 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -177,6 +177,7 @@ static int dump_misc(struct parasite_dump_misc *args) args->umask = sys_umask(0); sys_umask(args->umask); /* never fails */ args->dumpable = sys_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0); + args->thp_disabled = sys_prctl(PR_GET_THP_DISABLE, 0, 0, 0, 0); return 0; } diff --git a/images/mm.proto b/images/mm.proto index b372f45ff..e0f14c62f 100644 --- a/images/mm.proto +++ b/images/mm.proto @@ -29,4 +29,5 @@ message mm_entry { optional int32 dumpable = 15; repeated aio_ring_entry aios = 16; + optional bool thp_disabled = 17; } From 9d45bb39875b7cd647a96be9f49d4aeda5550c02 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 28 Jun 2017 09:43:27 +0300 Subject: [PATCH 0917/4375] lazy-pages: fix memory corruption when combining pre-dump with lazy pages When we combine pre-dump with lazy pages, we populate a part of a memory region with data that was saved during the pre-dump. Afterwards, the region is registered with userfaultfd and we expect to get page faults for the parts of the region that were not yet populated. However, khugepaged collapses the pages and the page faults we would expect do not occur. To mitigate this problem we temporarily disable THP for the restored process, up to the point when we register all the memory regions with userfaultfd. https://lists.openvz.org/pipermail/criu/2017-May/037728.html Reported-by: Adrian Reber Acked-by: Pavel Emelyanov Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 3 +++ criu/include/pagemap.h | 5 +++++ criu/include/restorer.h | 1 + criu/include/rst_info.h | 2 ++ criu/mem.c | 38 +++++++++++++++++++++++++++++++++++++- criu/pie/restorer.c | 8 ++++++++ 6 files changed, 56 insertions(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index fc27dd4fa..bbe0bc670 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2555,6 +2555,9 @@ static int prepare_mm(pid_t pid, struct task_restore_args *args) goto out; args->fd_exe_link = exe_fd; + + args->has_thp_enabled = rsti(current)->has_thp_enabled; + ret = 0; out: return ret; diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index d0a28b9f1..800768308 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -127,6 +127,11 @@ static inline unsigned long pagemap_len(PagemapEntry *pe) return pe->nr_pages * PAGE_SIZE; } +static inline bool page_read_has_parent(struct page_read *pr) +{ + return pr->parent != NULL; +} + /* Pagemap flags */ #define PE_PARENT (1 << 0) /* pages are in parent snapshot */ #define PE_LAZY (1 << 1) /* pages can be lazily restored */ diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 57b53e849..cad8cdf7b 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -118,6 +118,7 @@ struct task_restore_args { struct timeval logstart; int uffd; + bool has_thp_enabled; /* threads restoration */ int nr_threads; /* number of threads */ diff --git a/criu/include/rst_info.h b/criu/include/rst_info.h index c3dbe2dd3..336c08b6b 100644 --- a/criu/include/rst_info.h +++ b/criu/include/rst_info.h @@ -61,6 +61,8 @@ struct rst_info { */ bool has_seccomp; + bool has_thp_enabled; + void *breakpoint; }; diff --git a/criu/mem.c b/criu/mem.c index a6ef995db..dbeffe12b 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "types.h" #include "cr_options.h" @@ -27,6 +28,7 @@ #include "files-reg.h" #include "pagemap-cache.h" #include "fault-injection.h" +#include "prctl.h" #include #include "protobuf.h" @@ -1036,6 +1038,38 @@ err_addr: return -1; } +static int maybe_disable_thp(struct pstree_item *t, struct page_read *pr) +{ + struct _MmEntry *mm = rsti(t)->mm; + + /* + * There is no need to disable it if the page read doesn't + * have parent. In this case VMA will be empty until + * userfaultfd_register, so there would be no pages to + * collapse. And, once we register the VMA with uffd, + * khugepaged will skip it. + */ + if (!(opts.lazy_pages && page_read_has_parent(pr))) + return 0; + + if (!kdat.has_thp_disable) + pr_warn("Disabling transparent huge pages. " + "It may affect performance!\n"); + + /* + * temporarily disable THP to avoid collapse of pages + * in the areas that will be monitored by uffd + */ + if (prctl(PR_SET_THP_DISABLE, 1, 0, 0, 0)) { + pr_perror("Cannot disable THP"); + return -1; + } + if (!(mm->has_thp_disabled && mm->thp_disabled)) + rsti(t)->has_thp_enabled = true; + + return 0; +} + int prepare_mappings(struct pstree_item *t) { int ret = 0; @@ -1067,6 +1101,9 @@ int prepare_mappings(struct pstree_item *t) if (ret <= 0) return -1; + if (maybe_disable_thp(t, &pr)) + return -1; + pr.advance(&pr); /* shift to the 1st iovec */ ret = premap_priv_vmas(t, vmas, &addr, &pr); @@ -1216,4 +1253,3 @@ int prepare_vmas(struct pstree_item *t, struct task_restore_args *ta) return prepare_vma_ios(t, ta); } - diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index d478aa5bd..6e19ca356 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1244,6 +1244,14 @@ long __export_restore_task(struct task_restore_args *args) } if (args->uffd > -1) { + /* re-enable THP if we disabled it previously */ + if (args->has_thp_enabled) { + if (sys_prctl(PR_SET_THP_DISABLE, 0, 0, 0, 0)) { + pr_err("Cannot re-enable THP\n"); + goto core_restore_end; + } + } + pr_debug("lazy-pages: closing uffd %d\n", args->uffd); /* * All userfaultfd configuration has finished at this point. From b1aca099ccdb28585c39d3b55bf51886b3611cc7 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 28 Jun 2017 09:43:28 +0300 Subject: [PATCH 0918/4375] test: add test that verifies proper intraction between lazy-pages and THP Acked-by: Pavel Emelyanov Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm/transition/Makefile | 1 + test/zdtm/transition/lazy-thp.c | 61 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 test/zdtm/transition/lazy-thp.c diff --git a/test/zdtm/transition/Makefile b/test/zdtm/transition/Makefile index cd9892159..f482a8a09 100644 --- a/test/zdtm/transition/Makefile +++ b/test/zdtm/transition/Makefile @@ -20,6 +20,7 @@ TST_NOFILE = \ socket-tcp \ socket-tcp6 \ shmem \ + lazy-thp \ TST_FILE = \ diff --git a/test/zdtm/transition/lazy-thp.c b/test/zdtm/transition/lazy-thp.c new file mode 100644 index 000000000..f7af41446 --- /dev/null +++ b/test/zdtm/transition/lazy-thp.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "zdtmtst.h" + +#define N_PAGES 1024 + +const char *test_doc = "Test interaction between THP and lazy-pages"; + +/* The test is based on example by Adrian Reber */ +const char *test_author = "Mike Rapoport "; + +int main(int argc, char ** argv) +{ + char *mem, *org, *m; + int count; + + test_init(argc, argv); + + /* we presume that malloc returns not page aliged address */ + mem = malloc(PAGE_SIZE * N_PAGES); + org = malloc(PAGE_SIZE); + if (!mem || !org) { + fail("malloc failed\n"); + exit(1); + } + + memset(mem, 0x42, PAGE_SIZE * N_PAGES); + memset(org, 0x42, PAGE_SIZE); + + test_daemon(); + while (test_go()) { + for (count = 0; count < N_PAGES; count += 2) { + m = mem + (count * PAGE_SIZE) + 128; + *m = count; + } + + for (count = 0; count < N_PAGES; count++) { + m = mem+(count*PAGE_SIZE); + org[128] = (count % 2 == 0) ? count : 0x42; + + if (memcmp(org, m, PAGE_SIZE)) { + fail("memory corruption\n"); + return 1; + } + } + + sleep(1); + } + + pass(); + return 0; +} From a33b747f7d593a9db48d8bfc060f3ef61918e094 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 6 Jul 2017 10:19:23 +0300 Subject: [PATCH 0919/4375] lazy-pages: fix off-by-one in remap_lazy_iovs When the remap 'from' parameter matches an IOV end we try to split that IOV exactly at its end and effectively create an IOV with zero length. With the off-by-one fix we will skip the IOV in such case as expected. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index d631f4b25..703dc4362 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -481,7 +481,7 @@ static int remap_lazy_iovs(struct lazy_pages_info *lpi, unsigned long from, list_for_each_entry_safe(iov, n, &lpi->iovs, l) { unsigned long iov_end = iov->base + iov->len; - if (from > iov_end) + if (from >= iov_end) continue; if (len <= 0 || from + len < iov->base) From f9510f67e938de6c5d9061bf13a75bfc9f65e85e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 6 Jul 2017 12:39:16 +0300 Subject: [PATCH 0920/4375] pagemap: Remove seek_pagemap_page The page_read.seek_pagemap already tunes the pages offset, so the separate call for skip_pagemap_pages in the routine in question is always no-op. Acked-by: Mike Rapoport Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pagemap.c | 18 +++--------------- criu/uffd.c | 4 +--- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/criu/pagemap.c b/criu/pagemap.c index ef13220e7..e30d9e08d 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -74,8 +74,6 @@ static int punch_hole(struct page_read *pr, unsigned long off, return 0; } -static int seek_pagemap_page(struct page_read *pr, unsigned long vaddr); - int dedup_one_iovec(struct page_read *pr, unsigned long off, unsigned long len) { unsigned long iov_end; @@ -86,7 +84,7 @@ int dedup_one_iovec(struct page_read *pr, unsigned long off, unsigned long len) unsigned long piov_end; struct page_read * prp; - ret = seek_pagemap_page(pr, off); + ret = pr->seek_pagemap(pr, off); if (ret == 0) { pr_warn("Missing %lx in parent pagemap\n", off); if (off < pr->cvaddr && pr->cvaddr < iov_end) @@ -159,7 +157,7 @@ static int seek_pagemap(struct page_read *pr, unsigned long vaddr) break; if (vaddr >= start && vaddr < end) { - skip_pagemap_pages(pr, start - pr->cvaddr); + skip_pagemap_pages(pr, vaddr - pr->cvaddr); return 1; } @@ -172,16 +170,6 @@ adv: return 0; } -static int seek_pagemap_page(struct page_read *pr, unsigned long vaddr) -{ - if (seek_pagemap(pr, vaddr)) { - skip_pagemap_pages(pr, vaddr - pr->cvaddr); - return 1; - } - - return 0; -} - static inline void pagemap_bound_check(PagemapEntry *pe, unsigned long vaddr, int nr) { if (vaddr < pe->vaddr || (vaddr - pe->vaddr) / PAGE_SIZE + nr > pe->nr_pages) { @@ -214,7 +202,7 @@ static int read_parent_page(struct page_read *pr, unsigned long vaddr, int p_nr; pr_debug("\tpr%d-%u Read from parent\n", pr->pid, pr->id); - ret = seek_pagemap_page(ppr, vaddr); + ret = ppr->seek_pagemap(ppr, vaddr); if (ret <= 0) { pr_err("Missing %lx in parent pagemap\n", vaddr); return -1; diff --git a/criu/uffd.c b/criu/uffd.c index 703dc4362..a94eaaa13 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -787,11 +787,9 @@ static int uffd_seek_pages(struct lazy_pages_info *lpi, __u64 address, int nr) ret = lpi->pr.seek_pagemap(&lpi->pr, address); if (!ret) { lp_err(lpi, "no pagemap covers %llx\n", address); - return ret; + return -1; } - lpi->pr.skip_pages(&lpi->pr, address - lpi->pr.pe->vaddr); - return 0; } From 3c62260789d242541047e49249379900565aab88 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 6 Jul 2017 12:39:34 +0300 Subject: [PATCH 0921/4375] page-xfer: Fixup page server protocol for lazy pages Introduce the PS_IOV_ADD_F command that is to add pages with flags. We already use the similar notation on page-xfer -- the single write callback with pagemap and flags. For page-server let's use the same. Legacy _HOLE and _PAGE handling is kept. Changed commands numbers are OK, as the commands in question are still in criu-dev branch. Acked-by: Mike Rapoport Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index e653623bd..b05ba49ec 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -41,9 +41,8 @@ static void psi2iovec(struct page_server_iov *ps, struct iovec *iov) #define PS_IOV_OPEN 3 #define PS_IOV_OPEN2 4 #define PS_IOV_PARENT 5 -#define PS_IOV_ZERO 6 -#define PS_IOV_LAZY 7 -#define PS_IOV_GET 8 +#define PS_IOV_ADD_F 6 +#define PS_IOV_GET 7 #define PS_IOV_FLUSH 0x1023 #define PS_IOV_FLUSH_N_CLOSE 0x1024 @@ -161,18 +160,7 @@ static int write_pages_to_server(struct page_xfer *xfer, static int write_pagemap_to_server(struct page_xfer *xfer, struct iovec *iov, u32 flags) { - u32 cmd = 0; - - if (flags & PE_PRESENT) - cmd = encode_ps_cmd(PS_IOV_ADD, flags); - else if (flags & PE_PARENT) - cmd = PS_IOV_HOLE; - else if (flags & PE_LAZY) - cmd = PS_IOV_LAZY; - else - BUG(); - - return send_psi(xfer->sk, cmd, + return send_psi(xfer->sk, encode_ps_cmd(PS_IOV_ADD_F, flags), iov->iov_len / PAGE_SIZE, encode_pointer(iov->iov_base), xfer->dst_id); } @@ -711,12 +699,13 @@ static int page_server_get_pages(int sk, struct page_server_iov *pi) if (pi->nr_pages == 0) { /* no iovs found means we've hit a zero page */ pr_debug("no iovs found, zero pages\n"); - return send_psi(sk, PS_IOV_ZERO, 0, 0, 0); + return send_psi(sk, encode_ps_cmd(PS_IOV_ADD_F, 0), 0, 0, 0); } len = pi->nr_pages * PAGE_SIZE; - if (send_psi(sk, PS_IOV_ADD, pi->nr_pages, pi->vaddr, pi->dst_id)) + if (send_psi(sk, encode_ps_cmd(PS_IOV_ADD_F, PE_PRESENT), + pi->nr_pages, pi->vaddr, pi->dst_id)) return -1; ret = splice(pipe_read_dest.p[0], NULL, sk, NULL, len, SPLICE_F_MOVE); @@ -782,15 +771,22 @@ static int page_server_serve(int sk) case PS_IOV_PARENT: ret = page_server_check_parent(sk, &pi); break; + case PS_IOV_ADD_F: case PS_IOV_ADD: - ret = page_server_add(sk, &pi, PE_PRESENT | decode_ps_flags(pi.cmd)); - break; case PS_IOV_HOLE: - ret = page_server_add(sk, &pi, PE_PARENT); - break; - case PS_IOV_LAZY: - ret = page_server_add(sk, &pi, PE_LAZY); + { + u32 flags; + + if (likely(cmd == PS_IOV_ADD_F)) + flags = decode_ps_flags(pi.cmd); + else if (cmd == PS_IOV_ADD) + flags = PE_PRESENT; + else /* PS_IOV_HOLE */ + flags = PE_PARENT; + + ret = page_server_add(sk, &pi, flags); break; + } case PS_IOV_FLUSH: case PS_IOV_FLUSH_N_CLOSE: { From 4fd66c9d9ec55014c94b0a6f934adcef3eb8d6d7 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 6 Jul 2017 12:39:52 +0300 Subject: [PATCH 0922/4375] page-xfer: Tune up send_psi to accept less args The only thing it does is puts 4 values on the on-stack ps_iov, let's avoid double stack copying and put the values on ps_iov in callers. Acked-by: Mike Rapoport Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index b05ba49ec..e4d9a15c6 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -127,17 +127,10 @@ static inline u32 decode_ps_flags(u32 cmd) return cmd >> PS_CMD_BITS; } -static inline int send_psi(int sk, u32 cmd, u32 nr_pages, u64 vaddr, u64 dst_id) +static inline int send_psi(int sk, struct page_server_iov *pi) { - struct page_server_iov pi = { - .cmd = cmd, - .nr_pages = nr_pages, - .vaddr = vaddr, - .dst_id = dst_id, - }; - - if (write(sk, &pi, sizeof(pi)) != sizeof(pi)) { - pr_perror("Can't write PSI %d to server", cmd); + if (write(sk, pi, sizeof(*pi)) != sizeof(*pi)) { + pr_perror("Can't write PSI %d to server", pi->cmd); return -1; } @@ -160,9 +153,14 @@ static int write_pages_to_server(struct page_xfer *xfer, static int write_pagemap_to_server(struct page_xfer *xfer, struct iovec *iov, u32 flags) { - return send_psi(xfer->sk, encode_ps_cmd(PS_IOV_ADD_F, flags), - iov->iov_len / PAGE_SIZE, encode_pointer(iov->iov_base), - xfer->dst_id); + struct page_server_iov pi = { + .cmd = encode_ps_cmd(PS_IOV_ADD_F, flags), + .nr_pages = iov->iov_len / PAGE_SIZE, + .vaddr = encode_pointer(iov->iov_base), + .dst_id = xfer->dst_id, + }; + + return send_psi(xfer->sk, &pi); } static void close_server_xfer(struct page_xfer *xfer) @@ -173,6 +171,9 @@ static void close_server_xfer(struct page_xfer *xfer) static int open_page_server_xfer(struct page_xfer *xfer, int fd_type, long id) { char has_parent; + struct page_server_iov pi = { + .cmd = PS_IOV_OPEN2, + }; xfer->sk = page_server_sk; xfer->write_pagemap = write_pagemap_to_server; @@ -181,7 +182,8 @@ static int open_page_server_xfer(struct page_xfer *xfer, int fd_type, long id) xfer->dst_id = encode_pm(fd_type, id); xfer->parent = NULL; - if (send_psi(xfer->sk, PS_IOV_OPEN2, 0, 0, xfer->dst_id)) { + pi.dst_id = xfer->dst_id; + if (send_psi(xfer->sk, &pi)) { pr_perror("Can't write to page server"); return -1; } @@ -696,18 +698,23 @@ static int page_server_get_pages(int sk, struct page_server_iov *pi) if (ret) return ret; + /* + * The pi is reused for send_psi here, so .nr_pages, .vaddr and + * .dst_id all remain intact. + */ + if (pi->nr_pages == 0) { /* no iovs found means we've hit a zero page */ pr_debug("no iovs found, zero pages\n"); - return send_psi(sk, encode_ps_cmd(PS_IOV_ADD_F, 0), 0, 0, 0); + pi->cmd = encode_ps_cmd(PS_IOV_ADD_F, 0); + return send_psi(sk, pi); } - len = pi->nr_pages * PAGE_SIZE; - - if (send_psi(sk, encode_ps_cmd(PS_IOV_ADD_F, PE_PRESENT), - pi->nr_pages, pi->vaddr, pi->dst_id)) + pi->cmd = encode_ps_cmd(PS_IOV_ADD_F, PE_PRESENT); + if (send_psi(sk, pi)) return -1; + len = pi->nr_pages * PAGE_SIZE; ret = splice(pipe_read_dest.p[0], NULL, sk, NULL, len, SPLICE_F_MOVE); if (ret != len) return -1; From f83ba3fe31cb7712e2c336b2d97c3cb094074f5d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 6 Jul 2017 12:40:07 +0300 Subject: [PATCH 0923/4375] page-xfer: Rework send_psi to use send (and flags) There are cases when we need to specify flags with which to send the ps_iov, so tune-up the send_psi for that and use where needed. Acked-by: Mike Rapoport Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index e4d9a15c6..32012cc1a 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -127,16 +127,21 @@ static inline u32 decode_ps_flags(u32 cmd) return cmd >> PS_CMD_BITS; } -static inline int send_psi(int sk, struct page_server_iov *pi) +static inline int send_psi_flags(int sk, struct page_server_iov *pi, int flags) { - if (write(sk, pi, sizeof(*pi)) != sizeof(*pi)) { - pr_perror("Can't write PSI %d to server", pi->cmd); + if (send(sk, pi, sizeof(*pi), flags) != sizeof(*pi)) { + pr_perror("Can't send PSI %d to server", pi->cmd); return -1; } return 0; } +static inline int send_psi(int sk, struct page_server_iov *pi) +{ + return send_psi_flags(sk, pi, 0); +} + /* page-server xfer */ static int write_pages_to_server(struct page_xfer *xfer, int p, unsigned long len) @@ -1179,11 +1184,9 @@ int request_remote_pages(int pid, unsigned long addr, int nr_pages) .dst_id = pid, }; - /* We cannot use send_psi here because we have to use MSG_DONTWAIT */ - if (send(page_server_sk, &pi, sizeof(pi), MSG_DONTWAIT) != sizeof(pi)) { - pr_perror("Can't write PSI to server"); + /* XXX: why MSG_DONTWAIT here? */ + if (send_psi_flags(page_server_sk, &pi, MSG_DONTWAIT)) return -1; - } tcp_nodelay(page_server_sk, true); return 0; From efbf59ddf69085571f7f144f9e80898098596b2b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 6 Jul 2017 12:40:23 +0300 Subject: [PATCH 0924/4375] page-xfer: Use send_psi everywhere There are two places left that send ps_iov by hands into socket. Switch it to use common helper. Acked-by: Mike Rapoport Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 32012cc1a..5d4bf1128 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -538,10 +538,8 @@ static int check_parent_server_xfer(int fd_type, long id) pi.cmd = PS_IOV_PARENT; pi.dst_id = encode_pm(fd_type, id); - if (write(page_server_sk, &pi, sizeof(pi)) != sizeof(pi)) { - pr_perror("Can't write to page server"); + if (send_psi(page_server_sk, &pi)) return -1; - } tcp_nodelay(page_server_sk, true); @@ -1046,10 +1044,8 @@ int disconnect_from_page_server(void) else pi.cmd = PS_IOV_FLUSH; - if (write(page_server_sk, &pi, sizeof(pi)) != sizeof(pi)) { - pr_perror("Can't write the fini command to server"); + if (send_psi(page_server_sk, &pi)) goto out; - } if (read(page_server_sk, &status, sizeof(status)) != sizeof(status)) { pr_perror("The page server doesn't answer"); From 121f07a79f73a1ed0e5faa497073e1886ef1a894 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 6 Jul 2017 12:40:56 +0300 Subject: [PATCH 0925/4375] page-xfer: Move iov offset on xfer The offset in question is used by shmem dumping code to dump memory segments relative to shmem segment start, no to task mapping start. The offset value is now the part of the xfer callback and is typically 0 :) Let's keep this on xfer object to simplify the xfer API. Acked-by: Mike Rapoport Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 2 +- criu/include/page-xfer.h | 9 +++++++-- criu/mem.c | 2 +- criu/page-xfer.c | 22 ++++++++++++---------- criu/shmem.c | 10 ++++++---- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 0e297acb7..cf0ac8093 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1491,7 +1491,7 @@ static int cr_pre_dump_finish(int ret) goto err; mem_pp = dmpi(item)->mem_pp; - ret = page_xfer_dump_pages(&xfer, mem_pp, 0, true); + ret = page_xfer_dump_pages(&xfer, mem_pp, true); xfer.close(&xfer); diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index 2b806c797..00b18d3b4 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -17,6 +17,12 @@ struct page_xfer { int (*write_pages)(struct page_xfer *self, int pipe, unsigned long len); void (*close)(struct page_xfer *self); + /* + * In case we need to dump pagemaps not as-is, but + * relative to some address. Used, e.g. by shmem. + */ + unsigned long offset; + /* private data for every page-xfer engine */ union { struct /* local */ { @@ -35,8 +41,7 @@ struct page_xfer { extern int open_page_xfer(struct page_xfer *xfer, int fd_type, long id); struct page_pipe; -extern int page_xfer_dump_pages(struct page_xfer *, struct page_pipe *, - unsigned long off, bool dump_lazy); +extern int page_xfer_dump_pages(struct page_xfer *, struct page_pipe *, bool dump_lazy); extern int connect_to_page_server_to_send(void); extern int connect_to_page_server_to_recv(int epfd); extern int disconnect_from_page_server(void); diff --git a/criu/mem.c b/criu/mem.c index dbeffe12b..599c3036e 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -284,7 +284,7 @@ static int xfer_pages(struct page_pipe *pp, struct page_xfer *xfer, bool lazy) * pre-dump action (see pre_dump_one_task) */ timing_start(TIME_MEMWRITE); - ret = page_xfer_dump_pages(xfer, pp, 0, !lazy); + ret = page_xfer_dump_pages(xfer, pp, !lazy); timing_stop(TIME_MEMWRITE); return ret; diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 5d4bf1128..737e05fa3 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -378,6 +378,8 @@ out: int open_page_xfer(struct page_xfer *xfer, int fd_type, long id) { + xfer->offset = 0; + if (opts.use_page_server) return open_page_server_xfer(xfer, fd_type, id); else @@ -385,10 +387,10 @@ int open_page_xfer(struct page_xfer *xfer, int fd_type, long id) } static int page_xfer_dump_hole(struct page_xfer *xfer, - struct iovec *hole, unsigned long off, u32 flags) + struct iovec *hole, u32 flags) { - BUG_ON(hole->iov_base < (void *)off); - hole->iov_base -= off; + BUG_ON(hole->iov_base < (void *)xfer->offset); + hole->iov_base -= xfer->offset; pr_debug("\th %p [%u]\n", hole->iov_base, (unsigned int)(hole->iov_len / PAGE_SIZE)); @@ -411,7 +413,7 @@ static int get_hole_flags(struct page_pipe *pp, int n) } static int dump_holes(struct page_xfer *xfer, struct page_pipe *pp, - unsigned int *cur_hole, void *limit, unsigned long off) + unsigned int *cur_hole, void *limit) { int ret; @@ -423,7 +425,7 @@ static int dump_holes(struct page_xfer *xfer, struct page_pipe *pp, break; hole_flags = get_hole_flags(pp, *cur_hole); - ret = page_xfer_dump_hole(xfer, &hole, off, hole_flags); + ret = page_xfer_dump_hole(xfer, &hole, hole_flags); if (ret) return ret; } @@ -432,7 +434,7 @@ static int dump_holes(struct page_xfer *xfer, struct page_pipe *pp, } int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, - unsigned long off, bool dump_lazy) + bool dump_lazy) { struct page_pipe_buf *ppb; unsigned int cur_hole = 0; @@ -449,12 +451,12 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, struct iovec iov = ppb->iov[i]; u32 flags = PE_PRESENT; - ret = dump_holes(xfer, pp, &cur_hole, iov.iov_base, off); + ret = dump_holes(xfer, pp, &cur_hole, iov.iov_base); if (ret) return ret; - BUG_ON(iov.iov_base < (void *)off); - iov.iov_base -= off; + BUG_ON(iov.iov_base < (void *)xfer->offset); + iov.iov_base -= xfer->offset; pr_debug("\tp %p [%u]\n", iov.iov_base, (unsigned int)(iov.iov_len / PAGE_SIZE)); @@ -475,7 +477,7 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, } } - return dump_holes(xfer, pp, &cur_hole, NULL, off); + return dump_holes(xfer, pp, &cur_hole, NULL); } /* diff --git a/criu/shmem.c b/criu/shmem.c index cc5157d6b..7ab396359 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -628,7 +628,7 @@ int add_shmem_area(pid_t pid, VmaEntry *vma, u64 *map) return 0; } -static int dump_pages(struct page_pipe *pp, struct page_xfer *xfer, void *addr) +static int dump_pages(struct page_pipe *pp, struct page_xfer *xfer) { struct page_pipe_buf *ppb; @@ -640,7 +640,7 @@ static int dump_pages(struct page_pipe *pp, struct page_xfer *xfer, void *addr) return -1; } - return page_xfer_dump_pages(xfer, pp, (unsigned long)addr, true); + return page_xfer_dump_pages(xfer, pp, true); } static int next_data_segment(int fd, unsigned long pfn, @@ -687,6 +687,8 @@ static int do_dump_one_shmem(int fd, void *addr, struct shmem_info *si) if (err) goto err_pp; + xfer.offset = (unsigned long)addr; + for (pfn = 0; pfn < nrpages; pfn++) { unsigned int pgstate = PST_DIRTY; bool use_mc = true; @@ -718,7 +720,7 @@ again: ret = page_pipe_add_page(pp, pgaddr, 0); if (ret == -EAGAIN) { - ret = dump_pages(pp, &xfer, addr); + ret = dump_pages(pp, &xfer); if (ret) goto err_xfer; page_pipe_reinit(pp); @@ -727,7 +729,7 @@ again: goto err_xfer; } - ret = dump_pages(pp, &xfer, addr); + ret = dump_pages(pp, &xfer); err_xfer: xfer.close(&xfer); From daf8b4f75c9ea680a48e4b4828384fed7c9681e2 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 6 Jul 2017 12:41:12 +0300 Subject: [PATCH 0926/4375] page-xfer: Move lazy bool on xfer Same thing for the boolean value saying whether or not to send lazy pagemaps alone or follow them with the respective pages. This value is non-true in the single place, so let's simplify the API and keep this bool on xfer object. Acked-by: Mike Rapoport Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 2 +- criu/include/page-xfer.h | 3 ++- criu/mem.c | 10 ++++++---- criu/page-xfer.c | 6 +++--- criu/shmem.c | 2 +- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index cf0ac8093..8fdf85259 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1491,7 +1491,7 @@ static int cr_pre_dump_finish(int ret) goto err; mem_pp = dmpi(item)->mem_pp; - ret = page_xfer_dump_pages(&xfer, mem_pp, true); + ret = page_xfer_dump_pages(&xfer, mem_pp); xfer.close(&xfer); diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index 00b18d3b4..3769be482 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -22,6 +22,7 @@ struct page_xfer { * relative to some address. Used, e.g. by shmem. */ unsigned long offset; + bool transfer_lazy; /* private data for every page-xfer engine */ union { @@ -41,7 +42,7 @@ struct page_xfer { extern int open_page_xfer(struct page_xfer *xfer, int fd_type, long id); struct page_pipe; -extern int page_xfer_dump_pages(struct page_xfer *, struct page_pipe *, bool dump_lazy); +extern int page_xfer_dump_pages(struct page_xfer *, struct page_pipe *); extern int connect_to_page_server_to_send(void); extern int connect_to_page_server_to_recv(int epfd); extern int disconnect_from_page_server(void); diff --git a/criu/mem.c b/criu/mem.c index 599c3036e..f3b2c224d 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -275,7 +275,7 @@ static int drain_pages(struct page_pipe *pp, struct parasite_ctl *ctl, return 0; } -static int xfer_pages(struct page_pipe *pp, struct page_xfer *xfer, bool lazy) +static int xfer_pages(struct page_pipe *pp, struct page_xfer *xfer) { int ret; @@ -284,7 +284,7 @@ static int xfer_pages(struct page_pipe *pp, struct page_xfer *xfer, bool lazy) * pre-dump action (see pre_dump_one_task) */ timing_start(TIME_MEMWRITE); - ret = page_xfer_dump_pages(xfer, pp, !lazy); + ret = page_xfer_dump_pages(xfer, pp); timing_stop(TIME_MEMWRITE); return ret; @@ -346,6 +346,8 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, ret = open_page_xfer(&xfer, CR_FD_PAGEMAP, vpid(item)); if (ret < 0) goto out_pp; + + xfer.transfer_lazy = !mdc->lazy; } else { ret = check_parent_page_xfer(CR_FD_PAGEMAP, vpid(item)); if (ret < 0) @@ -387,7 +389,7 @@ again: ret = drain_pages(pp, ctl, args); if (!ret) - ret = xfer_pages(pp, &xfer, mdc->lazy /* false actually */); + ret = xfer_pages(pp, &xfer); if (!ret) { page_pipe_reinit(pp); goto again; @@ -403,7 +405,7 @@ again: sizeof(struct iovec) * pp->nr_iovs); ret = drain_pages(pp, ctl, args); if (!ret && !mdc->pre_dump) - ret = xfer_pages(pp, &xfer, mdc->lazy); + ret = xfer_pages(pp, &xfer); if (ret) goto out_xfer; diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 737e05fa3..8237e7749 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -379,6 +379,7 @@ out: int open_page_xfer(struct page_xfer *xfer, int fd_type, long id) { xfer->offset = 0; + xfer->transfer_lazy = true; if (opts.use_page_server) return open_page_server_xfer(xfer, fd_type, id); @@ -433,8 +434,7 @@ static int dump_holes(struct page_xfer *xfer, struct page_pipe *pp, return 0; } -int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, - bool dump_lazy) +int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp) { struct page_pipe_buf *ppb; unsigned int cur_hole = 0; @@ -461,7 +461,7 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp, (unsigned int)(iov.iov_len / PAGE_SIZE)); if (ppb->flags & PPB_LAZY) { - if (!dump_lazy) { + if (!xfer->transfer_lazy) { if (xfer->write_pagemap(xfer, &iov, PE_LAZY)) return -1; continue; diff --git a/criu/shmem.c b/criu/shmem.c index 7ab396359..5314cb504 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -640,7 +640,7 @@ static int dump_pages(struct page_pipe *pp, struct page_xfer *xfer) return -1; } - return page_xfer_dump_pages(xfer, pp, true); + return page_xfer_dump_pages(xfer, pp); } static int next_data_segment(int fd, unsigned long pfn, From f2f5fd68dd44ebc07f9d4b5ecebe21f658383f80 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 6 Jul 2017 12:41:28 +0300 Subject: [PATCH 0927/4375] page-xfer: Sanitize xfer core routine Make it call .write_pagemap once and decide whether or not to call .write_pages based on the flags caluculated in one place as well. Acked-by: Mike Rapoport Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 8237e7749..1bf1d1cb9 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -434,6 +434,19 @@ static int dump_holes(struct page_xfer *xfer, struct page_pipe *pp, return 0; } +static inline u32 ppb_xfer_flags(struct page_xfer *xfer, struct page_pipe_buf *ppb) +{ + if (ppb->flags & PPB_LAZY) + /* + * Pages that can be lazily restored are always marked as such. + * In the case we actually transfer them into image mark them + * as present as well. + */ + return (xfer->transfer_lazy ? PE_PRESENT : 0) | PE_LAZY; + else + return PE_PRESENT; +} + int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp) { struct page_pipe_buf *ppb; @@ -449,7 +462,7 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp) for (i = 0; i < ppb->nr_segs; i++) { struct iovec iov = ppb->iov[i]; - u32 flags = PE_PRESENT; + u32 flags; ret = dump_holes(xfer, pp, &cur_hole, iov.iov_base); if (ret) @@ -460,19 +473,12 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp) pr_debug("\tp %p [%u]\n", iov.iov_base, (unsigned int)(iov.iov_len / PAGE_SIZE)); - if (ppb->flags & PPB_LAZY) { - if (!xfer->transfer_lazy) { - if (xfer->write_pagemap(xfer, &iov, PE_LAZY)) - return -1; - continue; - } else { - flags |= PE_LAZY; - } - } + flags = ppb_xfer_flags(xfer, ppb); if (xfer->write_pagemap(xfer, &iov, flags)) return -1; - if (xfer->write_pages(xfer, ppb->p[0], iov.iov_len)) + if ((flags & PE_PRESENT) && xfer->write_pages(xfer, + ppb->p[0], iov.iov_len)) return -1; } } From 71c9a7a9c1e8809f0111bdc20c72058e73c111e6 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 6 Jul 2017 12:41:44 +0300 Subject: [PATCH 0928/4375] page-xfer: Don't send zero pages if none found When page-server gets a request for an absent pagemap from lazy-pages daemon, it should not reply with "zero pages"'. The pagemap should be completely in sync between src and dst and dst should never request pages that are not present. Maybe we should return -1 here? At least we'll have a chance that dump will unroll everything... Acked-by: Mike Rapoport Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 1bf1d1cb9..4b848ca20 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -715,10 +715,8 @@ static int page_server_get_pages(int sk, struct page_server_iov *pi) */ if (pi->nr_pages == 0) { - /* no iovs found means we've hit a zero page */ pr_debug("no iovs found, zero pages\n"); - pi->cmd = encode_ps_cmd(PS_IOV_ADD_F, 0); - return send_psi(sk, pi); + return -1; } pi->cmd = encode_ps_cmd(PS_IOV_ADD_F, PE_PRESENT); From 1a34089773328c6008ea79aa18889095440dbd6b Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 13 Jul 2017 08:50:36 +0300 Subject: [PATCH 0929/4375] page-pipe: drop dead code The page_pipe_read obsoleted page_pipe_split and related functions and there is no point in keeping them. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/include/page-pipe.h | 3 - criu/page-pipe.c | 161 --------------------------------------- 2 files changed, 164 deletions(-) diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h index 76ec1fd5a..301edaae0 100644 --- a/criu/include/page-pipe.h +++ b/criu/include/page-pipe.h @@ -133,9 +133,6 @@ extern int page_pipe_add_hole(struct page_pipe *pp, unsigned long addr, extern void debug_show_page_pipe(struct page_pipe *pp); void page_pipe_reinit(struct page_pipe *pp); -extern int page_pipe_split(struct page_pipe *pp, unsigned long addr, - unsigned int *nr_pages); - extern void page_pipe_destroy_ppb(struct page_pipe_buf *ppb); struct pipe_read_dest { diff --git a/criu/page-pipe.c b/criu/page-pipe.c index 4b4b3fc2a..63c5a8a75 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -83,25 +83,6 @@ static int ppb_resize_pipe(struct page_pipe_buf *ppb, unsigned long new_size) return 0; } -static struct page_pipe_buf *ppb_alloc_resize(struct page_pipe *pp, int size) -{ - struct page_pipe_buf *ppb; - int nr_pages = size / PAGE_SIZE; - - ppb = ppb_alloc(pp); - if (!ppb) - return NULL; - - if (ppb->pipe_size < nr_pages) { - if (ppb_resize_pipe(ppb, nr_pages)) { - ppb_destroy(ppb); - return NULL; - } - } - - return ppb; -} - static int page_pipe_grow(struct page_pipe *pp, unsigned int flags) { struct page_pipe_buf *ppb; @@ -332,148 +313,6 @@ static struct page_pipe_buf *get_ppb(struct page_pipe *pp, unsigned long addr, return NULL; } -static int page_pipe_split_iov(struct page_pipe *pp, struct page_pipe_buf *ppb, - struct iovec *iov, unsigned long addr, - bool popup_new) -{ - unsigned long len = addr - (unsigned long)iov->iov_base; - struct page_pipe_buf *ppb_new; - struct iovec *iov_new; - int ret; - - if (len == iov->iov_len) - return 0; - - ppb_new = ppb_alloc_resize(pp, len); - if (!ppb_new) - return -1; - - ret = splice(ppb->p[0], NULL, ppb_new->p[1], NULL, len, SPLICE_F_MOVE); - if (ret != len) - return -1; - - iov_new = &pp->iovs[pp->free_iov++]; - BUG_ON(pp->free_iov > pp->nr_iovs); - iov_new->iov_base = iov->iov_base; - iov_new->iov_len = len; - - ppb_init(ppb_new, len / PAGE_SIZE, 1, ppb->flags, iov_new); - - ppb->pages_in -= len / PAGE_SIZE; - - iov->iov_base += len; - iov->iov_len -= len; - - if (popup_new) - ppb = ppb_new; - list_move(&ppb->l, &pp->bufs); - - return 0; -} - -static int page_pipe_split_ppb(struct page_pipe *pp, struct page_pipe_buf *ppb, - struct iovec *iov, unsigned long len, - bool popup_new) -{ - struct page_pipe_buf *ppb_new; - int ret; - - ppb_new = ppb_alloc_resize(pp, len); - if (!ppb_new) - return -1; - - ret = splice(ppb->p[0], NULL, ppb_new->p[1], NULL, len, SPLICE_F_MOVE); - if (ret != len) - return -1; - - ppb_init(ppb_new, len / PAGE_SIZE, iov - ppb->iov, ppb->flags, ppb->iov); - - ppb->iov += ppb_new->nr_segs; - ppb->nr_segs -= ppb_new->nr_segs; - ppb->pages_in -= len / PAGE_SIZE; - - if (popup_new) - ppb = ppb_new; - list_move(&ppb->l, &pp->bufs); - - return 0; -} - -/* - * Find the ppb containing addr and split so that we can splice - * nr_pages starting from addr. Make the ppb containing relavant pages - * the first entry in bb->bufs list - */ -int page_pipe_split(struct page_pipe *pp, unsigned long addr, - unsigned int *nr_pages) -{ - struct page_pipe_buf *ppb; - struct iovec *iov = NULL; - unsigned long len = 0; - int ret; - - /* - * Get ppb that contains addr and count length of data between - * the beginning of the pipe and addr. If no ppb is found, the - * requested page is mapped to zero pfn - */ - ppb = get_ppb(pp, addr, &iov, &len); - if (!ppb) { - *nr_pages = 0; - return 0; - } - - /* - * Split origingal ppb on boundary of iov that contains - * addr. The ppb containing the address will remain at the - * pp->buf list head. - */ - if (iov != ppb->iov) { - len -= (addr - (unsigned long)iov->iov_base); - ret = page_pipe_split_ppb(pp, ppb, iov, len, false); - if (ret) - return -1; - } - - /* - * Split the tail of the ppb. We presume that requests do not - * cross IOV (that is pagemap entry) boundaries. - * The newly created ppb will contain the desired IOV and will - * be poped to the head of the pp->buf list - */ - if (ppb->nr_segs > 1) { - len = iov->iov_len; - ret = page_pipe_split_ppb(pp, ppb, iov + 1, len, true); - if (ret) - return -1; - ppb = list_first_entry(&pp->bufs, struct page_pipe_buf, l); - } - - /* - * if address does not match iov base, split the iov and - * create a new ppb pointing to the new iov - */ - if (addr != (unsigned long)iov->iov_base) { - ret = page_pipe_split_iov(pp, ppb, iov, addr, false); - if (ret) - return -1; - } - - /* - * at this point iov_base points to addr, so we need to split - * the part after addr + requested pages to a separate iov - */ - len = min((unsigned long)iov->iov_base + iov->iov_len - addr, - (unsigned long)(*nr_pages) * PAGE_SIZE); - ret = page_pipe_split_iov(pp, ppb, iov, addr + len, true); - if (ret) - return -1; - - *nr_pages = len / PAGE_SIZE; - - return 0; -} - int pipe_read_dest_init(struct pipe_read_dest *prd) { int ret; From 6cc31a7f0bc0a7cb8dedbfa957328bb669612a21 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 20 Jul 2017 21:18:09 +0300 Subject: [PATCH 0930/4375] travis: exclude futex and lazy-thp tests from lazy passes Both test seem to reproduce issue #357 [1] too frequently which make it really annoying. Temporarily remove them from lazy-pages passes until the issue is fixed. [1] https://github.com/xemul/criu/issues/357 Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 065535943..7f4f031d6 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -80,6 +80,7 @@ else -x socket_listen -x socket_listen6 -x cmdlinenv00 -x socket_close_data01 -x file_read" fi +LAZY_EXCLUDE="$LAZY_EXCLUDE -x futex -x lazy-thp" ./test/zdtm.py run -a -p 2 --lazy-pages $LAZY_EXCLUDE ./test/zdtm.py run -a -p 2 --remote-lazy-pages $LAZY_EXCLUDE From 2335be271faae80e4d6022f58ac5b2e9cb52f0fd Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 24 Jul 2017 17:23:19 +0300 Subject: [PATCH 0931/4375] lazy-pages: merge compete_page_fault into uffd_io_complete There's no real point to have two-liner wrapper for compete_page_fault and uffd_io_complete is better semantically. Acked-by: Pavel Emelyanov Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index a94eaaa13..606e8cbb2 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -711,11 +711,14 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) return 0; } -static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long img_addr, int nr) +static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr) { + struct lazy_pages_info *lpi; unsigned long addr = 0; struct lp_req *req; + lpi = container_of(pr, struct lazy_pages_info, pr); + list_for_each_entry(req, &lpi->reqs, l) { if (req->img_addr == img_addr) { addr = req->addr; @@ -741,14 +744,6 @@ static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long img_ad return drop_lazy_iovs(lpi, addr, nr * PAGE_SIZE); } -static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr) -{ - struct lazy_pages_info *lpi; - - lpi = container_of(pr, struct lazy_pages_info, pr); - return complete_page_fault(lpi, img_addr, nr); -} - static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) { struct uffdio_zeropage uffdio_zeropage; From c7650cc1e8f31730f456a099de830fc11e499725 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 24 Jul 2017 17:23:20 +0300 Subject: [PATCH 0932/4375] lazy-pages: drop _lazy_ annotation from iovec operations All the iovecs in uffd.c are lazy, there is no point in having _lazy_ in functions that operate on these iovecs. Acked-by: Pavel Emelyanov Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 606e8cbb2..d63b3667c 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -118,7 +118,7 @@ static struct lazy_pages_info *lpi_init(void) return lpi; } -static void free_lazy_iovs(struct lazy_pages_info *lpi) +static void free_iovs(struct lazy_pages_info *lpi) { struct lazy_iov *p, *n; @@ -133,7 +133,7 @@ static void lpi_fini(struct lazy_pages_info *lpi) if (!lpi) return; free(lpi->buf); - free_lazy_iovs(lpi); + free_iovs(lpi); if (lpi->lpfd.fd > 0) close(lpi->lpfd.fd); if (!lpi->parent && lpi->pr.close) @@ -336,8 +336,8 @@ static MmEntry *init_mm_entry(struct lazy_pages_info *lpi) return mm; } -static struct lazy_iov *find_lazy_iov(struct lazy_pages_info *lpi, - unsigned long addr) +static struct lazy_iov *find_iov(struct lazy_pages_info *lpi, + unsigned long addr) { struct lazy_iov *iov; @@ -375,8 +375,7 @@ static int split_iov(struct lazy_iov *iov, unsigned long addr, bool new_below) return 0; } -static int copy_lazy_iovs(struct lazy_pages_info *src, - struct lazy_pages_info *dst) +static int copy_iovs(struct lazy_pages_info *src, struct lazy_pages_info *dst) { struct lazy_iov *iov, *new, *n; int max_iov_len = 0; @@ -411,8 +410,7 @@ free_iovs: * Purge range (addr, addr + len) from lazy_iovs. The range may * cover several continuous IOVs. */ -static int drop_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, - int len) +static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) { struct lazy_iov *iov, *n; @@ -471,8 +469,8 @@ static int drop_lazy_iovs(struct lazy_pages_info *lpi, unsigned long addr, return 0; } -static int remap_lazy_iovs(struct lazy_pages_info *lpi, unsigned long from, - unsigned long to, unsigned long len) +static int remap_iovs(struct lazy_pages_info *lpi, unsigned long from, + unsigned long to, unsigned long len) { unsigned long off = to - from; struct lazy_iov *iov, *n, *p; @@ -533,7 +531,7 @@ static int remap_lazy_iovs(struct lazy_pages_info *lpi, unsigned long from, * only inside a single VMA. * We assume here that pagemaps and VMAs are sorted. */ -static int collect_lazy_iovs(struct lazy_pages_info *lpi) +static int collect_iovs(struct lazy_pages_info *lpi) { struct page_read *pr = &lpi->pr; struct lazy_iov *iov, *n; @@ -645,7 +643,7 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) * Find the memory pages belonging to the restored process * so that it is trackable when all pages have been transferred. */ - ret = collect_lazy_iovs(lpi); + ret = collect_iovs(lpi); if (ret < 0) goto out; lpi->total_pages = ret; @@ -667,7 +665,7 @@ static int handle_exit(struct lazy_pages_info *lpi) lp_debug(lpi, "EXIT\n"); if (epoll_del_rfd(epollfd, &lpi->lpfd)) return -1; - free_lazy_iovs(lpi); + free_iovs(lpi); close(lpi->lpfd.fd); lpi->lpfd.fd = 0; @@ -741,7 +739,7 @@ static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr if (uffd_copy(lpi, addr, nr)) return -1; - return drop_lazy_iovs(lpi, addr, nr * PAGE_SIZE); + return drop_iovs(lpi, addr, nr * PAGE_SIZE); } static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) @@ -884,7 +882,7 @@ static int handle_remove(struct lazy_pages_info *lpi, struct uffd_msg *msg) return -1; } - return drop_lazy_iovs(lpi, unreg.start, unreg.len); + return drop_iovs(lpi, unreg.start, unreg.len); } static int handle_remap(struct lazy_pages_info *lpi, struct uffd_msg *msg) @@ -895,7 +893,7 @@ static int handle_remap(struct lazy_pages_info *lpi, struct uffd_msg *msg) lp_debug(lpi, "REMAP: %lx -> %lx (%ld)\n", from , to, len); - return remap_lazy_iovs(lpi, from, to, len); + return remap_iovs(lpi, from, to, len); } static int handle_fork(struct lazy_pages_info *parent_lpi, struct uffd_msg *msg) @@ -909,7 +907,7 @@ static int handle_fork(struct lazy_pages_info *parent_lpi, struct uffd_msg *msg) if (!lpi) return -1; - if (copy_lazy_iovs(parent_lpi, lpi)) + if (copy_iovs(parent_lpi, lpi)) goto out; lpi->pid = parent_lpi->pid; @@ -975,7 +973,7 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) if (is_page_queued(lpi, address)) return 0; - iov = find_lazy_iov(lpi, address); + iov = find_iov(lpi, address); if (!iov) return uffd_zero(lpi, address, 1); From 294abb197a55b36099bac4b11da8d3c3950cbc83 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 24 Jul 2017 17:23:21 +0300 Subject: [PATCH 0933/4375] lazy-pages: use free_iovs helper when freeing IOVs on error paths Acked-by: Pavel Emelyanov Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index d63b3667c..d67fabc9d 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -377,7 +377,7 @@ static int split_iov(struct lazy_iov *iov, unsigned long addr, bool new_below) static int copy_iovs(struct lazy_pages_info *src, struct lazy_pages_info *dst) { - struct lazy_iov *iov, *new, *n; + struct lazy_iov *iov, *new; int max_iov_len = 0; list_for_each_entry(iov, &src->iovs, l) { @@ -401,8 +401,7 @@ static int copy_iovs(struct lazy_pages_info *src, struct lazy_pages_info *dst) return 0; free_iovs: - list_for_each_entry_safe(iov, n, &dst->iovs, l) - xfree(iov); + free_iovs(dst); return -1; } @@ -534,7 +533,7 @@ static int remap_iovs(struct lazy_pages_info *lpi, unsigned long from, static int collect_iovs(struct lazy_pages_info *lpi) { struct page_read *pr = &lpi->pr; - struct lazy_iov *iov, *n; + struct lazy_iov *iov; MmEntry *mm; int nr_pages = 0, n_vma = 0, max_iov_len = 0; int ret = -1; @@ -585,8 +584,7 @@ static int collect_iovs(struct lazy_pages_info *lpi) goto free_mm; free_iovs: - list_for_each_entry_safe(iov, n, &lpi->iovs, l) - xfree(iov); + free_iovs(lpi); free_mm: mm_entry__free_unpacked(mm, NULL); From aa88de59b17fe41acc78f458b91d0a04919dc96d Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 26 Jul 2017 18:06:52 +0300 Subject: [PATCH 0934/4375] lazy-pages: uffd_zero: update error reporting Acked-by: Adrian Reber Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index d67fabc9d..ab7c028d1 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -753,7 +753,8 @@ static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) lp_debug(lpi, "zero page at 0x%llx\n", address); rc = ioctl(lpi->lpfd.fd, UFFDIO_ZEROPAGE, &uffdio_zeropage); if (rc) { - lp_err(lpi, "UFFDIO_ZEROPAGE error %d\n", rc); + lp_perror(lpi, "zero page failed: %Ld", + uffdio_zeropage.zeropage); return -1; } From fc34b5144c6f03155bec033e8ac544fa119f0281 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 26 Jul 2017 18:06:53 +0300 Subject: [PATCH 0935/4375] lazy-pages: restorer: reduce amount of printouts Acked-by: Adrian Reber Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 6e19ca356..fb2b35f64 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -786,9 +786,6 @@ static void rst_tcp_socks_all(struct task_restore_args *ta) rst_tcp_repair_off(&ta->tcp_socks[i]); } - - - static int enable_uffd(int uffd, unsigned long addr, unsigned long len) { int rc; @@ -805,14 +802,14 @@ static int enable_uffd(int uffd, unsigned long addr, unsigned long len) uffdio_register.range.start = addr; uffdio_register.range.len = len; uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; - pr_info("lazy-pages: uffdio_register.range.start 0x%lx\n", (unsigned long) uffdio_register.range.start); - pr_info("lazy-pages: uffdio_register.len 0x%llx\n", uffdio_register.range.len); + + pr_info("lazy-pages: register: %lx, len %lx\n", addr, len); + rc = sys_ioctl(uffd, UFFDIO_REGISTER, (unsigned long) &uffdio_register); - pr_info("lazy-pages: ioctl UFFDIO_REGISTER rc %d\n", rc); - pr_info("lazy-pages: uffdio_register.range.start 0x%lx\n", (unsigned long) uffdio_register.range.start); - pr_info("lazy-pages: uffdio_register.len 0x%llx\n", uffdio_register.range.len); - if (rc != 0) + if (rc != 0) { + pr_err("lazy-pages: register %lx failed: rc:%d, \n", addr, rc); return -1; + } expected_ioctls = (1 << _UFFDIO_WAKE) | (1 << _UFFDIO_COPY) | (1 << _UFFDIO_ZEROPAGE); From 668ea674bd63c91f9922b2a4475d375abb42ea30 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 1 May 2017 10:11:56 +0300 Subject: [PATCH 0936/4375] docs: start documenting lazy-pages Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 24fba66d5..3e81d266d 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -317,6 +317,15 @@ For example, the command line for the above example should look like this: engine's default directory for tasks, permissions will not be preserved on the upper directories with no tasks in them, which may cause problems. +*--lazy-pages*:: + Perform the dump procedure without writing memory pages into the + image files and prepare to service page requests over the + network. When *dump* runs in this mode it presumes that + *lazy-pages* daemon will connect to it and fetch memory pages to + lazily inject them into the restored process address space. This + option is intended for post-copy (lazy) migration and should be + used in conjunction with *restore* with appropriate options. + *restore* ~~~~~~~~~ Restores previously checkpointed processes. @@ -466,6 +475,14 @@ are not adequate, but this can be suppressed by using *--cpu-cap=none*. to restore on an older kernel, or a kernel configured without some options. +*--lazy-pages*:: + Restore the processes without filling out the entire memory + contents. When this option is used, *restore* sets up the + infrastucture required to fill memory pages either on demand when + the process accesses them or in the background without stopping the + restored process. + This option requires running *lazy-pages* daemon. + *check* ~~~~~~~ Checks whether the kernel supports the features needed by *criu* to @@ -532,6 +549,18 @@ Launches *criu* in page server mode. *--port* 'number':: Page server port number. +*lazy-pages* +~~~~~~~~~~~~ +Launches *criu* in lazy-pages daemon mode. + +The *lazy-pages* daemon is responsible for managing user-level demand +paging for the restored processes. It gets information required to +fill the process memory pages from the *restore* and from the +checkpont directory. When a restored process access certain memory +page for the first time, the *lazy-pages* daemon injects its contents +into the process address space. The memory pages that are not yet +requested by the restored processes are injected in the background. + *exec* ~~~~~~ Executes a system call inside a destination task\'s context. This functionality From b325765cc9da0b881e05bb9282632ac22f5e2e02 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 8 Aug 2017 10:05:56 +0300 Subject: [PATCH 0937/4375] cr-check: use two features to verify userfaultfd availability For the older kernels the implementation of userfaultfd would not include non-cooperative mode. In such case it is still possible to use uffd and enable lazy-pages, but if the restored process will change its virtual memory layout during restore, we'll get memory corruption. After this change 'criu check --feature uffd' will report success if the kernel supports userfaultfd at all and 'criu check --feature uffd-noncoop' will report success if the kernel supports non-cooperative userfaultfd. Suggested-by: Pavel Emelyanov Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-check.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index 029fb4350..87b430cf6 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1048,11 +1048,6 @@ static int check_compat_cr(void) static int check_uffd(void) { - unsigned long features = UFFD_FEATURE_EVENT_FORK | - UFFD_FEATURE_EVENT_REMAP | - UFFD_FEATURE_EVENT_UNMAP | - UFFD_FEATURE_EVENT_REMOVE; - if (kerndat_uffd()) return -1; @@ -1061,8 +1056,21 @@ static int check_uffd(void) return -1; } + return 0; +} + +static int check_uffd_noncoop(void) +{ + unsigned long features = UFFD_FEATURE_EVENT_FORK | + UFFD_FEATURE_EVENT_REMAP | + UFFD_FEATURE_EVENT_UNMAP | + UFFD_FEATURE_EVENT_REMOVE; + + if (check_uffd()) + return -1; + if ((kdat.uffd_features & features) != features) { - pr_err("Userfaultfd missing essential features\n"); + pr_err("Non-cooperative UFFD is not supported\n"); return -1; } @@ -1181,6 +1189,7 @@ int cr_check(void) ret |= check_autofs(); ret |= check_compat_cr(); ret |= check_uffd(); + ret |= check_uffd_noncoop(); } print_on_level(DEFAULT_LOGLEVEL, "%s\n", ret ? CHECK_MAYBE : CHECK_GOOD); @@ -1222,7 +1231,8 @@ static struct feature_list feature_list[] = { { "autofs", check_autofs }, { "tcp_half_closed", check_tcp_halt_closed }, { "compat_cr", check_compat_cr }, - { "lazy_pages", check_uffd }, + { "uffd", check_uffd }, + { "uffd-noncoop", check_uffd_noncoop }, { NULL, NULL }, }; From 1dc55aef45a768549d8f35756fa6c4d1cc9b6f1e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 8 Aug 2017 10:05:57 +0300 Subject: [PATCH 0938/4375] test/zdtm: do not allow running with --lazy-pages on kernel without uffd Raise an exception for kernels that do not have userfaultfd. For the kernels that have userfaultfd but do not provide non-cooperative events (4.3 - 4.11) just print a warning. Fixes: #363 Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- test/zdtm.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index cfa7b2ee1..2e37087f5 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1655,6 +1655,15 @@ def run_tests(opts): if subprocess.Popen(["ip", "netns", "exec", "zdtm_netns", "ip", "link", "set", "up", "dev", "lo"]).wait(): raise Exception("ip link set up dev lo") + if opts['lazy_pages'] or opts['remote_lazy_pages']: + uffd = criu.check("uffd") + uffd_noncoop = criu.check("uffd-noncoop") + if not uffd: + raise Exception("UFFD is not supported, cannot run with --lazy-pages") + if not uffd_noncoop: + # Most tests will work with 4.3 - 4.11 + print "[WARNING] Non-cooperative UFFD is missing, some tests might spuriously fail" + l = launcher(opts, len(torun)) try: for t in torun: From 76ed56cdb5d2c2ea4dc08a6711fed3875f65fd2a Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 8 Aug 2017 14:44:29 +0300 Subject: [PATCH 0939/4375] cr-check: make uffd verification "extra" rather then "experimental" Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-check.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index 87b430cf6..9ab43652b 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1188,8 +1188,6 @@ int cr_check(void) if (opts.check_experimental_features) { ret |= check_autofs(); ret |= check_compat_cr(); - ret |= check_uffd(); - ret |= check_uffd_noncoop(); } print_on_level(DEFAULT_LOGLEVEL, "%s\n", ret ? CHECK_MAYBE : CHECK_GOOD); From 4b5605d986304f9e8dcc418bfc23837d18ec7e91 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 8 Aug 2017 16:18:03 +0300 Subject: [PATCH 0940/4375] Documentation: spelling fix Signed-off-by: Mike Rapoport Acked-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- Documentation/criu.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 3e81d266d..5a7cd3996 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -478,7 +478,7 @@ are not adequate, but this can be suppressed by using *--cpu-cap=none*. *--lazy-pages*:: Restore the processes without filling out the entire memory contents. When this option is used, *restore* sets up the - infrastucture required to fill memory pages either on demand when + infrastructure required to fill memory pages either on demand when the process accesses them or in the background without stopping the restored process. This option requires running *lazy-pages* daemon. From e5d7d71b1e746224bba0c85fbcdc2ef4a390b95f Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 8 Aug 2017 16:18:04 +0300 Subject: [PATCH 0941/4375] Documentation: add --lazy-pages option to page-server description Signed-off-by: Mike Rapoport Acked-by: Adrian Reber Signed-off-by: Pavel Emelyanov --- Documentation/criu.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 5a7cd3996..ef0105fdd 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -549,6 +549,12 @@ Launches *criu* in page server mode. *--port* 'number':: Page server port number. +*--lazy-pages*:: + Serve local memory dump to a remote *lazy-pages* daemon. In this + mode the *page-server* reads local memory dump and allows the + remote *lazy-pages* deamon to request memory pages in random + order. + *lazy-pages* ~~~~~~~~~~~~ Launches *criu* in lazy-pages daemon mode. From 1f2cc31fd5d2eef89bb570b2789b09fc3186c218 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 14 Aug 2017 16:50:00 +0300 Subject: [PATCH 0942/4375] lazy-pages: treat ESRCH returned by uffdio_copy as process exit condition Newer kernels will report ESRCH when uffdio_copy is attempted when the process is exiting [1]. We take care of the new errno value and keep ENOSPC for compatibility. [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/fs/userfaultfd.c?id=e86b298bebf7e799e4b7232e9135799f1947552e Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/uffd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index ab7c028d1..c5ad78503 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -688,7 +688,7 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) lp_debug(lpi, "uffd_copy: 0x%llx/%ld\n", uffdio_copy.dst, len); rc = ioctl(lpi->lpfd.fd, UFFDIO_COPY, &uffdio_copy); if (rc) { - if (errno == ENOSPC) { + if (errno == ENOSPC || errno == ESRCH) { handle_exit(lpi); return 0; } From 830dd3018fe17ec79ca339ed3c909271e5d02ba4 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Aug 2017 09:23:48 +0300 Subject: [PATCH 0943/4375] lazy-pages: introduce uffd_open kdat and lazy-pages use nearly the same sequence to open userfault. This code can definitely live in a dedicated function. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/include/uffd.h | 2 ++ criu/kerndat.c | 34 +++++++++++----------------- criu/uffd.c | 54 +++++++++++++++++++++++++++++++-------------- 3 files changed, 53 insertions(+), 37 deletions(-) diff --git a/criu/include/uffd.h b/criu/include/uffd.h index 4d790cebf..e2b9be693 100644 --- a/criu/include/uffd.h +++ b/criu/include/uffd.h @@ -2,6 +2,8 @@ #define __CR_UFFD_H_ struct task_restore_args; + +extern int uffd_open(int flags, unsigned long *features); extern int setup_uffd(int pid, struct task_restore_args *task_args); extern int lazy_pages_setup_zombie(int pid); extern int prepare_lazy_pages_socket(void); diff --git a/criu/kerndat.c b/criu/kerndat.c index 156b5b630..62b62613d 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -33,6 +33,7 @@ #include "netfilter.h" #include "linux/userfaultfd.h" #include "prctl.h" +#include "uffd.h" struct kerndat_s kdat = { }; @@ -719,18 +720,18 @@ unl: int kerndat_uffd(void) { - struct uffdio_api uffdio_api; int uffd; - uffd = syscall(SYS_userfaultfd, 0); + uffd = uffd_open(0, &kdat.uffd_features); /* - * uffd == -1 is probably enough to not use lazy-restore - * on this system. Additionally checking for ENOSYS - * makes sure it is actually not implemented. + * uffd == -ENOSYS means userfaultfd is not supported on this + * system and we just happily return with kdat.has_uffd = false. + * Error other than -ENOSYS would mean "Houston, Houston, we + * have a problem!" */ - if (uffd == -1) { - if (errno == ENOSYS) + if (uffd < 0) { + if (uffd == -ENOSYS) return 0; pr_err("Lazy pages are not available\n"); @@ -739,21 +740,12 @@ int kerndat_uffd(void) kdat.has_uffd = true; - uffdio_api.api = UFFD_API; - uffdio_api.features = 0; - if (ioctl(uffd, UFFDIO_API, &uffdio_api)) { - pr_perror("Failed to get uffd API"); - return -1; - } - if (uffdio_api.api != UFFD_API) { - pr_err("Incompatible uffd API: expected %Lu, got %Lu\n", - UFFD_API, uffdio_api.api); - return -1; - } - - kdat.uffd_features = uffdio_api.features; - + /* + * we have to close the uffd and reopen in later in restorer + * to enable non-cooperative features + */ close(uffd); + return 0; } diff --git a/criu/uffd.c b/criu/uffd.c index c5ad78503..d3142ae8b 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -211,10 +211,46 @@ int lazy_pages_setup_zombie(int pid) return 0; } +int uffd_open(int flags, unsigned long *features) +{ + struct uffdio_api uffdio_api = { 0 }; + int uffd; + + uffd = syscall(SYS_userfaultfd, flags); + if (uffd == -1) { + pr_perror("Lazy pages are not available"); + return -errno; + } + + uffdio_api.api = UFFD_API; + if (features) + uffdio_api.features = *features; + + if (ioctl(uffd, UFFDIO_API, &uffdio_api)) { + pr_perror("Failed to get uffd API"); + goto err; + } + + if (uffdio_api.api != UFFD_API) { + pr_err("Incompatible uffd API: expected %Lu, got %Lu\n", + UFFD_API, uffdio_api.api); + goto err; + } + + if (features) + *features = uffdio_api.features; + + return uffd; + +err: + close(uffd); + return -1; +} + /* This function is used by 'criu restore --lazy-pages' */ int setup_uffd(int pid, struct task_restore_args *task_args) { - struct uffdio_api uffdio_api; + unsigned long features = kdat.uffd_features & NEED_UFFD_API_FEATURES; if (!opts.lazy_pages) { task_args->uffd = -1; @@ -225,26 +261,12 @@ int setup_uffd(int pid, struct task_restore_args *task_args) * Open userfaulfd FD which is passed to the restorer blob and * to a second process handling the userfaultfd page faults. */ - task_args->uffd = syscall(SYS_userfaultfd, O_CLOEXEC | O_NONBLOCK); + task_args->uffd = uffd_open(O_CLOEXEC | O_NONBLOCK, &features); if (task_args->uffd < 0) { pr_perror("Unable to open an userfaultfd descriptor"); return -1; } - /* - * Check if the UFFD_API is the one which is expected - */ - uffdio_api.api = UFFD_API; - uffdio_api.features = kdat.uffd_features & NEED_UFFD_API_FEATURES; - if (ioctl(task_args->uffd, UFFDIO_API, &uffdio_api)) { - pr_err("Checking for UFFDIO_API failed.\n"); - goto err; - } - if (uffdio_api.api != UFFD_API) { - pr_err("Result of looking up UFFDIO_API does not match: %Lu\n", uffdio_api.api); - goto err; - } - if (send_uffd(task_args->uffd, pid) < 0) goto err; From cfc980c614925bfa57feffb27609861fbba262af Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 Aug 2017 09:23:49 +0300 Subject: [PATCH 0944/4375] kdat: move kerndat initialization to the very beginning With kdat cache and unified kerndat_init() we can call it very early in crtools and then kdat information will be available for all cr-* actions. Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-dump.c | 6 ------ criu/cr-restore.c | 3 --- criu/crtools.c | 4 ++++ 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 8fdf85259..985a64ba5 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1553,9 +1553,6 @@ int cr_pre_dump_tasks(pid_t pid) if (cr_plugin_init(CR_PLUGIN_STAGE__PRE_DUMP)) goto err; - if (kerndat_init()) - goto err; - if (lsm_check_opts()) goto err; @@ -1732,9 +1729,6 @@ int cr_dump_tasks(pid_t pid) if (cr_plugin_init(CR_PLUGIN_STAGE__DUMP)) goto err; - if (kerndat_init()) - goto err; - if (lsm_check_opts()) goto err; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index bbe0bc670..1c11cdf39 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2197,9 +2197,6 @@ int cr_restore_tasks(void) if (init_stats(RESTORE_STATS)) goto err; - if (kerndat_init()) - goto err; - if (lsm_check_opts()) goto err; diff --git a/criu/crtools.c b/criu/crtools.c index af1f0c588..ebfd1d6a7 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -47,6 +47,7 @@ #include "fault-injection.h" #include "lsm.h" #include "proc_parse.h" +#include "kerndat.h" #include "setproctitle.h" #include "sysctl.h" @@ -316,6 +317,9 @@ int main(int argc, char *argv[], char *envp[]) if (init_service_fd()) return 1; + if (kerndat_init()) + return 1; + if (!strcmp(argv[1], "swrk")) { if (argc < 3) goto usage; From 8d80012bf1817ea55f6fb9cb28e0b7c06600e06c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 5 Apr 2017 14:32:59 +0300 Subject: [PATCH 0945/4375] zdtm: rely on -D_GNU_SOURCE passed from Makefiles After the commit 02c763939c10 ("test/zdtm: unify common code") CFLAGS with -D_GNU_SOURCE defined in the top Makefile are being passed to tests Makefiles. As _GNU_SOURCE is also defined by tests, that resulted in zdtm tests build failures: make[2]: Entering directory `/home/criu/test/zdtm/lib' CC test.o test.c:1:0: error: "_GNU_SOURCE" redefined [-Werror] #define _GNU_SOURCE ^ :0:0: note: this is the location of the previous definition cc1: all warnings being treated as errors make[2]: *** [test.o] Error 1 However, we didn't catch this in time by Travis-CI, as zdtm.py doesn't do `make zdtm`, rather it does `make -C test/zdtm/{lib,static,transition}`. By calling middle makefile this way, it doesn't have _GNU_SOURCE in CFLAGS from top-Makefile. I think the right thing to do here - is following CRIU's way: rely on definition of _GNU_SOURCE by Makefiles. This patch is almost fully generated with find test/zdtm/ -name '*.c' -type f \ -exec sed -i '/define _GNU_SOURCE/{n;/^$/d;}' '{}' \; \ -exec sed -i '/define _GNU_SOURCE/d' '{}' \; With an exception for adding -D_GNU_SOURCE in tests Makefile.inc for keeping the same behaviour for zdtm.py. Also changed utsname.c to use utsname::domainname, rather private utsname::__domainname, as now it's uncovered (from sys/utsname.h): > struct utsname > { ... > # ifdef __USE_GNU > char domainname[_UTSNAME_DOMAIN_LENGTH]; > # else > char __domainname[_UTSNAME_DOMAIN_LENGTH]; > # endif Reported-by: Adrian Reber Cc: Kir Kolyshkin Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/uffd-events.c | 1 - 1 file changed, 1 deletion(-) diff --git a/test/zdtm/static/uffd-events.c b/test/zdtm/static/uffd-events.c index 9939c86b8..5a46d7e6d 100644 --- a/test/zdtm/static/uffd-events.c +++ b/test/zdtm/static/uffd-events.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include From 6a17d8cf49aaaccc76e232c6d22b01ed785b5ea0 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 16 Aug 2017 10:32:25 +0300 Subject: [PATCH 0946/4375] check/servise: use cached kdat values for features check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The kerndat_init() is now called before the jump to action handler. This allows us to directly use kdat without calling to the corresponding kerndat_*() methods. ✓ travis-ci: success for lazy-pages: update checks for availability of userfaultfd (rev3) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-check.c | 18 ------------------ criu/cr-service.c | 23 ++++------------------- 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index 9ab43652b..ef706bf7b 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -676,9 +676,6 @@ static int check_ptrace_dump_seccomp_filters(void) static int check_mem_dirty_track(void) { - if (kerndat_get_dirty_track() < 0) - return -1; - if (!kdat.has_dirty_track) { pr_warn("Dirty tracking is OFF. Memory snapshot will not work.\n"); return -1; @@ -772,9 +769,6 @@ static int check_aio_remap(void) static int check_fdinfo_lock(void) { - if (kerndat_fdinfo_has_lock()) - return -1; - if (!kdat.has_fdinfo_lock) { pr_err("fdinfo doesn't contain the lock field\n"); return -1; @@ -931,12 +925,6 @@ out: static int check_tcp_halt_closed(void) { - int ret; - - ret = kerndat_tcp_repair(); - if (ret < 0) - return -1; - if (!kdat.has_tcp_half_closed) { pr_err("TCP_REPAIR can't be enabled for half-closed sockets\n"); return -1; @@ -1023,9 +1011,6 @@ static int check_userns(void) static int check_loginuid(void) { - if (kerndat_loginuid() < 0) - return -1; - if (kdat.luid != LUID_FULL) { pr_warn("Loginuid restore is OFF.\n"); return -1; @@ -1048,9 +1033,6 @@ static int check_compat_cr(void) static int check_uffd(void) { - if (kerndat_uffd()) - return -1; - if (!kdat.has_uffd) { pr_err("UFFD is not supported\n"); return -1; diff --git a/criu/cr-service.c b/criu/cr-service.c index 375b03533..84d7eb2be 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -886,22 +886,11 @@ static int handle_feature_check(int sk, CriuReq * msg) setproctitle("feature-check --rpc"); if ((msg->features->has_mem_track == 1) && - (msg->features->mem_track == true)) { - - feat.mem_track = true; - ret = kerndat_get_dirty_track(); - - if (ret) - feat.mem_track = false; - - if (!kdat.has_dirty_track) - feat.mem_track = false; - } + (msg->features->mem_track == true)) + feat.mem_track = kdat.has_dirty_track; if ((msg->features->has_lazy_pages == 1) && - (msg->features->lazy_pages == true)) { - ret = kerndat_uffd(); - + (msg->features->lazy_pages == true)) /* * Not checking for specific UFFD features yet. * If no error is returned it is probably @@ -909,11 +898,7 @@ static int handle_feature_check(int sk, CriuReq * msg) * be extended in the future for a more detailed * UFFD feature check. */ - if (ret || !kdat.has_uffd) - feat.lazy_pages = false; - else - feat.lazy_pages = true; - } + feat.lazy_pages = kdat.has_uffd; resp.features = &feat; resp.type = msg->type; From 9c56992f2bc7567eec3de16f83c119445bb391ac Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 16 Aug 2017 10:32:26 +0300 Subject: [PATCH 0947/4375] cr-service: require non-cooperative userfaultfd for lazy-pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without non-cooperative userfaultfd some programs may fail during lazy restore because they perform operations that cannot be handled by the lazy-pages daemon. ✓ travis-ci: success for lazy-pages: update checks for availability of userfaultfd (rev3) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-check.c | 9 ++------- criu/cr-service.c | 10 ++-------- criu/include/uffd.h | 1 + criu/uffd.c | 7 +++++++ 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index ef706bf7b..ba47f410c 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -50,7 +50,7 @@ #include "libnetlink.h" #include "net.h" #include "restorer.h" -#include "linux/userfaultfd.h" +#include "uffd.h" static char *feature_name(int (*func)()); @@ -1043,15 +1043,10 @@ static int check_uffd(void) static int check_uffd_noncoop(void) { - unsigned long features = UFFD_FEATURE_EVENT_FORK | - UFFD_FEATURE_EVENT_REMAP | - UFFD_FEATURE_EVENT_UNMAP | - UFFD_FEATURE_EVENT_REMOVE; - if (check_uffd()) return -1; - if ((kdat.uffd_features & features) != features) { + if (!uffd_noncooperative()) { pr_err("Non-cooperative UFFD is not supported\n"); return -1; } diff --git a/criu/cr-service.c b/criu/cr-service.c index 84d7eb2be..2a4f37f58 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -40,6 +40,7 @@ #include #include #include "common/scm.h" +#include "uffd.h" #include "setproctitle.h" @@ -891,14 +892,7 @@ static int handle_feature_check(int sk, CriuReq * msg) if ((msg->features->has_lazy_pages == 1) && (msg->features->lazy_pages == true)) - /* - * Not checking for specific UFFD features yet. - * If no error is returned it is probably - * enough for basic UFFD functionality. This can - * be extended in the future for a more detailed - * UFFD feature check. - */ - feat.lazy_pages = kdat.has_uffd; + feat.lazy_pages = kdat.has_uffd && uffd_noncooperative(); resp.features = &feat; resp.type = msg->type; diff --git a/criu/include/uffd.h b/criu/include/uffd.h index e2b9be693..79abc1669 100644 --- a/criu/include/uffd.h +++ b/criu/include/uffd.h @@ -4,6 +4,7 @@ struct task_restore_args; extern int uffd_open(int flags, unsigned long *features); +extern bool uffd_noncooperative(void); extern int setup_uffd(int pid, struct task_restore_args *task_args); extern int lazy_pages_setup_zombie(int pid); extern int prepare_lazy_pages_socket(void); diff --git a/criu/uffd.c b/criu/uffd.c index d3142ae8b..077724b0d 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -211,6 +211,13 @@ int lazy_pages_setup_zombie(int pid) return 0; } +bool uffd_noncooperative(void) +{ + unsigned long features = NEED_UFFD_API_FEATURES; + + return (kdat.uffd_features & features) == features; +} + int uffd_open(int flags, unsigned long *features) { struct uffdio_api uffdio_api = { 0 }; From 254bf5d4b497b0e93d685603c1645cc84c7442c0 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 21 Aug 2017 06:53:00 +0300 Subject: [PATCH 0948/4375] kerndat: set uffd features to 0 before querying kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When there is a stale kdat cache file it's contents is read into the memory and we end up requesting random userfaultfd features. Explicitly set the kdat.uffd_features to zero before querying the kernel resolves the issue. ✓ travis-ci: success for kerndat: set uffd features to 0 before querying kernel Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/kerndat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/kerndat.c b/criu/kerndat.c index 62b62613d..32893ef2c 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -722,6 +722,7 @@ int kerndat_uffd(void) { int uffd; + kdat.uffd_features = 0; uffd = uffd_open(0, &kdat.uffd_features); /* From 97fbb1bdc48ed8d54c7fc692945619b01ddcae03 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 7 Sep 2017 11:46:11 +0300 Subject: [PATCH 0949/4375] jenkins: lazy-pages: reduce amount of parallel runs for --remote case Running zdtm/static/maps04 with --remote-lazy-pages in parallel with 3 other tests takes too much time on the Jenkins builder. Let's try running with --parallel 2. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/jenkins/criu-lazy-pages.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jenkins/criu-lazy-pages.sh b/test/jenkins/criu-lazy-pages.sh index ffcc88609..f32641e23 100755 --- a/test/jenkins/criu-lazy-pages.sh +++ b/test/jenkins/criu-lazy-pages.sh @@ -18,7 +18,7 @@ fi --lazy-pages $LAZY_EXCLUDE || fail # lazy restore from "remote" dump -./test/zdtm.py run --all --keep-going --report report --parallel 4 \ +./test/zdtm.py run --all --keep-going --report report --parallel 2 \ --remote-lazy-pages $LAZY_EXCLUDE || fail # During pre-dump + lazy-pages we leave VM_NOHUGEPAGE set From f384b8b6b37a7c7c7314cf90de5d379b109ed1d2 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 7 Sep 2017 18:15:57 +0300 Subject: [PATCH 0950/4375] lazy-pages: don't close page_read when a parent process exits If there were fork()'s during lazy-restore we create a shallow copy of the parent process' page-read. Since all the copies reference the same open files, we cannot close the page-read until we finish restore of all the processes that share the page-read. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index 077724b0d..43dc0ce21 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -80,6 +80,7 @@ struct lazy_pages_info { struct list_head reqs; struct lazy_pages_info *parent; + unsigned num_children; struct page_read pr; @@ -136,7 +137,9 @@ static void lpi_fini(struct lazy_pages_info *lpi) free_iovs(lpi); if (lpi->lpfd.fd > 0) close(lpi->lpfd.fd); - if (!lpi->parent && lpi->pr.close) + if (lpi->parent) + lpi->parent->num_children--; + if (!lpi->parent && !lpi->num_children && lpi->pr.close) lpi->pr.close(&lpi->pr); free(lpi); } @@ -947,6 +950,8 @@ static int handle_fork(struct lazy_pages_info *parent_lpi, struct uffd_msg *msg) dup_page_read(&lpi->parent->pr, &lpi->pr); + lpi->parent->num_children++; + return 1; out: From 440a2a864a0b28f4d0d0cb10edb31bfe6b77d3f2 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 13 Sep 2017 10:04:31 -0700 Subject: [PATCH 0951/4375] jenkins: lazy-pages: skip maps04 for remote-lazy-pages Even with 2 parallel jobs maps04 takes too much time with --remote-lazy-pages. Let's skip it for now. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/jenkins/criu-lazy-pages.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jenkins/criu-lazy-pages.sh b/test/jenkins/criu-lazy-pages.sh index f32641e23..cdbbf2a11 100755 --- a/test/jenkins/criu-lazy-pages.sh +++ b/test/jenkins/criu-lazy-pages.sh @@ -18,8 +18,8 @@ fi --lazy-pages $LAZY_EXCLUDE || fail # lazy restore from "remote" dump -./test/zdtm.py run --all --keep-going --report report --parallel 2 \ - --remote-lazy-pages $LAZY_EXCLUDE || fail +./test/zdtm.py run --all --keep-going --report report --parallel 4 \ + --remote-lazy-pages $LAZY_EXCLUDE -x maps04 || fail # During pre-dump + lazy-pages we leave VM_NOHUGEPAGE set LAZY_EXCLUDE="$LAZY_EXCLUDE -x maps02" From 3706af7b3fbde23f9028e057877bc26983ae0728 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 7 Sep 2017 11:41:59 +0300 Subject: [PATCH 0952/4375] compel/ppc64le: make task size detection more robust The recent changes to user address space limits in the Linux kernel break the assumption that TASK_SIZE is 128TB. For now, the maximal task size on ppc64le is 512TB and we need to detect it in runtime for compatibility with older kernels. Signed-off-by: Mike Rapoport Acked-by: Laurent Dufour Signed-off-by: Andrei Vagin --- compel/arch/ppc64/src/lib/infect.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/compel/arch/ppc64/src/lib/infect.c b/compel/arch/ppc64/src/lib/infect.c index 81125885d..1fa333e00 100644 --- a/compel/arch/ppc64/src/lib/infect.c +++ b/compel/arch/ppc64/src/lib/infect.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -9,6 +10,7 @@ #include "errno.h" #include "log.h" #include "common/bug.h" +#include "common/page.h" #include "infect.h" #include "infect-priv.h" @@ -458,7 +460,18 @@ int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s) * * NOTE: 32bit tasks are not supported. */ -#define TASK_SIZE_USER64 (0x0000400000000000UL) -#define TASK_SIZE TASK_SIZE_USER64 +#define TASK_SIZE_64TB (0x0000400000000000UL) +#define TASK_SIZE_512TB (0x0002000000000000UL) -unsigned long compel_task_size(void) { return TASK_SIZE; } +#define TASK_SIZE_MIN TASK_SIZE_64TB +#define TASK_SIZE_MAX TASK_SIZE_512TB + +unsigned long compel_task_size(void) +{ + unsigned long task_size; + + for (task_size = TASK_SIZE_MIN; task_size < TASK_SIZE_MAX; task_size <<= 1) + if (munmap((void *)task_size, page_size())) + break; + return task_size; +} From 23bdb6173c3579c2bb73f5fbd9564f0e1c6db162 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 14 Mar 2017 17:43:00 +0100 Subject: [PATCH 0953/4375] Remove bogus check in check_features The check_features RPC function required that both known fields are present. Without those fields it exited with an error. If RPC users where not specifying all parameters it would fail. It should, however, be possible to only check for a subset of options. Each supported option is checked separately anyway in the forked criu which does the actual check. Removing the check also enables RPC clients with older protobuf definitions to use the feature check. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-service.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 2a4f37f58..9172a8c4b 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -869,13 +869,6 @@ static int handle_feature_check(int sk, CriuReq * msg) feat.has_lazy_pages = 1; feat.lazy_pages = false; - /* Check if the requested feature check can be answered. */ - if ((msg->features->has_mem_track != 1) || - (msg->features->has_lazy_pages != 1)) { - pr_warn("Feature checking for unknown feature.\n"); - goto out; - } - pid = fork(); if (pid < 0) { pr_perror("Can't fork"); From 6127dd82db98535b1507fceda41aafbdddb4fca6 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 23 Mar 2017 15:02:02 -0700 Subject: [PATCH 0954/4375] Use pr_perror() on open() failure It makes sense to show errno to a user. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 3551078ba..c787659be 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -896,7 +896,7 @@ static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd, int *prev *prev_cwd_fd = open(".", O_RDONLY); if (*prev_cwd_fd < 0) { - pr_err("Can't open current dir\n"); + pr_perror("Can't open current dir"); return -1; } @@ -905,7 +905,7 @@ static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd, int *prev root = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc); *prev_root_fd = open("/", O_RDONLY); if (*prev_root_fd < 0) { - pr_err("Can't open current root\n"); + pr_perror("Can't open current root"); goto err; } From b85b5bcad9d66cdf9eeafe16dbcd2e2cd3f4c4f0 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 16 May 2017 22:45:42 +0300 Subject: [PATCH 0955/4375] arch: Fix sys_clone() arguments order The right order for all of our 4 archs is: SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, int __user *, parent_tidptr, unsigned long, tls, int __user *, child_tidptr) See Linux kernel for the details. Note, this is just a fix, and it's not connected with the second patch. Signed-off-by: Kirill Tkhai Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/arm/plugins/std/syscalls/syscall.def | 2 +- compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl | 2 +- compel/arch/x86/plugins/std/syscalls/syscall_32.tbl | 2 +- compel/arch/x86/plugins/std/syscalls/syscall_64.tbl | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compel/arch/arm/plugins/std/syscalls/syscall.def b/compel/arch/arm/plugins/std/syscalls/syscall.def index ba541ec14..9d0e758ae 100644 --- a/compel/arch/arm/plugins/std/syscalls/syscall.def +++ b/compel/arch/arm/plugins/std/syscalls/syscall.def @@ -42,7 +42,7 @@ shutdown 210 293 (int sockfd, int how) bind 235 282 (int sockfd, const struct sockaddr *addr, int addrlen) setsockopt 208 294 (int sockfd, int level, int optname, const void *optval, socklen_t optlen) getsockopt 209 295 (int sockfd, int level, int optname, const void *optval, socklen_t *optlen) -clone 220 120 (unsigned long flags, void *child_stack, void *parent_tid, void *child_tid) +clone 220 120 (unsigned long flags, void *child_stack, void *parent_tid, unsigned long newtls, void *child_tid) exit 93 1 (unsigned long error_code) wait4 260 114 (int pid, int *status, int options, struct rusage *ru) waitid 95 280 (int which, pid_t pid, struct siginfo *infop, int options, struct rusage *ru) diff --git a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl index 68411745a..17cfdc6ec 100644 --- a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl +++ b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl @@ -41,7 +41,7 @@ __NR_shutdown 338 sys_shutdown (int sockfd, int how) __NR_bind 327 sys_bind (int sockfd, const struct sockaddr *addr, int addrlen) __NR_setsockopt 339 sys_setsockopt (int sockfd, int level, int optname, const void *optval, socklen_t optlen) __NR_getsockopt 340 sys_getsockopt (int sockfd, int level, int optname, const void *optval, socklen_t *optlen) -__NR_clone 120 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, void *child_tid) +__NR_clone 120 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, unsigned long newtls, void *child_tid) __NR_exit 1 sys_exit (unsigned long error_code) __NR_wait4 114 sys_wait4 (int pid, int *status, int options, struct rusage *ru) __NR_kill 37 sys_kill (long pid, int sig) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl index 0eea9d061..c67fc4955 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl @@ -32,7 +32,7 @@ __NR_setitimer 104 sys_setitimer (int which, struct itimerval *in, struct iti __NR_getitimer 105 sys_getitimer (int which, struct itimerval *it) __NR_wait4 114 sys_wait4 (pid_t pid, int *stat_addr, int options, struct rusage *ru) __NR_ipc 117 sys_ipc (unsigned int call, int first, unsigned long second, unsigned long third, void *ptr, long fifth) -__NR_clone 120 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, void *child_tid) +__NR_clone 120 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, unsigned long newtls, void *child_tid) __NR_mprotect 125 sys_mprotect (const void *addr, unsigned long len, unsigned long prot) __NR_getpgid 132 sys_getpgid (pid_t pid) __NR_personality 136 sys_personality (unsigned int personality) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl index c291c9a42..e1c198929 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl @@ -37,7 +37,7 @@ __NR_shutdown 48 sys_shutdown (int sockfd, int how) __NR_bind 49 sys_bind (int sockfd, const struct sockaddr *addr, int addrlen) __NR_setsockopt 54 sys_setsockopt (int sockfd, int level, int optname, const void *optval, socklen_t optlen) __NR_getsockopt 55 sys_getsockopt (int sockfd, int level, int optname, const void *optval, socklen_t *optlen) -__NR_clone 56 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, void *child_tid) +__NR_clone 56 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, unsigned long newtls, void *child_tid) __NR_exit 60 sys_exit (unsigned long error_code) __NR_wait4 61 sys_wait4 (int pid, int *status, int options, struct rusage *ru) __NR_kill 62 sys_kill (long pid, int sig) From b4d13d3edd59c28c0eba5fc2345d8252aaf44b6e Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 15 Jun 2017 19:36:05 +0300 Subject: [PATCH 0956/4375] vdso: Check kdat.compat_cr in vdso_fill_compat_symtable Just slightly prettify code, no functional change. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/vdso.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index d8157cc3e..7eb28ce7f 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -421,6 +421,9 @@ static int vdso_fill_compat_symtable(struct vdso_symtable *native, void *vdso_mmap; int ret = -1; + if (!kdat.compat_cr) + return 0; + vdso_mmap = mmap(NULL, COMPAT_VDSO_BUF_SZ, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); if (vdso_mmap == MAP_FAILED) { @@ -464,8 +467,8 @@ int vdso_init(void) pr_err("Failed to fill self vdso symtable\n"); return -1; } - if (kdat.compat_cr && - vdso_fill_compat_symtable(&vdso_sym_rt, &vdso_compat_rt)) { + + if (vdso_fill_compat_symtable(&vdso_sym_rt, &vdso_compat_rt)) { pr_err("Failed to fill compat vdso symtable\n"); return -1; } From 3552146ad2fa7c12bc622b8401f0d0d04076ed3a Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 15 Jun 2017 19:36:06 +0300 Subject: [PATCH 0957/4375] vdso: Keep {vvar, vdso} sizes in symtable instead of end address The plan is to keep boot-persistent vdso properties in symtable, to omit parsing it in each invocation of criu. As sizes of vdso/vvar are being stable on the same kernel, move them into symtable, substituting end addresses. Begin/end addresses are randomized by ASLR so there is no point in storing them in kdat. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 6 ++-- criu/include/asm-generic/vdso.h | 11 ++++--- criu/include/util-vdso.h | 23 ++++----------- criu/include/vdso.h | 2 +- criu/pie/parasite-vdso.c | 52 ++++++++++++++++----------------- criu/vdso-compat.c | 11 +++---- criu/vdso.c | 39 +++++++++++++------------ 7 files changed, 68 insertions(+), 76 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 1c11cdf39..a6b2c9733 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3089,9 +3089,9 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns /* * Figure out how much memory runtime vdso and vvar will need. */ - vdso_rt_size = vdso_vma_size(&vdso_symtab_rt); - if (vdso_rt_size && vvar_vma_size(&vdso_symtab_rt)) - vdso_rt_size += ALIGN(vvar_vma_size(&vdso_symtab_rt), PAGE_SIZE); + vdso_rt_size = vdso_symtab_rt.vdso_size; + if (vdso_rt_size && vdso_symtab_rt.vvar_size) + vdso_rt_size += ALIGN(vdso_symtab_rt.vvar_size, PAGE_SIZE); task_args->bootstrap_len += vdso_rt_size; #endif diff --git a/criu/include/asm-generic/vdso.h b/criu/include/asm-generic/vdso.h index bb7460554..81e54d264 100644 --- a/criu/include/asm-generic/vdso.h +++ b/criu/include/asm-generic/vdso.h @@ -4,9 +4,12 @@ #define VDSO_PROT (PROT_READ | PROT_EXEC) #define VVAR_PROT (PROT_READ) -#define VDSO_BAD_ADDR (-1ul) -#define VVAR_BAD_ADDR VDSO_BAD_ADDR -#define VDSO_BAD_PFN (-1ull) -#define VVAR_BAD_PFN VDSO_BAD_PFN +/* Just in case of LPAE system PFN is u64. */ +#define VDSO_BAD_PFN (-1ull) +#define VVAR_BAD_PFN (-1ull) +#define VDSO_BAD_ADDR (-1ul) +#define VVAR_BAD_ADDR (-1ul) +#define VDSO_BAD_SIZE (-1ul) +#define VVAR_BAD_SIZE (-1ul) #endif /* __CR_ASM_GENERIC_VDSO_H__ */ diff --git a/criu/include/util-vdso.h b/criu/include/util-vdso.h index ad4a48eb2..4f734593c 100644 --- a/criu/include/util-vdso.h +++ b/criu/include/util-vdso.h @@ -28,10 +28,10 @@ struct vdso_symbol { }; struct vdso_symtable { - unsigned long vma_start; - unsigned long vma_end; + unsigned long vdso_start; + unsigned long vdso_size; unsigned long vvar_start; - unsigned long vvar_end; + unsigned long vvar_size; struct vdso_symbol symbols[VDSO_SYMBOL_MAX]; }; @@ -39,10 +39,10 @@ struct vdso_symtable { #define VDSO_SYMTABLE_INIT \ { \ - .vma_start = VDSO_BAD_ADDR, \ - .vma_end = VDSO_BAD_ADDR, \ + .vdso_start = VDSO_BAD_ADDR, \ + .vdso_size = VDSO_BAD_SIZE, \ .vvar_start = VVAR_BAD_ADDR, \ - .vvar_end = VVAR_BAD_ADDR, \ + .vvar_size = VVAR_BAD_SIZE, \ .symbols = { \ [0 ... VDSO_SYMBOL_MAX - 1] = \ (struct vdso_symbol)VDSO_SYMBOL_INIT, \ @@ -77,17 +77,6 @@ struct vdso_symtable { #endif /* CONFIG_VDSO_32 */ -/* Size of VMA associated with vdso */ -static inline unsigned long vdso_vma_size(struct vdso_symtable *t) -{ - return t->vma_end - t->vma_start; -} - -static inline unsigned long vvar_vma_size(struct vdso_symtable *t) -{ - return t->vvar_end - t->vvar_start; -} - #if defined(CONFIG_VDSO_32) # define vdso_fill_symtable vdso_fill_symtable_compat #endif diff --git a/criu/include/vdso.h b/criu/include/vdso.h index e118ed7f3..c4f8974e9 100644 --- a/criu/include/vdso.h +++ b/criu/include/vdso.h @@ -19,7 +19,7 @@ extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct vm_area_list *vma_area_list); #ifdef CONFIG_COMPAT -void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd, +extern void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd, int err_fd, void *vdso_buf, size_t buf_size); #endif diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index b0d531baf..5a97629d4 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -46,25 +46,25 @@ int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned l { int ret; - BUG_ON((vdso_vma_size(sym_rt) + vvar_vma_size(sym_rt)) < park_size); + BUG_ON((sym_rt->vdso_size + sym_rt->vvar_size) < park_size); if (sym_rt->vvar_start != VDSO_BAD_ADDR) { - if (sym_rt->vma_start < sym_rt->vvar_start) { - ret = vdso_remap("rt-vdso", sym_rt->vma_start, - park_at, vdso_vma_size(sym_rt)); - park_at += vdso_vma_size(sym_rt); + if (sym_rt->vdso_start < sym_rt->vvar_start) { + ret = vdso_remap("rt-vdso", sym_rt->vdso_start, + park_at, sym_rt->vdso_size); + park_at += sym_rt->vdso_size; ret |= vdso_remap("rt-vvar", sym_rt->vvar_start, - park_at, vvar_vma_size(sym_rt)); + park_at, sym_rt->vvar_size); } else { ret = vdso_remap("rt-vvar", sym_rt->vvar_start, - park_at, vvar_vma_size(sym_rt)); - park_at += vvar_vma_size(sym_rt); - ret |= vdso_remap("rt-vdso", sym_rt->vma_start, - park_at, vdso_vma_size(sym_rt)); + park_at, sym_rt->vvar_size); + park_at += sym_rt->vvar_size; + ret |= vdso_remap("rt-vdso", sym_rt->vdso_start, + park_at, sym_rt->vdso_size); } } else - ret = vdso_remap("rt-vdso", sym_rt->vma_start, - park_at, vdso_vma_size(sym_rt)); + ret = vdso_remap("rt-vdso", sym_rt->vdso_start, + park_at, sym_rt->vdso_size); return ret; } @@ -157,7 +157,7 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, * b) Symbols offsets must match * c) Have same number of vDSO zones */ - if (vma_entry_len(vma_vdso) == vdso_vma_size(sym_rt)) { + if (vma_entry_len(vma_vdso) == sym_rt->vdso_size) { size_t i; for (i = 0; i < ARRAY_SIZE(s.symbols); i++) { @@ -167,9 +167,9 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, if (i == ARRAY_SIZE(s.symbols)) { if (vma_vvar && sym_rt->vvar_start != VVAR_BAD_ADDR) { - remap_rt = (vvar_vma_size(sym_rt) == vma_entry_len(vma_vvar)); + remap_rt = (sym_rt->vvar_size == vma_entry_len(vma_vvar)); if (remap_rt) { - long delta_rt = sym_rt->vvar_start - sym_rt->vma_start; + long delta_rt = sym_rt->vvar_start - sym_rt->vdso_start; long delta_this = vma_vvar->start - vma_vdso->start; remap_rt = (delta_rt ^ delta_this) < 0 ? false : true; @@ -212,16 +212,16 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, } if (vma_vdso->start < vma_vvar->start) { - ret = vdso_remap("rt-vdso", vdso_rt_parked_at, vma_vdso->start, vdso_vma_size(sym_rt)); - vdso_rt_parked_at += vdso_vma_size(sym_rt); - ret |= vdso_remap("rt-vvar", vdso_rt_parked_at, vma_vvar->start, vvar_vma_size(sym_rt)); + ret = vdso_remap("rt-vdso", vdso_rt_parked_at, vma_vdso->start, sym_rt->vdso_size); + vdso_rt_parked_at += sym_rt->vdso_size; + ret |= vdso_remap("rt-vvar", vdso_rt_parked_at, vma_vvar->start, sym_rt->vvar_size); } else { - ret = vdso_remap("rt-vvar", vdso_rt_parked_at, vma_vvar->start, vvar_vma_size(sym_rt)); - vdso_rt_parked_at += vvar_vma_size(sym_rt); - ret |= vdso_remap("rt-vdso", vdso_rt_parked_at, vma_vdso->start, vdso_vma_size(sym_rt)); + ret = vdso_remap("rt-vvar", vdso_rt_parked_at, vma_vvar->start, sym_rt->vvar_size); + vdso_rt_parked_at += sym_rt->vvar_size; + ret |= vdso_remap("rt-vdso", vdso_rt_parked_at, vma_vdso->start, sym_rt->vdso_size); } } else - ret = vdso_remap("rt-vdso", vdso_rt_parked_at, vma_vdso->start, vdso_vma_size(sym_rt)); + ret = vdso_remap("rt-vdso", vdso_rt_parked_at, vma_vdso->start, sym_rt->vdso_size); return ret; } @@ -237,8 +237,8 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, * Don't forget to shift if vvar is before vdso. */ if (sym_rt->vvar_start != VDSO_BAD_ADDR && - sym_rt->vvar_start < sym_rt->vma_start) - vdso_rt_parked_at += vvar_vma_size(sym_rt); + sym_rt->vvar_start < sym_rt->vdso_start) + vdso_rt_parked_at += sym_rt->vvar_size; if (vdso_redirect_calls(vdso_rt_parked_at, vma_vdso->start, @@ -252,8 +252,8 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, * routine we could detect this vdso and do not dump it, since * it's auto-generated every new session if proxy required. */ - sys_mprotect((void *)vdso_rt_parked_at, vdso_vma_size(sym_rt), PROT_WRITE); + sys_mprotect((void *)vdso_rt_parked_at, sym_rt->vdso_size, PROT_WRITE); vdso_put_mark((void *)vdso_rt_parked_at, vma_vdso->start, vma_vvar ? vma_vvar->start : VVAR_BAD_ADDR); - sys_mprotect((void *)vdso_rt_parked_at, vdso_vma_size(sym_rt), VDSO_PROT); + sys_mprotect((void *)vdso_rt_parked_at, sym_rt->vdso_size, VDSO_PROT); return 0; } diff --git a/criu/vdso-compat.c b/criu/vdso-compat.c index 757377a15..9c9cca922 100644 --- a/criu/vdso-compat.c +++ b/criu/vdso-compat.c @@ -36,24 +36,21 @@ static void exit_on(int ret, int err_fd, char *reason) void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd, int err_fd, void *vdso_buf, size_t buf_size) { - size_t vma_size; void *vdso_addr; long vdso_size; long ret; - if (native->vma_start != VDSO_BAD_ADDR) { - vma_size = native->vma_end - native->vma_start; - ret = syscall(__NR_munmap, native->vma_start, vma_size); + if (native->vdso_start != VDSO_BAD_ADDR) { + ret = syscall(__NR_munmap, native->vdso_start, native->vdso_size); exit_on(ret, err_fd, "Error: Failed to unmap native vdso\n"); } if (native->vvar_start != VVAR_BAD_ADDR) { - vma_size = native->vvar_end - native->vvar_start; - ret = syscall(__NR_munmap, native->vvar_start, vma_size); + ret = syscall(__NR_munmap, native->vvar_start, native->vvar_size); exit_on(ret, err_fd, "Error: Failed to unmap native vvar\n"); } - ret = syscall(__NR_arch_prctl, ARCH_MAP_VDSO_32, native->vma_start); + ret = syscall(__NR_arch_prctl, ARCH_MAP_VDSO_32, native->vdso_start); if (ret < 0) exit_on(ret, err_fd, "Error: ARCH_MAP_VDSO failed\n"); diff --git a/criu/vdso.c b/criu/vdso.c index 7eb28ce7f..de5f22c07 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -28,9 +28,10 @@ #endif #define LOG_PREFIX "vdso: " -struct vdso_symtable vdso_sym_rt = VDSO_SYMTABLE_INIT; u64 vdso_pfn = VDSO_BAD_PFN; -struct vdso_symtable vdso_compat_rt = VDSO_SYMTABLE_INIT; +struct vdso_symtable vdso_sym_rt = VDSO_SYMTABLE_INIT; +struct vdso_symtable vdso_compat_rt = VDSO_SYMTABLE_INIT; + /* * The VMAs list might have proxy vdso/vvar areas left * from previous dump/restore cycle so we need to detect @@ -266,19 +267,19 @@ static int vdso_parse_maps(pid_t pid, struct vdso_symtable *s) } if (has_vdso) { - if (s->vma_start != VDSO_BAD_ADDR) { + if (s->vdso_start != VDSO_BAD_ADDR) { pr_err("Got second vDSO entry\n"); goto err; } - s->vma_start = start; - s->vma_end = end; + s->vdso_start = start; + s->vdso_size = end - start; } else { if (s->vvar_start != VVAR_BAD_ADDR) { pr_err("Got second VVAR entry\n"); goto err; } s->vvar_start = start; - s->vvar_end = end; + s->vvar_size = end - start; } } @@ -290,6 +291,8 @@ err: static int validate_vdso_addr(struct vdso_symtable *s) { + unsigned long vdso_end = s->vdso_start + s->vdso_size; + unsigned long vvar_end = s->vvar_start + s->vvar_size; /* * Validate its structure -- for new vDSO format the * structure must be like @@ -303,10 +306,10 @@ static int validate_vdso_addr(struct vdso_symtable *s) * 7fffc3504000-7fffc3506000 r-xp 00000000 00:00 0 [vdso] * */ - if (s->vma_start != VDSO_BAD_ADDR) { + if (s->vdso_start != VDSO_BAD_ADDR) { if (s->vvar_start != VVAR_BAD_ADDR) { - if (s->vma_end != s->vvar_start && - s->vvar_end != s->vma_start) { + if (vdso_end != s->vvar_start && + vvar_end != s->vdso_start) { pr_err("Unexpected rt vDSO area bounds\n"); return -1; } @@ -325,15 +328,15 @@ static int vdso_fill_self_symtable(struct vdso_symtable *s) if (vdso_parse_maps(PROC_SELF, s)) return -1; - if (vdso_fill_symtable(s->vma_start, s->vma_end - s->vma_start, s)) + if (vdso_fill_symtable(s->vdso_start, s->vdso_size, s)) return -1; if (validate_vdso_addr(s)) return -1; pr_debug("rt [vdso] %lx-%lx [vvar] %lx-%lx\n", - s->vma_start, s->vma_end, - s->vvar_start, s->vvar_end); + s->vdso_start, s->vdso_start + s->vdso_size, + s->vvar_start, s->vvar_start + s->vvar_size); return 0; } @@ -391,8 +394,8 @@ static int vdso_mmap_compat(struct vdso_symtable *native, pr_perror("Failed to kill(SIGCONT) for compat vdso helper\n"); goto out_kill; } - if (write(fds[1], &compat->vma_start, sizeof(void *)) != - sizeof(compat->vma_start)) { + if (write(fds[1], &compat->vdso_start, sizeof(void *)) != + sizeof(compat->vdso_start)) { pr_perror("Failed write to pipe\n"); goto out_kill; } @@ -437,14 +440,14 @@ static int vdso_fill_compat_symtable(struct vdso_symtable *native, } if (vdso_fill_symtable_compat((uintptr_t)vdso_mmap, - compat->vma_end - compat->vma_start, compat)) { + compat->vdso_size, compat)) { pr_err("Failed to parse mmaped compatible vdso blob\n"); goto out_unmap; } pr_debug("compat [vdso] %lx-%lx [vvar] %lx-%lx\n", - compat->vma_start, compat->vma_end, - compat->vvar_start, compat->vvar_end); + compat->vdso_start, compat->vdso_start + compat->vdso_size, + compat->vvar_start, compat->vvar_start + compat->vvar_size); ret = 0; out_unmap: @@ -475,7 +478,7 @@ int vdso_init(void) if (kdat.pmap != PM_FULL) pr_info("VDSO detection turned off\n"); - else if (vaddr_to_pfn(vdso_sym_rt.vma_start, &vdso_pfn)) + else if (vaddr_to_pfn(vdso_sym_rt.vdso_start, &vdso_pfn)) return -1; return 0; From 8f386360f6f5a3f527ef02f81417a78eaa6d19b0 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 15 Jun 2017 19:36:07 +0300 Subject: [PATCH 0958/4375] vdso: Don't park vdso/vvar if restoree doesn't have them Let's just unmap criu's vdso & vvar if restoree doesn't have them. This could be fired e.g. by migrating task from vdso-disabled kernel to vdso-enabled one. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/parasite-vdso.c | 5 ++--- criu/pie/restorer.c | 23 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 5a97629d4..4442a1179 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -122,9 +122,8 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, if (!vma_vdso && !vma_vvar) { pr_info("No VVAR, no vDSO in image\n"); /* - * We don't have to unmap rt-vdso, rt-vvar as they will - * be unmapped with restorer blob in the end, - * see __export_unmap() + * We don't have to unmap rt-vdso, rt-vvar as we didn't + * park them previously. */ return 0; } diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index fb2b35f64..1a7c6c9eb 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1134,6 +1134,26 @@ static int wait_zombies(struct task_restore_args *task_args) return 0; } +static bool vdso_needs_parking(struct task_restore_args *args) +{ + unsigned int i; + + /* Compatible vDSO will be mapped, not moved */ + if (args->compatible_mode) + return false; + + /* Don't park rt-vdso or rt-vvar if dumpee doesn't have them */ + for (i = 0; i < args->vmas_n; i++) { + VmaEntry *vma = &args->vmas[i]; + + if (vma_entry_is(vma, VMA_AREA_VDSO) || + vma_entry_is(vma, VMA_AREA_VVAR)) + return true; + } + + return false; +} + /* * The main routine to restore task via sigreturn. * This one is very special, we never return there @@ -1191,8 +1211,7 @@ long __export_restore_task(struct task_restore_args *args) pr_debug("lazy-pages: uffd %d\n", args->uffd); } - if (!args->compatible_mode) { - /* Compatible vDSO will be mapped, not moved */ + if (vdso_needs_parking(args)) { if (vdso_do_park(&args->vdso_sym_rt, args->vdso_rt_parked_at, vdso_rt_size)) goto core_restore_end; From 17644ff3c86391c21c17724416659196d54661a0 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 15 Jun 2017 19:36:08 +0300 Subject: [PATCH 0959/4375] zdtm/vdso: Add test for restoring task without vdso blob Check that task without vvar & vdso blobs is restored without them. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/vdso02.c | 231 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 test/zdtm/static/vdso02.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 2f26818d2..12962c21d 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -54,6 +54,7 @@ TST_NOFILE := \ pthread02 \ vdso00 \ vdso01 \ + vdso02 \ utsname \ pstree \ sockets01 \ diff --git a/test/zdtm/static/vdso02.c b/test/zdtm/static/vdso02.c new file mode 100644 index 000000000..f0047bc2c --- /dev/null +++ b/test/zdtm/static/vdso02.c @@ -0,0 +1,231 @@ +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Restoring task with unmapped vDSO blob. Poor man's test for C/R on vdso64_enabled=0 booted kernel.\n"; +const char *test_author = "Dmitry Safonov "; + +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) +#define VDSO_BAD_ADDR (-1ul) +#define VVAR_BAD_ADDR (-1ul) +#define BUF_SZ 1024 + +struct vm_area { + unsigned long start; + unsigned long end; +}; + +static int parse_vm_area(char *buf, struct vm_area *vma) +{ + if (sscanf(buf, "%lx-%lx", &vma->start, &vma->end) == 2) + return 0; + + pr_perror("Can't find VMA bounds"); + return -1; +} + +static int find_blobs(pid_t pid, struct vm_area *vdso, struct vm_area *vvar) +{ + char buf[BUF_SZ]; + int ret = -1; + FILE *maps; + + vdso->start = VDSO_BAD_ADDR; + vdso->end = VDSO_BAD_ADDR; + vvar->start = VVAR_BAD_ADDR; + vvar->end = VVAR_BAD_ADDR; + + if (snprintf(buf, BUF_SZ, "/proc/%d/maps", pid) < 0) { + pr_perror("snprintf() failure for path"); + return -1; + } + + maps = fopen(buf, "r"); + if (!maps) { + pr_perror("Can't open maps for %d", pid); + return -1; + } + + while (fgets(buf, sizeof(buf), maps)) { + if (strstr(buf, "[vdso]") && parse_vm_area(buf, vdso)) + goto err; + + if (strstr(buf, "[vvar]") && parse_vm_area(buf, vvar)) + goto err; + } + + if (vdso->start != VDSO_BAD_ADDR) + test_msg("[vdso] %lx-%lx\n", vdso->start, vdso->end); + if (vvar->start != VVAR_BAD_ADDR) + test_msg("[vvar] %lx-%lx\n", vvar->start, vvar->end); + ret = 0; +err: + fclose(maps); + return ret; +} + +#ifdef __i386__ +/* + * On i386 syscalls for speed are optimized trough vdso, + * call raw int80 as vdso is unmapped. + */ +#define __NR32_munmap 91 +#define __NR32_kill 37 +#define __NR32_exit 1 +struct syscall_args32 { + uint32_t nr, arg0, arg1; +}; + +static inline void do_full_int80(struct syscall_args32 *args) +{ + asm volatile ( + "int $0x80\n\t" + : "+a" (args->nr), + "+b" (args->arg0), "+c" (args->arg1)); +} + +int sys_munmap(void *addr, size_t len) +{ + struct syscall_args32 s = {0}; + + s.nr = __NR32_munmap; + s.arg0 = (uint32_t)(uintptr_t)addr; + s.arg1 = (uint32_t)len; + + do_full_int80(&s); + + return (int)s.nr; +} + +int sys_kill(pid_t pid, int sig) +{ + struct syscall_args32 s = {0}; + + s.nr = __NR32_kill; + s.arg0 = (uint32_t)pid; + s.arg1 = (uint32_t)sig; + + do_full_int80(&s); + + return (int)s.nr; +} + +void sys_exit(int status) +{ + struct syscall_args32 s = {0}; + + s.nr = __NR32_exit; + s.arg0 = (uint32_t)status; + + do_full_int80(&s); +} + +#else /* !__i386__ */ + +int sys_munmap(void *addr, size_t len) +{ + return syscall(SYS_munmap, addr, len); +} + +int sys_kill(pid_t pid, int sig) +{ + return syscall(SYS_kill, pid, sig); +} + +void sys_exit(int status) +{ + syscall(SYS_exit, status); +} + +#endif + +static int unmap_blobs(void) +{ + struct vm_area vdso, vvar; + int ret; + + if (find_blobs(getpid(), &vdso, &vvar)) + return -1; + + if (vdso.start != VDSO_BAD_ADDR) { + ret = sys_munmap((void*)vdso.start, vdso.end - vdso.start); + if (ret) + return ret; + } + if (vvar.start != VVAR_BAD_ADDR) { + ret = sys_munmap((void*)vvar.start, vvar.end - vvar.start); + if (ret) + return ret; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + struct vm_area vdso, vvar; + pid_t child; + int status, ret = -1; + + test_init(argc, argv); + + child = fork(); + if (child < 0) { + pr_perror("fork() failed"); + exit(1); + } + + if (child == 0) { + child = getpid(); + if (unmap_blobs() < 0) + syscall(SYS_exit, 1); + sys_kill(child, SIGSTOP); + sys_exit(2); + } + + waitpid(child, &status, WUNTRACED); + if (WIFEXITED(status)) { + int ret = WEXITSTATUS(status); + + pr_err("Child unexpectedly exited with %d\n", ret); + goto out_kill; + } else if (WIFSIGNALED(status)) { + int sig = WTERMSIG(status); + + pr_err("Child unexpectedly signaled with %d: %s\n", + sig, strsignal(sig)); + goto out_kill; + } else if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) { + pr_err("Child is unstoppable or was stopped by other means\n"); + goto out_kill; + } + + if (find_blobs(child, &vdso, &vvar)) + goto out_kill; + if (vdso.start != VDSO_BAD_ADDR || vvar.start != VVAR_BAD_ADDR) { + pr_err("Found vvar or vdso blob(s) in child, which should have unmapped them\n"); + goto out_kill; + } + + test_daemon(); + test_waitsig(); + + if (find_blobs(child, &vdso, &vvar)) + goto out_kill; + if (vdso.start != VDSO_BAD_ADDR || vvar.start != VVAR_BAD_ADDR) { + pr_err("Child without vdso got it after C/R\n"); + fail(); + goto out_kill; + } + + pass(); + + ret = 0; +out_kill: + kill(child, SIGKILL); + return ret; +} From 641407f6056426d44fdb24aa4bd5c0b734ad98b9 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 15 Jun 2017 19:36:09 +0300 Subject: [PATCH 0960/4375] vdso/restorer: Simplify vdso/vvar order checking Ordering check for vvar/vdso blobs was introduced with the commit b00bdb2dbc31 ("vdso: x86 -- Test VMAs order in vdso_proxify") Let's simplify it to more readable version. As above we've compared that vvar/vdso's blob size from dumpee matches sizes of rt-vvar/rt-vdso, kill that xor here. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/parasite-vdso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 4442a1179..4d77a86d7 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -171,7 +171,7 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, long delta_rt = sym_rt->vvar_start - sym_rt->vdso_start; long delta_this = vma_vvar->start - vma_vdso->start; - remap_rt = (delta_rt ^ delta_this) < 0 ? false : true; + remap_rt = (delta_rt == delta_this); } } else remap_rt = true; From ba9639215f5b1f00b286acf9c0e0c984ae32cf5a Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 15 Jun 2017 19:36:10 +0300 Subject: [PATCH 0961/4375] vdso/restore: Separate vdso/vvar blobs comparing logic Make a function which decides if we need to insert jump trampolines, or if the blobs are equal and just a remap if enough. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/parasite-vdso.c | 71 +++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 4d77a86d7..31b7f8d93 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -103,13 +103,48 @@ int __vdso_fill_symtable(uintptr_t mem, size_t size, } #endif +/* + * Proxification strategy + * + * - There might be two vDSO zones: vdso code and optionally vvar data + * - To be able to use in-place remapping we need + * + * a) Size and order of vDSO zones are to match + * b) Symbols offsets must match + * c) Have same number of vDSO zones + */ +static bool blobs_matches(VmaEntry *vdso_img, VmaEntry *vvar_img, + struct vdso_symtable *sym_img, struct vdso_symtable *sym_rt) +{ + size_t i; + + if (vma_entry_len(vdso_img) != sym_rt->vdso_size) + return false; + + for (i = 0; i < ARRAY_SIZE(sym_img->symbols); i++) { + if (sym_img->symbols[i].offset != sym_rt->symbols[i].offset) + return false; + } + + if (vvar_img && sym_rt->vvar_start != VVAR_BAD_ADDR) { + long delta_rt = sym_rt->vvar_start - sym_rt->vdso_start; + long delta_img = vvar_img->start - vdso_img->start; + + if (sym_rt->vvar_size != vma_entry_len(vvar_img)) + return false; + + return delta_rt == delta_img; + } + + return true; +} + int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso, bool force_trampolines) { VmaEntry *vma_vdso = NULL, *vma_vvar = NULL; struct vdso_symtable s = VDSO_SYMTABLE_INIT; - bool remap_rt = false; unsigned int i; for (i = 0; i < nr_vmas; i++) { @@ -146,38 +181,6 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, vma_entry_len(vma_vdso), &s, compat_vdso)) return -1; - /* - * Proxification strategy - * - * - There might be two vDSO zones: vdso code and optionally vvar data - * - To be able to use in-place remapping we need - * - * a) Size and order of vDSO zones are to match - * b) Symbols offsets must match - * c) Have same number of vDSO zones - */ - if (vma_entry_len(vma_vdso) == sym_rt->vdso_size) { - size_t i; - - for (i = 0; i < ARRAY_SIZE(s.symbols); i++) { - if (s.symbols[i].offset != sym_rt->symbols[i].offset) - break; - } - - if (i == ARRAY_SIZE(s.symbols)) { - if (vma_vvar && sym_rt->vvar_start != VVAR_BAD_ADDR) { - remap_rt = (sym_rt->vvar_size == vma_entry_len(vma_vvar)); - if (remap_rt) { - long delta_rt = sym_rt->vvar_start - sym_rt->vdso_start; - long delta_this = vma_vvar->start - vma_vdso->start; - - remap_rt = (delta_rt == delta_this); - } - } else - remap_rt = true; - } - } - pr_debug("image [vdso] %lx-%lx [vvar] %lx-%lx\n", (unsigned long)vma_vdso->start, (unsigned long)vma_vdso->end, vma_vvar ? (unsigned long)vma_vvar->start : VVAR_BAD_ADDR, @@ -192,7 +195,7 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, * by a caller code. So drop VMA_AREA_REGULAR from it and caller would * not touch it anymore. */ - if (remap_rt && !force_trampolines) { + if (blobs_matches(vma_vdso, vma_vvar, &s, sym_rt) && !force_trampolines) { int ret = 0; pr_info("Runtime vdso/vvar matches dumpee, remap inplace\n"); From 06f846b751277068a8d9e8890fb33d69d244faa0 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 15 Jun 2017 19:36:11 +0300 Subject: [PATCH 0962/4375] vdso: Save vdso/vvar pair order inside vdso_symtable I plan to keep boot-persistent vdso_symtable inside kdat, moving {vvar,vdso}_start addresses out into new structure. As order of vdso/vvar is preserved across one booting store it inside of vdso_symtable. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/util-vdso.h | 2 ++ criu/pie/parasite-vdso.c | 12 +++++------- criu/vdso.c | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/criu/include/util-vdso.h b/criu/include/util-vdso.h index 4f734593c..6e7182ba1 100644 --- a/criu/include/util-vdso.h +++ b/criu/include/util-vdso.h @@ -33,6 +33,7 @@ struct vdso_symtable { unsigned long vvar_start; unsigned long vvar_size; struct vdso_symbol symbols[VDSO_SYMBOL_MAX]; + bool vdso_before_vvar; /* order of vdso/vvar pair */ }; #define VDSO_SYMBOL_INIT { .offset = VDSO_BAD_ADDR, } @@ -47,6 +48,7 @@ struct vdso_symtable { [0 ... VDSO_SYMBOL_MAX - 1] = \ (struct vdso_symbol)VDSO_SYMBOL_INIT, \ }, \ + .vdso_before_vvar = false, \ } #ifdef CONFIG_VDSO_32 diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 31b7f8d93..05aa973b2 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -48,8 +48,8 @@ int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned l BUG_ON((sym_rt->vdso_size + sym_rt->vvar_size) < park_size); - if (sym_rt->vvar_start != VDSO_BAD_ADDR) { - if (sym_rt->vdso_start < sym_rt->vvar_start) { + if (sym_rt->vvar_start != VVAR_BAD_ADDR) { + if (sym_rt->vdso_before_vvar) { ret = vdso_remap("rt-vdso", sym_rt->vdso_start, park_at, sym_rt->vdso_size); park_at += sym_rt->vdso_size; @@ -127,13 +127,12 @@ static bool blobs_matches(VmaEntry *vdso_img, VmaEntry *vvar_img, } if (vvar_img && sym_rt->vvar_start != VVAR_BAD_ADDR) { - long delta_rt = sym_rt->vvar_start - sym_rt->vdso_start; - long delta_img = vvar_img->start - vdso_img->start; + bool vdso_firstly = (vvar_img->start > vdso_img->start); if (sym_rt->vvar_size != vma_entry_len(vvar_img)) return false; - return delta_rt == delta_img; + return (vdso_firstly == sym_rt->vdso_before_vvar); } return true; @@ -238,8 +237,7 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, /* * Don't forget to shift if vvar is before vdso. */ - if (sym_rt->vvar_start != VDSO_BAD_ADDR && - sym_rt->vvar_start < sym_rt->vdso_start) + if (sym_rt->vvar_start != VDSO_BAD_ADDR && !sym_rt->vdso_before_vvar) vdso_rt_parked_at += sym_rt->vvar_size; if (vdso_redirect_calls(vdso_rt_parked_at, diff --git a/criu/vdso.c b/criu/vdso.c index de5f22c07..d6e47cf81 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -283,6 +283,9 @@ static int vdso_parse_maps(pid_t pid, struct vdso_symtable *s) } } + if (s->vdso_start != VDSO_BAD_ADDR && s->vvar_start != VVAR_BAD_ADDR) + s->vdso_before_vvar = (s->vdso_start < s->vvar_start); + exit_code = 0; err: bclose(&f); From 1fdaed0a09d83645d71e463c1eb05ef1dbc38275 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 15 Jun 2017 19:36:12 +0300 Subject: [PATCH 0963/4375] vdso: Exclude {vdso, vvar}_start from vdso_symtable Preparation for saving vdso_symtable in kdat, which will allow skip parsing of native and compat symtables - that at least will save from running compat helper each criu launch. As {vvar,vdso}_start are randomized with ASLR, there is no point in saving them into kdat. We'll still need to reread them from /proc/self/maps for awhile. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 14 +++++----- criu/include/parasite-vdso.h | 3 ++- criu/include/restorer.h | 2 +- criu/include/util-vdso.h | 17 +++++++++--- criu/include/vdso.h | 6 ++--- criu/pie/parasite-vdso.c | 36 ++++++++++++------------- criu/pie/restorer.c | 4 +-- criu/vdso-compat.c | 8 +++--- criu/vdso.c | 52 ++++++++++++++++++------------------ 9 files changed, 77 insertions(+), 65 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index a6b2c9733..6fe9057da 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3037,7 +3037,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns struct restore_mem_zone *mz; #ifdef CONFIG_VDSO - struct vdso_symtable vdso_symtab_rt; + struct vdso_maps vdso_maps_rt; unsigned long vdso_rt_size = 0; #endif @@ -3083,15 +3083,15 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns #ifdef CONFIG_VDSO if (core_is_compat(core)) - vdso_symtab_rt = vdso_compat_rt; + vdso_maps_rt = vdso_maps_compat; else - vdso_symtab_rt = vdso_sym_rt; + vdso_maps_rt = vdso_maps; /* * Figure out how much memory runtime vdso and vvar will need. */ - vdso_rt_size = vdso_symtab_rt.vdso_size; - if (vdso_rt_size && vdso_symtab_rt.vvar_size) - vdso_rt_size += ALIGN(vdso_symtab_rt.vvar_size, PAGE_SIZE); + vdso_rt_size = vdso_maps_rt.sym.vdso_size; + if (vdso_rt_size && vdso_maps_rt.sym.vvar_size) + vdso_rt_size += ALIGN(vdso_maps_rt.sym.vvar_size, PAGE_SIZE); task_args->bootstrap_len += vdso_rt_size; #endif @@ -3308,7 +3308,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns */ mem += rst_mem_size; task_args->vdso_rt_parked_at = (unsigned long)mem; - task_args->vdso_sym_rt = vdso_symtab_rt; + task_args->vdso_maps_rt = vdso_maps_rt; task_args->vdso_rt_size = vdso_rt_size; #endif diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index 3dad9404d..2a7f10ed2 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -79,7 +79,8 @@ static inline bool is_vdso_mark(void *addr) return false; } -extern int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned long park_size); +extern int vdso_do_park(struct vdso_maps *rt, unsigned long park_at, + unsigned long park_size); extern int vdso_map_compat(unsigned long map_at); extern int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, diff --git a/criu/include/restorer.h b/criu/include/restorer.h index cad8cdf7b..789064ee1 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -193,7 +193,7 @@ struct task_restore_args { #ifdef CONFIG_VDSO unsigned long vdso_rt_size; - struct vdso_symtable vdso_sym_rt; /* runtime vdso symbols */ + struct vdso_maps vdso_maps_rt; /* runtime vdso symbols */ unsigned long vdso_rt_parked_at; /* safe place to keep vdso */ #endif void **breakpoint; diff --git a/criu/include/util-vdso.h b/criu/include/util-vdso.h index 6e7182ba1..1318a5956 100644 --- a/criu/include/util-vdso.h +++ b/criu/include/util-vdso.h @@ -28,21 +28,23 @@ struct vdso_symbol { }; struct vdso_symtable { - unsigned long vdso_start; unsigned long vdso_size; - unsigned long vvar_start; unsigned long vvar_size; struct vdso_symbol symbols[VDSO_SYMBOL_MAX]; bool vdso_before_vvar; /* order of vdso/vvar pair */ }; +struct vdso_maps { + unsigned long vdso_start; + unsigned long vvar_start; + struct vdso_symtable sym; +}; + #define VDSO_SYMBOL_INIT { .offset = VDSO_BAD_ADDR, } #define VDSO_SYMTABLE_INIT \ { \ - .vdso_start = VDSO_BAD_ADDR, \ .vdso_size = VDSO_BAD_SIZE, \ - .vvar_start = VVAR_BAD_ADDR, \ .vvar_size = VVAR_BAD_SIZE, \ .symbols = { \ [0 ... VDSO_SYMBOL_MAX - 1] = \ @@ -51,6 +53,13 @@ struct vdso_symtable { .vdso_before_vvar = false, \ } +#define VDSO_MAPS_INIT \ + { \ + .vdso_start = VDSO_BAD_ADDR, \ + .vvar_start = VVAR_BAD_ADDR, \ + .sym = VDSO_SYMTABLE_INIT, \ + } + #ifdef CONFIG_VDSO_32 #define Ehdr_t Elf32_Ehdr diff --git a/criu/include/vdso.h b/criu/include/vdso.h index c4f8974e9..731738425 100644 --- a/criu/include/vdso.h +++ b/criu/include/vdso.h @@ -10,8 +10,8 @@ #include "util-vdso.h" -extern struct vdso_symtable vdso_sym_rt; -extern struct vdso_symtable vdso_compat_rt; +extern struct vdso_maps vdso_maps; +extern struct vdso_maps vdso_maps_compat; extern int vdso_init(void); @@ -19,7 +19,7 @@ extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct vm_area_list *vma_area_list); #ifdef CONFIG_COMPAT -extern void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd, +extern void compat_vdso_helper(struct vdso_maps *native, int pipe_fd, int err_fd, void *vdso_buf, size_t buf_size); #endif diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 05aa973b2..40b269595 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -42,29 +42,29 @@ static int vdso_remap(char *who, unsigned long from, unsigned long to, size_t si } /* Park runtime vDSO in some safe place where it can be accessible from restorer */ -int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned long park_size) +int vdso_do_park(struct vdso_maps *rt, unsigned long park_at, unsigned long park_size) { int ret; - BUG_ON((sym_rt->vdso_size + sym_rt->vvar_size) < park_size); + BUG_ON((rt->sym.vdso_size + rt->sym.vvar_size) < park_size); - if (sym_rt->vvar_start != VVAR_BAD_ADDR) { - if (sym_rt->vdso_before_vvar) { - ret = vdso_remap("rt-vdso", sym_rt->vdso_start, - park_at, sym_rt->vdso_size); - park_at += sym_rt->vdso_size; - ret |= vdso_remap("rt-vvar", sym_rt->vvar_start, - park_at, sym_rt->vvar_size); + if (rt->vvar_start != VVAR_BAD_ADDR) { + if (rt->sym.vdso_before_vvar) { + ret = vdso_remap("rt-vdso", rt->vdso_start, + park_at, rt->sym.vdso_size); + park_at += rt->sym.vdso_size; + ret |= vdso_remap("rt-vvar", rt->vvar_start, + park_at, rt->sym.vvar_size); } else { - ret = vdso_remap("rt-vvar", sym_rt->vvar_start, - park_at, sym_rt->vvar_size); - park_at += sym_rt->vvar_size; - ret |= vdso_remap("rt-vdso", sym_rt->vdso_start, - park_at, sym_rt->vdso_size); + ret = vdso_remap("rt-vvar", rt->vvar_start, + park_at, rt->sym.vvar_size); + park_at += rt->sym.vvar_size; + ret |= vdso_remap("rt-vdso", rt->vdso_start, + park_at, rt->sym.vdso_size); } } else - ret = vdso_remap("rt-vdso", sym_rt->vdso_start, - park_at, sym_rt->vdso_size); + ret = vdso_remap("rt-vdso", rt->vdso_start, + park_at, rt->sym.vdso_size); return ret; } @@ -126,7 +126,7 @@ static bool blobs_matches(VmaEntry *vdso_img, VmaEntry *vvar_img, return false; } - if (vvar_img && sym_rt->vvar_start != VVAR_BAD_ADDR) { + if (vvar_img && sym_rt->vvar_size != VVAR_BAD_SIZE) { bool vdso_firstly = (vvar_img->start > vdso_img->start); if (sym_rt->vvar_size != vma_entry_len(vvar_img)) @@ -237,7 +237,7 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, /* * Don't forget to shift if vvar is before vdso. */ - if (sym_rt->vvar_start != VDSO_BAD_ADDR && !sym_rt->vdso_before_vvar) + if (sym_rt->vvar_size != VDSO_BAD_SIZE && !sym_rt->vdso_before_vvar) vdso_rt_parked_at += sym_rt->vvar_size; if (vdso_redirect_calls(vdso_rt_parked_at, diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 1a7c6c9eb..f33401e06 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1212,7 +1212,7 @@ long __export_restore_task(struct task_restore_args *args) } if (vdso_needs_parking(args)) { - if (vdso_do_park(&args->vdso_sym_rt, + if (vdso_do_park(&args->vdso_maps_rt, args->vdso_rt_parked_at, vdso_rt_size)) goto core_restore_end; } @@ -1345,7 +1345,7 @@ long __export_restore_task(struct task_restore_args *args) /* * Proxify vDSO. */ - if (vdso_proxify(&args->vdso_sym_rt, args->vdso_rt_parked_at, + if (vdso_proxify(&args->vdso_maps_rt.sym, args->vdso_rt_parked_at, args->vmas, args->vmas_n, args->compatible_mode, fault_injected(FI_VDSO_TRAMPOLINES))) goto core_restore_end; diff --git a/criu/vdso-compat.c b/criu/vdso-compat.c index 9c9cca922..6d7632814 100644 --- a/criu/vdso-compat.c +++ b/criu/vdso-compat.c @@ -33,7 +33,7 @@ static void exit_on(int ret, int err_fd, char *reason) * WARN: This helper shouldn't call pr_err() or any syscall with * Glibc's wrapper function - it may very likely blow up. */ -void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd, +void compat_vdso_helper(struct vdso_maps *native, int pipe_fd, int err_fd, void *vdso_buf, size_t buf_size) { void *vdso_addr; @@ -41,12 +41,14 @@ void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd, long ret; if (native->vdso_start != VDSO_BAD_ADDR) { - ret = syscall(__NR_munmap, native->vdso_start, native->vdso_size); + ret = syscall(__NR_munmap, + native->vdso_start, native->sym.vdso_size); exit_on(ret, err_fd, "Error: Failed to unmap native vdso\n"); } if (native->vvar_start != VVAR_BAD_ADDR) { - ret = syscall(__NR_munmap, native->vvar_start, native->vvar_size); + ret = syscall(__NR_munmap, + native->vvar_start, native->sym.vvar_size); exit_on(ret, err_fd, "Error: Failed to unmap native vvar\n"); } diff --git a/criu/vdso.c b/criu/vdso.c index d6e47cf81..b9de571ab 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -29,8 +29,8 @@ #define LOG_PREFIX "vdso: " u64 vdso_pfn = VDSO_BAD_PFN; -struct vdso_symtable vdso_sym_rt = VDSO_SYMTABLE_INIT; -struct vdso_symtable vdso_compat_rt = VDSO_SYMTABLE_INIT; +struct vdso_maps vdso_maps = VDSO_MAPS_INIT; +struct vdso_maps vdso_maps_compat = VDSO_MAPS_INIT; /* * The VMAs list might have proxy vdso/vvar areas left @@ -227,13 +227,13 @@ err: return exit_code; } -static int vdso_parse_maps(pid_t pid, struct vdso_symtable *s) +static int vdso_parse_maps(pid_t pid, struct vdso_maps *s) { int exit_code = -1; char *buf; struct bfd f; - *s = (struct vdso_symtable)VDSO_SYMTABLE_INIT; + *s = (struct vdso_maps)VDSO_MAPS_INIT; f.fd = open_proc(pid, "maps"); if (f.fd < 0) @@ -272,19 +272,19 @@ static int vdso_parse_maps(pid_t pid, struct vdso_symtable *s) goto err; } s->vdso_start = start; - s->vdso_size = end - start; + s->sym.vdso_size = end - start; } else { if (s->vvar_start != VVAR_BAD_ADDR) { pr_err("Got second VVAR entry\n"); goto err; } s->vvar_start = start; - s->vvar_size = end - start; + s->sym.vvar_size = end - start; } } if (s->vdso_start != VDSO_BAD_ADDR && s->vvar_start != VVAR_BAD_ADDR) - s->vdso_before_vvar = (s->vdso_start < s->vvar_start); + s->sym.vdso_before_vvar = (s->vdso_start < s->vvar_start); exit_code = 0; err: @@ -292,10 +292,10 @@ err: return exit_code; } -static int validate_vdso_addr(struct vdso_symtable *s) +static int validate_vdso_addr(struct vdso_maps *s) { - unsigned long vdso_end = s->vdso_start + s->vdso_size; - unsigned long vvar_end = s->vvar_start + s->vvar_size; + unsigned long vdso_end = s->vdso_start + s->sym.vdso_size; + unsigned long vvar_end = s->vvar_start + s->sym.vvar_size; /* * Validate its structure -- for new vDSO format the * structure must be like @@ -325,28 +325,28 @@ static int validate_vdso_addr(struct vdso_symtable *s) return 0; } -static int vdso_fill_self_symtable(struct vdso_symtable *s) +static int vdso_fill_self_symtable(struct vdso_maps *s) { if (vdso_parse_maps(PROC_SELF, s)) return -1; - if (vdso_fill_symtable(s->vdso_start, s->vdso_size, s)) + if (vdso_fill_symtable(s->vdso_start, s->sym.vdso_size, &s->sym)) return -1; if (validate_vdso_addr(s)) return -1; pr_debug("rt [vdso] %lx-%lx [vvar] %lx-%lx\n", - s->vdso_start, s->vdso_start + s->vdso_size, - s->vvar_start, s->vvar_start + s->vvar_size); + s->vdso_start, s->vdso_start + s->sym.vdso_size, + s->vvar_start, s->vvar_start + s->sym.vvar_size); return 0; } #ifdef CONFIG_COMPAT -static int vdso_mmap_compat(struct vdso_symtable *native, - struct vdso_symtable *compat, void *vdso_buf, size_t buf_size) +static int vdso_mmap_compat(struct vdso_maps *native, + struct vdso_maps *compat, void *vdso_buf, size_t buf_size) { pid_t pid; int status, ret = -1; @@ -421,8 +421,8 @@ out_close: } #define COMPAT_VDSO_BUF_SZ (PAGE_SIZE*2) -static int vdso_fill_compat_symtable(struct vdso_symtable *native, - struct vdso_symtable *compat) +static int vdso_fill_compat_symtable(struct vdso_maps *native, + struct vdso_maps *compat) { void *vdso_mmap; int ret = -1; @@ -443,14 +443,14 @@ static int vdso_fill_compat_symtable(struct vdso_symtable *native, } if (vdso_fill_symtable_compat((uintptr_t)vdso_mmap, - compat->vdso_size, compat)) { + compat->sym.vdso_size, &compat->sym)) { pr_err("Failed to parse mmaped compatible vdso blob\n"); goto out_unmap; } pr_debug("compat [vdso] %lx-%lx [vvar] %lx-%lx\n", - compat->vdso_start, compat->vdso_start + compat->vdso_size, - compat->vvar_start, compat->vvar_start + compat->vvar_size); + compat->vdso_start, compat->vdso_start + compat->sym.vdso_size, + compat->vvar_start, compat->vvar_start + compat->sym.vvar_size); ret = 0; out_unmap: @@ -460,8 +460,8 @@ out_unmap: } #else /* CONFIG_COMPAT */ -static int vdso_fill_compat_symtable(struct vdso_symtable *native, - struct vdso_symtable *compat) +static int vdso_fill_compat_symtable(struct vdso_maps *native, + struct vdso_maps *compat) { return 0; } @@ -469,19 +469,19 @@ static int vdso_fill_compat_symtable(struct vdso_symtable *native, int vdso_init(void) { - if (vdso_fill_self_symtable(&vdso_sym_rt)) { + if (vdso_fill_self_symtable(&vdso_maps)) { pr_err("Failed to fill self vdso symtable\n"); return -1; } - if (vdso_fill_compat_symtable(&vdso_sym_rt, &vdso_compat_rt)) { + if (vdso_fill_compat_symtable(&vdso_maps, &vdso_maps_compat)) { pr_err("Failed to fill compat vdso symtable\n"); return -1; } if (kdat.pmap != PM_FULL) pr_info("VDSO detection turned off\n"); - else if (vaddr_to_pfn(vdso_sym_rt.vdso_start, &vdso_pfn)) + else if (vaddr_to_pfn(vdso_maps.vdso_start, &vdso_pfn)) return -1; return 0; From 69a66e1397a3ab35ee7a0552ca0073f0d920778a Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 15 Jun 2017 19:36:13 +0300 Subject: [PATCH 0964/4375] vdso: Move parsing of self/maps outside vdso_fill_self_symtable() As ASLR randomizes {vdso,vvar}_start between criu launches, vdso_parse_maps() should be called each launch: - on restore to know {vdso,vvar}_start position for later parking in restorer's save zone - on checkpointing to get vdso's pfn for pre-v3.16 kernels which lose "[vdso]" hint in maps file. But vdso_fill_symtable() call may be omitted if symtable is inside kdat file. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/vdso.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index b9de571ab..f20703b1f 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -327,8 +327,7 @@ static int validate_vdso_addr(struct vdso_maps *s) static int vdso_fill_self_symtable(struct vdso_maps *s) { - - if (vdso_parse_maps(PROC_SELF, s)) + if (s->vdso_start == VDSO_BAD_ADDR || s->sym.vdso_size == VDSO_BAD_SIZE) return -1; if (vdso_fill_symtable(s->vdso_start, s->sym.vdso_size, &s->sym)) @@ -469,6 +468,11 @@ static int vdso_fill_compat_symtable(struct vdso_maps *native, int vdso_init(void) { + if (vdso_parse_maps(PROC_SELF, &vdso_maps)) { + pr_err("Failed reading self/maps for filling vdso/vvar bounds\n"); + return -1; + } + if (vdso_fill_self_symtable(&vdso_maps)) { pr_err("Failed to fill self vdso symtable\n"); return -1; From 78402658c25160eb65e1dca0d7c3f8bfbdab894b Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 15 Jun 2017 19:36:14 +0300 Subject: [PATCH 0965/4375] vdso: Separate vdso_init() on dump/restore On dump we only need vdso_pfn to be filled, on restore we need filled symtables. That means, that we can omit filling symtables on dump, which also means no need in calling compat_vdso_helper process with fork(), pipe(), read(), write() and so on syscalls. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 4 ++-- criu/cr-restore.c | 2 +- criu/include/vdso.h | 6 ++++-- criu/vdso.c | 22 ++++++++++++++++------ 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 985a64ba5..8c8a11c21 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1562,7 +1562,7 @@ int cr_pre_dump_tasks(pid_t pid) if (cpu_init()) goto err; - if (vdso_init()) + if (vdso_init_dump()) goto err; if (connect_to_page_server_to_send() < 0) @@ -1738,7 +1738,7 @@ int cr_dump_tasks(pid_t pid) if (cpu_init()) goto err; - if (vdso_init()) + if (vdso_init_dump()) goto err; if (cgp_init(opts.cgroup_props, diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 6fe9057da..d1d2b3e63 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2205,7 +2205,7 @@ int cr_restore_tasks(void) if (cpu_init() < 0) goto err; - if (vdso_init()) + if (vdso_init_restore()) goto err; if (opts.cpu_cap & (CPU_CAP_INS | CPU_CAP_CPU)) { diff --git a/criu/include/vdso.h b/criu/include/vdso.h index 731738425..6a9752bd1 100644 --- a/criu/include/vdso.h +++ b/criu/include/vdso.h @@ -13,7 +13,8 @@ extern struct vdso_maps vdso_maps; extern struct vdso_maps vdso_maps_compat; -extern int vdso_init(void); +extern int vdso_init_dump(void); +extern int vdso_init_restore(void); extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct vm_area_list *vma_area_list); @@ -25,7 +26,8 @@ extern void compat_vdso_helper(struct vdso_maps *native, int pipe_fd, #else /* CONFIG_VDSO */ -#define vdso_init() (0) +#define vdso_init_dump() (0) +#define vdso_init_restore() (0) #define parasite_fixup_vdso(ctl, pid, vma_area_list) (0) #endif /* CONFIG_VDSO */ diff --git a/criu/vdso.c b/criu/vdso.c index f20703b1f..da3da69f4 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -466,7 +466,22 @@ static int vdso_fill_compat_symtable(struct vdso_maps *native, } #endif /* CONFIG_COMPAT */ -int vdso_init(void) +int vdso_init_dump(void) +{ + if (vdso_parse_maps(PROC_SELF, &vdso_maps)) { + pr_err("Failed reading self/maps for filling vdso/vvar bounds\n"); + return -1; + } + + if (kdat.pmap != PM_FULL) + pr_info("VDSO detection turned off\n"); + else if (vaddr_to_pfn(vdso_maps.vdso_start, &vdso_pfn)) + return -1; + + return 0; +} + +int vdso_init_restore(void) { if (vdso_parse_maps(PROC_SELF, &vdso_maps)) { pr_err("Failed reading self/maps for filling vdso/vvar bounds\n"); @@ -483,10 +498,5 @@ int vdso_init(void) return -1; } - if (kdat.pmap != PM_FULL) - pr_info("VDSO detection turned off\n"); - else if (vaddr_to_pfn(vdso_maps.vdso_start, &vdso_pfn)) - return -1; - return 0; } From 7ad5df9e9fe87c17d7436ea440f0baccfcd24f07 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 15 Jun 2017 19:36:15 +0300 Subject: [PATCH 0966/4375] vdso/kdat: Store symtable in kerndat_s Don't need to parse vdso symtable each restore - it's boot-persistent, so move it into criu.kdat file on tmpfs. That will also remove syscalls made for filling compat vdso symtable by compat vdso helper. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/kerndat.h | 9 +++++++ criu/include/vdso.h | 2 ++ criu/kerndat.c | 4 +++ criu/vdso.c | 57 ++++++++++++++++++++++++++++++++++++------ 4 files changed, 65 insertions(+), 7 deletions(-) diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 946e81a9a..014cf87af 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -5,6 +5,9 @@ #include "int.h" #include "config.h" +#ifdef CONFIG_VDSO +#include "util-vdso.h" +#endif struct stat; @@ -52,6 +55,12 @@ struct kerndat_s { bool has_uffd; unsigned long uffd_features; bool has_thp_disable; +#ifdef CONFIG_VDSO + struct vdso_symtable vdso_sym; +#ifdef CONFIG_COMPAT + struct vdso_symtable vdso_sym_compat; +#endif +#endif }; extern struct kerndat_s kdat; diff --git a/criu/include/vdso.h b/criu/include/vdso.h index 6a9752bd1..b6110e442 100644 --- a/criu/include/vdso.h +++ b/criu/include/vdso.h @@ -15,6 +15,7 @@ extern struct vdso_maps vdso_maps_compat; extern int vdso_init_dump(void); extern int vdso_init_restore(void); +extern int kerndat_vdso_fill_symtable(void); extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct vm_area_list *vma_area_list); @@ -28,6 +29,7 @@ extern void compat_vdso_helper(struct vdso_maps *native, int pipe_fd, #define vdso_init_dump() (0) #define vdso_init_restore() (0) +#define kerndat_vdso_fill_symtable() (0) #define parasite_fixup_vdso(ctl, pid, vma_area_list) (0) #endif /* CONFIG_VDSO */ diff --git a/criu/kerndat.c b/criu/kerndat.c index 32893ef2c..055cc4e67 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -34,6 +34,7 @@ #include "linux/userfaultfd.h" #include "prctl.h" #include "uffd.h" +#include "vdso.h" struct kerndat_s kdat = { }; @@ -861,6 +862,9 @@ int kerndat_init(void) ret = kerndat_uffd(); if (!ret) ret = kerndat_has_thp_disable(); + /* Needs kdat.compat_cr filled before */ + if (!ret) + ret = kerndat_vdso_fill_symtable(); kerndat_lsm(); kerndat_mmap_min_addr(); diff --git a/criu/vdso.c b/criu/vdso.c index da3da69f4..83f30807e 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -457,13 +457,6 @@ out_unmap: pr_perror("Failed to unmap buf for compat vdso"); return ret; } - -#else /* CONFIG_COMPAT */ -static int vdso_fill_compat_symtable(struct vdso_maps *native, - struct vdso_maps *compat) -{ - return 0; -} #endif /* CONFIG_COMPAT */ int vdso_init_dump(void) @@ -481,7 +474,53 @@ int vdso_init_dump(void) return 0; } +/* + * Check vdso/vvar sized read from maps to kdat values. + * We do not read /proc/self/maps for compatible vdso as it's + * not parked as run-time vdso in restorer, but mapped with + * arch_prlctl(MAP_VDSO_32) API. + * By that reason we verify only native sizes. + */ +static int is_kdat_vdso_sym_valid(void) +{ + if (vdso_maps.sym.vdso_size != kdat.vdso_sym.vdso_size) + return false; + if (vdso_maps.sym.vvar_size != kdat.vdso_sym.vvar_size) + return false; + + return true; +} + int vdso_init_restore(void) +{ + if (kdat.vdso_sym.vdso_size == VDSO_BAD_SIZE) { + pr_err("Kdat has empty vdso symtable\n"); + return -1; + } + + /* Already filled vdso_maps during kdat test */ + if (vdso_maps.vdso_start != VDSO_BAD_ADDR) + return 0; + + if (vdso_parse_maps(PROC_SELF, &vdso_maps)) { + pr_err("Failed reading self/maps for filling vdso/vvar bounds\n"); + return -1; + } + + if (!is_kdat_vdso_sym_valid()) { + pr_err("Kdat sizes of vdso/vvar differ to maps file \n"); + return -1; + } + + vdso_maps.sym = kdat.vdso_sym; +#ifdef CONFIG_COMPAT + vdso_maps_compat.sym = kdat.vdso_sym_compat; +#endif + + return 0; +} + +int kerndat_vdso_fill_symtable(void) { if (vdso_parse_maps(PROC_SELF, &vdso_maps)) { pr_err("Failed reading self/maps for filling vdso/vvar bounds\n"); @@ -492,11 +531,15 @@ int vdso_init_restore(void) pr_err("Failed to fill self vdso symtable\n"); return -1; } + kdat.vdso_sym = vdso_maps.sym; +#ifdef CONFIG_COMPAT if (vdso_fill_compat_symtable(&vdso_maps, &vdso_maps_compat)) { pr_err("Failed to fill compat vdso symtable\n"); return -1; } + kdat.vdso_sym_compat = vdso_maps_compat.sym; +#endif return 0; } From aff44dd424f62c3ec44dc24eabb66d3820282b13 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 28 Jun 2017 03:53:33 +0300 Subject: [PATCH 0967/4375] aarch/vdso: include common/compiler.h before use __maybe_unused In file included from criu/include/util-vdso.h:23:0, from criu/include/kerndat.h:8, from criu/lsm.c:8: criu/arch/aarch64/include/asm/vdso.h:17:35: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'aarch_vdso_symbol1' static const char* __maybe_unused aarch_vdso_symbol1 = "__kernel_clock_getres"; Signed-off-by: Andrei Vagin --- criu/arch/aarch64/include/asm/vdso.h | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/arch/aarch64/include/asm/vdso.h b/criu/arch/aarch64/include/asm/vdso.h index 34d723f6c..a7802a279 100644 --- a/criu/arch/aarch64/include/asm/vdso.h +++ b/criu/arch/aarch64/include/asm/vdso.h @@ -2,6 +2,7 @@ #define __CR_ASM_VDSO_H__ #include "asm/int.h" +#include "common/compiler.h" #include "asm-generic/vdso.h" /* From 773fd40463d099cea3022008009d79ee809d1b1a Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Thu, 29 Jun 2017 21:24:40 +0200 Subject: [PATCH 0968/4375] criu/pie/parasite-vdso: Handle also systems without VVAR On s390 we don't use vvar. Therefore vvar_size in not been initialized and the value remains VVAR_BAD_SIZE. Fix the BUG() statement to also cover this case. Signed-off-by: Michael Holzheu Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/parasite-vdso.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 40b269595..ad178e9fd 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -44,9 +44,11 @@ static int vdso_remap(char *who, unsigned long from, unsigned long to, size_t si /* Park runtime vDSO in some safe place where it can be accessible from restorer */ int vdso_do_park(struct vdso_maps *rt, unsigned long park_at, unsigned long park_size) { + unsigned long vvar_size; int ret; - BUG_ON((rt->sym.vdso_size + rt->sym.vvar_size) < park_size); + vvar_size = (rt->sym.vvar_size == VVAR_BAD_SIZE) ? 0 : rt->sym.vvar_size; + BUG_ON((rt->sym.vdso_size + vvar_size) < park_size); if (rt->vvar_start != VVAR_BAD_ADDR) { if (rt->sym.vdso_before_vvar) { From bcba8d9702ae26ef9148b32754fbf6ebc4f5019e Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 10 Jul 2017 21:24:16 +0300 Subject: [PATCH 0969/4375] vdso: Introduce type for checking vdso hint in maps file Let's hide those kernel details in enum. Further in this patches set I'll add kdat test for presence of "[vdso]" hint after mremap(), so we will skip any checking on kernels > v3.16 and do not init vdso_pfn also (skipping parsing of self-pagemap). Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/vdso.c | 67 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index 83f30807e..a0b8a4e0b 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -32,6 +32,42 @@ u64 vdso_pfn = VDSO_BAD_PFN; struct vdso_maps vdso_maps = VDSO_MAPS_INIT; struct vdso_maps vdso_maps_compat = VDSO_MAPS_INIT; +/* + * Starting with 3.16 the [vdso]/[vvar] marks are reported correctly + * even when they are remapped into a new place, but only since that + * particular version of the kernel! + * On previous kernels we need to check if vma is vdso by some means: + * - if pagemap is present, by pfn + * - by parsing ELF and filling vdso symtable otherwise + */ +enum vdso_check_t { + /* from slowest to fastest */ + VDSO_CHECK_SYMS = 0, + VDSO_CHECK_PFN, + VDSO_NO_CHECK, +}; + +static enum vdso_check_t get_vdso_check_type(struct parasite_ctl *ctl) +{ + /* + * ia32 C/R depends on mremap() for vdso patches (v4.8), + * so we can omit any check and be sure that "[vdso]" + * hint stays in /proc/../maps file and is correct. + */ + if (!compel_mode_native(ctl)) { + pr_info("Don't check vdso\n"); + return VDSO_NO_CHECK; + } + + if (kdat.pmap == PM_FULL) { + pr_info("Check vdso by pfn from pagemap\n"); + return VDSO_CHECK_PFN; + } + + pr_info("Pagemap is unavailable, check vdso by filling symtable\n"); + return VDSO_CHECK_SYMS; +} + /* * The VMAs list might have proxy vdso/vvar areas left * from previous dump/restore cycle so we need to detect @@ -47,18 +83,19 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct vma_area *proxy_vvar_marked = NULL; struct parasite_vdso_vma_entry *args; int fd = -1, ret, exit_code = -1; + enum vdso_check_t vcheck; u64 pfn = VDSO_BAD_PFN; struct vma_area *vma; off_t off; + vcheck = get_vdso_check_type(ctl); args = compel_parasite_args(ctl, struct parasite_vdso_vma_entry); - if (kdat.pmap == PM_FULL) { + if (vcheck == VDSO_CHECK_PFN) { BUG_ON(vdso_pfn == VDSO_BAD_PFN); fd = open_proc(pid, "pagemap"); if (fd < 0) return -1; - } else - pr_info("Pagemap is unavailable, trying a slow way\n"); + } list_for_each_entry(vma, &vma_area_list->h, list) { if (!vma_area_is(vma, VMA_AREA_REGULAR)) @@ -105,10 +142,7 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, */ args->start = vma->e->start; args->len = vma_area_len(vma); - if (!compel_mode_native(ctl)) - args->try_fill_symtable = false; - else - args->try_fill_symtable = (fd < 0) ? true : false; + args->try_fill_symtable = (vcheck == VDSO_CHECK_SYMS); args->is_vdso = false; if (compel_rpc_call_sync(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) { @@ -132,6 +166,9 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, continue; } + if (vcheck == VDSO_NO_CHECK) + continue; + /* * If we have an access to pagemap we can handle vDSO * status early. Otherwise, in worst scenario, where @@ -140,7 +177,7 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, * detected via procfs status so we have to parse * symbols in parasite code. */ - if (fd >= 0) { + if (vcheck == VDSO_CHECK_PFN) { off = (vma->e->start / PAGE_SIZE) * sizeof(u64); ret = pread(fd, &pfn, sizeof(pfn), off); if (ret < 0 || ret != sizeof(pfn)) { @@ -155,13 +192,6 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, } } - /* - * Setup proper VMA status. Note starting with 3.16 - * the [vdso]/[vvar] marks are reported correctly - * even when they are remapped into a new place, - * but only since that particular version of the - * kernel! - */ if ((pfn == vdso_pfn && pfn != VDSO_BAD_PFN) || args->is_vdso) { if (!vma_area_is(vma, VMA_AREA_VDSO)) { pr_debug("Restore vDSO status by pfn/symtable at %lx\n", @@ -169,12 +199,7 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, vma->e->status |= VMA_AREA_VDSO; } } else { - /* - * Compat vDSO mremap support is only after v4.8, - * [vdso] vma name always stays after mremap. - */ - if (unlikely(vma_area_is(vma, VMA_AREA_VDSO)) && - compel_mode_native(ctl)) { + if (unlikely(vma_area_is(vma, VMA_AREA_VDSO))) { pr_debug("Drop mishinted vDSO status at %lx\n", (long)vma->e->start); vma->e->status &= ~VMA_AREA_VDSO; From 55ffa83064c77bf54ff2695ddb908656826cf6f3 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 10 Jul 2017 21:24:17 +0300 Subject: [PATCH 0970/4375] util: Add fd parameter to vaddr_to_pfn() Expand vaddr_to_pfn() so it can read and translate to PFN from already opened fd. This can be used as optimization if one need to translate a couple of addresses and also to read other task's PFN. I'll use it in the next patch for reading other tasks's vdso's PFN. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/util.h | 2 +- criu/kerndat.c | 2 +- criu/util.c | 23 +++++++++++++++++------ criu/vdso.c | 2 +- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/criu/include/util.h b/criu/include/util.h index bf466f5d6..5d471cb67 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -193,7 +193,7 @@ extern int read_fd_link(int lfd, char *buf, size_t size); #define USEC_PER_SEC 1000000L #define NSEC_PER_SEC 1000000000L -int vaddr_to_pfn(unsigned long vaddr, u64 *pfn); +int vaddr_to_pfn(int fd, unsigned long vaddr, u64 *pfn); /* * Check whether @str starts with @sub and report the diff --git a/criu/kerndat.c b/criu/kerndat.c index 055cc4e67..b9195176b 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -354,7 +354,7 @@ static int init_zero_page_pfn() return -1; } - ret = vaddr_to_pfn((unsigned long)addr, &kdat.zero_page_pfn); + ret = vaddr_to_pfn(-1, (unsigned long)addr, &kdat.zero_page_pfn); munmap(addr, PAGE_SIZE); if (kdat.zero_page_pfn == 0) diff --git a/criu/util.c b/criu/util.c index b681daf9b..dc11e5f9d 100644 --- a/criu/util.c +++ b/criu/util.c @@ -784,14 +784,23 @@ out: return ret; } -int vaddr_to_pfn(unsigned long vaddr, u64 *pfn) +/* + * Get PFN from pagemap file for virtual address vaddr. + * Optionally if fd >= 0, it's used as pagemap file descriptor + * (may be other task's pagemap) + */ +int vaddr_to_pfn(int fd, unsigned long vaddr, u64 *pfn) { - int fd, ret = -1; + int ret = -1; off_t off; + bool close_fd = false; - fd = open_proc(PROC_SELF, "pagemap"); - if (fd < 0) - return -1; + if (fd < 0) { + fd = open_proc(PROC_SELF, "pagemap"); + if (fd < 0) + return -1; + close_fd = true; + } off = (vaddr / page_size()) * sizeof(u64); ret = pread(fd, pfn, sizeof(*pfn), off); @@ -803,7 +812,9 @@ int vaddr_to_pfn(unsigned long vaddr, u64 *pfn) ret = 0; } - close(fd); + if (close_fd) + close(fd); + return ret; } diff --git a/criu/vdso.c b/criu/vdso.c index a0b8a4e0b..b4e6b1860 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -493,7 +493,7 @@ int vdso_init_dump(void) if (kdat.pmap != PM_FULL) pr_info("VDSO detection turned off\n"); - else if (vaddr_to_pfn(vdso_maps.vdso_start, &vdso_pfn)) + else if (vaddr_to_pfn(-1, vdso_maps.vdso_start, &vdso_pfn)) return -1; return 0; From 3376543570d92cbe4efc6737ac227bfa96692bc7 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 10 Jul 2017 21:24:18 +0300 Subject: [PATCH 0971/4375] vdso: Use vaddr_to_pfn() to get vdso's pfn Generalize addr-to-pfn conversion in one function. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/vdso.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index b4e6b1860..5489e4f03 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -82,11 +82,10 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct vma_area *proxy_vdso_marked = NULL; struct vma_area *proxy_vvar_marked = NULL; struct parasite_vdso_vma_entry *args; - int fd = -1, ret, exit_code = -1; + int fd = -1, exit_code = -1; enum vdso_check_t vcheck; u64 pfn = VDSO_BAD_PFN; struct vma_area *vma; - off_t off; vcheck = get_vdso_check_type(ctl); args = compel_parasite_args(ctl, struct parasite_vdso_vma_entry); @@ -178,14 +177,9 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, * symbols in parasite code. */ if (vcheck == VDSO_CHECK_PFN) { - off = (vma->e->start / PAGE_SIZE) * sizeof(u64); - ret = pread(fd, &pfn, sizeof(pfn), off); - if (ret < 0 || ret != sizeof(pfn)) { - pr_perror("Can't read pme for pid %d", pid); + if (vaddr_to_pfn(fd, vma->e->start, &pfn)) goto err; - } - pfn = PME_PFRAME(pfn); if (!pfn) { pr_err("Unexpected page fram number 0 for pid %d\n", pid); goto err; From 8da2d8f282076dd8a345470894f0dde8297e8385 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 10 Jul 2017 21:24:19 +0300 Subject: [PATCH 0972/4375] vdso: Separate function for checking vdso's pfn This is just to split this oversized outgrowed plumped up parasite_fixup_vdso() and separate it logically. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/vdso.c | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index 5489e4f03..83a10d4bf 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -68,6 +68,27 @@ static enum vdso_check_t get_vdso_check_type(struct parasite_ctl *ctl) return VDSO_CHECK_SYMS; } +static int check_vdso_by_pfn(int pagemap_fd, struct vma_area *vma, + bool *has_vdso_pfn) +{ + u64 pfn = VDSO_BAD_PFN; + + if (vaddr_to_pfn(pagemap_fd, vma->e->start, &pfn)) + return -1; + + if (!pfn) { + pr_err("Unexpected page frame number 0\n"); + return -1; + } + + if ((pfn == vdso_pfn && pfn != VDSO_BAD_PFN)) + *has_vdso_pfn = true; + else + *has_vdso_pfn = false; + + return 0; +} + /* * The VMAs list might have proxy vdso/vvar areas left * from previous dump/restore cycle so we need to detect @@ -84,7 +105,6 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct parasite_vdso_vma_entry *args; int fd = -1, exit_code = -1; enum vdso_check_t vcheck; - u64 pfn = VDSO_BAD_PFN; struct vma_area *vma; vcheck = get_vdso_check_type(ctl); @@ -97,6 +117,8 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, } list_for_each_entry(vma, &vma_area_list->h, list) { + bool has_vdso_pfn = false; + if (!vma_area_is(vma, VMA_AREA_REGULAR)) continue; @@ -168,25 +190,12 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, if (vcheck == VDSO_NO_CHECK) continue; - /* - * If we have an access to pagemap we can handle vDSO - * status early. Otherwise, in worst scenario, where - * the dumpee has been remapping vdso on its own and - * the kernel version is < 3.16, the vdso won't be - * detected via procfs status so we have to parse - * symbols in parasite code. - */ - if (vcheck == VDSO_CHECK_PFN) { - if (vaddr_to_pfn(fd, vma->e->start, &pfn)) - goto err; - - if (!pfn) { - pr_err("Unexpected page fram number 0 for pid %d\n", pid); - goto err; - } + if (vcheck == VDSO_CHECK_PFN && check_vdso_by_pfn(fd, vma, &has_vdso_pfn) < 0) { + pr_err("Failed checking vdso by pfn for %d\n", pid); + goto err; } - if ((pfn == vdso_pfn && pfn != VDSO_BAD_PFN) || args->is_vdso) { + if (has_vdso_pfn || args->is_vdso) { if (!vma_area_is(vma, VMA_AREA_VDSO)) { pr_debug("Restore vDSO status by pfn/symtable at %lx\n", (long)vma->e->start); From c7eb920fe111f3d5bc728341ca482ff8a66e21dd Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 10 Jul 2017 21:24:20 +0300 Subject: [PATCH 0973/4375] vdso: Separate checks for {vdso, vvar}-alikeness No functional change expected. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/vdso.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index 83a10d4bf..caed5efd8 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -89,6 +89,26 @@ static int check_vdso_by_pfn(int pagemap_fd, struct vma_area *vma, return 0; } +static bool not_vvar_or_vdso(struct vma_area *vma) +{ + if (!vma_area_is(vma, VMA_AREA_REGULAR)) + return true; + + if (vma_area_is(vma, VMA_FILE_SHARED)) + return true; + + if (vma_area_is(vma, VMA_FILE_PRIVATE)) + return true; + + if (vma->e->start > kdat.task_size) + return true; + + if (vma->e->flags & MAP_GROWSDOWN) + return true; + + return false; +} + /* * The VMAs list might have proxy vdso/vvar areas left * from previous dump/restore cycle so we need to detect @@ -119,12 +139,9 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, list_for_each_entry(vma, &vma_area_list->h, list) { bool has_vdso_pfn = false; - if (!vma_area_is(vma, VMA_AREA_REGULAR)) + if (not_vvar_or_vdso(vma)) continue; - if (vma_area_is(vma, VMA_FILE_SHARED) || - vma_area_is(vma, VMA_FILE_PRIVATE)) - continue; /* * It might be possible VVAR area from marked * vDSO zone, we need to detect it earlier than @@ -146,12 +163,6 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, if ((vma->e->prot & VDSO_PROT) != VDSO_PROT) continue; - if (vma->e->start > kdat.task_size) - continue; - - if (vma->e->flags & MAP_GROWSDOWN) - continue; - /* * I need to poke every potentially marked vma, * otherwise if task never called for vdso functions From 025ad384f409b807e971c3f5bd9b6ed1bdd34a34 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 10 Jul 2017 21:24:21 +0300 Subject: [PATCH 0974/4375] vdso: Separate remap_rt_vdso() from vdso_proxify() Make it more readable and change-ready. No functional change is expected. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/parasite-vdso.c | 83 +++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index ad178e9fd..ebc62e256 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -140,6 +140,48 @@ static bool blobs_matches(VmaEntry *vdso_img, VmaEntry *vvar_img, return true; } +/* + * The easy case -- the vdso from an image has the same offsets, + * order and size as runtime vdso, so we simply remap runtime vdso + * to dumpee position without generating any proxy. + */ +static int remap_rt_vdso(VmaEntry *vma_vdso, VmaEntry *vma_vvar, + struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at) +{ + unsigned long rt_vvar_addr = vdso_rt_parked_at; + unsigned long rt_vdso_addr = vdso_rt_parked_at; + int ret; + + pr_info("Runtime vdso/vvar matches dumpee, remap inplace\n"); + + if (sys_munmap((void *)vma_vdso->start, vma_entry_len(vma_vdso))) { + pr_err("Failed to unmap dumpee vdso\n"); + return -1; + } + + if (!vma_vvar) { + return vdso_remap("rt-vdso", rt_vdso_addr, + vma_vdso->start, sym_rt->vdso_size); + } + + if (sys_munmap((void *)vma_vvar->start, vma_entry_len(vma_vvar))) { + pr_err("Failed to unmap dumpee vvar\n"); + return -1; + } + + if (vma_vdso->start < vma_vvar->start) + rt_vvar_addr = vdso_rt_parked_at + sym_rt->vdso_size; + else + rt_vdso_addr = vdso_rt_parked_at + sym_rt->vvar_size; + + ret = vdso_remap("rt-vdso", rt_vdso_addr, + vma_vdso->start, sym_rt->vdso_size); + ret |= vdso_remap("rt-vvar", rt_vvar_addr, + vma_vvar->start, sym_rt->vvar_size); + + return ret; +} + int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso, bool force_trampolines) @@ -187,46 +229,9 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, vma_vvar ? (unsigned long)vma_vvar->start : VVAR_BAD_ADDR, vma_vvar ? (unsigned long)vma_vvar->end : VVAR_BAD_ADDR); - /* - * Easy case -- the vdso from image has same offsets, order and size - * as runtime, so we simply remap runtime vdso to dumpee position - * without generating any proxy. - * - * Note we may remap VVAR vdso as well which might not yet been mapped - * by a caller code. So drop VMA_AREA_REGULAR from it and caller would - * not touch it anymore. - */ if (blobs_matches(vma_vdso, vma_vvar, &s, sym_rt) && !force_trampolines) { - int ret = 0; - - pr_info("Runtime vdso/vvar matches dumpee, remap inplace\n"); - - if (sys_munmap((void *)(uintptr_t)vma_vdso->start, - vma_entry_len(vma_vdso))) { - pr_err("Failed to unmap dumpee\n"); - return -1; - } - - if (vma_vvar) { - if (sys_munmap((void *)(uintptr_t)vma_vvar->start, - vma_entry_len(vma_vvar))) { - pr_err("Failed to unmap dumpee\n"); - return -1; - } - - if (vma_vdso->start < vma_vvar->start) { - ret = vdso_remap("rt-vdso", vdso_rt_parked_at, vma_vdso->start, sym_rt->vdso_size); - vdso_rt_parked_at += sym_rt->vdso_size; - ret |= vdso_remap("rt-vvar", vdso_rt_parked_at, vma_vvar->start, sym_rt->vvar_size); - } else { - ret = vdso_remap("rt-vvar", vdso_rt_parked_at, vma_vvar->start, sym_rt->vvar_size); - vdso_rt_parked_at += sym_rt->vvar_size; - ret |= vdso_remap("rt-vdso", vdso_rt_parked_at, vma_vdso->start, sym_rt->vdso_size); - } - } else - ret = vdso_remap("rt-vdso", vdso_rt_parked_at, vma_vdso->start, sym_rt->vdso_size); - - return ret; + return remap_rt_vdso(vma_vdso, vma_vvar, + sym_rt, vdso_rt_parked_at); } /* From 041fa5285ec010caaad273edc5b654fa702ef6e2 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 10 Jul 2017 21:24:22 +0300 Subject: [PATCH 0975/4375] vdso: Cleanup vdso_do_park() Make it a bit easier to read. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/parasite-vdso.c | 48 ++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index ebc62e256..71776d7d9 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -41,32 +41,36 @@ static int vdso_remap(char *who, unsigned long from, unsigned long to, size_t si return 0; } -/* Park runtime vDSO in some safe place where it can be accessible from restorer */ -int vdso_do_park(struct vdso_maps *rt, unsigned long park_at, unsigned long park_size) +/* + * Park runtime vDSO in some safe place where it can be accessible + * from the restorer + */ +int vdso_do_park(struct vdso_maps *rt, unsigned long park_at, + unsigned long park_size) { - unsigned long vvar_size; + unsigned long vvar_size = rt->sym.vvar_size; + unsigned long vdso_size = rt->sym.vdso_size; + unsigned long rt_vvar_park = park_at; + unsigned long rt_vdso_park = park_at; int ret; - vvar_size = (rt->sym.vvar_size == VVAR_BAD_SIZE) ? 0 : rt->sym.vvar_size; - BUG_ON((rt->sym.vdso_size + vvar_size) < park_size); - if (rt->vvar_start != VVAR_BAD_ADDR) { - if (rt->sym.vdso_before_vvar) { - ret = vdso_remap("rt-vdso", rt->vdso_start, - park_at, rt->sym.vdso_size); - park_at += rt->sym.vdso_size; - ret |= vdso_remap("rt-vvar", rt->vvar_start, - park_at, rt->sym.vvar_size); - } else { - ret = vdso_remap("rt-vvar", rt->vvar_start, - park_at, rt->sym.vvar_size); - park_at += rt->sym.vvar_size; - ret |= vdso_remap("rt-vdso", rt->vdso_start, - park_at, rt->sym.vdso_size); - } - } else - ret = vdso_remap("rt-vdso", rt->vdso_start, - park_at, rt->sym.vdso_size); + if (rt->vvar_start == VVAR_BAD_ADDR) { + BUG_ON(vdso_size < park_size); + return vdso_remap("rt-vdso", rt->vdso_start, + rt_vdso_park, vdso_size); + } + + BUG_ON((vdso_size + vvar_size) < park_size); + + if (rt->sym.vdso_before_vvar) + rt_vvar_park = park_at + vdso_size; + else + rt_vdso_park = park_at + vvar_size; + + ret = vdso_remap("rt-vdso", rt->vdso_start, rt_vdso_park, vdso_size); + ret |= vdso_remap("rt-vvar", rt->vvar_start, rt_vvar_park, vvar_size); + return ret; } From fc95ea4c8de5d9d9c7360166fe95ae5ef7a1f1d6 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 10 Jul 2017 21:24:23 +0300 Subject: [PATCH 0976/4375] vdso: Separate add_vdso_proxy() I'll need to modify it - make it small and ready for changes. No functional change is expected. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/parasite-vdso.c | 67 +++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 71776d7d9..d5e527041 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -186,6 +186,42 @@ static int remap_rt_vdso(VmaEntry *vma_vdso, VmaEntry *vma_vvar, return ret; } +/* + * The complex case -- we need to proxify calls. We redirect + * calls from dumpee vdso to runtime vdso, making dumpee + * to operate as proxy vdso. + */ +static int add_vdso_proxy(VmaEntry *vma_vdso, VmaEntry *vma_vvar, + struct vdso_symtable *sym_img, struct vdso_symtable *sym_rt, + unsigned long rt_vdso_addr, bool compat_vdso) +{ + pr_info("Runtime vdso mismatches dumpee, generate proxy\n"); + + /* + * Don't forget to shift if vvar is before vdso. + */ + if (sym_rt->vvar_size != VDSO_BAD_SIZE && !sym_rt->vdso_before_vvar) + rt_vdso_addr += sym_rt->vvar_size; + + if (vdso_redirect_calls(rt_vdso_addr, vma_vdso->start, + sym_rt, sym_img, compat_vdso)) { + pr_err("Failed to proxify dumpee contents\n"); + return -1; + } + + /* + * Put a special mark into runtime vdso, thus at next checkpoint + * routine we could detect this vdso and do not dump it, since + * it's auto-generated every new session if proxy required. + */ + sys_mprotect((void *)rt_vdso_addr, sym_rt->vdso_size, PROT_WRITE); + vdso_put_mark((void *)rt_vdso_addr, vma_vdso->start, + vma_vvar ? vma_vvar->start : VVAR_BAD_ADDR); + sys_mprotect((void *)rt_vdso_addr, sym_rt->vdso_size, VDSO_PROT); + + return 0; +} + int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso, bool force_trampolines) @@ -238,33 +274,6 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, sym_rt, vdso_rt_parked_at); } - /* - * Now complex case -- we need to proxify calls. We redirect - * calls from dumpee vdso to runtime vdso, making dumpee - * to operate as proxy vdso. - */ - pr_info("Runtime vdso mismatches dumpee, generate proxy\n"); - - /* - * Don't forget to shift if vvar is before vdso. - */ - if (sym_rt->vvar_size != VDSO_BAD_SIZE && !sym_rt->vdso_before_vvar) - vdso_rt_parked_at += sym_rt->vvar_size; - - if (vdso_redirect_calls(vdso_rt_parked_at, - vma_vdso->start, - sym_rt, &s, compat_vdso)) { - pr_err("Failed to proxify dumpee contents\n"); - return -1; - } - - /* - * Put a special mark into runtime vdso, thus at next checkpoint - * routine we could detect this vdso and do not dump it, since - * it's auto-generated every new session if proxy required. - */ - sys_mprotect((void *)vdso_rt_parked_at, sym_rt->vdso_size, PROT_WRITE); - vdso_put_mark((void *)vdso_rt_parked_at, vma_vdso->start, vma_vvar ? vma_vvar->start : VVAR_BAD_ADDR); - sys_mprotect((void *)vdso_rt_parked_at, sym_rt->vdso_size, VDSO_PROT); - return 0; + return add_vdso_proxy(vma_vdso, vma_vvar, &s, sym_rt, + vdso_rt_parked_at, compat_vdso); } From 977e513834f691100661b14fd837becf5181b12b Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 10 Jul 2017 21:24:24 +0300 Subject: [PATCH 0977/4375] vdso/ia32: Don't unmap rt-vdso Found with fault-injected jump trampolines in vdso, that on ia32 tests rt-vdso got unmapped. I've fixed it previously, but have forgot it during debugging vdso cleanup. Fixes: commit 8544895a528b ("ia32/restorer: move 32-bit pie unmap to x86") Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/restorer_unmap.S | 1 + criu/pie/restorer.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/arch/x86/restorer_unmap.S b/criu/arch/x86/restorer_unmap.S index 09c4c9583..d721eaf97 100644 --- a/criu/arch/x86/restorer_unmap.S +++ b/criu/arch/x86/restorer_unmap.S @@ -6,6 +6,7 @@ ENTRY(__export_unmap_compat) .code32 mov bootstrap_start, %ebx mov bootstrap_len, %ecx + sub vdso_rt_size, %ecx movl $__NR32_munmap, %eax int $0x80 int $0x03 /* Guard */ diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index f33401e06..fe4b64a7b 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1009,7 +1009,7 @@ static void restore_posix_timers(struct task_restore_args *args) * trap us on the exit from sys_munmap. */ #ifdef CONFIG_VDSO -static unsigned long vdso_rt_size; +unsigned long vdso_rt_size = 0; #else #define vdso_rt_size (0) #endif From 91c81e5f40664dae105f5073703b5a1603a1a496 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 17 Jul 2017 15:39:52 +0300 Subject: [PATCH 0978/4375] kdat: Add test for presence of vdso mapping API Previously, arch_prctl(ARCH_MAP_VDSO_32) was only used by CONFIG_COMPAT to map compatible vdso blob for 32-bit restoree. But we can make it more generic: Omitting mremap() for moving vdso to rt-vdso zone in restorer and afterward on needed position in restoree. Also omitting reading /proc/self/maps to find vdso/vvar addresses (to park afterward in restorer). TLDR; under this kdat feature we can get rid of a buch of mremap()'s for each restoree and from parsing /proc/self/maps in vdso_init_restore(). The API is present from v4.9 kernel. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/include/asm/restorer.h | 1 + criu/arch/arm/include/asm/restorer.h | 1 + criu/arch/ppc64/include/asm/restorer.h | 1 + criu/arch/x86/crtools.c | 63 +++++++++++++++--------- criu/arch/x86/include/asm/restorer.h | 1 + criu/cr-check.c | 10 ++++ criu/include/kerndat.h | 1 + criu/kerndat.c | 11 +++-- 8 files changed, 63 insertions(+), 26 deletions(-) diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h index 78cc9bd39..000d3f8ba 100644 --- a/criu/arch/aarch64/include/asm/restorer.h +++ b/criu/arch/aarch64/include/asm/restorer.h @@ -53,6 +53,7 @@ #define kdat_compatible_cr() 0 +#define kdat_can_map_vdso() 0 int restore_gpregs(struct rt_sigframe *f, UserAarch64RegsEntry *r); int restore_nonsigframe_gpregs(UserAarch64RegsEntry *r); diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h index 8748281fc..3da166a44 100644 --- a/criu/arch/arm/include/asm/restorer.h +++ b/criu/arch/arm/include/asm/restorer.h @@ -54,6 +54,7 @@ #define kdat_compatible_cr() 0 +#define kdat_can_map_vdso() 0 int restore_gpregs(struct rt_sigframe *f, UserArmRegsEntry *r); int restore_nonsigframe_gpregs(UserArmRegsEntry *r); diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h index e3d2d291e..ad9c39a78 100644 --- a/criu/arch/ppc64/include/asm/restorer.h +++ b/criu/arch/ppc64/include/asm/restorer.h @@ -49,6 +49,7 @@ : "memory","0","3","4","5","6","7","14","15") #define kdat_compatible_cr() 0 +#define kdat_can_map_vdso() 0 int restore_gpregs(struct rt_sigframe *f, UserPpc64RegsEntry *r); int restore_nonsigframe_gpregs(UserPpc64RegsEntry *r); diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 90b809b5e..af5a315ad 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -30,33 +30,48 @@ #include "images/core.pb-c.h" #include "images/creds.pb-c.h" -#ifdef CONFIG_COMPAT -static int has_arch_map_vdso(void) +int kdat_can_map_vdso(void) { - unsigned long auxval; - int ret; + pid_t child; + int stat; - errno = 0; - auxval = getauxval(AT_SYSINFO_EHDR); - if (!auxval) { - if (errno == ENOENT) { /* No vDSO - OK */ - pr_warn("No SYSINFO_EHDR - no vDSO\n"); - return 1; - } else { /* That can't happen, according to man */ - pr_err("Failed to get auxval: errno %d\n", errno); - return -1; - } - } /* - * Mapping vDSO while have not unmap it yet: - * this is restricted by API if ARCH_MAP_VDSO_* is supported. + * Running under fork so if vdso_64 is disabled - don't create + * it for criu accidentally. */ - ret = syscall(SYS_arch_prctl, ARCH_MAP_VDSO_32, 1); - if (ret == -1 && errno == EEXIST) - return 1; - return 0; + child = fork(); + if (child < 0) + return -1; + + if (child == 0) { + int ret; + + ret = syscall(SYS_arch_prctl, ARCH_MAP_VDSO_32, 0); + if (ret == 0) + exit(1); + /* + * Mapping vDSO while have not unmap it yet: + * this is restricted by API if ARCH_MAP_VDSO_* is supported. + */ + if (ret == -1 && errno == EEXIST) + exit(1); + exit(0); + } + + if (waitpid(child, &stat, 0) != child) { + pr_err("Failed to wait for arch_prctl() test"); + kill(child, SIGKILL); + return -1; + } + + if (!WIFEXITED(stat)) + return -1; + + return WEXITSTATUS(stat); + } +#ifdef CONFIG_COMPAT void *mmap_ia32(void *addr, size_t len, int prot, int flags, int fildes, off_t off) { @@ -151,13 +166,15 @@ static int has_32bit_mmap_bug(void) int kdat_compatible_cr(void) { - if (!has_arch_map_vdso()) + if (!kdat.can_map_vdso) return 0; + if (has_32bit_mmap_bug()) return 0; + return 1; } -#else +#else /* !CONFIG_COMPAT */ int kdat_compatible_cr(void) { return 0; diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index e7199f684..04509ff2f 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -77,6 +77,7 @@ static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) #endif extern int kdat_compatible_cr(void); +extern int kdat_can_map_vdso(void); static inline void __setup_sas_compat(struct ucontext_ia32* uc, ThreadSasEntry *sas) diff --git a/criu/cr-check.c b/criu/cr-check.c index ba47f410c..5dd448bb1 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1054,6 +1054,14 @@ static int check_uffd_noncoop(void) return 0; } +static int check_can_map_vdso(void) +{ + if (kdat_can_map_vdso() == 1) + return 0; + pr_warn("Do not have API to map vDSO - will use mremap() to restore vDSO\n"); + return -1; +} + static int (*chk_feature)(void); /* @@ -1157,6 +1165,7 @@ int cr_check(void) ret |= check_tcp_halt_closed(); ret |= check_userns(); ret |= check_loginuid(); + ret |= check_can_map_vdso(); } /* @@ -1208,6 +1217,7 @@ static struct feature_list feature_list[] = { { "compat_cr", check_compat_cr }, { "uffd", check_uffd }, { "uffd-noncoop", check_uffd_noncoop }, + { "can_map_vdso", check_can_map_vdso}, { NULL, NULL }, }; diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 014cf87af..d34ffa1e2 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -55,6 +55,7 @@ struct kerndat_s { bool has_uffd; unsigned long uffd_features; bool has_thp_disable; + bool can_map_vdso; #ifdef CONFIG_VDSO struct vdso_symtable vdso_sym; #ifdef CONFIG_COMPAT diff --git a/criu/kerndat.c b/criu/kerndat.c index b9195176b..cad2597b6 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -560,11 +560,16 @@ err: static int kerndat_compat_restore(void) { - int ret = kdat_compatible_cr(); + int ret; - if (ret < 0) /* failure */ + ret = kdat_can_map_vdso(); + if (ret < 0) return ret; - kdat.compat_cr = !!ret; + kdat.can_map_vdso = !!ret; + + /* depends on kdat.can_map_vdso result */ + kdat.compat_cr = kdat_compatible_cr(); + return 0; } From 3b8071bac0fa47ad6883fa5dfec766e71ed2310a Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 17 Jul 2017 15:39:53 +0300 Subject: [PATCH 0979/4375] vdso: Introduce vdso mark v3 We need to place @rt_vvar_addr into vdso mark, as we don't know the position of rt-vvar to be dropped on the following dumps. I've renamed proxy_*_addr to orig_*_addr, as it looks more describing. orig_*_addr we need for marking those VMAs as accordingly, so restorer would know what to do with them. Otherwise, it'll think they are just regular vmas. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/parasite-vdso.h | 71 +++++++++++++++++++----------------- criu/pie/parasite-vdso.c | 21 ++++++++--- criu/pie/parasite.c | 4 +- 3 files changed, 56 insertions(+), 40 deletions(-) diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index 2a7f10ed2..3d6585a01 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -18,64 +18,69 @@ static inline bool vdso_symbol_empty(struct vdso_symbol *s) } /* - * Special mark which allows to identify runtime vdso where - * calls from proxy vdso are redirected. This mark usually + * Special mark which allows to identify runtime vdso (rt-vdso) where + * calls from proxy (original) vdso are redirected. This mark usually * placed at the start of vdso area where Elf header lives. - * Since such runtime vdso is solevey used by proxy and + * Since such runtime vdso is solely used by the proxy and * nobody else is supposed to access it, it's more-less * safe to screw the Elf header with @signature and - * @proxy_addr. + * vvar/vdso addresses for next dumping. * - * The @proxy_addr deserves a few comments. When we redirect - * the calls from proxy to runtime vdso, on next checkpoint - * it won't be possible to find which VMA is proxy, thus - * we save its address in the member. + * The @orig_addr deserves a few comments. When we redirect the calls + * from the original vdso to runtime vdso, on next checkpoint it won't + * be possible to find original vdso/vvar pair, thus we save their + * addresses in the member. + * + * As on the following dumps we need to drop rt-{vvar,vdso} pair + * from list of VMAs to save in images, we save rt-vvar address also. */ struct vdso_mark { u64 signature; - unsigned long proxy_vdso_addr; - + unsigned long orig_vdso_addr; unsigned long version; - - /* - * In case of new vDSO format the VVAR area address - * neeed for easier discovering where it lives without - * relying on procfs output. - */ - unsigned long proxy_vvar_addr; + unsigned long orig_vvar_addr; + unsigned long rt_vvar_addr; }; -#define VDSO_MARK_SIGNATURE (0x6f73647675697263ULL) /* Magic number (criuvdso) */ +#define VDSO_MARK_SIGNATURE_V1 (0x6f73647675697263ULL) /* Magic number (criuvdso) */ #define VDSO_MARK_SIGNATURE_V2 (0x4f53447675697263ULL) /* Magic number (criuvDSO) */ -#define VDSO_MARK_CUR_VERSION (2) +#define VDSO_MARK_SIGNATURE_V3 (0x4f53447655495243ULL) /* Magic number (CRIUvDSO) */ +#define VDSO_MARK_CUR_VERSION (3) -static inline void vdso_put_mark(void *where, unsigned long proxy_vdso_addr, unsigned long proxy_vvar_addr) +static inline void vdso_put_mark(void *where, unsigned long rt_vvar_addr, + unsigned long orig_vdso_addr, unsigned long orig_vvar_addr) { struct vdso_mark *m = where; - m->signature = VDSO_MARK_SIGNATURE_V2; - m->proxy_vdso_addr = proxy_vdso_addr; + m->signature = VDSO_MARK_SIGNATURE_V3; + m->orig_vdso_addr = orig_vdso_addr; m->version = VDSO_MARK_CUR_VERSION; - m->proxy_vvar_addr = proxy_vvar_addr; + m->orig_vvar_addr = orig_vvar_addr; + m->rt_vvar_addr = rt_vvar_addr; } static inline bool is_vdso_mark(void *addr) { struct vdso_mark *m = addr; - if (m->signature == VDSO_MARK_SIGNATURE_V2) { - /* - * New format - */ + switch (m->signature) { + case VDSO_MARK_SIGNATURE_V3: return true; - } else if (m->signature == VDSO_MARK_SIGNATURE) { - /* - * Old format -- simply extend the mark up - * to the version we support. - */ - vdso_put_mark(m, m->proxy_vdso_addr, VVAR_BAD_ADDR); + /* + * Old formats -- simply extend the mark up + * to the version we support. + */ + case VDSO_MARK_SIGNATURE_V2: + vdso_put_mark(m, VVAR_BAD_ADDR, + m->orig_vdso_addr, m->orig_vvar_addr); + return true; + + case VDSO_MARK_SIGNATURE_V1: + vdso_put_mark(m, VVAR_BAD_ADDR, + m->orig_vdso_addr, VVAR_BAD_ADDR); return true; } + return false; } diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index d5e527041..5285a2c31 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -193,15 +193,26 @@ static int remap_rt_vdso(VmaEntry *vma_vdso, VmaEntry *vma_vvar, */ static int add_vdso_proxy(VmaEntry *vma_vdso, VmaEntry *vma_vvar, struct vdso_symtable *sym_img, struct vdso_symtable *sym_rt, - unsigned long rt_vdso_addr, bool compat_vdso) + unsigned long vdso_rt_parked_at, bool compat_vdso) { + unsigned long rt_vvar_addr = vdso_rt_parked_at; + unsigned long rt_vdso_addr = vdso_rt_parked_at; + unsigned long orig_vvar_addr = + vma_vvar ? vma_vvar->start : VVAR_BAD_ADDR; + pr_info("Runtime vdso mismatches dumpee, generate proxy\n"); /* * Don't forget to shift if vvar is before vdso. */ - if (sym_rt->vvar_size != VDSO_BAD_SIZE && !sym_rt->vdso_before_vvar) - rt_vdso_addr += sym_rt->vvar_size; + if (sym_rt->vvar_size == VVAR_BAD_SIZE) { + rt_vvar_addr = VVAR_BAD_ADDR; + } else { + if (sym_rt->vdso_before_vvar) + rt_vvar_addr += sym_rt->vdso_size; + else + rt_vdso_addr += sym_rt->vvar_size; + } if (vdso_redirect_calls(rt_vdso_addr, vma_vdso->start, sym_rt, sym_img, compat_vdso)) { @@ -215,8 +226,8 @@ static int add_vdso_proxy(VmaEntry *vma_vdso, VmaEntry *vma_vvar, * it's auto-generated every new session if proxy required. */ sys_mprotect((void *)rt_vdso_addr, sym_rt->vdso_size, PROT_WRITE); - vdso_put_mark((void *)rt_vdso_addr, vma_vdso->start, - vma_vvar ? vma_vvar->start : VVAR_BAD_ADDR); + vdso_put_mark((void *)rt_vdso_addr, rt_vvar_addr, + vma_vdso->start, orig_vvar_addr); sys_mprotect((void *)rt_vdso_addr, sym_rt->vdso_size, VDSO_PROT); return 0; diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index 78bbe9e3b..eeae848eb 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -555,8 +555,8 @@ static int parasite_check_vdso_mark(struct parasite_vdso_vma_entry *args) return -EINVAL; } args->is_marked = 1; - args->proxy_vdso_addr = m->proxy_vdso_addr; - args->proxy_vvar_addr = m->proxy_vvar_addr; + args->proxy_vdso_addr = m->orig_vdso_addr; + args->proxy_vvar_addr = m->orig_vvar_addr; } else { args->is_marked = 0; args->proxy_vdso_addr = VDSO_BAD_ADDR; From 33b5b417da2178e0dacc584ef18cefc55bc94ad5 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 17 Jul 2017 15:39:54 +0300 Subject: [PATCH 0980/4375] vdso: Don't drop original VVAR VMA on dump I think, it's better if we still restore the original vvar as some code may expect vma to be there or may dereference pointer there. E.g., if we checkpointed task while it was on vdso page, it'll dereference pointer to vvar. Better keep it in vmas. So, the original code deleted it becase it was proxy_vvar_marked, which I think is misnaming problem. Having two vvar addresses named rt_ and orig_ describes what to do with them on dump. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/parasite.h | 5 ++-- criu/pie/parasite.c | 14 ++++++----- criu/vdso.c | 56 +++++++++++++++++++++-------------------- 3 files changed, 40 insertions(+), 35 deletions(-) diff --git a/criu/include/parasite.h b/criu/include/parasite.h index 115891f3b..9de0d2e9a 100644 --- a/criu/include/parasite.h +++ b/criu/include/parasite.h @@ -49,8 +49,9 @@ struct parasite_vma_entry struct parasite_vdso_vma_entry { unsigned long start; unsigned long len; - unsigned long proxy_vdso_addr; - unsigned long proxy_vvar_addr; + unsigned long orig_vdso_addr; + unsigned long orig_vvar_addr; + unsigned long rt_vvar_addr; int is_marked; bool try_fill_symtable; bool is_vdso; diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index eeae848eb..f3fa2e39a 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -554,13 +554,15 @@ static int parasite_check_vdso_mark(struct parasite_vdso_vma_entry *args) pr_err("vdso: Mark version mismatch!\n"); return -EINVAL; } - args->is_marked = 1; - args->proxy_vdso_addr = m->orig_vdso_addr; - args->proxy_vvar_addr = m->orig_vvar_addr; + args->is_marked = 1; + args->orig_vdso_addr = m->orig_vdso_addr; + args->orig_vvar_addr = m->orig_vvar_addr; + args->rt_vvar_addr = m->rt_vvar_addr; } else { - args->is_marked = 0; - args->proxy_vdso_addr = VDSO_BAD_ADDR; - args->proxy_vvar_addr = VVAR_BAD_ADDR; + args->is_marked = 0; + args->orig_vdso_addr = VDSO_BAD_ADDR; + args->orig_vvar_addr = VVAR_BAD_ADDR; + args->rt_vvar_addr = VVAR_BAD_ADDR; if (args->try_fill_symtable) { struct vdso_symtable t; diff --git a/criu/vdso.c b/criu/vdso.c index caed5efd8..ffe97b95e 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -118,10 +118,11 @@ static bool not_vvar_or_vdso(struct vma_area *vma) int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct vm_area_list *vma_area_list) { - unsigned long proxy_vdso_addr = VDSO_BAD_ADDR; - unsigned long proxy_vvar_addr = VVAR_BAD_ADDR; - struct vma_area *proxy_vdso_marked = NULL; - struct vma_area *proxy_vvar_marked = NULL; + unsigned long orig_vdso_addr = VDSO_BAD_ADDR; + unsigned long orig_vvar_addr = VVAR_BAD_ADDR; + unsigned long rt_vvar_addr = VVAR_BAD_ADDR; + struct vma_area *rt_vdso_marked = NULL; + struct vma_area *rt_vvar_marked = NULL; struct parasite_vdso_vma_entry *args; int fd = -1, exit_code = -1; enum vdso_check_t vcheck; @@ -152,10 +153,10 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, BUILD_BUG_ON(!(VDSO_PROT & VVAR_PROT)); if ((vma->e->prot & VVAR_PROT) == VVAR_PROT) { - if (proxy_vvar_addr != VVAR_BAD_ADDR && - proxy_vvar_addr == vma->e->start) { - BUG_ON(proxy_vvar_marked); - proxy_vvar_marked = vma; + if (rt_vvar_addr != VVAR_BAD_ADDR && + rt_vvar_addr == vma->e->start) { + BUG_ON(rt_vvar_marked); + rt_vvar_marked = vma; continue; } } @@ -188,13 +189,14 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, * area status. */ if (unlikely(args->is_marked)) { - if (proxy_vdso_marked) { + if (rt_vdso_marked) { pr_err("Ow! Second vdso mark detected!\n"); goto err; } - proxy_vdso_marked = vma; - proxy_vdso_addr = args->proxy_vdso_addr; - proxy_vvar_addr = args->proxy_vvar_addr; + rt_vdso_marked = vma; + orig_vdso_addr = args->orig_vdso_addr; + orig_vvar_addr = args->orig_vvar_addr; + rt_vvar_addr = args->rt_vvar_addr; continue; } @@ -225,38 +227,38 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, * There is marked vdso, it means such vdso is autogenerated * and must be dropped from vma list. */ - if (proxy_vdso_marked) { - pr_debug("vdso: Found marked at %lx (proxy vDSO at %lx VVAR at %lx)\n", - (long)proxy_vdso_marked->e->start, - (long)proxy_vdso_addr, (long)proxy_vvar_addr); + if (rt_vdso_marked) { + pr_debug("vdso: Found marked at %lx (orig vDSO at %lx VVAR at %lx)\n", + (long)rt_vdso_marked->e->start, + (long)orig_vdso_addr, (long)orig_vvar_addr); /* * Don't forget to restore the proxy vdso/vvar status, since * it's unknown to the kernel. */ list_for_each_entry(vma, &vma_area_list->h, list) { - if (vma->e->start == proxy_vdso_addr) { + if (vma->e->start == orig_vdso_addr) { vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VDSO; - pr_debug("vdso: Restore proxy vDSO status at %lx\n", + pr_debug("vdso: Restore orig vDSO status at %lx\n", (long)vma->e->start); - } else if (vma->e->start == proxy_vvar_addr) { + } else if (vma->e->start == orig_vvar_addr) { vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VVAR; - pr_debug("vdso: Restore proxy VVAR status at %lx\n", + pr_debug("vdso: Restore orig VVAR status at %lx\n", (long)vma->e->start); } } pr_debug("vdso: Droppping marked vdso at %lx\n", - (long)proxy_vdso_marked->e->start); - list_del(&proxy_vdso_marked->list); - xfree(proxy_vdso_marked); + (long)rt_vdso_marked->e->start); + list_del(&rt_vdso_marked->list); + xfree(rt_vdso_marked); vma_area_list->nr--; - if (proxy_vvar_marked) { + if (rt_vvar_marked) { pr_debug("vdso: Droppping marked vvar at %lx\n", - (long)proxy_vvar_marked->e->start); - list_del(&proxy_vvar_marked->list); - xfree(proxy_vvar_marked); + (long)rt_vvar_marked->e->start); + list_del(&rt_vvar_marked->list); + xfree(rt_vvar_marked); vma_area_list->nr--; } } From e101026bdf2b8953378eb296dffb99f4e6c20aa8 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 17 Jul 2017 15:39:55 +0300 Subject: [PATCH 0981/4375] vdso: Don't miss rt-vvar while searching As rt-vvar can be placed lower (by address) than rt-vdso, it likely will go earlier in vma_area_list. That means that at the moment, when we've found rt-vdso, we already passed rt-vvar and rt_vvar_marked pointer will not be initialized. Search for rt-vvar during the second vma list traverse, so we will always find it if it's present. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/vdso.c | 121 +++++++++++++++++++++++++++------------------------- 1 file changed, 63 insertions(+), 58 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index ffe97b95e..30c22aabd 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -106,9 +106,70 @@ static bool not_vvar_or_vdso(struct vma_area *vma) if (vma->e->flags & MAP_GROWSDOWN) return true; + BUILD_BUG_ON(!(VDSO_PROT & VVAR_PROT)); + if ((vma->e->prot & VVAR_PROT) != VVAR_PROT) + return true; + return false; } +static void drop_rt_vdso(struct vm_area_list *vma_area_list, + unsigned long orig_vdso_addr, unsigned long orig_vvar_addr, + unsigned long rt_vvar_addr, struct vma_area *rt_vdso_marked) +{ + struct vma_area *rt_vvar_marked = NULL; + struct vma_area *vma; + + if (!rt_vdso_marked) + return; + + /* + * There is marked vdso, it means such vdso is autogenerated + * and must be dropped from vma list. + */ + pr_debug("vdso: Found marked at %lx (orig vDSO at %lx VVAR at %lx)\n", + (long)rt_vdso_marked->e->start, orig_vdso_addr, orig_vvar_addr); + + /* + * Don't forget to restore the proxy vdso/vvar status, since + * they're unknown to the kernel. + * Also BTW search for rt-vvar to remove it later. + */ + list_for_each_entry(vma, &vma_area_list->h, list) { + if (vma->e->start == orig_vdso_addr) { + vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VDSO; + pr_debug("vdso: Restore orig vDSO status at %lx\n", + (long)vma->e->start); + } else if (vma->e->start == orig_vvar_addr) { + vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VVAR; + pr_debug("vdso: Restore orig VVAR status at %lx\n", + (long)vma->e->start); + } else if (rt_vvar_addr != VVAR_BAD_ADDR && + rt_vvar_addr == vma->e->start) { + BUG_ON(rt_vvar_marked); + if (not_vvar_or_vdso(vma)) { + pr_warn("Mark in rt-vdso points to vma, that doesn't look like vvar - skipping unmap\n"); + continue; + } + rt_vvar_marked = vma; + } + } + + pr_debug("vdso: Droppping marked vdso at %lx\n", + (long)rt_vdso_marked->e->start); + list_del(&rt_vdso_marked->list); + xfree(rt_vdso_marked); + vma_area_list->nr--; + + if (rt_vvar_marked) { + pr_debug("vdso: Droppping marked vvar at %lx\n", + (long)rt_vvar_marked->e->start); + list_del(&rt_vvar_marked->list); + xfree(rt_vvar_marked); + vma_area_list->nr--; + } +} + /* * The VMAs list might have proxy vdso/vvar areas left * from previous dump/restore cycle so we need to detect @@ -122,7 +183,6 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, unsigned long orig_vvar_addr = VVAR_BAD_ADDR; unsigned long rt_vvar_addr = VVAR_BAD_ADDR; struct vma_area *rt_vdso_marked = NULL; - struct vma_area *rt_vvar_marked = NULL; struct parasite_vdso_vma_entry *args; int fd = -1, exit_code = -1; enum vdso_check_t vcheck; @@ -143,24 +203,6 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, if (not_vvar_or_vdso(vma)) continue; - /* - * It might be possible VVAR area from marked - * vDSO zone, we need to detect it earlier than - * VDSO_PROT test because VVAR_PROT is a subset - * of it but don't yield continue here, - * sigh... what a mess. - */ - BUILD_BUG_ON(!(VDSO_PROT & VVAR_PROT)); - - if ((vma->e->prot & VVAR_PROT) == VVAR_PROT) { - if (rt_vvar_addr != VVAR_BAD_ADDR && - rt_vvar_addr == vma->e->start) { - BUG_ON(rt_vvar_marked); - rt_vvar_marked = vma; - continue; - } - } - if ((vma->e->prot & VDSO_PROT) != VDSO_PROT) continue; @@ -223,45 +265,8 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, } } - /* - * There is marked vdso, it means such vdso is autogenerated - * and must be dropped from vma list. - */ - if (rt_vdso_marked) { - pr_debug("vdso: Found marked at %lx (orig vDSO at %lx VVAR at %lx)\n", - (long)rt_vdso_marked->e->start, - (long)orig_vdso_addr, (long)orig_vvar_addr); - - /* - * Don't forget to restore the proxy vdso/vvar status, since - * it's unknown to the kernel. - */ - list_for_each_entry(vma, &vma_area_list->h, list) { - if (vma->e->start == orig_vdso_addr) { - vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VDSO; - pr_debug("vdso: Restore orig vDSO status at %lx\n", - (long)vma->e->start); - } else if (vma->e->start == orig_vvar_addr) { - vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VVAR; - pr_debug("vdso: Restore orig VVAR status at %lx\n", - (long)vma->e->start); - } - } - - pr_debug("vdso: Droppping marked vdso at %lx\n", - (long)rt_vdso_marked->e->start); - list_del(&rt_vdso_marked->list); - xfree(rt_vdso_marked); - vma_area_list->nr--; - - if (rt_vvar_marked) { - pr_debug("vdso: Droppping marked vvar at %lx\n", - (long)rt_vvar_marked->e->start); - list_del(&rt_vvar_marked->list); - xfree(rt_vvar_marked); - vma_area_list->nr--; - } - } + drop_rt_vdso(vma_area_list, orig_vdso_addr, orig_vvar_addr, + rt_vvar_addr, rt_vdso_marked); exit_code = 0; err: close_safe(&fd); From e89a2c044a12adee3a8575f9da3fb81783a50b3a Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 17 Jul 2017 15:39:56 +0300 Subject: [PATCH 0982/4375] vdso: Split parasite_fixup_vdso() once more It's hard to stop, when you've begun. No functional change is expected. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/vdso.c | 178 +++++++++++++++++++++++++++++----------------------- 1 file changed, 101 insertions(+), 77 deletions(-) diff --git a/criu/vdso.c b/criu/vdso.c index 30c22aabd..ce62996fb 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -113,9 +113,16 @@ static bool not_vvar_or_vdso(struct vma_area *vma) return false; } +/* Contains addresses from vdso mark */ +struct vdso_quarter { + unsigned long orig_vdso; + unsigned long orig_vvar; + unsigned long rt_vdso; + unsigned long rt_vvar; +}; + static void drop_rt_vdso(struct vm_area_list *vma_area_list, - unsigned long orig_vdso_addr, unsigned long orig_vvar_addr, - unsigned long rt_vvar_addr, struct vma_area *rt_vdso_marked) + struct vdso_quarter *addr, struct vma_area *rt_vdso_marked) { struct vma_area *rt_vvar_marked = NULL; struct vma_area *vma; @@ -128,7 +135,7 @@ static void drop_rt_vdso(struct vm_area_list *vma_area_list, * and must be dropped from vma list. */ pr_debug("vdso: Found marked at %lx (orig vDSO at %lx VVAR at %lx)\n", - (long)rt_vdso_marked->e->start, orig_vdso_addr, orig_vvar_addr); + (long)rt_vdso_marked->e->start, addr->orig_vdso, addr->orig_vvar); /* * Don't forget to restore the proxy vdso/vvar status, since @@ -136,16 +143,16 @@ static void drop_rt_vdso(struct vm_area_list *vma_area_list, * Also BTW search for rt-vvar to remove it later. */ list_for_each_entry(vma, &vma_area_list->h, list) { - if (vma->e->start == orig_vdso_addr) { + if (vma->e->start == addr->orig_vdso) { vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VDSO; pr_debug("vdso: Restore orig vDSO status at %lx\n", (long)vma->e->start); - } else if (vma->e->start == orig_vvar_addr) { + } else if (vma->e->start == addr->orig_vvar) { vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VVAR; pr_debug("vdso: Restore orig VVAR status at %lx\n", (long)vma->e->start); - } else if (rt_vvar_addr != VVAR_BAD_ADDR && - rt_vvar_addr == vma->e->start) { + } else if (addr->rt_vvar != VVAR_BAD_ADDR && + addr->rt_vvar == vma->e->start) { BUG_ON(rt_vvar_marked); if (not_vvar_or_vdso(vma)) { pr_warn("Mark in rt-vdso points to vma, that doesn't look like vvar - skipping unmap\n"); @@ -170,6 +177,79 @@ static void drop_rt_vdso(struct vm_area_list *vma_area_list, } } +/* + * I need to poke every potentially marked vma, + * otherwise if task never called for vdso functions + * page frame number won't be reported. + * + * Moreover, if page frame numbers are not accessible + * we have to scan the vma zone for vDSO elf structure + * which gonna be a slow way. + */ +static int check_if_vma_is_vdso(enum vdso_check_t vcheck, int pagemap_fd, + struct parasite_ctl *ctl, struct vma_area *vma, + struct vma_area **rt_vdso_marked, struct vdso_quarter *addr) +{ + struct parasite_vdso_vma_entry *args; + bool has_vdso_pfn = false; + + args = compel_parasite_args(ctl, struct parasite_vdso_vma_entry); + + if (not_vvar_or_vdso(vma)) + return 0; + + if ((vma->e->prot & VDSO_PROT) != VDSO_PROT) + return 0; + + args->start = vma->e->start; + args->len = vma_area_len(vma); + args->try_fill_symtable = (vcheck == VDSO_CHECK_SYMS); + args->is_vdso = false; + + if (compel_rpc_call_sync(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) { + pr_err("Parasite failed to poke for mark\n"); + return -1; + } + + if (unlikely(args->is_marked)) { + if (*rt_vdso_marked) { + pr_err("Ow! Second vdso mark detected!\n"); + return -1; + } + *rt_vdso_marked = vma; + addr->orig_vdso = args->orig_vdso_addr; + addr->orig_vvar = args->orig_vvar_addr; + addr->rt_vvar = args->rt_vvar_addr; + return 0; + } + + if (vcheck == VDSO_NO_CHECK) + return 0; + + if (vcheck == VDSO_CHECK_PFN) { + if (check_vdso_by_pfn(pagemap_fd, vma, &has_vdso_pfn) < 0) { + pr_err("Failed checking vdso by pfn\n"); + return -1; + } + } + + if (has_vdso_pfn || args->is_vdso) { + if (!vma_area_is(vma, VMA_AREA_VDSO)) { + pr_debug("Restore vDSO status by pfn/symtable at %lx\n", + (long)vma->e->start); + vma->e->status |= VMA_AREA_VDSO; + } + } else { + if (unlikely(vma_area_is(vma, VMA_AREA_VDSO))) { + pr_debug("Drop mishinted vDSO status at %lx\n", + (long)vma->e->start); + vma->e->status &= ~VMA_AREA_VDSO; + } + } + + return 0; +} + /* * The VMAs list might have proxy vdso/vvar areas left * from previous dump/restore cycle so we need to detect @@ -179,17 +259,18 @@ static void drop_rt_vdso(struct vm_area_list *vma_area_list, int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct vm_area_list *vma_area_list) { - unsigned long orig_vdso_addr = VDSO_BAD_ADDR; - unsigned long orig_vvar_addr = VVAR_BAD_ADDR; - unsigned long rt_vvar_addr = VVAR_BAD_ADDR; struct vma_area *rt_vdso_marked = NULL; - struct parasite_vdso_vma_entry *args; - int fd = -1, exit_code = -1; + struct vdso_quarter addr = { + .orig_vdso = VDSO_BAD_ADDR, + .orig_vvar = VVAR_BAD_ADDR, + .rt_vdso = VDSO_BAD_ADDR, + .rt_vvar = VVAR_BAD_ADDR, + }; enum vdso_check_t vcheck; struct vma_area *vma; + int fd = -1; vcheck = get_vdso_check_type(ctl); - args = compel_parasite_args(ctl, struct parasite_vdso_vma_entry); if (vcheck == VDSO_CHECK_PFN) { BUG_ON(vdso_pfn == VDSO_BAD_PFN); fd = open_proc(pid, "pagemap"); @@ -198,79 +279,22 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, } list_for_each_entry(vma, &vma_area_list->h, list) { - bool has_vdso_pfn = false; - - if (not_vvar_or_vdso(vma)) - continue; - - if ((vma->e->prot & VDSO_PROT) != VDSO_PROT) - continue; - - /* - * I need to poke every potentially marked vma, - * otherwise if task never called for vdso functions - * page frame number won't be reported. - * - * Moreover, if page frame numbers are not accessible - * we have to scan the vma zone for vDSO elf structure - * which gonna be a slow way. - */ - args->start = vma->e->start; - args->len = vma_area_len(vma); - args->try_fill_symtable = (vcheck == VDSO_CHECK_SYMS); - args->is_vdso = false; - - if (compel_rpc_call_sync(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) { - pr_err("Parasite failed to poke for mark\n"); - goto err; - } - /* * Defer handling marked vdso until we walked over * all vmas and restore potentially remapped vDSO * area status. */ - if (unlikely(args->is_marked)) { - if (rt_vdso_marked) { - pr_err("Ow! Second vdso mark detected!\n"); - goto err; - } - rt_vdso_marked = vma; - orig_vdso_addr = args->orig_vdso_addr; - orig_vvar_addr = args->orig_vvar_addr; - rt_vvar_addr = args->rt_vvar_addr; - continue; - } - - if (vcheck == VDSO_NO_CHECK) - continue; - - if (vcheck == VDSO_CHECK_PFN && check_vdso_by_pfn(fd, vma, &has_vdso_pfn) < 0) { - pr_err("Failed checking vdso by pfn for %d\n", pid); - goto err; - } - - if (has_vdso_pfn || args->is_vdso) { - if (!vma_area_is(vma, VMA_AREA_VDSO)) { - pr_debug("Restore vDSO status by pfn/symtable at %lx\n", - (long)vma->e->start); - vma->e->status |= VMA_AREA_VDSO; - } - } else { - if (unlikely(vma_area_is(vma, VMA_AREA_VDSO))) { - pr_debug("Drop mishinted vDSO status at %lx\n", - (long)vma->e->start); - vma->e->status &= ~VMA_AREA_VDSO; - } + if (check_if_vma_is_vdso(vcheck, fd, ctl, vma, + &rt_vdso_marked, &addr)) { + close_safe(&fd); + return -1; } } - drop_rt_vdso(vma_area_list, orig_vdso_addr, orig_vvar_addr, - rt_vvar_addr, rt_vdso_marked); - exit_code = 0; -err: + drop_rt_vdso(vma_area_list, &addr, rt_vdso_marked); + close_safe(&fd); - return exit_code; + return 0; } static int vdso_parse_maps(pid_t pid, struct vdso_maps *s) From df289c04fcfc71326d6675d9f65d27502e563f17 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 17 Jul 2017 15:39:57 +0300 Subject: [PATCH 0983/4375] vdso: Add a comment about rt-vdso and decreasing nr. of symbols No functional change is expected :-D Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/parasite-vdso.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 5285a2c31..a31363352 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -214,6 +214,14 @@ static int add_vdso_proxy(VmaEntry *vma_vdso, VmaEntry *vma_vvar, rt_vdso_addr += sym_rt->vvar_size; } + /* + * Note: we assume that after first migration with inserted + * rt-vdso and trampoilines on the following migrations + * number of vdso symbols will not decrease. + * We don't save the content of original vdso under inserted + * jumps, so we can't remove them if on the following migration + * found that number of symbols in vdso has decreased. + */ if (vdso_redirect_calls(rt_vdso_addr, vma_vdso->start, sym_rt, sym_img, compat_vdso)) { pr_err("Failed to proxify dumpee contents\n"); From 8459a3de9df28a6d24b1056045cec29f5ef9ed20 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 17 Jul 2017 15:39:58 +0300 Subject: [PATCH 0984/4375] vdso/zdtm: Add iterative proxification test Test for previously fixed bugs for vdso-trampolines insertion: - unmapping original vvar (which went unnoticed) - leaving rt-vvar after each C/R cycle and resulting pollution Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/jenkins/criu-fault.sh | 1 + test/zdtm/static/Makefile | 1 + test/zdtm/static/vdso-proxy.c | 147 ++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 test/zdtm/static/vdso-proxy.c diff --git a/test/jenkins/criu-fault.sh b/test/jenkins/criu-fault.sh index b7879116d..1e9862f7d 100755 --- a/test/jenkins/criu-fault.sh +++ b/test/jenkins/criu-fault.sh @@ -10,6 +10,7 @@ prep ./test/zdtm.py run -t zdtm/static/env00 --fault 129 -f uns || fail ./test/zdtm.py run -t zdtm/transition/fork --fault 130 -f h || fail ./test/zdtm.py run -t zdtm/static/vdso01 --fault 127 || fail +./test/zdtm.py run -t zdtm/static/vdso-proxy --fault 127 --iters 3 || fail ./test/zdtm.py run -t zdtm/static/mntns_ghost --fault 2 --keep-going --report report || fail ./test/zdtm.py run -t zdtm/static/mntns_ghost --fault 4 --keep-going --report report || fail diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 12962c21d..67de8b8ac 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -55,6 +55,7 @@ TST_NOFILE := \ vdso00 \ vdso01 \ vdso02 \ + vdso-proxy \ utsname \ pstree \ sockets01 \ diff --git a/test/zdtm/static/vdso-proxy.c b/test/zdtm/static/vdso-proxy.c new file mode 100644 index 000000000..eadd9af8b --- /dev/null +++ b/test/zdtm/static/vdso-proxy.c @@ -0,0 +1,147 @@ +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Compare mappings before/after C/R for vdso/vvar presence. Should run iterative under vdso proxy fault-injection.\n"; +const char *test_author = "Dmitry Safonov "; + +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) +#define VDSO_BAD_ADDR (-1ul) +#define MAX_VMAS 80 +#define BUF_SIZE 1024 + +/* + * After C/R with vdso trampolines insertion, there should + * be added one or two vmas: vdso and possibly vvar. + * We need to check that nr. vmas after C/R <= +2 new vmas. + * Also previous vdso/vvar vma should still be present after C/R. + */ +struct vm_area { + unsigned long start; + unsigned long end; + bool is_vvar_or_vdso; +}; + +static char buf[BUF_SIZE]; + +static int parse_maps(struct vm_area *vmas) +{ + FILE *maps; + int i; + + maps = fopen("/proc/self/maps", "r"); + if (maps == NULL) { + pr_err("Failed to open maps file: %m\n"); + return -1; + } + + for (i = 0; i < MAX_VMAS; i++) { + struct vm_area *v = &vmas[i]; + char *end; + + if (fgets(buf, BUF_SIZE, maps) == NULL) + break; + + v->start = strtoul(buf, &end, 16); + v->end = strtoul(end + 1, NULL, 16); + v->is_vvar_or_vdso |= strstr(buf, "[vdso]") != NULL; + v->is_vvar_or_vdso |= strstr(buf, "[vvar]") != NULL; + test_msg("[NOTE]\tVMA: [%#lx, %#lx]\n", v->start, v->end); + } + + if (i == MAX_VMAS) { + pr_err("Number of VMAs is bigger than reserved array's size\n"); + return -1; + } + + if (fclose(maps)) { + pr_err("Failed to close maps file: %m\n"); + return -1; + } + + return i; +} + +int compare_vmas(struct vm_area *vmax, struct vm_area *vmay) +{ + if (vmax->start > vmay->start) + return 1; + if (vmax->start < vmay->start) + return -1; + if (vmax->end > vmay->end) + return 1; + if (vmax->end < vmay->end) + return -1; + + return 0; +} + +static int check_vvar_vdso(struct vm_area *before, struct vm_area *after) +{ + int i, j = 0; + + for (i = 0; i < MAX_VMAS && j < MAX_VMAS; i++, j++) { + int cmp = compare_vmas(&before[i], &after[j]); + + if (cmp == 0) + continue; + + if (cmp < 0) {/* Lost mapping */ + test_msg("[NOTE]\tLost mapping: %#lx-%#lx\n", + before[i].start, before[i].end); + j--; + if (before[i].is_vvar_or_vdso) { + fail("Lost vvar/vdso mapping"); + return -1; + } + continue; + } + + test_msg("[NOTE]\tNew mapping appeared: %#lx-%#lx\n", + after[j].start, after[j].end); + i--; + } + + return 0; +} + +static struct vm_area vmas_before[MAX_VMAS]; +static struct vm_area vmas_after[MAX_VMAS]; + +int main(int argc, char *argv[]) +{ + int nr_before, nr_after; + + test_init(argc, argv); + + test_msg("[NOTE]\tMappings before:\n"); + nr_before = parse_maps(vmas_before); + if (nr_before < 0) { + pr_perror("Faied to parse maps"); + return -1; + } + + test_daemon(); + test_waitsig(); + + test_msg("[NOTE]\tMappings after:\n"); + nr_after = parse_maps(vmas_after); + if (nr_after < 0) { + pr_perror("Faied to parse maps"); + return -1; + } + + /* After restore vDSO/VVAR blobs must remain in the old place. */ + if (check_vvar_vdso(vmas_before, vmas_after)) + return -1; + + if (nr_before + 2 < nr_after) { + fail("There is more than two (VVAR/vDSO) vmas added after C/R"); + return -1; + } + + pass(); + + return 0; +} From 3f6cce985080b788cfdcc0ce28a19b0010dd79f1 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 17 Jul 2017 15:39:59 +0300 Subject: [PATCH 0985/4375] vdso/restorer: Don't map compatible vdso if it was unmapped If there is no vdso in images - we don't need to map it. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index fe4b64a7b..b26cc2be3 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1134,24 +1134,29 @@ static int wait_zombies(struct task_restore_args *task_args) return 0; } -static bool vdso_needs_parking(struct task_restore_args *args) +static bool vdso_unmapped(struct task_restore_args *args) { unsigned int i; - /* Compatible vDSO will be mapped, not moved */ - if (args->compatible_mode) - return false; - /* Don't park rt-vdso or rt-vvar if dumpee doesn't have them */ for (i = 0; i < args->vmas_n; i++) { VmaEntry *vma = &args->vmas[i]; if (vma_entry_is(vma, VMA_AREA_VDSO) || vma_entry_is(vma, VMA_AREA_VVAR)) - return true; + return false; } - return false; + return true; +} + +static bool vdso_needs_parking(struct task_restore_args *args) +{ + /* Compatible vDSO will be mapped, not moved */ + if (args->compatible_mode) + return false; + + return !vdso_unmapped(args); } /* @@ -1222,8 +1227,10 @@ long __export_restore_task(struct task_restore_args *args) goto core_restore_end; /* Map compatible vdso */ - if (args->compatible_mode && vdso_map_compat(args->vdso_rt_parked_at)) - goto core_restore_end; + if (!vdso_unmapped(args) && args->compatible_mode) { + if (vdso_map_compat(args->vdso_rt_parked_at)) + goto core_restore_end; + } /* Shift private vma-s to the left */ for (i = 0; i < args->vmas_n; i++) { From b8f3fca4891b4844407caad8e9a1239ca88c7a5c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 17 Jul 2017 15:40:00 +0300 Subject: [PATCH 0986/4375] vdso: Don't parse self-maps if kdat.can_map_vdso Just map vdso at restorer's parking zone, no need for searching it in CRIU and remap it to park zone. That will save some open()/read()/close() syscalls for parsing maps file. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/include/asm/restorer.h | 1 + criu/arch/arm/include/asm/restorer.h | 1 + criu/arch/ppc64/include/asm/restorer.h | 1 + criu/arch/x86/include/asm/restorer.h | 5 +++++ criu/arch/x86/restorer.c | 10 ++++++++++ criu/cr-restore.c | 1 + criu/include/restorer.h | 1 + criu/pie/parasite-vdso.c | 19 +------------------ criu/pie/restorer.c | 11 ++++++++--- criu/vdso.c | 22 +++++++++++++++------- 10 files changed, 44 insertions(+), 28 deletions(-) diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h index 000d3f8ba..bef85f3a3 100644 --- a/criu/arch/aarch64/include/asm/restorer.h +++ b/criu/arch/aarch64/include/asm/restorer.h @@ -54,6 +54,7 @@ #define kdat_compatible_cr() 0 #define kdat_can_map_vdso() 0 +#define arch_map_vdso(map, compat) -1 int restore_gpregs(struct rt_sigframe *f, UserAarch64RegsEntry *r); int restore_nonsigframe_gpregs(UserAarch64RegsEntry *r); diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h index 3da166a44..d9208185f 100644 --- a/criu/arch/arm/include/asm/restorer.h +++ b/criu/arch/arm/include/asm/restorer.h @@ -55,6 +55,7 @@ #define kdat_compatible_cr() 0 #define kdat_can_map_vdso() 0 +#define arch_map_vdso(map, compat) -1 int restore_gpregs(struct rt_sigframe *f, UserArmRegsEntry *r); int restore_nonsigframe_gpregs(UserArmRegsEntry *r); diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h index ad9c39a78..3fffa833c 100644 --- a/criu/arch/ppc64/include/asm/restorer.h +++ b/criu/arch/ppc64/include/asm/restorer.h @@ -50,6 +50,7 @@ #define kdat_compatible_cr() 0 #define kdat_can_map_vdso() 0 +#define arch_map_vdso(map, compat) -1 int restore_gpregs(struct rt_sigframe *f, UserPpc64RegsEntry *r); int restore_nonsigframe_gpregs(UserPpc64RegsEntry *r); diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index 04509ff2f..e39675d95 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -76,6 +76,10 @@ static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) # define ARCH_MAP_VDSO_32 0x2002 #endif +#ifndef ARCH_MAP_VDSO_64 +# define ARCH_MAP_VDSO_64 0x2003 +#endif + extern int kdat_compatible_cr(void); extern int kdat_can_map_vdso(void); @@ -114,5 +118,6 @@ int restore_nonsigframe_gpregs(UserX86RegsEntry *r); int ptrace_set_breakpoint(pid_t pid, void *addr); int ptrace_flush_breakpoints(pid_t pid); +extern int arch_map_vdso(unsigned long map_at, bool compatible); #endif diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index d6da030b2..2d335d5e1 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -13,6 +13,16 @@ #include "log.h" #include "cpu.h" +int arch_map_vdso(unsigned long map_at, bool compatible) +{ + int vdso_type = compatible ? ARCH_MAP_VDSO_32 : ARCH_MAP_VDSO_64; + + pr_debug("Mapping %s vDSO at %lx\n", + compatible ? "compatible" : "native", map_at); + + return sys_arch_prctl(vdso_type, map_at); +} + int restore_nonsigframe_gpregs(UserX86RegsEntry *r) { long ret; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index d1d2b3e63..83e9de1bb 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3310,6 +3310,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns task_args->vdso_rt_parked_at = (unsigned long)mem; task_args->vdso_maps_rt = vdso_maps_rt; task_args->vdso_rt_size = vdso_rt_size; + task_args->can_map_vdso = kdat.can_map_vdso; #endif new_sp = restorer_stack(task_args->t->mz); diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 789064ee1..6e1c78579 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -191,6 +191,7 @@ struct task_restore_args { bool compatible_mode; + bool can_map_vdso; #ifdef CONFIG_VDSO unsigned long vdso_rt_size; struct vdso_maps vdso_maps_rt; /* runtime vdso symbols */ diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index a31363352..8072c11f7 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -74,19 +74,8 @@ int vdso_do_park(struct vdso_maps *rt, unsigned long park_at, return ret; } +/* XXX: move in arch/ */ #if defined(CONFIG_X86_64) && defined(CONFIG_COMPAT) -int vdso_map_compat(unsigned long map_at) -{ - int ret; - - pr_debug("Mapping compatible vDSO at %lx\n", map_at); - - ret = sys_arch_prctl(ARCH_MAP_VDSO_32, map_at); - if (ret < 0) - return ret; - return 0; -} - int __vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t, bool compat_vdso) { @@ -96,12 +85,6 @@ int __vdso_fill_symtable(uintptr_t mem, size_t size, return vdso_fill_symtable(mem, size, t); } #else -int vdso_map_compat(unsigned long __always_unused map_at) -{ - /* shouldn't be called on !CONFIG_COMPAT */ - BUG(); - return 0; -} int __vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t, bool __always_unused compat_vdso) { diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index b26cc2be3..48b064d95 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1156,6 +1156,9 @@ static bool vdso_needs_parking(struct task_restore_args *args) if (args->compatible_mode) return false; + if (args->can_map_vdso) + return false; + return !vdso_unmapped(args); } @@ -1226,10 +1229,12 @@ long __export_restore_task(struct task_restore_args *args) bootstrap_start, bootstrap_len, args->task_size)) goto core_restore_end; - /* Map compatible vdso */ - if (!vdso_unmapped(args) && args->compatible_mode) { - if (vdso_map_compat(args->vdso_rt_parked_at)) + /* Map vdso that wasn't parked */ + if (!vdso_unmapped(args) && args->can_map_vdso) { + if (arch_map_vdso(args->vdso_rt_parked_at, + args->compatible_mode) < 0) { goto core_restore_end; + } } /* Shift private vma-s to the left */ diff --git a/criu/vdso.c b/criu/vdso.c index ce62996fb..64046bc16 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -572,14 +572,22 @@ int vdso_init_restore(void) if (vdso_maps.vdso_start != VDSO_BAD_ADDR) return 0; - if (vdso_parse_maps(PROC_SELF, &vdso_maps)) { - pr_err("Failed reading self/maps for filling vdso/vvar bounds\n"); - return -1; - } + /* + * Parsing self-maps here only to find vvar/vdso vmas in + * criu's address space, for further remapping to restorer's + * parking zone. Don't need to do this if map-vdso API + * is present. + */ + if (!kdat.can_map_vdso) { + if (vdso_parse_maps(PROC_SELF, &vdso_maps)) { + pr_err("Failed reading self/maps for filling vdso/vvar bounds\n"); + return -1; + } - if (!is_kdat_vdso_sym_valid()) { - pr_err("Kdat sizes of vdso/vvar differ to maps file \n"); - return -1; + if (!is_kdat_vdso_sym_valid()) { + pr_err("Kdat sizes of vdso/vvar differ to maps file \n"); + return -1; + } } vdso_maps.sym = kdat.vdso_sym; From ff28da95040d191b0ca55efdb069d2211fa2f9b6 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 17 Jul 2017 15:40:01 +0300 Subject: [PATCH 0987/4375] vdso/kdat: Add test for preserving "[vdso]" hint after mremap() If it does preserve, we can omit checking pagemap for dumpee or filling symtable in parasite. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/kerndat.h | 1 + criu/include/vdso.h | 2 ++ criu/kerndat.c | 3 ++ criu/vdso.c | 75 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+) diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index d34ffa1e2..950755b5e 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -56,6 +56,7 @@ struct kerndat_s { unsigned long uffd_features; bool has_thp_disable; bool can_map_vdso; + bool vdso_hint_reliable; #ifdef CONFIG_VDSO struct vdso_symtable vdso_sym; #ifdef CONFIG_COMPAT diff --git a/criu/include/vdso.h b/criu/include/vdso.h index b6110e442..3c4c0ecbd 100644 --- a/criu/include/vdso.h +++ b/criu/include/vdso.h @@ -16,6 +16,7 @@ extern struct vdso_maps vdso_maps_compat; extern int vdso_init_dump(void); extern int vdso_init_restore(void); extern int kerndat_vdso_fill_symtable(void); +extern int kerndat_vdso_preserves_hint(void); extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct vm_area_list *vma_area_list); @@ -30,6 +31,7 @@ extern void compat_vdso_helper(struct vdso_maps *native, int pipe_fd, #define vdso_init_dump() (0) #define vdso_init_restore() (0) #define kerndat_vdso_fill_symtable() (0) +#define kerndat_vdso_preserves_hint() (0) #define parasite_fixup_vdso(ctl, pid, vma_area_list) (0) #endif /* CONFIG_VDSO */ diff --git a/criu/kerndat.c b/criu/kerndat.c index cad2597b6..de33b049d 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -870,6 +870,9 @@ int kerndat_init(void) /* Needs kdat.compat_cr filled before */ if (!ret) ret = kerndat_vdso_fill_symtable(); + /* Depends on kerndat_vdso_fill_symtable() */ + if (!ret) + ret = kerndat_vdso_preserves_hint(); kerndat_lsm(); kerndat_mmap_min_addr(); diff --git a/criu/vdso.c b/criu/vdso.c index 64046bc16..013a9a6c2 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -621,3 +621,78 @@ int kerndat_vdso_fill_symtable(void) return 0; } + +/* + * On x86 pre-v3.16 kernels can lose "[vdso]" hint + * in /proc/.../maps file after mremap()'ing vdso vma. + * Depends on kerndat_vdso_fill_symtable() - assuming that + * vdso_maps and vdso_maps_compat are filled. + */ +int kerndat_vdso_preserves_hint(void) +{ + struct vdso_maps vdso_maps_after; + int status, ret = -1; + pid_t child; + + kdat.vdso_hint_reliable = 0; + + if (vdso_maps.vdso_start == VDSO_BAD_ADDR) + return 0; + + child = fork(); + if (child < 0) { + pr_perror("fork() failed"); + return -1; + } + + if (child == 0) { + unsigned long vdso_addr = vdso_maps.vdso_start; + unsigned long vdso_size = vdso_maps.sym.vdso_size; + void *new_addr; + + new_addr = mmap(0, vdso_size, PROT_NONE, + MAP_ANON | MAP_PRIVATE, -1, 0); + if (new_addr == MAP_FAILED) + exit(1); + + child = getpid(); + new_addr = (void *)syscall(SYS_mremap, vdso_addr, vdso_size, + vdso_size, MREMAP_MAYMOVE | MREMAP_FIXED, new_addr); + if (new_addr == MAP_FAILED) + syscall(SYS_exit, 2); + syscall(SYS_kill, child, SIGSTOP); + syscall(SYS_exit, 3); + } + + waitpid(child, &status, WUNTRACED); + if (WIFEXITED(status)) { + int ret = WEXITSTATUS(status); + + pr_err("Child unexpectedly exited with %d\n", ret); + goto out; + } else if (WIFSIGNALED(status)) { + int sig = WTERMSIG(status); + + pr_err("Child unexpectedly signaled with %d: %s\n", + sig, strsignal(sig)); + goto out; + } else if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) { + pr_err("Child is unstoppable or was stopped by other means\n"); + goto out_kill; + } + + if (vdso_parse_maps(child, &vdso_maps_after)) { + pr_err("Failed parsing maps for child helper\n"); + goto out_kill; + } + + if (vdso_maps_after.vdso_start != VDSO_BAD_ADDR) + kdat.vdso_hint_reliable = 1; + + ret = 0; +out_kill: + kill(child, SIGKILL); + waitpid(child, &status, 0); +out: + return ret; +} From 88de3d1cbe8827272268a2bbeed5c592fee15108 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 17 Jul 2017 15:40:02 +0300 Subject: [PATCH 0988/4375] vdso: Don't read pagemap or parse symtable under vdso_hint_reliable We can save some syscalls for *each* dumpee if we don't open()/seek()/read()/close() /proc/pid/pagemap for each dumpee and even don't use parasite to parse symtable if pagemap is unavailable. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/vdso.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/criu/vdso.c b/criu/vdso.c index 013a9a6c2..731f94165 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -55,7 +55,12 @@ static enum vdso_check_t get_vdso_check_type(struct parasite_ctl *ctl) * hint stays in /proc/../maps file and is correct. */ if (!compel_mode_native(ctl)) { - pr_info("Don't check vdso\n"); + pr_info("Don't check vdso for compat task\n"); + return VDSO_NO_CHECK; + } + + if (kdat.vdso_hint_reliable) { + pr_info("vDSO hint is reliable - omit checking\n"); return VDSO_NO_CHECK; } From 4671d7426045022723d31f104c72feb9f40b3898 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 21 Jul 2017 18:44:37 +0300 Subject: [PATCH 0989/4375] s390/vdso: Add arch-stubs for vdso map API That's a merge conflict between vdso patches set and s390 set. Cc: Michael Holzheu Cc: Alice Frosi Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/s390/include/asm/restorer.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/arch/s390/include/asm/restorer.h b/criu/arch/s390/include/asm/restorer.h index 0fd23cff1..63e099863 100644 --- a/criu/arch/s390/include/asm/restorer.h +++ b/criu/arch/s390/include/asm/restorer.h @@ -40,6 +40,8 @@ : "0", "1", "2", "3", "4", "5", "6", "cc", "memory") #define kdat_compatible_cr() 0 +#define kdat_can_map_vdso() 0 +#define arch_map_vdso(map, compat) -1 int restore_gpregs(struct rt_sigframe *f, UserS390RegsEntry *r); int restore_nonsigframe_gpregs(UserS390RegsEntry *r); From 82cb4b4bd419b1ac63c49db61e488ac7c875bc3e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 6 Jun 2017 09:50:57 +0300 Subject: [PATCH 0990/4375] mount: don't use phys_stat_resolve_dev() in open_mount() We don't need to look up a mount info element, because we already have it there. Cc: Cyrill Gorcunov Cc: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/mount.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 8773ca2e8..672930945 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1019,8 +1019,8 @@ int mnt_is_dir(struct mount_info *pm) */ int __open_mountpoint(struct mount_info *pm, int mnt_fd) { - dev_t dev; struct stat st; + int dev; int ret; if (mnt_fd == -1) { @@ -1049,7 +1049,7 @@ int __open_mountpoint(struct mount_info *pm, int mnt_fd) goto err; } - dev = phys_stat_resolve_dev(pm->nsid, st.st_dev, pm->ns_mountpoint + 1); + dev = MKKDEV(major(st.st_dev), minor(st.st_dev)); /* * Always check for @s_dev_rt here, because the @s_dev * from the image (in case of restore) has all rights @@ -1058,7 +1058,7 @@ int __open_mountpoint(struct mount_info *pm, int mnt_fd) */ if (dev != pm->s_dev_rt) { pr_err("The file system %#x %#x (%#x) %s %s is inaccessible\n", - pm->s_dev, pm->s_dev_rt, (int)dev, + pm->s_dev, pm->s_dev_rt, dev, pm->fstype->name, pm->ns_mountpoint); goto err; } From dc4d61f84f7c7ed43758af1724d2c34557782393 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 24 Aug 2017 14:57:41 +0300 Subject: [PATCH 0991/4375] compel/test: fix "infect" test compilation errors Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- compel/test/infect/parasite.c | 1 + compel/test/infect/spy.c | 20 +++++++++++++++----- compel/test/infect/victim.c | 3 ++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/compel/test/infect/parasite.c b/compel/test/infect/parasite.c index bdbe72229..f18580966 100644 --- a/compel/test/infect/parasite.c +++ b/compel/test/infect/parasite.c @@ -1,6 +1,7 @@ #include #include +#include /* * Stubs for std compel plugin. diff --git a/compel/test/infect/spy.c b/compel/test/infect/spy.c index b8a65c345..a5aba7308 100644 --- a/compel/test/infect/spy.c +++ b/compel/test/infect/spy.c @@ -87,7 +87,9 @@ static inline int chk(int fd, int val) { int v = 0; - read(fd, &v, sizeof(v)); + if (read(fd, &v, sizeof(v)) != sizeof(v)) + return 0; + printf("%d, want %d\n", v, val); return v == val; } @@ -118,8 +120,12 @@ int main(int argc, char **argv) /* * Tell the little guy some numbers */ - i = 1; write(p_in[1], &i, sizeof(i)); - i = 42; write(p_in[1], &i, sizeof(i)); + i = 1; + if (write(p_in[1], &i, sizeof(i)) != sizeof(i)) + return 1; + i = 42; + if (write(p_in[1], &i, sizeof(i)) != sizeof(i)) + return 1; printf("Checking the victim alive\n"); pass = chk(p_out[0], 1); @@ -138,8 +144,12 @@ int main(int argc, char **argv) /* * Tell the victim some more stuff to check it's alive */ - i = 1234; write(p_in[1], &i, sizeof(i)); - i = 4096; write(p_in[1], &i, sizeof(i)); + i = 1234; + if (write(p_in[1], &i, sizeof(i)) != sizeof(i)) + return 1; + i = 4096; + if (write(p_in[1], &i, sizeof(i)) != sizeof(i)) + return 1; /* * Stop the victim and check the infection went well diff --git a/compel/test/infect/victim.c b/compel/test/infect/victim.c index b37688b84..f94613fa1 100644 --- a/compel/test/infect/victim.c +++ b/compel/test/infect/victim.c @@ -8,7 +8,8 @@ int main(int argc, char **argv) if (read(0, &i, sizeof(i)) != sizeof(i)) break; - write(1, &i, sizeof(i)); + if (write(1, &i, sizeof(i)) != sizeof(i)) + break; } return 0; From 7148e16b311fd66aa227aa7b3d85c595a140a231 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 30 Aug 2017 15:28:23 +0300 Subject: [PATCH 0992/4375] sk-tcp: Print libsoccr_save() error message Improve dump_tcp_conn_state() *debugibility*. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-tcp.c | 4 +++- soccr/soccr.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c index 20ea528bb..5fe93ab0a 100644 --- a/criu/sk-tcp.c +++ b/criu/sk-tcp.c @@ -113,8 +113,10 @@ static int dump_tcp_conn_state(struct inet_sk_desc *sk) struct libsoccr_sk_data data; ret = libsoccr_save(socr, &data, sizeof(data)); - if (ret < 0) + if (ret < 0) { + pr_err("libsoccr_save() failed with %d\n", ret); goto err_r; + } if (ret != sizeof(data)) { pr_err("This libsocr is not supported (%d vs %d)\n", ret, (int)sizeof(data)); diff --git a/soccr/soccr.c b/soccr/soccr.c index 583f1eaaa..48469aaab 100644 --- a/soccr/soccr.c +++ b/soccr/soccr.c @@ -374,10 +374,10 @@ int libsoccr_save(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigne sk->flags |= SK_FLAG_FREE_SQ | SK_FLAG_FREE_RQ; if (get_queue(sk->fd, TCP_RECV_QUEUE, &data->inq_seq, data->inq_len, &sk->recv_queue)) - return -4; + return -5; if (get_queue(sk->fd, TCP_SEND_QUEUE, &data->outq_seq, data->outq_len, &sk->send_queue)) - return -5; + return -6; return sizeof(struct libsoccr_sk_data); } From a58330a26b29cffad56f2eab861d86f7747968f5 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsburskiy Date: Wed, 13 Sep 2017 14:35:06 +0300 Subject: [PATCH 0993/4375] tests: do not try to read more than packet in AutoFS test The intention was to make sure, that only one packet is sent at a time. And thus read has to return exactly the size of one packet. But it doesnt' work as expected, because size of autofs_v5_packet_union differs on 32 bit and 64 bit architectures. This is a bug, but it's hidden so deeply, that no one really cares by the following 2 aspects: 1) Autofs pipe has O_DIRECT flag, which means excess bytes will be discarded upon read. 2) No one tries to read more than one packet size at a time. So let's fix the test instead and do not try to read more bytes, than expected. Signed-off-by: Stanislav Kinsburskiy Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/autofs.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/test/zdtm/static/autofs.c b/test/zdtm/static/autofs.c index 747ab69dc..ae7853806 100644 --- a/test/zdtm/static/autofs.c +++ b/test/zdtm/static/autofs.c @@ -460,7 +460,7 @@ static int automountd_loop(int pipe, const char *mountpoint, struct autofs_param { union autofs_v5_packet_union *packet; ssize_t bytes; - size_t psize = sizeof(*packet) + 1; + size_t psize = sizeof(*packet); int err = 0; packet = malloc(psize); @@ -473,7 +473,7 @@ static int automountd_loop(int pipe, const char *mountpoint, struct autofs_param siginterrupt(SIGUSR2, 1); while (!stop && !err) { - memset(packet, 0, sizeof(*packet)); + memset(packet, 0, psize); bytes = read(pipe, packet, psize); if (bytes < 0) { @@ -483,12 +483,9 @@ static int automountd_loop(int pipe, const char *mountpoint, struct autofs_param } continue; } - if (bytes == psize) { - pr_err("read more that expected\n"); - return -EINVAL; - } - if (bytes != sizeof(*packet)) { - pr_err("read less than expected: %zd\n", bytes); + if (bytes != psize) { + pr_err("read less than expected: %zd < %zd\n", + bytes, psize); return -EINVAL; } err = automountd_serve(mountpoint, param, packet); From f7724aa5739668d745476fce5b9e197bb2f2f80d Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 30 Jul 2017 09:29:20 +0300 Subject: [PATCH 0994/4375] util/epoll: do not report polling timeout It's not really interesting and just pollutes the log Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/util.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/criu/util.c b/criu/util.c index dc11e5f9d..a938453b8 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1260,8 +1260,6 @@ int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout if (ret <= 0) { if (ret < 0) pr_perror("polling failed"); - else - pr_debug("polling timeout\n"); break; } From b6d397e46077cbee63222a5aa640c935ad2eca80 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 14 Aug 2017 11:47:00 +0300 Subject: [PATCH 0995/4375] kdat: lazy-thp: split error paths cleanups to two cases When an error occurs we need to close a file descriptor and unmap a region. Use a separate label for each cleanup. Fix CID 182644 (#1-2 of 2): Use after close (USE_AFTER_FREE)8. pass_closed_arg: Passing closed handle f.fd as an argument to bclose Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/kerndat.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/criu/kerndat.c b/criu/kerndat.c index de33b049d..7ae20ac69 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -784,21 +784,21 @@ int kerndat_has_thp_disable(void) f.fd = open("/proc/self/smaps", O_RDONLY); if (f.fd < 0) { pr_perror("Can't open /proc/self/smaps"); - goto out; + goto out_unmap; } if (bfdopenr(&f)) - goto out; + goto out_unmap; while ((str = breadline(&f)) != NULL) { if (IS_ERR(str)) - goto out; + goto out_close; if (is_vma_range_fmt(str)) { unsigned long vma_addr; if (sscanf(str, "%lx-", &vma_addr) != 1) { pr_err("Can't parse: %s\n", str); - goto out; + goto out_close; } if (vma_addr == (unsigned long)addr) @@ -818,8 +818,9 @@ int kerndat_has_thp_disable(void) ret = 0; -out: +out_close: bclose(&f); +out_unmap: munmap(addr, PAGE_SIZE); return ret; From babc8b3d74d7f8d4879c9cc9cc303966325f9d21 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 5 Sep 2017 14:39:00 +0300 Subject: [PATCH 0996/4375] crit: Files now sit in another image When merging files into one image we've forgotten about crit x feature that scans image files by names. https://github.com/xemul/criu/issues/381 The patch was made for master (as in criu-dev there was problem with pstree_item.pid parsing), but should apply to dev smoothly. Signed-off-by: Pavel Emelyanov --- crit/crit | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/crit/crit b/crit/crit index a6a6832b5..22e7ea789 100755 --- a/crit/crit +++ b/crit/crit @@ -89,8 +89,32 @@ def explore_ps(opts): print "%7s%7s%7s %s" % ('PID', 'PGID', 'SID', 'COMM') show_ps(psr, opts) +files_img = None + +def ftype_find_in_files(opts, ft, fid): + global files_img + + if files_img is None: + try: + files_img = pycriu.images.load(dinf(opts, "files.img"))['entries'] + except: + files_img = [] + + if len(files_img) == 0: + return None + + for f in files_img: + if f['id'] == fid: + return f + + return None + def ftype_find_in_image(opts, ft, fid, img): + f = ftype_find_in_files(opts, ft, fid) + if f: + return f[ft['field']] + if ft['img'] == None: ft['img'] = pycriu.images.load(dinf(opts, img))['entries'] for f in ft['img']: @@ -111,13 +135,13 @@ def ftype_unix(opts, ft, fid): if not ux: return 'unix[?]' - n = ux['name'] and ' %s' % ux['name'].decode('base64') or '' + n = ux['name'] and ' %s' % ux['name'] or '' return 'unix[%d (%d)%s]' % (ux['ino'], ux['peer'], n) file_types = { - 'REG': {'get': ftype_reg, 'img': None}, - 'PIPE': {'get': ftype_pipe, 'img': None}, - 'UNIXSK': {'get': ftype_unix, 'img': None}, + 'REG': {'get': ftype_reg, 'img': None, 'field': 'reg'}, + 'PIPE': {'get': ftype_pipe, 'img': None, 'field': 'pipe'}, + 'UNIXSK': {'get': ftype_unix, 'img': None, 'field': 'usk'}, } def ftype_gen(opts, ft, fid): From 91bc6e072a945eb9c7711bf245e5316a984fad4f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 27 Sep 2017 15:30:40 +0300 Subject: [PATCH 0997/4375] criu: Version 3.5 So, the long-running task with lazy restore is (almost) finished :) Some issues are still to be resolved, but the heaviest lift has been done. Another notable thing is VDSO C/R rework. It's now more robust and fast. Signed-off-by: Pavel Emelyanov --- Makefile.versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index 475e9e207..aef41a6e7 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 4 +CRIU_VERSION_MINOR := 5 CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Cobalt Swan +CRIU_VERSION_NAME := Clay Jay CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From 832dfed7778fd8f6d1a579c84be75b12b6fa92c5 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 5 Oct 2017 20:44:44 +0300 Subject: [PATCH 0998/4375] net: handle a case when --empty net is set only for criu dump The origin idea was to set --empty net for criu dump and criu restore, but before cde33dcb0639 ("empty-ns: Don't C/R iptables too (v2)"), criu restore worked without --empty net and we didn't notice that docker doesn't set this option on restore. After a small brainstorm, we decided that it is better to remove this requirement. Docker has to set this option, but with this changes, the docker issue will be less urgent. https://github.com/checkpoint-restore/criu/issues/393 --- criu/net.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/criu/net.c b/criu/net.c index 936611de8..4215b8503 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1541,13 +1541,18 @@ static inline int restore_iptables(int pid) struct cr_img *img; img = open_image(CR_FD_IPTABLES, O_RSTR, pid); - if (img) { - ret = run_iptables_tool("iptables-restore", img_raw_fd(img), -1); - close_image(img); + if (img == NULL) + return -1; + if (empty_image(img)) { + ret = 0; + goto ipt6; } + + ret = run_iptables_tool("iptables-restore", img_raw_fd(img), -1); + close_image(img); if (ret) return ret; - +ipt6: img = open_image(CR_FD_IP6TABLES, O_RSTR, pid); if (img == NULL) return -1; From c1e68a947e002c448a7baafa5d47f249395178ab Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 5 Oct 2017 20:38:24 +0300 Subject: [PATCH 0999/4375] travis: check docker checkpoint Install the last version of Docker, start a container and C/R it a few times. --- .travis.yml | 4 +++ scripts/travis/Makefile | 3 ++ scripts/travis/docker-test.sh | 65 +++++++++++++++++++++++++++++++++++ scripts/travis/travis-tests | 3 ++ 4 files changed, 75 insertions(+) create mode 100755 scripts/travis/docker-test.sh diff --git a/.travis.yml b/.travis.yml index eaa8401cf..3a063cd4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,10 @@ env: - TR_ARCH=aarch64 CLANG=1 - TR_ARCH=ppc64le CLANG=1 - TR_ARCH=alpine CLANG=1 + - TR_ARCH=docker-test +matrix: + allow_failures: + - env: TR_ARCH=docker-test script: - sudo make CCACHE=1 -C scripts/travis $TR_ARCH after_success: diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index e759ac25e..d76555ba8 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -21,5 +21,8 @@ asan: $(MAKE) -C ../build fedora-asan docker run --rm -it --privileged -v /lib/modules:/lib/modules criu-fedora-asan ./scripts/travis/asan.sh +docker-test: + ./docker-test.sh + %: $(MAKE) -C ../build $@$(target-suffix) diff --git a/scripts/travis/docker-test.sh b/scripts/travis/docker-test.sh new file mode 100755 index 000000000..2fad42854 --- /dev/null +++ b/scripts/travis/docker-test.sh @@ -0,0 +1,65 @@ +#!/bin/bash +set -x -e -o pipefail + +apt-get install -qq \ + apt-transport-https \ + ca-certificates \ + curl \ + software-properties-common + +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - + +add-apt-repository \ + "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) \ + stable" + + +apt-get update -qq + +apt-get install -qq docker-ce + +cat > /etc/docker/daemon.json <&1 | tee log || { + cat "`cat log | grep 'log file:' | sed 's/log file:\s*//'`" || true + docker logs cr || true + cat /tmp/zdtm-core-* || true + dmesg + docker ps + exit 1 + } + docker ps + sleep 1 +done + diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 7f4f031d6..305b45f44 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -48,6 +48,9 @@ echo "|`pwd`/test/abrt.sh %P %p %s %e" > /proc/sys/kernel/core_pattern export GCOV time make CC="$CC" -j4 + +[ -n "$SKIP_TRAVIS_TEST" ] && return + time make CC="$CC" -j4 -C test/zdtm [ -f "$CCACHE_LOGFILE" ] && cat $CCACHE_LOGFILE From 7c0cedd84e2c5e71c733826e1adedc666389aa20 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Mon, 25 Sep 2017 16:47:12 +0200 Subject: [PATCH 1000/4375] zdtm/s390x_regs_check: Fix compiler warning When running 'make zdtm' on s390x it fails on RHEL7 with: make[3]: Leaving directory `/tmp/criu/test/zdtm/lib' CC s390x_regs_check.o s390x_regs_check.c: In function "util_hexdump_grp": s390x_regs_check.c:214:7: error: "ptr" may be used uninitialized in this function [-Werror=maybe-uninitialized] ptr += sprintf(ptr, "%02x", buf[i]); Fix this and assign ptr from the beginning to help gcc. Reported-by: Adrian Reber Signed-off-by: Michael Holzheu Acked-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/zdtm/static/s390x_regs_check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/s390x_regs_check.c b/test/zdtm/static/s390x_regs_check.c index a92679ab0..1a7e84191 100644 --- a/test/zdtm/static/s390x_regs_check.c +++ b/test/zdtm/static/s390x_regs_check.c @@ -198,8 +198,8 @@ struct reg_set *reg_set_vec[] = { void util_hexdump_grp(const char *tag, const void *data, int grp, int count, int indent) { + char str[1024], *ptr = str; const char *buf = data; - char str[1024], *ptr; int i, first = 1; for (i = 0; i < count; i++) { From f9170eff126204c83bbd420d8f32bd8109307fc1 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Fri, 22 Sep 2017 18:25:43 +0300 Subject: [PATCH 1001/4375] lazy-pages: consolidate error handling for uffdio_copy and uffdio_zeropage The errors set by both uffdio_copy and uffdio_zeropage are the same and require the same handling. Let's use a helper function to handle the errors returned by uffdio_copy and uffdio_zero. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 43dc0ce21..7e858903f 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -705,6 +705,27 @@ static int handle_exit(struct lazy_pages_info *lpi) return 0; } +static int uffd_check_op_error(struct lazy_pages_info *lpi, const char *op, + unsigned long len, unsigned long rc_len, int rc) +{ + if (rc) { + if (errno == ENOSPC || errno == ESRCH) { + handle_exit(lpi); + return 0; + } + if (rc_len != -EEXIST) { + lp_perror(lpi, "%s: rc:%d copy:%ld, errno:%d", + op, rc, rc_len, errno); + return -1; + } + } else if (rc_len != len) { + lp_err(lpi, "%s unexpected size %ld\n", op, rc_len); + return -1; + } + + return 0; +} + static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) { struct uffdio_copy uffdio_copy; @@ -719,20 +740,8 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) lp_debug(lpi, "uffd_copy: 0x%llx/%ld\n", uffdio_copy.dst, len); rc = ioctl(lpi->lpfd.fd, UFFDIO_COPY, &uffdio_copy); - if (rc) { - if (errno == ENOSPC || errno == ESRCH) { - handle_exit(lpi); - return 0; - } - if (uffdio_copy.copy != -EEXIST) { - lp_debug(lpi, "uffd_copy: rc:%d copy:%Ld, errno:%d\n", - rc, uffdio_copy.copy, errno); - return -1; - } - } else if (uffdio_copy.copy != len) { - lp_err(lpi, "UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy); + if (uffd_check_op_error(lpi, "copy", len, uffdio_copy.copy, rc)) return -1; - } lpi->copied_pages += nr_pages; @@ -784,11 +793,8 @@ static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) lp_debug(lpi, "zero page at 0x%llx\n", address); rc = ioctl(lpi->lpfd.fd, UFFDIO_ZEROPAGE, &uffdio_zeropage); - if (rc) { - lp_perror(lpi, "zero page failed: %Ld", - uffdio_zeropage.zeropage); + if (uffd_check_op_error(lpi, "zero", len, uffdio_zeropage.zeropage, rc)) return -1; - } return 0; } From b2707bab02459678cd2b354d39cbdfd182968ee4 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 26 Sep 2017 20:49:27 +0300 Subject: [PATCH 1002/4375] net: Call ip[6]tables-restore with -w parameter New ip[6]tables-restore utils has this parameter, which allows to wait for xtables lock, if it's occupied. When they don't wait, then the restore of iptables fails. Old versions just ignore this parameter with error in stderr, but it does not make them fail. So, pass it unconditionally. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/net.c b/criu/net.c index 4215b8503..78249e5bc 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1548,7 +1548,7 @@ static inline int restore_iptables(int pid) goto ipt6; } - ret = run_iptables_tool("iptables-restore", img_raw_fd(img), -1); + ret = run_iptables_tool("iptables-restore -w", img_raw_fd(img), -1); close_image(img); if (ret) return ret; @@ -1559,7 +1559,7 @@ ipt6: if (empty_image(img)) goto out; - ret = run_iptables_tool("ip6tables-restore", img_raw_fd(img), -1); + ret = run_iptables_tool("ip6tables-restore -w", img_raw_fd(img), -1); out: close_image(img); From ee7d3becd44cda8ac308385dac0c020360af6897 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 28 Sep 2017 11:24:47 +0300 Subject: [PATCH 1003/4375] kdat: if iptables-restore has xtable lock support do wait on lock On VZ7 we have a problem in random tests on iptables restore when running tests in parallel(one iptables-restore instance tries to lock xtables lock and fails while other instance(some iptables* command) is already holding the lock): ================== Run zdtm/static/socket_udp_shutdown in ns =================== Start test ./socket_udp_shutdown --pidfile=socket_udp_shutdown.pid --outfile=socket_udp_shutdown.out Run criu dump Run criu restore =[log]=> dump/zdtm/static/socket_udp_shutdown/77/1/restore.log ------------------------ grep Error ------------------------ (00.158864) 1: Running ip rule delete table local (00.167319) 1: Running ip rule restore (00.175647) 1: Running iptables-restore for iptables-restore Another app is currently holding the xtables lock. Perhaps you want to use the -w option? (00.185245) 1: Error (criu/util.c:719): exited, status=4 (00.185289) 1: Error (criu/net.c:1739): iptables-restore failed (00.185301) 1: Error (criu/net.c:2382): Can't create net_ns (00.185370) 1: Error (criu/util.c:1412): Can't wait or bad status: errno=0, status=65280(00.187281) Error (criu/mount.c:2944): mnt: Can't remove the directory /tmp/.criu.mntns.Ai5EG9: No such file or directory (00.187298) uns: calling exit_usernsd (-1, 1) (00.187344) uns: daemon calls 0x466a40 (93, -1, 1) (00.187361) uns: `- daemon exits w/ 0 (00.188375) uns: daemon stopped (00.188390) Error (criu/cr-restore.c:2450): Restoring FAILED. ------------------------ ERROR OVER ------------------------ Test zdtm/static/socket_udp_shutdown FAIL at CRIU restore https://ci.openvz.org/job/CRIU/job/CRIU-virtuozzo/job/criu-dev/2873 It happens now in every test-suit run on VZ7 host as we had updated to 1.4.21-18 iptables package, which has patches for xlocks support in iptables-restore ported: * Mon Apr 24 2017 Thomas Woerner 1.4.21-18 - Add support for --wait options to restore commands (RHBZ#1438597) Whether these patches are ported to other distribution packages we'll have these problem in other distributions. Just add -w to wait lock on iptables-restore as older versions does not error on invalid option, just warning is printed. Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/net.c b/criu/net.c index 78249e5bc..4bd4c6e8e 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1758,8 +1758,8 @@ int netns_keep_nsfd(void) static int iptables_restore(bool ipv6, char *buf, int size) { int pfd[2], ret = -1; - char *cmd4[] = {"iptables-restore", "--noflush", NULL}; - char *cmd6[] = {"ip6tables-restore", "--noflush", NULL}; + char *cmd4[] = {"iptables-restore", "-w", "--noflush", NULL}; + char *cmd6[] = {"ip6tables-restore", "-w", "--noflush", NULL}; char **cmd = ipv6 ? cmd6 : cmd4;; if (pipe(pfd) < 0) { From d50f0e90fad3200710d0932af39586002a5526b4 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 27 Sep 2017 15:57:24 -0700 Subject: [PATCH 1004/4375] files: print an error if fdinfo can't be opened Without this message, we don't know which fdinfo can't be opened. https://github.com/xemul/criu/issues/390 Signed-off-by: Andrei Vagin Signed-off-by: Andrei Vagin --- criu/files.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/criu/files.c b/criu/files.c index e084316fd..28b21dd03 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1103,8 +1103,11 @@ static int open_fdinfos(struct pstree_item *me) st = fle->stage; BUG_ON(st == FLE_RESTORED); ret = open_fd(fle); - if (ret == -1) + if (ret == -1) { + pr_err("Unable to open fd=%d id=%#x\n", + fle->fe->fd, fle->fe->id); goto splice; + } if (st != fle->stage || ret == 0) progress = true; if (ret == 0) { From 477618276b3a7cc03b391a1958a55ecee3c65621 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 29 Sep 2017 04:12:15 +0300 Subject: [PATCH 1005/4375] zdtm/chroot: allocate enough memory for a path ==36==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000001c at pc 0x7fb26c88d5f9 bp 0x7ffc15087d40 sp 0x7ffc150874d0 WRITE of size 13 at 0x60200000001c thread T0 #0 0x7fb26c88d5f8 in vsprintf (/lib64/libasan.so.4+0x9e5f8) #1 0x7fb26c88d986 in __interceptor_sprintf (/lib64/libasan.so.4+0x9e986) #2 0x402453 in main /root/git/main/criu/test/zdtm/static/chroot.c:68 #3 0x7fb26c43e4d9 in __libc_start_main (/lib64/libc.so.6+0x204d9) #4 0x4031b9 in _start (/root/git/main/criu/test/zdtm/static/chroot+0x4031b9) Signed-off-by: Andrei Vagin --- test/zdtm/static/chroot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/chroot.c b/test/zdtm/static/chroot.c index 39b1ace0c..439a8e7dc 100644 --- a/test/zdtm/static/chroot.c +++ b/test/zdtm/static/chroot.c @@ -64,7 +64,7 @@ int main(int argc, char **argv) test_init(argc, argv); - filepath = malloc(strlen(filename) + 1); + filepath = malloc(strlen(filename) + 2); sprintf(filepath, "/%s", filename); pipe(pipe_prep); From 0b1aa087efeece4c77c4a70505ef891fbed1cb6a Mon Sep 17 00:00:00 2001 From: Stanislav Kinsburskiy Date: Wed, 27 Sep 2017 12:22:18 +0300 Subject: [PATCH 1006/4375] util: xatol() and xatoi() helpers introduced These helpers are safe versions of atol() and atoi() respectively. And they check for overflow and NAN errors v3: 1) Added string print to convertion error message in xatol_base() 2) Added check for INT range in xatoi() Signed-off-by: Stanislav Kinsburskiy Signed-off-by: Andrei Vagin --- criu/include/util.h | 3 +++ criu/util.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/criu/include/util.h b/criu/include/util.h index 5d471cb67..83945a104 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -276,6 +276,9 @@ void tcp_cork(int sk, bool on); const char *ns_to_string(unsigned int ns); +int xatol(const char *string, long *number); +int xatoi(const char *string, int *number); + char *xstrcat(char *str, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); char *xsprintf(const char *fmt, ...) diff --git a/criu/util.c b/criu/util.c index a938453b8..27bf71e44 100644 --- a/criu/util.c +++ b/criu/util.c @@ -56,6 +56,51 @@ #define VMA_OPT_LEN 128 +static int xatol_base(const char *string, long *number, int base) +{ + char *endptr; + long nr; + + errno = 0; + nr = strtol(string, &endptr, base); + if ((errno == ERANGE && (nr == LONG_MAX || nr == LONG_MIN)) + || (errno != 0 && nr == 0)) { + pr_perror("failed to convert string '%s'", string); + return -EINVAL; + } + + if ((endptr == string) || (*endptr != '\0')) { + pr_err("String is not a number: '%s'\n", string); + return -EINVAL; + } + *number = nr; + return 0; +} + +int xatol(const char *string, long *number) +{ + return xatol_base(string, number, 10); +} + + +int xatoi(const char *string, int *number) +{ + long tmp; + int err; + + err = xatol(string, &tmp); + if (err) + return err; + + if (tmp > INT_MAX || tmp < INT_MIN) { + pr_err("value %#lx (%ld) is out of int range\n", tmp, tmp); + return -ERANGE; + } + + *number = (int)tmp; + return 0; +} + /* * This function reallocates passed str pointer. * It means: From 745461572274c82062c917d69d7674cbd1d1ea8e Mon Sep 17 00:00:00 2001 From: Stanislav Kinsburskiy Date: Wed, 27 Sep 2017 12:22:23 +0300 Subject: [PATCH 1007/4375] autofs: use safe xatol() and xatoi() helpers Plus patch replaces atoi(32 bit) to xatol(64 bits) for "pipe_ino" mount option thus fixing the issue with negative inode number for big values. v2: fixed uninitialized "err" variable in "parse_options" function Signed-off-by: Stanislav Kinsburskiy Signed-off-by: Andrei Vagin --- criu/autofs.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/criu/autofs.c b/criu/autofs.c index d6d2eee7f..01cbdcfdf 100644 --- a/criu/autofs.c +++ b/criu/autofs.c @@ -149,7 +149,9 @@ static int autofs_find_pipe_read_end(int pgrp, long ino, int *read_fd) goto out; } - fd = atoi(de->d_name); + ret = xatoi(de->d_name, &fd); + if (ret) + goto out; found = autofs_check_fd_stat(&buf, pgrp, fd, ino, &mode); if (found < 0) @@ -223,19 +225,20 @@ static int parse_options(char *options, AutofsEntry *entry, long *pipe_ino) for (i = 0; i < nr_opts; i++) { char *opt = opts[i]; + int err = 0; if (!strncmp(opt, "fd=", strlen("fd="))) - entry->fd = atoi(opt + strlen("fd=")); + err = xatoi(opt + strlen("fd="), &entry->fd); else if (!strncmp(opt, "pipe_ino=", strlen("pipe_ino="))) - *pipe_ino = atoi(opt + strlen("pipe_ino=")); + err = xatol(opt + strlen("pipe_ino="), pipe_ino); else if (!strncmp(opt, "pgrp=", strlen("pgrp="))) - entry->pgrp = atoi(opt + strlen("pgrp=")); + err = xatoi(opt + strlen("pgrp="), &entry->pgrp); else if (!strncmp(opt, "timeout=", strlen("timeout="))) - entry->timeout = atoi(opt + strlen("timeout=")); + err = xatoi(opt + strlen("timeout="), &entry->timeout); else if (!strncmp(opt, "minproto=", strlen("minproto="))) - entry->minproto = atoi(opt + strlen("minproto=")); + err = xatoi(opt + strlen("minproto="), &entry->minproto); else if (!strncmp(opt, "maxproto=", strlen("maxproto="))) - entry->maxproto = atoi(opt + strlen("maxproto=")); + err = xatoi(opt + strlen("maxproto="), &entry->maxproto); else if (!strcmp(opt, "indirect")) entry->mode = AUTOFS_MODE_INDIRECT; else if (!strcmp(opt, "offset")) @@ -243,9 +246,12 @@ static int parse_options(char *options, AutofsEntry *entry, long *pipe_ino) else if (!strcmp(opt, "direct")) entry->mode = AUTOFS_MODE_DIRECT; else if (!strncmp(opt, "uid=", strlen("uid="))) - entry->uid = atoi(opt + strlen("uid=")); + err = xatoi(opt + strlen("uid="), &entry->uid); else if (!strncmp(opt, "gid=", strlen("gid="))) - entry->gid = atoi(opt + strlen("gid=")); + err = xatoi(opt + strlen("gid="), &entry->gid); + + if (err) + return -1; } for (i = 0; i < nr_opts; i++) @@ -308,7 +314,9 @@ static int autofs_revisit_options(struct mount_info *pm) while ((token = strsep(&str, " ")) != NULL) { if (mnt_id == -1) { - mnt_id = atoi(token); + ret = xatoi(token, &mnt_id); + if (ret) + goto close_proc; if (mnt_id != pm->mnt_id) break; } else if (strstr(token, "pipe_ino=")) { From 1a79b4d686a2d5481bc164065c15fde72dadb8d3 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Wed, 27 Sep 2017 17:21:48 +0200 Subject: [PATCH 1008/4375] zdtm/s390x_regs_check: Fix wait() for threads For older kernels (e.g. RHEL7 with 3.10) it seems that wait(NULL) after ptrace(PTHREAD_ATTACH) does not work properly for threads that have to be created via clone(). Fix this by using waitpid() with the __WALL flag. >From the waitpid() man page: __WALL (since Linux 2.4) Wait for all children, regardless of type ("clone" or "non-clone"). Reported-by: Adrian Reber Signed-off-by: Michael Holzheu Signed-off-by: Andrei Vagin --- test/zdtm/static/s390x_regs_check.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/s390x_regs_check.c b/test/zdtm/static/s390x_regs_check.c index 1a7e84191..b8f9d862c 100644 --- a/test/zdtm/static/s390x_regs_check.c +++ b/test/zdtm/static/s390x_regs_check.c @@ -391,7 +391,10 @@ static void child_func(void) static int ptrace_attach(pid_t pid) { if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) { - wait(NULL); + if (waitpid(pid, NULL, __WALL) < 0) { + pr_perror("Waiting for thread %d failed", pid); + return -1; + } return 0; } pr_perror("Attach to thread %d failed", pid); From 737a561703af45a5c5378705fce1e3d3c5d53214 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 13 Sep 2017 10:36:42 -0700 Subject: [PATCH 1009/4375] jenkins: criu-lib: add BUILD_NUMBER to the archive filename Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/jenkins/criu-lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jenkins/criu-lib.sh b/test/jenkins/criu-lib.sh index d244434fb..138066943 100644 --- a/test/jenkins/criu-lib.sh +++ b/test/jenkins/criu-lib.sh @@ -36,7 +36,7 @@ function fail() uname -a ps axf > ps.log cat /sys/kernel/debug/tracing/trace > trace.log - tar -czf /home/`basename $0`-${GIT_COMMIT}-$(date +%m%d%H%M).tar.gz . + tar -czf /home/`basename $0`-${BUILD_NUMBER}-${GIT_COMMIT}-$(date +%m%d%H%M).tar.gz . tar -czf report.tar.gz -C test/ report exit 1 } From f7e52b8b4a565401ae4e6740cd11407044a87607 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 14 Sep 2017 07:52:05 -0700 Subject: [PATCH 1010/4375] jenkins: lazy-pages: split lazy-pages runs to local and remote Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/jenkins/criu-lazy-pages.sh | 8 -------- test/jenkins/criu-remote-lazy-pages.sh | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) create mode 100755 test/jenkins/criu-remote-lazy-pages.sh diff --git a/test/jenkins/criu-lazy-pages.sh b/test/jenkins/criu-lazy-pages.sh index cdbbf2a11..474cb3c6b 100755 --- a/test/jenkins/criu-lazy-pages.sh +++ b/test/jenkins/criu-lazy-pages.sh @@ -17,17 +17,9 @@ fi ./test/zdtm.py run --all --keep-going --report report --parallel 4 \ --lazy-pages $LAZY_EXCLUDE || fail -# lazy restore from "remote" dump -./test/zdtm.py run --all --keep-going --report report --parallel 4 \ - --remote-lazy-pages $LAZY_EXCLUDE -x maps04 || fail - # During pre-dump + lazy-pages we leave VM_NOHUGEPAGE set LAZY_EXCLUDE="$LAZY_EXCLUDE -x maps02" # lazy restore from images with pre-dumps ./test/zdtm.py run --all --keep-going --report report --parallel 4 \ --lazy-pages --pre 2 $LAZY_EXCLUDE || fail - -# lazy restore from "remote" dump with pre-dumps -./test/zdtm.py run --all --keep-going --report report --parallel 4 \ - --remote-lazy-pages --pre 2 $LAZY_EXCLUDE || fail diff --git a/test/jenkins/criu-remote-lazy-pages.sh b/test/jenkins/criu-remote-lazy-pages.sh new file mode 100755 index 000000000..7d671029d --- /dev/null +++ b/test/jenkins/criu-remote-lazy-pages.sh @@ -0,0 +1,25 @@ +# Check remote-lazy-pages +set -e +source `dirname $0`/criu-lib.sh +prep + +KERN_MAJ=`uname -r | cut -d. -f1` +KERN_MIN=`uname -r | cut -d. -f2` +if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then + LAZY_EXCLUDE="-x cmdlinenv00" +else + LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns + -x socket_listen -x socket_listen6 -x cmdlinenv00 + -x socket_close_data01 -x file_read" +fi + +# lazy restore from "remote" dump +./test/zdtm.py run --all --keep-going --report report --parallel 4 \ + --remote-lazy-pages $LAZY_EXCLUDE -x maps04 || fail + +# During pre-dump + lazy-pages we leave VM_NOHUGEPAGE set +LAZY_EXCLUDE="$LAZY_EXCLUDE -x maps02" + +# lazy restore from "remote" dump with pre-dumps +./test/zdtm.py run --all --keep-going --report report --parallel 4 \ + --remote-lazy-pages --pre 2 $LAZY_EXCLUDE || fail From 20a460fabf48f6c97faa61736f67bbcd072f603b Mon Sep 17 00:00:00 2001 From: Kirill Kolyshkin Date: Sun, 1 Oct 2017 13:43:22 -0700 Subject: [PATCH 1011/4375] Silence clang-4 warning about unaligned pointer This is what we have: > compel/src/lib/infect.c:1145:38: error: taking address of packed member > 'uc_sigmask' of class or structure 'ucontext_ia32' may result in an > unaligned pointer value [-Werror,-Waddress-of-packed-member] > blk_sigset = RT_SIGFRAME_UC_SIGMASK(f); > ~~~~~~~~~~~~~~~~~~~~~~~^~ > compel/include/uapi/asm/sigframe.h:133:4: note: expanded from macro > 'RT_SIGFRAME_UC_SIGMASK' > (&rt_sigframe->compat.uc.uc_sigmask)) > ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > 1 error generated. Indeed this results in an unaligned pointer, but as this is intended and well known (see commit dd6736bd "compel/x86/compat: pack ucontext_ia32"), we need to silence the warning here. For more details, see https://reviews.llvm.org/D20561 Originally found by Travis on Alpine Linux, reproduced on Ubuntu 17.10. [v2: fix for non-x86] Reported-by: Andrei Vagin Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/include/uapi/asm/sigframe.h | 2 +- compel/src/lib/infect.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h index 2b51c3666..3260d9c16 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h @@ -130,7 +130,7 @@ struct rt_sigframe { #define RT_SIGFRAME_UC_SIGMASK(rt_sigframe) \ ((rt_sigframe->is_native) ? \ (&rt_sigframe->native.uc.uc_sigmask) : \ - (&rt_sigframe->compat.uc.uc_sigmask)) + ((k_rtsigset_t *)(void *)&rt_sigframe->compat.uc.uc_sigmask)) #define RT_SIGFRAME_REGIP(rt_sigframe) \ ((rt_sigframe->is_native) ? \ diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 07200a7a6..9ebc5b5ac 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -1126,7 +1126,7 @@ static int save_regs_plain(void *to, user_regs_struct_t *r, user_fpregs_struct_t #ifndef RT_SIGFRAME_UC_SIGMASK #define RT_SIGFRAME_UC_SIGMASK(sigframe) \ - (k_rtsigset_t*)&RT_SIGFRAME_UC(sigframe)->uc_sigmask + (k_rtsigset_t*)(void *)&RT_SIGFRAME_UC(sigframe)->uc_sigmask #endif static int make_sigframe_plain(void *from, struct rt_sigframe *f, struct rt_sigframe *rtf, k_rtsigset_t *b) From 7a4bb5fddf5d5b768b173c4e2ab926311e2e8061 Mon Sep 17 00:00:00 2001 From: Kirill Kolyshkin Date: Sun, 1 Oct 2017 13:43:23 -0700 Subject: [PATCH 1012/4375] Dockerfile.fedora-asan: don't ignore failures Same as commit e4000c59a71 ("Dockerfiles: don't ignore make failures"). Seems that Dockerfile.fedora-asan copy/pasted an old version. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.fedora-asan | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build/Dockerfile.fedora-asan b/scripts/build/Dockerfile.fedora-asan index 13aad28a0..5db430752 100644 --- a/scripts/build/Dockerfile.fedora-asan +++ b/scripts/build/Dockerfile.fedora-asan @@ -10,7 +10,7 @@ COPY . /criu WORKDIR /criu ENV CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes -RUN mv .ccache /tmp; make mrproper; ccache -s; \ - date; make -j $(nproc) ASAN=1 CC="$CC"; date +RUN mv .ccache /tmp && make mrproper && ccache -s && \ + date && make -j $(nproc) ASAN=1 CC="$CC" && date RUN make ASAN=1 -C test/zdtm -j $(nproc) From 0b044ecb443054fda86d0fd05c2a9b8f98e2357e Mon Sep 17 00:00:00 2001 From: Kirill Kolyshkin Date: Sun, 1 Oct 2017 13:43:24 -0700 Subject: [PATCH 1013/4375] travis arm64: switch to zesty Let's use Ubuntu 17.04 "Zesty" for ARM-64 bit CI. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.aarch64.hdr | 2 +- scripts/build/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build/Dockerfile.aarch64.hdr b/scripts/build/Dockerfile.aarch64.hdr index 3dd8600ae..3bc0db06e 100644 --- a/scripts/build/Dockerfile.aarch64.hdr +++ b/scripts/build/Dockerfile.aarch64.hdr @@ -1,3 +1,3 @@ -FROM aarch64/ubuntu:trusty +FROM arm64v8/ubuntu:zesty COPY scripts/build/qemu-user-static/usr/bin/qemu-aarch64-static /usr/bin/qemu-aarch64-static diff --git a/scripts/build/Makefile b/scripts/build/Makefile index 234649afa..61f0d7056 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -40,7 +40,7 @@ $(foreach t,$(TARGETS),$(eval $(call CLANG_DEP,$(t)))) %-clang: DB_CC=--build-arg CC=clang-3.8 %-clang: DB_ENV=--build-arg ENV1=CCACHE_CPP2 alpine-clang: DB_CC=--build-arg CC=clang -aarch64-clang: DB_CC=--build-arg CC=clang-3.6 +aarch64-clang: DB_CC=--build-arg CC=clang .PHONY: $(TARGETS_CLANG) clean: From 7b8ed84cd9872f8610a15704d06ddc453473b1af Mon Sep 17 00:00:00 2001 From: Kirill Kolyshkin Date: Sun, 1 Oct 2017 13:43:25 -0700 Subject: [PATCH 1014/4375] scripts/build/binfmt_misc: fix for ppc64le Got this error trying to build criu on ppc64le under qemu, after updating the Dockerfile to use Ubuntu Xenial (rather than Trusty): > $ rm -rf .ccache; make -C scripts/build ppc64le-clang > > ... > > Processing triggers for libc-bin (2.24-9ubuntu2.2) ... > /sbin/ldconfig.real: 1: /sbin/ldconfig.real: Syntax error: "(" unexpected > /sbin/ldconfig.real: 1: /sbin/ldconfig.real: Syntax error: "(" unexpected > dpkg: error processing package libc-bin (--configure): > subprocess installed post-installation script returned error exit status 2 > ... Apparently, ldconfig.real binary header differs from others: root@3c7593d3298d:/# od -x /bin/ls | head -2 0000000 457f 464c 0102 0001 0000 0000 0000 0000 0000020 0002 0015 0001 0000 5680 1000 0000 0000 root@3c7593d3298d:/# od -x /sbin/ldconfig.real | head -2 0000000 457f 464c 0102 0301 0000 0000 0000 0000 0000020 0002 0015 0001 0000 1d58 1000 0000 0000 Amend the mask in binfmt_misc entry to take this into account. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- scripts/build/binfmt_misc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/binfmt_misc b/scripts/build/binfmt_misc index 3e76b660e..adbac080d 100755 --- a/scripts/build/binfmt_misc +++ b/scripts/build/binfmt_misc @@ -7,7 +7,7 @@ test -f /proc/sys/fs/binfmt_misc/aarch64 || echo ':aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-aarch64-static:' > /proc/sys/fs/binfmt_misc/register test -f /proc/sys/fs/binfmt_misc/ppc64le || - echo ':ppc64le:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00:/usr/bin/qemu-ppc64le-static:' > /proc/sys/fs/binfmt_misc/register + echo ':ppc64le:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00:\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00:/usr/bin/qemu-ppc64le-static:' > /proc/sys/fs/binfmt_misc/register; done test -f /proc/sys/fs/binfmt_misc/s390x || echo ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-s390x-static:' > /proc/sys/fs/binfmt_misc/register From d23617e95ddf4f579e35b39ab7e9ae0bbcaa5cf0 Mon Sep 17 00:00:00 2001 From: Kirill Kolyshkin Date: Sun, 1 Oct 2017 13:43:26 -0700 Subject: [PATCH 1015/4375] travis ppc64: use ubuntu zesty This comes with newer libc headers so we can catch errors earlier. Also, clang 4.0. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.ppc64le.hdr | 2 +- scripts/build/Makefile | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/build/Dockerfile.ppc64le.hdr b/scripts/build/Dockerfile.ppc64le.hdr index 6b3c6592c..e08f6c279 100644 --- a/scripts/build/Dockerfile.ppc64le.hdr +++ b/scripts/build/Dockerfile.ppc64le.hdr @@ -1,4 +1,4 @@ -FROM ppc64le/ubuntu:trusty +FROM ppc64le/ubuntu:zesty ENV QEMU_CPU POWER8 COPY scripts/build/qemu-user-static/usr/bin/qemu-ppc64le-static /usr/bin/qemu-ppc64le-static diff --git a/scripts/build/Makefile b/scripts/build/Makefile index 61f0d7056..e08943e88 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -41,6 +41,7 @@ $(foreach t,$(TARGETS),$(eval $(call CLANG_DEP,$(t)))) %-clang: DB_ENV=--build-arg ENV1=CCACHE_CPP2 alpine-clang: DB_CC=--build-arg CC=clang aarch64-clang: DB_CC=--build-arg CC=clang +ppc64le-clang: DB_CC=--build-arg CC=clang .PHONY: $(TARGETS_CLANG) clean: From 5b158804e83f4183a86df67564378324164309d2 Mon Sep 17 00:00:00 2001 From: Kirill Kolyshkin Date: Sun, 1 Oct 2017 13:43:27 -0700 Subject: [PATCH 1016/4375] scripts/build/extract-deb-pkg: fix/improve Numerous improvement to extract-deb-pkg, in no particular order: * Use bash * More strict error checking (set -u -o pipefail) * Print error message if target dir exists * Check number of arguments, provide usage info * Separate mirror to a variable for easier changing * Use mirrors.kernel.org * Use https and check cert with curl * Make curl silent * Use zgrep instead of gunzip | grep * Error out with a message in case more than 1 package was found * Do not create a target directory before we need it * Fix shellcheck warnings (way too many to mention) * ... * PROFIT!!!111 Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- scripts/build/extract-deb-pkg | 44 ++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/scripts/build/extract-deb-pkg b/scripts/build/extract-deb-pkg index 922f9c197..f2c9e9238 100755 --- a/scripts/build/extract-deb-pkg +++ b/scripts/build/extract-deb-pkg @@ -1,10 +1,36 @@ -#'http://mirror.yandex.ru/debian/pool/main/q/qemu/qemu-user-static_2.5%2Bdfsg-5_amd64.deb' +#!/bin/bash + set -e -test -d $1 && exit -mkdir $1 -cd $1 -pkg=`curl http://mirror.yandex.ru/ubuntu/dists/xenial/universe/binary-amd64/Packages.gz | zcat | grep "Filename.*$1" | awk '{ print $2 }'` -wget "http://mirror.yandex.ru/ubuntu/$pkg" -pkg=`basename $pkg` -ar vx $pkg -tar -xJvf data.tar.xz +set -u +set -o pipefail +MIRROR="https://mirrors.kernel.org/ubuntu" +PKGS="$MIRROR/dists/xenial/universe/binary-amd64/Packages.gz" + +if [ $# -ne 1 ]; then + echo "Usage: $0 package-name" 1>&2 + exit 1 +fi + +if [ -d "$1" ]; then + echo "Directory $1 already exists -- exiting" + exit 0 +fi + +if ! pkg=$(curl -sSL "$PKGS" | zgrep "Filename.*$1" | awk '{ print $2 }'); then + echo "ERROR: no packages matching $1" 1>&2 + exit 1 +fi + +if [ "$(wc -w <<< "$pkg")" -gt 1 ]; then + echo "$pkg" 1>&2 + echo "ERROR: more than one match for $1" 1>&2 + exit 1 +fi + +mkdir "$1" +cd "$1" + +wget "$MIRROR/$pkg" +pkg=$(basename "$pkg") +ar vx "$pkg" +tar xJvf data.tar.xz From a1196183563ed20a4a2481f9a8112f17d21ef1ef Mon Sep 17 00:00:00 2001 From: Kirill Kolyshkin Date: Sun, 1 Oct 2017 17:34:02 -0700 Subject: [PATCH 1017/4375] Fix armv7 compile with clang 4 With clang 4, the following error appears: > CC criu/pie/parasite.o > In file included from criu/pie/parasite.c:23: > criu/arch/arm/include/asm/parasite.h:6:21: error: this function > declaration is not a > prototype [-Werror,-Wstrict-prototypes] > *ptls = ((tls_t (*)())0xffff0fe0)(); > ^ > void > 1 error generated. Apparently, adding void fixes it. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- criu/arch/arm/include/asm/parasite.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/arch/arm/include/asm/parasite.h b/criu/arch/arm/include/asm/parasite.h index 7f62bb9d2..0ed320ba6 100644 --- a/criu/arch/arm/include/asm/parasite.h +++ b/criu/arch/arm/include/asm/parasite.h @@ -3,7 +3,7 @@ static inline void arch_get_tls(tls_t *ptls) { - *ptls = ((tls_t (*)())0xffff0fe0)(); + *ptls = ((tls_t (*)(void))0xffff0fe0)(); } #endif From 4ccafdd920eae43b85f9fb756e653e1dea30b5aa Mon Sep 17 00:00:00 2001 From: Kirill Kolyshkin Date: Sun, 1 Oct 2017 17:34:03 -0700 Subject: [PATCH 1018/4375] CI: update ARM 32 bit build to Zesty Also, use more official / better maintained Docker image repo. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.armv7hf.hdr | 2 +- scripts/build/Makefile | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/build/Dockerfile.armv7hf.hdr b/scripts/build/Dockerfile.armv7hf.hdr index 8d4a9c89f..d4f7d9aba 100644 --- a/scripts/build/Dockerfile.armv7hf.hdr +++ b/scripts/build/Dockerfile.armv7hf.hdr @@ -1,3 +1,3 @@ -FROM armv7/armhf-ubuntu +FROM arm32v7/ubuntu:zesty COPY scripts/build/qemu-user-static/usr/bin/qemu-arm-static /usr/bin/qemu-arm-static diff --git a/scripts/build/Makefile b/scripts/build/Makefile index e08943e88..5927b27b7 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -37,11 +37,9 @@ $(1)-clang: $(1) endef $(foreach t,$(TARGETS),$(eval $(call CLANG_DEP,$(t)))) -%-clang: DB_CC=--build-arg CC=clang-3.8 +%-clang: DB_CC=--build-arg CC=clang %-clang: DB_ENV=--build-arg ENV1=CCACHE_CPP2 -alpine-clang: DB_CC=--build-arg CC=clang -aarch64-clang: DB_CC=--build-arg CC=clang -ppc64le-clang: DB_CC=--build-arg CC=clang +s390x-clang: DB_CC=--build-arg CC=clang-3.8 .PHONY: $(TARGETS_CLANG) clean: From d723061b53c5192a4e64aa8c7fa542dbfb058549 Mon Sep 17 00:00:00 2001 From: Kirill Kolyshkin Date: Sun, 1 Oct 2017 17:34:04 -0700 Subject: [PATCH 1019/4375] CI x86_64: switch to Zesty, add clang build The x86_64 job is the one we run inside Docker (as opposed to 'local', which runs on the host). Let's update this to use Ubuntu Zesty, and since it has clang-4 (unlike the 'local' one) it makes sense to add a clang build. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- .travis.yml | 1 + scripts/build/Dockerfile.x86_64.hdr | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3a063cd4b..2693e8e09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ env: - TR_ARCH=alpine - TR_ARCH=asan - TR_ARCH=x86_64 + - TR_ARCH=x86_64 CLANG=1 - TR_ARCH=armv7hf - TR_ARCH=aarch64 - TR_ARCH=ppc64le diff --git a/scripts/build/Dockerfile.x86_64.hdr b/scripts/build/Dockerfile.x86_64.hdr index ba8282cbf..bf9040978 100644 --- a/scripts/build/Dockerfile.x86_64.hdr +++ b/scripts/build/Dockerfile.x86_64.hdr @@ -1,4 +1,4 @@ -FROM ubuntu:trusty +FROM ubuntu:zesty RUN apt-get update -qq && apt-get install -qq \ gcc-multilib From 32191ac444e90e458f734aec436d39df960a238a Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 3 Oct 2017 20:38:09 +0300 Subject: [PATCH 1020/4375] travis: use xenial instead of zesty xenial is LTS and it is more stable and popular. Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.aarch64.hdr | 2 +- scripts/build/Dockerfile.armv7hf.hdr | 2 +- scripts/build/Dockerfile.ppc64le.hdr | 2 +- scripts/build/Dockerfile.x86_64.hdr | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/build/Dockerfile.aarch64.hdr b/scripts/build/Dockerfile.aarch64.hdr index 3bc0db06e..c90c98088 100644 --- a/scripts/build/Dockerfile.aarch64.hdr +++ b/scripts/build/Dockerfile.aarch64.hdr @@ -1,3 +1,3 @@ -FROM arm64v8/ubuntu:zesty +FROM arm64v8/ubuntu:xenial COPY scripts/build/qemu-user-static/usr/bin/qemu-aarch64-static /usr/bin/qemu-aarch64-static diff --git a/scripts/build/Dockerfile.armv7hf.hdr b/scripts/build/Dockerfile.armv7hf.hdr index d4f7d9aba..d453d6df7 100644 --- a/scripts/build/Dockerfile.armv7hf.hdr +++ b/scripts/build/Dockerfile.armv7hf.hdr @@ -1,3 +1,3 @@ -FROM arm32v7/ubuntu:zesty +FROM arm32v7/ubuntu:xenial COPY scripts/build/qemu-user-static/usr/bin/qemu-arm-static /usr/bin/qemu-arm-static diff --git a/scripts/build/Dockerfile.ppc64le.hdr b/scripts/build/Dockerfile.ppc64le.hdr index e08f6c279..ba65901c2 100644 --- a/scripts/build/Dockerfile.ppc64le.hdr +++ b/scripts/build/Dockerfile.ppc64le.hdr @@ -1,4 +1,4 @@ -FROM ppc64le/ubuntu:zesty +FROM ppc64le/ubuntu:xenial ENV QEMU_CPU POWER8 COPY scripts/build/qemu-user-static/usr/bin/qemu-ppc64le-static /usr/bin/qemu-ppc64le-static diff --git a/scripts/build/Dockerfile.x86_64.hdr b/scripts/build/Dockerfile.x86_64.hdr index bf9040978..b020d9cfc 100644 --- a/scripts/build/Dockerfile.x86_64.hdr +++ b/scripts/build/Dockerfile.x86_64.hdr @@ -1,4 +1,4 @@ -FROM ubuntu:zesty +FROM ubuntu:xenial RUN apt-get update -qq && apt-get install -qq \ gcc-multilib From 833c10450ddb471cc62199f652a1e51e64e22dd0 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 3 Oct 2017 20:40:11 +0300 Subject: [PATCH 1021/4375] travis: use a last alpine release to build criu Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.alpine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index 1c4684922..bb6af2057 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM alpine:3.5 +FROM alpine ARG CC=gcc ARG ENV1=FOOBAR From 2d093a170227e5790bab08eb790ef5274dcb6bdb Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 30 Sep 2017 01:41:37 +0300 Subject: [PATCH 1022/4375] travis: add a job to test on the fedora rawhide This job is optional and it don't affect the status of a whole job. Signed-off-by: Andrei Vagin --- .travis.yml | 4 +++- scripts/build/Dockerfile.aarch64.tmpl | 1 + scripts/build/Dockerfile.armv7hf.tmpl | 1 + scripts/build/Dockerfile.fedora-asan.hdr | 2 ++ scripts/build/Dockerfile.fedora-asan.tmpl | 1 + scripts/build/Dockerfile.fedora-rawhide.hdr | 1 + scripts/build/Dockerfile.fedora-rawhide.tmpl | 1 + ...ckerfile.fedora-asan => Dockerfile.fedora.tmpl} | 7 +++---- scripts/build/Dockerfile.ppc64le.tmpl | 1 + scripts/build/Dockerfile.rawhide | 14 ++++++++++++++ scripts/build/Dockerfile.s390x.tmpl | 1 + scripts/build/Dockerfile.x86_64.tmpl | 1 + scripts/build/Makefile | 8 +++++--- scripts/travis/Makefile | 10 ++++------ 14 files changed, 39 insertions(+), 14 deletions(-) create mode 120000 scripts/build/Dockerfile.aarch64.tmpl create mode 120000 scripts/build/Dockerfile.armv7hf.tmpl create mode 100644 scripts/build/Dockerfile.fedora-asan.hdr create mode 120000 scripts/build/Dockerfile.fedora-asan.tmpl create mode 100644 scripts/build/Dockerfile.fedora-rawhide.hdr create mode 120000 scripts/build/Dockerfile.fedora-rawhide.tmpl rename scripts/build/{Dockerfile.fedora-asan => Dockerfile.fedora.tmpl} (69%) create mode 120000 scripts/build/Dockerfile.ppc64le.tmpl create mode 100644 scripts/build/Dockerfile.rawhide create mode 120000 scripts/build/Dockerfile.s390x.tmpl create mode 120000 scripts/build/Dockerfile.x86_64.tmpl diff --git a/.travis.yml b/.travis.yml index 2693e8e09..5baee546d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ env: - TR_ARCH=local GCOV=1 - TR_ARCH=local CLANG=1 - TR_ARCH=alpine - - TR_ARCH=asan + - TR_ARCH=fedora-asan - TR_ARCH=x86_64 - TR_ARCH=x86_64 CLANG=1 - TR_ARCH=armv7hf @@ -20,9 +20,11 @@ env: - TR_ARCH=ppc64le CLANG=1 - TR_ARCH=alpine CLANG=1 - TR_ARCH=docker-test + - TR_ARCH=fedora-rawhide matrix: allow_failures: - env: TR_ARCH=docker-test + - env: TR_ARCH=fedora-rawhide script: - sudo make CCACHE=1 -C scripts/travis $TR_ARCH after_success: diff --git a/scripts/build/Dockerfile.aarch64.tmpl b/scripts/build/Dockerfile.aarch64.tmpl new file mode 120000 index 000000000..cb804790e --- /dev/null +++ b/scripts/build/Dockerfile.aarch64.tmpl @@ -0,0 +1 @@ +Dockerfile.tmpl \ No newline at end of file diff --git a/scripts/build/Dockerfile.armv7hf.tmpl b/scripts/build/Dockerfile.armv7hf.tmpl new file mode 120000 index 000000000..cb804790e --- /dev/null +++ b/scripts/build/Dockerfile.armv7hf.tmpl @@ -0,0 +1 @@ +Dockerfile.tmpl \ No newline at end of file diff --git a/scripts/build/Dockerfile.fedora-asan.hdr b/scripts/build/Dockerfile.fedora-asan.hdr new file mode 100644 index 000000000..328af2433 --- /dev/null +++ b/scripts/build/Dockerfile.fedora-asan.hdr @@ -0,0 +1,2 @@ +FROM fedora:latest +ENV ASAN=1 diff --git a/scripts/build/Dockerfile.fedora-asan.tmpl b/scripts/build/Dockerfile.fedora-asan.tmpl new file mode 120000 index 000000000..e4c40309c --- /dev/null +++ b/scripts/build/Dockerfile.fedora-asan.tmpl @@ -0,0 +1 @@ +Dockerfile.fedora.tmpl \ No newline at end of file diff --git a/scripts/build/Dockerfile.fedora-rawhide.hdr b/scripts/build/Dockerfile.fedora-rawhide.hdr new file mode 100644 index 000000000..d6d9ab7e2 --- /dev/null +++ b/scripts/build/Dockerfile.fedora-rawhide.hdr @@ -0,0 +1 @@ +FROM fedora:rawhide diff --git a/scripts/build/Dockerfile.fedora-rawhide.tmpl b/scripts/build/Dockerfile.fedora-rawhide.tmpl new file mode 120000 index 000000000..e4c40309c --- /dev/null +++ b/scripts/build/Dockerfile.fedora-rawhide.tmpl @@ -0,0 +1 @@ +Dockerfile.fedora.tmpl \ No newline at end of file diff --git a/scripts/build/Dockerfile.fedora-asan b/scripts/build/Dockerfile.fedora.tmpl similarity index 69% rename from scripts/build/Dockerfile.fedora-asan rename to scripts/build/Dockerfile.fedora.tmpl index 5db430752..38a0e54e6 100644 --- a/scripts/build/Dockerfile.fedora-asan +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -1,4 +1,3 @@ -FROM fedora:latest ARG CC=gcc ARG ENV1=FOOBAR @@ -10,7 +9,7 @@ COPY . /criu WORKDIR /criu ENV CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes -RUN mv .ccache /tmp && make mrproper && ccache -s && \ - date && make -j $(nproc) ASAN=1 CC="$CC" && date -RUN make ASAN=1 -C test/zdtm -j $(nproc) +RUN mv .ccache /tmp && make mrproper && ccache -s && ccache -z && \ + date && make -j $(nproc) CC="$CC" && date && ccache -s +RUN make -C test/zdtm -j $(nproc) diff --git a/scripts/build/Dockerfile.ppc64le.tmpl b/scripts/build/Dockerfile.ppc64le.tmpl new file mode 120000 index 000000000..cb804790e --- /dev/null +++ b/scripts/build/Dockerfile.ppc64le.tmpl @@ -0,0 +1 @@ +Dockerfile.tmpl \ No newline at end of file diff --git a/scripts/build/Dockerfile.rawhide b/scripts/build/Dockerfile.rawhide new file mode 100644 index 000000000..b5080d416 --- /dev/null +++ b/scripts/build/Dockerfile.rawhide @@ -0,0 +1,14 @@ +FROM fedora:rawhide + +ARG CC=gcc + +RUN dnf install -y git gcc make +RUN dnf install -y protobuf-devel protobuf-c-devel libaio-devel libcap-devel libnl3-devel libnet-devel +RUN dnf install -y python ccache libasan findutils tar python-yaml protobuf-python iptables iproute python-ipaddr procps-ng + +COPY . /criu +WORKDIR /criu +RUN make mrproper && make -j $(nproc) + +RUN pip install protobuf +RUN make -C test/zdtm/static env00 diff --git a/scripts/build/Dockerfile.s390x.tmpl b/scripts/build/Dockerfile.s390x.tmpl new file mode 120000 index 000000000..cb804790e --- /dev/null +++ b/scripts/build/Dockerfile.s390x.tmpl @@ -0,0 +1 @@ +Dockerfile.tmpl \ No newline at end of file diff --git a/scripts/build/Dockerfile.x86_64.tmpl b/scripts/build/Dockerfile.x86_64.tmpl new file mode 120000 index 000000000..cb804790e --- /dev/null +++ b/scripts/build/Dockerfile.x86_64.tmpl @@ -0,0 +1 @@ +Dockerfile.tmpl \ No newline at end of file diff --git a/scripts/build/Makefile b/scripts/build/Makefile index 5927b27b7..21330be77 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -1,6 +1,6 @@ QEMU_ARCHES := armv7hf aarch64 ppc64le s390x # require qemu -ARCHES := $(QEMU_ARCHES) x86_64 -TARGETS := $(ARCHES) alpine fedora-asan +ARCHES := $(QEMU_ARCHES) x86_64 fedora-asan fedora-rawhide +TARGETS := $(ARCHES) alpine TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) all: $(TARGETS) $(TARGETS_CLANG) @@ -12,7 +12,7 @@ $(1): Dockerfile.$(1) endef $(foreach arch,$(ARCHES),$(eval $(call ARCH_DEP,$(arch)))) -Dockerfile.%: Dockerfile.%.hdr Dockerfile.tmpl +Dockerfile.%: Dockerfile.%.hdr Dockerfile.%.tmpl cat $^ > $@ qemu-user-static: @@ -38,6 +38,8 @@ endef $(foreach t,$(TARGETS),$(eval $(call CLANG_DEP,$(t)))) %-clang: DB_CC=--build-arg CC=clang +Dockerfile.fedora-asan: override DOCKER_TMPL=Dockerfile.fedora.tmpl +Dockerfile.fedora-rawhide: override DOCKER_TMPL=Dockerfile.fedora.tmpl %-clang: DB_ENV=--build-arg ENV1=CCACHE_CPP2 s390x-clang: DB_CC=--build-arg CC=clang-3.8 .PHONY: $(TARGETS_CLANG) diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index d76555ba8..53b27649a 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -11,15 +11,13 @@ ifdef CLANG target-suffix = -clang endif -alpine: - $(MAKE) -C ../build $@$(target-suffix) - docker run --rm -it --privileged -v /lib/modules:/lib/modules criu-alpine ./test/zdtm.py run -t zdtm/static/env00 +TARGETS := fedora-asan alpine fedora-rawhide -asan: +$(TARGETS): echo 'DOCKER_OPTS="--storage-driver=devicemapper"' > /etc/default/docker restart docker - $(MAKE) -C ../build fedora-asan - docker run --rm -it --privileged -v /lib/modules:/lib/modules criu-fedora-asan ./scripts/travis/asan.sh + $(MAKE) -C ../build $@$(target-suffix) + docker run --rm -it --privileged -v /lib/modules:/lib/modules criu-$@ ./scripts/travis/asan.sh docker-test: ./docker-test.sh From d5d41bac19350e63c51d897aedcdfa626e77bf0a Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 30 Sep 2017 01:41:38 +0300 Subject: [PATCH 1023/4375] zdtm: don't use find to get executable files find: unrecognized: -executable Signed-off-by: Andrei Vagin --- test/zdtm.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 2e37087f5..b48301f03 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1530,16 +1530,25 @@ class launcher: def all_tests(opts): desc = eval(open(opts['set'] + '.desc').read()) - lst = subprocess.Popen(['find', desc['dir'], '-type', 'f', '-executable'], - stdout = subprocess.PIPE) + + files = [] + mask = stat.S_IFREG | stat.S_IXUSR + for d in os.walk(desc['dir']): + for f in d[2]: + fp = os.path.join(d[0], f) + st = os.lstat(fp) + if (st.st_mode & mask) != mask: + continue + if stat.S_IFMT(st.st_mode) in [stat.S_IFLNK, stat.S_IFSOCK]: + continue + files.append(fp) excl = map(lambda x: os.path.join(desc['dir'], x), desc['exclude']) tlist = filter(lambda x: not x.endswith('.checkskip') and not x.endswith('.hook') and x not in excl, - map(lambda x: x.strip(), lst.stdout.readlines()) + map(lambda x: x.strip(), files) ) - lst.wait() return tlist From fb67fb14f9f43152e5b9c4e7f113b62b1551d3a2 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 30 Sep 2017 01:41:39 +0300 Subject: [PATCH 1024/4375] alpine: use uid_t instead of __uid_t __uid_t isn't public Signed-off-by: Andrei Vagin --- test/zdtm/static/pid00.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/zdtm/static/pid00.c b/test/zdtm/static/pid00.c index e40bf73ae..4fd3e09aa 100644 --- a/test/zdtm/static/pid00.c +++ b/test/zdtm/static/pid00.c @@ -13,9 +13,9 @@ int setfsgid(uid_t fsgid); int main(int argc, char **argv) { int pid, s_p[2], f_p[2], r_p[3]; - const __uid_t w_ruid = 1, w_euid = 2, w_suid = 3, w_fsuid = w_euid; - const __uid_t w_rgid = 5, w_egid = 6, w_sgid = 7, w_fsgid = 8; - __uid_t rid, eid, sid, fsid; + const uid_t w_ruid = 1, w_euid = 2, w_suid = 3, w_fsuid = w_euid; + const gid_t w_rgid = 5, w_egid = 6, w_sgid = 7, w_fsgid = 8; + uid_t rid, eid, sid, fsid; char res = 'x'; test_init(argc, argv); From c645cc937c2efc3d3bf4ccdb7a4629c897e12666 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 30 Sep 2017 01:41:40 +0300 Subject: [PATCH 1025/4375] alpine: use sys/wait.h instead of wait.h In file included from socket_listen.c:22:0: /usr/include/wait.h:1:2: error: #warning redirecting incorrect #include to [-Werror=cpp] #warning redirecting incorrect #include to Signed-off-by: Andrei Vagin --- test/zdtm/static/socket6_udp.c | 2 +- test/zdtm/static/socket_aio.c | 2 +- test/zdtm/static/socket_listen.c | 2 +- test/zdtm/static/socket_udp.c | 2 +- test/zdtm/static/socket_udp_shutdown.c | 2 +- test/zdtm/static/socket_udplite.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/zdtm/static/socket6_udp.c b/test/zdtm/static/socket6_udp.c index d1c39c729..b81a6afee 100644 --- a/test/zdtm/static/socket6_udp.c +++ b/test/zdtm/static/socket6_udp.c @@ -13,7 +13,7 @@ const char *test_author = "Cyrill Gorcunov \n"; #include #include #include /* for sockaddr_in and inet_ntoa() */ -#include +#include static int port = 8880; static char buf[64]; diff --git a/test/zdtm/static/socket_aio.c b/test/zdtm/static/socket_aio.c index b8966b023..b276adb2b 100644 --- a/test/zdtm/static/socket_aio.c +++ b/test/zdtm/static/socket_aio.c @@ -16,7 +16,7 @@ const char *test_author = "Andrew Vagin "; #include #include #include -#include +#include #include static int port = 8880; diff --git a/test/zdtm/static/socket_listen.c b/test/zdtm/static/socket_listen.c index f11d37959..aae3c7993 100644 --- a/test/zdtm/static/socket_listen.c +++ b/test/zdtm/static/socket_listen.c @@ -19,7 +19,7 @@ const char *test_author = "Stanislav Kinsbursky "; #include #include #include -#include +#include #include static int port = 8880; diff --git a/test/zdtm/static/socket_udp.c b/test/zdtm/static/socket_udp.c index 5e24a8b0f..36a954237 100644 --- a/test/zdtm/static/socket_udp.c +++ b/test/zdtm/static/socket_udp.c @@ -18,7 +18,7 @@ const char *test_author = "Pavel Emelyanov \n"; #include #include #include /* for sockaddr_in and inet_ntoa() */ -#include +#include static int port = 8880; static char buf[8]; diff --git a/test/zdtm/static/socket_udp_shutdown.c b/test/zdtm/static/socket_udp_shutdown.c index 4e2834af9..ae148c5fa 100644 --- a/test/zdtm/static/socket_udp_shutdown.c +++ b/test/zdtm/static/socket_udp_shutdown.c @@ -8,7 +8,7 @@ #include #include #include /* for sockaddr_in and inet_ntoa() */ -#include +#include #include "zdtmtst.h" diff --git a/test/zdtm/static/socket_udplite.c b/test/zdtm/static/socket_udplite.c index 8218ff556..d2510ef2f 100644 --- a/test/zdtm/static/socket_udplite.c +++ b/test/zdtm/static/socket_udplite.c @@ -18,7 +18,7 @@ const char *test_author = "Pavel Emelyanov \n"; #include #include #include /* for sockaddr_in and inet_ntoa() */ -#include +#include static int port = 8890; static char buf[8]; From 7178717bcf019aee7b24b677e412b72aa1749708 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 30 Sep 2017 02:09:40 +0300 Subject: [PATCH 1026/4375] alpine: cast addresses to struct sockaddr * Otherwise we get errors like this: /usr/include/sys/socket.h:315:5: note: expected 'const struct sockaddr *' but argument is of type 'struct sockaddr_un *' int bind (int, const struct sockaddr *, socklen_t); Signed-off-by: Andrei Vagin --- test/zdtm/static/del_standalone_un.c | 2 +- test/zdtm/static/packet_sock_spkt.c | 2 +- test/zdtm/static/sk-unix-rel.c | 4 ++-- test/zdtm/static/socket-ext.c | 4 ++-- test/zdtm/static/socket_close_data01.c | 2 +- test/zdtm/static/socket_dgram_data.c | 6 +++--- test/zdtm/static/socket_snd_addr.c | 6 +++--- test/zdtm/static/sockets00.c | 6 +++--- test/zdtm/static/sockets03.c | 4 ++-- test/zdtm/static/sockets_dgram.c | 16 ++++++++-------- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/test/zdtm/static/del_standalone_un.c b/test/zdtm/static/del_standalone_un.c index b512ff710..f62edb2ed 100644 --- a/test/zdtm/static/del_standalone_un.c +++ b/test/zdtm/static/del_standalone_un.c @@ -39,7 +39,7 @@ static int bind_and_listen(struct sockaddr_un *addr) return -1; } - if (bind(sk, addr, sizeof(*addr))) { + if (bind(sk, (struct sockaddr *) addr, sizeof(*addr))) { fail("bind %s", addr->sun_path); close(sk); return -1; diff --git a/test/zdtm/static/packet_sock_spkt.c b/test/zdtm/static/packet_sock_spkt.c index 4e9540fb4..55cd16518 100644 --- a/test/zdtm/static/packet_sock_spkt.c +++ b/test/zdtm/static/packet_sock_spkt.c @@ -23,7 +23,7 @@ static int do_bind(int sk) addr.sa_family = AF_PACKET; strcpy(addr.sa_data, "lo"); - return bind(sk, &addr, sizeof(addr)); + return bind(sk, (struct sockaddr *) &addr, sizeof(addr)); } static int check_socket_binding(int sk, char *dev) diff --git a/test/zdtm/static/sk-unix-rel.c b/test/zdtm/static/sk-unix-rel.c index f69a81697..4f0b186d1 100644 --- a/test/zdtm/static/sk-unix-rel.c +++ b/test/zdtm/static/sk-unix-rel.c @@ -64,7 +64,7 @@ int main(int argc, char *argv[]) exit(1); } - ret = bind(sock[0], &addr, addrlen); + ret = bind(sock[0], (struct sockaddr *) &addr, addrlen); if (ret) { fail("bind\n"); exit(1); @@ -79,7 +79,7 @@ int main(int argc, char *argv[]) test_daemon(); test_waitsig(); - if (connect(sock[1], &addr, addrlen)) { + if (connect(sock[1], (struct sockaddr *) &addr, addrlen)) { fail("connect\n"); exit(1); } diff --git a/test/zdtm/static/socket-ext.c b/test/zdtm/static/socket-ext.c index 4e550534b..c33960dbf 100644 --- a/test/zdtm/static/socket-ext.c +++ b/test/zdtm/static/socket-ext.c @@ -55,7 +55,7 @@ int main(int argc, char *argv[]) pr_perror("Can't create socket"); return 1; } - ret = bind(sk, &addr, addrlen); + ret = bind(sk, (struct sockaddr *) &addr, addrlen); if (ret < 0) { pr_perror("Can't bind socket to %s", path); return 1; @@ -82,7 +82,7 @@ int main(int argc, char *argv[]) return 1; } - ret = connect(sk, &addr, addrlen); + ret = connect(sk, (struct sockaddr *) &addr, addrlen); if (ret < 0) { pr_perror("Can't connect socket"); return 1; diff --git a/test/zdtm/static/socket_close_data01.c b/test/zdtm/static/socket_close_data01.c index 123e882db..df4b894b2 100644 --- a/test/zdtm/static/socket_close_data01.c +++ b/test/zdtm/static/socket_close_data01.c @@ -30,7 +30,7 @@ static int client(const char *iter) addr.sun_family = AF_UNIX; strcpy(addr.sun_path, filename); - if (connect(sk, (void *)&addr, sizeof(struct sockaddr_un)) < 0) { + if (connect(sk, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) < 0) { pr_perror("connect failed %s", iter); return 1; } diff --git a/test/zdtm/static/socket_dgram_data.c b/test/zdtm/static/socket_dgram_data.c index 9437d44a3..2f635b6e6 100644 --- a/test/zdtm/static/socket_dgram_data.c +++ b/test/zdtm/static/socket_dgram_data.c @@ -42,15 +42,15 @@ int main(int argc, char **argv) memcpy(addr.sun_path, SK_SRV, sizeof(SK_SRV)); addrlen = sizeof(addr.sun_family) + sizeof(SK_SRV); - if (bind(srv, &addr, addrlen)) { + if (bind(srv, (struct sockaddr *) &addr, addrlen)) { fail("bind\n"); exit(1); } - if (connect(clnt1, &addr, addrlen)) { + if (connect(clnt1, (struct sockaddr *) &addr, addrlen)) { fail("connect\n"); exit(1); } - if (connect(clnt2, &addr, addrlen)) { + if (connect(clnt2, (struct sockaddr *) &addr, addrlen)) { fail("connect\n"); exit(1); } diff --git a/test/zdtm/static/socket_snd_addr.c b/test/zdtm/static/socket_snd_addr.c index fa587a03e..7e5376e72 100644 --- a/test/zdtm/static/socket_snd_addr.c +++ b/test/zdtm/static/socket_snd_addr.c @@ -44,7 +44,7 @@ int main(int argc, char **argv) memcpy(addr.sun_path, SK_SRV, sizeof(SK_SRV)); addrlen = sizeof(addr.sun_family) + sizeof(SK_SRV); - if (bind(srv, &addr, addrlen)) { + if (bind(srv, (struct sockaddr *) &addr, addrlen)) { fail("bind\n"); exit(1); } @@ -58,14 +58,14 @@ int main(int argc, char **argv) memcpy(addr.sun_path, sk_names[i], sizeof(SK_NAME)); addrlen = sizeof(addr.sun_family) + sizeof(SK_NAME); - if (bind(clnt, &addr, addrlen)) { + if (bind(clnt, (struct sockaddr *) &addr, addrlen)) { fail("bind\n"); exit(1); } memcpy(addr.sun_path, SK_SRV, sizeof(SK_SRV)); addrlen = sizeof(addr.sun_family) + sizeof(SK_SRV); - if (connect(clnt, &addr, addrlen)) { + if (connect(clnt, (struct sockaddr *) &addr, addrlen)) { fail("connect\n"); exit(1); } diff --git a/test/zdtm/static/sockets00.c b/test/zdtm/static/sockets00.c index a9558d7ad..ab5d2e450 100644 --- a/test/zdtm/static/sockets00.c +++ b/test/zdtm/static/sockets00.c @@ -63,7 +63,7 @@ int main(int argc, char *argv[]) exit(1); } - ret = bind(ssk_icon[0], &addr, addrlen); + ret = bind(ssk_icon[0], (struct sockaddr *) &addr, addrlen); if (ret) { fail("bind\n"); exit(1); @@ -87,7 +87,7 @@ int main(int argc, char *argv[]) exit(1); } - ret = connect(ssk_icon[2], &addr, addrlen); + ret = connect(ssk_icon[2], (struct sockaddr *) &addr, addrlen); if (ret) { fail("connect\n"); exit(1); @@ -99,7 +99,7 @@ int main(int argc, char *argv[]) exit(1); } - ret = connect(ssk_icon[1], &addr, addrlen); + ret = connect(ssk_icon[1], (struct sockaddr *) &addr, addrlen); if (ret) { fail("connect\n"); exit(1); diff --git a/test/zdtm/static/sockets03.c b/test/zdtm/static/sockets03.c index 309e7a080..f62f565c0 100644 --- a/test/zdtm/static/sockets03.c +++ b/test/zdtm/static/sockets03.c @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) exit(1); } - ret = bind(sk[0], &addr, addrlen); + ret = bind(sk[0], (struct sockaddr *) &addr, addrlen); if (ret) { fail("bind\n"); exit(1); @@ -74,7 +74,7 @@ int main(int argc, char *argv[]) exit(1); } - ret = connect(sk[1], &addr, addrlen); + ret = connect(sk[1], (struct sockaddr *) &addr, addrlen); if (ret) { fail("connect\n"); exit(1); diff --git a/test/zdtm/static/sockets_dgram.c b/test/zdtm/static/sockets_dgram.c index 952453d01..f135a3bbf 100644 --- a/test/zdtm/static/sockets_dgram.c +++ b/test/zdtm/static/sockets_dgram.c @@ -102,38 +102,38 @@ int main(int argc, char *argv[]) name_bound_conn.sun_family = AF_UNIX; strncpy(name_bound_conn.sun_path, path, sizeof(name_bound_conn.sun_path)); - ret = bind(sk_dgram_bound_server, &name_bound, sizeof(name_bound)); + ret = bind(sk_dgram_bound_server, (struct sockaddr *) &name_bound, sizeof(name_bound)); if (ret) { fail("bind"); exit(1); } - ret = bind(sk_dgram_conn_server, &name_conn, sizeof(name_conn)); + ret = bind(sk_dgram_conn_server, (struct sockaddr *) &name_conn, sizeof(name_conn)); if (ret) { fail("bind"); exit(1); } - ret = connect(sk_dgram_conn_client, &name_conn, sizeof(name_conn)); + ret = connect(sk_dgram_conn_client, (struct sockaddr *) &name_conn, sizeof(name_conn)); if (ret) { fail("connect"); exit(1); } - ret = connect(sk_dgram_conn_client2, &name_conn, sizeof(name_conn)); + ret = connect(sk_dgram_conn_client2, (struct sockaddr *) &name_conn, sizeof(name_conn)); if (ret) { fail("connect"); exit(1); } - ret = bind(sk_dgram_bound_conn, &name_bound_conn, sizeof(name_bound_conn)); + ret = bind(sk_dgram_bound_conn, (struct sockaddr *) &name_bound_conn, sizeof(name_bound_conn)); if (ret) { fail("bind"); exit(1); } /* Note, it's already bound, so make it more idiotic! */ - ret = connect(sk_dgram_bound_conn, &name_bound_conn, sizeof(name_bound_conn)); + ret = connect(sk_dgram_bound_conn, (struct sockaddr *) &name_bound_conn, sizeof(name_bound_conn)); if (ret) { fail("connect"); exit(1); @@ -141,7 +141,7 @@ int main(int argc, char *argv[]) memset(buf, 0, sizeof(buf)); sendto(sk_dgram_bound_client, SK_DATA_BOUND, sizeof(SK_DATA_BOUND), 0, - &name_bound, sizeof(name_bound)); + (struct sockaddr *) &name_bound, sizeof(name_bound)); read(sk_dgram_bound_server, &buf, sizeof(buf)); if (strcmp(buf, SK_DATA_BOUND)) { fail("data corrupted\n"); @@ -172,7 +172,7 @@ int main(int argc, char *argv[]) memset(buf, 0, sizeof(buf)); sendto(sk_dgram_bound_client, SK_DATA_BOUND, sizeof(SK_DATA_BOUND), 0, - &name_bound, sizeof(name_bound)); + (struct sockaddr *) &name_bound, sizeof(name_bound)); read(sk_dgram_bound_server, &buf, sizeof(buf)); if (strcmp(buf, SK_DATA_BOUND)) { fail("data corrupted\n"); From 598790eb4396769eeedc36c9b92d617a9cca80ef Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 30 Sep 2017 01:41:42 +0300 Subject: [PATCH 1027/4375] tcp: be ready that a size of tcp_info can be changed (00.052683) Error (soccr/soccr.c:166): Failed to obtain TCP_INFO: No error information We don't need a whole tcp info, so get only a part what we are going to use. Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 9 ++++++++- soccr/soccr.c | 18 +++++++++++++++--- test/zdtm/static/socket-tcp-close0.c | 5 ++++- test/zdtm/static/socket-tcp-close1.c | 5 ++++- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 94170cb93..93de1e2ee 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -246,7 +246,14 @@ static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int sk->sd.ino = p->stat.st_ino; if (proto == IPPROTO_TCP) { - struct tcp_info info; + struct { + __u8 tcpi_state; + __u8 tcpi_ca_state; + __u8 tcpi_retransmits; + __u8 tcpi_probes; + __u8 tcpi_backoff; + __u8 tcpi_options; + } info; aux = sizeof(info); ret = getsockopt(lfd, SOL_TCP, TCP_INFO, &info, &aux); diff --git a/soccr/soccr.c b/soccr/soccr.c index 48469aaab..1a1aaa35d 100644 --- a/soccr/soccr.c +++ b/soccr/soccr.c @@ -157,7 +157,18 @@ void libsoccr_release(struct libsoccr_sk *sk) free(sk); } -static int refresh_sk(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, struct tcp_info *ti) +struct soccr_tcp_info { + __u8 tcpi_state; + __u8 tcpi_ca_state; + __u8 tcpi_retransmits; + __u8 tcpi_probes; + __u8 tcpi_backoff; + __u8 tcpi_options; + __u8 tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4; +}; + +static int refresh_sk(struct libsoccr_sk *sk, + struct libsoccr_sk_data *data, struct soccr_tcp_info *ti) { int size; socklen_t olen = sizeof(*ti); @@ -215,7 +226,8 @@ static int refresh_sk(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, str return 0; } -static int get_stream_options(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, struct tcp_info *ti) +static int get_stream_options(struct libsoccr_sk *sk, + struct libsoccr_sk_data *data, struct soccr_tcp_info *ti) { int ret; socklen_t auxl; @@ -353,7 +365,7 @@ err_recv: int libsoccr_save(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigned data_size) { - struct tcp_info ti; + struct soccr_tcp_info ti; if (!data || data_size < SOCR_DATA_MIN_SIZE) { loge("Invalid input parameters\n"); diff --git a/test/zdtm/static/socket-tcp-close0.c b/test/zdtm/static/socket-tcp-close0.c index 2bc0f64f9..6043cebb8 100644 --- a/test/zdtm/static/socket-tcp-close0.c +++ b/test/zdtm/static/socket-tcp-close0.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "zdtmtst.h" @@ -14,7 +15,9 @@ static int port = 8880; static int check_socket_closed(int sk) { int err, buffer = 0; - struct tcp_info info; + struct { + __u8 tcpi_state; + } info; socklen_t len = sizeof(info); err = getsockopt(sk, IPPROTO_TCP, TCP_INFO, (void *)&info, &len); diff --git a/test/zdtm/static/socket-tcp-close1.c b/test/zdtm/static/socket-tcp-close1.c index 54511a341..3dba4e54d 100644 --- a/test/zdtm/static/socket-tcp-close1.c +++ b/test/zdtm/static/socket-tcp-close1.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "zdtmtst.h" @@ -13,7 +14,9 @@ static int port = 8880; static int check_socket_state(int sk, int state) { int err; - struct tcp_info info; + struct { + __u8 tcpi_state; + } info; socklen_t len = sizeof(info); err = getsockopt(sk, IPPROTO_TCP, TCP_INFO, (void *)&info, &len); From 0a303160774f9e807dee4194cf591f153a2382cc Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 30 Sep 2017 01:41:43 +0300 Subject: [PATCH 1028/4375] zdtm/autofs: don't include bits/signum.h It isn't required and it is absant on alpine autofs.c:9:25: fatal error: bits/signum.h: No such file or directory Signed-off-by: Andrei Vagin --- test/zdtm/static/autofs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/zdtm/static/autofs.c b/test/zdtm/static/autofs.c index ae7853806..c2e047714 100644 --- a/test/zdtm/static/autofs.c +++ b/test/zdtm/static/autofs.c @@ -6,8 +6,6 @@ #include #include -#include - #include #include #include From 7678f440cac6ea74040bff82b8d7964b3640c8e6 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 30 Sep 2017 01:41:44 +0300 Subject: [PATCH 1029/4375] test/zdtm: a few fixes to compile tests on Alpine Signed-off-by: Andrei Vagin --- test/zdtm/static/file_locks01.c | 8 ++++++++ test/zdtm/static/ghost_holes00.c | 5 +++++ test/zdtm/static/ipc_namespace.c | 6 +++--- test/zdtm/static/netns-dev.c | 1 + test/zdtm/static/poll.c | 2 +- test/zdtm/static/pthread01.c | 2 +- test/zdtm/static/sigpending.c | 26 ++++++++++++++++++++++---- 7 files changed, 41 insertions(+), 9 deletions(-) diff --git a/test/zdtm/static/file_locks01.c b/test/zdtm/static/file_locks01.c index aadc5e422..399a42835 100644 --- a/test/zdtm/static/file_locks01.c +++ b/test/zdtm/static/file_locks01.c @@ -10,6 +10,14 @@ #include "zdtmtst.h" #include "fs.h" +#ifndef LOCK_MAND +#define LOCK_MAND 32 +#endif + +#ifndef LOCK_READ +#define LOCK_READ 64 +#endif + const char *test_doc = "Check that flock locks are restored"; const char *test_author = "Qiang Huang "; diff --git a/test/zdtm/static/ghost_holes00.c b/test/zdtm/static/ghost_holes00.c index 11561d9fe..214a39141 100644 --- a/test/zdtm/static/ghost_holes00.c +++ b/test/zdtm/static/ghost_holes00.c @@ -19,6 +19,11 @@ TEST_OPTION(filename, string, "file name", 1); #define BUFSIZE 4096 static unsigned char buf4k[BUFSIZE]; +#ifndef SEEK_DATA +#define SEEK_DATA 3 +#define SEEK_HOLE 4 +#endif + #ifdef HEAD_HOLE #define HH 1 #else diff --git a/test/zdtm/static/ipc_namespace.c b/test/zdtm/static/ipc_namespace.c index 84331d370..a7f0fd103 100644 --- a/test/zdtm/static/ipc_namespace.c +++ b/test/zdtm/static/ipc_namespace.c @@ -12,9 +12,9 @@ #define CLONE_NEWIPC 0x08000000 -extern int msgctl (int __msqid, int __cmd, struct msqid_ds *__buf) __THROW; -extern int semctl (int __semid, int __semnum, int __cmd, ...) __THROW; -extern int shmctl (int __shmid, int __cmd, struct shmid_ds *__buf) __THROW; +extern int msgctl (int __msqid, int __cmd, struct msqid_ds *__buf); +extern int semctl (int __semid, int __semnum, int __cmd, ...); +extern int shmctl (int __shmid, int __cmd, struct shmid_ds *__buf); struct ipc_ids { int in_use; /* TODO: Check for 0 */ diff --git a/test/zdtm/static/netns-dev.c b/test/zdtm/static/netns-dev.c index 4efbeba7e..8763773cc 100644 --- a/test/zdtm/static/netns-dev.c +++ b/test/zdtm/static/netns-dev.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "zdtmtst.h" diff --git a/test/zdtm/static/poll.c b/test/zdtm/static/poll.c index 33bc0bd4a..53d801a0b 100644 --- a/test/zdtm/static/poll.c +++ b/test/zdtm/static/poll.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include diff --git a/test/zdtm/static/pthread01.c b/test/zdtm/static/pthread01.c index 2520fcfee..1e84463ee 100644 --- a/test/zdtm/static/pthread01.c +++ b/test/zdtm/static/pthread01.c @@ -33,7 +33,7 @@ static char *decode_signal(const sigset_t *s, char *buf) #define COLLECT(sig) \ do { \ - if ((long)s->__val[0] & (long)sigmask(sig)) \ + if (sigismember(s, sig)) \ strcat(buf, #sig " "); \ } while (0) diff --git a/test/zdtm/static/sigpending.c b/test/zdtm/static/sigpending.c index 4adcfa626..b6d224c75 100644 --- a/test/zdtm/static/sigpending.c +++ b/test/zdtm/static/sigpending.c @@ -28,6 +28,24 @@ static int thread_nr; # define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif +/* cr_siginfo is declared to get an offset of _sifields */ +union cr_siginfo { + struct { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[10]; + /* ... */ + } _sifields; + } _info; + siginfo_t info; +}; +typedef union cr_siginfo cr_siginfo_t; + +#define siginf_body(s) (&((cr_siginfo_t *)(s))->_info._sifields) + #ifdef __i386__ /* * On x86_32 kernel puts only relevant union member when signal arrives, @@ -44,9 +62,9 @@ static int thread_nr; */ # define _si_fields_sz 12 #else -# define _si_fields_sz (sizeof(siginfo_t) - offsetof(siginfo_t, _sifields)) +# define _si_fields_sz (sizeof(siginfo_t) - offsetof(cr_siginfo_t, _info._sifields)) #endif -#define siginfo_filled (offsetof(siginfo_t, _sifields) + _si_fields_sz) +#define siginfo_filled (offsetof(cr_siginfo_t, _info._sifields) + _si_fields_sz) static pthread_mutex_t exit_lock; static pthread_mutex_t init_lock; @@ -90,7 +108,7 @@ static void sig_handler(int signal, siginfo_t *info, void *data) } crc = ~0; - if (datachk((uint8_t *) &info->_sifields, _si_fields_sz, &crc)) { + if (datachk((uint8_t *) siginf_body(info), _si_fields_sz, &crc)) { fail("CRC mismatch\n"); return; } @@ -172,7 +190,7 @@ int send_siginfo(int signo, pid_t pid, pid_t tid, int group, siginfo_t *info) info->si_code = si_code; si_code--; info->si_signo = signo; - datagen((uint8_t *) &info->_sifields, _si_fields_sz, &crc); + datagen((uint8_t *) siginf_body(info), _si_fields_sz, &crc); sent_sigs++; From 061a407ce3fdf6a3e3398b43c8c787a1a27d0991 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 2 Oct 2017 21:45:48 +0300 Subject: [PATCH 1030/4375] alpine: compile all tests Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.alpine | 11 +++++++---- scripts/travis/Makefile | 5 ++++- scripts/travis/asan.sh | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index bb6af2057..ac13d344e 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -20,8 +20,8 @@ RUN apk update && apk add \ COPY . /criu WORKDIR /criu ENV CC="ccache $CC" CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes -RUN mv .ccache /tmp && make mrproper && ccache -s && \ - date && make -j $(nproc) CC="$CC" && date +RUN mv .ccache /tmp && make mrproper && ccache -s && ccache -z &&\ + date && make -j $(nproc) CC="$CC" && date && ccache -s # Run a test RUN apk add py-yaml \ @@ -29,5 +29,8 @@ RUN apk add py-yaml \ ip6tables \ iptables \ iproute2 \ - && pip install protobuf \ - && make -C test/zdtm/static env00 + tar \ + bash + +RUN pip install protobuf ipaddr +RUN make -C test/zdtm diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index 53b27649a..48a04fa35 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -12,12 +12,15 @@ ifdef CLANG endif TARGETS := fedora-asan alpine fedora-rawhide +ZDTM_OPTIONS := + +alpine: ZDTM_OPTIONS=-x zdtm/static/binfmt_misc -x zdtm/static/netns-nf -x zdtm/static/sched_policy00 -x zdtm/static/seccomp_strict -x zdtm/static/sigaltstack -x zdtm/static/signalfd00 -x zdtm/static/config_inotify_irmap $(TARGETS): echo 'DOCKER_OPTS="--storage-driver=devicemapper"' > /etc/default/docker restart docker $(MAKE) -C ../build $@$(target-suffix) - docker run --rm -it --privileged -v /lib/modules:/lib/modules criu-$@ ./scripts/travis/asan.sh + docker run --rm -it --privileged -v /lib/modules:/lib/modules criu-$@ ./scripts/travis/asan.sh $(ZDTM_OPTIONS) docker-test: ./docker-test.sh diff --git a/scripts/travis/asan.sh b/scripts/travis/asan.sh index 5b34da61e..15bfe53fe 100755 --- a/scripts/travis/asan.sh +++ b/scripts/travis/asan.sh @@ -8,7 +8,7 @@ chmod 0777 test chmod 0777 test/zdtm/transition/ chmod 0777 test/zdtm/static -./test/zdtm.py run -a --keep-going -k always --parallel 4 -x zdtm/static/rtc +./test/zdtm.py run -a --keep-going -k always --parallel 4 -x zdtm/static/rtc "$@" ret=$? for i in `find / -name 'asan.log*'`; do From 251b4d06a98554639b2893fea994220f4edd14bb Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 30 Sep 2017 04:33:57 +0300 Subject: [PATCH 1031/4375] zdtm: report test results in the junit format We found a good plugin for Jenkins to analize test results, but it can handle only the junit format. v2: work without the junit python module v3: install junit-xml, because zdtm.py is executed with the --report option from jenkins scripts. Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 1 + test/zdtm.py | 30 +++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 305b45f44..d3aaf9f48 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -38,6 +38,7 @@ travis_prep () { apt-get update -qq apt-get install -qq --no-install-recommends $TRAVIS_PKGS + pip install junit-xml chmod a+x $HOME } diff --git a/test/zdtm.py b/test/zdtm.py index b48301f03..8f7cbd4b5 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1383,6 +1383,8 @@ class launcher: self.__subs = {} self.__fail = False self.__file_report = None + self.__junit_file = None + self.__junit_test_cases = None self.__failed = [] self.__nr_skip = 0 if self.__max > 1 and self.__total > 1: @@ -1393,13 +1395,20 @@ class launcher: self.__use_log = False if opts['report'] and (opts['keep_going'] or self.__total == 1): + global TestSuite, TestCase + from junit_xml import TestSuite, TestCase now = datetime.datetime.now() att = 0 reportname = os.path.join(report_dir, "criu-testreport.tap") - while os.access(reportname, os.F_OK): + junitreport = os.path.join(report_dir, "criu-testreport.xml") + while os.access(reportname, os.F_OK) or os.access(junitreport, os.F_OK): reportname = os.path.join(report_dir, "criu-testreport" + ".%d.tap" % att) + junitreport = os.path.join(report_dir, "criu-testreport" + ".%d.xml" % att) att += 1 + self.__junit_file = open(junitreport, 'a') + self.__junit_test_cases = [] + self.__file_report = open(reportname, 'a') print >> self.__file_report, "TAP version 13" print >> self.__file_report, "# Hardware architecture: " + arch @@ -1421,6 +1430,12 @@ class launcher: self.__nr += 1 self.__runtest += 1 self.__nr_skip += 1 + + if self.__junit_test_cases != None: + tc = TestCase(name) + tc.add_skipped_info(reason) + if self.__junit_test_cases != None: + self.__junit_test_cases.append(tc) if self.__file_report: testline = "ok %d - %s # SKIP %s" % (self.__runtest, name, reason) print >> self.__file_report, testline @@ -1455,7 +1470,7 @@ class launcher: sub = subprocess.Popen(["./zdtm_ct", "zdtm.py"], env = dict(os.environ, CR_CT_TEST_INFO = arg), stdout = log, stderr = subprocess.STDOUT, close_fds = True) - self.__subs[sub.pid] = {'sub': sub, 'log': logf, 'name': name} + self.__subs[sub.pid] = {'sub': sub, 'log': logf, 'name': name, "start": time.time()} if test_flag(desc, 'excl'): self.wait() @@ -1465,13 +1480,19 @@ class launcher: self.__runtest += 1 if pid != 0: sub = self.__subs.pop(pid) + tc = None + if self.__junit_test_cases != None: + tc = TestCase(sub['name'], elapsed_sec=time.time() - sub['start']) + self.__junit_test_cases.append(tc) if status != 0: self.__fail = True failed_flavor = decode_flav(os.WEXITSTATUS(status)) self.__failed.append([sub['name'], failed_flavor]) if self.__file_report: testline = "not ok %d - %s # flavor %s" % (self.__runtest, sub['name'], failed_flavor) - details = {'output': open(sub['log']).read()} + output = open(sub['log']).read() + details = {'output': output} + tc.add_error_info(output = output) print >> self.__file_report, testline print >> self.__file_report, yaml.dump(details, explicit_start=True, explicit_end=True, default_style='|') if sub['log']: @@ -1511,6 +1532,8 @@ class launcher: if not opts['fault'] and check_core_files(): self.__fail = True if self.__file_report: + ts = TestSuite(opts['title'], self.__junit_test_cases, os.getenv("NODE_NAME")) + self.__junit_file.write(TestSuite.to_xml_string([ts])) self.__file_report.close() if opts['keep_going']: @@ -1968,6 +1991,7 @@ rp.add_argument("--keep-going", help = "Keep running tests in spite of failures" rp.add_argument("--ignore-taint", help = "Don't care about a non-zero kernel taint flag", action = 'store_true') rp.add_argument("--lazy-pages", help = "restore pages on demand", action = 'store_true') rp.add_argument("--remote-lazy-pages", help = "simulate lazy migration", action = 'store_true') +rp.add_argument("--title", help = "A test suite title", default = "criu") lp = sp.add_parser("list", help = "List tests") lp.set_defaults(action = list_tests) From 4ff68eeb36185ef538a7ccc8ca30b0c1be662109 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 2 Oct 2017 10:07:48 +0300 Subject: [PATCH 1032/4375] fsnotify: Filter event mask from old kernels When checkpoint is done on the kernels where commit 6933599697c96c3213c95f5f1fc7cb6abfd08c54 is not yet present then mask is not filtered and saved in image in this raw form. For such case restore on more modern kernels will fail because only a small set of events are allowed to pass from userspace. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/fsnotify.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 54f70e698..6098b5b4c 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -551,12 +551,19 @@ static int restore_one_inotify(int inotify_fd, struct fsnotify_mark_info *info) InotifyWdEntry *iwe = info->iwe; int ret = -1, target = -1; char buf[PSFDS], *path; + uint32_t mask; path = get_mark_path("inotify", info->remap, iwe->f_handle, iwe->i_ino, iwe->s_dev, buf, &target); if (!path) goto err; + mask = iwe->mask & IN_ALL_EVENTS; + if (iwe->mask & ~IN_ALL_EVENTS) { + pr_info("\t\tfilter event mask %#x -> %#x\n", + iwe->mask, mask); + } + /* * FIXME The kernel allocates wd-s sequentially, * this is suboptimal, but the kernel doesn't @@ -565,7 +572,7 @@ static int restore_one_inotify(int inotify_fd, struct fsnotify_mark_info *info) while (1) { int wd; - wd = inotify_add_watch(inotify_fd, path, iwe->mask); + wd = inotify_add_watch(inotify_fd, path, mask); if (wd < 0) { pr_perror("Can't add watch for 0x%x with 0x%x", inotify_fd, iwe->wd); break; From da3f0d9a066bea0544e07ce36b39dfcbd3e7c90b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 2 Oct 2017 13:16:18 +0300 Subject: [PATCH 1033/4375] criu: threads -- Allow uids/gids being different We are carrying uids/gids in per-thread way since v1.8, so no need to require them to match anymore. We still require seccomp to match though. Need to revisit, seems may relax this requirement as well. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/seize.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/criu/seize.c b/criu/seize.c index ae99ddf56..635c0c088 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -629,23 +629,14 @@ static inline bool thread_collected(struct pstree_item *i, pid_t tid) static bool creds_dumpable(struct proc_status_creds *parent, struct proc_status_creds *child) { - size_t size; /* - * The comparison rules are the following - * - * - CAPs can be different * - seccomp filters should be passed via * semantic comparison (FIXME) but for * now we require them to be exactly * identical - * - sigpnd may be different - * - the rest of members must match */ - - size = offsetof(struct proc_status_creds, cap_inh) - - sizeof(parent->s.sigpnd); - - if (memcmp(&parent->s.sigpnd, &child->s.sigpnd, size)) { + if (parent->s.seccomp_mode != child->s.seccomp_mode || + parent->last_filter != child->last_filter) { if (!pr_quelled(LOG_DEBUG)) { pr_debug("Creds undumpable (parent:child)\n" " uids: %d:%d %d:%d %d:%d %d:%d\n" From 7d12ce293cbf6a4e77db22051db4fe13a7665c22 Mon Sep 17 00:00:00 2001 From: Vitaly Ostrosablin Date: Mon, 2 Oct 2017 13:16:19 +0300 Subject: [PATCH 1034/4375] zdtm: Implement different per-thread credentials testcase As requested, implement a test with two threads that have mismatching, non-root credentials, like Apache does. Signed-off-by: Vitaly Ostrosablin Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 3 + test/zdtm/static/thread_different_uid_gid.c | 177 ++++++++++++++++++ .../zdtm/static/thread_different_uid_gid.desc | 1 + 3 files changed, 181 insertions(+) create mode 100644 test/zdtm/static/thread_different_uid_gid.c create mode 100644 test/zdtm/static/thread_different_uid_gid.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 67de8b8ac..a35b81443 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -175,6 +175,7 @@ TST_NOFILE := \ sock_peercred \ s390x_mmap_high \ uffd-events \ + thread_different_uid_gid \ # jobctl00 \ include ../Makefile.inc @@ -471,6 +472,8 @@ shm-unaligned: CFLAGS += -DZDTM_SHM_UNALIGNED s390x_regs_check: LDFLAGS += -pthread +thread_different_uid_gid: LDLIBS += -pthread -lcap + $(LIB): force $(Q) $(MAKE) -C $(LIBDIR) diff --git a/test/zdtm/static/thread_different_uid_gid.c b/test/zdtm/static/thread_different_uid_gid.c new file mode 100644 index 000000000..1951668fb --- /dev/null +++ b/test/zdtm/static/thread_different_uid_gid.c @@ -0,0 +1,177 @@ +/* + * Check that we can dump a process with threads having mismatching UID/GID + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "zdtmtst.h" + +#define exit_group(code) \ + syscall(__NR_exit_group, code) + +const char *test_doc = "Acquire UID/GID setting caps, create thread and drop thread to non-root by changing UID/GID\n"; +const char *test_author = "Vitaly Ostrosablin "; + +unsigned int gid; +unsigned int uid; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +int done = 0; + +void *chg_uid_gid(void *arg) +{ + int ret; + cap_t mycaps; + cap_t newcaps; + test_msg("Aux thread runs as UID: %d; GID: %d\n", getuid(), getgid()); + newcaps = cap_from_text("cap_setgid,cap_setuid=+eip"); + if (!newcaps) + { + pr_perror("Failed to get capability struct\n"); + exit(1); + } + ret = cap_set_proc(newcaps); + if (ret) { + pr_perror("Failed to set capabilities for the process\n"); + exit(1); + } + mycaps = cap_get_proc(); + if (!mycaps) { + pr_perror("Failed to get child thread capabilities\n"); + exit_group(2); + } + test_msg("Child capabilities: %s\n", cap_to_text(mycaps, NULL)); + test_msg("Changing UID/GID in child thread to %d:%d\n", uid, gid); + ret = syscall(SYS_setresgid, gid, gid, gid); + if (ret >= 0) { + syscall(SYS_setresuid, uid, uid, uid); + } + if (ret < 0) { + pr_perror("Failed to change UID/GID\n"); + exit_group(2); + } + gid = getgid(); + uid = getuid(); + test_msg("Now aux thread runs as UID: %d; GID: %d\n", uid, gid); + test_msg("Child thread is waiting for main thread's signal\n"); + pthread_mutex_lock(&mutex); + while (!done) + { + pthread_cond_wait(&cond, &mutex); + } + pthread_mutex_unlock(&mutex); + + test_msg("Child thread returns\n"); + return NULL; +} + +int main(int argc, char **argv) +{ + + int ret; + cap_t newcaps; + struct group *group; + struct passwd *user; + pthread_t diff_cred_thread; + test_init(argc, argv); + int maingroup; + int mainuser; + + if (getuid() != 0) { + fail("Test is expected to be run with root privileges\n"); + exit(1); + } + + test_daemon(); + test_msg("Test daemonized\n"); + + test_msg("Acquiring CAP_SETGID and CAP_SETUID...\n"); + newcaps = cap_from_text("cap_setgid,cap_setuid=+eip"); + if (!newcaps) + { + pr_perror("Failed to get capability struct\n"); + exit(1); + } + ret = cap_set_proc(newcaps); + if (ret) { + pr_perror("Failed to set capabilities for the process\n"); + exit(1); + } + ret = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); + if (ret) { + pr_perror("Unable to set KEEPCAPS\n"); + exit(1); + } + + test_msg("Main thread runs as UID: %d; GID: %d\n", getuid(), getgid()); + group = getgrnam("nogroup"); + group = (group) ? group : getgrnam("nobody"); + if (!group) { + pr_perror("Failed to get nogroup/nobody GID\n"); + exit(1); + } + user = getpwnam("nobody"); + if (!user) { + pr_perror("Failed to get nobody UID\n"); + exit(1); + } + gid = group->gr_gid; + uid = user->pw_uid; + group = getgrnam("mail"); + if (!group) { + pr_perror("Failed to get mail GID\n"); + exit(1); + } + user = getpwnam("mail"); + if (!user) { + pr_perror("Failed to get mail UID\n"); + exit(1); + } + maingroup = group->gr_gid; + mainuser = user->pw_uid; + + test_msg("Creating thread with different UID/GID\n"); + ret = pthread_create(&diff_cred_thread, NULL, &chg_uid_gid, NULL); + sleep(5); + test_msg("Relinquishing root privileges\n"); + ret = syscall(SYS_setresgid, maingroup, maingroup, maingroup); + if (ret >= 0) { + ret = syscall(SYS_setresuid, mainuser, mainuser, mainuser); + } + if (ret < 0) { + pr_perror("Failed to drop privileges\n"); + exit(1); + } + test_msg("Now main thread runs as UID: %d; GID: %d\n", getuid(), getgid()); + if (gid == getgid() || uid == getuid()) { + pr_perror("Thread credentials match\n"); + exit(1); + } + test_msg("Main thread is waiting for signal\n"); + + test_waitsig(); + + if (gid == getgid() || uid == getuid()) { + pr_perror("Thread credentials match after restore\n"); + exit(1); + } + pthread_mutex_lock(&mutex); + done = 1; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + pthread_join(diff_cred_thread, NULL); + test_msg("Threads joined\n"); + pass(); + return 0; +} diff --git a/test/zdtm/static/thread_different_uid_gid.desc b/test/zdtm/static/thread_different_uid_gid.desc new file mode 100644 index 000000000..fa2c82d08 --- /dev/null +++ b/test/zdtm/static/thread_different_uid_gid.desc @@ -0,0 +1 @@ +{'flavor': 'h', 'flags': 'suid'} From f54acb48f95fe4dd2dfc6be565a942eb458821f9 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 5 Oct 2017 02:17:06 +0300 Subject: [PATCH 1035/4375] zdtm: fix warnings from flake8 test/zdtm.py:1535:30: E711 comparison to None should be 'if cond is not None:' test/zdtm.py:1538:31: E711 comparison to None should be 'if cond is not None:' test/zdtm.py:1601:31: E711 comparison to None should be 'if cond is not None:' Signed-off-by: Andrei Vagin --- test/zdtm.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 8f7cbd4b5..28f00aeb8 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1431,11 +1431,10 @@ class launcher: self.__runtest += 1 self.__nr_skip += 1 - if self.__junit_test_cases != None: + if self.__junit_test_cases is not None: tc = TestCase(name) tc.add_skipped_info(reason) - if self.__junit_test_cases != None: - self.__junit_test_cases.append(tc) + self.__junit_test_cases.append(tc) if self.__file_report: testline = "ok %d - %s # SKIP %s" % (self.__runtest, name, reason) print >> self.__file_report, testline @@ -1481,7 +1480,7 @@ class launcher: if pid != 0: sub = self.__subs.pop(pid) tc = None - if self.__junit_test_cases != None: + if self.__junit_test_cases is not None: tc = TestCase(sub['name'], elapsed_sec=time.time() - sub['start']) self.__junit_test_cases.append(tc) if status != 0: From 5dc2e922d72e9767f2320ec4a894cfcd93007042 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 4 Oct 2017 01:33:19 +0300 Subject: [PATCH 1036/4375] travis: mount tmpfs into /run for docker containers Otherwise we will see warnings like these ones: Warn (criu/kerndat.c:805): Can't load /run/criu.kdat Warn (criu/net.c:2726): Unable to get a socket network namespace Warn (criu/kerndat.c:844): Can't keep kdat cache on non-tempfs Signed-off-by: Andrei Vagin --- scripts/travis/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index 48a04fa35..4d89610bf 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -20,7 +20,7 @@ $(TARGETS): echo 'DOCKER_OPTS="--storage-driver=devicemapper"' > /etc/default/docker restart docker $(MAKE) -C ../build $@$(target-suffix) - docker run --rm -it --privileged -v /lib/modules:/lib/modules criu-$@ ./scripts/travis/asan.sh $(ZDTM_OPTIONS) + docker run --rm -it --privileged -v /lib/modules:/lib/modules --tmpfs /run criu-$@ ./scripts/travis/asan.sh $(ZDTM_OPTIONS) docker-test: ./docker-test.sh From f41e386d4d40e3e26b0cfdc85a812b7edb337f1d Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 28 Sep 2017 09:13:33 +0000 Subject: [PATCH 1037/4375] fix building on newest glibc and kernel On Fedora rawhide with kernel-headers-4.14.0-0.rc2.git0.1.fc28.x86_64 glibc-devel-2.26.90-15.fc28.x86_64 criu does not build any more: In file included from /usr/include/linux/aio_abi.h:31:0, from criu/cr-check.c:24: /usr/include/sys/mount.h:35:3: error: expected identifier before numeric constant MS_RDONLY = 1, /* Mount read-only. */ ^ make[2]: *** [/builddir/build/BUILD/criu-3.5/scripts/nmk/scripts/build.mk:111: criu/cr-check.o] Error 1 make[1]: *** [criu/Makefile:73: criu/built-in.o] Error 2 make: *** [Makefile:233: criu] Error 2 This simple re-ordering of includes fixes it for me. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index 5dd448bb1..8986ec405 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -21,8 +21,8 @@ #include #include #include -#include #include +#include #include "../soccr/soccr.h" From 0ee7df54de502d1306eb0a33da58dc540fae3e18 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 8 Oct 2017 09:26:53 +0300 Subject: [PATCH 1038/4375] lazy-pages: treat ENOMEM returned by UFFDIO_UNREGISTER as task exit The UFFDIO_UNREGISTER returns ENOMEM only when it is unable to get mm_struct. We can assume in such case that the task is exited. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/criu/uffd.c b/criu/uffd.c index 7e858903f..740f5e371 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -914,6 +914,15 @@ static int handle_remove(struct lazy_pages_info *lpi, struct uffd_msg *msg) */ if (msg->event == UFFD_EVENT_REMOVE && ioctl(lpi->lpfd.fd, UFFDIO_UNREGISTER, &unreg)) { + /* + * The kernel returns -ENOMEM when unregister is + * called after the process has gone + */ + if (errno == ENOMEM) { + handle_exit(lpi); + return 0; + } + pr_perror("Failed to unregister (%llx - %llx)", unreg.start, unreg.start + unreg.len); return -1; From 3fb3e87058b143f63346cfffeafd7bad1e3e8986 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 8 Oct 2017 16:19:40 +0300 Subject: [PATCH 1039/4375] travis/lazy-pages: explicitly define the tests to verify lazy-pages Running all the tests with --lazy-pages and --remote-lazy-pages takes too long. Let's run only several representing tests for those cases. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index d3aaf9f48..5c1349f0a 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -84,9 +84,12 @@ else -x socket_listen -x socket_listen6 -x cmdlinenv00 -x socket_close_data01 -x file_read" fi -LAZY_EXCLUDE="$LAZY_EXCLUDE -x futex -x lazy-thp" -./test/zdtm.py run -a -p 2 --lazy-pages $LAZY_EXCLUDE -./test/zdtm.py run -a -p 2 --remote-lazy-pages $LAZY_EXCLUDE +LAZY_EXCLUDE="$LAZY_EXCLUDE -x maps04" + +LAZY_TESTS=.*\(maps0\|uffd-events\|lazy-thp\|futex\|fork\).* + +./test/zdtm.py run -p 2 -T $LAZY_TESTS --lazy-pages $LAZY_EXCLUDE +./test/zdtm.py run -p 2 -T $LAZY_TESTS --remote-lazy-pages $LAZY_EXCLUDE bash ./test/jenkins/criu-fault.sh bash ./test/jenkins/criu-fcg.sh From 04e0bcae1dc9c8df0d2be8af3bf9589aef886a15 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Thu, 5 Oct 2017 15:50:39 +0200 Subject: [PATCH 1040/4375] Restore registers not present in the sigreturn signal frame Add new function arch_set_task_regs_nosigrt(). It allows to restore architecture-specific registers not present in sigreturn signal frame. Each architecture can overwrite this function. The arch_set_task_regs_nosigrt function restores the registers between the final sigreturn and PTRACE_DETACH. We do this at this point because we are sure that all threads have already been created. Add arch_set_thread_regs in pre-dump because some registers may have been changed by the parasite infection and they are not present in sigreturn signal frame. Signed-off-by: Alice Frosi Reviewed-by: Michael Holzheu Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 16 ++++++++++++++-- criu/cr-restore.c | 11 +++++++++++ criu/include/dump.h | 3 +++ criu/include/restore.h | 5 +++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 8c8a11c21..b874be014 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -86,8 +86,13 @@ /* * Architectures can overwrite this function to restore register sets that * are not covered by ptrace_set/get_regs(). + * + * with_threads = false: Only the register sets of the tasks are restored + * with_threads = true : The register sets of the tasks with all their threads + * are restored */ -int __attribute__((weak)) arch_set_thread_regs(struct pstree_item *item) +int __attribute__((weak)) arch_set_thread_regs(struct pstree_item *item, + bool with_threads) { return 0; } @@ -1468,6 +1473,12 @@ static int cr_pre_dump_finish(int ret) { struct pstree_item *item; + /* + * Restore registers for tasks only. The threads have not been + * infected. Therefore, the thread register sets have not been changed. + */ + if (arch_set_thread_regs(root_item, false) < 0) + goto err; pstree_switch_state(root_item, TASK_ALIVE); timing_stop(TIME_FROZEN); @@ -1680,7 +1691,8 @@ static int cr_dump_finish(int ret) if (!ret && opts.lazy_pages) ret = cr_lazy_mem_dump(); - arch_set_thread_regs(root_item); + if (arch_set_thread_regs(root_item, true) < 0) + return -1; pstree_switch_state(root_item, (ret || post_dump_ret) ? TASK_ALIVE : opts.final_state); diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 83e9de1bb..7d3c06e4b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -121,6 +121,15 @@ static int prepare_rlimits(int pid, struct task_restore_args *, CoreEntry *core) static int prepare_posix_timers(int pid, struct task_restore_args *ta, CoreEntry *core); static int prepare_signals(int pid, struct task_restore_args *, CoreEntry *core); +/* + * Architectures can overwrite this function to restore registers that are not + * present in the sigreturn signal frame. + */ +int __attribute__((weak)) arch_set_thread_regs_nosigrt(struct pid *pid) +{ + return 0; +} + static inline int stage_participants(int next_stage) { switch (next_stage) { @@ -1812,6 +1821,8 @@ static void finalize_restore_detach(int status) break; } + if (arch_set_thread_regs_nosigrt(&item->threads[i])) + pr_perror("Restoring regs for %d failed", pid); if (ptrace(PTRACE_DETACH, pid, NULL, 0)) pr_perror("Unable to execute %d", pid); } diff --git a/criu/include/dump.h b/criu/include/dump.h index d9a4b61ad..1c1446886 100644 --- a/criu/include/dump.h +++ b/criu/include/dump.h @@ -1,4 +1,7 @@ #ifndef __CR_INC_DUMP_H__ #define __CR_INC_DUMP_H__ #include "asm/dump.h" + +extern int arch_set_thread_regs(struct pstree_item *item, bool with_threads); + #endif diff --git a/criu/include/restore.h b/criu/include/restore.h index 7a1efcfc4..8ef0dbddf 100644 --- a/criu/include/restore.h +++ b/criu/include/restore.h @@ -1,5 +1,10 @@ #ifndef __CR_INC_RESTORE_H__ #define __CR_INC_RESTORE_H__ + +#include "pid.h" #include "types.h" #include "asm/restore.h" + +extern int arch_set_thread_regs_nosigrt(struct pid *pid); + #endif From a14421045124982633c393be85ad6359eed814bf Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Thu, 5 Oct 2017 15:50:40 +0200 Subject: [PATCH 1041/4375] s390: Add guarded-storage support Dump and restore tasks with GS control blocks. Guarded-storage is a new s390 feature to improve garbage collecting languages like Java. There are two control blocks in the CPU: - GS control block - GS broadcast control block Both control blocks have to be dumped and restored for all threads. Signed-off-by: Alice Frosi Reviewed-by: Michael Holzheu Signed-off-by: Andrei Vagin --- .../src/lib/include/uapi/asm/infect-types.h | 6 + compel/arch/s390/src/lib/infect.c | 102 ++++++- criu/arch/s390/crtools.c | 266 +++++++++++++++--- images/core-s390.proto | 6 + 4 files changed, 341 insertions(+), 39 deletions(-) diff --git a/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h b/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h index 84edea5d7..038c4a034 100644 --- a/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h @@ -38,12 +38,18 @@ struct prfpreg { }; #define USER_FPREGS_VXRS 0x000000001 +/* Guarded-storage control block */ +#define USER_GS_CB 0x000000002 +/* Guarded-storage broadcast control block */ +#define USER_GS_BC 0x000000004 typedef struct { uint32_t flags; struct prfpreg prfpreg; uint64_t vxrs_low[16]; vector128_t vxrs_high[16]; + uint64_t gs_cb[4]; + uint64_t gs_bc[4]; } user_fpregs_struct_t; typedef struct { diff --git a/compel/arch/s390/src/lib/infect.c b/compel/arch/s390/src/lib/infect.c index 3c1fff68c..897b66fd9 100644 --- a/compel/arch/s390/src/lib/infect.c +++ b/compel/arch/s390/src/lib/infect.c @@ -19,6 +19,8 @@ #define NT_PRFPREG 2 #define NT_S390_VXRS_LOW 0x309 #define NT_S390_VXRS_HIGH 0x30a +#define NT_S390_GS_CB 0x30b +#define NT_S390_GS_BC 0x30c /* * Print general purpose and access registers @@ -40,17 +42,12 @@ static void print_user_regs_struct(const char *msg, int pid, } /* - * Print floating point and vector registers + * Print vector registers */ -static void print_user_fpregs_struct(const char *msg, int pid, - user_fpregs_struct_t *fpregs) +static void print_vxrs(user_fpregs_struct_t *fpregs) { int i; - pr_debug("%s: FP registers for pid=%d\n", msg, pid); - pr_debug(" fpc %08x\n", fpregs->prfpreg.fpc); - for (i = 0; i < 16; i++) - pr_debug(" f%02d %016lx\n", i, fpregs->prfpreg.fprs[i]); if (!(fpregs->flags & USER_FPREGS_VXRS)) { pr_debug(" No VXRS\n"); return; @@ -63,6 +60,53 @@ static void print_user_fpregs_struct(const char *msg, int pid, fpregs->vxrs_high[i].part2); } +/* + * Print guarded-storage control block + */ +static void print_gs_cb(user_fpregs_struct_t *fpregs) +{ + int i; + + if (!(fpregs->flags & USER_GS_CB)) { + pr_debug(" No GS_CB\n"); + return; + } + for (i = 0; i < 4; i++) + pr_debug(" gs_cb%02d %016lx\n", i, fpregs->gs_cb[i]); +} + +/* + * Print guarded-storage broadcast control block + */ +static void print_gs_bc(user_fpregs_struct_t *fpregs) +{ + int i; + + if (!(fpregs->flags & USER_GS_BC)) { + pr_debug(" No GS_BC\n"); + return; + } + for (i = 0; i < 4; i++) + pr_debug(" gs_bc%02d %016lx\n", i, fpregs->gs_bc[i]); +} + +/* + * Print FP registers, VX registers, and guarded storage + */ +static void print_user_fpregs_struct(const char *msg, int pid, + user_fpregs_struct_t *fpregs) +{ + int i; + + pr_debug("%s: FP registers for pid=%d\n", msg, pid); + pr_debug(" fpc %08x\n", fpregs->prfpreg.fpc); + for (i = 0; i < 16; i++) + pr_debug(" f%02d %016lx\n", i, fpregs->prfpreg.fprs[i]); + print_vxrs(fpregs); + print_gs_cb(fpregs); + print_gs_bc(fpregs); +} + int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) @@ -148,7 +192,47 @@ int get_vx_regs(pid_t pid, user_fpregs_struct_t *fpregs) return 0; } +/* + * Get guarded-storage control block + */ +int get_gs_cb(pid_t pid, user_fpregs_struct_t *fpregs) +{ + struct iovec iov; + fpregs->flags &= ~(USER_GS_CB | USER_GS_BC); + iov.iov_base = &fpregs->gs_cb; + iov.iov_len = sizeof(fpregs->gs_cb); + if (ptrace(PTRACE_GETREGSET, pid, NT_S390_GS_CB, &iov) < 0) { + switch (errno) { + case EINVAL: + case ENODEV: + memset(&fpregs->gs_cb, 0, sizeof(fpregs->gs_cb)); + memset(&fpregs->gs_bc, 0, sizeof(fpregs->gs_bc)); + pr_debug("GS_CB not supported\n"); + return 0; + case ENODATA: + pr_debug("GS_CB not set\n"); + break; + default: + return -1; + } + } else { + fpregs->flags |= USER_GS_CB; + } + iov.iov_base = &fpregs->gs_bc; + iov.iov_len = sizeof(fpregs->gs_bc); + if (ptrace(PTRACE_GETREGSET, pid, NT_S390_GS_BC, &iov) < 0) { + if (errno == ENODATA) { + pr_debug("GS_BC not set\n"); + return 0; + } + pr_perror("Couldn't get GS_BC\n"); + return -1; + } + fpregs->flags |= USER_GS_BC; + + return 0; +} /* * Prepare task registers for restart */ @@ -172,6 +256,10 @@ int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, pr_perror("Couldn't get vector registers"); return -1; } + if (get_gs_cb(pid, &fpregs)) { + pr_perror("Couldn't get guarded-storage"); + return -1; + } print_user_fpregs_struct("get_task_regs", pid, &fpregs); /* Check for system call restarting. */ if (regs->system_call) { diff --git a/criu/arch/s390/crtools.c b/criu/arch/s390/crtools.c index 27b19f76f..ddf268b90 100644 --- a/criu/arch/s390/crtools.c +++ b/criu/arch/s390/crtools.c @@ -24,10 +24,13 @@ #include "images/creds.pb-c.h" #include "ptrace.h" #include "pstree.h" +#include "image.h" #define NT_PRFPREG 2 #define NT_S390_VXRS_LOW 0x309 #define NT_S390_VXRS_HIGH 0x30a +#define NT_S390_GS_CB 0x30b +#define NT_S390_GS_BC 0x30c /* * Print general purpose and access registers @@ -47,24 +50,18 @@ static void print_core_gpregs(const char *msg, UserS390RegsEntry *gpregs) } /* - * Print floating point and vector registers + * Print vector registers */ -static void print_core_fp_regs(const char *msg, CoreEntry *core) +static void print_core_vx_regs(CoreEntry *core) { UserS390VxrsHighEntry *vxrs_high; UserS390VxrsLowEntry *vxrs_low; - UserS390FpregsEntry *fpregs; int i; vxrs_high = CORE_THREAD_ARCH_INFO(core)->vxrs_high; vxrs_low = CORE_THREAD_ARCH_INFO(core)->vxrs_low; - fpregs = CORE_THREAD_ARCH_INFO(core)->fpregs; - pr_debug("%s: Floating point registers\n", msg); - pr_debug(" fpc %08x\n", fpregs->fpc); - for (i = 0; i < 16; i++) - pr_debug(" f%02d %016lx\n", i, fpregs->fprs[i]); - if (!vxrs_low) { + if (vxrs_low == NULL) { pr_debug(" No VXRS\n"); return; } @@ -75,6 +72,60 @@ static void print_core_fp_regs(const char *msg, CoreEntry *core) vxrs_high->regs[i], vxrs_high->regs[i + 1]); } +/* + * Print guarded-storage control block + */ +static void print_core_gs_cb(CoreEntry *core) +{ + UserS390GsCbEntry *gs_cb; + int i; + + gs_cb = CORE_THREAD_ARCH_INFO(core)->gs_cb; + if (!gs_cb) { + pr_debug(" No GS_CB\n"); + return; + } + for (i = 0; i < 4; i++) + pr_debug(" gs_cb%d %lx\n", i, gs_cb->regs[i]); +} + +/* + * Print guarded-storage broadcast control block + */ +static void print_core_gs_bc(CoreEntry *core) +{ + UserS390GsCbEntry *gs_bc; + int i; + + gs_bc = CORE_THREAD_ARCH_INFO(core)->gs_bc; + + if (!gs_bc) { + pr_debug(" No GS_BC\n"); + return; + } + for (i = 0; i < 4; i++) + pr_debug(" gs_bc%d %lx\n", i, gs_bc->regs[i]); +} + +/* + * Print architecture registers + */ +static void print_core_fp_regs(const char *msg, CoreEntry *core) +{ + UserS390FpregsEntry *fpregs; + int i; + + fpregs = CORE_THREAD_ARCH_INFO(core)->fpregs; + + pr_debug("%s: Floating point registers\n", msg); + pr_debug(" fpc %08x\n", fpregs->fpc); + for (i = 0; i < 16; i++) + pr_debug(" f%02d %016lx\n", i, fpregs->fprs[i]); + print_core_vx_regs(core); + print_core_gs_cb(core); + print_core_gs_bc(core); +} + /* * Allocate VxrsLow registers */ @@ -143,15 +194,50 @@ static void free_vxrs_high_regs(UserS390VxrsHighEntry *vxrs_high) } } +/* + * Allocate guarded-storage control block (GS_CB and GS_BC) + */ +static UserS390GsCbEntry *allocate_gs_cb(void) +{ + UserS390GsCbEntry *gs_cb; + + gs_cb = xmalloc(sizeof(*gs_cb)); + if (!gs_cb) + return NULL; + user_s390_gs_cb_entry__init(gs_cb); + + gs_cb->n_regs = 4; + gs_cb->regs = xzalloc(4 * sizeof(uint64_t)); + if (!gs_cb->regs) + goto fail_free_gs_cb; + return gs_cb; + +fail_free_gs_cb: + xfree(gs_cb); + return NULL; +} + +/* + * Free Guareded Storage control blocks + */ +static void free_gs_cb(UserS390GsCbEntry *gs_cb) +{ + if (gs_cb) { + xfree(gs_cb->regs); + xfree(gs_cb); + } +} /* * Copy internal structures into Google Protocol Buffers */ int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f) { - UserS390VxrsHighEntry *vxrs_high; - UserS390VxrsLowEntry *vxrs_low; - UserS390FpregsEntry *fpregs; - UserS390RegsEntry *gpregs; + UserS390VxrsHighEntry *vxrs_high = NULL; + UserS390VxrsLowEntry *vxrs_low = NULL; + UserS390FpregsEntry *fpregs = NULL; + UserS390RegsEntry *gpregs = NULL; + UserS390GsCbEntry *gs_cb = NULL; + UserS390GsCbEntry *gs_bc = NULL; CoreEntry *core = arg; gpregs = CORE_THREAD_ARCH_INFO(core)->gpregs; @@ -163,15 +249,29 @@ int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f) if (!vxrs_low) return -1; vxrs_high = allocate_vxrs_high_regs(); - if (!vxrs_high) { - free_vxrs_low_regs(vxrs_low); - return -1; - } + if (!vxrs_high) + goto fail_free_vxrs_low; memcpy(vxrs_low->regs, &f->vxrs_low, sizeof(f->vxrs_low)); memcpy(vxrs_high->regs, &f->vxrs_high, sizeof(f->vxrs_high)); CORE_THREAD_ARCH_INFO(core)->vxrs_low = vxrs_low; CORE_THREAD_ARCH_INFO(core)->vxrs_high = vxrs_high; } + /* Guarded-storage control block */ + if (f->flags & USER_GS_CB) { + gs_cb = allocate_gs_cb(); + if (!gs_cb) + goto fail_free_gs_cb; + memcpy(gs_cb->regs, &f->gs_cb, sizeof(f->gs_cb)); + CORE_THREAD_ARCH_INFO(core)->gs_cb = gs_cb; + } + /* Guarded-storage broadcast control block */ + if (f->flags & USER_GS_BC) { + gs_bc = allocate_gs_cb(); + if (!gs_bc) + goto fail_free_gs_bc; + memcpy(gs_bc->regs, &f->gs_bc, sizeof(f->gs_bc)); + CORE_THREAD_ARCH_INFO(core)->gs_bc = gs_bc; + } /* General purpose registers */ memcpy(gpregs->gprs, u->prstatus.gprs, sizeof(u->prstatus.gprs)); gpregs->psw_mask = u->prstatus.psw.mask; @@ -184,6 +284,13 @@ int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f) fpregs->fpc = f->prfpreg.fpc; memcpy(fpregs->fprs, f->prfpreg.fprs, sizeof(f->prfpreg.fprs)); return 0; +fail_free_gs_cb: + free_gs_cb(gs_cb); +fail_free_gs_bc: + free_gs_cb(gs_bc); +fail_free_vxrs_low: + free_vxrs_low_regs(vxrs_low); + return -1; } /* @@ -225,7 +332,6 @@ int restore_fpu(struct rt_sigframe *f, CoreEntry *core) memcpy(&dst_ext->vxrs_high, vxrs_high->regs, sizeof(dst_ext->vxrs_high)); } - print_core_fp_regs("restore_fp_regs", core); return 0; } @@ -342,6 +448,8 @@ void arch_free_thread_info(CoreEntry *core) free_fp_regs(CORE_THREAD_ARCH_INFO(core)->fpregs); free_vxrs_low_regs(CORE_THREAD_ARCH_INFO(core)->vxrs_low); free_vxrs_high_regs(CORE_THREAD_ARCH_INFO(core)->vxrs_high); + free_gs_cb(CORE_THREAD_ARCH_INFO(core)->gs_cb); + free_gs_cb(CORE_THREAD_ARCH_INFO(core)->gs_bc); xfree(CORE_THREAD_ARCH_INFO(core)); CORE_THREAD_ARCH_INFO(core) = NULL; } @@ -389,6 +497,52 @@ static int set_vx_regs(pid_t pid, user_fpregs_struct_t *fpregs) return setregset(pid, NT_S390_VXRS_HIGH, "S390_VXRS_HIGH", &iov); } +/* + * Set guarded-storage control block + */ +static int set_gs_cb(pid_t pid, user_fpregs_struct_t *fpregs) +{ + struct iovec iov; + + if (fpregs->flags & USER_GS_CB) { + iov.iov_base = &fpregs->gs_cb; + iov.iov_len = sizeof(fpregs->gs_cb); + if (setregset(pid, NT_S390_GS_CB, "S390_GS_CB", &iov)) + return -1; + } + + if (!(fpregs->flags & USER_GS_BC)) + return 0; + iov.iov_base = &fpregs->gs_bc; + iov.iov_len = sizeof(fpregs->gs_bc); + return setregset(pid, NT_S390_GS_BC, "S390_GS_BC", &iov); +} + +/* + * Restore registers not present in sigreturn signal frame + */ +static int set_task_regs_nosigrt(pid_t pid, CoreEntry *core) +{ + user_fpregs_struct_t fpregs; + UserS390GsCbEntry *cgs_cb; + UserS390GsCbEntry *cgs_bc; + + memset(&fpregs, 0, sizeof(fpregs)); + /* Guarded-storage control block (optional) */ + cgs_cb = CORE_THREAD_ARCH_INFO(core)->gs_cb; + if (cgs_cb != NULL) { + fpregs.flags |= USER_GS_CB; + memcpy(&fpregs.gs_cb, cgs_cb->regs, sizeof(fpregs.gs_cb)); + } + /* Guarded-storage broadcast control block (optional) */ + cgs_bc = CORE_THREAD_ARCH_INFO(core)->gs_bc; + if (cgs_bc != NULL) { + fpregs.flags |= USER_GS_BC; + memcpy(&fpregs.gs_bc, cgs_bc->regs, sizeof(fpregs.gs_bc)); + } + return set_gs_cb(pid, &fpregs); +} + /* * Restore registers for pid from core */ @@ -410,34 +564,42 @@ static int set_task_regs(pid_t pid, CoreEntry *core) return -1; /* Vector registers (optional) */ cvxrs_low = CORE_THREAD_ARCH_INFO(core)->vxrs_low; - if (!cvxrs_low) - return 0; - cvxrs_high = CORE_THREAD_ARCH_INFO(core)->vxrs_high; - if (!cvxrs_high) - return -1; - fpregs.flags |= USER_FPREGS_VXRS; - memcpy(&fpregs.vxrs_low, cvxrs_low->regs, sizeof(fpregs.vxrs_low)); - memcpy(&fpregs.vxrs_high, cvxrs_high->regs, sizeof(fpregs.vxrs_high)); - - return set_vx_regs(pid, &fpregs); + if (cvxrs_low != NULL) { + cvxrs_high = CORE_THREAD_ARCH_INFO(core)->vxrs_high; + if (!cvxrs_high) + return -1; + fpregs.flags |= USER_FPREGS_VXRS; + memcpy(&fpregs.vxrs_low, cvxrs_low->regs, + sizeof(fpregs.vxrs_low)); + memcpy(&fpregs.vxrs_high, cvxrs_high->regs, + sizeof(fpregs.vxrs_high)); + if (set_vx_regs(pid, &fpregs) < 0) + return -1; + } + return set_task_regs_nosigrt(pid, core); } /* - * Restore vector and floating point registers for all threads + * Restore registers for all threads: + * - Floating point registers + * - Vector registers + * - Guarded-storage control block + * - Guarded-storage broadcast control block */ -int arch_set_thread_regs(struct pstree_item *item) +int arch_set_thread_regs(struct pstree_item *item, bool with_threads) { int i; for_each_pstree_item(item) { if (item->pid->state == TASK_DEAD || - item->pid->state == TASK_ZOMBIE || - item->pid->state == TASK_HELPER) + item->pid->state == TASK_ZOMBIE) continue; for (i = 0; i < item->nr_threads; i++) { if (item->threads[i].state == TASK_DEAD || item->threads[i].state == TASK_ZOMBIE) continue; + if (!with_threads && i > 0) + continue; if (set_task_regs(item->threads[i].real, item->core[i])) { pr_perror("Not set registers for task %d", @@ -448,3 +610,43 @@ int arch_set_thread_regs(struct pstree_item *item) } return 0; } + +static int open_core(int pid, CoreEntry **pcore) +{ + struct cr_img *img; + int ret; + + img = open_image(CR_FD_CORE, O_RSTR, pid); + if (!img) { + pr_err("Can't open core data for %d\n", pid); + return -1; + } + ret = pb_read_one(img, pcore, PB_CORE); + close_image(img); + + return ret <= 0 ? -1 : 0; +} + +/* + * Restore all registers not present in sigreturn signal frame + * + * - Guarded-storage control block + * - Guarded-storage broadcast control block + */ +int arch_set_thread_regs_nosigrt(struct pid *pid) +{ + CoreEntry *core; + + core = xmalloc(sizeof(*core)); + if (open_core(pid->ns[0].virt, &core) < 0) { + pr_perror("Cannot open core for virt pid %d", pid->ns[0].virt); + return -1; + } + + if (set_task_regs_nosigrt(pid->real, core) < 0) { + pr_perror("Set register for pid %d", pid->real); + return -1; + } + print_core_fp_regs("restore_fp_regs", core); + return 0; +} diff --git a/images/core-s390.proto b/images/core-s390.proto index 78d3e1447..3b587fb38 100644 --- a/images/core-s390.proto +++ b/images/core-s390.proto @@ -30,10 +30,16 @@ message user_s390_fpregs_entry { repeated uint64 fprs = 2; } +message user_s390_gs_cb_entry { + repeated uint64 regs = 1; +} + message thread_info_s390 { required uint64 clear_tid_addr = 1[(criu).hex = true]; required user_s390_regs_entry gpregs = 2[(criu).hex = true]; required user_s390_fpregs_entry fpregs = 3[(criu).hex = true]; optional user_s390_vxrs_low_entry vxrs_low = 4[(criu).hex = true]; optional user_s390_vxrs_high_entry vxrs_high = 5[(criu).hex = true]; + optional user_s390_gs_cb_entry gs_cb = 6[(criu).hex = true]; + optional user_s390_gs_cb_entry gs_bc = 7[(criu).hex = true]; } From 16474786cbcfb0de70216fc3c81ad04ea9ee451f Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Thu, 5 Oct 2017 15:50:41 +0200 Subject: [PATCH 1042/4375] s390: Add runtime-instrumentation support Dump and restore process with RI control block. Runtime instrumentation allows to collect information about program execution as CPU data. The RI control block is dumped and restored for all threads. Ptrace kernel interface is provided by: c122bc239b13 ("s390/ptrace: add runtime instrumention register get/set") Signed-off-by: Alice Frosi Reviewed-by: Michael Holzheu Signed-off-by: Andrei Vagin --- .../src/lib/include/uapi/asm/infect-types.h | 5 + compel/arch/s390/src/lib/infect.c | 100 ++++++++++++- criu/arch/s390/crtools.c | 132 +++++++++++++++++- images/core-s390.proto | 6 + 4 files changed, 240 insertions(+), 3 deletions(-) diff --git a/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h b/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h index 038c4a034..938699877 100644 --- a/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h @@ -42,6 +42,10 @@ struct prfpreg { #define USER_GS_CB 0x000000002 /* Guarded-storage broadcast control block */ #define USER_GS_BC 0x000000004 +/* Runtime-instrumentation control block */ +#define USER_RI_CB 0x000000008 +/* Runtime-instrumentation bit set */ +#define USER_RI_ON 0x000000010 typedef struct { uint32_t flags; @@ -50,6 +54,7 @@ typedef struct { vector128_t vxrs_high[16]; uint64_t gs_cb[4]; uint64_t gs_bc[4]; + uint64_t ri_cb[8]; } user_fpregs_struct_t; typedef struct { diff --git a/compel/arch/s390/src/lib/infect.c b/compel/arch/s390/src/lib/infect.c index 897b66fd9..abc1e6cd3 100644 --- a/compel/arch/s390/src/lib/infect.c +++ b/compel/arch/s390/src/lib/infect.c @@ -21,6 +21,7 @@ #define NT_S390_VXRS_HIGH 0x30a #define NT_S390_GS_CB 0x30b #define NT_S390_GS_BC 0x30c +#define NT_S390_RI_CB 0x30d /* * Print general purpose and access registers @@ -91,7 +92,23 @@ static void print_gs_bc(user_fpregs_struct_t *fpregs) } /* - * Print FP registers, VX registers, and guarded storage + * Print runtime-instrumentation control block + */ +static void print_ri_cb(user_fpregs_struct_t *fpregs) +{ + int i; + + if (!(fpregs->flags & USER_RI_CB)) { + pr_debug(" No RI_CB\n"); + return; + } + for (i = 0; i < 8; i++) + pr_debug(" ri_cb%02d %016lx\n", i, fpregs->ri_cb[i]); +} + +/* + * Print FP registers, VX registers, guarded-storage, and + * runtime-instrumentation */ static void print_user_fpregs_struct(const char *msg, int pid, user_fpregs_struct_t *fpregs) @@ -105,6 +122,7 @@ static void print_user_fpregs_struct(const char *msg, int pid, print_vxrs(fpregs); print_gs_cb(fpregs); print_gs_bc(fpregs); + print_ri_cb(fpregs); } int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, @@ -233,6 +251,63 @@ int get_gs_cb(pid_t pid, user_fpregs_struct_t *fpregs) return 0; } + +/* + * Get runtime-instrumentation control block + */ +int get_ri_cb(pid_t pid, user_fpregs_struct_t *fpregs) +{ + user_regs_struct_t regs; + struct iovec iov; + psw_t *psw; + + fpregs->flags &= ~(USER_RI_CB | USER_RI_ON); + iov.iov_base = &fpregs->ri_cb; + iov.iov_len = sizeof(fpregs->ri_cb); + if (ptrace(PTRACE_GETREGSET, pid, NT_S390_RI_CB, &iov) < 0) { + switch (errno) { + case EINVAL: + case ENODEV: + memset(&fpregs->ri_cb, 0, sizeof(fpregs->ri_cb)); + pr_debug("RI_CB not supported\n"); + return 0; + case ENODATA: + pr_debug("RI_CB not set\n"); + return 0; + default: + pr_perror("Couldn't get RI_CB\n"); + return -1; + } + } + fpregs->flags |= USER_RI_CB; + + /* Get PSW and check if runtime-instrumentation bit is enabled */ + iov.iov_base = ®s.prstatus; + iov.iov_len = sizeof(regs.prstatus); + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov) < 0) + return -1; + psw = ®s.prstatus.psw; + if (psw->mask & PSW_MASK_RI) + fpregs->flags |= USER_RI_ON; + + return 0; +} + +/* + * Disable runtime-instrumentation bit + */ +static int s390_disable_ri_bit(pid_t pid, user_regs_struct_t *regs) +{ + struct iovec iov; + psw_t *psw; + + iov.iov_base = ®s->prstatus; + iov.iov_len = sizeof(regs->prstatus); + psw = ®s->prstatus.psw; + psw->mask &= ~PSW_MASK_RI; + return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov); +} + /* * Prepare task registers for restart */ @@ -260,6 +335,18 @@ int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, pr_perror("Couldn't get guarded-storage"); return -1; } + if (get_ri_cb(pid, &fpregs)) { + pr_perror("Couldn't get runtime-instrumentation"); + return -1; + } + /* + * If the runtime-instrumentation bit is set, we have to disable it + * before we execute parasite code. Otherwise parasite operations + * would be recorded. + */ + if (fpregs.flags & USER_RI_ON) + s390_disable_ri_bit(pid, regs); + print_user_fpregs_struct("get_task_regs", pid, &fpregs); /* Check for system call restarting. */ if (regs->system_call) { @@ -391,10 +478,11 @@ void parasite_setup_regs(unsigned long new_ip, void *stack, } /* - * We don't support 24 and 31 bit mode - only 64 bit + * Check if we have all kernel and CRIU features to dump the task */ bool arch_can_dump_task(struct parasite_ctl *ctl) { + user_fpregs_struct_t fpregs; user_regs_struct_t regs; pid_t pid = ctl->rpid; char str[8]; @@ -403,6 +491,14 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) if (ptrace_get_regs(pid, ®s)) return false; psw = ®s.prstatus.psw; + /* Check if the kernel supports RI ptrace interface */ + if (psw->mask & PSW_MASK_RI) { + if (get_ri_cb(pid, &fpregs) < 0) { + pr_perror("Can't dump process with RI bit active"); + return -1; + } + } + /* We don't support 24 and 31 bit mode - only 64 bit */ if (psw->mask & PSW_MASK_EA) { if (psw->mask & PSW_MASK_BA) return true; diff --git a/criu/arch/s390/crtools.c b/criu/arch/s390/crtools.c index ddf268b90..238035b76 100644 --- a/criu/arch/s390/crtools.c +++ b/criu/arch/s390/crtools.c @@ -31,6 +31,7 @@ #define NT_S390_VXRS_HIGH 0x30a #define NT_S390_GS_CB 0x30b #define NT_S390_GS_BC 0x30c +#define NT_S390_RI_CB 0x30d /* * Print general purpose and access registers @@ -107,6 +108,22 @@ static void print_core_gs_bc(CoreEntry *core) pr_debug(" gs_bc%d %lx\n", i, gs_bc->regs[i]); } +/* + * Print runtime-instrumentation control block + */ +static void print_core_ri_cb(CoreEntry *core) +{ + UserS390RiEntry *ri_cb; + int i; + + ri_cb = CORE_THREAD_ARCH_INFO(core)->ri_cb; + if (!ri_cb) { + pr_debug(" No RI_CB\n"); + return; + } + for (i = 0; i < 8; i++) + pr_debug(" ri_cb%d %lx\n", i, ri_cb->regs[i]); +} /* * Print architecture registers */ @@ -124,6 +141,7 @@ static void print_core_fp_regs(const char *msg, CoreEntry *core) print_core_vx_regs(core); print_core_gs_cb(core); print_core_gs_bc(core); + print_core_ri_cb(core); } /* @@ -227,6 +245,42 @@ static void free_gs_cb(UserS390GsCbEntry *gs_cb) xfree(gs_cb); } } + +/* + * Allocate runtime-instrumentation control block + */ +static UserS390RiEntry *allocate_ri_cb(void) +{ + UserS390RiEntry *ri_cb; + + ri_cb = xmalloc(sizeof(*ri_cb)); + if (!ri_cb) + return NULL; + user_s390_ri_entry__init(ri_cb); + + ri_cb->ri_on = 0; + ri_cb->n_regs = 8; + ri_cb->regs = xzalloc(8 * sizeof(uint64_t)); + if (!ri_cb->regs) + goto fail_free_ri_cb; + return ri_cb; + +fail_free_ri_cb: + xfree(ri_cb); + return NULL; +} + +/* + * Free runtime-instrumentation control block + */ +static void free_ri_cb(UserS390RiEntry *ri_cb) +{ + if (ri_cb) { + xfree(ri_cb->regs); + xfree(ri_cb); + } +} + /* * Copy internal structures into Google Protocol Buffers */ @@ -238,6 +292,7 @@ int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f) UserS390RegsEntry *gpregs = NULL; UserS390GsCbEntry *gs_cb = NULL; UserS390GsCbEntry *gs_bc = NULL; + UserS390RiEntry *ri_cb = NULL; CoreEntry *core = arg; gpregs = CORE_THREAD_ARCH_INFO(core)->gpregs; @@ -272,6 +327,17 @@ int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f) memcpy(gs_bc->regs, &f->gs_bc, sizeof(f->gs_bc)); CORE_THREAD_ARCH_INFO(core)->gs_bc = gs_bc; } + /* Runtime-instrumentation control block */ + if (f->flags & USER_RI_CB) { + ri_cb = allocate_ri_cb(); + if (!ri_cb) + goto fail_free_ri_cb; + memcpy(ri_cb->regs, &f->ri_cb, sizeof(f->ri_cb)); + CORE_THREAD_ARCH_INFO(core)->ri_cb = ri_cb; + /* We need to remember that the RI bit was on */ + if (f->flags & USER_RI_ON) + ri_cb->ri_on = 1; + } /* General purpose registers */ memcpy(gpregs->gprs, u->prstatus.gprs, sizeof(u->prstatus.gprs)); gpregs->psw_mask = u->prstatus.psw.mask; @@ -284,6 +350,8 @@ int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f) fpregs->fpc = f->prfpreg.fpc; memcpy(fpregs->fprs, f->prfpreg.fprs, sizeof(f->prfpreg.fprs)); return 0; +fail_free_ri_cb: + free_ri_cb(ri_cb); fail_free_gs_cb: free_gs_cb(gs_cb); fail_free_gs_bc: @@ -450,6 +518,7 @@ void arch_free_thread_info(CoreEntry *core) free_vxrs_high_regs(CORE_THREAD_ARCH_INFO(core)->vxrs_high); free_gs_cb(CORE_THREAD_ARCH_INFO(core)->gs_cb); free_gs_cb(CORE_THREAD_ARCH_INFO(core)->gs_bc); + free_ri_cb(CORE_THREAD_ARCH_INFO(core)->ri_cb); xfree(CORE_THREAD_ARCH_INFO(core)); CORE_THREAD_ARCH_INFO(core) = NULL; } @@ -518,6 +587,49 @@ static int set_gs_cb(pid_t pid, user_fpregs_struct_t *fpregs) return setregset(pid, NT_S390_GS_BC, "S390_GS_BC", &iov); } +/* + * Set runtime-instrumentation control block + */ +static int set_ri_cb(pid_t pid, user_fpregs_struct_t *fpregs) +{ + struct iovec iov; + + if (!(fpregs->flags & USER_RI_CB)) + return 0; + + iov.iov_base = &fpregs->ri_cb; + iov.iov_len = sizeof(fpregs->ri_cb); + return setregset(pid, NT_S390_RI_CB, "S390_RI_CB", &iov); +} + +/* + * Set runtime-instrumentation bit + * + * The CPU collects information when the RI bit of the PSW is set. + * The RI control block is not part of the signal frame. Therefore during + * sigreturn it is not set. If the RI control block is present, the CPU + * writes into undefined storage. Hence, we have disabled the RI bit in + * the sigreturn PSW and set this bit after sigreturn by modifying the PSW + * of the task. + */ +static int set_ri_bit(pid_t pid) +{ + user_regs_struct_t regs; + struct iovec iov; + psw_t *psw; + + iov.iov_base = ®s.prstatus; + iov.iov_len = sizeof(regs.prstatus); + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov) < 0) { + pr_perror("Fail to activate RI bit"); + return -1; + } + psw = ®s.prstatus.psw; + psw->mask |= PSW_MASK_RI; + + return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov); +} + /* * Restore registers not present in sigreturn signal frame */ @@ -526,6 +638,8 @@ static int set_task_regs_nosigrt(pid_t pid, CoreEntry *core) user_fpregs_struct_t fpregs; UserS390GsCbEntry *cgs_cb; UserS390GsCbEntry *cgs_bc; + UserS390RiEntry *cri_cb; + int ret = 0; memset(&fpregs, 0, sizeof(fpregs)); /* Guarded-storage control block (optional) */ @@ -540,7 +654,21 @@ static int set_task_regs_nosigrt(pid_t pid, CoreEntry *core) fpregs.flags |= USER_GS_BC; memcpy(&fpregs.gs_bc, cgs_bc->regs, sizeof(fpregs.gs_bc)); } - return set_gs_cb(pid, &fpregs); + if (set_gs_cb(pid, &fpregs) < 0) + return -1; + /* Runtime-instrumentation control block (optional) */ + cri_cb = CORE_THREAD_ARCH_INFO(core)->ri_cb; + if (cri_cb != NULL) { + fpregs.flags |= USER_RI_CB; + memcpy(&fpregs.ri_cb, cri_cb->regs, sizeof(fpregs.ri_cb)); + if (set_ri_cb(pid, &fpregs) < 0) + return -1; + if (cri_cb->ri_on) { + fpregs.flags |= USER_RI_ON; + ret = set_ri_bit(pid); + } + } + return ret; } /* @@ -585,6 +713,7 @@ static int set_task_regs(pid_t pid, CoreEntry *core) * - Vector registers * - Guarded-storage control block * - Guarded-storage broadcast control block + * - Runtime-instrumentation control block */ int arch_set_thread_regs(struct pstree_item *item, bool with_threads) { @@ -632,6 +761,7 @@ static int open_core(int pid, CoreEntry **pcore) * * - Guarded-storage control block * - Guarded-storage broadcast control block + * - Runtime-instrumentation control block */ int arch_set_thread_regs_nosigrt(struct pid *pid) { diff --git a/images/core-s390.proto b/images/core-s390.proto index 3b587fb38..497c73b20 100644 --- a/images/core-s390.proto +++ b/images/core-s390.proto @@ -34,6 +34,11 @@ message user_s390_gs_cb_entry { repeated uint64 regs = 1; } +message user_s390_ri_entry { + required uint32 ri_on = 1; + repeated uint64 regs = 2; +} + message thread_info_s390 { required uint64 clear_tid_addr = 1[(criu).hex = true]; required user_s390_regs_entry gpregs = 2[(criu).hex = true]; @@ -42,4 +47,5 @@ message thread_info_s390 { optional user_s390_vxrs_high_entry vxrs_high = 5[(criu).hex = true]; optional user_s390_gs_cb_entry gs_cb = 6[(criu).hex = true]; optional user_s390_gs_cb_entry gs_bc = 7[(criu).hex = true]; + optional user_s390_ri_entry ri_cb = 8[(criu).hex = true]; } From 581f731ba61420ee9b66d8ad1b4f65f35c9b2bc7 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Thu, 5 Oct 2017 15:50:42 +0200 Subject: [PATCH 1043/4375] s390: Add test case for GS - Add new test "s390x_gs_threads" for GS with broadcast command for the s390_guarded_storage() system call. - Add GS control blocks in test s390x_regs_check.c The original test case for GS has been provided by Martin Schwidefsky Signed-off-by: Alice Frosi Reviewed-by: Michael Holzheu Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 4 +- test/zdtm/static/s390x_gs_threads.c | 187 ++++++++++++++++++++++++++++ test/zdtm/static/s390x_regs_check.c | 47 +++++++ 3 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 test/zdtm/static/s390x_gs_threads.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index a35b81443..3a20f0f1a 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -187,7 +187,8 @@ endif endif ifeq ($(SRCARCH),s390) - TST_NOFILE += s390x_regs_check + TST_NOFILE += s390x_regs_check \ + s390x_gs_threads endif TST_FILE = \ @@ -471,6 +472,7 @@ pty-console: CFLAGS += -D ZDTM_DEV_CONSOLE shm-unaligned: CFLAGS += -DZDTM_SHM_UNALIGNED s390x_regs_check: LDFLAGS += -pthread +s390x_gs_threads: LDFLAGS += -pthread thread_different_uid_gid: LDLIBS += -pthread -lcap diff --git a/test/zdtm/static/s390x_gs_threads.c b/test/zdtm/static/s390x_gs_threads.c new file mode 100644 index 000000000..486b32087 --- /dev/null +++ b/test/zdtm/static/s390x_gs_threads.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lock.h" +#include "zdtmtst.h" + +#define NR_THREADS 4 +#define GS_ENABLE 0 +#define GS_SET_BC_CB 2 +#define GS_BROADCAST 4 + +#ifndef __NR_guarded_storage +#define __NR_guarded_storage 378 +#endif + +const char *test_doc = "Check the guarded storage broadcast"; +/* Original test provided by Martin Schwidefsky */ +const char *test_author = "Alice Frosi "; + +static unsigned long main_thread_tid; + +/* + * This test case executes the following procedure: + * + * 1) The parent thread creates NR_THREADS child threads + * + * 2) For each thread (including the parent thread): + * - Enable guarded-storage + * - Set the guarded-storage broadcast control block and + * specify gs_handler as Guarded-Storage-Event Parameter-List + * address + * + * 3) Dump and restore + * + * 4) Guarded-storage broadcast event + * - Child threads: Wait until main thread does GS broadcast + * - Parent thread: Trigger GS broadcast + * + * 5) Verify that all GS works as expected and all threads have been + * executed the gs_handler + */ + +struct gs_cb { + __u64 reserved; + __u64 gsd; + __u64 gssm; + __u64 gs_epl_a; +}; + +static futex_t futex; +static futex_t futex2; + +/* + * Load guarded-storage + */ +void load_guarded(unsigned long *mem); +asm( + ".global load_guarded\n" + "load_guarded:\n" + " .insn rxy,0xe3000000004c,%r2,0(%r2)\n" + " br %r14\n" + " .size load_guarded,.-load_guarded\n"); + +/* + * Inline assembly to deal with interrupted context to the call of + * the GS handler. Load guarded can be turned into a branch to this + * function. + */ +void gs_handler_asm(void); +asm( + ".globl gs_handler_asm\n" + "gs_handler_asm:\n" + " lgr %r14,%r15\n" + " aghi %r15,-320\n" + " stmg %r0,%r14,192(%r15)\n" + " stg %r14,312(%r14)\n" + " la %r2,160(%r15)\n" + " .insn rxy,0xe30000000049,0,160(%r15)\n" + " lg %r14,24(%r2)\n" + " lg %r14,40(%r14)\n" + " la %r14,6(%r14)\n" + " stg %r14,304(%r15)\n" + " brasl %r14,gs_handler\n" + " lmg %r0,%r15,192(%r15)\n" + " br %r14\n" + " .size gs_handler_asm,.-gs_handler_asm\n"); + +/* + * GS handler called when GS event occurs + */ +void gs_handler(struct gs_cb *this_cb) +{ + unsigned long tid = syscall(SYS_gettid); + test_msg("gs_handler for thread %016lx\n", tid); + futex_dec_and_wake(&futex2); +} + +/* + * Entry point for threads + */ +static void *thread_run(void *param) +{ + unsigned long test = 0x1234000000; + unsigned long *gs_epl; + struct gs_cb *gs_cb; + + /* Enable guarded-storage */ + if (syscall(__NR_guarded_storage, GS_ENABLE) != 0) { + fail("Unable to enable guarded storage"); + exit(1); + } + gs_epl = malloc(sizeof(unsigned long) * 6); + gs_cb = malloc(sizeof(*gs_cb)); + if (gs_epl == NULL || gs_cb == NULL) { + fail("Error allocating memory\n"); + exit(1); + } + gs_cb->gsd = 0x1234000000UL | 26; + gs_cb->gssm = -1UL; + gs_cb->gs_epl_a = (unsigned long) gs_epl; + gs_epl[1] = (unsigned long) gs_handler_asm; + /* Set the GS broadcast control block */ + syscall(__NR_guarded_storage, GS_SET_BC_CB, gs_cb); + futex_dec_and_wake(&futex); + /* Wait for all threads to set the GS broadcast control block */ + futex_wait_until(&futex, 0); + test_msg("Thread %016lx staring loop\n", syscall(SYS_gettid)); + /* + * Designate a guarded-storage section until the main task + * performs the GS_BROADCAST action and the following load_guarded + * will provoke the switch to the gs handler + */ + while (1) + load_guarded(&test); +} + +int main(int argc, char *argv[]) +{ + pthread_t tids[NR_THREADS]; + int i; + + main_thread_tid = syscall(SYS_gettid); + test_init(argc, argv); + /* Enable guarded-storage */ + if (syscall(__NR_guarded_storage, GS_ENABLE) != 0) { + if (errno == ENOSYS) { + test_daemon(); + test_waitsig(); + skip("No guarded storage support"); + pass(); + return 0; + } + fail("Unable to enable guarded storage"); + return 1; + } + + futex_set(&futex, NR_THREADS); + + for (i = 0; i < NR_THREADS; i++) + pthread_create(tids + i, NULL, thread_run, NULL); + + test_msg("Waiting for thread startup\n"); + /* Wait for all threads to set the GS broadcast control block */ + futex_wait_until(&futex, 0); + + test_daemon(); + test_waitsig(); + + test_msg("Doing broadcast\n"); + futex_set(&futex2, NR_THREADS); + /* + * Triggers a GS event and force all the threads to execute + * the gs handler + */ + syscall(__NR_guarded_storage, GS_BROADCAST); + + test_msg("Waiting for thread completion\n"); + futex_wait_until(&futex2, 0); + pass(); + return 0; +} diff --git a/test/zdtm/static/s390x_regs_check.c b/test/zdtm/static/s390x_regs_check.c index b8f9d862c..ab9d7d139 100644 --- a/test/zdtm/static/s390x_regs_check.c +++ b/test/zdtm/static/s390x_regs_check.c @@ -182,6 +182,50 @@ struct reg_set reg_set_vxrs_high = { .optional = true, }; +/* + * s390 guarded-storage registers + */ +#define NT_S390_GS_CB 0x30b +#define NT_S390_GS_BC 0x30c + +struct gs_cb { + uint64_t regs[4]; +}; + +struct gs_cb gs_cb_data = { + .regs = { + 0x0000000000000000, + 0x000000123400001a, + 0x5555555555555555, + 0x000000014b58a010, + } +}; + +struct reg_set reg_set_gs_cb = { + .name = "GS_CB", + .nr = NT_S390_GS_CB, + .data = &gs_cb_data, + .len = sizeof(gs_cb_data), + .optional = true, +}; + +struct gs_cb gs_bc_data = { + .regs = { + 0x0000000000000000, + 0x000000123400001a, + 0xffffffffffffffff, + 0x0000000aaaaaaaaa, + } +}; + +struct reg_set reg_set_gs_bc = { + .name = "GS_BC_CB", + .nr = NT_S390_GS_BC, + .data = &gs_bc_data, + .len = sizeof(gs_bc_data), + .optional = true, +}; + /* * Vector with all regsets */ @@ -189,6 +233,8 @@ struct reg_set *reg_set_vec[] = { ®_set_prfpreg, ®_set_vxrs_low, ®_set_vxrs_high, + ®_set_gs_cb, + ®_set_gs_bc, NULL, }; @@ -246,6 +292,7 @@ static int set_regset(pid_t pid, struct reg_set *reg_set) } if (reg_set->optional) { switch (errno) { + case EOPNOTSUPP: case ENODEV: test_msg(" REGSET: %12s -> not supported by machine\n", reg_set->name); From 865f099d702a94a8e429359869f38a938e498f15 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Thu, 5 Oct 2017 15:50:43 +0200 Subject: [PATCH 1044/4375] s390: Add test case for RI - Add new test "s390x_runtime_instr" to check if the RI control block is correctly restored when the RI is active. - Add RI control block in test s390x_regs_check.c The original test case for RI has been provided by Martin Schwidefsky Signed-off-by: Alice Frosi Reviewed-by: Michael Holzheu Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 3 +- test/zdtm/static/s390x_regs_check.c | 31 ++++ test/zdtm/static/s390x_runtime_instr.c | 212 +++++++++++++++++++++++++ 3 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 test/zdtm/static/s390x_runtime_instr.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 3a20f0f1a..83ac95ff4 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -188,7 +188,8 @@ endif ifeq ($(SRCARCH),s390) TST_NOFILE += s390x_regs_check \ - s390x_gs_threads + s390x_gs_threads \ + s390x_runtime_instr endif TST_FILE = \ diff --git a/test/zdtm/static/s390x_regs_check.c b/test/zdtm/static/s390x_regs_check.c index ab9d7d139..9aaf41951 100644 --- a/test/zdtm/static/s390x_regs_check.c +++ b/test/zdtm/static/s390x_regs_check.c @@ -226,6 +226,36 @@ struct reg_set reg_set_gs_bc = { .optional = true, }; +/* + * s390 runtime-instrumentation control block + */ +#define NT_S390_RI_CB 0x30d + +struct ri_cb { + uint64_t regs[8]; +}; + +struct ri_cb ri_cb_data = { + .regs = { + 0x000002aa13aae000, + 0x000002aa13aad000, + 0x000002aa13aadfff, + 0xe0a1000400000000, + 0x0000000000000000, + 0x0000000000004e20, + 0x0000000000003479, + 0x0000000000000000, + } +}; + +struct reg_set reg_set_ri_cb = { + .name = "RI_CB", + .nr = NT_S390_RI_CB, + .data = &ri_cb_data, + .len = sizeof(ri_cb_data), + .optional = true, +}; + /* * Vector with all regsets */ @@ -235,6 +265,7 @@ struct reg_set *reg_set_vec[] = { ®_set_vxrs_high, ®_set_gs_cb, ®_set_gs_bc, + ®_set_ri_cb, NULL, }; diff --git a/test/zdtm/static/s390x_runtime_instr.c b/test/zdtm/static/s390x_runtime_instr.c new file mode 100644 index 000000000..6be32c3c1 --- /dev/null +++ b/test/zdtm/static/s390x_runtime_instr.c @@ -0,0 +1,212 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +#ifndef __NR_s390_runtime_instr +#define __NR_s390_runtime_instr 342 +#endif +#define NT_S390_RI_CB 0x30d + +#define BUF_SIZE (1024*1024) + +const char *test_doc = "Check runtime-instrumentation"; +/* Original test provided by Martin Schwidefsky */ +const char *test_author = "Alice Frosi "; + +struct runtime_instr_cb { + unsigned long rca; + unsigned long roa; + unsigned long rla; + + unsigned int v : 1; + unsigned int s : 1; + unsigned int k : 1; + unsigned int h : 1; + unsigned int a : 1; + unsigned int reserved1 : 3; + unsigned int ps : 1; + unsigned int qs : 1; + unsigned int pc : 1; + unsigned int qc : 1; + unsigned int reserved2 : 1; + unsigned int g : 1; + unsigned int u : 1; + unsigned int l : 1; + unsigned int key : 4; + unsigned int reserved3 : 8; + unsigned int t : 1; + unsigned int rgs : 3; + + unsigned int m : 4; + unsigned int n : 1; + unsigned int mae : 1; + unsigned int reserved4 : 2; + unsigned int c : 1; + unsigned int r : 1; + unsigned int b : 1; + unsigned int j : 1; + unsigned int e : 1; + unsigned int x : 1; + unsigned int reserved5 : 2; + unsigned int bpxn : 1; + unsigned int bpxt : 1; + unsigned int bpti : 1; + unsigned int bpni : 1; + unsigned int reserved6 : 2; + + unsigned int d : 1; + unsigned int f : 1; + unsigned int ic : 4; + unsigned int dc : 4; + + unsigned long reserved7; + unsigned long sf; + unsigned long rsic; + unsigned long reserved8; +}; + +/* + * Return PSW mask + */ +static inline unsigned long extract_psw(void) +{ + unsigned int reg1, reg2; + + asm volatile("epsw %0,%1" : "=d" (reg1), "=a" (reg2)); + return (((unsigned long) reg1) << 32) | ((unsigned long) reg2); +} + +/* + * Enable runtime-instrumentation + */ +static inline void rion(void) +{ + asm volatile (".word 0xaa01, 0x0000"); +} + +/* + * Disable runtime-instrumentation + */ +static inline void rioff(void) +{ + asm volatile (".word 0xaa03, 0x0000"); +} + +/* + * Modify the current runtime-instrumentation control block + */ +static inline void mric(struct runtime_instr_cb *cb) +{ + asm volatile(".insn rsy,0xeb0000000062,0,0,%0" : : "Q" (*cb)); +} + +/* + * Store the current runtime-instrumentation control block + */ +static inline void stric(struct runtime_instr_cb *cb) +{ + asm volatile(".insn rsy,0xeb0000000061,0,0,%0" : "=Q" (*cb) : : "cc"); +} + +/* + * Ensure that runtime-intstrumentation is still working after C/R + */ +int main(int argc, char **argv) +{ + struct runtime_instr_cb ricb, ricb_check; + unsigned long *ricb_check_ptr = (unsigned long *) &ricb_check; + unsigned long *ricb_ptr = (unsigned long *) &ricb; + unsigned long psw_mask; + void *buf; + int i; + + test_init(argc, argv); + buf = malloc(BUF_SIZE); + memset(buf, 0, BUF_SIZE); + memset(&ricb, 0, sizeof(ricb)); + /* Initialize the default RI control block in the kernel */ + if (syscall(__NR_s390_runtime_instr, 1, NULL) < 0) { + if (errno == EOPNOTSUPP) { + test_daemon(); + test_waitsig(); + skip("RI not supported"); + pass(); + return 0; + } + fail("Fail with error %d", errno); + return -1; + } + /* Set buffer for RI */ + ricb.rca = ricb.roa = (unsigned long) buf; + ricb.rla = (unsigned long) buf + BUF_SIZE; + mric(&ricb); + /* Enable RI - afterwards the PSW will have RI bit set */ + rion(); + psw_mask = extract_psw(); + /* Verify that the RI bit is set in the PSW */ + if (!(psw_mask & PSW_MASK_RI)) { + fail("Failed to enable RI"); + return -1; + } + /* Collect RI records until we hit buffer-full condition */ + while (ricb.rca < ricb.rla + 1) { + for (i = 0; i < 10000; i++) + asm volatile("" : : : "memory"); + rioff(); + stric(&ricb); + rion(); + } + /* Disable RI */ + rioff(); + /* Save the current RI control block */ + stric(&ricb); + ricb_check = ricb; + /* Re-enable RI for checkpoint */ + rion(); + + /* Do C/R now */ + test_daemon(); + test_waitsig(); + + /* Verify that the RI bit is set in the PSW */ + psw_mask = extract_psw(); + if (!(psw_mask & PSW_MASK_RI)) { + fail("RI bit in PSW not set"); + return -1; + } + /* + * Verify that the RI block has been restored correctly + * and the buffer is unchanged + */ + rioff(); + stric(&ricb); + for (i = 0; i < 8; i++) { + if (ricb_ptr[i] == ricb_check_ptr[i]) + continue; + /* Skip sf field because its value may change */ + if (i == 6) + continue; + fail("%d:Got %016lx expected %016lx", + i, ricb_ptr[i], ricb_check_ptr[i]); + return -1; + } + + pass(); + return 0; +} From c821f24d5bfeb66e286b05f8163a24fd5e38e326 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 7 Oct 2017 00:31:54 +0300 Subject: [PATCH 1045/4375] libsoccr: ignore data in a sent queue, if a connect is closed If a connection was reseted, it can have some data in a sent queue, a use can't read this data, so we can ignore them too. https://jira.sw.ru/browse/PSBM-67026 Signed-off-by: Andrei Vagin --- soccr/soccr.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/soccr/soccr.c b/soccr/soccr.c index 1a1aaa35d..394095f00 100644 --- a/soccr/soccr.c +++ b/soccr/soccr.c @@ -209,6 +209,18 @@ static int refresh_sk(struct libsoccr_sk *sk, data->unsq_len = size; + if (data->state == TCP_CLOSE) { + /* A connection could be reseted. In thise case a sent queue + * may contain some data. A user can't read this data, so let's + * ignore them. Otherwise we will need to add a logic whether + * the send queue contains a fin packet or not and decide whether + * a fin or reset packet has to be sent to restore a state + */ + + data->unsq_len = 0; + data->outq_len = 0; + } + /* Don't account the fin packet. It doesn't countain real data. */ if ((1 << data->state) & (SNDQ_FIRST_FIN | SNDQ_SECOND_FIN)) { if (data->outq_len) From 040c2487ea5de2646d7b61f38ea69dd743d9fd92 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 7 Oct 2017 00:31:55 +0300 Subject: [PATCH 1046/4375] zdtm: check a reseted tcp connect This test create a closed socket with a non-empty sent queue. Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/socket-tcp-reseted.c | 90 ++++++++++++++++++++++++ test/zdtm/static/socket-tcp-reseted.desc | 10 +++ test/zdtm/static/socket-tcp-reseted.hook | 1 + 4 files changed, 102 insertions(+) create mode 100644 test/zdtm/static/socket-tcp-reseted.c create mode 100644 test/zdtm/static/socket-tcp-reseted.desc create mode 120000 test/zdtm/static/socket-tcp-reseted.hook diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 83ac95ff4..da9abdfcc 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -63,6 +63,7 @@ TST_NOFILE := \ sockets_spair \ socket_queues \ socket-tcp \ + socket-tcp-reseted \ socket-tcp6 \ socket-tcp-local \ socket-tcp-nfconntrack \ diff --git a/test/zdtm/static/socket-tcp-reseted.c b/test/zdtm/static/socket-tcp-reseted.c new file mode 100644 index 000000000..f5d1bfb92 --- /dev/null +++ b/test/zdtm/static/socket-tcp-reseted.c @@ -0,0 +1,90 @@ + +#include "zdtmtst.h" +#include +#include +#include /* for sockaddr_in and inet_ntoa() */ +#include +#include + + +#ifdef ZDTM_IPV6 +#define ZDTM_FAMILY AF_INET6 +#else +#define ZDTM_FAMILY AF_INET +#endif + +const char *test_doc = "Check, that a reseted TCP connection can be restored\n"; +const char *test_author = "Andrey Vagin +#include +#include +#include +#include +#include +#include +#include +#include + +static int port = 8880; + +int main(int argc, char **argv) +{ + int fd, fd_s, clt; + char cmd[4096], buf[10]; + + test_init(argc, argv); + + if ((fd_s = tcp_init_server(ZDTM_FAMILY, &port)) < 0) { + pr_err("initializing server failed\n"); + return 1; + } + + + clt = tcp_init_client(ZDTM_FAMILY, "localhost", port); + if (clt < 0) { + pr_perror("Unable to create a client socket"); + return 1; + } + + /* + * parent is server of TCP connection + */ + fd = tcp_accept_server(fd_s); + if (fd < 0) { + pr_err("can't accept client connection\n"); + return 1; + } + if (write(clt, "asd", 3) != 3) { + pr_perror("Unable to write into a socket"); + return 1; + } + snprintf(cmd, sizeof(cmd), "iptables -w -t filter --protocol tcp -A INPUT --dport %d -j REJECT --reject-with tcp-reset", port); + if (system(cmd)) + return 1; + + if (write(fd, "asdas", 5) == -1) { + pr_perror("Unable to write into a socket"); + return 1; + } + + snprintf(cmd, sizeof(cmd), "iptables -w -t filter --protocol tcp -D INPUT --dport %d -j REJECT --reject-with tcp-reset", port); + if (system(cmd)) + return 1; + + test_daemon(); + test_waitsig(); + + if (read(fd, buf, sizeof(buf)) != 3) { + fail("Unable to read data from a socket"); + return 1; + } + + if (write(fd, buf, 3) != -1) { + fail("Can write into a closed socket"); + return 1; + } + + pass(); + return 0; +} diff --git a/test/zdtm/static/socket-tcp-reseted.desc b/test/zdtm/static/socket-tcp-reseted.desc new file mode 100644 index 000000000..c026d9d61 --- /dev/null +++ b/test/zdtm/static/socket-tcp-reseted.desc @@ -0,0 +1,10 @@ +{ 'deps': [ '/bin/sh', + '/sbin/iptables', + '/usr/lib64/xtables/libxt_tcp.so|/lib/xtables/libxt_tcp.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_tcp.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so', + '/usr/lib64/xtables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so', + '/usr/lib64/xtables/libipt_REJECT.so|/lib/xtables/libipt_REJECT.so|/usr/lib/powerpc64le-linux-gnu/xtables/libipt_REJECT.so|/usr/lib/x86_64-linux-gnu/xtables/libipt_REJECT.so', + ], + 'opts': '--tcp-established', + 'flags': 'suid nouser samens', + 'feature' : 'tcp_half_closed' +} diff --git a/test/zdtm/static/socket-tcp-reseted.hook b/test/zdtm/static/socket-tcp-reseted.hook new file mode 120000 index 000000000..73d7da1c4 --- /dev/null +++ b/test/zdtm/static/socket-tcp-reseted.hook @@ -0,0 +1 @@ +socket-tcp-fin-wait1.hook \ No newline at end of file From ac21ffe215fce4222e01930acbc84f271cecd6ce Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 4 Oct 2017 09:43:04 +0300 Subject: [PATCH 1047/4375] travis: set umask before a first criu run so that .gcda (coverage data) files are created with read-write permissions for all, otherwise uns tests will not be able to modify these files and code coverage data will not be collected for them. Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 5c1349f0a..55adb4e96 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -56,12 +56,14 @@ time make CC="$CC" -j4 -C test/zdtm [ -f "$CCACHE_LOGFILE" ] && cat $CCACHE_LOGFILE +# umask has to be called before a first criu run, so that .gcda (coverage data) +# files are created with read-write permissions for all. +umask 0000 ./criu/criu check ./criu/criu check --all || echo $? ./criu/criu cpuinfo dump ./criu/criu cpuinfo check -umask 0000 export SKIP_PREP=1 # The 3.19 kernel (from Ubuntu 14.04) has a bug. When /proc/PID/pagemap # is read for a few VMAs in one read call, incorrect data is returned. From 44dc01597a0712856c93aa765293f5079be9b9a0 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 13 Oct 2017 11:22:08 +0300 Subject: [PATCH 1048/4375] zdtm: don't use getpwnam and getgrnam For us it doesn't matter what names of users and groups are used, we want to be sure that we restore right uid-s and gid-s. If we use these functions, we can't run tests in namespaces and they use an external unix socket, what can be a problem too. sk unix: Runaway socket: ino 0x1df1ae4 peer_ino 0x1df1ae3 family 1 type 1 state 1 name /run/dbus/system_bus_socket Error (criu/sk-unix.c:712): sk unix: External socket is used. Consider using --ext-unix-sk option. Cc: Vitaly Ostrosablin Cc: Cyrill Gorcunov Signed-off-by: Andrei Vagin Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/thread_different_uid_gid.c | 32 +++---------------- .../zdtm/static/thread_different_uid_gid.desc | 2 +- 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/test/zdtm/static/thread_different_uid_gid.c b/test/zdtm/static/thread_different_uid_gid.c index 1951668fb..2a5e4bdd8 100644 --- a/test/zdtm/static/thread_different_uid_gid.c +++ b/test/zdtm/static/thread_different_uid_gid.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -81,8 +80,6 @@ int main(int argc, char **argv) int ret; cap_t newcaps; - struct group *group; - struct passwd *user; pthread_t diff_cred_thread; test_init(argc, argv); int maingroup; @@ -115,31 +112,10 @@ int main(int argc, char **argv) } test_msg("Main thread runs as UID: %d; GID: %d\n", getuid(), getgid()); - group = getgrnam("nogroup"); - group = (group) ? group : getgrnam("nobody"); - if (!group) { - pr_perror("Failed to get nogroup/nobody GID\n"); - exit(1); - } - user = getpwnam("nobody"); - if (!user) { - pr_perror("Failed to get nobody UID\n"); - exit(1); - } - gid = group->gr_gid; - uid = user->pw_uid; - group = getgrnam("mail"); - if (!group) { - pr_perror("Failed to get mail GID\n"); - exit(1); - } - user = getpwnam("mail"); - if (!user) { - pr_perror("Failed to get mail UID\n"); - exit(1); - } - maingroup = group->gr_gid; - mainuser = user->pw_uid; + gid = 99; + uid = 99; + maingroup = 8; + mainuser = 12; test_msg("Creating thread with different UID/GID\n"); ret = pthread_create(&diff_cred_thread, NULL, &chg_uid_gid, NULL); diff --git a/test/zdtm/static/thread_different_uid_gid.desc b/test/zdtm/static/thread_different_uid_gid.desc index fa2c82d08..2eac7e654 100644 --- a/test/zdtm/static/thread_different_uid_gid.desc +++ b/test/zdtm/static/thread_different_uid_gid.desc @@ -1 +1 @@ -{'flavor': 'h', 'flags': 'suid'} +{'flags': 'suid'} From aa9b6a5d1a7dc5ef3b40c5024aded964d09a91cb Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 12 Oct 2017 21:44:54 +0300 Subject: [PATCH 1049/4375] fault_inject: use SIGKILL instead of BUG() to kill itself If a process calls BUG(), it genereates a core file and we get a false warning from abrtd. Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 2 +- criu/cr-restore.c | 2 +- criu/files-reg.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index b874be014..8faa00b45 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1286,7 +1286,7 @@ static int dump_one_task(struct pstree_item *item) if (fault_injected(FI_DUMP_EARLY)) { pr_info("fault: CRIU sudden detach\n"); - BUG(); + kill(getpid(), SIGKILL); } if (root_ns_mask & CLONE_NEWPID && root_item == item) { diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 7d3c06e4b..442844ee9 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1615,7 +1615,7 @@ static int restore_task_with_children(void *_arg) if (fault_injected(FI_RESTORE_ROOT_ONLY)) { pr_info("fault: Restore root task failure!\n"); - BUG(); + kill(getpid(), SIGKILL); } timing_start(TIME_FORK); diff --git a/criu/files-reg.c b/criu/files-reg.c index 88a07d782..d5a97ce60 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1609,7 +1609,7 @@ int open_path(struct file_desc *d, if (rfi->remap) { if (fault_injected(FI_RESTORE_OPEN_LINK_REMAP)) { pr_info("fault: Open link-remap failure!\n"); - BUG(); + kill(getpid(), SIGKILL); } mutex_lock(remap_open_lock); From 105765830b0ac0a014727b17dc10488dd0b1c9f8 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 12 Oct 2017 21:33:05 +0300 Subject: [PATCH 1050/4375] zdtm: skip vsyscall vmas for x32 tests It is known issue that a vsyscall vmas are not unmapped from x32 processes. Signed-off-by: Andrei Vagin --- test/zdtm.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index 28f00aeb8..c859ad97c 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1153,6 +1153,11 @@ def check_visible_state(test, state, opts): old_maps = state[1][pid] new_maps = new[1][pid] + if os.getenv("COMPAT_TEST"): + # the vsyscall vma isn't unmapped from x32 processes + vsyscall = "ffffffffff600000-ffffffffff601000 ['r-xp']" + if vsyscall in new_maps and vsyscall not in old_maps: + new_maps.remove(vsyscall) if old_maps != new_maps: print "%s: Old maps lost: %s" % (pid, old_maps - new_maps) print "%s: New maps appeared: %s" % (pid, new_maps - old_maps) From bd5611530308b7a26c8a7c1b500454673adf831b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 14 Oct 2017 00:26:31 +0300 Subject: [PATCH 1051/4375] test: thread_different_uid_gid -- Style nitpicking CC: Vitaly Ostrosablin Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/thread_different_uid_gid.c | 41 +++++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/test/zdtm/static/thread_different_uid_gid.c b/test/zdtm/static/thread_different_uid_gid.c index 2a5e4bdd8..7964b6893 100644 --- a/test/zdtm/static/thread_different_uid_gid.c +++ b/test/zdtm/static/thread_different_uid_gid.c @@ -30,43 +30,48 @@ int done = 0; void *chg_uid_gid(void *arg) { - int ret; - cap_t mycaps; cap_t newcaps; + cap_t mycaps; + int ret; + test_msg("Aux thread runs as UID: %d; GID: %d\n", getuid(), getgid()); + newcaps = cap_from_text("cap_setgid,cap_setuid=+eip"); - if (!newcaps) - { + if (!newcaps) { pr_perror("Failed to get capability struct\n"); exit(1); } + ret = cap_set_proc(newcaps); if (ret) { pr_perror("Failed to set capabilities for the process\n"); exit(1); } + mycaps = cap_get_proc(); if (!mycaps) { pr_perror("Failed to get child thread capabilities\n"); exit_group(2); } + test_msg("Child capabilities: %s\n", cap_to_text(mycaps, NULL)); test_msg("Changing UID/GID in child thread to %d:%d\n", uid, gid); + ret = syscall(SYS_setresgid, gid, gid, gid); if (ret >= 0) { syscall(SYS_setresuid, uid, uid, uid); - } - if (ret < 0) { + } else if (ret < 0) { pr_perror("Failed to change UID/GID\n"); exit_group(2); } + gid = getgid(); uid = getuid(); test_msg("Now aux thread runs as UID: %d; GID: %d\n", uid, gid); + test_msg("Child thread is waiting for main thread's signal\n"); pthread_mutex_lock(&mutex); - while (!done) - { + while (!done) { pthread_cond_wait(&cond, &mutex); } pthread_mutex_unlock(&mutex); @@ -77,13 +82,13 @@ void *chg_uid_gid(void *arg) int main(int argc, char **argv) { - - int ret; - cap_t newcaps; pthread_t diff_cred_thread; - test_init(argc, argv); + cap_t newcaps; int maingroup; int mainuser; + int ret; + + test_init(argc, argv); if (getuid() != 0) { fail("Test is expected to be run with root privileges\n"); @@ -94,9 +99,9 @@ int main(int argc, char **argv) test_msg("Test daemonized\n"); test_msg("Acquiring CAP_SETGID and CAP_SETUID...\n"); + newcaps = cap_from_text("cap_setgid,cap_setuid=+eip"); - if (!newcaps) - { + if (!newcaps) { pr_perror("Failed to get capability struct\n"); exit(1); } @@ -119,13 +124,14 @@ int main(int argc, char **argv) test_msg("Creating thread with different UID/GID\n"); ret = pthread_create(&diff_cred_thread, NULL, &chg_uid_gid, NULL); + sleep(5); + test_msg("Relinquishing root privileges\n"); ret = syscall(SYS_setresgid, maingroup, maingroup, maingroup); if (ret >= 0) { ret = syscall(SYS_setresuid, mainuser, mainuser, mainuser); - } - if (ret < 0) { + } else if (ret < 0) { pr_perror("Failed to drop privileges\n"); exit(1); } @@ -142,12 +148,15 @@ int main(int argc, char **argv) pr_perror("Thread credentials match after restore\n"); exit(1); } + pthread_mutex_lock(&mutex); done = 1; pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); pthread_join(diff_cred_thread, NULL); test_msg("Threads joined\n"); + pass(); + return 0; } From eff4c2acf40695b54047fa016b6d5233e7a433a7 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 14 Oct 2017 00:26:32 +0300 Subject: [PATCH 1052/4375] test: thread_different_uid_gid -- Fixup sync points Wait for thread to finish its creation instead of calling sleep. Same time call for test_daemon only when we're ready. CC: Vitaly Ostrosablin Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/thread_different_uid_gid.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/zdtm/static/thread_different_uid_gid.c b/test/zdtm/static/thread_different_uid_gid.c index 7964b6893..1a6cdc976 100644 --- a/test/zdtm/static/thread_different_uid_gid.c +++ b/test/zdtm/static/thread_different_uid_gid.c @@ -25,6 +25,7 @@ unsigned int gid; unsigned int uid; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +task_waiter_t t; int done = 0; @@ -70,6 +71,8 @@ void *chg_uid_gid(void *arg) test_msg("Now aux thread runs as UID: %d; GID: %d\n", uid, gid); test_msg("Child thread is waiting for main thread's signal\n"); + task_waiter_complete(&t, 1); + pthread_mutex_lock(&mutex); while (!done) { pthread_cond_wait(&cond, &mutex); @@ -89,15 +92,13 @@ int main(int argc, char **argv) int ret; test_init(argc, argv); + task_waiter_init(&t); if (getuid() != 0) { fail("Test is expected to be run with root privileges\n"); exit(1); } - test_daemon(); - test_msg("Test daemonized\n"); - test_msg("Acquiring CAP_SETGID and CAP_SETUID...\n"); newcaps = cap_from_text("cap_setgid,cap_setuid=+eip"); @@ -124,8 +125,7 @@ int main(int argc, char **argv) test_msg("Creating thread with different UID/GID\n"); ret = pthread_create(&diff_cred_thread, NULL, &chg_uid_gid, NULL); - - sleep(5); + task_waiter_wait4(&t, 1); test_msg("Relinquishing root privileges\n"); ret = syscall(SYS_setresgid, maingroup, maingroup, maingroup); @@ -142,6 +142,7 @@ int main(int argc, char **argv) } test_msg("Main thread is waiting for signal\n"); + test_daemon(); test_waitsig(); if (gid == getgid() || uid == getuid()) { From 0768d9203f3f3533c2fe9d71192f9b4bcc9f4651 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 14 Oct 2017 03:04:24 +0300 Subject: [PATCH 1053/4375] zdtm: rework a synchronization scheme Currently test_daemon() sends a signal to a parent process, when a test completed a prepartion stage. But it doesn't work, if a child changed uid and gid, because it doesn't have enough permissions in this case. This patch reworks a synchronization scheme to use a futex instead of sending signals. Signed-off-by: Andrei Vagin --- test/zdtm/lib/test.c | 45 +++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/test/zdtm/lib/test.c b/test/zdtm/lib/test.c index a01eac377..562fa56c6 100644 --- a/test/zdtm/lib/test.c +++ b/test/zdtm/lib/test.c @@ -20,9 +20,23 @@ #include "ns.h" futex_t sig_received; +static struct { + futex_t stage; +} *test_shared_state; + +enum { + TEST_INIT_STAGE = 0, + TEST_RUNNING_STAGE, + TEST_FINI_STAGE, + TEST_FAIL_STAGE, +}; + +static int parent; static void sig_hand(int signo) { + if (parent) + futex_set_and_wake(&test_shared_state->stage, TEST_FAIL_STAGE); futex_set_and_wake(&sig_received, signo); } @@ -208,16 +222,26 @@ void test_init(int argc, char **argv) setup_outfile(); redir_stdfds(); + test_shared_state = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0); + if (test_shared_state == MAP_FAILED) { + pr_perror("Unable to map a shared memory"); + exit(1); + } + + futex_init(&test_shared_state->stage); + futex_set(&test_shared_state->stage, TEST_INIT_STAGE); + pid = fork(); if (pid < 0) { pr_perror("Daemonizing failed"); exit(1); } + parent = 1; if (pid) { /* parent will exit when the child is ready */ - test_waitsig(); + futex_wait_while(&test_shared_state->stage, TEST_INIT_STAGE); - if (futex_get(&sig_received) == SIGCHLD) { + if (futex_get(&test_shared_state->stage) == TEST_FAIL_STAGE) { int ret; if (waitpid(pid, &ret, 0) != pid) { pr_perror("Unable to wait %d", pid); @@ -239,6 +263,7 @@ void test_init(int argc, char **argv) _exit(0); } + parent = 0; if (setsid() < 0) { pr_perror("Can't become session group leader"); @@ -259,21 +284,7 @@ void test_init(int argc, char **argv) void test_daemon() { - pid_t ppid; - - ppid = getppid(); - if (ppid <= 1) { - pr_perror("Test orphaned"); - goto out; - } - - if (kill(ppid, SIGTERM)) - goto out; - return; -out: - /* kill out our process group for safety */ - kill(0, SIGKILL); - exit(1); + futex_set_and_wake(&test_shared_state->stage, TEST_RUNNING_STAGE); } int test_go(void) From f65517b95d9da8117d74065da3e3b4877f75731f Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 14 Oct 2017 04:19:35 +0300 Subject: [PATCH 1054/4375] shmem: dump shared memory before dumping namespaces page_ids is a global variable and it is used to dump shared memroy, process memory and ipc shared memory. The problem is that an IPC namespace is dumped in a child process, so page_ids isn't changed in a parent process. This patch is a quick workaround this issue. Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 8faa00b45..35ca7019e 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1834,6 +1834,16 @@ int cr_dump_tasks(pid_t pid) if (dump_pstree(root_item)) goto err; + /* + * TODO: cr_dump_shmem has to be called before dump_namespaces(), + * because page_ids is a global variable and it is used to dump + * ipc shared memory, but an ipc namespace is dumped in a child + * process. + */ + ret = cr_dump_shmem(); + if (ret) + goto err; + if (root_ns_mask) if (dump_namespaces(root_item, root_ns_mask) < 0) goto err; @@ -1842,10 +1852,6 @@ int cr_dump_tasks(pid_t pid) if (ret) goto err; - ret = cr_dump_shmem(); - if (ret) - goto err; - ret = fix_external_unix_sockets(); if (ret) goto err; From 0509bc9f177bc38a574c274452dc106b95741ee9 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 14 Oct 2017 09:12:28 +0300 Subject: [PATCH 1055/4375] restore: set a dumpable flag after restoring changing uid and gid This flag is reseted each time when uid-s, gid-s or capabilities are changed. ------------------------ grep Error ------------------------ (00.235109) 6: Opening 0x002ad2fb7a1000-0x002ad2fb7a2000 0000000000000000 (101) vma (00.235115) 6: Search for 0x002ad2fb7a1000 shmem 0x3ec72 0x2b9ac74058c0/5 (00.235119) 6: Waiting for the 3ec72 shmem to appear (00.235122) 6: Opening shmem [/proc/5/fd/6] (00.235153) 6: Error (criu/shmem.c:453): Can't open 5/fd/6 on procfs: Permission denied (00.235171) 6: Error (criu/mem.c:1200): `- Can't open vma (00.283466) uns: calling exit_usernsd (-1, 1) (00.283521) uns: daemon calls 0x47f6b0 (189, -1, 1) (00.283532) uns: `- daemon exits w/ 0 (00.289212) uns: daemon stopped (00.289232) Error (criu/cr-restore.c:2152): Restoring FAILED. ------------------------ ERROR OVER ------------------------ Signed-off-by: Andrei Vagin Signed-off-by: Andrei Vagin Signed-off-by: Andrei Vagin --- criu/files.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/files.c b/criu/files.c index 28b21dd03..2eac20b30 100644 --- a/criu/files.c +++ b/criu/files.c @@ -674,6 +674,9 @@ int restore_fown(int fd, FownEntry *fown) return -1; } + if (prctl(PR_SET_DUMPABLE, 1, 0)) + pr_perror("Unable to set PR_SET_DUMPABLE"); + return 0; } From 4a044e6af93f6b9d473a8ca56cbc0b07224cf6ab Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 5 Jul 2017 16:59:43 +0300 Subject: [PATCH 1056/4375] net: Dump regular sit device Nothing special here, just parse all known NLAs and keep them on the image. Issue #11 Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/net.c | 127 +++++++++++++++++++++++++++++++++++++++++++- images/Makefile | 1 + images/netdev.proto | 4 ++ images/sit.proto | 22 ++++++++ 4 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 images/sit.proto diff --git a/criu/net.c b/criu/net.c index 4bd4c6e8e..d8940543a 100644 --- a/criu/net.c +++ b/criu/net.c @@ -50,6 +50,30 @@ #define IFLA_MACVLAN_FLAGS 2 #endif +enum { + IFLA_IPTUN_UNSPEC, + IFLA_IPTUN_LINK, + IFLA_IPTUN_LOCAL, + IFLA_IPTUN_REMOTE, + IFLA_IPTUN_TTL, + IFLA_IPTUN_TOS, + IFLA_IPTUN_ENCAP_LIMIT, + IFLA_IPTUN_FLOWINFO, + IFLA_IPTUN_FLAGS, + IFLA_IPTUN_PROTO, + IFLA_IPTUN_PMTUDISC, + IFLA_IPTUN_6RD_PREFIX, + IFLA_IPTUN_6RD_RELAY_PREFIX, + IFLA_IPTUN_6RD_PREFIXLEN, + IFLA_IPTUN_6RD_RELAY_PREFIXLEN, + IFLA_IPTUN_ENCAP_TYPE, + IFLA_IPTUN_ENCAP_FLAGS, + IFLA_IPTUN_ENCAP_SPORT, + IFLA_IPTUN_ENCAP_DPORT, + __IFLA_IPTUN_MAX, +}; +#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) + static int ns_sysfs_fd = -1; int read_ns_sys_file(char *path, char *buf, int len) @@ -635,6 +659,106 @@ static int dump_one_gre(struct ifinfomsg *ifi, char *kind, return dump_unknown_device(ifi, kind, tb, fds); } +static int dump_sit(NetDeviceEntry *nde, struct cr_imgset *imgset, struct nlattr **info) +{ + int ret; + struct nlattr *data[__IFLA_IPTUN_MAX]; + SitEntry se = SIT_ENTRY__INIT; + /* There are for IP(v6) addresses kernel feeds to us */ + uint32_t a_local, a_remote, rd_prefix[4], rl_prefix; + + if (!info || !info[IFLA_INFO_DATA]) { + pr_err("no data for sit\n"); + return -1; + } + + pr_info("Some data for SIT provided\n"); + ret = nla_parse_nested(data, IFLA_IPTUN_MAX, info[IFLA_INFO_DATA], NULL); + if (ret < 0) { + pr_err("failed ot parse sit data\n"); + return -1; + } + +#define ENCODE_ENTRY(__type, __ifla, __proto) do { \ + if (data[__ifla]) { \ + se.__proto = *(__type *)nla_data(data[__ifla]); \ + if (se.__proto) \ + se.has_##__proto = true; \ + } \ + } while (0) + + if (data[IFLA_IPTUN_LOCAL]) { + a_local = *(u32 *)nla_data(data[IFLA_IPTUN_LOCAL]); + if (a_local != 0) { + se.n_local = 1; + se.local = &a_local; + } + } + + if (data[IFLA_IPTUN_REMOTE]) { + a_remote = *(u32 *)nla_data(data[IFLA_IPTUN_REMOTE]); + if (a_remote != 0) { + se.n_remote = 1; + se.remote = &a_remote; + } + } + + ENCODE_ENTRY(u32, IFLA_IPTUN_LINK, link); + ENCODE_ENTRY(u8, IFLA_IPTUN_TTL, ttl); + ENCODE_ENTRY(u8, IFLA_IPTUN_TOS, tos); + ENCODE_ENTRY(u16, IFLA_IPTUN_FLAGS, flags); + ENCODE_ENTRY(u8, IFLA_IPTUN_PROTO, proto); + + if (data[IFLA_IPTUN_PMTUDISC]) { + u8 v; + + v = *(u8 *)nla_data(data[IFLA_IPTUN_PMTUDISC]); + if (v) + se.pmtudisc = se.has_pmtudisc = true; + } + + ENCODE_ENTRY(u16, IFLA_IPTUN_ENCAP_TYPE, encap_type); + ENCODE_ENTRY(u16, IFLA_IPTUN_ENCAP_FLAGS, encap_flags); + ENCODE_ENTRY(u16, IFLA_IPTUN_ENCAP_SPORT, encap_sport); + ENCODE_ENTRY(u16, IFLA_IPTUN_ENCAP_DPORT, encap_dport); + + if (data[IFLA_IPTUN_6RD_PREFIXLEN]) { + se.rd_prefixlen = *(u16 *)nla_data(data[IFLA_IPTUN_6RD_PREFIXLEN]); + if (!se.rd_prefixlen) + goto skip; + + if (!data[IFLA_IPTUN_6RD_PREFIX]) { + pr_err("No 6rd prefix for sit device\n"); + return -1; + } + + se.has_rd_prefixlen = true; + memcpy(&rd_prefix, nla_data(data[IFLA_IPTUN_6RD_PREFIX]), sizeof(rd_prefix)); + se.n_rd_prefix = 4; + se.rd_prefix = rd_prefix; + + se.relay_prefixlen = *(u16 *)nla_data(data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); + if (!se.relay_prefixlen) + goto skip; + + if (!data[IFLA_IPTUN_6RD_RELAY_PREFIX]) { + pr_err("No 6rd relay prefix for sit device\n"); + return -1; + } + + se.has_relay_prefixlen = true; + memcpy(&rl_prefix, nla_data(data[IFLA_IPTUN_6RD_RELAY_PREFIX]), sizeof(rl_prefix)); + se.n_relay_prefix = 1; + se.relay_prefix = &rl_prefix; +skip:; + } + +#undef ENCODE_ENTRY + + nde->sit = &se; + return write_netdev_img(nde, imgset, info); +} + static int dump_one_sit(struct ifinfomsg *ifi, char *kind, struct nlattr **tb, struct cr_imgset *fds) { @@ -656,8 +780,7 @@ static int dump_one_sit(struct ifinfomsg *ifi, char *kind, return 0; } - pr_warn("SIT device %s not supported natively\n", name); - return dump_unknown_device(ifi, kind, tb, fds); + return dump_one_netdev(ND_TYPE__SIT, ifi, tb, fds, dump_sit); } static int dump_one_link(struct nlmsghdr *hdr, void *arg) diff --git a/images/Makefile b/images/Makefile index 5f0ed6488..276f1fcf7 100644 --- a/images/Makefile +++ b/images/Makefile @@ -62,6 +62,7 @@ proto-obj-y += time.o proto-obj-y += sysctl.o proto-obj-y += autofs.o proto-obj-y += macvlan.o +proto-obj-y += sit.o CFLAGS += -iquote $(obj)/ diff --git a/images/netdev.proto b/images/netdev.proto index d3fde30b7..5f9dae2f5 100644 --- a/images/netdev.proto +++ b/images/netdev.proto @@ -4,6 +4,7 @@ import "macvlan.proto"; import "opts.proto"; import "tun.proto"; import "sysctl.proto"; +import "sit.proto"; enum nd_type { LOOPBACK = 1; @@ -19,6 +20,7 @@ enum nd_type { VENET = 5; /* OpenVZ device */ BRIDGE = 6; MACVLAN = 7; + SIT = 8; } message net_device_entry { @@ -39,6 +41,8 @@ message net_device_entry { repeated sysctl_entry conf6 = 10; optional macvlan_link_entry macvlan = 11; + + optional sit_entry sit = 15; } message netns_entry { diff --git a/images/sit.proto b/images/sit.proto new file mode 100644 index 000000000..7ca91ccd0 --- /dev/null +++ b/images/sit.proto @@ -0,0 +1,22 @@ +syntax = "proto2"; + +import "opts.proto"; + +message sit_entry { + optional uint32 link = 1; + repeated uint32 local = 2 [(criu).ipadd = true]; + repeated uint32 remote = 3 [(criu).ipadd = true]; + optional uint32 ttl = 4; + optional uint32 tos = 5; + optional bool pmtudisc = 6; + optional uint32 proto = 7; + optional uint32 flags = 8; + optional uint32 encap_type = 9; + optional uint32 encap_flags = 10; + optional uint32 encap_sport = 11; + optional uint32 encap_dport = 12; + optional uint32 rd_prefixlen = 13; + repeated uint32 rd_prefix = 14 [(criu).ipadd = true]; + optional uint32 relay_prefixlen = 15; + repeated uint32 relay_prefix = 16 [(criu).ipadd = true]; +}; From 87bfe588006929f1fce5110a1e2b615b28828989 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 5 Jul 2017 16:59:57 +0300 Subject: [PATCH 1057/4375] net: Restore sit device from image Same here -- prepare the IFLA_INFO_DATA section using the date from SitEntry. Issue #11 Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/net.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/criu/net.c b/criu/net.c index d8940543a..d22ab1638 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1330,6 +1330,94 @@ out: return ret; } +static int sit_link_info(NetDeviceEntry *nde, struct newlink_req *req) +{ + struct rtattr *sit_data; + SitEntry *se = nde->sit; + + if (!se) { + pr_err("Missing sit entry %d\n", nde->ifindex); + return -1; + } + + addattr_l(&req->h, sizeof(*req), IFLA_INFO_KIND, "sit", 3); + sit_data = NLMSG_TAIL(&req->h); + addattr_l(&req->h, sizeof(*req), IFLA_INFO_DATA, NULL, 0); + +#define DECODE_ENTRY(__type, __ifla, __proto) do { \ + __type aux; \ + if (se->has_##__proto) { \ + aux = se->__proto; \ + addattr_l(&req->h, sizeof(*req), __ifla, \ + &aux, sizeof(__type)); \ + } \ + } while (0) + + if (se->n_local) { + if (se->n_local != 1) { + pr_err("Too long local addr for sit\n"); + return -1; + } + addattr_l(&req->h, sizeof(*req), IFLA_IPTUN_LOCAL, se->local, sizeof(u32)); + } + + if (se->n_remote) { + if (se->n_remote != 1) { + pr_err("Too long remote addr for sit\n"); + return -1; + } + addattr_l(&req->h, sizeof(*req), IFLA_IPTUN_REMOTE, se->remote, sizeof(u32)); + } + + DECODE_ENTRY(u32, IFLA_IPTUN_LINK, link); + DECODE_ENTRY(u8, IFLA_IPTUN_TTL, ttl); + DECODE_ENTRY(u8, IFLA_IPTUN_TOS, tos); + DECODE_ENTRY(u16, IFLA_IPTUN_FLAGS, flags); + DECODE_ENTRY(u8, IFLA_IPTUN_PROTO, proto); + + if (se->has_pmtudisc && se->pmtudisc) { + u8 aux = 1; + addattr_l(&req->h, sizeof(*req), IFLA_IPTUN_PMTUDISC, &aux, sizeof(u8)); + } + + DECODE_ENTRY(u16, IFLA_IPTUN_ENCAP_TYPE, encap_type); + DECODE_ENTRY(u16, IFLA_IPTUN_ENCAP_FLAGS, encap_flags); + DECODE_ENTRY(u16, IFLA_IPTUN_ENCAP_SPORT, encap_sport); + DECODE_ENTRY(u16, IFLA_IPTUN_ENCAP_DPORT, encap_dport); + + if (!se->has_rd_prefixlen) { + u16 aux; + + if (se->n_rd_prefix != 4) { + pr_err("Bad 6rd prefixlen for sit\n"); + return -1; + } + + aux = se->rd_prefixlen; + addattr_l(&req->h, sizeof(*req), IFLA_IPTUN_6RD_PREFIXLEN, &aux, sizeof(u16)); + addattr_l(&req->h, sizeof(*req), IFLA_IPTUN_6RD_PREFIX, se->rd_prefix, 4 * sizeof(u32)); + + if (!se->has_relay_prefixlen) + goto skip; + + if (se->n_relay_prefix != 1) { + pr_err("Bad 6rd relay prefixlen for sit\n"); + return -1; + } + + aux = se->relay_prefixlen; + addattr_l(&req->h, sizeof(*req), IFLA_IPTUN_6RD_RELAY_PREFIXLEN, &aux, sizeof(u16)); + addattr_l(&req->h, sizeof(*req), IFLA_IPTUN_6RD_RELAY_PREFIX, se->relay_prefix, sizeof(u32)); +skip:; + } + +#undef DECODE_ENTRY + + sit_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)sit_data; + + return 0; +} + static int restore_link(NetDeviceEntry *nde, int nlsk, int criu_nlsk) { pr_info("Restoring link %s type %d\n", nde->name, nde->type); @@ -1348,6 +1436,8 @@ static int restore_link(NetDeviceEntry *nde, int nlsk, int criu_nlsk) return restore_one_link(nde, nlsk, bridge_link_info, NULL); case ND_TYPE__MACVLAN: return restore_one_macvlan(nde, nlsk, criu_nlsk); + case ND_TYPE__SIT: + return restore_one_link(nde, nlsk, sit_link_info, NULL); default: pr_err("Unsupported link type %d\n", nde->type); break; From fb85281c3b88cd159255bbadbe8e6882ecf2e576 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 5 Jul 2017 17:00:12 +0300 Subject: [PATCH 1058/4375] zdtm: Test sit device C/R Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/sit.c | 58 +++++++++++++++++++++++++++++++++++++++ test/zdtm/static/sit.desc | 3 ++ 3 files changed, 62 insertions(+) create mode 100644 test/zdtm/static/sit.c create mode 100644 test/zdtm/static/sit.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index da9abdfcc..68ea320a1 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -172,6 +172,7 @@ TST_NOFILE := \ helper_zombie_child \ clone_fs \ macvlan \ + sit \ cr_veth \ sock_peercred \ s390x_mmap_high \ diff --git a/test/zdtm/static/sit.c b/test/zdtm/static/sit.c new file mode 100644 index 000000000..07c36ab5d --- /dev/null +++ b/test/zdtm/static/sit.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "zdtmtst.h" + +const char *test_doc = "check sit devices"; +const char *test_author = "Pavel Emelyanov "; + +#define IF_NAME "zdtmsit0" +#define LOCAL_ADDR "1.1.1.2" +#define REMOT_ADDR "2.2.2.1" + +int main(int argc, char **argv) +{ + int ret = 1; + + test_init(argc, argv); + + if (system("ip link add " IF_NAME " type sit ttl 13 local " LOCAL_ADDR " remote " REMOT_ADDR)) { + pr_perror("Can't make sit device"); + return 1; + } + + if (system("ip -details addr list dev " IF_NAME " > sit.dump.test")) { + fail("can't save net config"); + goto out; + } + + test_daemon(); + test_waitsig(); + + if (system("ip -details addr list dev " IF_NAME " > sit.rst.test")) { + fail("can't get net config"); + goto out; + } + + if (system("diff sit.rst.test sit.dump.test")) { + fail("Net config differs after restore"); + goto out; + } + + pass(); + ret = 0; + +out: + return ret; +} + diff --git a/test/zdtm/static/sit.desc b/test/zdtm/static/sit.desc new file mode 100644 index 000000000..01c4149e0 --- /dev/null +++ b/test/zdtm/static/sit.desc @@ -0,0 +1,3 @@ +{ 'deps': [ '/bin/sh', '/sbin/ip|/bin/ip', '/usr/bin/diff' ], + 'flags': 'suid', + 'flavor': 'ns uns' } From 882bacffc12a76cbe2be987ecdd3769063b943f1 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 19 Jul 2017 12:04:03 +0300 Subject: [PATCH 1059/4375] net: Don't try to restore sit6rd when not present Due to a misprint in an if the 6rd info for sit device was restored when not present. https://github.com/xemul/criu/issues/366 Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/net.c b/criu/net.c index d22ab1638..dcaf93f88 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1385,7 +1385,7 @@ static int sit_link_info(NetDeviceEntry *nde, struct newlink_req *req) DECODE_ENTRY(u16, IFLA_IPTUN_ENCAP_SPORT, encap_sport); DECODE_ENTRY(u16, IFLA_IPTUN_ENCAP_DPORT, encap_dport); - if (!se->has_rd_prefixlen) { + if (se->has_rd_prefixlen) { u16 aux; if (se->n_rd_prefix != 4) { From f6c9ac7e0d3e0362b1e816de4ee8e1f65ba842f2 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 7 Jun 2017 14:28:35 +0300 Subject: [PATCH 1060/4375] files: Declare structures of fake masters Fake masters are files, which are not owned by a process, that is able to open them. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 3 +++ criu/include/files.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/criu/files.c b/criu/files.c index 2eac20b30..741ae22ee 100644 --- a/criu/files.c +++ b/criu/files.c @@ -54,6 +54,8 @@ #define FDESC_HASH_SIZE 64 static struct hlist_head file_desc_hash[FDESC_HASH_SIZE]; +/* file_desc's, which fle is not owned by a process, that is able to open them */ +static LIST_HEAD(fake_master_head); static void init_fdesc_hash(void) { @@ -66,6 +68,7 @@ static void init_fdesc_hash(void) void file_desc_init(struct file_desc *d, u32 id, struct file_desc_ops *ops) { INIT_LIST_HEAD(&d->fd_info_head); + INIT_LIST_HEAD(&d->fake_master_list); INIT_HLIST_NODE(&d->hash); d->id = id; diff --git a/criu/include/files.h b/criu/include/files.h index 419e50dd3..352fefc4e 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -133,6 +133,8 @@ struct file_desc { struct hlist_node hash; /* Descriptor hashing and lookup */ struct list_head fd_info_head; /* Chain of fdinfo_list_entry-s with same ID and type but different pids */ struct file_desc_ops *ops; /* Associated operations */ + struct list_head fake_master_list;/* To chain in the list of file_desc, which don't + have a fle in a task, that having permissions */ }; struct fdtype_ops { From 7e9fe49f54b90cacdac01e32742ba01200fabdc8 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 7 Jun 2017 14:27:14 +0300 Subject: [PATCH 1061/4375] files: Move fle_init() to files.c It has only one user. Also, in next patches will be used pstree_item_by_virt() function, and I don't want to add "#include" to "files.h" for it, and to nest headers. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 8 ++++++++ criu/include/files.h | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/criu/files.c b/criu/files.c index 741ae22ee..b23e1fba4 100644 --- a/criu/files.c +++ b/criu/files.c @@ -692,6 +692,14 @@ int rst_file_params(int fd, FownEntry *fown, int flags) return 0; } +static void fle_init(struct fdinfo_list_entry *fle, int pid, FdinfoEntry *fe) +{ + fle->pid = pid; + fle->fe = fe; + fle->received = 0; + fle->stage = FLE_INITIALIZED; +} + static int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info) { struct fdinfo_list_entry *le, *new_le; diff --git a/criu/include/files.h b/criu/include/files.h index 352fefc4e..c301cb2da 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -89,14 +89,6 @@ struct fdinfo_list_entry { u8 stage:3; }; -static inline void fle_init(struct fdinfo_list_entry *fle, int pid, FdinfoEntry *fe) -{ - fle->pid = pid; - fle->fe = fe; - fle->received = 0; - fle->stage = FLE_INITIALIZED; -} - /* reports whether fd_a takes prio over fd_b */ static inline int fdinfo_rst_prio(struct fdinfo_list_entry *fd_a, struct fdinfo_list_entry *fd_b) { From 82acfd44878d2b64b251cea8e35552b958db08cc Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 7 Jun 2017 14:27:38 +0300 Subject: [PATCH 1062/4375] files: Merge shmalloc() to fle_init() Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/criu/files.c b/criu/files.c index b23e1fba4..ba24ce9a7 100644 --- a/criu/files.c +++ b/criu/files.c @@ -692,12 +692,19 @@ int rst_file_params(int fd, FownEntry *fown, int flags) return 0; } -static void fle_init(struct fdinfo_list_entry *fle, int pid, FdinfoEntry *fe) +static struct fdinfo_list_entry *alloc_fle(int pid, FdinfoEntry *fe) { + struct fdinfo_list_entry *fle; + + fle = shmalloc(sizeof(*fle)); + if (!fle) + return NULL; fle->pid = pid; fle->fe = fe; fle->received = 0; fle->stage = FLE_INITIALIZED; + + return fle; } static int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info) @@ -708,12 +715,10 @@ static int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info) pr_info("Collect fdinfo pid=%d fd=%d id=%#x\n", pid, e->fd, e->id); - new_le = shmalloc(sizeof(*new_le)); + new_le = alloc_fle(pid, e); if (!new_le) return -1; - fle_init(new_le, pid, e); - fdesc = find_file_desc(e); if (fdesc == NULL) { pr_err("No file for fd %d id %#x\n", e->fd, e->id); From 70be2395bfbe3b112bdfb8e134bf4be8dd9361f1 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 7 Jun 2017 14:29:01 +0300 Subject: [PATCH 1063/4375] files: Add fake fle flag and close such fles after restore files Allow to mark some fles as "fake" and close them, when they are not needed. v2: Cache fake file in separate list, when they are restored, to do not iterate over files list again. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 21 ++++++++++++++++++++- criu/include/files.h | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/criu/files.c b/criu/files.c index ba24ce9a7..5d6b1139d 100644 --- a/criu/files.c +++ b/criu/files.c @@ -702,6 +702,7 @@ static struct fdinfo_list_entry *alloc_fle(int pid, FdinfoEntry *fe) fle->pid = pid; fle->fe = fe; fle->received = 0; + fle->fake = 0; fle->stage = FLE_INITIALIZED; return fle; @@ -1106,11 +1107,20 @@ static int receive_fd(struct fdinfo_list_entry *fle) return 0; } +static void close_fdinfos(struct list_head *list) +{ + struct fdinfo_list_entry *fle; + + list_for_each_entry(fle, list, ps_list) + close(fle->fe->fd); +} + static int open_fdinfos(struct pstree_item *me) { struct list_head *list = &rsti(me)->fds; struct fdinfo_list_entry *fle, *tmp; LIST_HEAD(completed); + LIST_HEAD(fake); bool progress, again; int st, ret = 0; @@ -1136,7 +1146,10 @@ static int open_fdinfos(struct pstree_item *me) * and reduce number of fles in their checks. */ list_del(&fle->ps_list); - list_add(&fle->ps_list, &completed); + if (!fle->fake) + list_add(&fle->ps_list, &completed); + else + list_add(&fle->ps_list, &fake); } if (ret == 1) again = true; @@ -1146,7 +1159,13 @@ static int open_fdinfos(struct pstree_item *me) } while (again || progress); BUG_ON(!list_empty(list)); + /* + * Fake fles may be used for restore other + * file types, so their closing is delayed. + */ + close_fdinfos(&fake); splice: + list_splice(&fake, list); list_splice(&completed, list); return ret; diff --git a/criu/include/files.h b/criu/include/files.h index c301cb2da..275b36e2d 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -87,6 +87,7 @@ struct fdinfo_list_entry { FdinfoEntry *fe; u8 received:1; u8 stage:3; + u8 fake:1; }; /* reports whether fd_a takes prio over fd_b */ From 940187818c95c3f20c55d3ee5b7a058e6aa7383a Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 1 Jun 2017 14:34:28 +0300 Subject: [PATCH 1064/4375] autofs: Delete alignment in autofs_create_fle() shmalloc() already returns address with sizeof(unsigned long) alignment. So, the second alignment is useless. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/autofs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/autofs.c b/criu/autofs.c index 01cbdcfdf..3add35bc7 100644 --- a/criu/autofs.c +++ b/criu/autofs.c @@ -865,10 +865,9 @@ static int autofs_create_fle(struct pstree_item *task, FdinfoEntry *fe, struct fdinfo_list_entry *le; struct rst_info *rst_info = rsti(task); - le = shmalloc(sizeof(*le) + sizeof(int)); + le = shmalloc(sizeof(*le)); if (!le) return -1; - le = (void *)ALIGN((long)le, sizeof(int)); fle_init(le, vpid(task), fe); From 107f2e40fe2329d3f09eca6b57a2733c8d07fb58 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 1 Jun 2017 15:08:36 +0300 Subject: [PATCH 1065/4375] files: Kill autofs_create_fle() and use generic helper On 01.06.2017 14:34, Kirill Tkhai wrote: > Everything is prepared: the pair "type and id" is > uniqul, so find_file_desc() in collect_fd() will > work as expected and it will find the file_desc > we just added in autofs_create_pipe()->collect_one_pipe_ops(). > > So, the not-generic helper may be killed. > > Signed-off-by: Kirill Tkhai Returned debug print: [PATCH 4/5 v2]files: Kill autofs_create_fle() and use generic helper Everything is prepared: the pair "type and id" is uniqul, so find_file_desc() in collect_fd() will work as expected and it will find the file_desc we just added in autofs_create_pipe()->collect_one_pipe_ops(). So, the not-generic helper may be killed. v2: Leave debug print on the place. Signed-off-by: Kirill Tkhai Acked-by: Stanislav Kinsburskiy Acked-by: Stanislav Kinsburskiy Signed-off-by: Andrei Vagin --- criu/autofs.c | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/criu/autofs.c b/criu/autofs.c index 3add35bc7..ce6042814 100644 --- a/criu/autofs.c +++ b/criu/autofs.c @@ -859,28 +859,6 @@ static struct fdinfo_list_entry *autofs_pipe_le(struct pstree_item *master, return ple; } -static int autofs_create_fle(struct pstree_item *task, FdinfoEntry *fe, - struct file_desc *desc) -{ - struct fdinfo_list_entry *le; - struct rst_info *rst_info = rsti(task); - - le = shmalloc(sizeof(*le)); - if (!le) - return -1; - - fle_init(le, vpid(task), fe); - - collect_task_fd(le, rst_info); - - list_add_tail(&le->desc_list, &desc->fd_info_head); - le->desc = desc; - - pr_info("autofs: added pipe fd %d, flags %#x to %d (with post_open)\n", - le->fe->fd, le->fe->flags, le->pid); - return 0; -} - static int autofs_open_pipefd(struct file_desc *d, int *new_fd) { struct fdinfo_list_entry *fle = file_master(d); @@ -933,7 +911,9 @@ static int autofs_create_pipe(struct pstree_item *task, autofs_info_t *i, if (!fe) return -1; - return autofs_create_fle(task, fe, &i->pi.d); + pr_info("autofs: adding pipe fd %d, flags %#x to %d (with post_open)\n", + fe->fd, fe->flags, vpid(task)); + return collect_fd(vpid(task), fe, rsti(task)); } static int autofs_add_mount_info(struct pprep_head *ph) From 674651995f2a8dafb4aebf02a86c3a2a3a57ec2d Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 1 Jun 2017 14:34:50 +0300 Subject: [PATCH 1066/4375] files: Export collect_fd() Declare it extern and allow to use outside files.c. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 2 +- criu/include/files.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/files.c b/criu/files.c index 5d6b1139d..3a57682c8 100644 --- a/criu/files.c +++ b/criu/files.c @@ -708,7 +708,7 @@ static struct fdinfo_list_entry *alloc_fle(int pid, FdinfoEntry *fe) return fle; } -static int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info) +int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info) { struct fdinfo_list_entry *le, *new_le; struct file_desc *fdesc; diff --git a/criu/include/files.h b/criu/include/files.h index 275b36e2d..0d711b75c 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -116,6 +116,7 @@ struct file_desc_ops { char * (*name)(struct file_desc *, char *b, size_t s); }; +int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info); void collect_task_fd(struct fdinfo_list_entry *new_fle, struct rst_info *ri); unsigned int find_unused_fd(struct pstree_item *, int hint_fd); From dc89ac658b0d9e1a4109baca886ac76f7b9f6259 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 7 Jun 2017 14:29:09 +0300 Subject: [PATCH 1067/4375] files: Teach collect_fd() mark fake files Add new argument to this function. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/autofs.c | 2 +- criu/files.c | 9 +++++---- criu/include/files.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/criu/autofs.c b/criu/autofs.c index ce6042814..6432b4213 100644 --- a/criu/autofs.c +++ b/criu/autofs.c @@ -913,7 +913,7 @@ static int autofs_create_pipe(struct pstree_item *task, autofs_info_t *i, pr_info("autofs: adding pipe fd %d, flags %#x to %d (with post_open)\n", fe->fd, fe->flags, vpid(task)); - return collect_fd(vpid(task), fe, rsti(task)); + return collect_fd(vpid(task), fe, rsti(task), false); } static int autofs_add_mount_info(struct pprep_head *ph) diff --git a/criu/files.c b/criu/files.c index 3a57682c8..6848e8996 100644 --- a/criu/files.c +++ b/criu/files.c @@ -708,7 +708,7 @@ static struct fdinfo_list_entry *alloc_fle(int pid, FdinfoEntry *fe) return fle; } -int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info) +int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info, bool fake) { struct fdinfo_list_entry *le, *new_le; struct file_desc *fdesc; @@ -719,6 +719,7 @@ int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info) new_le = alloc_fle(pid, e); if (!new_le) return -1; + new_le->fake = (!!fake); fdesc = find_file_desc(e); if (fdesc == NULL) { @@ -767,7 +768,7 @@ int dup_fle(struct pstree_item *task, struct fdinfo_list_entry *ple, if (!e) return -1; - return collect_fd(vpid(task), e, rsti(task)); + return collect_fd(vpid(task), e, rsti(task), false); } int prepare_ctl_tty(int pid, struct rst_info *rst_info, u32 ctl_tty_id) @@ -789,7 +790,7 @@ int prepare_ctl_tty(int pid, struct rst_info *rst_info, u32 ctl_tty_id) e->fd = reserve_service_fd(CTL_TTY_OFF); e->type = FD_TYPES__TTY; - if (collect_fd(pid, e, rst_info)) { + if (collect_fd(pid, e, rst_info, false)) { xfree(e); return -1; } @@ -829,7 +830,7 @@ int prepare_fd_pid(struct pstree_item *item) break; } - ret = collect_fd(pid, e, rst_info); + ret = collect_fd(pid, e, rst_info, false); if (ret < 0) { fdinfo_entry__free_unpacked(e, NULL); break; diff --git a/criu/include/files.h b/criu/include/files.h index 0d711b75c..2192cc6d2 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -116,7 +116,7 @@ struct file_desc_ops { char * (*name)(struct file_desc *, char *b, size_t s); }; -int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info); +int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info, bool ghost); void collect_task_fd(struct fdinfo_list_entry *new_fle, struct rst_info *ri); unsigned int find_unused_fd(struct pstree_item *, int hint_fd); From 5360ed761fd5bde678791048104c4155526eb0c1 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 5 Jun 2017 20:24:01 +0300 Subject: [PATCH 1068/4375] files: Kill file_desc_options::collect_fd() The only user is fifo, but it uses collect_fd() to do read only actions (the only change is fifo_info::reg_d population, which may be easily moved to open_fifo_fd()). So, move the collect_special_file() functionality from collect_fifo_fd() to open_fifo_fd() and kill collect_fd method at all. Signed-off-by: Kirill Tkhai --- criu/fifo.c | 18 +++++------------- criu/files.c | 3 --- criu/include/files.h | 7 ------- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/criu/fifo.c b/criu/fifo.c index 73d45e07a..d0728e1b0 100644 --- a/criu/fifo.c +++ b/criu/fifo.c @@ -33,7 +33,6 @@ struct fifo_info { struct file_desc d; FifoEntry *fe; bool restore_data; - struct file_desc *reg_d; }; static LIST_HEAD(fifo_head); @@ -114,29 +113,22 @@ out: static int open_fifo_fd(struct file_desc *d, int *new_fd) { struct fifo_info *info = container_of(d, struct fifo_info, d); + struct file_desc *reg_d; int fd; - fd = open_path(info->reg_d, do_open_fifo, info); + reg_d = find_file_desc_raw(FD_TYPES__REG, info->fe->id); + BUG_ON(!reg_d); + + fd = open_path(reg_d, do_open_fifo, info); if (fd < 0) return -1; *new_fd = fd; return 0; } -static void collect_fifo_fd(struct file_desc *d, - struct fdinfo_list_entry *fle, struct rst_info *ri) -{ - struct fifo_info *info; - - info = container_of(d, struct fifo_info, d); - info->reg_d = collect_special_file(info->fe->id); - BUG_ON(info->reg_d == NULL); -} - static struct file_desc_ops fifo_desc_ops = { .type = FD_TYPES__FIFO, .open = open_fifo_fd, - .collect_fd = collect_fifo_fd, }; static int collect_one_fifo(void *o, ProtobufCMessage *base, struct cr_img *i) diff --git a/criu/files.c b/criu/files.c index 6848e8996..cbe8de5e0 100644 --- a/criu/files.c +++ b/criu/files.c @@ -731,9 +731,6 @@ int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info, bool fake) if (pid_rst_prio(new_le->pid, le->pid)) break; - if (fdesc->ops->collect_fd) - fdesc->ops->collect_fd(fdesc, new_le, rst_info); - collect_task_fd(new_le, rst_info); list_add_tail(&new_le->desc_list, &le->desc_list); diff --git a/criu/include/files.h b/criu/include/files.h index 2192cc6d2..6b226429a 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -106,13 +106,6 @@ struct file_desc_ops { * so it shouldn't be saved for any post-actions. */ int (*open)(struct file_desc *d, int *new_fd); - /* - * Called to collect a new fd before adding it on desc. Clients - * may chose to collect it to some specific rst_info list. See - * prepare_fds() for details. - */ - void (*collect_fd)(struct file_desc *, struct fdinfo_list_entry *, - struct rst_info *); char * (*name)(struct file_desc *, char *b, size_t s); }; From deba6311ce2950bc0584eb6435b1e49feb32c0d9 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 7 Jun 2017 14:27:55 +0300 Subject: [PATCH 1069/4375] files: Assign fdesc to fle in collect_fd() earlier Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/files.c b/criu/files.c index cbe8de5e0..a15cbc3b2 100644 --- a/criu/files.c +++ b/criu/files.c @@ -726,6 +726,7 @@ int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info, bool fake) pr_err("No file for fd %d id %#x\n", e->fd, e->id); return -1; } + new_le->desc = fdesc; list_for_each_entry(le, &fdesc->fd_info_head, desc_list) if (pid_rst_prio(new_le->pid, le->pid)) @@ -734,7 +735,6 @@ int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info, bool fake) collect_task_fd(new_le, rst_info); list_add_tail(&new_le->desc_list, &le->desc_list); - new_le->desc = fdesc; return 0; } From 50131370aefc6a2241c92f83c7770945de7b392b Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 7 Jun 2017 14:28:44 +0300 Subject: [PATCH 1070/4375] files: Extract new_fle assignment from collect_fd() to separate func The algorhythm of searching file master will be more complicated in next patches. So, move current functionality in separate func. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/criu/files.c b/criu/files.c index a15cbc3b2..614ade613 100644 --- a/criu/files.c +++ b/criu/files.c @@ -708,9 +708,21 @@ static struct fdinfo_list_entry *alloc_fle(int pid, FdinfoEntry *fe) return fle; } +static void collect_desc_fle(struct fdinfo_list_entry *new_le, struct file_desc *fdesc) +{ + struct fdinfo_list_entry *le; + + new_le->desc = fdesc; + + list_for_each_entry(le, &fdesc->fd_info_head, desc_list) + if (pid_rst_prio(new_le->pid, le->pid)) + break; + list_add_tail(&new_le->desc_list, &le->desc_list); +} + int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info, bool fake) { - struct fdinfo_list_entry *le, *new_le; + struct fdinfo_list_entry *new_le; struct file_desc *fdesc; pr_info("Collect fdinfo pid=%d fd=%d id=%#x\n", @@ -726,16 +738,9 @@ int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info, bool fake) pr_err("No file for fd %d id %#x\n", e->fd, e->id); return -1; } - new_le->desc = fdesc; - - list_for_each_entry(le, &fdesc->fd_info_head, desc_list) - if (pid_rst_prio(new_le->pid, le->pid)) - break; - + collect_desc_fle(new_le, fdesc); collect_task_fd(new_le, rst_info); - list_add_tail(&new_le->desc_list, &le->desc_list); - return 0; } From a95f68e08273aa79a72e9a71590c1814ac878bba Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 3 Aug 2017 17:14:30 +0300 Subject: [PATCH 1071/4375] files: Reorder fdinfo_list_entry fields Keep int pid with short-len fields to avoid alignment gaps in structure. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/include/files.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/include/files.h b/criu/include/files.h index 6b226429a..a82d9bedb 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -83,8 +83,8 @@ struct fdinfo_list_entry { struct list_head desc_list; /* To chain on @fd_info_head */ struct file_desc *desc; /* Associated file descriptor */ struct list_head ps_list; /* To chain per-task files */ - int pid; FdinfoEntry *fe; + int pid; u8 received:1; u8 stage:3; u8 fake:1; From f084b246092617027e2700c8680cdeb3f5d70021 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 7 Jun 2017 14:27:47 +0300 Subject: [PATCH 1072/4375] files: Add task link to created fdinfo_list_entry and populate it This will be used in further to determine whether task's namespace allows to restore file_desc. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 6 ++++++ criu/include/files.h | 1 + 2 files changed, 7 insertions(+) diff --git a/criu/files.c b/criu/files.c index 614ade613..d5f15fe2b 100644 --- a/criu/files.c +++ b/criu/files.c @@ -704,6 +704,12 @@ static struct fdinfo_list_entry *alloc_fle(int pid, FdinfoEntry *fe) fle->received = 0; fle->fake = 0; fle->stage = FLE_INITIALIZED; + fle->task = pstree_item_by_virt(pid); + if (!fle->task) { + pr_err("Can't find task with pid %d\n", pid); + shfree_last(fle); + return NULL; + } return fle; } diff --git a/criu/include/files.h b/criu/include/files.h index a82d9bedb..7c8e0153b 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -83,6 +83,7 @@ struct fdinfo_list_entry { struct list_head desc_list; /* To chain on @fd_info_head */ struct file_desc *desc; /* Associated file descriptor */ struct list_head ps_list; /* To chain per-task files */ + struct pstree_item *task; FdinfoEntry *fe; int pid; u8 received:1; From 00468aa801caf2dc8596f6eedb2af029ea4167a9 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:37:50 +0300 Subject: [PATCH 1073/4375] zdtm: Test descriptor sent over unix and kept open Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 2 ++ test/zdtm/static/scm00.c | 26 +++++++++++++++++++++----- test/zdtm/static/scm01.c | 1 + test/zdtm/static/scm01.desc | 1 + 4 files changed, 25 insertions(+), 5 deletions(-) create mode 120000 test/zdtm/static/scm01.c create mode 100644 test/zdtm/static/scm01.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 68ea320a1..52e6a6667 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -154,6 +154,7 @@ TST_NOFILE := \ remap_dead_pid \ remap_dead_pid_root \ scm00 \ + scm01 \ aio00 \ aio01 \ fd \ @@ -439,6 +440,7 @@ socket-tcp-closed-last-ack: CFLAGS += -D ZDTM_TCP_LAST_ACK mnt_ext_manual: CFLAGS += -D ZDTM_EXTMAP_MANUAL sigpending: LDLIBS += -lrt vdso01: LDLIBS += -lrt +scm01: CFLAGS += -DKEEP_SENT_FD mntns_link_remap: CFLAGS += -DZDTM_LINK_REMAP mntns_shared_bind02: CFLAGS += -DSHARED_BIND02 mntns_root_bind02: CFLAGS += -DROOT_BIND02 diff --git a/test/zdtm/static/scm00.c b/test/zdtm/static/scm00.c index 6f0c7b789..39c14737a 100644 --- a/test/zdtm/static/scm00.c +++ b/test/zdtm/static/scm00.c @@ -68,7 +68,7 @@ static int recv_fd(int via) int main(int argc, char **argv) { - int sk[2], p[2]; + int sk[2], p[2], rfd; #define MSG "HELLO" char buf[8]; /* bigger than the MSG to check boundaries */ @@ -89,6 +89,7 @@ int main(int argc, char **argv) exit(1); } +#ifndef KEEP_SENT_FD close(p[0]); /* Swap pipe ends to make scm recv put pipe into different place */ @@ -96,22 +97,29 @@ int main(int argc, char **argv) close(p[1]); p[1] = p[0]; p[0] = -1; +#endif test_daemon(); test_waitsig(); - p[0] = recv_fd(sk[1]); - if (p[0] < 0) { + rfd = recv_fd(sk[1]); + if (rfd < 0) { fail("Can't recv pipe back (%d)", p[0]); goto out; } - +#ifdef KEEP_SENT_FD + if (rfd == p[0]) { + fail("Original descriptor not kept"); + goto out; + } +again: +#endif if (write(p[1], MSG, sizeof(MSG)) != sizeof(MSG)) { fail("Pipe write-broken"); goto out; } - if (read(p[0], buf, sizeof(buf)) != sizeof(MSG)) { + if (read(rfd, buf, sizeof(buf)) != sizeof(MSG)) { fail("Pipe read-broken"); goto out; } @@ -122,6 +130,14 @@ int main(int argc, char **argv) goto out; } +#ifdef KEEP_SENT_FD + if (rfd != p[0]) { + test_msg("Check kept\n"); + rfd = p[0]; + goto again; + } +#endif + pass(); out: return 0; diff --git a/test/zdtm/static/scm01.c b/test/zdtm/static/scm01.c new file mode 120000 index 000000000..4cab0edd2 --- /dev/null +++ b/test/zdtm/static/scm01.c @@ -0,0 +1 @@ +scm00.c \ No newline at end of file diff --git a/test/zdtm/static/scm01.desc b/test/zdtm/static/scm01.desc new file mode 100644 index 000000000..ded89879a --- /dev/null +++ b/test/zdtm/static/scm01.desc @@ -0,0 +1 @@ +{'flags': 'crfail'} From c6908011bba29b5d7a573fad0c4cc79c874b1600 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:38:04 +0300 Subject: [PATCH 1074/4375] zdtm: Send two descriptors via unix socket Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 2 ++ test/zdtm/static/scm00.c | 20 +++++++++++++++++++- test/zdtm/static/scm02.c | 1 + test/zdtm/static/scm02.desc | 1 + 4 files changed, 23 insertions(+), 1 deletion(-) create mode 120000 test/zdtm/static/scm02.c create mode 100644 test/zdtm/static/scm02.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 52e6a6667..69d7d0560 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -155,6 +155,7 @@ TST_NOFILE := \ remap_dead_pid_root \ scm00 \ scm01 \ + scm02 \ aio00 \ aio01 \ fd \ @@ -441,6 +442,7 @@ mnt_ext_manual: CFLAGS += -D ZDTM_EXTMAP_MANUAL sigpending: LDLIBS += -lrt vdso01: LDLIBS += -lrt scm01: CFLAGS += -DKEEP_SENT_FD +scm02: CFLAGS += -DSEND_BOTH mntns_link_remap: CFLAGS += -DZDTM_LINK_REMAP mntns_shared_bind02: CFLAGS += -DSHARED_BIND02 mntns_root_bind02: CFLAGS += -DROOT_BIND02 diff --git a/test/zdtm/static/scm00.c b/test/zdtm/static/scm00.c index 39c14737a..de626d9c9 100644 --- a/test/zdtm/static/scm00.c +++ b/test/zdtm/static/scm00.c @@ -91,12 +91,20 @@ int main(int argc, char **argv) #ifndef KEEP_SENT_FD close(p[0]); - +#ifdef SEND_BOTH + if (send_fd(sk[0], p[1]) < 0) { + pr_perror("Can't send 2nd descriptor"); + exit(1); + } + close(p[1]); + p[0] = p[1] = -1; +#else /* Swap pipe ends to make scm recv put pipe into different place */ dup2(p[1], p[0]); close(p[1]); p[1] = p[0]; p[0] = -1; +#endif #endif test_daemon(); @@ -107,6 +115,16 @@ int main(int argc, char **argv) fail("Can't recv pipe back (%d)", p[0]); goto out; } + +#ifdef SEND_BOTH + test_msg("Recv 2nd end\n"); + p[1] = recv_fd(sk[1]); + if (p[1] < 0) { + fail("Can't recv 2nd pipe back (%d)", p[1]); + goto out; + } +#endif + #ifdef KEEP_SENT_FD if (rfd == p[0]) { fail("Original descriptor not kept"); diff --git a/test/zdtm/static/scm02.c b/test/zdtm/static/scm02.c new file mode 120000 index 000000000..4cab0edd2 --- /dev/null +++ b/test/zdtm/static/scm02.c @@ -0,0 +1 @@ +scm00.c \ No newline at end of file diff --git a/test/zdtm/static/scm02.desc b/test/zdtm/static/scm02.desc new file mode 100644 index 000000000..ded89879a --- /dev/null +++ b/test/zdtm/static/scm02.desc @@ -0,0 +1 @@ +{'flags': 'crfail'} From ff90e847ac68da242b1c73b9d464885fca62bf9d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:38:20 +0300 Subject: [PATCH 1075/4375] zdtm: Send two descriptors in one message Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/scm03.c | 126 ++++++++++++++++++++++++++++++++++++ test/zdtm/static/scm03.desc | 1 + 3 files changed, 128 insertions(+) create mode 100644 test/zdtm/static/scm03.c create mode 100644 test/zdtm/static/scm03.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 69d7d0560..b3fd2182f 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -156,6 +156,7 @@ TST_NOFILE := \ scm00 \ scm01 \ scm02 \ + scm03 \ aio00 \ aio01 \ fd \ diff --git a/test/zdtm/static/scm03.c b/test/zdtm/static/scm03.c new file mode 100644 index 000000000..9e89628e8 --- /dev/null +++ b/test/zdtm/static/scm03.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check that SCM_RIGHTS are preserved"; +const char *test_author = "Pavel Emelyanov "; + +static int send_fd(int via, int fd1, int fd2) +{ + struct msghdr h = {}; + struct cmsghdr *ch; + struct iovec iov; + char buf[CMSG_SPACE(2 * sizeof(int))], c = '\0'; + int *fdp; + + h.msg_control = buf; + h.msg_controllen = sizeof(buf); + ch = CMSG_FIRSTHDR(&h); + ch->cmsg_level = SOL_SOCKET; + ch->cmsg_type = SCM_RIGHTS; + ch->cmsg_len = CMSG_LEN(2 * sizeof(int)); + fdp = (int *)CMSG_DATA(ch); + fdp[0] = fd1; + fdp[1] = fd2; + h.msg_iov = &iov; + h.msg_iovlen = 1; + iov.iov_base = &c; + iov.iov_len = sizeof(c); + + if (sendmsg(via, &h, 0) <= 0) + return -1; + + return 0; +} + +static int recv_fd(int via, int *fd1, int *fd2) +{ + struct msghdr h = {}; + struct cmsghdr *ch; + struct iovec iov; + char buf[CMSG_SPACE(2 * sizeof(int))], c; + int *fdp; + + h.msg_control = buf; + h.msg_controllen = sizeof(buf); + h.msg_iov = &iov; + h.msg_iovlen = 1; + iov.iov_base = &c; + iov.iov_len = sizeof(c); + + if (recvmsg(via, &h, 0) <= 0) + return -1; + + ch = CMSG_FIRSTHDR(&h); + if (h.msg_flags & MSG_TRUNC) + return -2; + if (ch == NULL) + return -3; + if (ch->cmsg_type != SCM_RIGHTS) + return -4; + + fdp = (int *)CMSG_DATA(ch); + *fd1 = fdp[0]; + *fd2 = fdp[1]; + return 0; +} + +int main(int argc, char **argv) +{ + int sk[2], p[2]; +#define MSG "HELLO" + char buf[8]; /* bigger than the MSG to check boundaries */ + + test_init(argc, argv); + + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sk) < 0) { + pr_perror("Can't make unix pair"); + exit(1); + } + + if (pipe(p) < 0) { + pr_perror("Can't make pipe"); + exit(1); + } + + if (send_fd(sk[0], p[0], p[1]) < 0) { + pr_perror("Can't send descriptor"); + exit(1); + } + + close(p[0]); + close(p[1]); + p[0] = p[1] = -1; + + test_daemon(); + test_waitsig(); + + if (recv_fd(sk[1], &p[0], &p[1]) < 0) { + fail("Can't recv pipes back"); + goto out; + } + + if (write(p[1], MSG, sizeof(MSG)) != sizeof(MSG)) { + fail("Pipe write-broken"); + goto out; + } + + if (read(p[0], buf, sizeof(buf)) != sizeof(MSG)) { + fail("Pipe read-broken"); + goto out; + } + + if (strcmp(buf, MSG)) { + buf[sizeof(buf) - 1] = '\0'; + fail("Pipe read-broken (%s)", buf); + goto out; + } + + pass(); +out: + return 0; +} diff --git a/test/zdtm/static/scm03.desc b/test/zdtm/static/scm03.desc new file mode 100644 index 000000000..ded89879a --- /dev/null +++ b/test/zdtm/static/scm03.desc @@ -0,0 +1 @@ +{'flags': 'crfail'} From 49a2cbd62f80e98c898630842ba392f0d999b276 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:38:36 +0300 Subject: [PATCH 1076/4375] zdtm: Send two descriptors in two SCMs Only the send code is altered, as upon receiving kernel merges all scm_rights int one. CRIU relies on this merge and this is to catch situations if the kernel suddenly stops doing this. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 2 ++ test/zdtm/static/scm03.c | 31 +++++++++++++++++++++++++++++-- test/zdtm/static/scm04.c | 1 + test/zdtm/static/scm04.desc | 1 + 4 files changed, 33 insertions(+), 2 deletions(-) create mode 120000 test/zdtm/static/scm04.c create mode 100644 test/zdtm/static/scm04.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index b3fd2182f..9d0cb24aa 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -157,6 +157,7 @@ TST_NOFILE := \ scm01 \ scm02 \ scm03 \ + scm04 \ aio00 \ aio01 \ fd \ @@ -444,6 +445,7 @@ sigpending: LDLIBS += -lrt vdso01: LDLIBS += -lrt scm01: CFLAGS += -DKEEP_SENT_FD scm02: CFLAGS += -DSEND_BOTH +scm04: CFLAGS += -DSEPARATE mntns_link_remap: CFLAGS += -DZDTM_LINK_REMAP mntns_shared_bind02: CFLAGS += -DSHARED_BIND02 mntns_root_bind02: CFLAGS += -DROOT_BIND02 diff --git a/test/zdtm/static/scm03.c b/test/zdtm/static/scm03.c index 9e89628e8..881bdf8e7 100644 --- a/test/zdtm/static/scm03.c +++ b/test/zdtm/static/scm03.c @@ -14,11 +14,30 @@ static int send_fd(int via, int fd1, int fd2) struct msghdr h = {}; struct cmsghdr *ch; struct iovec iov; - char buf[CMSG_SPACE(2 * sizeof(int))], c = '\0'; +#ifdef SEPARATE + char buf[2 * CMSG_SPACE(sizeof(int))]; +#else + char buf[CMSG_SPACE(2 * sizeof(int))]; +#endif + char c = '\0'; int *fdp; h.msg_control = buf; h.msg_controllen = sizeof(buf); +#ifdef SEPARATE + ch = CMSG_FIRSTHDR(&h); + ch->cmsg_level = SOL_SOCKET; + ch->cmsg_type = SCM_RIGHTS; + ch->cmsg_len = CMSG_LEN(sizeof(int)); + fdp = (int *)CMSG_DATA(ch); + fdp[0] = fd1; + ch = CMSG_NXTHDR(&h, ch); + ch->cmsg_level = SOL_SOCKET; + ch->cmsg_type = SCM_RIGHTS; + ch->cmsg_len = CMSG_LEN(sizeof(int)); + fdp = (int *)CMSG_DATA(ch); + fdp[0] = fd2; +#else ch = CMSG_FIRSTHDR(&h); ch->cmsg_level = SOL_SOCKET; ch->cmsg_type = SCM_RIGHTS; @@ -26,6 +45,7 @@ static int send_fd(int via, int fd1, int fd2) fdp = (int *)CMSG_DATA(ch); fdp[0] = fd1; fdp[1] = fd2; +#endif h.msg_iov = &iov; h.msg_iovlen = 1; iov.iov_base = &c; @@ -42,7 +62,8 @@ static int recv_fd(int via, int *fd1, int *fd2) struct msghdr h = {}; struct cmsghdr *ch; struct iovec iov; - char buf[CMSG_SPACE(2 * sizeof(int))], c; + char buf[CMSG_SPACE(2 * sizeof(int))]; + char c; int *fdp; h.msg_control = buf; @@ -55,6 +76,12 @@ static int recv_fd(int via, int *fd1, int *fd2) if (recvmsg(via, &h, 0) <= 0) return -1; + if (h.msg_flags & MSG_CTRUNC) { + test_msg("CTR\n"); + return -2; + } + + /* No 2 SCM-s here, kernel merges them upon send */ ch = CMSG_FIRSTHDR(&h); if (h.msg_flags & MSG_TRUNC) return -2; diff --git a/test/zdtm/static/scm04.c b/test/zdtm/static/scm04.c new file mode 120000 index 000000000..f1f86dd8b --- /dev/null +++ b/test/zdtm/static/scm04.c @@ -0,0 +1 @@ +scm03.c \ No newline at end of file diff --git a/test/zdtm/static/scm04.desc b/test/zdtm/static/scm04.desc new file mode 100644 index 000000000..ded89879a --- /dev/null +++ b/test/zdtm/static/scm04.desc @@ -0,0 +1 @@ +{'flags': 'crfail'} From 73a1f362fed864a7ec92e0d43f386a163069b2ad Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:38:51 +0300 Subject: [PATCH 1077/4375] tty: Prepare for no parasite_ctl SCM-dumping code won't provide the ctl for TTY dump. To make this work we'll have to peek required tty info from current (see the SCM patch), but I doubt that anyone sends TTYs via sockets ... so keep this in TODO list. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/tty.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/criu/tty.c b/criu/tty.c index f5f4ef9c0..250bcdaef 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -1760,6 +1760,11 @@ static int dump_tty_info(int lfd, u32 id, const struct fd_parms *p, struct tty_d int ret = -1; + if (!p->fd_ctl) { + pr_err("No CTL for TTY dump, likely SCM case\n"); + return -1; + } + /* * Make sure the structures the system provides us * correlates well with protobuf templates. From c0e929abc55d5a9c8831035f1e0985bc3746c62c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:39:05 +0300 Subject: [PATCH 1078/4375] fifo: Generate unique ID for satellite regfile entry The plan is to have all file entries have unique ID. Fifo generates a reg file entry to reuse the whole reg-files c/r-ing engine (ghosts, open-by-path, etc.) and right now ID for this entry is the same as for fifo entry. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/fifo.c | 14 +++++++++++--- images/fifo.proto | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/criu/fifo.c b/criu/fifo.c index d0728e1b0..a26934319 100644 --- a/criu/fifo.c +++ b/criu/fifo.c @@ -8,6 +8,7 @@ #include "image.h" #include "files.h" #include "files-reg.h" +#include "file-ids.h" #include "pipes.h" #include "fifo.h" @@ -43,13 +44,16 @@ static int dump_one_fifo(int lfd, u32 id, const struct fd_parms *p) struct cr_img *img = img_from_set(glob_imgset, CR_FD_FILES); FileEntry fe = FILE_ENTRY__INIT; FifoEntry e = FIFO_ENTRY__INIT; + u32 rf_id; + + fd_id_generate_special(NULL, &rf_id); /* * It's a trick here, we use regular files dumping * code to save path to a fifo, then we reuse it * on restore. */ - if (dump_one_reg_file(lfd, id, p)) + if (dump_one_reg_file(lfd, rf_id, p)) return -1; pr_info("Dumping fifo %d with id %#x pipe_id %#x\n", @@ -57,6 +61,8 @@ static int dump_one_fifo(int lfd, u32 id, const struct fd_parms *p) e.id = id; e.pipe_id = pipe_id(p); + e.has_regf_id = true; + e.regf_id = rf_id; fe.type = FD_TYPES__FIFO; fe.id = e.id; @@ -116,8 +122,10 @@ static int open_fifo_fd(struct file_desc *d, int *new_fd) struct file_desc *reg_d; int fd; - reg_d = find_file_desc_raw(FD_TYPES__REG, info->fe->id); - BUG_ON(!reg_d); + reg_d = collect_special_file(info->fe->has_regf_id ? + info->fe->regf_id : info->fe->id); + if (!reg_d) + return -1; fd = open_path(reg_d, do_open_fifo, info); if (fd < 0) diff --git a/images/fifo.proto b/images/fifo.proto index 9d5b9538b..f5b3283ff 100644 --- a/images/fifo.proto +++ b/images/fifo.proto @@ -3,4 +3,5 @@ syntax = "proto2"; message fifo_entry { required uint32 id = 1; required uint32 pipe_id = 2; + optional uint32 regf_id = 3; } From d4c6e785159cc5428ce1b9b29b4336e28fe1aed1 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:39:19 +0300 Subject: [PATCH 1079/4375] tty: Generate unique ID for satellite regfile entry Same thing as for fifo-s. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/tty.c | 18 ++++++++++++++---- images/tty.proto | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/criu/tty.c b/criu/tty.c index 250bcdaef..cd2370ba9 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -1626,7 +1626,8 @@ static int tty_info_setup(struct tty_info *info) * reg file rectord because they are inherited from * command line on restore. */ - info->reg_d = try_collect_special_file(info->tfe->id, 1); + info->reg_d = try_collect_special_file( info->tfe->has_regf_id ? + info->tfe->regf_id : info->tfe->id, 1); if (!info->reg_d) { if (info->driver->type != TTY_TYPE__EXT_TTY) { if (!deprecated_ok("TTY w/o regfile")) @@ -1904,14 +1905,23 @@ static int dump_one_tty(int lfd, u32 id, const struct fd_parms *p) return -1; } - if (driver->type != TTY_TYPE__EXT_TTY && dump_one_reg_file(lfd, id, p)) - return -1; - e.id = id; e.tty_info_id = tty_gen_id(driver, index); e.flags = p->flags; e.fown = (FownEntry *)&p->fown; + if (driver->type != TTY_TYPE__EXT_TTY) { + u32 rf_id; + + fd_id_generate_special(NULL, &rf_id); + if (dump_one_reg_file(lfd, rf_id, p)) + return -1; + + e.has_regf_id = true; + e.regf_id = rf_id; + } + + /* * FIXME * diff --git a/images/tty.proto b/images/tty.proto index 739a4ffed..c282cc2ef 100644 --- a/images/tty.proto +++ b/images/tty.proto @@ -81,4 +81,5 @@ message tty_file_entry { required uint32 flags = 3 [(criu).hex = true]; required fown_entry fown = 4; + optional uint32 regf_id = 6; } From 05abfa5d741c27ee3cd3d58cfb653c5b86710a68 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:39:35 +0300 Subject: [PATCH 1080/4375] fdinfo: Extract FdinfoEntry from dump_one_file To support SCMs we'll need to receive them into criu task (see the SCM patch for details), then dump the received file as if it was in the dumpee. Then the info about received descriptor will be written into packet entry. For this we'll need to perform all the regular file dumping code BUT not write the FdinfoEntry into image, so shuffle the code for that. The gist of the patch is in two changes -- one in the do_dump_gen_file(), the other in dump_task_files_seized(). The rest is just tossing the arguments of the functions relevant to that change. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/files-ext.c | 4 +-- criu/files.c | 57 +++++++++++++++++++++--------------------- criu/include/files.h | 4 +-- criu/include/sockets.h | 3 ++- criu/sockets.c | 4 +-- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/criu/files-ext.c b/criu/files-ext.c index af9c2681a..a6247d673 100644 --- a/criu/files-ext.c +++ b/criu/files-ext.c @@ -84,11 +84,11 @@ struct collect_image_info ext_file_cinfo = { }; int dump_unsupp_fd(struct fd_parms *p, int lfd, - struct cr_img *img, char *more, char *info) + char *more, char *info, FdinfoEntry *e) { int ret; - ret = do_dump_gen_file(p, lfd, &ext_dump_ops, img); + ret = do_dump_gen_file(p, lfd, &ext_dump_ops, e); if (ret == 0) return 0; if (ret == -ENOTSUP) diff --git a/criu/files.c b/criu/files.c index d5f15fe2b..cf926d02e 100644 --- a/criu/files.c +++ b/criu/files.c @@ -278,27 +278,20 @@ static u32 make_gen_id(const struct fd_parms *p) } int do_dump_gen_file(struct fd_parms *p, int lfd, - const struct fdtype_ops *ops, struct cr_img *img) + const struct fdtype_ops *ops, FdinfoEntry *e) { - FdinfoEntry e = FDINFO_ENTRY__INIT; int ret = -1; - e.type = ops->type; - e.id = make_gen_id(p); - e.fd = p->fd; - e.flags = p->fd_flags; + e->type = ops->type; + e->id = make_gen_id(p); + e->fd = p->fd; + e->flags = p->fd_flags; - ret = fd_id_generate(p->pid, &e, p); + ret = fd_id_generate(p->pid, e, p); if (ret == 1) /* new ID generated */ - ret = ops->dump(lfd, e.id, p); + ret = ops->dump(lfd, e->id, p); - if (ret < 0) - return ret; - - pr_info("fdinfo: type: %#2x flags: %#o/%#o pos: %#8"PRIx64" fd: %d\n", - ops->type, p->flags, (int)p->fd_flags, p->pos, p->fd); - - return pb_write_one(img, &e, PB_FDINFO); + return ret; } int fill_fdlink(int lfd, const struct fd_parms *p, struct fd_link *link) @@ -407,7 +400,7 @@ static const struct fdtype_ops *get_mem_dev_ops(struct fd_parms *p, int minor) return ops; } -static int dump_chrdev(struct fd_parms *p, int lfd, struct cr_img *img) +static int dump_chrdev(struct fd_parms *p, int lfd, FdinfoEntry *e) { struct fd_link *link_old = p->link; int maj = major(p->stat.st_rdev); @@ -436,19 +429,19 @@ static int dump_chrdev(struct fd_parms *p, int lfd, struct cr_img *img) } sprintf(more, "%d:%d", maj, minor(p->stat.st_rdev)); - err = dump_unsupp_fd(p, lfd, img, "chr", more); + err = dump_unsupp_fd(p, lfd, "chr", more, e); p->link = link_old; return err; } } - err = do_dump_gen_file(p, lfd, ops, img); + err = do_dump_gen_file(p, lfd, ops, e); p->link = link_old; return err; } static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, - struct cr_img *img, struct parasite_ctl *ctl) + struct parasite_ctl *ctl, FdinfoEntry *e) { struct fd_parms p = FD_PARMS_INIT; const struct fdtype_ops *ops; @@ -465,10 +458,10 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, p.fd_ctl = ctl; /* Some dump_opts require this to talk to parasite */ if (S_ISSOCK(p.stat.st_mode)) - return dump_socket(&p, lfd, img); + return dump_socket(&p, lfd, e); if (S_ISCHR(p.stat.st_mode)) - return dump_chrdev(&p, lfd, img); + return dump_chrdev(&p, lfd, e); if (p.fs_type == ANON_INODE_FS_MAGIC) { char link[32]; @@ -489,9 +482,9 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, else if (is_timerfd_link(link)) ops = &timerfd_dump_ops; else - return dump_unsupp_fd(&p, lfd, img, "anon", link); + return dump_unsupp_fd(&p, lfd, "anon", link, e); - return do_dump_gen_file(&p, lfd, ops, img); + return do_dump_gen_file(&p, lfd, ops, e); } if (S_ISREG(p.stat.st_mode) || S_ISDIR(p.stat.st_mode)) { @@ -500,12 +493,12 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, p.link = &link; if (link.name[1] == '/') - return do_dump_gen_file(&p, lfd, ®file_dump_ops, img); + return do_dump_gen_file(&p, lfd, ®file_dump_ops, e); if (check_ns_proc(&link)) - return do_dump_gen_file(&p, lfd, &nsfile_dump_ops, img); + return do_dump_gen_file(&p, lfd, &nsfile_dump_ops, e); - return dump_unsupp_fd(&p, lfd, img, "reg", link.name + 1); + return dump_unsupp_fd(&p, lfd, "reg", link.name + 1, e); } if (S_ISFIFO(p.stat.st_mode)) { @@ -514,7 +507,7 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, else ops = &fifo_dump_ops; - return do_dump_gen_file(&p, lfd, ops, img); + return do_dump_gen_file(&p, lfd, ops, e); } /* @@ -525,7 +518,7 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, if (fill_fdlink(lfd, &p, &link)) memzero(&link, sizeof(link)); - return dump_unsupp_fd(&p, lfd, img, "unknown", link.name + 1); + return dump_unsupp_fd(&p, lfd, "unknown", link.name + 1, e); } int dump_task_files_seized(struct parasite_ctl *ctl, struct pstree_item *item, @@ -564,11 +557,17 @@ int dump_task_files_seized(struct parasite_ctl *ctl, struct pstree_item *item, goto err; for (i = 0; i < nr_fds; i++) { + FdinfoEntry e = FDINFO_ENTRY__INIT; + ret = dump_one_file(item->pid, dfds->fds[i + off], - lfds[i], opts + i, img, ctl); + lfds[i], opts + i, ctl, &e); close(lfds[i]); if (ret) break; + + ret = pb_write_one(img, &e, PB_FDINFO); + if (ret) + break; } } diff --git a/criu/include/files.h b/criu/include/files.h index 7c8e0153b..2b067623e 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -135,7 +135,7 @@ struct cr_img; extern int do_dump_gen_file(struct fd_parms *p, int lfd, const struct fdtype_ops *ops, - struct cr_img *); + FdinfoEntry *e); struct parasite_drain_fd; int dump_task_files_seized(struct parasite_ctl *ctl, struct pstree_item *item, struct parasite_drain_fd *dfds); @@ -175,7 +175,7 @@ extern int shared_fdt_prepare(struct pstree_item *item); extern struct collect_image_info ext_file_cinfo; extern int dump_unsupp_fd(struct fd_parms *p, int lfd, - struct cr_img *, char *more, char *info); + char *more, char *info, FdinfoEntry *); extern int inherit_fd_parse(char *optarg); extern int inherit_fd_add(int fd, char *key); diff --git a/criu/include/sockets.h b/criu/include/sockets.h index 798c3b890..c93177f7f 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -5,6 +5,7 @@ #include #include "images/sk-opts.pb-c.h" +#include "images/fdinfo.pb-c.h" struct fdinfo_list_entry; struct sk_opts_entry; @@ -21,7 +22,7 @@ struct socket_desc { int already_dumped; }; -extern int dump_socket(struct fd_parms *p, int lfd, struct cr_img *); +extern int dump_socket(struct fd_parms *p, int lfd, FdinfoEntry *); extern int dump_socket_opts(int sk, SkOptsEntry *soe); extern int restore_socket_opts(int sk, SkOptsEntry *soe); extern void release_skopts(SkOptsEntry *); diff --git a/criu/sockets.c b/criu/sockets.c index a783be87a..c2a5cd130 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -552,7 +552,7 @@ void release_skopts(SkOptsEntry *soe) xfree(soe->so_bound_dev); } -int dump_socket(struct fd_parms *p, int lfd, struct cr_img *img) +int dump_socket(struct fd_parms *p, int lfd, FdinfoEntry *e) { int family; const struct fdtype_ops *ops; @@ -581,7 +581,7 @@ int dump_socket(struct fd_parms *p, int lfd, struct cr_img *img) return -1; } - return do_dump_gen_file(p, lfd, ops, img); + return do_dump_gen_file(p, lfd, ops, e); } static int inet_receive_one(struct nlmsghdr *h, void *arg) From 858f150931b0bd25efb7404aaa6cff9d9e6593e3 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:39:50 +0300 Subject: [PATCH 1081/4375] file: Find descs by ID only (v2) Actually all file-s we dump have unique IDs, regardless of their types. This fact will be used to reduce complexity of the SCM code -- instead of keeping TYPE:ID pair it'll save only the ID. Siad that -- we will need the way to lookup desc by ID only. v2: Older images had fifo-s and tty-s having matching IDs with respective reg-file entries Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/files.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/criu/files.c b/criu/files.c index cf926d02e..d3d3d3058 100644 --- a/criu/files.c +++ b/criu/files.c @@ -89,7 +89,15 @@ struct file_desc *find_file_desc_raw(int type, u32 id) chain = &file_desc_hash[id % FDESC_HASH_SIZE]; hlist_for_each_entry(d, chain, hash) - if (d->ops->type == type && d->id == id) + if ((d->id == id) && + (d->ops->type == type || type == FD_TYPES__UND)) + /* + * Warning -- old CRIU might generate matching IDs + * for different file types! So any code that uses + * FD_TYPES__UND for fdesc search MUST make sure it's + * dealing with the merged files images where all + * descs are forced to have different IDs. + */ return d; return NULL; From 67c572dff7960a019112b09ae81c0710b21398e9 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:40:06 +0300 Subject: [PATCH 1082/4375] fd: Helper for local fd dump An aux code to dump the received file and report back its ID and type. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/files.c | 17 +++++++++++++++++ criu/include/files.h | 1 + 2 files changed, 18 insertions(+) diff --git a/criu/files.c b/criu/files.c index d3d3d3058..12b3aa5e1 100644 --- a/criu/files.c +++ b/criu/files.c @@ -529,6 +529,23 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, return dump_unsupp_fd(&p, lfd, "unknown", link.name + 1, e); } +int dump_my_file(int lfd, u32 *id, int *type) +{ + struct pid me = {}; + struct fd_opts fo = {}; + FdinfoEntry e = FDINFO_ENTRY__INIT; + + me.real = getpid(); + me.ns[0].virt = -1; /* FIXME */ + + if (dump_one_file(&me, lfd, lfd, &fo, NULL, &e)) + return -1; + + *id = e.id; + *type = e.type; + return 0; +} + int dump_task_files_seized(struct parasite_ctl *ctl, struct pstree_item *item, struct parasite_drain_fd *dfds) { diff --git a/criu/include/files.h b/criu/include/files.h index 2b067623e..e962d77cf 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -133,6 +133,7 @@ struct fdtype_ops { struct cr_img; +extern int dump_my_file(int lfd, u32 *, int *type); extern int do_dump_gen_file(struct fd_parms *p, int lfd, const struct fdtype_ops *ops, FdinfoEntry *e); From 0d1dac2b7c0f70f61789f90830bde3522f93620a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:40:21 +0300 Subject: [PATCH 1083/4375] fd: Split file_master In SCM patch we'll need to generate temporary fdinfo entry for a task that will send descriptors via sockets. Sometimes the files in questions will NOT have any other fdinfo-s (if they are SCM-sent and closed), so we need a helper that would either give us existing fdinfo or say there's no such. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/files.c | 17 ++++++++++++++--- criu/include/files.h | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/criu/files.c b/criu/files.c index 12b3aa5e1..1924945ac 100644 --- a/criu/files.c +++ b/criu/files.c @@ -194,16 +194,27 @@ void wait_fds_event(void) clear_fds_event(); } +struct fdinfo_list_entry *try_file_master(struct file_desc *d) +{ + if (list_empty(&d->fd_info_head)) + return NULL; + + return list_first_entry(&d->fd_info_head, + struct fdinfo_list_entry, desc_list); +} + struct fdinfo_list_entry *file_master(struct file_desc *d) { - if (list_empty(&d->fd_info_head)) { + struct fdinfo_list_entry *fle; + + fle = try_file_master(d); + if (!fle) { pr_err("Empty list on file desc id %#x(%d)\n", d->id, d->ops ? d->ops->type : -1); BUG(); } - return list_first_entry(&d->fd_info_head, - struct fdinfo_list_entry, desc_list); + return fle; } void show_saved_files(void) diff --git a/criu/include/files.h b/criu/include/files.h index e962d77cf..50fe53638 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -144,6 +144,7 @@ int predump_task_files(int pid); extern void file_desc_init(struct file_desc *d, u32 id, struct file_desc_ops *ops); extern int file_desc_add(struct file_desc *d, u32 id, struct file_desc_ops *ops); +extern struct fdinfo_list_entry *try_file_master(struct file_desc *d); extern struct fdinfo_list_entry *file_master(struct file_desc *d); extern struct file_desc *find_file_desc_raw(int type, u32 id); From fefc408b5fa1d5a1978ec057ff43cc74b8b653b1 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:40:36 +0300 Subject: [PATCH 1084/4375] fd: Split fdinfo collect routine In SCM code there will be the need to attach a newly created FdinfoEntry to a particulat file desc object, then get the created fdinfo helper object back. Current code only allows this via two lookup calls -- first one to attach entry to desc by ID (lookup #1), then get the fdinfo helper by FD (lookup #2). Fortunately, the exising code allows simple split that gives us the optimized routine. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/files.c | 26 ++++++++++++++++++-------- criu/include/files.h | 2 ++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/criu/files.c b/criu/files.c index 1924945ac..7ac8a2e00 100644 --- a/criu/files.c +++ b/criu/files.c @@ -761,26 +761,36 @@ static void collect_desc_fle(struct fdinfo_list_entry *new_le, struct file_desc list_add_tail(&new_le->desc_list, &le->desc_list); } -int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info, bool fake) +struct fdinfo_list_entry *collect_fd_to(int pid, FdinfoEntry *e, + struct rst_info *rst_info, struct file_desc *fdesc, bool fake) { struct fdinfo_list_entry *new_le; + + new_le = alloc_fle(pid, e); + if (new_le) { + new_le->fake = (!!fake); + collect_desc_fle(new_le, fdesc); + collect_task_fd(new_le, rst_info); + } + + return new_le; +} + +int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info, bool fake) +{ struct file_desc *fdesc; pr_info("Collect fdinfo pid=%d fd=%d id=%#x\n", pid, e->fd, e->id); - new_le = alloc_fle(pid, e); - if (!new_le) - return -1; - new_le->fake = (!!fake); - fdesc = find_file_desc(e); if (fdesc == NULL) { pr_err("No file for fd %d id %#x\n", e->fd, e->id); return -1; } - collect_desc_fle(new_le, fdesc); - collect_task_fd(new_le, rst_info); + + if (!collect_fd_to(pid, e, rst_info, fdesc, fake)) + return -1; return 0; } diff --git a/criu/include/files.h b/criu/include/files.h index 50fe53638..0f134c99d 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -112,6 +112,8 @@ struct file_desc_ops { int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info, bool ghost); void collect_task_fd(struct fdinfo_list_entry *new_fle, struct rst_info *ri); +struct fdinfo_list_entry *collect_fd_to(int pid, FdinfoEntry *e, + struct rst_info *rst_info, struct file_desc *fdesc, bool fake); unsigned int find_unused_fd(struct pstree_item *, int hint_fd); struct fdinfo_list_entry *find_used_fd(struct pstree_item *, int fd); From 4bf3942a153e57e25d531b2b7e8569bc3726e381 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:40:50 +0300 Subject: [PATCH 1085/4375] unix: Set queuer in set_peer For SCM restore we need to know all queuers, even if they are socketpair-s, but current code skips this setting for one half of them. So set this info for every socket out there. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index c787659be..d8f73b4f9 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1457,6 +1457,8 @@ static void set_peer(struct unix_sk_info *ui, struct unix_sk_info *peer) { ui->peer = peer; list_add(&ui->node, &peer->connected); + if (!peer->queuer) + peer->queuer = ui->ue->ino; } static void interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *peer) @@ -1496,8 +1498,6 @@ static int resolve_unix_peer(struct unix_sk_info *ui) } set_peer(ui, peer); - if (!peer->queuer) - peer->queuer = ui->ue->ino; if (ui == peer) /* socket connected to self %) */ goto out; From a73914cf725aaa40f47e4ed9e9abb0184b7d8103 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:41:04 +0300 Subject: [PATCH 1086/4375] unix: Use queuer id, not ino The sk-queue.img keeps socket IDs as recepient descriptor. For SCM code we'll need to find the unix sk info who is the sender for a particular other socket by this ID. There's already the queuer field in the unix_sk_info, but it needs to be an ID rather than inode. Fortunately, id-inode pairs are unique. Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index d8f73b4f9..a30f9aca5 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -974,7 +974,7 @@ static int post_open_unix_sk(struct file_desc *d, int fd) revert_unix_sk_cwd(&cwd_fd, &root_fd); - if (peer->queuer == ui->ue->ino && restore_sk_queue(fd, peer->ue->id)) + if (peer->queuer == ui->ue->id && restore_sk_queue(fd, peer->ue->id)) return -1; return restore_sk_common(fd, ui); @@ -1458,7 +1458,7 @@ static void set_peer(struct unix_sk_info *ui, struct unix_sk_info *peer) ui->peer = peer; list_add(&ui->node, &peer->connected); if (!peer->queuer) - peer->queuer = ui->ue->ino; + peer->queuer = ui->ue->id; } static void interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *peer) From 5c84e93ec8132c8b758e18835de80bff3c77187a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:41:19 +0300 Subject: [PATCH 1087/4375] unix: Split resolv and interconnect (v2) In order to make sender of a descriptor (unix socket) be restored _after_ the descriptor in question, we need to find out those sockets early (before post-prep calls). The problem is that current code gives us info about who's the queuer for who only in post-prep hooks, so the peer resolution should happen right in collect callback. At the same time we need to make sure that all peers configured in the image exist, as well as need to put master/slave flags for socketpairs. Both these actions can only happen in post-prep. Said that -- the current peer resolve routine should be split into two steps. v2: Handle the socket connected to self (dgram) Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 60 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index a30f9aca5..0dac2f845 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1370,14 +1370,15 @@ static void unlink_stale(struct unix_sk_info *ui) revert_unix_sk_cwd(&cwd_fd, &root_fd); } -static int resolve_unix_peer(struct unix_sk_info *ui); +static void try_resolve_unix_peer(struct unix_sk_info *ui); +static int fixup_unix_peer(struct unix_sk_info *ui); static int post_prepare_unix_sk(struct pprep_head *ph) { struct unix_sk_info *ui; ui = container_of(ph, struct unix_sk_info, peer_resolve); - if (ui->ue->peer && resolve_unix_peer(ui)) + if (ui->ue->peer && fixup_unix_peer(ui)) return -1; if (ui->name) unlink_stale(ui); @@ -1437,6 +1438,9 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) ui->name_dir ? ui->name_dir : "-"); if (ui->ue->peer || ui->name) { + if (ui->ue->peer) + try_resolve_unix_peer(ui); + ui->peer_resolve.actor = post_prepare_unix_sk; add_post_prepare_cb(&ui->peer_resolve); } @@ -1481,38 +1485,50 @@ static void interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *pe } } -static int resolve_unix_peer(struct unix_sk_info *ui) +static int fixup_unix_peer(struct unix_sk_info *ui) { - struct unix_sk_info *peer; + struct unix_sk_info *peer = ui->peer; - if (ui->peer) - goto out; - - BUG_ON(!ui->ue->peer); - - peer = find_unix_sk_by_ino(ui->ue->peer); if (!peer) { pr_err("FATAL: Peer %#x unresolved for %#x\n", ui->ue->peer, ui->ue->ino); return -1; } - set_peer(ui, peer); - if (ui == peer) - /* socket connected to self %) */ - goto out; - if (peer->ue->peer != ui->ue->ino) - goto out; + if (peer != ui && peer->peer == ui && + !(ui->flags & (USK_PAIR_MASTER | USK_PAIR_SLAVE))) { + pr_info("Connected %#x -> %#x (%#x) flags %#x\n", + ui->ue->ino, ui->ue->peer, peer->ue->ino, ui->flags); + /* socketpair or interconnected sockets */ + interconnected_pair(ui, peer); + } - pr_info("Connected %#x -> %#x (%#x) flags %#x\n", - ui->ue->ino, ui->ue->peer, peer->ue->ino, ui->flags); - set_peer(peer, ui); - /* socketpair or interconnected sockets */ - interconnected_pair(ui, peer); -out: return 0; } +static void try_resolve_unix_peer(struct unix_sk_info *ui) +{ + struct unix_sk_info *peer; + + if (ui->peer) + return; + + BUG_ON(!ui->ue->peer); + + if (ui->ue->peer == ui->ue->ino) { + /* socket connected to self %) */ + set_peer(ui, ui); + return; + } + + peer = find_unix_sk_by_ino(ui->ue->peer); + if (peer) { + set_peer(ui, peer); + if (peer->ue->peer == ui->ue->ino) + set_peer(peer, ui); + } /* else -- maybe later */ +} + int unix_sk_id_add(unsigned int ino) { char *e_str; From ff91d4f721ea21d37f78d8fe8e185003abcc4764 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:41:33 +0300 Subject: [PATCH 1088/4375] skqueue: Split the packets sending code Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/sk-queue.c | 50 ++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/criu/sk-queue.c b/criu/sk-queue.c index 28578b4a7..057c0bf46 100644 --- a/criu/sk-queue.c +++ b/criu/sk-queue.c @@ -197,6 +197,34 @@ err_brk: return ret; } +static int send_one_pkt(int fd, struct sk_packet *pkt) +{ + int ret; + SkPacketEntry *entry = pkt->entry; + + /* + * Don't try to use sendfile here, because it use sendpage() and + * all data are split on pages and a new skb is allocated for + * each page. It creates a big overhead on SNDBUF. + * sendfile() isn't suitable for DGRAM sockets, because message + * boundaries messages should be saved. + */ + + ret = write(fd, pkt->data, entry->length); + xfree(pkt->data); + if (ret < 0) { + pr_perror("Failed to send packet"); + return -1; + } + if (ret != entry->length) { + pr_err("Restored skb trimmed to %d/%d\n", + ret, (unsigned int)entry->length); + return -1; + } + + return 0; +} + int restore_sk_queue(int fd, unsigned int peer_id) { struct sk_packet *pkt, *tmp; @@ -216,26 +244,10 @@ int restore_sk_queue(int fd, unsigned int peer_id) pr_info("\tRestoring %d-bytes skb for %u\n", (unsigned int)entry->length, peer_id); - /* - * Don't try to use sendfile here, because it use sendpage() and - * all data are split on pages and a new skb is allocated for - * each page. It creates a big overhead on SNDBUF. - * sendfile() isn't suitable for DGRAM sockets, because message - * boundaries messages should be saved. - */ + ret = send_one_pkt(fd, pkt); + if (ret) + goto out; - ret = write(fd, pkt->data, entry->length); - xfree(pkt->data); - if (ret < 0) { - pr_perror("Failed to send packet"); - goto out; - } - if (ret != entry->length) { - pr_err("Restored skb trimmed to %d/%d\n", - ret, (unsigned int)entry->length); - ret = -1; - goto out; - } list_del(&pkt->list); sk_packet_entry__free_unpacked(entry, NULL); xfree(pkt); From e52341f5a300ef1557c7e22087aaa28e7219f287 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 10 Jul 2017 12:41:47 +0300 Subject: [PATCH 1089/4375] skqueue: Use sendmsg() to send data Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/sk-queue.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/criu/sk-queue.c b/criu/sk-queue.c index 057c0bf46..77e203e38 100644 --- a/criu/sk-queue.c +++ b/criu/sk-queue.c @@ -201,6 +201,13 @@ static int send_one_pkt(int fd, struct sk_packet *pkt) { int ret; SkPacketEntry *entry = pkt->entry; + struct msghdr mh = {}; + struct iovec iov; + + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + iov.iov_base = pkt->data; + iov.iov_len = entry->length; /* * Don't try to use sendfile here, because it use sendpage() and @@ -210,7 +217,7 @@ static int send_one_pkt(int fd, struct sk_packet *pkt) * boundaries messages should be saved. */ - ret = write(fd, pkt->data, entry->length); + ret = sendmsg(fd, &mh, 0); xfree(pkt->data); if (ret < 0) { pr_perror("Failed to send packet"); From 5087faa0b852ab19f7f4dcc0a03afadce12b8a0c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 13 Jul 2017 14:24:29 +0300 Subject: [PATCH 1090/4375] SCM: Dump and restore SCM_RIGHTs Most of the pieces has already been described in the previous patches :) so here's the summary. * Dump: When receiving a message, also receive any SCM-s (already there) and when SCM_RIGHTs one is met -- go ahead and just dump received descriptors using regular code, but taking current as the victim task. Few words about file paths resolution -- since we do dump path-ed files by receiving them from victim's parasite, such files sent via sockets should still work OK, as we still receive them, just from another socket. Several problems here: 1. Unix sockets sent via unix sockets form knots. Not supported. 2. Eventpolls sent via unix might themseves poll unix sockets. Knots again. Not supported either. * Restore: On restore we need to make unix socket wait for the soon-to-be-scm-sent descriptors to get restored, so we need to find them, then put a dependency. After that, the fake fdinfo entry is attached to the respective file descs, when sent the respective descriptors are closed. https://github.com/xemul/criu/issues/251 v2: Addressed comments from Kirill * Moved prepare_scms before adding fake fles (with comment) * Add scm-only fles as fake, thus removing close_scm_fds * Try hard finding any suitable fle to use as scm one when queuing them for unix socket scm list, only allocate a new one if really needed Reviewed-by: Kirill Tkhai Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 8 +++ criu/include/sockets.h | 2 + criu/sk-queue.c | 140 ++++++++++++++++++++++++++++++++++++- criu/sk-unix.c | 152 ++++++++++++++++++++++++++++++++++++++++- images/sk-packet.proto | 6 ++ 5 files changed, 303 insertions(+), 5 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 442844ee9..7086c7415 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -366,6 +366,14 @@ static int root_prepare_shared(void) if (ret) goto err; + /* + * This should be called with all packets collected AND all + * fdescs and fles prepared BUT post-prep-s not run. + */ + ret = prepare_scms(); + if (ret) + goto err; + ret = run_post_prepare(); if (ret) goto err; diff --git a/criu/include/sockets.h b/criu/include/sockets.h index c93177f7f..c0f302474 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -37,6 +37,8 @@ extern int collect_sockets(struct ns_id *); extern struct collect_image_info inet_sk_cinfo; extern struct collect_image_info unix_sk_cinfo; extern int fix_external_unix_sockets(void); +extern int prepare_scms(void); +extern int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ids); extern struct collect_image_info netlink_sk_cinfo; diff --git a/criu/sk-queue.c b/criu/sk-queue.c index 77e203e38..f3ebd6c64 100644 --- a/criu/sk-queue.c +++ b/criu/sk-queue.c @@ -18,9 +18,9 @@ #include "util.h" #include "util-pie.h" #include "sockets.h" - +#include "xmalloc.h" #include "sk-queue.h" - +#include "files.h" #include "protobuf.h" #include "images/sk-packet.pb-c.h" @@ -28,6 +28,8 @@ struct sk_packet { struct list_head list; SkPacketEntry *entry; char *data; + unsigned scm_len; + int *scm; }; static LIST_HEAD(packets_list); @@ -37,11 +39,21 @@ static int collect_one_packet(void *obj, ProtobufCMessage *msg, struct cr_img *i struct sk_packet *pkt = obj; pkt->entry = pb_msg(msg, SkPacketEntry); - + pkt->scm = NULL; pkt->data = xmalloc(pkt->entry->length); if (pkt->data ==NULL) return -1; + /* + * See dump_packet_cmsg() -- only SCM_RIGHTS are supported and + * only 1 of that kind is possible, thus not more than 1 SCMs + * on a packet. + */ + if (pkt->entry->n_scm > 1) { + pr_err("More than 1 SCM is not possible\n"); + return -1; + } + /* * NOTE: packet must be added to the tail. Otherwise sequence * will be broken. @@ -64,6 +76,50 @@ struct collect_image_info sk_queues_cinfo = { .collect = collect_one_packet, }; +static int dump_scm_rights(struct cmsghdr *ch, SkPacketEntry *pe) +{ + int nr_fds, *fds, i; + void *buf; + ScmEntry *scme; + + nr_fds = (ch->cmsg_len - sizeof(*ch)) / sizeof(int); + fds = (int *)CMSG_DATA(ch); + + buf = xmalloc(sizeof(ScmEntry) + nr_fds * sizeof(uint32_t)); + if (!buf) + return -1; + + scme = xptr_pull(&buf, ScmEntry); + scm_entry__init(scme); + scme->type = SCM_RIGHTS; + scme->n_rights = nr_fds; + scme->rights = xptr_pull_s(&buf, nr_fds * sizeof(uint32_t)); + + for (i = 0; i < nr_fds; i++) { + int ftyp; + + if (dump_my_file(fds[i], &scme->rights[i], &ftyp)) + return -1; + + /* + * Unix sent over Unix or Epoll with some other sh*t + * sent over unix (maybe with this very unix polled) + * are tricky and not supported for now. (XXX -- todo) + */ + if (ftyp == FD_TYPES__UNIXSK || ftyp == FD_TYPES__EVENTPOLL) { + pr_err("Can't dump send %d (unix/epoll) fd\n", ftyp); + return -1; + } + } + + i = pe->n_scm++; + if (xrealloc_safe(&pe->scm, pe->n_scm * sizeof(ScmEntry*))) + return -1; + + pe->scm[i] = scme; + return 0; +} + /* * Maximum size of the control messages. XXX -- is there any * way to get this value out of the kernel? @@ -73,8 +129,26 @@ struct collect_image_info sk_queues_cinfo = { static int dump_packet_cmsg(struct msghdr *mh, SkPacketEntry *pe) { struct cmsghdr *ch; + int n_rights = 0; for (ch = CMSG_FIRSTHDR(mh); ch; ch = CMSG_NXTHDR(mh, ch)) { + if (ch->cmsg_type == SCM_RIGHTS) { + if (n_rights) { + /* + * Even if user is sending more than one cmsg with + * rights, kernel merges them alltogether on recv. + */ + pr_err("Unexpected 2nd SCM_RIGHTS from the kernel\n"); + return -1; + } + + if (dump_scm_rights(ch, pe)) + return -1; + + n_rights++; + continue; + } + pr_err("Control messages in queue, not supported\n"); return -1; } @@ -82,6 +156,18 @@ static int dump_packet_cmsg(struct msghdr *mh, SkPacketEntry *pe) return 0; } +static void release_cmsg(SkPacketEntry *pe) +{ + int i; + + for (i = 0; i < pe->n_scm; i++) + xfree(pe->scm[i]); + xfree(pe->scm); + + pe->n_scm = 0; + pe->scm = NULL; +} + int dump_sk_queue(int sock_fd, int sock_id) { SkPacketEntry pe = SK_PACKET_ENTRY__INIT; @@ -181,6 +267,9 @@ int dump_sk_queue(int sock_fd, int sock_id) ret = -EIO; goto err_set_sock; } + + if (pe.scm) + release_cmsg(&pe); } ret = 0; @@ -209,6 +298,11 @@ static int send_one_pkt(int fd, struct sk_packet *pkt) iov.iov_base = pkt->data; iov.iov_len = entry->length; + if (pkt->scm != NULL) { + mh.msg_controllen = pkt->scm_len; + mh.msg_control = pkt->scm; + } + /* * Don't try to use sendfile here, because it use sendpage() and * all data are split on pages and a new skb is allocated for @@ -264,3 +358,43 @@ int restore_sk_queue(int fd, unsigned int peer_id) out: return ret; } + +int prepare_scms(void) +{ + struct sk_packet *pkt; + + pr_info("Preparing SCMs\n"); + list_for_each_entry(pkt, &packets_list, list) { + SkPacketEntry *pe = pkt->entry; + ScmEntry *se; + struct cmsghdr *ch; + + if (!pe->n_scm) + continue; + + se = pe->scm[0]; /* Only 1 SCM is possible */ + + if (se->type == SCM_RIGHTS) { + pkt->scm_len = CMSG_SPACE(se->n_rights * sizeof(int)); + pkt->scm = xmalloc(pkt->scm_len); + if (!pkt->scm) + return -1; + + ch = (struct cmsghdr *)pkt->scm; /* FIXME -- via msghdr */ + ch->cmsg_level = SOL_SOCKET; + ch->cmsg_type = SCM_RIGHTS; + ch->cmsg_len = CMSG_LEN(se->n_rights * sizeof(int)); + + if (unix_note_scm_rights(pe->id_for, se->rights, + (int *)CMSG_DATA(ch), se->n_rights)) + return -1; + + continue; + } + + pr_err("Unsupported scm %d in image\n", se->type); + return -1; + } + + return 0; +} diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 0dac2f845..16b4bf3ec 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -795,6 +795,7 @@ struct unix_sk_info { struct file_desc d; struct list_head connected; /* List of sockets, connected to me */ struct list_head node; /* To link in peer's connected list */ + struct list_head scm_fles; /* * For DGRAM sockets with queues, we should only restore the queue @@ -806,6 +807,11 @@ struct unix_sk_info { u8 listen:1; }; +struct scm_fle { + struct list_head l; + struct fdinfo_list_entry *fle; +}; + #define USK_PAIR_MASTER 0x1 #define USK_PAIR_SLAVE 0x2 @@ -821,6 +827,141 @@ static struct unix_sk_info *find_unix_sk_by_ino(int ino) return NULL; } +static struct unix_sk_info *find_queuer_for(int id) +{ + struct unix_sk_info *ui; + + list_for_each_entry(ui, &unix_sockets, list) { + if (ui->queuer == id) + return ui; + } + + return NULL; +} + +static struct fdinfo_list_entry *get_fle_for_scm(struct file_desc *tgt, + struct pstree_item *owner) +{ + struct fdinfo_list_entry *fle; + FdinfoEntry *e = NULL; + int fd; + + list_for_each_entry(fle, &tgt->fd_info_head, desc_list) { + if (fle->task == owner) + /* + * Owner already has this file in its fdtable. + * Just use one. + */ + return fle; + + e = fle->fe; /* keep any for further reference */ + } + + /* + * Some other task restores this file. Pretend that + * we're another user of it. + */ + fd = find_unused_fd(owner, -1); + pr_info("`- will add SCM-only %d fd\n", fd); + + if (e != NULL) { + e = dup_fdinfo(e, fd, 0); + if (!e) { + pr_err("Can't duplicate fdinfo for scm\n"); + return NULL; + } + } else { + /* + * This can happen if the file in question is + * sent over the socket and closed. In this case + * we need to ... invent a new one! + */ + + e = xmalloc(sizeof(*e)); + if (!e) + return NULL; + + fdinfo_entry__init(e); + e->id = tgt->id; + e->type = tgt->ops->type; + e->fd = fd; + e->flags = 0; + } + + /* + * Make this fle fake, so that files collecting engine + * closes them at the end. + */ + return collect_fd_to(vpid(owner), e, rsti(owner), tgt, true); +} + +int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ids) +{ + struct unix_sk_info *ui; + struct pstree_item *owner; + int i; + + ui = find_queuer_for(id_for); + if (!ui) { + pr_err("Can't find sender for %d\n", id_for); + return -1; + } + + pr_info("Found queuer for %d -> %d\n", id_for, ui->ue->id); + /* + * This is the task that will restore this socket + */ + owner = file_master(&ui->d)->task; + + pr_info("-> will set up deps\n"); + /* + * The ui will send data to the rights receiver. Add a fake fle + * for the file and a dependency. + */ + for (i = 0; i < n_ids; i++) { + struct file_desc *tgt; + struct scm_fle *sfle; + + tgt = find_file_desc_raw(FD_TYPES__UND, file_ids[i]); + if (!tgt) { + pr_err("Can't find fdesc to send\n"); + return -1; + } + + pr_info("scm: add file %d -> %d\n", tgt->id, vpid(owner)); + sfle = xmalloc(sizeof(*sfle)); + if (!sfle) + return -1; + + sfle->fle = get_fle_for_scm(tgt, owner); + if (!sfle->fle) { + pr_err("Can't request new fle for scm\n"); + return -1; + } + + list_add_tail(&sfle->l, &ui->scm_fles); + fds[i] = sfle->fle->fe->fd; + } + + return 0; +} + +static int chk_restored_scms(struct unix_sk_info *ui) +{ + struct scm_fle *sf, *n; + + list_for_each_entry_safe(sf, n, &ui->scm_fles, l) { + if (sf->fle->stage < FLE_OPEN) + return 1; + + /* Optimization for the next pass */ + list_del(&sf->l); + xfree(sf); + } + + return 0; +} + static int wake_connected_sockets(struct unix_sk_info *ui) { struct fdinfo_list_entry *fle; @@ -1306,12 +1447,18 @@ static int open_unix_sk(struct file_desc *d, int *new_fd) struct unix_sk_info *ui; int ret; + ui = container_of(d, struct unix_sk_info, d); + + /* FIXME -- only queue restore may be postponed */ + if (chk_restored_scms(ui)) { + pr_info("scm: Wait for tgt to restore\n"); + return 1; + } + fle = file_master(d); if (fle->stage >= FLE_OPEN) return post_open_unix_sk(d, fle->fe->fd); - ui = container_of(d, struct unix_sk_info, d); - if (inherited_fd(d, new_fd)) { ui->ue->uflags |= USK_INHERIT; ret = *new_fd >= 0 ? 0 : -1; @@ -1410,6 +1557,7 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) ui->listen = 0; INIT_LIST_HEAD(&ui->connected); INIT_LIST_HEAD(&ui->node); + INIT_LIST_HEAD(&ui->scm_fles); ui->flags = 0; uname = ui->name; diff --git a/images/sk-packet.proto b/images/sk-packet.proto index 5f61c7376..dcda280f6 100644 --- a/images/sk-packet.proto +++ b/images/sk-packet.proto @@ -1,6 +1,12 @@ syntax = "proto2"; +message scm_entry { + required uint32 type = 1; + repeated uint32 rights = 2; +} + message sk_packet_entry { required uint32 id_for = 1; required uint32 length = 2; + repeated scm_entry scm = 4; } From fd9fd56883f236c02b87177ae37877d8e9b3dc46 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 18 Aug 2017 18:19:00 +0300 Subject: [PATCH 1091/4375] test: Zeroify scm buffer before filling The CMSG_NXTHDR checks the length of the __next__ cmsg, i.e. the one that it is about to return for filling. Thus, keeping there anything but zeroes is unsafe. Reported-by: Pavel Tikhomirov Signed-off-by: Pavel Emelyanov --- test/zdtm/static/scm03.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/zdtm/static/scm03.c b/test/zdtm/static/scm03.c index 881bdf8e7..cf6049781 100644 --- a/test/zdtm/static/scm03.c +++ b/test/zdtm/static/scm03.c @@ -22,6 +22,7 @@ static int send_fd(int via, int fd1, int fd2) char c = '\0'; int *fdp; + memset(buf, 0, sizeof(buf)); h.msg_control = buf; h.msg_controllen = sizeof(buf); #ifdef SEPARATE From 62cc04df6901b0dc1b7db76b079189a48959d94d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 17 Oct 2017 11:44:06 +0300 Subject: [PATCH 1092/4375] test: Scm tests no longer fail :) Signed-off-by: Pavel Emelyanov --- test/zdtm/static/scm00.desc | 1 - test/zdtm/static/scm01.desc | 1 - test/zdtm/static/scm02.desc | 1 - test/zdtm/static/scm03.desc | 1 - test/zdtm/static/scm04.desc | 1 - 5 files changed, 5 deletions(-) delete mode 100644 test/zdtm/static/scm00.desc delete mode 100644 test/zdtm/static/scm01.desc delete mode 100644 test/zdtm/static/scm02.desc delete mode 100644 test/zdtm/static/scm03.desc delete mode 100644 test/zdtm/static/scm04.desc diff --git a/test/zdtm/static/scm00.desc b/test/zdtm/static/scm00.desc deleted file mode 100644 index ded89879a..000000000 --- a/test/zdtm/static/scm00.desc +++ /dev/null @@ -1 +0,0 @@ -{'flags': 'crfail'} diff --git a/test/zdtm/static/scm01.desc b/test/zdtm/static/scm01.desc deleted file mode 100644 index ded89879a..000000000 --- a/test/zdtm/static/scm01.desc +++ /dev/null @@ -1 +0,0 @@ -{'flags': 'crfail'} diff --git a/test/zdtm/static/scm02.desc b/test/zdtm/static/scm02.desc deleted file mode 100644 index ded89879a..000000000 --- a/test/zdtm/static/scm02.desc +++ /dev/null @@ -1 +0,0 @@ -{'flags': 'crfail'} diff --git a/test/zdtm/static/scm03.desc b/test/zdtm/static/scm03.desc deleted file mode 100644 index ded89879a..000000000 --- a/test/zdtm/static/scm03.desc +++ /dev/null @@ -1 +0,0 @@ -{'flags': 'crfail'} diff --git a/test/zdtm/static/scm04.desc b/test/zdtm/static/scm04.desc deleted file mode 100644 index ded89879a..000000000 --- a/test/zdtm/static/scm04.desc +++ /dev/null @@ -1 +0,0 @@ -{'flags': 'crfail'} From 9ad12876691483a8c14cc4394db0f8f9fcdfd8c5 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 15 Oct 2017 09:16:40 +0300 Subject: [PATCH 1093/4375] travis/lazy-pages: exclude lazy-thp for older kernels The lazy-thp may fail with older kernels if khugepaded will be fast enough to merge pages in the partially populated areas. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 55adb4e96..d4321aed6 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -84,7 +84,7 @@ if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then else LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns -x socket_listen -x socket_listen6 -x cmdlinenv00 - -x socket_close_data01 -x file_read" + -x socket_close_data01 -x file_read -x lazy-thp" fi LAZY_EXCLUDE="$LAZY_EXCLUDE -x maps04" From 342019bb07162db2c1bf106c4fec35b0c61e5879 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 17 Oct 2017 09:34:52 +0300 Subject: [PATCH 1094/4375] zdtm: avoid arithmetic overflow in datagen and datachk p + FAST_SIZE > buffer + length In this sentence p + FAST_SIZE may be bigger than (1<<32), and we will be in trouble. $ gdb -c coredump test/zdtm/static/write_read01 (gdb) p p $3 = (uint8_t *) 0xffffa89e (gdb) p buffer $4 = (uint8_t *) 0xfff06780 (gdb) p length $5 = 1000000 Signed-off-by: Andrei Vagin --- test/zdtm/lib/datagen.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/test/zdtm/lib/datagen.c b/test/zdtm/lib/datagen.c index 550339c40..83fbea285 100644 --- a/test/zdtm/lib/datagen.c +++ b/test/zdtm/lib/datagen.c @@ -14,42 +14,42 @@ static void datagen_fast(uint8_t *buffer, unsigned length, uint32_t *crc) { - uint8_t *p; + size_t off; datagen(buffer, FAST_SIZE, crc); - p = buffer + FAST_SIZE; + off = FAST_SIZE; - while (p < buffer + length) { + while (off < length) { unsigned long size = FAST_SIZE; - if (p + FAST_SIZE > buffer + length) - size = buffer + length - p; - memcpy(p, buffer, size); + if (off + FAST_SIZE > length) + size = length - off; + memcpy(buffer + off, buffer, size); - p += FAST_SIZE; + off += size; } } static int datachk_fast(const uint8_t *buffer, unsigned length, uint32_t *crc) { - const uint8_t *p; + size_t off; if (datachk(buffer, FAST_SIZE, crc)) return 1; - p = buffer + FAST_SIZE; + off = FAST_SIZE; - while (p < buffer + length) { + while (off < length) { unsigned long size = FAST_SIZE; - if (p + FAST_SIZE > buffer + length) - size = buffer + length - p; + if (off + FAST_SIZE > length) + size = length - off; - if (memcmp(p, buffer, size)) { - test_msg("Memory corruption [%p, %p]\n", p, p + size); + if (memcmp(buffer + off, buffer, size)) { + test_msg("Memory corruption [%p, %p]\n", buffer, buffer + size); return 1; } - p += FAST_SIZE; + off += size; } return 0; From b53d90692d84f3c04ceb43080973553407e1e231 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 17 Oct 2017 22:38:34 +0100 Subject: [PATCH 1095/4375] compel: Add R_X86_64{,_REX}_GOTPCRELX relocs Add handeling of R_X86_64_GOTPCRELX and R_X86_64_REX_GOTPCRELX. They are not that old, so I provided ifdef-guards for them. According to x86-64 ABI specification paper, they should be generated instead of R_X86_64_GOTPCREL for cases when relaxation is possible. At this moment we can handle them the same way like R_X86_64_GOTPCREL. [0] https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-r249.pdf Fixes: #397 Cc: Cyrill Gorcunov Reported-by: Adrian Reber Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/include/handle-elf.h | 8 ++++++++ compel/src/lib/handle-elf.c | 2 ++ 2 files changed, 10 insertions(+) diff --git a/compel/arch/x86/src/lib/include/handle-elf.h b/compel/arch/x86/src/lib/include/handle-elf.h index 08de8363f..e68fe3bcf 100644 --- a/compel/arch/x86/src/lib/include/handle-elf.h +++ b/compel/arch/x86/src/lib/include/handle-elf.h @@ -5,6 +5,14 @@ #define ELF_X86_64 +#ifndef R_X86_64_GOTPCRELX +# define R_X86_64_GOTPCRELX 41 +#endif + +#ifndef R_X86_64_REX_GOTPCRELX +# define R_X86_64_REX_GOTPCRELX 42 +#endif + #define __handle_elf handle_elf_x86_64 #define arch_is_machine_supported(e_machine) (e_machine == EM_X86_64) diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index bf94d93b6..f1cf74ff4 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -517,6 +517,8 @@ int __handle_elf(void *mem, size_t size) */ *((int32_t *)where) = value32 + addend32 - place; break; + case R_X86_64_GOTPCRELX: + case R_X86_64_REX_GOTPCRELX: case R_X86_64_GOTPCREL: /* SymbolOffsetInGot + GOT + Addend - Place (4 bytes) */ pr_debug("\t\t\t\tR_X86_64_GOTPCREL at 0x%-4lx val 0x%x\n", place, value32); pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_LONG | COMPEL_TYPE_GOTPCREL, " From d0a8aa748284b55bd57ecba2279966599516c772 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 19 Oct 2017 21:11:38 +0300 Subject: [PATCH 1096/4375] aarch64: copy the sigcontext structure from the kernel headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Its declaration was changed in glibc headers and we don't want to handle two version of itю In file included from compel/include/uapi/compel/infect.h:6:0, from compel/include/uapi/compel/compel.h:12, from compel/include/log.h:4, from compel/arch/aarch64/src/lib/infect.c:8: compel/arch/aarch64/src/lib/infect.c: In function 'sigreturn_prep_regs_plain': compel/include/uapi/compel/asm/sigframe.h:47:99: error: 'mcontext_t {aka struct }' has no member named '__reserved'; did you mean '__glibc_reserved1'? #define RT_SIGFRAME_AUX_CONTEXT(rt_sigframe) ((struct aux_context*)&(rt_sigframe)->uc.uc_mcontext.__reserved) ^ compel/include/uapi/compel/asm/sigframe.h:48:41: note: in expansion of macro 'RT_SIGFRAME_AUX_CONTEXT' #define RT_SIGFRAME_FPU(rt_sigframe) (&RT_SIGFRAME_AUX_CONTEXT(rt_sigframe)->fpsimd) ^~~~~~~~~~~~~~~~~~~~~~~ compel/arch/aarch64/src/lib/infect.c:34:34: note: in expansion of macro 'RT_SIGFRAME_FPU' struct fpsimd_context *fpsimd = RT_SIGFRAME_FPU(sigframe); ^~~~~~~~~~~~~~~ make[1]: *** [/builddir/build/BUILD/criu-3.5/scripts/nmk/scripts/build.mk:209: compel/arch/aarch64/src/lib/infect.o] Error 1 make: *** [Makefile.compel:36: compel/libcompel.a] Error 2 error: Bad exit status from /var/tmp/rpm-tmp.IExY9K (%build) This seems to be related to the following glibc changes: https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=4fa9b3bfe6759c82beb4b043a54a3598ca467289 Reported-by: Adrian Reber Tested-by: Adrian Reber Signed-off-by: Andrei Vagin --- .../aarch64/src/lib/include/uapi/asm/sigframe.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h b/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h index 22246b8fa..6b511ce0c 100644 --- a/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h @@ -41,10 +41,23 @@ struct rt_sigframe { : "r"(new_sp) \ : "sp", "x8", "memory") +/* cr_sigcontext is copied from arch/arm64/include/uapi/asm/sigcontext.h */ +struct cr_sigcontext { + __u64 fault_address; + /* AArch64 registers */ + __u64 regs[31]; + __u64 sp; + __u64 pc; + __u64 pstate; + /* 4K reserved for FP/SIMD state and future expansion */ + __u8 __reserved[4096] __attribute__((__aligned__(16))); +}; + #define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->uc) #define RT_SIGFRAME_REGIP(rt_sigframe) ((long unsigned int)(rt_sigframe)->uc.uc_mcontext.pc) #define RT_SIGFRAME_HAS_FPU(rt_sigframe) (1) -#define RT_SIGFRAME_AUX_CONTEXT(rt_sigframe) ((struct aux_context*)&(rt_sigframe)->uc.uc_mcontext.__reserved) +#define RT_SIGFRAME_SIGCONTEXT(rt_sigframe) ((struct cr_sigcontext *)&(rt_sigframe)->uc.uc_mcontext) +#define RT_SIGFRAME_AUX_CONTEXT(rt_sigframe) ((struct aux_context*)&(RT_SIGFRAME_SIGCONTEXT(rt_sigframe)->__reserved)) #define RT_SIGFRAME_FPU(rt_sigframe) (&RT_SIGFRAME_AUX_CONTEXT(rt_sigframe)->fpsimd) #define RT_SIGFRAME_OFFSET(rt_sigframe) 0 From 15b29140a8832eff44cfb09cc6e543613dceee47 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 17 Oct 2017 22:22:57 +0300 Subject: [PATCH 1097/4375] travis: check compilation for arm64v8/fedora:rawhide Signed-off-by: Andrei Vagin --- .travis.yml | 2 ++ scripts/build/Dockerfile.fedora-rawhide-aarch64.hdr | 3 +++ scripts/build/Dockerfile.fedora-rawhide-aarch64.tmpl | 1 + scripts/build/Makefile | 4 +--- 4 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 scripts/build/Dockerfile.fedora-rawhide-aarch64.hdr create mode 120000 scripts/build/Dockerfile.fedora-rawhide-aarch64.tmpl diff --git a/.travis.yml b/.travis.yml index 5baee546d..ff2e09b83 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,10 +21,12 @@ env: - TR_ARCH=alpine CLANG=1 - TR_ARCH=docker-test - TR_ARCH=fedora-rawhide + - TR_ARCH=fedora-rawhide-aarch64 matrix: allow_failures: - env: TR_ARCH=docker-test - env: TR_ARCH=fedora-rawhide + - env: TR_ARCH=fedora-rawhide-aarch64 script: - sudo make CCACHE=1 -C scripts/travis $TR_ARCH after_success: diff --git a/scripts/build/Dockerfile.fedora-rawhide-aarch64.hdr b/scripts/build/Dockerfile.fedora-rawhide-aarch64.hdr new file mode 100644 index 000000000..82f29e336 --- /dev/null +++ b/scripts/build/Dockerfile.fedora-rawhide-aarch64.hdr @@ -0,0 +1,3 @@ +FROM arm64v8/fedora:rawhide + +COPY scripts/build/qemu-user-static/usr/bin/qemu-aarch64-static /usr/bin/qemu-aarch64-static diff --git a/scripts/build/Dockerfile.fedora-rawhide-aarch64.tmpl b/scripts/build/Dockerfile.fedora-rawhide-aarch64.tmpl new file mode 120000 index 000000000..e4c40309c --- /dev/null +++ b/scripts/build/Dockerfile.fedora-rawhide-aarch64.tmpl @@ -0,0 +1 @@ +Dockerfile.fedora.tmpl \ No newline at end of file diff --git a/scripts/build/Makefile b/scripts/build/Makefile index 21330be77..dbf599de3 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -1,4 +1,4 @@ -QEMU_ARCHES := armv7hf aarch64 ppc64le s390x # require qemu +QEMU_ARCHES := armv7hf aarch64 ppc64le s390x fedora-rawhide-aarch64 # require qemu ARCHES := $(QEMU_ARCHES) x86_64 fedora-asan fedora-rawhide TARGETS := $(ARCHES) alpine TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) @@ -38,8 +38,6 @@ endef $(foreach t,$(TARGETS),$(eval $(call CLANG_DEP,$(t)))) %-clang: DB_CC=--build-arg CC=clang -Dockerfile.fedora-asan: override DOCKER_TMPL=Dockerfile.fedora.tmpl -Dockerfile.fedora-rawhide: override DOCKER_TMPL=Dockerfile.fedora.tmpl %-clang: DB_ENV=--build-arg ENV1=CCACHE_CPP2 s390x-clang: DB_CC=--build-arg CC=clang-3.8 .PHONY: $(TARGETS_CLANG) From 086df7e5709f5c09c79647abced914388c80de2b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 23 Oct 2017 14:23:02 +0300 Subject: [PATCH 1098/4375] criu: Version 3.6 As usually -- many bugfixes and several new features. The s390x stuff goes well too. The most tempting new feature is the ability to dump and restore files sent over unix sockets (SCM_RIGHTS). Signed-off-by: Pavel Emelyanov --- Makefile.versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index aef41a6e7..f92388e74 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 5 +CRIU_VERSION_MINOR := 6 CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Clay Jay +CRIU_VERSION_NAME := Alabaster Finch CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From 8e92c9f241698da831fa33f5a2bed3224f4de361 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 8 Aug 2017 14:44:29 +0300 Subject: [PATCH 1099/4375] cr-check: make uffd verification "extra" rather then "experimental" Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-check.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/cr-check.c b/criu/cr-check.c index 8986ec405..21d241f68 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1166,6 +1166,8 @@ int cr_check(void) ret |= check_userns(); ret |= check_loginuid(); ret |= check_can_map_vdso(); + ret |= check_uffd(); + ret |= check_uffd_noncoop(); } /* From b3e18c9329b4a4572780380fdf48340a8cc1d6be Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 26 Jul 2017 00:08:06 +0300 Subject: [PATCH 1100/4375] cgroup: Refactor special_props comparisons Let's add a function which will tell if cgroup property is special. Note that I do not touch restore_special_props() indention in this patch as I separate subfunction from it in the next patch, so touching this pile of code once. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cgroup.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index bb8523a40..3aea48f99 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -969,6 +969,17 @@ static const char *special_props[] = { NULL, }; +bool is_special_property(const char *prop) +{ + size_t i = 0; + + for (i = 0; special_props[i]; i++) + if (strcmp(prop, special_props[i]) == 0) + return true; + + return false; +} + static int userns_move(void *arg, int fd, pid_t pid) { char pidbuf[32]; @@ -1312,9 +1323,6 @@ static int prepare_cgroup_dir_properties(char *path, int off, CgroupDirEntry **e off2 += sprintf(path + off, "/%s", e->dir_name); if (e->n_properties > 0) { for (j = 0; j < e->n_properties; ++j) { - int k; - bool special = false; - if (!strcmp(e->properties[j]->name, "freezer.state")) { add_freezer_state_for_restore(e->properties[j], path, off2); continue; /* skip restore now */ @@ -1325,14 +1333,7 @@ static int prepare_cgroup_dir_properties(char *path, int off, CgroupDirEntry **e * the restore to fail if some other task has * entered the cgroup. */ - for (k = 0; special_props[k]; k++) { - if (!strcmp(e->properties[j]->name, special_props[k])) { - special = true; - break; - } - } - - if (special) + if (is_special_property(e->properties[j]->name)) continue; if (restore_cgroup_prop(e->properties[j], path, off2) < 0) { @@ -1372,17 +1373,16 @@ int prepare_cgroup_properties(void) static int restore_special_props(char *paux, size_t off, CgroupDirEntry *e) { - int i, j; + int j; pr_info("Restore special props\n"); - for (i = 0; special_props[i]; i++) { - const char *name = special_props[i]; + { for (j = 0; j < e->n_properties; j++) { CgroupPropEntry *prop = e->properties[j]; - if (strcmp(name, prop->name) == 0) { + if (is_special_property(prop->name)) { /* XXX: we can drop this hack and make * memory.swappiness and memory.oom_control * regular properties when we drop support for From 1668356526b5f73e9a206d112a561ecbe5c760eb Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 26 Jul 2017 00:08:07 +0300 Subject: [PATCH 1101/4375] cgroup: Use local variable prop in restore_special_props() For the purpose of separation this as a function, refactor the code to use local variable prop, so the new function will have (CgroupPropEntry *) type instead of (CgroupDirEntry *). Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cgroup.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index 3aea48f99..3df741ddd 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -1396,7 +1396,7 @@ static int restore_special_props(char *paux, size_t off, CgroupDirEntry *e) continue; } - if (!strcmp(e->properties[j]->name, "devices.list")) { + if (!strcmp(prop->name, "devices.list")) { /* The devices cgroup must be restored in a * special way: only the contents of * devices.list can be read, and it is a @@ -1410,7 +1410,7 @@ static int restore_special_props(char *paux, size_t off, CgroupDirEntry *e) * each line, because the kernel only parses * the first line of any write(). */ - CgroupPropEntry *pe = e->properties[j]; + CgroupPropEntry *pe = prop; char *old_val = pe->value, *old_name = pe->name; int ret; char *pos; @@ -1426,7 +1426,7 @@ static int restore_special_props(char *paux, size_t off, CgroupDirEntry *e) pe->name = "devices.deny"; pe->value = "a"; - ret = restore_cgroup_prop(e->properties[j], paux, off); + ret = restore_cgroup_prop(prop, paux, off); pe->name = old_name; pe->value = old_val; From f14cdada9b88b2776319c4db9d171bfed2a68019 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 26 Jul 2017 00:08:08 +0300 Subject: [PATCH 1102/4375] cgroup: Introduce restore_special_propery() To reduce restore_special_props() size - let's factor a new function for restoring one special property. No functional change expected. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cgroup.c | 172 +++++++++++++++++++++++++------------------------- 1 file changed, 85 insertions(+), 87 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index 3df741ddd..5ab4c3777 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -1371,100 +1371,98 @@ int prepare_cgroup_properties(void) return 0; } +static int restore_special_property(char *paux, size_t off, CgroupPropEntry *pr) +{ + /* + * XXX: we can drop this hack and make memory.swappiness and + * memory.oom_control regular properties when we drop support for + * kernels < 3.16. See 3dae7fec5. + */ + if (!strcmp(pr->name, "memory.swappiness") && !strcmp(pr->value, "60")) + return 0; + if (!strcmp(pr->name, "memory.oom_control") && !strcmp(pr->value, "0")) + return 0; + + if (!strcmp(pr->name, "devices.list")) { + /* + * The devices cgroup must be restored in a special way: + * only the contents of devices.list can be read, and it + * is a whitelist of all the devices the cgroup is allowed + * to create. To re-create this whitelist, we firstly deny + * everything via devices.deny, and then write the list back + * into devices.allow. + * + * Further, we must have a write() call for each line, + * because the kernel only parses the first line of + * any write(). + */ + CgroupPropEntry *pe = pr; + char *old_val = pe->value, *old_name = pe->name; + int ret; + char *pos; + + /* + * A bit of a fudge here. These are write only by owner + * by default, but the container engine could have changed + * the perms. We should come up with a better way to + * restore all of this stuff. + */ + pe->perms->mode = 0200; + + pe->name = "devices.deny"; + pe->value = "a"; + ret = restore_cgroup_prop(pr, paux, off); + pe->name = old_name; + pe->value = old_val; + + /* + * An emptry string here means nothing is allowed, + * and the kernel disallows writing an "" to devices.allow, + * so let's just keep going. + */ + if (!strcmp(pe->value, "")) + return 0; + + if (ret < 0) + return -1; + + pe->name = "devices.allow"; + + pos = pe->value; + while (*pos) { + int offset = next_device_entry(pos); + pe->value = pos; + ret = restore_cgroup_prop(pe, paux, off); + if (ret < 0) { + pe->name = old_name; + pe->value = old_val; + return -1; + } + pos += offset; + } + pe->value = old_val; + pe->name = old_name; + return 0; + } + + return restore_cgroup_prop(pr, paux, off); +} + static int restore_special_props(char *paux, size_t off, CgroupDirEntry *e) { - int j; + unsigned int j; pr_info("Restore special props\n"); - { + for (j = 0; j < e->n_properties; j++) { + CgroupPropEntry *prop = e->properties[j]; - for (j = 0; j < e->n_properties; j++) { - CgroupPropEntry *prop = e->properties[j]; + if (!is_special_property(prop->name)) + continue; - if (is_special_property(prop->name)) { - /* XXX: we can drop this hack and make - * memory.swappiness and memory.oom_control - * regular properties when we drop support for - * kernels < 3.16. See 3dae7fec5. - */ - if (!strcmp(prop->name, "memory.swappiness") && - !strcmp(prop->value, "60")) { - continue; - } else if (!strcmp(prop->name, "memory.oom_control") && - !strcmp(prop->value, "0")) { - continue; - } - - if (!strcmp(prop->name, "devices.list")) { - /* The devices cgroup must be restored in a - * special way: only the contents of - * devices.list can be read, and it is a - * whitelist of all the devices the cgroup is - * allowed to create. To re-creat this - * whitelist, we first deny everything via - * devices.deny, and then write the list back - * into devices.allow. - * - * Further, we must have a write() call for - * each line, because the kernel only parses - * the first line of any write(). - */ - CgroupPropEntry *pe = prop; - char *old_val = pe->value, *old_name = pe->name; - int ret; - char *pos; - - /* A bit of a fudge here. These are - * write only by owner by default, but - * the container engine could have - * changed the perms. We should come up - * with a better way to restore all of - * this stuff. - */ - pe->perms->mode = 0200; - - pe->name = "devices.deny"; - pe->value = "a"; - ret = restore_cgroup_prop(prop, paux, off); - pe->name = old_name; - pe->value = old_val; - - /* an emptry string here means nothing - * is allowed, and the kernel disallows - * writing an "" to devices.allow, so - * let's just keep going. - */ - if (!strcmp(pe->value, "")) - continue; - - if (ret < 0) - return -1; - - pe->name = "devices.allow"; - - pos = pe->value; - while (*pos) { - int offset = next_device_entry(pos); - pe->value = pos; - ret = restore_cgroup_prop(pe, paux, off); - if (ret < 0) { - pe->name = old_name; - pe->value = old_val; - return -1; - } - pos += offset; - } - pe->value = old_val; - pe->name = old_name; - continue; - - } - - if (restore_cgroup_prop(prop, paux, off) < 0) { - return -1; - } - } + if (restore_special_property(paux, off, prop) < 0) { + pr_err("Restoring %s special property failed\n", prop->name); + return -1; } } From 831d155ca4ed4add5e893763c2d9e9e0cc5a89c7 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 26 Jul 2017 00:08:09 +0300 Subject: [PATCH 1103/4375] cgroup: Separate devices.list cgroup restoring Now restore_special_property() only deals which special property restore and restore_devices_list() deals with devices.list. BTW, let's have two variables dev_allow and dev_deny on stack to simplify it - all this fuss with old_val and old_name kills the fun. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cgroup.c | 103 ++++++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 53 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index 5ab4c3777..fd705a643 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -1371,6 +1371,54 @@ int prepare_cgroup_properties(void) return 0; } +/* + * The devices cgroup must be restored in a special way: + * only the contents of devices.list can be read, and it is a whitelist + * of all the devices the cgroup is allowed to create. To re-create + * this whitelist, we firstly deny everything via devices.deny, + * and then write the list back into devices.allow. + * + * Further, we must have a write() call for each line, because the kernel + * only parses the first line of any write(). + */ +static int restore_devices_list(char *paux, size_t off, CgroupPropEntry *pr) +{ + CgroupPropEntry dev_allow = *pr; + CgroupPropEntry dev_deny = *pr; + char *pos; + int ret; + + dev_allow.name = "devices.allow"; + dev_deny.name = "devices.deny"; + dev_deny.value = "a"; + + ret = restore_cgroup_prop(&dev_deny, paux, off); + + /* + * An emptry string here means nothing is allowed, + * and the kernel disallows writing an "" to devices.allow, + * so let's just keep going. + */ + if (!strcmp(dev_allow.value, "")) + return 0; + + if (ret < 0) + return -1; + + pos = dev_allow.value; + while (*pos) { + int offset = next_device_entry(pos); + + dev_allow.value = pos; + ret = restore_cgroup_prop(&dev_allow, paux, off); + if (ret < 0) + return -1; + pos += offset; + } + + return 0; +} + static int restore_special_property(char *paux, size_t off, CgroupPropEntry *pr) { /* @@ -1384,65 +1432,14 @@ static int restore_special_property(char *paux, size_t off, CgroupPropEntry *pr) return 0; if (!strcmp(pr->name, "devices.list")) { - /* - * The devices cgroup must be restored in a special way: - * only the contents of devices.list can be read, and it - * is a whitelist of all the devices the cgroup is allowed - * to create. To re-create this whitelist, we firstly deny - * everything via devices.deny, and then write the list back - * into devices.allow. - * - * Further, we must have a write() call for each line, - * because the kernel only parses the first line of - * any write(). - */ - CgroupPropEntry *pe = pr; - char *old_val = pe->value, *old_name = pe->name; - int ret; - char *pos; - /* * A bit of a fudge here. These are write only by owner * by default, but the container engine could have changed * the perms. We should come up with a better way to * restore all of this stuff. */ - pe->perms->mode = 0200; - - pe->name = "devices.deny"; - pe->value = "a"; - ret = restore_cgroup_prop(pr, paux, off); - pe->name = old_name; - pe->value = old_val; - - /* - * An emptry string here means nothing is allowed, - * and the kernel disallows writing an "" to devices.allow, - * so let's just keep going. - */ - if (!strcmp(pe->value, "")) - return 0; - - if (ret < 0) - return -1; - - pe->name = "devices.allow"; - - pos = pe->value; - while (*pos) { - int offset = next_device_entry(pos); - pe->value = pos; - ret = restore_cgroup_prop(pe, paux, off); - if (ret < 0) { - pe->name = old_name; - pe->value = old_val; - return -1; - } - pos += offset; - } - pe->value = old_val; - pe->name = old_name; - return 0; + pr->perms->mode = 0200; + return restore_devices_list(paux, off, pr); } return restore_cgroup_prop(pr, paux, off); From 610e1536e95cabe0554d28240369f0f6d29b6585 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 26 Jul 2017 00:08:10 +0300 Subject: [PATCH 1104/4375] cgroup: Handle multiline properties in restore_cgroup_prop() We need to write some multiline properties line-by-line, instead of writing all buffer at once - because kernel doesn't support parsing them in one write(). Previously, it was done for devices.allow list, but I need it also for netprio.ifpriomap. To make easier reusing this code, add split_lines parameter to restore_cgroup_prop(). Dropping next_device_entry() and multiply calls to restore_cgroup_prop() also improves performance: previously for each property's line, cgroup file was re-open() and close() again, while new code only calls write() for each line, reducing number of syscalls done for each line. This also makes it suitable for future: if patch(s) for parsing all lines of property with one write() would be accepted, then we can easily change call to something: restore_cgroup_prop(&dev_allow, paux, off, !kdat.cgroup_multiline_write); We can even use split_lines = true by default for all cases, as strchrnul() will only find zero-terminator as does strlen(). But I don't want to do it - if there are cgroup files which supportes multi-line write(), it'll add syscalls. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cgroup.c | 73 +++++++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index fd705a643..ef7a4a2d5 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -1197,10 +1197,10 @@ static int restore_perms(int fd, const char *path, CgroupPerms *perms) return 0; } -static int restore_cgroup_prop(const CgroupPropEntry * cg_prop_entry_p, - char *path, int off) +static int restore_cgroup_prop(const CgroupPropEntry *cg_prop_entry_p, + char *path, int off, bool split_lines) { - int cg, fd, len, ret = -1; + int cg, fd, ret = -1; CgroupPerms *perms = cg_prop_entry_p->perms; if (!cg_prop_entry_p->value) { @@ -1231,10 +1231,28 @@ static int restore_cgroup_prop(const CgroupPropEntry * cg_prop_entry_p, goto out; } - len = strlen(cg_prop_entry_p->value); - if (write(fd, cg_prop_entry_p->value, len) != len) { - pr_perror("Failed writing %s to %s", cg_prop_entry_p->value, path); - goto out; + if (split_lines) { + char *line = cg_prop_entry_p->value; + char *next_line; + size_t len; + + do { + next_line = strchrnul(line, '\n'); + len = next_line - line; + + if (write(fd, line, len) != len) { + pr_perror("Failed writing %s to %s", line, path); + goto out; + } + line = next_line + 1; + } while(*next_line != '\0'); + } else { + size_t len = strlen(cg_prop_entry_p->value); + + if (write(fd, cg_prop_entry_p->value, len) != len) { + pr_perror("Failed writing %s to %s", cg_prop_entry_p->value, path); + goto out; + } } ret = 0; @@ -1257,7 +1275,7 @@ int restore_freezer_state(void) return 0; freezer_path_len = strlen(freezer_path); - return restore_cgroup_prop(freezer_state_entry, freezer_path, freezer_path_len); + return restore_cgroup_prop(freezer_state_entry, freezer_path, freezer_path_len, false); } static void add_freezer_state_for_restore(CgroupPropEntry *entry, char *path, size_t path_len) @@ -1289,25 +1307,6 @@ static void add_freezer_state_for_restore(CgroupPropEntry *entry, char *path, si freezer_path[path_len] = 0; } -static int next_device_entry(char *buf) -{ - char *pos = buf; - - while (1) { - if (*pos == '\n') { - *pos = '\0'; - pos++; - break; - } else if (*pos == '\0') { - break; - } - - pos++; - } - - return pos - buf; -} - static int prepare_cgroup_dir_properties(char *path, int off, CgroupDirEntry **ents, unsigned int n_ents) { @@ -1336,7 +1335,7 @@ static int prepare_cgroup_dir_properties(char *path, int off, CgroupDirEntry **e if (is_special_property(e->properties[j]->name)) continue; - if (restore_cgroup_prop(e->properties[j], path, off2) < 0) { + if (restore_cgroup_prop(e->properties[j], path, off2, false) < 0) { return -1; } @@ -1385,14 +1384,13 @@ static int restore_devices_list(char *paux, size_t off, CgroupPropEntry *pr) { CgroupPropEntry dev_allow = *pr; CgroupPropEntry dev_deny = *pr; - char *pos; int ret; dev_allow.name = "devices.allow"; dev_deny.name = "devices.deny"; dev_deny.value = "a"; - ret = restore_cgroup_prop(&dev_deny, paux, off); + ret = restore_cgroup_prop(&dev_deny, paux, off, false); /* * An emptry string here means nothing is allowed, @@ -1405,18 +1403,7 @@ static int restore_devices_list(char *paux, size_t off, CgroupPropEntry *pr) if (ret < 0) return -1; - pos = dev_allow.value; - while (*pos) { - int offset = next_device_entry(pos); - - dev_allow.value = pos; - ret = restore_cgroup_prop(&dev_allow, paux, off); - if (ret < 0) - return -1; - pos += offset; - } - - return 0; + return restore_cgroup_prop(&dev_allow, paux, off, true); } static int restore_special_property(char *paux, size_t off, CgroupPropEntry *pr) @@ -1442,7 +1429,7 @@ static int restore_special_property(char *paux, size_t off, CgroupPropEntry *pr) return restore_devices_list(paux, off, pr); } - return restore_cgroup_prop(pr, paux, off); + return restore_cgroup_prop(pr, paux, off, false); } static int restore_special_props(char *paux, size_t off, CgroupDirEntry *e) From 3fbc10f72982818154535f947738eab23e3af2ef Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 26 Jul 2017 00:08:11 +0300 Subject: [PATCH 1105/4375] cgroup: Drop useless check e->n_properties > 0 As for-cycle already checks it. While at it - add local CgroupPropEntry variable and use it. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cgroup.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index ef7a4a2d5..334c2a661 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -1320,26 +1320,24 @@ static int prepare_cgroup_dir_properties(char *path, int off, CgroupDirEntry **e goto skip; /* skip root cgroups */ off2 += sprintf(path + off, "/%s", e->dir_name); - if (e->n_properties > 0) { - for (j = 0; j < e->n_properties; ++j) { - if (!strcmp(e->properties[j]->name, "freezer.state")) { - add_freezer_state_for_restore(e->properties[j], path, off2); - continue; /* skip restore now */ - } - - /* Skip restoring special cpuset props now. - * They were restored earlier, and can cause - * the restore to fail if some other task has - * entered the cgroup. - */ - if (is_special_property(e->properties[j]->name)) - continue; - - if (restore_cgroup_prop(e->properties[j], path, off2, false) < 0) { - return -1; - } + for (j = 0; j < e->n_properties; ++j) { + CgroupPropEntry *p = e->properties[j]; + if (!strcmp(p->name, "freezer.state")) { + add_freezer_state_for_restore(p, path, off2); + continue; /* skip restore now */ } + + /* Skip restoring special cpuset props now. + * They were restored earlier, and can cause + * the restore to fail if some other task has + * entered the cgroup. + */ + if (is_special_property(p->name)) + continue; + + if (restore_cgroup_prop(p, path, off2, false) < 0) + return -1; } skip: if (prepare_cgroup_dir_properties(path, off2, e->children, e->n_children) < 0) From b8ddf85d4d540a9e6004f2ee11ad9c9f8d6bbd02 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 26 Jul 2017 00:08:12 +0300 Subject: [PATCH 1106/4375] cgroup: Split net_prio.ifpriomap writes At this moment the kernel doesn't support multi-line write() to net_prio.ifpriomap. On such write the kernel will parse only the first line. That results in the following failed restore: > (01.454153) cg: Restoring cgroup property value [lo 0 > enp5s0 0 > enp6s0 0 > br0 0 > venet0 0 > host-routed 0 > virbr0 0 > virbr0-nic 0] to [net_prio,net_cls/machine.slice/91d3ac46-380e-4d91-89d3-d2bd1eb30f97/net_prio.ifpriomap] > (01.454188) Error (criu/cgroup.c:1225): cg: Failed writing lo 0 > enp5s0 0 > enp6s0 0 > br0 0 > venet0 0 > host-routed 0 > virbr0 0 > virbr0-nic 0 to net_prio,net_cls/machine.slice/91d3ac46-380e-4d91-89d3-d2bd1eb30f97/net_prio.ifpriomap: Argument list too long > (01.472144) Error (criu/cr-restore.c:1013): 20509 killed by signal 9: Killed > (01.472391) mnt: Switching to new ns to clean ghosts > (01.472690) Error (criu/cr-restore.c:2007): Restoring FAILED. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cgroup.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index 334c2a661..ec31e05b9 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -1322,6 +1322,7 @@ static int prepare_cgroup_dir_properties(char *path, int off, CgroupDirEntry **e off2 += sprintf(path + off, "/%s", e->dir_name); for (j = 0; j < e->n_properties; ++j) { CgroupPropEntry *p = e->properties[j]; + bool split = false; if (!strcmp(p->name, "freezer.state")) { add_freezer_state_for_restore(p, path, off2); @@ -1336,7 +1337,11 @@ static int prepare_cgroup_dir_properties(char *path, int off, CgroupDirEntry **e if (is_special_property(p->name)) continue; - if (restore_cgroup_prop(p, path, off2, false) < 0) + /* The kernel can't handle it in one write() */ + if (strcmp(p->name, "net_prio.ifpriomap") == 0) + split = true; + + if (restore_cgroup_prop(p, path, off2, split) < 0) return -1; } skip: From 2408280d699d2b6c35c8cbf8d2b90ad7505afb36 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 26 Jul 2017 00:08:13 +0300 Subject: [PATCH 1107/4375] cgroup: Add skipping fails arg for writing to property net_prio.ifpriomap property may differ between hosts as they may have different number of interfaces and this cgroup property property has init-ns interfaces, not net-ns: https://www.spinics.net/lists/netdev/msg418785.html Let's skip fails if interface is no longer present on restore. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cgroup.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index ec31e05b9..d01412dc8 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -1198,7 +1198,7 @@ static int restore_perms(int fd, const char *path, CgroupPerms *perms) } static int restore_cgroup_prop(const CgroupPropEntry *cg_prop_entry_p, - char *path, int off, bool split_lines) + char *path, int off, bool split_lines, bool skip_fails) { int cg, fd, ret = -1; CgroupPerms *perms = cg_prop_entry_p->perms; @@ -1242,7 +1242,8 @@ static int restore_cgroup_prop(const CgroupPropEntry *cg_prop_entry_p, if (write(fd, line, len) != len) { pr_perror("Failed writing %s to %s", line, path); - goto out; + if (!skip_fails) + goto out; } line = next_line + 1; } while(*next_line != '\0'); @@ -1251,7 +1252,8 @@ static int restore_cgroup_prop(const CgroupPropEntry *cg_prop_entry_p, if (write(fd, cg_prop_entry_p->value, len) != len) { pr_perror("Failed writing %s to %s", cg_prop_entry_p->value, path); - goto out; + if (!skip_fails) + goto out; } } @@ -1275,7 +1277,8 @@ int restore_freezer_state(void) return 0; freezer_path_len = strlen(freezer_path); - return restore_cgroup_prop(freezer_state_entry, freezer_path, freezer_path_len, false); + return restore_cgroup_prop(freezer_state_entry, freezer_path, + freezer_path_len, false, false); } static void add_freezer_state_for_restore(CgroupPropEntry *entry, char *path, size_t path_len) @@ -1322,7 +1325,7 @@ static int prepare_cgroup_dir_properties(char *path, int off, CgroupDirEntry **e off2 += sprintf(path + off, "/%s", e->dir_name); for (j = 0; j < e->n_properties; ++j) { CgroupPropEntry *p = e->properties[j]; - bool split = false; + bool pm = false; if (!strcmp(p->name, "freezer.state")) { add_freezer_state_for_restore(p, path, off2); @@ -1337,11 +1340,14 @@ static int prepare_cgroup_dir_properties(char *path, int off, CgroupDirEntry **e if (is_special_property(p->name)) continue; - /* The kernel can't handle it in one write() */ + /* + * The kernel can't handle it in one write() + * Number of network interfaces on host may differ. + */ if (strcmp(p->name, "net_prio.ifpriomap") == 0) - split = true; + pm = true; - if (restore_cgroup_prop(p, path, off2, split) < 0) + if (restore_cgroup_prop(p, path, off2, pm, pm) < 0) return -1; } skip: @@ -1393,7 +1399,7 @@ static int restore_devices_list(char *paux, size_t off, CgroupPropEntry *pr) dev_deny.name = "devices.deny"; dev_deny.value = "a"; - ret = restore_cgroup_prop(&dev_deny, paux, off, false); + ret = restore_cgroup_prop(&dev_deny, paux, off, false, false); /* * An emptry string here means nothing is allowed, @@ -1406,7 +1412,7 @@ static int restore_devices_list(char *paux, size_t off, CgroupPropEntry *pr) if (ret < 0) return -1; - return restore_cgroup_prop(&dev_allow, paux, off, true); + return restore_cgroup_prop(&dev_allow, paux, off, true, false); } static int restore_special_property(char *paux, size_t off, CgroupPropEntry *pr) @@ -1432,7 +1438,7 @@ static int restore_special_property(char *paux, size_t off, CgroupPropEntry *pr) return restore_devices_list(paux, off, pr); } - return restore_cgroup_prop(pr, paux, off, false); + return restore_cgroup_prop(pr, paux, off, false, false); } static int restore_special_props(char *paux, size_t off, CgroupDirEntry *e) From 334c379261b6350e30886aedb4fcf3d889da1605 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 26 Jul 2017 00:08:14 +0300 Subject: [PATCH 1108/4375] cgroup: Optimize ifpriomap restoring Skip writing 0 for interfaces, as it's the default value. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cgroup.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index d01412dc8..ecf24f612 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -20,6 +20,7 @@ #include "util-pie.h" #include "namespaces.h" #include "seize.h" +#include "string.h" #include "protobuf.h" #include "images/core.pb-c.h" #include "images/cgroup.pb-c.h" @@ -1310,6 +1311,70 @@ static void add_freezer_state_for_restore(CgroupPropEntry *entry, char *path, si freezer_path[path_len] = 0; } +/* + * Filter out ifpriomap interfaces which have 0 as priority. + * As by default new ifpriomap has 0 as a priority for each + * interface, this will save up some write()'s. + * As this property is used rarely, this may save a whole bunch + * of syscalls, skipping all ifpriomap restore. + */ +static int filter_ifpriomap(char *out, char *line) +{ + char *next_line, *space; + bool written = false; + size_t len; + + if (*line == '\0') + return 0; + + do { + next_line = strchrnul(line, '\n'); + len = next_line - line; + + space = strchr(line, ' '); + if (!space) { + pr_err("Invalid value for ifpriomap: `%s'\n", line); + return -1; + } + + if (!strtol(space, NULL, 10)) + goto next; + + /* Copying with last \n or \0 */ + strncpy(out, line, len + 1); + out += len + 1; + written = true; +next: + line = next_line + 1; + } while(*next_line != '\0'); + + if (written) + *(out - 1) = '\0'; + + return 0; +} + +static int restore_cgroup_ifpriomap(CgroupPropEntry *cpe, char *path, int off) +{ + CgroupPropEntry priomap = *cpe; + int ret = -1; + + priomap.value = xmalloc(strlen(cpe->value) + 1); + priomap.value[0] = '\0'; + + if (filter_ifpriomap(priomap.value, cpe->value)) + goto out; + + if (strlen(priomap.value)) + ret = restore_cgroup_prop(&priomap, path, off, true, true); + else + ret = 0; + +out: + xfree(priomap.value); + return ret; +} + static int prepare_cgroup_dir_properties(char *path, int off, CgroupDirEntry **ents, unsigned int n_ents) { @@ -1325,7 +1390,6 @@ static int prepare_cgroup_dir_properties(char *path, int off, CgroupDirEntry **e off2 += sprintf(path + off, "/%s", e->dir_name); for (j = 0; j < e->n_properties; ++j) { CgroupPropEntry *p = e->properties[j]; - bool pm = false; if (!strcmp(p->name, "freezer.state")) { add_freezer_state_for_restore(p, path, off2); @@ -1344,10 +1408,13 @@ static int prepare_cgroup_dir_properties(char *path, int off, CgroupDirEntry **e * The kernel can't handle it in one write() * Number of network interfaces on host may differ. */ - if (strcmp(p->name, "net_prio.ifpriomap") == 0) - pm = true; + if (strcmp(p->name, "net_prio.ifpriomap") == 0) { + if (restore_cgroup_ifpriomap(p, path, off2)) + return -1; + continue; + } - if (restore_cgroup_prop(p, path, off2, pm, pm) < 0) + if (restore_cgroup_prop(p, path, off2, false, false) < 0) return -1; } skip: From 0f9ed59527a27abf293eb70378f857a680b5526c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 26 Jul 2017 00:08:15 +0300 Subject: [PATCH 1109/4375] zdtm/cgroup: Fix misnamed array deny => dev_allow Those are devices which are written to devices.allow cgroup. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/cgroup04.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/zdtm/static/cgroup04.c b/test/zdtm/static/cgroup04.c index 812a9a3c2..6998358ef 100644 --- a/test/zdtm/static/cgroup04.c +++ b/test/zdtm/static/cgroup04.c @@ -115,7 +115,7 @@ int main(int argc, char **argv) char buf[1024], path[PATH_MAX]; struct stat sb; - char *deny[] = { + char *dev_allow[] = { "c *:* m", "b *:* m", "c 1:3 rwm", @@ -136,8 +136,8 @@ int main(int argc, char **argv) /* need to allow /dev/null for restore */ sprintf(path, "%s/devices/%s/devices.allow", dirname, cgname); - for (i = 0; i < ARRAY_SIZE(deny); i++) { - if (write_value(path, deny[i]) < 0) + for (i = 0; i < ARRAY_SIZE(dev_allow); i++) { + if (write_value(path, dev_allow[i]) < 0) goto out; } @@ -148,8 +148,8 @@ int main(int argc, char **argv) test_waitsig(); buf[0] = 0; - for (i = 0; i < ARRAY_SIZE(deny); i++) { - strcat(buf, deny[i]); + for (i = 0; i < ARRAY_SIZE(dev_allow); i++) { + strcat(buf, dev_allow[i]); strcat(buf, "\n"); } From 95d6621ccd9450da09de0b21ed72affe723752fe Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 26 Jul 2017 00:08:16 +0300 Subject: [PATCH 1110/4375] zdtm/cgroup: Add test for ifpriomap A test to check C/R of multiline cgroup net_prio.ifpriomap. Before this patches set restoring of this file failed as it's a multiline cgroup property and kernel can read it only line-by-line. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/cgroup_ifpriomap.c | 271 +++++++++++++++++++++++++ test/zdtm/static/cgroup_ifpriomap.desc | 1 + test/zdtm/static/cgroup_ifpriomap.hook | 15 ++ 4 files changed, 288 insertions(+) create mode 100644 test/zdtm/static/cgroup_ifpriomap.c create mode 100644 test/zdtm/static/cgroup_ifpriomap.desc create mode 100755 test/zdtm/static/cgroup_ifpriomap.hook diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 9d0cb24aa..de9ca7467 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -277,6 +277,7 @@ TST_DIR = \ cgroup02 \ cgroup03 \ cgroup04 \ + cgroup_ifpriomap \ cgroup_stray \ unlink_fstat04 \ mntns_remap \ diff --git a/test/zdtm/static/cgroup_ifpriomap.c b/test/zdtm/static/cgroup_ifpriomap.c new file mode 100644 index 000000000..d14508060 --- /dev/null +++ b/test/zdtm/static/cgroup_ifpriomap.c @@ -0,0 +1,271 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check preserving multiline cgroup controller's property net_prio/net_prio.ifpriomap"; +const char *test_author = "Dmitry Safonov "; + +char *dirname; +TEST_OPTION(dirname, string, "cgroup directory name", 1); + +static const char *cgname = "zdtmtst"; + +#define BUF_SZ 1024 +#define PRIOMAPS_SZ 40 + +struct ifpriomap_t { + char *ifname; + uint32_t prio; +}; +struct ifpriomap_t maps[PRIOMAPS_SZ], new_maps[PRIOMAPS_SZ]; + +static int mount_cg(const char *controller) +{ + char mnt_point[BUF_SZ], subdir[BUF_SZ]; + char tasks_path[BUF_SZ], pid_str[BUF_SZ]; + int fd; + + sprintf(mnt_point, "%s/%s", dirname, controller); + sprintf(subdir, "%s/%s/%s", dirname, controller, cgname); + sprintf(pid_str, "%d", getpid()); + sprintf(tasks_path, "%s/%s/%s/tasks", dirname, controller, cgname); + + if (mkdir(dirname, 0700) < 0 && errno != EEXIST) { + pr_perror("Can't make dir"); + return -1; + } + if (mkdir(mnt_point, 0700) < 0) { + pr_perror("Can't make dir `%s'", mnt_point); + return -1; + } + if (mount("none", mnt_point, "cgroup", 0, controller)) { + pr_perror("Can't mount cgroups"); + goto err_rm; + } + if (mkdir(subdir, 0700) < 0 && errno != EEXIST) { + pr_perror("Can't make dir `%s'", subdir); + goto err_umount; + } + + /* Add self to newly created cgroup */ + fd = open(tasks_path, O_WRONLY); + if (fd < 0) { + pr_perror("Failed to open `%s'", tasks_path); + goto err_controller; + } + if (write(fd, pid_str, strlen(pid_str)) != strlen(pid_str)) { + pr_perror("failed to write `%s' to `%s'", pid_str, tasks_path); + close(fd); + goto err_controller; + } + + close(fd); + return 0; + +err_controller: + rmdir(subdir); +err_umount: + umount(mnt_point); +err_rm: + rmdir(mnt_point); + return -1; +} + +static int umount_cg(const char *controller) +{ + char mnt_point[BUF_SZ], subdir[BUF_SZ]; + + sprintf(mnt_point, "%s/%s", dirname, controller); + sprintf(subdir, "%s/%s/%s", dirname, controller, cgname); + + rmdir(subdir); + + return umount(mnt_point); +} + +static int read_one_priomap(char *prop_line, struct ifpriomap_t *out) +{ + char *space; + size_t len; + + space = strchr(prop_line, ' '); + if (!space) { + pr_err("Broken ifpriomap file line: `%s'\n", prop_line); + return -1; + } + len = space - prop_line; + + out->ifname = malloc(len + 1); + strncpy(out->ifname, prop_line, len); + out->ifname[len] = '\0'; /* poor man's strlcpy() */ + out->prio = (uint32_t)strtol(space + 1, NULL, 10); + + return 0; +} + +static int read_map(const char *path, struct ifpriomap_t *out, size_t out_sz) +{ + char buf[BUF_SZ]; + FILE *fpriomap; + size_t i; + + fpriomap = fopen(path, "r"); + if (!fpriomap) { + pr_perror("Failed to open `%s'", path); + return -1; + } + + for (i = 0; i < out_sz; i++) { + if (!fgets(buf, BUF_SZ, fpriomap)) + break; + + if (read_one_priomap(buf, &out[i])) { + fclose(fpriomap); + return -1; + } + } + + if (fclose(fpriomap)) { + pr_perror("Failed to close `%s'", path); + return -1; + } + + return 0; +} + +static int write_map(const char *path, struct ifpriomap_t *out, size_t out_sz) +{ + char buf[BUF_SZ]; + ssize_t written; + size_t i; + int fd; + + fd = open(path, O_WRONLY); + if (fd < 0) { + pr_perror("Failed to open `%s'", path); + return -1; + } + + for (i = 0; i < out_sz; i++) { + struct ifpriomap_t *p = &out[i]; + + if (!p->ifname) + break; + + snprintf(buf, BUF_SZ, "%s %lu", + p->ifname, (unsigned long)p->prio); + + written = write(fd, buf, strlen(buf)); + if (written < 0) { + pr_perror("Failed to write `%s' to `%s'", buf, path); + close(fd); + return -1; + } + } + + if (close(fd)) { + pr_perror("Failed to close `%s'", path); + return -1; + } + + return 0; +} + +static void randomize_map(struct ifpriomap_t *out, size_t out_sz) +{ + size_t i; + + for (i = 0; i < out_sz; i++) { + struct ifpriomap_t *p = &out[i]; + + if (!p->ifname) + return; + + p->prio += rand(); + } +} + +static int compare_maps(void) +{ + size_t i, j; + + for (i = 0; i < PRIOMAPS_SZ; i++) { + struct ifpriomap_t *a = &maps[i]; + + if (!a->ifname) + return 0; + + for (j = 0; j < PRIOMAPS_SZ; j++) { + struct ifpriomap_t *b = &new_maps[j]; + + if (!b->ifname) + break; + + if (strcmp(a->ifname, b->ifname) == 0) { + if (a->prio != b->prio) { + pr_err("`%s' prio: %lu != %lu\n", + a->ifname, + (unsigned long)a->prio, + (unsigned long)b->prio); + return -1; + } + } + } + } + + return 0; +} + +int main(int argc, char **argv) +{ + char subdir[PATH_MAX]; + char path[PATH_MAX]; + int ret = -1; + + srand(time(NULL)); + + test_init(argc, argv); + + if (mount_cg("net_prio") < 0) + return -1; + + sprintf(path, "%s/net_prio/%s/net_prio.ifpriomap", dirname, cgname); + + if (read_map(path, maps, PRIOMAPS_SZ)) + goto out_umount; + + randomize_map(maps, PRIOMAPS_SZ); + + if (write_map(path, maps, PRIOMAPS_SZ)) + goto out_umount; + + test_daemon(); + test_waitsig(); + + if (read_map(path, new_maps, PRIOMAPS_SZ)) { + fail("Can't read ifpriomap after C/R"); + goto out_umount; + } + + if (!compare_maps()) { + ret = 0; + pass(); + } else { + fail("ifpriomap differs before/after C/R"); + } + +out_umount: + sprintf(subdir, "%s/%s/%s", dirname, "net_prio", cgname); + rmdir(subdir); + umount_cg("net_prio"); + + return ret; +} diff --git a/test/zdtm/static/cgroup_ifpriomap.desc b/test/zdtm/static/cgroup_ifpriomap.desc new file mode 100644 index 000000000..5fa9d5079 --- /dev/null +++ b/test/zdtm/static/cgroup_ifpriomap.desc @@ -0,0 +1 @@ +{'flavor': 'h', 'flags': 'suid excl', 'opts': '--manage-cgroups=full'} diff --git a/test/zdtm/static/cgroup_ifpriomap.hook b/test/zdtm/static/cgroup_ifpriomap.hook new file mode 100755 index 000000000..692c5ebe2 --- /dev/null +++ b/test/zdtm/static/cgroup_ifpriomap.hook @@ -0,0 +1,15 @@ +#!/bin/bash + +[ "$1" == "--clean" -o "$1" == "--pre-restore" ] || exit 0 + +tname=$(mktemp -d cgclean.XXXXXX) +mount -t cgroup none $tname -o "net_prio" + +echo "Cleaning $tname" + +set +e +rmdir "$tname/zdtmtst" +set -e + +umount "$tname" +rmdir "$tname" From be98273cf1375cb96f3d494bb36a24cd73c97f3d Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 6 Sep 2017 23:39:36 +0300 Subject: [PATCH 1111/4375] zdtm: mark static/cgroup_ifpriomap as noauto All Jenkins jobs fail with this error: 22:25:13.186: 37: ERR: cgroup_ifpriomap.c:50: Can't mount cgroups (errno = 16 (Device or resource busy)) Signed-off-by: Andrei Vagin --- test/zdtm/static/cgroup_ifpriomap.desc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/cgroup_ifpriomap.desc b/test/zdtm/static/cgroup_ifpriomap.desc index 5fa9d5079..3bb68f00a 100644 --- a/test/zdtm/static/cgroup_ifpriomap.desc +++ b/test/zdtm/static/cgroup_ifpriomap.desc @@ -1 +1 @@ -{'flavor': 'h', 'flags': 'suid excl', 'opts': '--manage-cgroups=full'} +{'flavor': 'h', 'flags': 'suid excl noauto', 'opts': '--manage-cgroups=full'} From 2062abf822b2a988f9bed3e15d63805f5b9a567a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 3 Aug 2017 21:28:38 +0300 Subject: [PATCH 1112/4375] test: static,file_locks01 -- Use fdinfo output Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/file_locks01.c | 130 ++++++++++++++++---------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/test/zdtm/static/file_locks01.c b/test/zdtm/static/file_locks01.c index 399a42835..545238c13 100644 --- a/test/zdtm/static/file_locks01.c +++ b/test/zdtm/static/file_locks01.c @@ -27,7 +27,7 @@ TEST_OPTION(filename, string, "file name", 1); char file0[PATH_MAX]; char file1[PATH_MAX]; char file2[PATH_MAX]; -unsigned int inodes[3]; +unsigned long inodes[3]; static mnt_info_t *m; dev_t dev; @@ -72,91 +72,80 @@ static int open_all_files(int *fd_0, int *fd_1, int *fd_2) pr_perror("Unable to open file %s", file1); return -1; } - fstat(*fd_2, &buf); inodes[2] = buf.st_ino; return 0; } -static int check_file_locks() +static int check_file_lock(int fd, char *expected_type, + char *expected_option, + unsigned int expected_dev, + unsigned long expected_ino) { - FILE *fp_locks = NULL; - char buf[100]; + char buf[100], fl_flag[16], fl_type[16], fl_option[16]; + int found = 0, num, fl_owner; + FILE *fp_locks = NULL; + char path[PATH_MAX]; + unsigned long i_no; + int maj, min; - long long fl_id = 0; - char fl_flag[10], fl_type[15], fl_option[10]; - pid_t fl_owner; - int maj, min; - unsigned long i_no; - long long start; - char end[32]; + test_msg("check_file_lock: (fsname %s) expecting fd %d type %s option %s dev %u ino %lu\n", + m->fsname, fd, expected_type, expected_option, expected_dev, expected_ino); - int num; - int count = 3; - - fp_locks = fopen("/proc/locks", "r"); - if (!fp_locks) + snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd); + fp_locks = fopen(path, "r"); + if (!fp_locks) { + pr_err("Can't open %s\n", path); return -1; - - test_msg("C: %d/%d/%d\n", inodes[0], inodes[1], inodes[2]); + } while (fgets(buf, sizeof(buf), fp_locks)) { + if (strncmp(buf, "lock:\t", 6) != 0) + continue; test_msg("c: %s", buf); - if (strstr(buf, "->")) - continue; - - num = sscanf(buf, - "%lld:%s %s %s %d %x:%x:%ld %lld %s", - &fl_id, fl_flag, fl_type, fl_option, - &fl_owner, &maj, &min, &i_no, &start, end); - - if (num < 10) { - pr_perror("Invalid lock info."); - break; - } - - if (i_no != inodes[0] && i_no != inodes[1] && i_no != inodes[2]) - continue; - - if (!strcmp(m->fsname, "btrfs")) { - if (MKKDEV(major(maj), minor(min)) != dev) - continue; - } else { - if (makedev(maj, min) != dev) - continue; - } - - if (!strcmp(fl_flag, "FLOCK") && !strcmp(fl_type, "ADVISORY")) { - if (!strcmp(fl_option, "READ")) - count--; - else if (!strcmp(fl_option, "WRITE")) - count--; - } - - if (!strcmp(fl_flag, "FLOCK") && - !strcmp(fl_type, "MSNFS") && - !strcmp(fl_option, "READ")) - count--; - memset(fl_flag, 0, sizeof(fl_flag)); memset(fl_type, 0, sizeof(fl_type)); memset(fl_option, 0, sizeof(fl_option)); + + num = sscanf(buf, "%*s %*d:%s %s %s %d %02x:%02x:%ld %*d %*s", + fl_flag, fl_type, fl_option, &fl_owner, + &maj, &min, &i_no); + if (num < 7) { + pr_perror("Invalid lock info."); + break; + } + + if (!strcmp(m->fsname, "btrfs")) { + if (MKKDEV(major(maj), minor(min)) != expected_dev) + continue; + } else { + if (makedev(maj, min) != expected_dev) + continue; + } + + if (fl_owner != getpid()) + continue; + if (i_no != expected_ino) + continue; + if (strcmp(fl_flag, "FLOCK")) + continue; + if (strcmp(fl_type, expected_type)) + continue; + if (strcmp(fl_option, expected_option)) + continue; + found++; } fclose(fp_locks); - /* - * If we find all three matched file locks, count would be 0, - * return 0 for success. - */ - return count; + return found == 1 ? 0 : -1; } int main(int argc, char **argv) { - int fd_0, fd_1, fd_2; + int fd_0, fd_1, fd_2, ret = 0; test_init(argc, argv); @@ -178,9 +167,20 @@ int main(int argc, char **argv) test_daemon(); test_waitsig(); - if (check_file_locks()) - fail("Flock file locks check failed"); - else + if (check_file_lock(fd_0, "ADVISORY", "READ", dev, inodes[0])) { + fail("Failed on fd %d", fd_0); + ret |= 1; + } + if (check_file_lock(fd_1, "ADVISORY", "WRITE", dev, inodes[1])) { + fail("Failed on fd %d", fd_1); + ret |= 1; + } + if (check_file_lock(fd_2, "MSNFS", "READ", dev, inodes[2])) { + fail("Failed on fd %d", fd_2); + ret |= 1; + } + + if (!ret) pass(); close(fd_0); @@ -190,5 +190,5 @@ int main(int argc, char **argv) unlink(file1); unlink(file2); - return 0; + return ret; } From 8dab31beae5bc204f78f04635ea61a6c7a693954 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 3 Aug 2017 21:28:39 +0300 Subject: [PATCH 1113/4375] test: static,file_locks02 -- Use fdinfo output Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/file_locks02.c | 68 ++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/test/zdtm/static/file_locks02.c b/test/zdtm/static/file_locks02.c index 4e2e31b60..91d13854a 100644 --- a/test/zdtm/static/file_locks02.c +++ b/test/zdtm/static/file_locks02.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "zdtmtst.h" @@ -14,29 +15,35 @@ const char *test_author = "Pavel Emelyanov "; char *filename; TEST_OPTION(filename, string, "file name", 1); -static int check_file_locks(pid_t child) +static int check_file_lock(pid_t pid, pid_t child, int fd, char *expected_type, + char *expected_option) { - FILE *fp_locks = NULL; - char buf[100], fl_flag[16], fl_type[16], fl_option[16]; - pid_t pid = getpid(); - int found = 0, num, fl_owner; + char buf[100], fl_flag[16], fl_type[16], fl_option[16]; + int found = 0, num, fl_owner; + FILE *fp_locks = NULL; + char path[PATH_MAX]; - fp_locks = fopen("/proc/locks", "r"); - if (!fp_locks) + test_msg("check_file_lock: (pid %d child %d) expecting fd %d type %s option %s\n", + pid, child, fd, expected_type, expected_option); + + snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd); + fp_locks = fopen(path, "r"); + if (!fp_locks) { + pr_err("Can't open %s\n", path); return -1; - - test_msg("C: %d\n", pid); + } while (fgets(buf, sizeof(buf), fp_locks)) { + if (strncmp(buf, "lock:\t", 6) != 0) + continue; test_msg("c: %s", buf); - if (strstr(buf, "->")) - continue; - - num = sscanf(buf, - "%*d:%s %s %s %d %*02x:%*02x:%*d %*d %*s", - fl_flag, fl_type, fl_option, &fl_owner); + memset(fl_flag, 0, sizeof(fl_flag)); + memset(fl_type, 0, sizeof(fl_type)); + memset(fl_option, 0, sizeof(fl_option)); + num = sscanf(buf, "%*s %*d:%s %s %s %d", + fl_flag, fl_type, fl_option, &fl_owner); if (num < 4) { pr_perror("Invalid lock info."); break; @@ -44,25 +51,23 @@ static int check_file_locks(pid_t child) if (fl_owner != pid && fl_owner != child) continue; - - if (!strcmp(fl_flag, "FLOCK") && - !strcmp(fl_type, "ADVISORY") && - !strcmp(fl_option, "WRITE")) - found++; - - memset(fl_flag, 0, sizeof(fl_flag)); - memset(fl_type, 0, sizeof(fl_type)); - memset(fl_option, 0, sizeof(fl_option)); + if (strcmp(fl_flag, "FLOCK")) + continue; + if (strcmp(fl_type, expected_type)) + continue; + if (strcmp(fl_option, expected_option)) + continue; + found++; } fclose(fp_locks); - return found == 1; + return found == 1 ? 0 : -1; } int main(int argc, char **argv) { - int fd, pid; + int fd, pid, ret = 0; test_init(argc, argv); @@ -83,15 +88,18 @@ int main(int argc, char **argv) test_daemon(); test_waitsig(); - if (check_file_locks(pid)) - pass(); - else + if (check_file_lock(getpid(), pid, fd, "ADVISORY", "WRITE")) { fail("Flock file locks check failed"); + ret |= 1; + } + + if (!ret) + pass(); kill(pid, SIGTERM); waitpid(pid, NULL, 0); close(fd); unlink(filename); - return 0; + return ret; } From a088aeb475ad7f3a78e1d4fe68e4de9032c54f22 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 3 Aug 2017 21:28:40 +0300 Subject: [PATCH 1114/4375] test: static,file_locks03 -- Use fdinfo output Also use task_waiter_t syncpoint to make sure fd won't escape while we're reading output. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/file_locks03.c | 74 +++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/test/zdtm/static/file_locks03.c b/test/zdtm/static/file_locks03.c index 9d5f198ef..19c11dbb6 100644 --- a/test/zdtm/static/file_locks03.c +++ b/test/zdtm/static/file_locks03.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "zdtmtst.h" @@ -14,57 +15,63 @@ const char *test_author = "Pavel Emelyanov "; char *filename; TEST_OPTION(filename, string, "file name", 1); -static int check_file_locks(int alt_pid) +static int check_file_lock(pid_t pid, pid_t child, int fd, char *expected_type, + char *expected_option) { - FILE *fp_locks = NULL; - char buf[100], fl_flag[16], fl_type[16], fl_option[16]; - pid_t pid = getpid(); - int found = 0, num, fl_owner; + char buf[100], fl_flag[16], fl_type[16], fl_option[16]; + int found = 0, num, fl_owner; + FILE *fp_locks = NULL; + char path[PATH_MAX]; - fp_locks = fopen("/proc/locks", "r"); - if (!fp_locks) + test_msg("check_file_lock: (pid %d child %d) expecting fd %d type %s option %s\n", + pid, child, fd, expected_type, expected_option); + + snprintf(path, sizeof(path), "/proc/%d/fdinfo/%d", child, fd); + fp_locks = fopen(path, "r"); + if (!fp_locks) { + pr_err("Can't open %s\n", path); return -1; - - test_msg("C: %d/%d\n", pid, alt_pid); + } while (fgets(buf, sizeof(buf), fp_locks)) { + if (strncmp(buf, "lock:\t", 6) != 0) + continue; test_msg("c: %s", buf); - if (strstr(buf, "->")) - continue; - - num = sscanf(buf, - "%*d:%s %s %s %d %*02x:%*02x:%*d %*d %*s", - fl_flag, fl_type, fl_option, &fl_owner); + memset(fl_flag, 0, sizeof(fl_flag)); + memset(fl_type, 0, sizeof(fl_type)); + memset(fl_option, 0, sizeof(fl_option)); + num = sscanf(buf, "%*s %*d:%s %s %s %d", + fl_flag, fl_type, fl_option, &fl_owner); if (num < 4) { pr_perror("Invalid lock info."); break; } - if (fl_owner != pid && fl_owner != alt_pid) + if (fl_owner != pid && fl_owner != child) continue; - - if (!strcmp(fl_flag, "FLOCK") && - !strcmp(fl_type, "ADVISORY") && - !strcmp(fl_option, "WRITE")) - found++; - - memset(fl_flag, 0, sizeof(fl_flag)); - memset(fl_type, 0, sizeof(fl_type)); - memset(fl_option, 0, sizeof(fl_option)); + if (strcmp(fl_flag, "FLOCK")) + continue; + if (strcmp(fl_type, expected_type)) + continue; + if (strcmp(fl_option, expected_option)) + continue; + found++; } fclose(fp_locks); - return found == 1; + return found == 1 ? 0 : -1; } int main(int argc, char **argv) { - int fd, pid; + int fd, pid, ret = 0; + task_waiter_t t; test_init(argc, argv); + task_waiter_init(&t); fd = open(filename, O_CREAT | O_RDWR, 0600); if (fd < 0) { @@ -77,6 +84,7 @@ int main(int argc, char **argv) pid = fork(); if (pid == 0) { test_waitsig(); + task_waiter_wait4(&t, 1); exit(0); } @@ -85,14 +93,18 @@ int main(int argc, char **argv) test_daemon(); test_waitsig(); - if (check_file_locks(pid)) - pass(); - else + if (check_file_lock(getpid(), pid, fd, "ADVISORY", "WRITE")) { fail("Flock file locks check failed"); + ret |= 1; + } + + task_waiter_complete(&t, 1); + + if (!ret) + pass(); kill(pid, SIGTERM); waitpid(pid, NULL, 0); - close(fd); unlink(filename); return 0; From 6ea74dda580827b45e40e95a26abeb34edf1328c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 21 Oct 2017 23:25:03 +0300 Subject: [PATCH 1115/4375] build: Don't forget to rebuild pie code on compel plugins change https://github.com/checkpoint-restore/criu/issues/399 Rerorted-by: Andrew Vagin Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- Makefile.compel | 1 + criu/pie/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.compel b/Makefile.compel index 1ef7f8cb2..8768c795d 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -28,6 +28,7 @@ LIBCOMPEL_SO := libcompel.so LIBCOMPEL_A := libcompel.a export LIBCOMPEL_SO LIBCOMPEL_A criu-deps += compel/$(LIBCOMPEL_A) +criu-deps += $(compel-plugins) # # Compel itself. diff --git a/criu/pie/Makefile b/criu/pie/Makefile index de4d667a5..8b05c14a0 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -37,7 +37,7 @@ $(1)-obj-e += pie.lib.a $(1)-obj-e += $$(compel_plugins) # Dependency on compel linker script, to relink if it has changed -$$(obj)/$(1).built-in.o: $$(LDS) +$$(obj)/$(1).built-in.o: $$(LDS) $$(compel_plugins) $$(obj)/$(1)-blob.h: $$(obj)/$(1).built-in.o $$(call msg-gen, $$@) From c9ca83f05ae30810bd90e092dfc98fa7afe310b9 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 23 Oct 2017 09:57:48 -0700 Subject: [PATCH 1116/4375] tests: fix lint warnings for zdtm.py flake8 was updated recently and now it shows a few new warnings: [root@fc24 criu]# make lint flake8 --config=scripts/flake8.cfg test/zdtm.py test/zdtm.py:181:4: E722 do not use bare except' test/zdtm.py:304:2: E722 do not use bare except' test/zdtm.py:325:3: E722 do not use bare except' test/zdtm.py:445:3: E722 do not use bare except' test/zdtm.py:573:4: E722 do not use bare except' test/zdtm.py:1369:2: E722 do not use bare except' test/zdtm.py:1385:3: E722 do not use bare except' test/zdtm.py:1396:2: E722 do not use bare except' test/zdtm.py:1420:3: E722 do not use bare except' test/zdtm.py:1820:2: E741 ambiguous variable name 'l' make: *** [Makefile:369: lint] Error 1 Signed-off-by: Andrei Vagin --- test/zdtm.py | 64 ++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index c859ad97c..efed1348c 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -171,8 +171,9 @@ class ns_flavor: # run in parallel try: os.makedirs(self.root + os.path.dirname(fname)) - except: - pass + except OSError, e: + if e.errno != errno.EEXIST: + raise dst = tempfile.mktemp(".tso", "", self.root + os.path.dirname(fname)) shutil.copy2(fname, dst) os.rename(dst, tfname) @@ -292,10 +293,7 @@ def encode_flav(f): def decode_flav(i): - try: - return flavors.keys()[i - 128] - except: - return "unknown" + return flavors.keys().get([i - 128], "unknown") def tail(path): @@ -315,7 +313,8 @@ def wait_pid_die(pid, who, tmo = 30): while stime < tmo: try: os.kill(int(pid), 0) - except: # Died + except Exception, e: + print "Unable to kill %d: %s" % (pid, e) break print "Wait for %s(%d) to die for %f" % (who, pid, stime) @@ -434,8 +433,8 @@ class zdtm_test: try: os.kill(int(self.getpid()), 0) - except: - raise test_fail_exc("start") + except Exception, e: + raise test_fail_exc("start: %s" % e) if not self.static(): # Wait less than a second to give the test chance to @@ -560,7 +559,8 @@ class inhfd_test: os.close(start_pipe[1]) try: data = peer_file.read(16) - except: + except Exception, e: + print "Unable to read a peer file: %s" % e sys.exit(1) sys.exit(data == self.__message and 42 or 2) @@ -1265,7 +1265,8 @@ def pstree_each_pid(root_pid): pid_line = f_children.readline().strip(" \n") if pid_line: child_pids += pid_line.split(" ") - except: + except Exception, e: + print "Unable to read /proc/*/children: %s" % e return # process is dead yield root_pid @@ -1281,7 +1282,8 @@ def is_proc_stopped(pid): for line in f_status.readlines(): if line.startswith("State:"): return line.split(":", 1)[1].strip().split(" ")[0] - except: + except Exception, e: + print "Unable to read a thread status: %s" % e pass # process is dead return None @@ -1292,7 +1294,8 @@ def is_proc_stopped(pid): thread_dirs = [] try: thread_dirs = os.listdir(tasks_dir) - except: + except Exception, e: + print "Unable to read threads: %s" % e pass # process is dead for thread_dir in thread_dirs: @@ -1316,7 +1319,8 @@ def pstree_signal(root_pid, signal): for pid in pstree_each_pid(root_pid): try: os.kill(int(pid), signal) - except: + except Exception, e: + print "Unable to kill %d: %s" % (pid, e) pass # process is dead @@ -1378,7 +1382,7 @@ def do_run_test(tname, tdesc, flavs, opts): print_sep("Test %s PASS" % tname) -class launcher: +class Launcher: def __init__(self, opts, nr_tests): self.__opts = opts self.__total = nr_tests @@ -1700,26 +1704,26 @@ def run_tests(opts): # Most tests will work with 4.3 - 4.11 print "[WARNING] Non-cooperative UFFD is missing, some tests might spuriously fail" - l = launcher(opts, len(torun)) + launcher = Launcher(opts, len(torun)) try: for t in torun: global arch if excl and excl.match(t): - l.skip(t, "exclude") + launcher.skip(t, "exclude") continue tdesc = get_test_desc(t) if tdesc.get('arch', arch) != arch: - l.skip(t, "arch %s" % tdesc['arch']) + launcher.skip(t, "arch %s" % tdesc['arch']) continue if test_flag(tdesc, 'reqrst') and opts['norst']: - l.skip(t, "restore stage is required") + launcher.skip(t, "restore stage is required") continue if run_all and test_flag(tdesc, 'noauto'): - l.skip(t, "manual run only") + launcher.skip(t, "manual run only") continue feat = tdesc.get('feature', None) @@ -1729,34 +1733,34 @@ def run_tests(opts): features[feat] = criu.check(feat) if not features[feat]: - l.skip(t, "no %s feature" % feat) + launcher.skip(t, "no %s feature" % feat) continue if self_checkskip(t): - l.skip(t, "checkskip failed") + launcher.skip(t, "checkskip failed") continue if opts['user']: if test_flag(tdesc, 'suid'): - l.skip(t, "suid test in user mode") + launcher.skip(t, "suid test in user mode") continue if test_flag(tdesc, 'nouser'): - l.skip(t, "criu root prio needed") + launcher.skip(t, "criu root prio needed") continue if opts['join_ns']: if test_flag(tdesc, 'samens'): - l.skip(t, "samens test in the same namespace") + launcher.skip(t, "samens test in the same namespace") continue if opts['lazy_pages'] or opts['remote_lazy_pages']: if test_flag(tdesc, 'nolazy'): - l.skip(t, "lazy pages are not supported") + launcher.skip(t, "lazy pages are not supported") continue if opts['remote_lazy_pages']: if test_flag(tdesc, 'noremotelazy'): - l.skip(t, "remote lazy pages are not supported") + launcher.skip(t, "remote lazy pages are not supported") continue test_flavs = tdesc.get('flavor', 'h ns uns').split() @@ -1778,11 +1782,11 @@ def run_tests(opts): run_flavs -= set(['h']) if run_flavs: - l.run_test(t, tdesc, run_flavs) + launcher.run_test(t, tdesc, run_flavs) else: - l.skip(t, "no flavors") + launcher.skip(t, "no flavors") finally: - l.finish() + launcher.finish() if opts['join_ns']: subprocess.Popen(["ip", "netns", "delete", "zdtm_netns"]).wait() From 20bc6aed12a0bae6d3b455e5dcc42bf1759a43e9 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 5 Sep 2017 11:19:41 +0300 Subject: [PATCH 1117/4375] crit: Use ns_pid, ns_sid and ns_gid Reflect commit 3086b0323cf8 "pstree: Dump and restore NSpid, NSsid etc" in crit. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- crit/crit | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/crit/crit b/crit/crit index 22e7ea789..08e84575d 100755 --- a/crit/crit +++ b/crit/crit @@ -49,20 +49,22 @@ def info(opts): json.dump(infs, sys.stdout, indent = 4) print +def get_task_id(p, val): + return p[val] if val in p else p['ns_' + val][0] # # Explorers # class ps_item: def __init__(self, p, core): - self.pid = p['pid'] + self.pid = get_task_id(p, 'pid') self.ppid = p['ppid'] self.p = p self.core = core self.kids = [] def show_ps(p, opts, depth = 0): - print "%7d%7d%7d %s%s" % (p.pid, p.p['pgid'], p.p['sid'], + print "%7d%7d%7d %s%s" % (p.pid, get_task_id(p.p, 'pgid'), get_task_id(p.p, 'sid'), ' ' * (4 * depth), p.core['tc']['comm']) for kid in p.kids: show_ps(kid, opts, depth + 1) @@ -71,7 +73,7 @@ def explore_ps(opts): pss = { } ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) for p in ps_img['entries']: - core = pycriu.images.load(dinf(opts, 'core-%d.img' % p['pid'])) + core = pycriu.images.load(dinf(opts, 'core-%d.img' % get_task_id(p, 'pid'))) ps = ps_item(p, core['entries'][0]) pss[ps.pid] = ps @@ -162,7 +164,7 @@ def get_file_str(opts, fd): def explore_fds(opts): ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) for p in ps_img['entries']: - pid = p['pid'] + pid = get_task_id(p, 'pid') idi = pycriu.images.load(dinf(opts, 'ids-%s.img' % pid)) fdt = idi['entries'][0]['files_id'] fdi = pycriu.images.load(dinf(opts, 'fdinfo-%d.img' % fdt)) @@ -194,7 +196,7 @@ def explore_mems(opts): ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) vids = vma_id() for p in ps_img['entries']: - pid = p['pid'] + pid = get_task_id(p, 'pid') mmi = pycriu.images.load(dinf(opts, 'mm-%d.img' % pid))['entries'][0] print "%d" % pid @@ -239,7 +241,7 @@ def explore_mems(opts): def explore_rss(opts): ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) for p in ps_img['entries']: - pid = p['pid'] + pid = get_task_id(p, 'pid') vmas = pycriu.images.load(dinf(opts, 'mm-%d.img' % pid))['entries'][0]['vmas'] pms = pycriu.images.load(dinf(opts, 'pagemap-%d.img' % pid))['entries'] From 5785dbd93dec20f56a89245b94f6fde28cd098ac Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 26 Oct 2017 00:27:43 +0300 Subject: [PATCH 1118/4375] zdtm.py: fix decode_flav() Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index efed1348c..d3e0c9a05 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -293,7 +293,7 @@ def encode_flav(f): def decode_flav(i): - return flavors.keys().get([i - 128], "unknown") + return flavors.get(i - 128, "unknown") def tail(path): From c94fb7d069034fc4dbc725716daf6728b6dc2c59 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:39 +0300 Subject: [PATCH 1119/4375] fault-injection: Add FI_HUGE_ANON_SHMEM_ID type To test if we can survive with shmid more than 4 bytes long in image formats. Without the fix for shmid | [root@uranus criu] test/zdtm.py run -t zdtm/static/maps01 --fault 132 -f h -k always | === Run 1/1 ================ zdtm/static/maps01 | | ========================= Run zdtm/static/maps01 in h ========================== | Start test | Test is SUID | ./maps01 --pidfile=maps01.pid --outfile=maps01.out | Run criu dump | Forcing 132 fault | Run criu restore | Forcing 132 fault | =[log]=> dump/zdtm/static/maps01/36/1/restore.log | ------------------------ grep Error ------------------------ | (00.016464) 37: Opening 0x007f39c04b5000-0x007f3a004b5000 0000000000000000 (101) vma | (00.016465) 37: Search for 0x007f39c04b5000 shmem 0x10118e915 0x7f97f7ae4ae8/36 | (00.016470) 37: Waiting for the 10118e915 shmem to appear | (00.016479) 36: No pagemap-shmem-18409749.img image | (00.016481) 36: Error (criu/shmem.c:559): Can't restore shmem content | (00.016501) 36: Error (criu/mem.c:1208): `- Can't open vma | (00.016552) Error (criu/cr-restore.c:2449): Restoring FAILED. | ------------------------ ERROR OVER ------------------------ And with the fix | [root@uranus criu] test/zdtm.py run -t zdtm/static/maps01 --fault 132 -f h -k always | === Run 1/1 ================ zdtm/static/maps01 | | ========================= Run zdtm/static/maps01 in h ========================== | Start test | Test is SUID | ./maps01 --pidfile=maps01.pid --outfile=maps01.out | Run criu dump | Forcing 132 fault | Run criu restore | Forcing 132 fault | Send the 15 signal to 36 | Wait for zdtm/static/maps01(36) to die for 0.100000 | ========================= Test zdtm/static/maps01 PASS ========================= Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/fault-injection.h | 3 +++ criu/proc_parse.c | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/criu/include/fault-injection.h b/criu/include/fault-injection.h index 46a5f71b0..852d27166 100644 --- a/criu/include/fault-injection.h +++ b/criu/include/fault-injection.h @@ -16,6 +16,7 @@ enum faults { FI_NO_MEMFD = 129, FI_NO_BREAKPOINTS = 130, FI_PARTIAL_PAGES = 131, + FI_HUGE_ANON_SHMEM_ID = 132, FI_MAX, }; @@ -32,6 +33,8 @@ static inline bool __fault_injected(enum faults f, enum faults fi_strategy) return fi_strategy == f; } +#define FI_HUGE_ANON_SHMEM_ID_BASE (0xfffffffflu) + #ifndef CR_NOGLIBC extern enum faults fi_strategy; diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 2d8197aa3..153618447 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -40,6 +40,7 @@ #include "cgroup-props.h" #include "timerfd.h" #include "path.h" +#include "fault-injection.h" #include "protobuf.h" #include "images/fdinfo.pb-c.h" @@ -310,8 +311,12 @@ static int vma_get_mapfile_user(const char *fname, struct vma_area *vma, vma->e->status |= VMA_ANON_SHARED; vma->e->shmid = vfi->ino; - if (!strncmp(fname, "/SYSV", 5)) + if (!strncmp(fname, "/SYSV", 5)) { vma->e->status |= VMA_AREA_SYSVIPC; + } else { + if (fault_injected(FI_HUGE_ANON_SHMEM_ID)) + vma->e->shmid += FI_HUGE_ANON_SHMEM_ID_BASE; + } return 0; } @@ -598,6 +603,9 @@ static int handle_vma(pid_t pid, struct vma_area *vma_area, if (!strncmp(file_path, "/SYSV", 5)) { pr_info("path: %s\n", file_path); vma_area->e->status |= VMA_AREA_SYSVIPC; + } else { + if (fault_injected(FI_HUGE_ANON_SHMEM_ID)) + vma_area->e->shmid += FI_HUGE_ANON_SHMEM_ID_BASE; } } else { if (vma_area->e->flags & MAP_PRIVATE) From 78d4f7c3521adb77793eb252d9c7d9326bb3408b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:40 +0300 Subject: [PATCH 1120/4375] test: jenkins -- Add huge shmid fault into the tests Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/jenkins/criu-fault.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jenkins/criu-fault.sh b/test/jenkins/criu-fault.sh index 1e9862f7d..ec6d26f89 100755 --- a/test/jenkins/criu-fault.sh +++ b/test/jenkins/criu-fault.sh @@ -22,3 +22,4 @@ prep ./test/zdtm.py run -t zdtm/static/env00 --fault 5 --keep-going --report report || fail ./test/zdtm.py run -t zdtm/static/maps04 --fault 131 --keep-going --report report --pre 2:1 || fail ./test/zdtm.py run -t zdtm/transition/maps008 --fault 131 --keep-going --report report --pre 2:1 || fail +./test/zdtm.py run -t zdtm/static/maps01 --fault 132 -f h || fail From 57e4ad5ba841bac2c1ff87d3c19860fe018bc740 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:26 +0300 Subject: [PATCH 1121/4375] namespaces: __get_ns_id -- Use safe snprintf Namespace descriptors are not promised to have constant short names, so just to be on a safe side. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/namespaces.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/namespaces.c b/criu/namespaces.c index e607ec4b0..285974eae 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -437,7 +437,7 @@ static unsigned int __get_ns_id(int pid, struct ns_desc *nd, protobuf_c_boolean if (proc_dir < 0) return 0; - sprintf(ns_path, "ns/%s", nd->str); + snprintf(ns_path, sizeof(ns_path), "ns/%s", nd->str); if (fstatat(proc_dir, ns_path, &st, 0)) { if (errno == ENOENT) { From 1fbc51f8e2b344525a0877e7fda649de603b63d9 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:28 +0300 Subject: [PATCH 1122/4375] image-desc: Fix fdinfo format We pass unsigned 4 byte integer here, so use appropriate format. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/image-desc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/image-desc.c b/criu/image-desc.c index 7fedf1a09..b3197ce19 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -26,7 +26,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY(INVENTORY, "inventory"), - FD_ENTRY(FDINFO, "fdinfo-%d"), + FD_ENTRY(FDINFO, "fdinfo-%u"), FD_ENTRY(PAGEMAP, "pagemap-%ld"), FD_ENTRY(SHMEM_PAGEMAP, "pagemap-shmem-%ld"), FD_ENTRY(REG_FILES, "reg-files"), From 2ca78e9a004e538a2f0500d979f8e9d6352b3b07 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:29 +0300 Subject: [PATCH 1123/4375] image-desc: Use unsigned format for autofs Both the kernel and criu uses unsigned int for it, make the format appropriate. | struct mount_info { | ... | unsigned int s_dev; | ... | } We didn't see negative number here in real life so I don't think if such %d to %u convention cause backward compatibility problem ever. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/image-desc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/image-desc.c b/criu/image-desc.c index b3197ce19..dfd89805b 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -78,7 +78,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY_F(IP6TABLES, "ip6tables-%d", O_NOBUF), FD_ENTRY_F(TMPFS_IMG, "tmpfs-%d.tar.gz", O_NOBUF), FD_ENTRY_F(TMPFS_DEV, "tmpfs-dev-%d.tar.gz", O_NOBUF), - FD_ENTRY_F(AUTOFS, "autofs-%d", O_NOBUF), + FD_ENTRY_F(AUTOFS, "autofs-%u", O_NOBUF), FD_ENTRY(BINFMT_MISC_OLD, "binfmt-misc-%d"), FD_ENTRY(BINFMT_MISC, "binfmt-misc"), FD_ENTRY(TTY_FILES, "tty"), From 9020d18d44c2299b5bb912fe5f22f240b0b972b6 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:30 +0300 Subject: [PATCH 1124/4375] image-desc: Use unsigned int for tmpfs dev image Same as for autofs. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/image-desc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/image-desc.c b/criu/image-desc.c index dfd89805b..8ea78f41e 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -77,7 +77,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY_F(IPTABLES, "iptables-%d", O_NOBUF), FD_ENTRY_F(IP6TABLES, "ip6tables-%d", O_NOBUF), FD_ENTRY_F(TMPFS_IMG, "tmpfs-%d.tar.gz", O_NOBUF), - FD_ENTRY_F(TMPFS_DEV, "tmpfs-dev-%d.tar.gz", O_NOBUF), + FD_ENTRY_F(TMPFS_DEV, "tmpfs-dev-%u.tar.gz", O_NOBUF), FD_ENTRY_F(AUTOFS, "autofs-%u", O_NOBUF), FD_ENTRY(BINFMT_MISC_OLD, "binfmt-misc-%d"), FD_ENTRY(BINFMT_MISC, "binfmt-misc"), From 6a08b0cdf1194ca74e77bc565101566318e0068b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:31 +0300 Subject: [PATCH 1125/4375] image-desc: Use unsigned int for old binfmt-misc Same as for autofs. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/image-desc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/image-desc.c b/criu/image-desc.c index 8ea78f41e..dbef77905 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -79,7 +79,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY_F(TMPFS_IMG, "tmpfs-%d.tar.gz", O_NOBUF), FD_ENTRY_F(TMPFS_DEV, "tmpfs-dev-%u.tar.gz", O_NOBUF), FD_ENTRY_F(AUTOFS, "autofs-%u", O_NOBUF), - FD_ENTRY(BINFMT_MISC_OLD, "binfmt-misc-%d"), + FD_ENTRY(BINFMT_MISC_OLD, "binfmt-misc-%u"), FD_ENTRY(BINFMT_MISC, "binfmt-misc"), FD_ENTRY(TTY_FILES, "tty"), FD_ENTRY(TTY_INFO, "tty-info"), From ba10ae1ac0faf2a2760539de624baec0b8c1fe12 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:32 +0300 Subject: [PATCH 1126/4375] image-desc: Use unsigned for mountpoints Just as we declare it in ns_id structure. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/image-desc.c | 2 +- criu/mount.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/image-desc.c b/criu/image-desc.c index dbef77905..e30308625 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -67,7 +67,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY(REMAP_FPATH, "remap-fpath"), FD_ENTRY_F(GHOST_FILE, "ghost-file-%x", O_NOBUF), FD_ENTRY(TCP_STREAM, "tcp-stream-%x"), - FD_ENTRY(MNTS, "mountpoints-%d"), + FD_ENTRY(MNTS, "mountpoints-%u"), FD_ENTRY(NETDEV, "netdev-%d"), FD_ENTRY(NETNS, "netns-%d"), FD_ENTRY_F(IFADDR, "ifaddr-%d", O_NOBUF), diff --git a/criu/mount.c b/criu/mount.c index 672930945..648154371 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1438,7 +1438,7 @@ static int dump_mnt_ns(struct ns_id *ns, struct mount_info *pms) struct mount_info *pm; int ret = -1; struct cr_img *img; - int ns_id = ns->id; + unsigned int ns_id = ns->id; pr_info("Dumping mountpoints\n"); img = open_image(CR_FD_MNTS, O_DUMP, ns_id); From a8d785730312d5541e3ae809a69ef8993af4c7f5 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:33 +0300 Subject: [PATCH 1127/4375] image-desc: Use unsigned format for netdev Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/image-desc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/image-desc.c b/criu/image-desc.c index e30308625..1624d3ab5 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -68,7 +68,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY_F(GHOST_FILE, "ghost-file-%x", O_NOBUF), FD_ENTRY(TCP_STREAM, "tcp-stream-%x"), FD_ENTRY(MNTS, "mountpoints-%u"), - FD_ENTRY(NETDEV, "netdev-%d"), + FD_ENTRY(NETDEV, "netdev-%u"), FD_ENTRY(NETNS, "netns-%d"), FD_ENTRY_F(IFADDR, "ifaddr-%d", O_NOBUF), FD_ENTRY_F(ROUTE, "route-%d", O_NOBUF), From af5a6b52cbe200b7072f5ea793312c30484a77b3 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:34 +0300 Subject: [PATCH 1128/4375] image-desc: Use unsigned format for netns Since it uses ns->id Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/image-desc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/image-desc.c b/criu/image-desc.c index 1624d3ab5..8a4e2489e 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -69,7 +69,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY(TCP_STREAM, "tcp-stream-%x"), FD_ENTRY(MNTS, "mountpoints-%u"), FD_ENTRY(NETDEV, "netdev-%u"), - FD_ENTRY(NETNS, "netns-%d"), + FD_ENTRY(NETNS, "netns-%u"), FD_ENTRY_F(IFADDR, "ifaddr-%d", O_NOBUF), FD_ENTRY_F(ROUTE, "route-%d", O_NOBUF), FD_ENTRY_F(ROUTE6, "route6-%d", O_NOBUF), From 582f104d04dac6d694c2076a1eef781a9fe8984d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:35 +0300 Subject: [PATCH 1129/4375] image-desc: Use unsigned format for userns It uses ns->id Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/image-desc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/image-desc.c b/criu/image-desc.c index 8a4e2489e..53299a704 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -96,7 +96,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY(TIMERFD, "timerfd"), FD_ENTRY(CPUINFO, "cpuinfo"), FD_ENTRY(SECCOMP, "seccomp"), - FD_ENTRY(USERNS, "userns-%d"), + FD_ENTRY(USERNS, "userns-%u"), FD_ENTRY(NETNF_CT, "netns-ct-%d"), FD_ENTRY(NETNF_EXP, "netns-exp-%d"), FD_ENTRY(FILES, "files"), From d9952dcd4f2955b55c64c6160572648b76379b3b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:36 +0300 Subject: [PATCH 1130/4375] image-desc: Use unsigned format for pid driven entries For images which are using pid as id for image names use unsigned format since here is no negative pid in real system. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/image-desc.c | 52 +++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/criu/image-desc.c b/criu/image-desc.c index 53299a704..f3e614966 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -40,42 +40,42 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY(INOTIFY_WD, "inotify-wd"), FD_ENTRY(FANOTIFY_FILE, "fanotify"), FD_ENTRY(FANOTIFY_MARK, "fanotify-mark"), - FD_ENTRY(CORE, "core-%d"), - FD_ENTRY(IDS, "ids-%d"), - FD_ENTRY(MM, "mm-%d"), - FD_ENTRY(VMAS, "vmas-%d"), + FD_ENTRY(CORE, "core-%u"), + FD_ENTRY(IDS, "ids-%u"), + FD_ENTRY(MM, "mm-%u"), + FD_ENTRY(VMAS, "vmas-%u"), FD_ENTRY(PIPES, "pipes"), FD_ENTRY_F(PIPES_DATA, "pipes-data", O_NOBUF), /* splices data */ FD_ENTRY(FIFO, "fifo"), FD_ENTRY_F(FIFO_DATA, "fifo-data", O_NOBUF), /* the same */ FD_ENTRY(PSTREE, "pstree"), - FD_ENTRY(SIGACT, "sigacts-%d"), + FD_ENTRY(SIGACT, "sigacts-%u"), FD_ENTRY(UNIXSK, "unixsk"), FD_ENTRY(INETSK, "inetsk"), FD_ENTRY(PACKETSK, "packetsk"), FD_ENTRY(NETLINK_SK, "netlinksk"), FD_ENTRY_F(SK_QUEUES, "sk-queues", O_NOBUF), /* lseeks the image */ - FD_ENTRY(ITIMERS, "itimers-%d"), - FD_ENTRY(POSIX_TIMERS, "posix-timers-%d"), - FD_ENTRY(CREDS, "creds-%d"), - FD_ENTRY(UTSNS, "utsns-%d"), - FD_ENTRY(IPC_VAR, "ipcns-var-%d"), - FD_ENTRY_F(IPCNS_SHM, "ipcns-shm-%d", O_NOBUF), /* writes segments of data */ - FD_ENTRY(IPCNS_MSG, "ipcns-msg-%d"), - FD_ENTRY(IPCNS_SEM, "ipcns-sem-%d"), - FD_ENTRY(FS, "fs-%d"), + FD_ENTRY(ITIMERS, "itimers-%u"), + FD_ENTRY(POSIX_TIMERS, "posix-timers-%u"), + FD_ENTRY(CREDS, "creds-%u"), + FD_ENTRY(UTSNS, "utsns-%u"), + FD_ENTRY(IPC_VAR, "ipcns-var-%u"), + FD_ENTRY_F(IPCNS_SHM, "ipcns-shm-%u", O_NOBUF), /* writes segments of data */ + FD_ENTRY(IPCNS_MSG, "ipcns-msg-%u"), + FD_ENTRY(IPCNS_SEM, "ipcns-sem-%u"), + FD_ENTRY(FS, "fs-%u"), FD_ENTRY(REMAP_FPATH, "remap-fpath"), FD_ENTRY_F(GHOST_FILE, "ghost-file-%x", O_NOBUF), FD_ENTRY(TCP_STREAM, "tcp-stream-%x"), FD_ENTRY(MNTS, "mountpoints-%u"), FD_ENTRY(NETDEV, "netdev-%u"), FD_ENTRY(NETNS, "netns-%u"), - FD_ENTRY_F(IFADDR, "ifaddr-%d", O_NOBUF), - FD_ENTRY_F(ROUTE, "route-%d", O_NOBUF), - FD_ENTRY_F(ROUTE6, "route6-%d", O_NOBUF), - FD_ENTRY_F(RULE, "rule-%d", O_NOBUF), - FD_ENTRY_F(IPTABLES, "iptables-%d", O_NOBUF), - FD_ENTRY_F(IP6TABLES, "ip6tables-%d", O_NOBUF), + FD_ENTRY_F(IFADDR, "ifaddr-%u", O_NOBUF), + FD_ENTRY_F(ROUTE, "route-%u", O_NOBUF), + FD_ENTRY_F(ROUTE6, "route6-%u", O_NOBUF), + FD_ENTRY_F(RULE, "rule-%u", O_NOBUF), + FD_ENTRY_F(IPTABLES, "iptables-%u", O_NOBUF), + FD_ENTRY_F(IP6TABLES, "ip6tables-%u", O_NOBUF), FD_ENTRY_F(TMPFS_IMG, "tmpfs-%d.tar.gz", O_NOBUF), FD_ENTRY_F(TMPFS_DEV, "tmpfs-dev-%u.tar.gz", O_NOBUF), FD_ENTRY_F(AUTOFS, "autofs-%u", O_NOBUF), @@ -85,20 +85,20 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY(TTY_INFO, "tty-info"), FD_ENTRY_F(TTY_DATA, "tty-data", O_NOBUF), FD_ENTRY(FILE_LOCKS, "filelocks"), - FD_ENTRY(RLIMIT, "rlimit-%d"), + FD_ENTRY(RLIMIT, "rlimit-%u"), FD_ENTRY_F(PAGES, "pages-%u", O_NOBUF), FD_ENTRY_F(PAGES_OLD, "pages-%d", O_NOBUF), FD_ENTRY_F(SHM_PAGES_OLD, "pages-shmem-%ld", O_NOBUF), - FD_ENTRY(SIGNAL, "signal-s-%d"), - FD_ENTRY(PSIGNAL, "signal-p-%d"), + FD_ENTRY(SIGNAL, "signal-s-%u"), + FD_ENTRY(PSIGNAL, "signal-p-%u"), FD_ENTRY(TUNFILE, "tunfile"), FD_ENTRY(CGROUP, "cgroup"), FD_ENTRY(TIMERFD, "timerfd"), FD_ENTRY(CPUINFO, "cpuinfo"), FD_ENTRY(SECCOMP, "seccomp"), FD_ENTRY(USERNS, "userns-%u"), - FD_ENTRY(NETNF_CT, "netns-ct-%d"), - FD_ENTRY(NETNF_EXP, "netns-exp-%d"), + FD_ENTRY(NETNF_CT, "netns-ct-%u"), + FD_ENTRY(NETNF_EXP, "netns-exp-%u"), FD_ENTRY(FILES, "files"), [CR_FD_STATS] = { @@ -114,7 +114,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { }, [CR_FD_FILE_LOCKS_PID] = { - .fmt = "filelocks-%d.img", + .fmt = "filelocks-%u.img", .magic = FILE_LOCKS_MAGIC, }, }; From bf341b463e566e97bd1db0d9b7d952a0d33ff349 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:37 +0300 Subject: [PATCH 1131/4375] image-desc: Use unsigned format for tmpfs image The index comes from mnt_id which is signed integer both in kernel and in userspace, but negative value is never valid, thus don't use it. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/image-desc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/image-desc.c b/criu/image-desc.c index f3e614966..4fefdab97 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -76,7 +76,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY_F(RULE, "rule-%u", O_NOBUF), FD_ENTRY_F(IPTABLES, "iptables-%u", O_NOBUF), FD_ENTRY_F(IP6TABLES, "ip6tables-%u", O_NOBUF), - FD_ENTRY_F(TMPFS_IMG, "tmpfs-%d.tar.gz", O_NOBUF), + FD_ENTRY_F(TMPFS_IMG, "tmpfs-%u.tar.gz", O_NOBUF), FD_ENTRY_F(TMPFS_DEV, "tmpfs-dev-%u.tar.gz", O_NOBUF), FD_ENTRY_F(AUTOFS, "autofs-%u", O_NOBUF), FD_ENTRY(BINFMT_MISC_OLD, "binfmt-misc-%u"), From b2d257495503993f541617821b7b82b9475d59fd Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 25 Oct 2017 11:39:38 +0300 Subject: [PATCH 1132/4375] image-desc: Encode pagemap in unsigned long format The anonymous shared memory are using shmid for image name encoding which is unsigned long and we already met scenario where high bits get strippped off thus the restore failed. Lets use unsigned long here, and because pagemap code is shared between plain memory and anon shared memory use unsigned long every where. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-dedup.c | 20 +++++++++--------- criu/image-desc.c | 4 ++-- criu/include/page-xfer.h | 8 ++++---- criu/include/pagemap.h | 6 +++--- criu/page-xfer.c | 44 ++++++++++++++++++++-------------------- criu/pagemap.c | 36 ++++++++++++++++---------------- 6 files changed, 59 insertions(+), 59 deletions(-) diff --git a/criu/cr-dedup.c b/criu/cr-dedup.c index e84303f2c..71b7a9cc3 100644 --- a/criu/cr-dedup.c +++ b/criu/cr-dedup.c @@ -8,12 +8,12 @@ #include "pagemap.h" #include "restorer.h" -static int cr_dedup_one_pagemap(int id, int flags); +static int cr_dedup_one_pagemap(unsigned long img_id, int flags); int cr_dedup(void) { int close_ret, ret = 0; - int id; + unsigned long img_id; DIR * dirp; struct dirent *ent; @@ -36,18 +36,18 @@ int cr_dedup(void) break; } - ret = sscanf(ent->d_name, "pagemap-%d.img", &id); + ret = sscanf(ent->d_name, "pagemap-%lu.img", &img_id); if (ret == 1) { - pr_info("pid=%d\n", id); - ret = cr_dedup_one_pagemap(id, PR_TASK); + pr_info("pid=%lu\n", img_id); + ret = cr_dedup_one_pagemap(img_id, PR_TASK); if (ret < 0) break; } - ret = sscanf(ent->d_name, "pagemap-shmem-%d.img", &id); + ret = sscanf(ent->d_name, "pagemap-shmem-%lu.img", &img_id); if (ret == 1) { - pr_info("shmid=%d\n", id); - ret = cr_dedup_one_pagemap(id, PR_SHMEM); + pr_info("shmid=%lu\n", img_id); + ret = cr_dedup_one_pagemap(img_id, PR_SHMEM); if (ret < 0) break; } @@ -67,14 +67,14 @@ err: return 0; } -static int cr_dedup_one_pagemap(int id, int flags) +static int cr_dedup_one_pagemap(unsigned long img_id, int flags) { int ret; struct page_read pr; struct page_read * prp; flags |= PR_MOD; - ret = open_page_read(id, &pr, flags); + ret = open_page_read(img_id, &pr, flags); if (ret <= 0) return -1; diff --git a/criu/image-desc.c b/criu/image-desc.c index 4fefdab97..b96eb3e5f 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -27,8 +27,8 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY(INVENTORY, "inventory"), FD_ENTRY(FDINFO, "fdinfo-%u"), - FD_ENTRY(PAGEMAP, "pagemap-%ld"), - FD_ENTRY(SHMEM_PAGEMAP, "pagemap-shmem-%ld"), + FD_ENTRY(PAGEMAP, "pagemap-%lu"), + FD_ENTRY(SHMEM_PAGEMAP, "pagemap-shmem-%lu"), FD_ENTRY(REG_FILES, "reg-files"), FD_ENTRY(EXT_FILES, "ext-files"), FD_ENTRY(NS_FILES, "ns-files"), diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index 3769be482..89e7ea9f0 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -40,14 +40,14 @@ struct page_xfer { struct page_read *parent; }; -extern int open_page_xfer(struct page_xfer *xfer, int fd_type, long id); +extern int open_page_xfer(struct page_xfer *xfer, int fd_type, unsigned long id); struct page_pipe; extern int page_xfer_dump_pages(struct page_xfer *, struct page_pipe *); extern int connect_to_page_server_to_send(void); extern int connect_to_page_server_to_recv(int epfd); extern int disconnect_from_page_server(void); -extern int check_parent_page_xfer(int fd_type, long id); +extern int check_parent_page_xfer(int fd_type, unsigned long id); /* * The post-copy migration makes it necessary to receive pages from @@ -60,9 +60,9 @@ extern int check_parent_page_xfer(int fd_type, long id); */ /* async request/receive of remote pages */ -extern int request_remote_pages(int pid, unsigned long addr, int nr_pages); +extern int request_remote_pages(unsigned long img_id, unsigned long addr, int nr_pages); -typedef int (*ps_async_read_complete)(int pid, unsigned long vaddr, int nr_pages, void *); +typedef int (*ps_async_read_complete)(unsigned long img_id, unsigned long vaddr, int nr_pages, void *); extern int page_server_start_read(void *buf, int nr_pages, ps_async_read_complete complete, void *priv, unsigned flags); diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index 800768308..45284b87d 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -76,7 +76,7 @@ struct page_read { struct iovec bunch; /* record consequent neighbour iovecs to punch together */ unsigned id; /* for logging */ - int pid; /* PID of the process */ + unsigned long img_id; /* pagemap image file ID */ PagemapEntry **pmes; int nr_pmes; @@ -102,8 +102,8 @@ struct page_read { * 0 -- no images * 1 -- opened */ -extern int open_page_read(int pid, struct page_read *, int pr_flags); -extern int open_page_read_at(int dfd, int pid, struct page_read *pr, +extern int open_page_read(unsigned long id, struct page_read *, int pr_flags); +extern int open_page_read_at(int dfd, unsigned long id, struct page_read *pr, int pr_flags); struct task_restore_args; diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 4b848ca20..7ba50502c 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -60,7 +60,7 @@ static void psi2iovec(struct page_server_iov *ps, struct iovec *iov) * numbers that can be met from older CRIUs */ -static inline u64 encode_pm(int type, long id) +static inline u64 encode_pm(int type, unsigned long id) { if (type == CR_FD_PAGEMAP) type = PS_TYPE_PID; @@ -74,7 +74,7 @@ static inline u64 encode_pm(int type, long id) return ((u64)id) << PS_TYPE_BITS | type; } -static int decode_pm(u64 dst_id, long *id) +static int decode_pm(u64 dst_id, unsigned long *id) { int type; @@ -173,7 +173,7 @@ static void close_server_xfer(struct page_xfer *xfer) xfer->sk = -1; } -static int open_page_server_xfer(struct page_xfer *xfer, int fd_type, long id) +static int open_page_server_xfer(struct page_xfer *xfer, int fd_type, unsigned long img_id) { char has_parent; struct page_server_iov pi = { @@ -184,7 +184,7 @@ static int open_page_server_xfer(struct page_xfer *xfer, int fd_type, long id) xfer->write_pagemap = write_pagemap_to_server; xfer->write_pages = write_pages_to_server; xfer->close = close_server_xfer; - xfer->dst_id = encode_pm(fd_type, id); + xfer->dst_id = encode_pm(fd_type, img_id); xfer->parent = NULL; pi.dst_id = xfer->dst_id; @@ -321,11 +321,11 @@ static void close_page_xfer(struct page_xfer *xfer) close_image(xfer->pmi); } -static int open_page_local_xfer(struct page_xfer *xfer, int fd_type, long id) +static int open_page_local_xfer(struct page_xfer *xfer, int fd_type, unsigned long img_id) { u32 pages_id; - xfer->pmi = open_image(fd_type, O_DUMP, id); + xfer->pmi = open_image(fd_type, O_DUMP, img_id); if (!xfer->pmi) return -1; @@ -358,7 +358,7 @@ static int open_page_local_xfer(struct page_xfer *xfer, int fd_type, long id) return -1; } - ret = open_page_read_at(pfd, id, xfer->parent, pr_flags); + ret = open_page_read_at(pfd, img_id, xfer->parent, pr_flags); if (ret <= 0) { pr_perror("No parent image found, though parent directory is set"); xfree(xfer->parent); @@ -376,15 +376,15 @@ out: return 0; } -int open_page_xfer(struct page_xfer *xfer, int fd_type, long id) +int open_page_xfer(struct page_xfer *xfer, int fd_type, unsigned long img_id) { xfer->offset = 0; xfer->transfer_lazy = true; if (opts.use_page_server) - return open_page_server_xfer(xfer, fd_type, id); + return open_page_server_xfer(xfer, fd_type, img_id); else - return open_page_local_xfer(xfer, fd_type, id); + return open_page_local_xfer(xfer, fd_type, img_id); } static int page_xfer_dump_hole(struct page_xfer *xfer, @@ -492,7 +492,7 @@ int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp) * 0 - if a parent image doesn't exist * -1 - in error cases */ -int check_parent_local_xfer(int fd_type, int id) +int check_parent_local_xfer(int fd_type, unsigned long img_id) { char path[PATH_MAX]; struct stat st; @@ -502,7 +502,7 @@ int check_parent_local_xfer(int fd_type, int id) if (pfd < 0 && errno == ENOENT) return 0; - snprintf(path, sizeof(path), imgset_template[fd_type].fmt, id); + snprintf(path, sizeof(path), imgset_template[fd_type].fmt, img_id); ret = fstatat(pfd, path, &st, 0); if (ret == -1 && errno != ENOENT) { pr_perror("Unable to stat %s", path); @@ -518,7 +518,7 @@ int check_parent_local_xfer(int fd_type, int id) static int page_server_check_parent(int sk, struct page_server_iov *pi) { int type, ret; - long id; + unsigned long id; type = decode_pm(pi->dst_id, &id); if (type == -1) { @@ -538,13 +538,13 @@ static int page_server_check_parent(int sk, struct page_server_iov *pi) return 0; } -static int check_parent_server_xfer(int fd_type, long id) +static int check_parent_server_xfer(int fd_type, unsigned long img_id) { struct page_server_iov pi = {}; int has_parent; pi.cmd = PS_IOV_PARENT; - pi.dst_id = encode_pm(fd_type, id); + pi.dst_id = encode_pm(fd_type, img_id); if (send_psi(page_server_sk, &pi)) return -1; @@ -559,12 +559,12 @@ static int check_parent_server_xfer(int fd_type, long id) return has_parent; } -int check_parent_page_xfer(int fd_type, long id) +int check_parent_page_xfer(int fd_type, unsigned long img_id) { if (opts.use_page_server) - return check_parent_server_xfer(fd_type, id); + return check_parent_server_xfer(fd_type, img_id); else - return check_parent_local_xfer(fd_type, id); + return check_parent_local_xfer(fd_type, img_id); } struct page_xfer_job { @@ -596,7 +596,7 @@ static void page_server_close(void) static int page_server_open(int sk, struct page_server_iov *pi) { int type; - long id; + unsigned long id; type = decode_pm(pi->dst_id, &id); if (type == -1) { @@ -604,7 +604,7 @@ static int page_server_open(int sk, struct page_server_iov *pi) return -1; } - pr_info("Opening %d/%ld\n", type, id); + pr_info("Opening %d/%lu\n", type, id); page_server_close(); @@ -1177,13 +1177,13 @@ int connect_to_page_server_to_recv(int epfd) return epoll_add_rfd(epfd, &ps_rfd); } -int request_remote_pages(int pid, unsigned long addr, int nr_pages) +int request_remote_pages(unsigned long img_id, unsigned long addr, int nr_pages) { struct page_server_iov pi = { .cmd = PS_IOV_GET, .nr_pages = nr_pages, .vaddr = addr, - .dst_id = pid, + .dst_id = img_id, }; /* XXX: why MSG_DONTWAIT here? */ diff --git a/criu/pagemap.c b/criu/pagemap.c index e30d9e08d..e6470651f 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -54,7 +54,7 @@ static int punch_hole(struct page_read *pr, unsigned long off, struct iovec * bunch = &pr->bunch; if (!cleanup && can_extend_bunch(bunch, off, len)) { - pr_debug("pr%d-%d:Extend bunch len from %zu to %lu\n", pr->pid, + pr_debug("pr%lu-%u:Extend bunch len from %zu to %lu\n", pr->img_id, pr->id, bunch->iov_len, bunch->iov_len + len); bunch->iov_len += len; } else { @@ -69,7 +69,7 @@ static int punch_hole(struct page_read *pr, unsigned long off, } bunch->iov_base = (void *)off; bunch->iov_len = len; - pr_debug("pr%d-%d:New bunch/%p/%zu/\n", pr->pid, pr->id, bunch->iov_base, bunch->iov_len); + pr_debug("pr%lu-%u:New bunch/%p/%zu/\n", pr->img_id, pr->id, bunch->iov_base, bunch->iov_len); } return 0; } @@ -201,7 +201,7 @@ static int read_parent_page(struct page_read *pr, unsigned long vaddr, do { int p_nr; - pr_debug("\tpr%d-%u Read from parent\n", pr->pid, pr->id); + pr_debug("\tpr%lu-%u Read from parent\n", pr->img_id, pr->id); ret = ppr->seek_pagemap(ppr, vaddr); if (ret <= 0) { pr_err("Missing %lx in parent pagemap\n", vaddr); @@ -249,7 +249,7 @@ static int read_local_page(struct page_read *pr, unsigned long vaddr, if (pr->sync(pr)) return -1; - pr_debug("\tpr%d-%u Read page from self %lx/%"PRIx64"\n", pr->pid, pr->id, pr->cvaddr, pr->pi_off); + pr_debug("\tpr%lu-%u Read page from self %lx/%"PRIx64"\n", pr->img_id, pr->id, pr->cvaddr, pr->pi_off); while (1) { ret = pread(fd, buf + curr, len - curr, pr->pi_off + curr); if (ret < 1) { @@ -402,14 +402,14 @@ static int maybe_read_page_local(struct page_read *pr, unsigned long vaddr, return ret; } -static int read_page_complete(int pid, unsigned long vaddr, int nr_pages, void *priv) +static int read_page_complete(unsigned long img_id, unsigned long vaddr, int nr_pages, void *priv) { int ret = 0; struct page_read *pr = priv; - if (pr->pid != pid) { - pr_err("Out of order read completed (want %d have %d)\n", - pr->pid, pid); + if (pr->img_id != img_id) { + pr_err("Out of order read completed (want %lu have %lu)\n", + pr->img_id, img_id); return -1; } @@ -425,7 +425,7 @@ static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, int ret; /* We always do PR_ASAP mode here (FIXME?) */ - ret = request_remote_pages(pr->pid, vaddr, nr); + ret = request_remote_pages(pr->img_id, vaddr, nr); if (!ret) ret = page_server_start_read(buf, nr, read_page_complete, pr, flags); @@ -435,7 +435,7 @@ static int maybe_read_page_remote(struct page_read *pr, unsigned long vaddr, static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, int nr, void *buf, unsigned flags) { - pr_info("pr%d-%u Read %lx %u pages\n", pr->pid, pr->id, vaddr, nr); + pr_info("pr%lu-%u Read %lx %u pages\n", pr->img_id, pr->id, vaddr, nr); pagemap_bound_check(pr->pe, vaddr, nr); if (pagemap_in_parent(pr->pe)) { @@ -591,7 +591,7 @@ static void reset_pagemap(struct page_read *pr) reset_pagemap(pr->parent); } -static int try_open_parent(int dfd, int pid, struct page_read *pr, int pr_flags) +static int try_open_parent(int dfd, unsigned long id, struct page_read *pr, int pr_flags) { int pfd, ret; struct page_read *parent = NULL; @@ -604,7 +604,7 @@ static int try_open_parent(int dfd, int pid, struct page_read *pr, int pr_flags) if (!parent) goto err_cl; - ret = open_page_read_at(pfd, pid, parent, pr_flags); + ret = open_page_read_at(pfd, id, parent, pr_flags); if (ret < 0) goto err_free; @@ -696,7 +696,7 @@ free_pagemaps: return -1; } -int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) +int open_page_read_at(int dfd, unsigned long img_id, struct page_read *pr, int pr_flags) { int flags, i_typ; static unsigned ids = 1; @@ -736,7 +736,7 @@ int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) pr->pmes = NULL; pr->pieok = false; - pr->pmi = open_image_at(dfd, i_typ, O_RSTR, (long)pid); + pr->pmi = open_image_at(dfd, i_typ, O_RSTR, img_id); if (!pr->pmi) return -1; @@ -745,7 +745,7 @@ int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) return 0; } - if (try_open_parent(dfd, pid, pr, pr_flags)) { + if (try_open_parent(dfd, img_id, pr, pr_flags)) { close_image(pr->pmi); return -1; } @@ -770,7 +770,7 @@ int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) pr->reset = reset_pagemap; pr->io_complete = NULL; /* set up by the client if needed */ pr->id = ids++; - pr->pid = pid; + pr->img_id = img_id; if (remote) pr->maybe_read_page = maybe_read_page_remote; @@ -787,9 +787,9 @@ int open_page_read_at(int dfd, int pid, struct page_read *pr, int pr_flags) return 1; } -int open_page_read(int pid, struct page_read *pr, int pr_flags) +int open_page_read(unsigned long img_id, struct page_read *pr, int pr_flags) { - return open_page_read_at(get_service_fd(IMG_FD_OFF), pid, pr, pr_flags); + return open_page_read_at(get_service_fd(IMG_FD_OFF), img_id, pr, pr_flags); } From 2214568de9d357539d529781bb0ec727dbc24c14 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 20 Oct 2017 10:24:27 +0300 Subject: [PATCH 1133/4375] mount: fix parent shared group dependency in can_mount_now What we do before patch: 1) If we are NOT in the same shared group - if we have some parent's shared group member unmounted, we just wait for it. 2) If we are in the same group - we wait only for members with root path len shorter than ours. That is done to make child mount propagate in all shared group, but I think it is wrong, e.g.: mkdir -p /dir/a/b/c /d /e /f mount --bind /dir/a /d mount --bind /dir/a/b /e mount --bind /f /e/c Before c/r we have: 507 114 182:1017985 / / rw,relatime shared:63 master:60 - ext4 /dev/ploop63624p1 rw,data=ordered,balloon_ino=12 144 507 182:1017985 /dir/a /d rw,relatime shared:63 master:60 - ext4 /dev/ploop63624p1 rw,data=ordered,balloon_ino=12 146 507 182:1017985 /dir/a/b /e rw,relatime shared:63 master:60 - ext4 /dev/ploop63624p1 rw,data=ordered,balloon_ino=12 148 146 182:1017985 /f /e/c rw,relatime shared:63 master:60 - ext4 /dev/ploop63624p1 rw,data=ordered,balloon_ino=12 150 507 182:1017985 /f /dir/a/b/c rw,relatime shared:63 master:60 - ext4 /dev/ploop63624p1 rw,data=ordered,balloon_ino=12 149 144 182:1017985 /f /d/b/c rw,relatime shared:63 master:60 - ext4 /dev/ploop63624p1 rw,data=ordered,balloon_ino=12 After c/r we have: 600 132 182:1017985 / / rw,relatime shared:63 master:60 - ext4 /dev/ploop63624p1 rw,data=ordered,balloon_ino=12 602 600 182:1017985 /f /dir/a/b/c rw,relatime shared:63 master:60 - ext4 /dev/ploop63624p1 rw,data=ordered,balloon_ino=12 603 600 182:1017985 /dir/a /d rw,relatime shared:63 master:60 - ext4 /dev/ploop63624p1 rw,data=ordered,balloon_ino=12 604 600 182:1017985 /dir/a/b /e rw,relatime shared:63 master:60 - ext4 /dev/ploop63624p1 rw,data=ordered,balloon_ino=12 There is no propagation as all mounts are in same shared group and 602(150) has shorter root than 603(144) and 604(146). What we should do: Wait member of our parent's shared group only if it has our 'sibling' mount in it. Sibling mount is the one which had propagated to shared mount of our parent for us when we were mounted. We need to enforce propagation only for these case. https://jira.sw.ru/browse/PSBM-69501 Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 648154371..279eba900 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2132,18 +2132,27 @@ static bool can_mount_now(struct mount_info *mi) shared: if (mi->parent->shared_id) { - struct mount_info *p = mi->parent, *n; + struct mount_info *n; - if (mi->parent->shared_id == mi->shared_id) { - int rlen = strlen(mi->root); - list_for_each_entry(n, &p->mnt_share, mnt_share) - if (strlen(n->root) < rlen && !n->mounted) - return false; - } else { - list_for_each_entry(n, &p->mnt_share, mnt_share) - if (!n->mounted) - return false; - } + list_for_each_entry(n, &mi->parent->mnt_share, mnt_share) + /* + * All mounts from mi's parent shared group which + * have mi's 'sibling' should receive it through + * mount propagation, so all such mounts in parent + * shared group should be mounted beforehand. + */ + if (!n->mounted) { + char path[PATH_MAX], *mp; + struct mount_info *c; + + mp = mnt_get_sibling_path(mi, n, path, sizeof(path)); + if (mp == NULL) + continue; + + list_for_each_entry(c, &n->children, siblings) + if (mounts_equal(mi, c) && !strcmp(mp, c->mountpoint)) + return false; + } } return true; From bf1f9c61c1f1418b6b28a9a435fad8aa3d966d39 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 20 Oct 2017 10:24:28 +0300 Subject: [PATCH 1134/4375] mount: allow overmount on parent with shared group In CT, we do: mkdir -p /a/b/c1 mkdir -p /c2 mount --bind /c2 /a/b/c1 mount --rbind /a/b /a And after that container is not dumpable with error: mnt: Unable to handle mounts under 146:./a Just because overmounts with shared parent group are prohibited, but I can't see any problem with enabling them. https://jira.sw.ru/browse/PSBM-69501 Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 279eba900..bb63ecc85 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -688,7 +688,7 @@ static int validate_mounts(struct mount_info *info, bool for_dump) return -1; if (mnt_is_external(m)) - goto skip_fstype; + continue; /* * Mountpoint can point to / of an FS. In that case this FS @@ -738,13 +738,6 @@ static int validate_mounts(struct mount_info *info, bool for_dump) } } } -skip_fstype: - if (does_mnt_overmount(m) && - !list_empty(&m->parent->mnt_share)) { - pr_err("Unable to handle mounts under %d:%s\n", - m->mnt_id, m->mountpoint); - return -1; - } } return 0; @@ -1685,12 +1678,21 @@ static int propagate_mount(struct mount_info *mi) char path[PATH_MAX], *mp; bool found = false; + /* + * If a mount from parent's shared group is not yet mounted + * it shouldn't have 'sibling' in it - see can_mount_now() + */ + if (!t->mounted) + continue; + mp = mnt_get_sibling_path(mi, t, path, sizeof(path)); if (mp == NULL) continue; list_for_each_entry(c, &t->children, siblings) { if (mounts_equal(mi, c) && !strcmp(mp, c->mountpoint)) { + /* Should not propagate the same mount twice */ + BUG_ON(c->mounted); pr_debug("\t\tPropagate %s\n", c->mountpoint); /* @@ -2287,7 +2289,7 @@ static int try_remap_mount(struct mount_info *m) if (!does_mnt_overmount(m)) return 0; - BUG_ON(!m->parent || !list_empty(&m->parent->mnt_share)); + BUG_ON(!m->parent); r = xmalloc(sizeof(struct mnt_remap_entry)); if (!r) From 2d2381e01d799b9b3708d9331e77bf34f6f697ef Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 27 Oct 2017 11:21:03 +0300 Subject: [PATCH 1135/4375] zdtm: test shared mount propagation is preserved Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/shared_mount_propagation.c | 120 ++++++++++++++++++ .../zdtm/static/shared_mount_propagation.desc | 1 + 3 files changed, 122 insertions(+) create mode 100644 test/zdtm/static/shared_mount_propagation.c create mode 100644 test/zdtm/static/shared_mount_propagation.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index de9ca7467..cac804bed 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -268,6 +268,7 @@ TST_DIR = \ mnt_ro_bind \ mount_paths \ bind-mount \ + shared_mount_propagation \ inotify00 \ inotify01 \ inotify02 \ diff --git a/test/zdtm/static/shared_mount_propagation.c b/test/zdtm/static/shared_mount_propagation.c new file mode 100644 index 000000000..9fe58487f --- /dev/null +++ b/test/zdtm/static/shared_mount_propagation.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check mounts are propagated to shared mounts"; +const char *test_author = "Pavel Tikhomirov "; + +char *dirname; +TEST_OPTION(dirname, string, "directory name", 1); + +int main(int argc, char **argv) +{ + char dir_a[PATH_MAX], dir_b[PATH_MAX], dir_c[PATH_MAX]; + char dir_d[PATH_MAX], dir_e[PATH_MAX], dir_f[PATH_MAX]; + char test_file[PATH_MAX]; + char test_bind_file1[PATH_MAX]; + char test_bind_file2[PATH_MAX]; + char test_bind_file3[PATH_MAX]; + int fd; + + test_init(argc, argv); + + mkdir(dirname, 0700); + + if (mount(dirname, dirname, NULL, MS_BIND, NULL)) { + pr_perror("Unable to self bind mount %s", dirname); + return 1; + } + + if (mount(NULL, dirname, NULL, MS_SHARED, NULL)) { + pr_perror("Unable to make shared mount %s", dirname); + return 1; + } + + snprintf(dir_a, sizeof(dir_a), "%s/a", dirname); + snprintf(dir_d, sizeof(dir_d), "%s/d", dirname); + snprintf(dir_e, sizeof(dir_e), "%s/e", dirname); + snprintf(dir_f, sizeof(dir_f), "%s/f", dirname); + mkdir(dir_a, 0700); + mkdir(dir_d, 0700); + mkdir(dir_e, 0700); + mkdir(dir_f, 0700); + + snprintf(dir_b, sizeof(dir_a), "%s/b", dir_a); + snprintf(dir_c, sizeof(dir_c), "%s/c", dir_b); + mkdir(dir_b, 0700); + mkdir(dir_c, 0700); + + if (mount(dir_a, dir_d, NULL, MS_BIND, NULL)) { + pr_perror("Unable to bind mount %s to %s", dir_a, dir_d); + return 1; + } + + if (mount(dir_b, dir_e, NULL, MS_BIND, NULL)) { + pr_perror("Unable to bind mount %s to %s", dir_b, dir_e); + return 1; + } + + if (mount(dir_f, dir_c, NULL, MS_BIND, NULL)) { + pr_perror("Unable to bind mount %s to %s", dir_f, dir_c); + return 1; + } + + snprintf(test_file, sizeof(test_file), "%s/file", dir_f); + fd = open(test_file, O_CREAT | O_WRONLY | O_EXCL, 0600); + if (fd < 0) { + pr_perror("Unable to open %s", test_file); + return 1; + } + close(fd); + + test_daemon(); + test_waitsig(); + + snprintf(test_bind_file1, sizeof(test_bind_file1), "%s/file", dir_c); + snprintf(test_bind_file2, sizeof(test_bind_file2), "%s/b/c/file", dir_d); + snprintf(test_bind_file3, sizeof(test_bind_file3), "%s/c/file", dir_e); + + + if (access(test_file, F_OK)) { + pr_perror("%s doesn't exist", test_file); + return 1; + } + + if (access(test_bind_file1, F_OK)) { + pr_perror("%s doesn't exist", test_bind_file1); + return 1; + } + + if (access(test_bind_file2, F_OK)) { + pr_perror("%s doesn't exist", test_bind_file2); + return 1; + } + + if (access(test_bind_file3, F_OK)) { + pr_perror("%s doesn't exist", test_bind_file3); + return 1; + } + + if (umount(dir_c)) { + pr_perror("Unable to umount %s", dir_c); + return 1; + } + + if (umount(dir_e)) { + pr_perror("Unable to umount %s", dir_e); + return 1; + } + + if (umount(dir_d)) { + pr_perror("Unable to umount %s", dir_d); + return 1; + } + + pass(); + return 0; +} diff --git a/test/zdtm/static/shared_mount_propagation.desc b/test/zdtm/static/shared_mount_propagation.desc new file mode 100644 index 000000000..7657ba45c --- /dev/null +++ b/test/zdtm/static/shared_mount_propagation.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns', 'flags': 'suid'} From 926e42ac632dc78af0f9c82adf9439763df1da94 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 27 Oct 2017 11:21:04 +0300 Subject: [PATCH 1136/4375] zdtm: test overmounting with shared parent works Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + .../static/overmount_with_shared_parent.c | 69 +++++++++++++++++++ .../static/overmount_with_shared_parent.desc | 1 + 3 files changed, 71 insertions(+) create mode 100644 test/zdtm/static/overmount_with_shared_parent.c create mode 100644 test/zdtm/static/overmount_with_shared_parent.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index cac804bed..3c057634d 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -269,6 +269,7 @@ TST_DIR = \ mount_paths \ bind-mount \ shared_mount_propagation \ + overmount_with_shared_parent \ inotify00 \ inotify01 \ inotify02 \ diff --git a/test/zdtm/static/overmount_with_shared_parent.c b/test/zdtm/static/overmount_with_shared_parent.c new file mode 100644 index 000000000..8261fb969 --- /dev/null +++ b/test/zdtm/static/overmount_with_shared_parent.c @@ -0,0 +1,69 @@ +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check overmount on shared parent works"; +const char *test_author = "Pavel Tikhomirov "; + +char *dirname; +TEST_OPTION(dirname, string, "directory name", 1); + +int main(int argc, char **argv) +{ + char dir_a[PATH_MAX], dir_b[PATH_MAX], dir_c[PATH_MAX]; + char dir_d[PATH_MAX], dir_a_c[PATH_MAX]; + + test_init(argc, argv); + + mkdir(dirname, 0700); + + if (mount(dirname, dirname, NULL, MS_BIND, NULL)) { + pr_perror("Unable to self bind mount %s", dirname); + return 1; + } + + if (mount(NULL, dirname, NULL, MS_SHARED, NULL)) { + pr_perror("Unable to make shared mount %s", dirname); + return 1; + } + + snprintf(dir_a, sizeof(dir_a), "%s/a", dirname); + snprintf(dir_d, sizeof(dir_d), "%s/d", dirname); + mkdir(dir_a, 0700); + mkdir(dir_d, 0700); + + snprintf(dir_b, sizeof(dir_a), "%s/b", dir_a); + snprintf(dir_c, sizeof(dir_c), "%s/c", dir_b); + mkdir(dir_b, 0700); + mkdir(dir_c, 0700); + + if (mount(dir_b, dir_a, NULL, MS_BIND, NULL)) { + pr_perror("Unable to bind mount %s to %s", dir_b, dir_a); + return 1; + } + + snprintf(dir_a_c, sizeof(dir_a_c), "%s/c", dir_a); + + if (mount(dir_d, dir_a_c, NULL, MS_BIND, NULL)) { + pr_perror("Unable to bind mount %s to %s", dir_d, dir_a_c); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (umount(dir_a_c)) { + pr_perror("Unable to umount %s", dir_a_c); + return 1; + } + + if (umount(dir_a)) { + pr_perror("Unable to umount %s", dir_a); + return 1; + } + + pass(); + return 0; +} diff --git a/test/zdtm/static/overmount_with_shared_parent.desc b/test/zdtm/static/overmount_with_shared_parent.desc new file mode 100644 index 000000000..7657ba45c --- /dev/null +++ b/test/zdtm/static/overmount_with_shared_parent.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns', 'flags': 'suid'} From ec273275febbfb4c6236aebfdcbf5ab7ad12aacc Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 1 Nov 2017 16:19:18 +0300 Subject: [PATCH 1137/4375] crit: Add INET6 familiy Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- lib/py/images/pb2dict.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index bf05278ff..6b0ead7fa 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -124,7 +124,7 @@ gen_maps = { } sk_maps = { - 'family' : { 2: 'INET' }, + 'family' : { 2: 'INET', 10: 'INET6'}, 'type' : { 1: 'STREAM', 2: 'DGRAM' }, 'state' : { 1: 'ESTABLISHED', 7: 'CLOSE', 10: 'LISTEN' }, 'proto' : { 6: 'TCP' }, From 56cd56706d5e4afd56f865f956ecaf7d865a0a0a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 1 Nov 2017 16:19:19 +0300 Subject: [PATCH 1138/4375] crit: Add more families into socket decoding Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- lib/py/images/pb2dict.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index 6b0ead7fa..5d720ba90 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -124,7 +124,11 @@ gen_maps = { } sk_maps = { - 'family' : { 2: 'INET', 10: 'INET6'}, + 'family' : { 1: 'UNIX', + 2: 'INET', + 10: 'INET6', + 16: 'NETLINK', + 17: 'PACKET' }, 'type' : { 1: 'STREAM', 2: 'DGRAM' }, 'state' : { 1: 'ESTABLISHED', 7: 'CLOSE', 10: 'LISTEN' }, 'proto' : { 6: 'TCP' }, From d4c29ab7cb4eea998c3da4844c21a313925aae7e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 1 Nov 2017 16:19:20 +0300 Subject: [PATCH 1139/4375] crit: Add protocols decoding Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- lib/py/images/pb2dict.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index 5d720ba90..bcaa49b3e 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -131,7 +131,10 @@ sk_maps = { 17: 'PACKET' }, 'type' : { 1: 'STREAM', 2: 'DGRAM' }, 'state' : { 1: 'ESTABLISHED', 7: 'CLOSE', 10: 'LISTEN' }, - 'proto' : { 6: 'TCP' }, + 'proto' : { 0: 'IP', + 6: 'TCP', + 17: 'UDP', + 136: 'UDPLITE' }, } gen_rmaps = { k: {v2:k2 for k2,v2 in v.items()} for k,v in gen_maps.items() } From 4d0fc1a4969c2d54d58a8ea4b54b24be09914792 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 1 Nov 2017 16:19:21 +0300 Subject: [PATCH 1140/4375] crit: Add socket types decoding Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- lib/py/images/pb2dict.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index bcaa49b3e..ed82a5fe2 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -129,7 +129,11 @@ sk_maps = { 10: 'INET6', 16: 'NETLINK', 17: 'PACKET' }, - 'type' : { 1: 'STREAM', 2: 'DGRAM' }, + 'type' : { 1: 'STREAM', + 2: 'DGRAM', + 3: 'RAW', + 5: 'SEQPACKET', + 10: 'PACKET' }, 'state' : { 1: 'ESTABLISHED', 7: 'CLOSE', 10: 'LISTEN' }, 'proto' : { 0: 'IP', 6: 'TCP', From fc21d6fb53f228622bc4d67c53b9f0e74cbd1fbb Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 1 Nov 2017 16:19:22 +0300 Subject: [PATCH 1141/4375] crit: Add socket states decoding Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- lib/py/images/pb2dict.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index ed82a5fe2..fe3dcf175 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -134,7 +134,16 @@ sk_maps = { 3: 'RAW', 5: 'SEQPACKET', 10: 'PACKET' }, - 'state' : { 1: 'ESTABLISHED', 7: 'CLOSE', 10: 'LISTEN' }, + 'state' : { 1: 'ESTABLISHED', + 2: 'SYN_SENT', + 3: 'SYN_RECV', + 4: 'FIN_WAIT1', + 5: 'FIN_WAIT2', + 6: 'TIME_WAIT', + 7: 'CLOSE', + 8: 'CLOSE_WAIT', + 9: 'LAST_ACK', + 10: 'LISTEN' }, 'proto' : { 0: 'IP', 6: 'TCP', 17: 'UDP', From 2e16cc1e4f83e9ab5406a25b85c27328b841f515 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 1 Nov 2017 16:19:23 +0300 Subject: [PATCH 1142/4375] compel: Do not loose sign of result in compat syscall Regs are present in unsigned format so convert them into signed first to provide results. In particular if memfd_create syscall failed we won't notice -ENOMEM error but rather treat it as unsigned hex value | (05.303002) Putting parasite blob into 0x7f1c6ffe0000->0xfffffff4 | (05.303234) Putting tsock into pid 42773 Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/infect.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index 9c919e64e..e546ee376 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -293,9 +293,10 @@ int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, unsigned long arg6) { user_regs_struct_t regs = ctl->orig.regs; + bool native = user_regs_native(®s); int err; - if (user_regs_native(®s)) { + if (native) { user_regs_struct64 *r = ®s.native; r->ax = (uint64_t)nr; @@ -321,7 +322,9 @@ int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, err = compel_execute_syscall(ctl, ®s, code_int_80); } - *ret = get_user_reg(®s, ax); + *ret = native ? + (long)get_user_reg(®s, ax) : + (int)get_user_reg(®s, ax); return err; } @@ -345,6 +348,13 @@ void *remote_mmap(struct parasite_ctl *ctl, return NULL; } + /* + * For compat tasks the address in foreign process + * must lay inside 4 bytes. + */ + if (compat_task) + map &= 0xfffffffful; + return (void *)map; } From 3503332086e9156398388ce03be74ec7443138f7 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 31 Oct 2017 08:53:42 +0300 Subject: [PATCH 1143/4375] zdtm: check a case when one port is shared between two sockets SO_REUSEPORT allows multiple sockets on the same host to bind to the same port. Signed-off-by: Andrei Vagin --- test/zdtm/lib/tcp.c | 21 ++- test/zdtm/lib/zdtmtst.h | 9 ++ test/zdtm/static/Makefile | 1 + test/zdtm/static/socket-tcp-reuseport.c | 171 +++++++++++++++++++++ test/zdtm/static/socket-tcp-reuseport.desc | 1 + 5 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 test/zdtm/static/socket-tcp-reuseport.c create mode 100644 test/zdtm/static/socket-tcp-reuseport.desc diff --git a/test/zdtm/lib/tcp.c b/test/zdtm/lib/tcp.c index 4fb190266..e753e3c8a 100644 --- a/test/zdtm/lib/tcp.c +++ b/test/zdtm/lib/tcp.c @@ -10,6 +10,16 @@ union sockaddr_inet { }; int tcp_init_server(int family, int *port) +{ + struct zdtm_tcp_opts opts = { + .reuseaddr = true, + .reuseport = false, + }; + + return tcp_init_server_with_opts(family, port, &opts); +} + +int tcp_init_server_with_opts(int family, int *port, struct zdtm_tcp_opts *opts) { union sockaddr_inet addr; int sock; @@ -25,13 +35,20 @@ int tcp_init_server(int family, int *port) } else return -1; - sock = socket(family, SOCK_STREAM, IPPROTO_TCP); + sock = socket(family, SOCK_STREAM | opts->flags, IPPROTO_TCP); if (sock == -1) { pr_perror("socket() failed"); return -1; } - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1 ) { + if (opts->reuseport && + setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(int)) == -1) { + pr_perror(""); + return -1; + } + + if (opts->reuseaddr && + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1 ) { pr_perror("setsockopt() error"); return -1; } diff --git a/test/zdtm/lib/zdtmtst.h b/test/zdtm/lib/zdtmtst.h index de01cc2be..cd513b9c9 100644 --- a/test/zdtm/lib/zdtmtst.h +++ b/test/zdtm/lib/zdtmtst.h @@ -3,6 +3,7 @@ #include #include +#include #define INPROGRESS ".inprogress" @@ -141,4 +142,12 @@ extern int tcp_init_server(int family, int *port); extern int tcp_accept_server(int sock); extern int tcp_init_client(int family, char *servIP, unsigned short servPort); +struct zdtm_tcp_opts { + bool reuseaddr; + bool reuseport; + int flags; +}; + +extern int tcp_init_server_with_opts(int family, int *port, struct zdtm_tcp_opts *opts); + #endif /* _VIMITESU_H_ */ diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 3c057634d..e58887bec 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -66,6 +66,7 @@ TST_NOFILE := \ socket-tcp-reseted \ socket-tcp6 \ socket-tcp-local \ + socket-tcp-reuseport \ socket-tcp-nfconntrack \ socket-tcp6-local \ socket-tcpbuf \ diff --git a/test/zdtm/static/socket-tcp-reuseport.c b/test/zdtm/static/socket-tcp-reuseport.c new file mode 100644 index 000000000..4cd1802f9 --- /dev/null +++ b/test/zdtm/static/socket-tcp-reuseport.c @@ -0,0 +1,171 @@ +#include "zdtmtst.h" + +#ifdef ZDTM_IPV6 +#define ZDTM_FAMILY AF_INET6 +#else +#define ZDTM_FAMILY AF_INET +#endif + +const char *test_doc = "Check a case when one port is shared between two listening sockets\n"; +const char *test_author = "Andrey Vagin +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for sockaddr_in and inet_ntoa() */ + +#define BUF_SIZE 4096 + +int read_data(int fd, unsigned char *buf, int size) +{ + int cur = 0; + int ret; + while (cur != size) { + ret = read(fd, buf + cur, size - cur); + if (ret <= 0) + return -1; + cur += ret; + } + + return 0; +} + +int write_data(int fd, const unsigned char *buf, int size) +{ + int cur = 0; + int ret; + + while (cur != size) { + ret = write(fd, buf + cur, size - cur); + if (ret <= 0) + return -1; + cur += ret; + } + + return 0; +} + +int main(int argc, char **argv) +{ + struct zdtm_tcp_opts opts = { .reuseaddr = false, + .reuseport = true, + .flags = SOCK_NONBLOCK}; + unsigned char buf[BUF_SIZE]; + int port = 8880, port2; + int fd, fd_s, fd_s2, clt, i; + socklen_t optlen; + int no = 0, val; + uint32_t crc; + + test_init(argc, argv); + + if ((fd_s = tcp_init_server_with_opts(ZDTM_FAMILY, &port, &opts)) < 0) { + pr_err("initializing server failed\n"); + return 1; + } + + port2 = port; + if ((fd_s2 = tcp_init_server_with_opts(ZDTM_FAMILY, &port2, &opts)) < 0) { + pr_err("initializing server failed\n"); + return 1; + } + if (port != port2) + return 1; + + if (setsockopt(fd_s, SOL_SOCKET, SO_REUSEPORT, &no, sizeof(int)) == -1 ) { + pr_perror("Unable to set SO_REUSEPORT"); + return -1; + } + + + clt = tcp_init_client(ZDTM_FAMILY, "localhost", port); + if (clt < 0) + return 1; + + /* + * parent is server of TCP connection + */ + fd = tcp_accept_server(fd_s); + if (fd < 0) + fd = tcp_accept_server(fd_s2); + if (fd < 0) { + pr_err("can't accept client connection\n"); + return 1; + } + + test_daemon(); + test_waitsig(); + + + optlen = sizeof(val); + if (getsockopt(fd_s, SOL_SOCKET, SO_REUSEPORT, &val, &optlen)) { + pr_perror("getsockopt"); + return 1; + } + if (val == 1) { + fail("SO_REUSEPORT is set for %d\n", fd); + return 1; + } + optlen = sizeof(val); + if (getsockopt(fd_s2, SOL_SOCKET, SO_REUSEPORT, &val, &optlen)) { + pr_perror("getsockopt"); + return 1; + } + if (val != 1) { + fail("SO_REUSEPORT is not set for %d\n", fd); + return 1; + } + + for (i = 0; ; i++) { + crc = 0; + datagen(buf, BUF_SIZE, &crc); + if (write_data(fd, buf, BUF_SIZE)) { + pr_perror("can't write"); + return 1; + } + + memset(buf, 0, BUF_SIZE); + if (read_data(clt, buf, BUF_SIZE)) { + pr_perror("read less then have to"); + return 1; + } + crc = 0; + if (datachk(buf, BUF_SIZE, &crc)) + return 2; + + close(clt); + close(fd); + + if (i == 2) + break; + + clt = tcp_init_client(ZDTM_FAMILY, "localhost", port); + if (clt < 0) + return 1; + + /* + * parent is server of TCP connection + */ + fd = tcp_accept_server(fd_s2); + if (fd < 0) { + fd = tcp_accept_server(fd_s); + close(fd_s); + } else { + close(fd_s2); + } + if (fd < 0) { + pr_err("can't accept client connection %d\n", i); + return 1; + } + } + + pass(); + return 0; +} diff --git a/test/zdtm/static/socket-tcp-reuseport.desc b/test/zdtm/static/socket-tcp-reuseport.desc new file mode 100644 index 000000000..6a406f6ec --- /dev/null +++ b/test/zdtm/static/socket-tcp-reuseport.desc @@ -0,0 +1 @@ +{'flavor': 'h ns uns', 'opts': '--tcp-established', 'flags': 'nouser samens'} From 09b93e0ac59117f45aa681d47da32b2615bd0fb7 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 31 Oct 2017 08:53:43 +0300 Subject: [PATCH 1144/4375] sk-inet: restore a value of SO_REUSEPORT The SO_REUSEPORT option allows multiple sockets on the same host to bind to the same port. This option has to ve restored when all sockets are bound to a port. The same logic is already used to restore SO_REUSEADDR. Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 10 ++++++++-- criu/sockets.c | 4 ++++ images/sk-opts.proto | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 93de1e2ee..06275c922 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -586,14 +586,18 @@ static int post_open_inet_sk(struct file_desc *d, int sk) } /* SO_REUSEADDR is set for all sockets */ - if (ii->ie->opts->reuseaddr) + if (ii->ie->opts->reuseaddr && ii->ie->opts->so_reuseport) return 0; if (atomic_read(&ii->port->users)) return 1; val = ii->ie->opts->reuseaddr; - if (restore_opt(sk, SOL_SOCKET, SO_REUSEADDR, &val)) + if (!val && restore_opt(sk, SOL_SOCKET, SO_REUSEADDR, &val)) + return -1; + + val = ii->ie->opts->so_reuseport; + if (!val && restore_opt(sk, SOL_SOCKET, SO_REUSEPORT, &val)) return -1; return 0; @@ -653,6 +657,8 @@ static int open_inet_sk(struct file_desc *d, int *new_fd) */ if (restore_opt(sk, SOL_SOCKET, SO_REUSEADDR, &yes)) goto err; + if (restore_opt(sk, SOL_SOCKET, SO_REUSEPORT, &yes)) + goto err; if (tcp_connection(ie)) { if (!opts.tcp_established_ok && !opts.tcp_close) { diff --git a/criu/sockets.c b/criu/sockets.c index c2a5cd130..70d57b009 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -524,6 +524,10 @@ int dump_socket_opts(int sk, SkOptsEntry *soe) soe->reuseaddr = val ? true : false; soe->has_reuseaddr = true; + ret |= dump_opt(sk, SOL_SOCKET, SO_REUSEPORT, &val); + soe->so_reuseport = val ? true : false; + soe->has_so_reuseport = true; + ret |= dump_opt(sk, SOL_SOCKET, SO_PASSCRED, &val); soe->has_so_passcred = true; soe->so_passcred = val ? true : false; diff --git a/images/sk-opts.proto b/images/sk-opts.proto index b5374c976..af61975e9 100644 --- a/images/sk-opts.proto +++ b/images/sk-opts.proto @@ -21,6 +21,7 @@ message sk_opts_entry { optional string so_bound_dev = 15; repeated fixed64 so_filter = 16; + optional bool so_reuseport = 17; } enum sk_shutdown { From 6e770e50b80172976b57edfac915cc8f8dd0f618 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 2 Nov 2017 00:40:34 +0300 Subject: [PATCH 1145/4375] soccr: c/r ipv6 sockets which handles ipv4 connections IPv6 listening sockets can accept both ipv4 and ipv6 connections, in both cases a family of an accepted socket will be AF_INET6. But we have to send tcp packets accoding with a connection type. ------------------------ grep Error ------------------------ (00.002320) 53: Debug: Will set rcv_wscale to 7 (00.002325) 53: Debug: Will turn timestamps on (00.002331) 53: Debug: Will set mss clamp to 65495 (00.002338) 53: Debug: Restoring TCP 1 queue data 2 bytes (00.002403) 53: Error (soccr/soccr.c:673): Unable to send a fin packet: libnet_write_raw_ipv6(): -1 bytes written (Network is unreachable) (00.002434) 53: Error (criu/files.c:1191): Unable to open fd=3 id=0x6 (00.002506) Error (criu/cr-restore.c:2171): Restoring FAILED. ------------------------ ERROR OVER ------------------------ Signed-off-by: Andrei Vagin Signed-off-by: Andrei Vagin --- soccr/soccr.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/soccr/soccr.c b/soccr/soccr.c index 394095f00..2d49766dc 100644 --- a/soccr/soccr.c +++ b/soccr/soccr.c @@ -580,16 +580,33 @@ static int libsoccr_set_sk_data_noq(struct libsoccr_sk *sk, return 0; } +/* IPv4-Mapped IPv6 Addresses */ +static int ipv6_addr_mapped(union libsoccr_addr *addr) +{ + return (addr->v6.sin6_addr.s6_addr32[2] == htonl(0x0000ffff)); +} + static int send_fin(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigned data_size, uint8_t flags) { - int ret, exit_code = -1; + uint32_t src_v4 = sk->src_addr->v4.sin_addr.s_addr; + uint32_t dst_v4 = sk->dst_addr->v4.sin_addr.s_addr; + int ret, exit_code = -1, family; char errbuf[LIBNET_ERRBUF_SIZE]; int mark = SOCCR_MARK;; int libnet_type; libnet_t *l; - if (sk->dst_addr->sa.sa_family == AF_INET6) + family = sk->dst_addr->sa.sa_family; + + if (family == AF_INET6 && ipv6_addr_mapped(sk->dst_addr)) { + /* TCP over IPv4 */ + family = AF_INET; + dst_v4 = sk->dst_addr->v6.sin6_addr.s6_addr32[3]; + src_v4 = sk->src_addr->v6.sin6_addr.s6_addr32[3]; + } + + if (family == AF_INET6) libnet_type = LIBNET_RAW6; else libnet_type = LIBNET_RAW4; @@ -627,7 +644,7 @@ static int send_fin(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, goto err; } - if (sk->dst_addr->sa.sa_family == AF_INET6) { + if (family == AF_INET6) { struct libnet_in6_addr src, dst; memcpy(&dst, &sk->dst_addr->v6.sin6_addr, sizeof(dst)); @@ -644,7 +661,7 @@ static int send_fin(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, 0, /* payload size */ l, /* libnet handle */ 0); /* libnet id */ - } else if (sk->dst_addr->sa.sa_family == AF_INET) + } else if (family == AF_INET) ret = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_TCP_H + 20, /* length */ 0, /* TOS */ @@ -653,8 +670,8 @@ static int send_fin(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, 64, /* TTL */ IPPROTO_TCP, /* protocol */ 0, /* checksum */ - sk->dst_addr->v4.sin_addr.s_addr, /* source IP */ - sk->src_addr->v4.sin_addr.s_addr, /* destination IP */ + dst_v4, /* source IP */ + src_v4, /* destination IP */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ From 00413cb5a78a69a2fa81bf501bc33bf0f7d2e7c3 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 2 Nov 2017 00:40:35 +0300 Subject: [PATCH 1146/4375] test: check ipv6 sockets which handle ipv4 connections A server socket is created with AF_INET6, but a client socket is create with AF_INET. Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 18 ++++++++++++++++++ test/zdtm/static/socket-tcp-close-wait.c | 9 +++++++-- test/zdtm/static/socket-tcp-closed.c | 9 +++++++-- test/zdtm/static/socket-tcp-closing.c | 9 +++++++-- test/zdtm/static/socket-tcp-fin-wait1.c | 9 +++++++-- test/zdtm/static/socket-tcp-last-ack.desc | 2 +- test/zdtm/static/socket-tcp-reseted.c | 10 +++++++--- test/zdtm/static/socket-tcp-syn-sent.c | 9 +++++++-- test/zdtm/static/socket-tcp-unconn.c | 9 +++++++-- test/zdtm/static/socket-tcp.c | 9 +++++++-- test/zdtm/static/socket-tcp4v6-close-wait.c | 1 + test/zdtm/static/socket-tcp4v6-close-wait.desc | 1 + test/zdtm/static/socket-tcp4v6-closed.c | 1 + test/zdtm/static/socket-tcp4v6-closed.desc | 1 + test/zdtm/static/socket-tcp4v6-closing.c | 1 + test/zdtm/static/socket-tcp4v6-closing.desc | 1 + test/zdtm/static/socket-tcp4v6-fin-wait1.c | 1 + test/zdtm/static/socket-tcp4v6-fin-wait1.desc | 1 + test/zdtm/static/socket-tcp4v6-fin-wait2.c | 1 + test/zdtm/static/socket-tcp4v6-fin-wait2.desc | 1 + test/zdtm/static/socket-tcp4v6-last-ack.c | 1 + test/zdtm/static/socket-tcp4v6-last-ack.desc | 1 + test/zdtm/static/socket-tcp4v6-local.c | 1 + test/zdtm/static/socket-tcp4v6-local.desc | 1 + test/zdtm/static/socket-tcp4v6.c | 1 + test/zdtm/static/socket-tcp4v6.desc | 1 + test/zdtm/static/socket_listen.c | 9 +++++++-- test/zdtm/static/socket_listen4v6.c | 1 + 28 files changed, 99 insertions(+), 20 deletions(-) create mode 120000 test/zdtm/static/socket-tcp4v6-close-wait.c create mode 120000 test/zdtm/static/socket-tcp4v6-close-wait.desc create mode 120000 test/zdtm/static/socket-tcp4v6-closed.c create mode 120000 test/zdtm/static/socket-tcp4v6-closed.desc create mode 120000 test/zdtm/static/socket-tcp4v6-closing.c create mode 120000 test/zdtm/static/socket-tcp4v6-closing.desc create mode 120000 test/zdtm/static/socket-tcp4v6-fin-wait1.c create mode 120000 test/zdtm/static/socket-tcp4v6-fin-wait1.desc create mode 120000 test/zdtm/static/socket-tcp4v6-fin-wait2.c create mode 120000 test/zdtm/static/socket-tcp4v6-fin-wait2.desc create mode 120000 test/zdtm/static/socket-tcp4v6-last-ack.c create mode 120000 test/zdtm/static/socket-tcp4v6-last-ack.desc create mode 120000 test/zdtm/static/socket-tcp4v6-local.c create mode 120000 test/zdtm/static/socket-tcp4v6-local.desc create mode 120000 test/zdtm/static/socket-tcp4v6.c create mode 120000 test/zdtm/static/socket-tcp4v6.desc create mode 120000 test/zdtm/static/socket_listen4v6.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index e58887bec..0e1db5c5c 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -26,6 +26,7 @@ TST_NOFILE := \ sched_policy00 \ socket_listen \ socket_listen6 \ + socket_listen4v6 \ socket_udp \ socket6_udp \ socket_udp_shutdown \ @@ -65,27 +66,35 @@ TST_NOFILE := \ socket-tcp \ socket-tcp-reseted \ socket-tcp6 \ + socket-tcp4v6 \ socket-tcp-local \ socket-tcp-reuseport \ socket-tcp-nfconntrack \ socket-tcp6-local \ + socket-tcp4v6-local \ socket-tcpbuf \ socket-tcpbuf-local \ socket-tcpbuf6-local \ socket-tcpbuf6 \ socket-tcp-fin-wait1 \ socket-tcp6-fin-wait1 \ + socket-tcp4v6-fin-wait1 \ socket-tcp-fin-wait2 \ socket-tcp6-fin-wait2 \ + socket-tcp4v6-fin-wait2 \ socket-tcp-close-wait \ socket-tcp6-close-wait \ + socket-tcp4v6-close-wait \ socket-tcp-last-ack \ socket-tcp6-last-ack \ + socket-tcp4v6-last-ack \ socket-tcp-closing \ socket-tcp6-closing \ + socket-tcp4v6-closing \ socket-tcp-closed \ socket-tcp-closed-last-ack \ socket-tcp6-closed \ + socket-tcp4v6-closed \ socket-tcp-close0 \ socket-tcp-close1 \ socket-tcp-unconn \ @@ -435,14 +444,18 @@ sem: CFLAGS += -DNEW_IPC_NS posix_timers: LDLIBS += -lrt -pthread remap_dead_pid_root: CFLAGS += -DREMAP_PID_ROOT socket-tcp6: CFLAGS += -D ZDTM_IPV6 +socket-tcp4v6: CFLAGS += -D ZDTM_IPV4V6 socket-tcpbuf6: CFLAGS += -D ZDTM_IPV6 socket-tcpbuf-local: CFLAGS += -D ZDTM_TCP_LOCAL socket-tcpbuf6-local: CFLAGS += -D ZDTM_TCP_LOCAL -D ZDTM_IPV6 socket-tcp6-local: CFLAGS += -D ZDTM_TCP_LOCAL -D ZDTM_IPV6 +socket-tcp4v6-local: CFLAGS += -D ZDTM_TCP_LOCAL -D ZDTM_IPV4V6 socket-tcp-local: CFLAGS += -D ZDTM_TCP_LOCAL socket-tcp-nfconntrack: CFLAGS += -D ZDTM_TCP_LOCAL -DZDTM_CONNTRACK socket_listen6: CFLAGS += -D ZDTM_IPV6 +socket_listen4v6: CFLAGS += -D ZDTM_IPV4V6 socket-tcp6-closed: CFLAGS += -D ZDTM_IPV6 +socket-tcp6-closed: CFLAGS += -D ZDTM_IPV4V6 socket-tcp-closed-last-ack: CFLAGS += -D ZDTM_TCP_LAST_ACK mnt_ext_manual: CFLAGS += -D ZDTM_EXTMAP_MANUAL sigpending: LDLIBS += -lrt @@ -474,12 +487,17 @@ socket-tcp-fin-wait1: CFLAGS += -D ZDTM_TCP_FIN_WAIT1 socket-tcp-fin-wait2: CFLAGS += -D ZDTM_TCP_FIN_WAIT2 socket-tcp6-fin-wait1: CFLAGS += -D ZDTM_TCP_FIN_WAIT1 -D ZDTM_IPV6 socket-tcp6-fin-wait2: CFLAGS += -D ZDTM_TCP_FIN_WAIT2 -D ZDTM_IPV6 +socket-tcp4v6-fin-wait1: CFLAGS += -D ZDTM_TCP_FIN_WAIT1 -D ZDTM_IPV4V6 +socket-tcp4v6-fin-wait2: CFLAGS += -D ZDTM_TCP_FIN_WAIT2 -D ZDTM_IPV4V6 socket-tcp-close-wait: CFLAGS += -D ZDTM_TCP_CLOSE_WAIT socket-tcp6-close-wait: CFLAGS += -D ZDTM_TCP_CLOSE_WAIT -D ZDTM_IPV6 +socket-tcp4v6-close-wait: CFLAGS += -D ZDTM_TCP_CLOSE_WAIT -D ZDTM_IPV4V6 socket-tcp-last-ack: CFLAGS += -D ZDTM_TCP_LAST_ACK socket-tcp6-last-ack: CFLAGS += -D ZDTM_TCP_LAST_ACK -D ZDTM_IPV6 socket-tcp6-closing: CFLAGS += -D ZDTM_IPV6 socket-tcp6-unconn: CFLAGS += -D ZDTM_IPV6 +socket-tcp4v6-last-ack: CFLAGS += -D ZDTM_TCP_LAST_ACK -D ZDTM_IPV4V6 +socket-tcp4v6-closing: CFLAGS += -D ZDTM_IPV4V6 pty-console: CFLAGS += -D ZDTM_DEV_CONSOLE diff --git a/test/zdtm/static/socket-tcp-close-wait.c b/test/zdtm/static/socket-tcp-close-wait.c index ff79c0cd7..3e3462bff 100644 --- a/test/zdtm/static/socket-tcp-close-wait.c +++ b/test/zdtm/static/socket-tcp-close-wait.c @@ -1,9 +1,14 @@ #include "zdtmtst.h" -#ifdef ZDTM_IPV6 +#ifdef ZDTM_IPV4V6 +#define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET6 +#elif defined(ZDTM_IPV6) #define ZDTM_FAMILY AF_INET6 +#define ZDTM_SRV_FAMILY AF_INET6 #else #define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET #endif const char *test_doc = "Check sockets in TCP_WAIT_STOP and TCP_LAST_ACK states\n"; @@ -186,7 +191,7 @@ int main(int argc, char **argv) if (!newns) test_init(argc, argv); - if ((fd_s = tcp_init_server(ZDTM_FAMILY, &port)) < 0) { + if ((fd_s = tcp_init_server(ZDTM_SRV_FAMILY, &port)) < 0) { pr_err("initializing server failed"); return 1; } diff --git a/test/zdtm/static/socket-tcp-closed.c b/test/zdtm/static/socket-tcp-closed.c index 2125b00be..0447e95b2 100644 --- a/test/zdtm/static/socket-tcp-closed.c +++ b/test/zdtm/static/socket-tcp-closed.c @@ -1,9 +1,14 @@ #include "zdtmtst.h" -#ifdef ZDTM_IPV6 +#ifdef ZDTM_IPV4V6 +#define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET6 +#elif defined(ZDTM_IPV6) #define ZDTM_FAMILY AF_INET6 +#define ZDTM_SRV_FAMILY AF_INET6 #else #define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET #endif const char *test_doc = "Check closed tcp sockets\n"; @@ -45,7 +50,7 @@ int main(int argc, char **argv) return 1; } - if ((fd_s = tcp_init_server(ZDTM_FAMILY, &port)) < 0) { + if ((fd_s = tcp_init_server(ZDTM_SRV_FAMILY, &port)) < 0) { pr_err("initializing server failed\n"); return 1; } diff --git a/test/zdtm/static/socket-tcp-closing.c b/test/zdtm/static/socket-tcp-closing.c index 14c9227d2..23d49cc86 100644 --- a/test/zdtm/static/socket-tcp-closing.c +++ b/test/zdtm/static/socket-tcp-closing.c @@ -1,9 +1,14 @@ #include "zdtmtst.h" -#ifdef ZDTM_IPV6 +#ifdef ZDTM_IPV4V6 +#define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET6 +#elif defined(ZDTM_IPV6) #define ZDTM_FAMILY AF_INET6 +#define ZDTM_SRV_FAMILY AF_INET6 #else #define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET #endif const char *test_doc = "Check sockets in the TCP_CLOSING state\n"; @@ -160,7 +165,7 @@ int main(int argc, char **argv) if (!newns) test_init(argc, argv); - if ((fd_s = tcp_init_server(ZDTM_FAMILY, &port)) < 0) { + if ((fd_s = tcp_init_server(ZDTM_SRV_FAMILY, &port)) < 0) { pr_err("initializing server failed"); return 1; } diff --git a/test/zdtm/static/socket-tcp-fin-wait1.c b/test/zdtm/static/socket-tcp-fin-wait1.c index f6d45c040..6c7cc93e5 100644 --- a/test/zdtm/static/socket-tcp-fin-wait1.c +++ b/test/zdtm/static/socket-tcp-fin-wait1.c @@ -1,9 +1,14 @@ #include "zdtmtst.h" -#ifdef ZDTM_IPV6 +#ifdef ZDTM_IPV4V6 +#define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET6 +#elif defined(ZDTM_IPV6) #define ZDTM_FAMILY AF_INET6 +#define ZDTM_SRV_FAMILY AF_INET6 #else #define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET #endif const char *test_doc = "Check sockets in TCP_FIN_WAIT* states\n"; @@ -159,7 +164,7 @@ int main(int argc, char **argv) if (!newns) test_init(argc, argv); - if ((fd_s = tcp_init_server(ZDTM_FAMILY, &port)) < 0) { + if ((fd_s = tcp_init_server(ZDTM_SRV_FAMILY, &port)) < 0) { pr_err("initializing server failed"); return 1; } diff --git a/test/zdtm/static/socket-tcp-last-ack.desc b/test/zdtm/static/socket-tcp-last-ack.desc index a0ff359ce..8cf84164e 100644 --- a/test/zdtm/static/socket-tcp-last-ack.desc +++ b/test/zdtm/static/socket-tcp-last-ack.desc @@ -1 +1 @@ -{'flavor': 'h', 'opts': '--tcp-established', 'flags': 'nouser samens', 'feature' : 'tcp_half_closed'} +{'flavor': 'h ns uns', 'opts': '--tcp-established', 'flags': 'nouser samens', 'feature' : 'tcp_half_closed'} diff --git a/test/zdtm/static/socket-tcp-reseted.c b/test/zdtm/static/socket-tcp-reseted.c index f5d1bfb92..ce52e1148 100644 --- a/test/zdtm/static/socket-tcp-reseted.c +++ b/test/zdtm/static/socket-tcp-reseted.c @@ -6,11 +6,15 @@ #include #include - -#ifdef ZDTM_IPV6 +#ifdef ZDTM_IPV4V6 +#define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET6 +#elif defined(ZDTM_IPV6) #define ZDTM_FAMILY AF_INET6 +#define ZDTM_SRV_FAMILY AF_INET6 #else #define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET #endif const char *test_doc = "Check, that a reseted TCP connection can be restored\n"; @@ -35,7 +39,7 @@ int main(int argc, char **argv) test_init(argc, argv); - if ((fd_s = tcp_init_server(ZDTM_FAMILY, &port)) < 0) { + if ((fd_s = tcp_init_server(ZDTM_SRV_FAMILY, &port)) < 0) { pr_err("initializing server failed\n"); return 1; } diff --git a/test/zdtm/static/socket-tcp-syn-sent.c b/test/zdtm/static/socket-tcp-syn-sent.c index e68307e8c..cf4c3bb46 100644 --- a/test/zdtm/static/socket-tcp-syn-sent.c +++ b/test/zdtm/static/socket-tcp-syn-sent.c @@ -1,9 +1,14 @@ #include "zdtmtst.h" -#ifdef ZDTM_IPV6 +#ifdef ZDTM_IPV4V6 +#define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET6 +#elif defined(ZDTM_IPV6) #define ZDTM_FAMILY AF_INET6 +#define ZDTM_SRV_FAMILY AF_INET6 #else #define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET #endif const char *test_doc = "Check unconnected tcp sockets\n"; @@ -42,7 +47,7 @@ int main(int argc, char **argv) return 1; } - if ((fd_s = tcp_init_server(ZDTM_FAMILY, &port)) < 0) { + if ((fd_s = tcp_init_server(ZDTM_SRV_FAMILY, &port)) < 0) { pr_err("initializing server failed\n"); return 1; } diff --git a/test/zdtm/static/socket-tcp-unconn.c b/test/zdtm/static/socket-tcp-unconn.c index 124a7330b..e943b7c7a 100644 --- a/test/zdtm/static/socket-tcp-unconn.c +++ b/test/zdtm/static/socket-tcp-unconn.c @@ -1,9 +1,14 @@ #include "zdtmtst.h" -#ifdef ZDTM_IPV6 +#ifdef ZDTM_IPV4V6 +#define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET6 +#elif defined(ZDTM_IPV6) #define ZDTM_FAMILY AF_INET6 +#define ZDTM_SRV_FAMILY AF_INET6 #else #define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET #endif const char *test_doc = "Check unconnected tcp sockets\n"; @@ -41,7 +46,7 @@ int main(int argc, char **argv) return 1; } - if ((fd_s = tcp_init_server(ZDTM_FAMILY, &port)) < 0) { + if ((fd_s = tcp_init_server(ZDTM_SRV_FAMILY, &port)) < 0) { pr_err("initializing server failed\n"); return 1; } diff --git a/test/zdtm/static/socket-tcp.c b/test/zdtm/static/socket-tcp.c index 19dc53b85..6b30fc42d 100644 --- a/test/zdtm/static/socket-tcp.c +++ b/test/zdtm/static/socket-tcp.c @@ -1,9 +1,14 @@ #include "zdtmtst.h" -#ifdef ZDTM_IPV6 +#ifdef ZDTM_IPV4V6 +#define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET6 +#elif defined(ZDTM_IPV6) #define ZDTM_FAMILY AF_INET6 +#define ZDTM_SRV_FAMILY AF_INET6 #else #define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET #endif const char *test_doc = "Check, that a TCP connection can be restored\n"; @@ -135,7 +140,7 @@ int main(int argc, char **argv) test_init(argc, argv); #endif - if ((fd_s = tcp_init_server(ZDTM_FAMILY, &port)) < 0) { + if ((fd_s = tcp_init_server(ZDTM_SRV_FAMILY, &port)) < 0) { pr_err("initializing server failed\n"); return 1; } diff --git a/test/zdtm/static/socket-tcp4v6-close-wait.c b/test/zdtm/static/socket-tcp4v6-close-wait.c new file mode 120000 index 000000000..20d7e7898 --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-close-wait.c @@ -0,0 +1 @@ +socket-tcp-close-wait.c \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6-close-wait.desc b/test/zdtm/static/socket-tcp4v6-close-wait.desc new file mode 120000 index 000000000..c8cfe5e1f --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-close-wait.desc @@ -0,0 +1 @@ +socket-tcp6-close-wait.desc \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6-closed.c b/test/zdtm/static/socket-tcp4v6-closed.c new file mode 120000 index 000000000..b0c363c5c --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-closed.c @@ -0,0 +1 @@ +socket-tcp-closed.c \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6-closed.desc b/test/zdtm/static/socket-tcp4v6-closed.desc new file mode 120000 index 000000000..9644990be --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-closed.desc @@ -0,0 +1 @@ +socket-tcp6-closed.desc \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6-closing.c b/test/zdtm/static/socket-tcp4v6-closing.c new file mode 120000 index 000000000..154ef8b8d --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-closing.c @@ -0,0 +1 @@ +socket-tcp-closing.c \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6-closing.desc b/test/zdtm/static/socket-tcp4v6-closing.desc new file mode 120000 index 000000000..6981d0ada --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-closing.desc @@ -0,0 +1 @@ +socket-tcp6-closing.desc \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6-fin-wait1.c b/test/zdtm/static/socket-tcp4v6-fin-wait1.c new file mode 120000 index 000000000..2dede5f76 --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-fin-wait1.c @@ -0,0 +1 @@ +socket-tcp-fin-wait1.c \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6-fin-wait1.desc b/test/zdtm/static/socket-tcp4v6-fin-wait1.desc new file mode 120000 index 000000000..82ad86eae --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-fin-wait1.desc @@ -0,0 +1 @@ +socket-tcp6-fin-wait1.desc \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6-fin-wait2.c b/test/zdtm/static/socket-tcp4v6-fin-wait2.c new file mode 120000 index 000000000..a95fa079f --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-fin-wait2.c @@ -0,0 +1 @@ +socket-tcp-fin-wait2.c \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6-fin-wait2.desc b/test/zdtm/static/socket-tcp4v6-fin-wait2.desc new file mode 120000 index 000000000..f393f96bf --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-fin-wait2.desc @@ -0,0 +1 @@ +socket-tcp6-fin-wait2.desc \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6-last-ack.c b/test/zdtm/static/socket-tcp4v6-last-ack.c new file mode 120000 index 000000000..1f0bedf9d --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-last-ack.c @@ -0,0 +1 @@ +socket-tcp-last-ack.c \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6-last-ack.desc b/test/zdtm/static/socket-tcp4v6-last-ack.desc new file mode 120000 index 000000000..4b39f99e1 --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-last-ack.desc @@ -0,0 +1 @@ +socket-tcp6-last-ack.desc \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6-local.c b/test/zdtm/static/socket-tcp4v6-local.c new file mode 120000 index 000000000..8cb60dd03 --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-local.c @@ -0,0 +1 @@ +socket-tcp.c \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6-local.desc b/test/zdtm/static/socket-tcp4v6-local.desc new file mode 120000 index 000000000..ce647d040 --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6-local.desc @@ -0,0 +1 @@ +socket-tcp6-local.desc \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6.c b/test/zdtm/static/socket-tcp4v6.c new file mode 120000 index 000000000..8cb60dd03 --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6.c @@ -0,0 +1 @@ +socket-tcp.c \ No newline at end of file diff --git a/test/zdtm/static/socket-tcp4v6.desc b/test/zdtm/static/socket-tcp4v6.desc new file mode 120000 index 000000000..094f5b898 --- /dev/null +++ b/test/zdtm/static/socket-tcp4v6.desc @@ -0,0 +1 @@ +socket-tcp6.desc \ No newline at end of file diff --git a/test/zdtm/static/socket_listen.c b/test/zdtm/static/socket_listen.c index aae3c7993..d0acfd911 100644 --- a/test/zdtm/static/socket_listen.c +++ b/test/zdtm/static/socket_listen.c @@ -1,9 +1,14 @@ #include "zdtmtst.h" -#ifdef ZDTM_IPV6 +#ifdef ZDTM_IPV4V6 +#define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET6 +#elif defined(ZDTM_IPV6) #define ZDTM_FAMILY AF_INET6 +#define ZDTM_SRV_FAMILY AF_INET6 #else #define ZDTM_FAMILY AF_INET +#define ZDTM_SRV_FAMILY AF_INET #endif const char *test_doc = "static test for listening socket\n"; @@ -43,7 +48,7 @@ int main(int argc, char **argv) test_init(argc, argv); - if ((fd_s = tcp_init_server(ZDTM_FAMILY, &port)) < 0) { + if ((fd_s = tcp_init_server(ZDTM_SRV_FAMILY, &port)) < 0) { pr_err("initializing server failed\n"); return 1; } diff --git a/test/zdtm/static/socket_listen4v6.c b/test/zdtm/static/socket_listen4v6.c new file mode 120000 index 000000000..d026b3bf8 --- /dev/null +++ b/test/zdtm/static/socket_listen4v6.c @@ -0,0 +1 @@ +socket_listen.c \ No newline at end of file From 7d6d795d28109a0bfc973face7cdf7de16b97032 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 8 Nov 2017 03:36:01 +0300 Subject: [PATCH 1147/4375] stats: add counters for pipes and page_pipe_bufs The number of pipes are limited in a system, so it is better to know how many we use. Acked-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/include/stats.h | 2 ++ criu/page-pipe.c | 3 +++ criu/page-xfer.c | 4 ++++ criu/stats.c | 4 ++++ images/stats.proto | 2 ++ 5 files changed, 15 insertions(+) diff --git a/criu/include/stats.h b/criu/include/stats.h index d30be6a39..07690b8ea 100644 --- a/criu/include/stats.h +++ b/criu/include/stats.h @@ -26,6 +26,8 @@ enum { CNT_PAGES_SKIPPED_PARENT, CNT_PAGES_WRITTEN, CNT_PAGES_LAZY, + CNT_PAGE_PIPES, + CNT_PAGE_PIPE_BUFS, DUMP_CNT_NR_STATS, }; diff --git a/criu/page-pipe.c b/criu/page-pipe.c index 63c5a8a75..518248aaf 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -9,6 +9,7 @@ #include "criu-log.h" #include "page-pipe.h" #include "fcntl.h" +#include "stats.h" /* can existing iov accumulate the page? */ static inline bool iov_grow_page(struct iovec *iov, unsigned long addr) @@ -34,12 +35,14 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp) ppb = xmalloc(sizeof(*ppb)); if (!ppb) return NULL; + cnt_add(CNT_PAGE_PIPE_BUFS, 1); if (pipe(ppb->p)) { xfree(ppb); pr_perror("Can't make pipe for page-pipe"); return NULL; } + cnt_add(CNT_PAGE_PIPES, 1); ppb->pipe_size = fcntl(ppb->p[0], F_GETPIPE_SZ, 0) / PAGE_SIZE; pp->nr_pipes++; diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 7ba50502c..86f1e6692 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -20,6 +20,7 @@ #include "pstree.h" #include "parasite-syscall.h" #include "rst_info.h" +#include "stats.h" static int page_server_sk = -1; @@ -966,6 +967,9 @@ int cr_page_server(bool daemon_mode, bool lazy_dump, int cfd) int sk = -1; int ret; + if (init_stats(DUMP_STATS)) + return -1; + if (!opts.lazy_pages) up_page_ids_base(); else if (!lazy_dump) diff --git a/criu/stats.c b/criu/stats.c index 2b0c1a60b..64679b134 100644 --- a/criu/stats.c +++ b/criu/stats.c @@ -160,6 +160,10 @@ void write_stats(int what) ds_entry.pages_skipped_parent = dstats->counts[CNT_PAGES_SKIPPED_PARENT]; ds_entry.pages_written = dstats->counts[CNT_PAGES_WRITTEN]; ds_entry.pages_lazy = dstats->counts[CNT_PAGES_LAZY]; + ds_entry.page_pipes = dstats->counts[CNT_PAGE_PIPES]; + ds_entry.has_page_pipes = true; + ds_entry.page_pipe_bufs = dstats->counts[CNT_PAGE_PIPE_BUFS]; + ds_entry.has_page_pipe_bufs = true; name = "dump"; } else if (what == RESTORE_STATS) { diff --git a/images/stats.proto b/images/stats.proto index ad6279a81..d76503441 100644 --- a/images/stats.proto +++ b/images/stats.proto @@ -14,6 +14,8 @@ message dump_stats_entry { optional uint32 irmap_resolve = 8; required uint64 pages_lazy = 9; + optional uint64 page_pipes = 10; + optional uint64 page_pipe_bufs = 11; } message restore_stats_entry { From cae6262ce9ce73b040f03bfecf7217e35c92d8f0 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 8 Nov 2017 03:36:02 +0300 Subject: [PATCH 1148/4375] zdtm: add an option to show criu statistics v2: defining crit_bin and using it for Popen() // Mike Acked-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index d3e0c9a05..5135efaef 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -672,6 +672,7 @@ test_classes = {'zdtm': zdtm_test, 'inhfd': inhfd_test, 'groups': groups_test} # criu_bin = "../criu/criu" +crit_bin = "../crit/crit" join_ns_file = '/run/netns/zdtm_netns' @@ -789,6 +790,7 @@ class criu: self.__user = (opts['user'] and True or False) self.__leave_stopped = (opts['stop'] and True or False) self.__criu = (opts['rpc'] and criu_rpc or criu_cli) + self.__show_stats = (opts['show_stats'] and True or False) self.__lazy_pages_p = None self.__page_server_p = None @@ -907,6 +909,14 @@ class criu: else: raise test_fail_exc("CRIU %s" % action) + def show_stats(self, action): + if not self.__show_stats: + return + + subprocess.Popen([crit_bin, "show", + os.path.join(self.__dump_path, + str(self.__iter), "stats-%s" % action)]).wait() + def dump(self, action, opts = []): self.__iter += 1 os.mkdir(self.__ddir()) @@ -948,6 +958,8 @@ class criu: if self.__mdedup and self.__iter > 1: self.__criu_act("dedup", opts = []) + self.show_stats("dump") + if self.__leave_stopped: pstree_check_stopped(self.__test.getpid()) pstree_signal(self.__test.getpid(), signal.SIGKILL) @@ -991,6 +1003,7 @@ class criu: r_opts += ['--leave-stopped'] self.__criu_act("restore", opts = r_opts + ["--restore-detached"]) + self.show_stats("restore") if self.__leave_stopped: pstree_check_stopped(self.__test.getpid()) @@ -1465,7 +1478,8 @@ class Launcher: nd = ('nocr', 'norst', 'pre', 'iters', 'page_server', 'sibling', 'stop', 'empty_ns', 'fault', 'keep_img', 'report', 'snaps', 'sat', 'script', 'rpc', 'lazy_pages', - 'join_ns', 'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup', 'remote_lazy_pages') + 'join_ns', 'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup', + 'remote_lazy_pages', 'show_stats') arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd})) if self.__use_log: @@ -2000,6 +2014,7 @@ rp.add_argument("--ignore-taint", help = "Don't care about a non-zero kernel tai rp.add_argument("--lazy-pages", help = "restore pages on demand", action = 'store_true') rp.add_argument("--remote-lazy-pages", help = "simulate lazy migration", action = 'store_true') rp.add_argument("--title", help = "A test suite title", default = "criu") +rp.add_argument("--show-stats", help = "Show criu statistics", action = 'store_true') lp = sp.add_parser("list", help = "List tests") lp.set_defaults(action = list_tests) From 30b2630e805479183d1fe93d3b97c1d611ade575 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 7 Nov 2017 19:19:24 +0300 Subject: [PATCH 1149/4375] test: static,aio01 -- Use proper type for context aio_context_t is 8 byte long so on 32 bit mode it might be strippped off when unsigned long used instead. Fix this typo. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/aio01.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/aio01.c b/test/zdtm/static/aio01.c index 193f562d1..f84fd359f 100644 --- a/test/zdtm/static/aio01.c +++ b/test/zdtm/static/aio01.c @@ -30,7 +30,7 @@ int main(int argc, char **argv) { struct iocb iocb, *iocbp = &iocb; volatile struct aio_ring *ring; - unsigned long ctx = 0; + aio_context_t ctx = 0; struct io_event event; unsigned tail[2], head[2]; unsigned nr[2]; From 3e0200e5711aaad70098b49a900843aaf585dded Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Sat, 21 Oct 2017 17:12:50 +0300 Subject: [PATCH 1150/4375] build: get rid of warnings with sysmacro warning: In the GNU C Library, "major" is defined by . For historical compatibility, it is currently defined by as well, but we plan to remove this soon. To use "major", include directly. If you did not intend to use a system-defined macro "major", you should undefine it after including . if (major(st.st_rdev) != major(st_rtc.st_rdev) || Signed-off-by: Pavel Begunkov Signed-off-by: Andrei Vagin --- criu/kerndat.c | 1 - test/zdtm/static/criu-rtc.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/kerndat.c b/criu/kerndat.c index 7ae20ac69..ea4d2a162 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include /* for sockaddr_in and inet_ntoa() */ diff --git a/test/zdtm/static/criu-rtc.c b/test/zdtm/static/criu-rtc.c index 0d6ffeac0..8588f9f52 100644 --- a/test/zdtm/static/criu-rtc.c +++ b/test/zdtm/static/criu-rtc.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include From 8e45ce4905d186abafb7c20abb3b00207fefdb53 Mon Sep 17 00:00:00 2001 From: Avindra Goolcharan Date: Sat, 11 Nov 2017 20:11:58 -0500 Subject: [PATCH 1151/4375] images.py: remove shebang This file is not executable directly, so it should not have the shebang. Signed-off-by: Avindra Goolcharan Signed-off-by: Andrei Vagin --- lib/py/images/images.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/py/images/images.py b/lib/py/images/images.py index bb2f3834e..b706fd3b3 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -1,5 +1,3 @@ -#!/bin/env python2 - # This file contains methods to deal with criu images. # # According to http://criu.org/Images, criu images can be described From d62e01929ee12e687152afc395db6fa9738775f4 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sun, 22 Oct 2017 01:16:04 +0300 Subject: [PATCH 1152/4375] build: nmk -- Add .FORCE target Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- scripts/nmk/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nmk/Makefile b/scripts/nmk/Makefile index f05e5c5c8..ab1aa2255 100644 --- a/scripts/nmk/Makefile +++ b/scripts/nmk/Makefile @@ -5,7 +5,7 @@ include $(__nmk_dir)include.mk MAKEFLAGS := -r -R --no-print-directory -.PHONY: all help test docs clean install +.PHONY: all help test docs clean install .FORCE help: @echo ' Targets:' From 8db0f03758496b37107e1a828b451ef12b041bcd Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sun, 22 Oct 2017 01:16:05 +0300 Subject: [PATCH 1153/4375] build: nmk -- Move phony targets to include.mk So they can be reused. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- scripts/nmk/Makefile | 2 -- scripts/nmk/scripts/include.mk | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nmk/Makefile b/scripts/nmk/Makefile index ab1aa2255..baab57b94 100644 --- a/scripts/nmk/Makefile +++ b/scripts/nmk/Makefile @@ -5,8 +5,6 @@ include $(__nmk_dir)include.mk MAKEFLAGS := -r -R --no-print-directory -.PHONY: all help test docs clean install .FORCE - help: @echo ' Targets:' @echo ' install dir= - Install scripts into directory ' diff --git a/scripts/nmk/scripts/include.mk b/scripts/nmk/scripts/include.mk index 04ccb3ade..e1701103f 100644 --- a/scripts/nmk/scripts/include.mk +++ b/scripts/nmk/scripts/include.mk @@ -4,6 +4,8 @@ ifndef ____nmk_defined__msg include $(__nmk_dir)msg.mk endif +.PHONY: all help test docs clean install .FORCE + # # Common vars. SUBARCH := $(shell uname -m | sed \ From 0b6f9c7975db606ddacbfac9b0ae8192e5b0c33c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sun, 22 Oct 2017 01:16:06 +0300 Subject: [PATCH 1154/4375] build: Reused .FORCE from nmk Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- Makefile | 2 -- criu/Makefile | 2 -- lib/Makefile | 2 -- lib/py/Makefile | 2 -- 4 files changed, 8 deletions(-) diff --git a/Makefile b/Makefile index 0dd5e8374..9610151f9 100644 --- a/Makefile +++ b/Makefile @@ -195,8 +195,6 @@ endif $(eval $(call gen-built-in,images)) criu-deps += images/built-in.o -.PHONY: .FORCE - # # Compel get used by CRIU, build it earlier include Makefile.compel diff --git a/criu/Makefile b/criu/Makefile index b2c663310..b3b09ce7a 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -1,5 +1,3 @@ -.PHONY: .FORCE - # here is a workaround for a bug in libnl-3: # 6a8d90f5fec4 "attr: Allow attribute type 0" WRAPFLAGS += -Wl,--wrap=nla_parse,--wrap=nlmsg_parse diff --git a/lib/Makefile b/lib/Makefile index b1bb05727..26b355aa2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -2,8 +2,6 @@ CRIU_SO := libcriu.so UAPI_HEADERS := lib/c/criu.h images/rpc.proto PYTHON_BIN ?= python2 -.PHONY: .FORCE - # # File to keep track of files installed by setup.py CRIT_SETUP_FILES := lib/.crit-setup.files diff --git a/lib/py/Makefile b/lib/py/Makefile index 5eb77d40e..691b6bdd3 100644 --- a/lib/py/Makefile +++ b/lib/py/Makefile @@ -1,7 +1,5 @@ all-y += libpy-images rpc_pb2.py -.PHONY: .FORCE - $(obj)/images/Makefile: ; $(obj)/images/%: .FORCE $(Q) $(MAKE) $(build)=$(obj)/images $@ From ebd64bddfeef04d0e80d0e6925b8b92adf5998f0 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 18 May 2017 03:14:33 +0300 Subject: [PATCH 1155/4375] service: allow to execute page-server as a child process In this case we can wait it and get an exit code. For example, it will be useful for p.haul where one connection is used several times, so we need a way how to understand that page-server exited unexpectedly. v2: don't write ps_info if a start descriptor isn't set Signed-off-by: Andrei Vagin --- criu/cr-service.c | 79 ++++++++++++++++++++++++++++------------ criu/include/page-xfer.h | 5 +++ criu/page-xfer.c | 13 +++++++ images/rpc.proto | 8 ++++ 4 files changed, 82 insertions(+), 23 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 9172a8c4b..33d417329 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -706,12 +706,7 @@ static int pre_dump_loop(int sk, CriuReq *msg) return dump_using_req(sk, msg->opts); } -struct ps_info { - int pid; - unsigned short port; -}; - -static int start_page_server_req(int sk, CriuOpts *req) +static int start_page_server_req(int sk, CriuOpts *req, bool daemon_mode) { int ret = -1, pid, start_pipe[2]; ssize_t count; @@ -736,35 +731,40 @@ static int start_page_server_req(int sk, CriuOpts *req) pr_debug("Starting page server\n"); - pid = cr_page_server(true, false, start_pipe[1]); + pid = cr_page_server(daemon_mode, false, start_pipe[1]); if (pid < 0) goto out_ch; - info.pid = pid; - info.port = opts.port; + if (daemon_mode) { + info.pid = pid; + info.port = opts.port; - count = write(start_pipe[1], &info, sizeof(info)); - if (count != sizeof(info)) - goto out_ch; + count = write(start_pipe[1], &info, sizeof(info)); + if (count != sizeof(info)) + goto out_ch; + } ret = 0; out_ch: - if (ret < 0 && pid > 0) + if (daemon_mode && ret < 0 && pid > 0) kill(pid, SIGKILL); close(start_pipe[1]); exit(ret); } close(start_pipe[1]); - wait(&ret); - if (WIFEXITED(ret)) { - if (WEXITSTATUS(ret)) { - pr_err("Child exited with an error\n"); + + if (daemon_mode) { + wait(&ret); + if (WIFEXITED(ret)) { + if (WEXITSTATUS(ret)) { + pr_err("Child exited with an error\n"); + goto out; + } + } else { + pr_err("Child wasn't terminated normally\n"); goto out; } - } else { - pr_err("Child wasn't terminated normally\n"); - goto out; } count = read(start_pipe[0], &info, sizeof(info)); @@ -772,11 +772,12 @@ out_ch: if (count != sizeof(info)) goto out; - success = true; - ps.has_pid = true; ps.pid = info.pid; ps.has_port = true; ps.port = info.port; + + success = true; + ps.has_pid = true; resp.ps = &ps; pr_debug("Page server started\n"); @@ -803,6 +804,9 @@ static int chk_keepopen_req(CriuReq *msg) if (msg->type == CRIU_REQ_TYPE__PAGE_SERVER) /* This just fork()-s so no leaks */ return 0; + if (msg->type == CRIU_REQ_TYPE__PAGE_SERVER_CHLD) + /* This just fork()-s so no leaks */ + return 0; else if (msg->type == CRIU_REQ_TYPE__CPUINFO_DUMP || msg->type == CRIU_REQ_TYPE__CPUINFO_CHECK) return 0; @@ -925,6 +929,29 @@ out: return send_criu_msg(sk, &resp); } +static int handle_wait_pid(int sk, int pid) +{ + CriuResp resp = CRIU_RESP__INIT; + bool success = false; + int status; + + if (waitpid(pid, &status, 0) == -1) { + resp.cr_errno = errno; + pr_perror("Unable to wait %d", pid); + goto out; + } + + resp.status = status; + resp.has_status = true; + + success = true; +out: + resp.type = CRIU_REQ_TYPE__WAIT_PID; + resp.success = success; + + return send_criu_msg(sk, &resp); +} + static int handle_cpuinfo(int sk, CriuReq *msg) { CriuResp resp = CRIU_RESP__INIT; @@ -1010,7 +1037,13 @@ more: ret = pre_dump_loop(sk, msg); break; case CRIU_REQ_TYPE__PAGE_SERVER: - ret = start_page_server_req(sk, msg->opts); + ret = start_page_server_req(sk, msg->opts, true); + break; + case CRIU_REQ_TYPE__PAGE_SERVER_CHLD: + ret = start_page_server_req(sk, msg->opts, false); + break; + case CRIU_REQ_TYPE__WAIT_PID: + ret = handle_wait_pid(sk, msg->pid); break; case CRIU_REQ_TYPE__CPUINFO_DUMP: case CRIU_REQ_TYPE__CPUINFO_CHECK: diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index 89e7ea9f0..ee90ae65a 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -2,6 +2,11 @@ #define __CR_PAGE_XFER__H__ #include "pagemap.h" +struct ps_info { + int pid; + unsigned short port; +}; + extern int cr_page_server(bool daemon_mode, bool lazy_dump, int cfd); /* diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 86f1e6692..df4eb2877 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -987,6 +987,19 @@ int cr_page_server(bool daemon_mode, bool lazy_dump, int cfd) if (sk == -1) return -1; no_server: + + if (!daemon_mode && cfd >= 0) { + struct ps_info info = {.pid = getpid(), .port = opts.port}; + int count; + + count = write(cfd, &info, sizeof(info)); + close_safe(&cfd); + if (count != sizeof(info)) { + pr_perror("Unable to write ps_info"); + exit(1); + } + } + ret = run_tcp_server(daemon_mode, &ask, cfd, sk); if (ret != 0) return ret > 0 ? 0 : -1; diff --git a/images/rpc.proto b/images/rpc.proto index 48e42e26e..71f47d594 100644 --- a/images/rpc.proto +++ b/images/rpc.proto @@ -142,6 +142,9 @@ enum criu_req_type { FEATURE_CHECK = 9; VERSION = 10; + + WAIT_PID = 11; + PAGE_SERVER_CHLD = 12; } /* @@ -176,6 +179,9 @@ message criu_req { * via RPC. */ optional criu_features features = 5; + + /* 'pid' is used for WAIT_PID */ + optional uint32 pid = 6; } /* @@ -196,6 +202,8 @@ message criu_resp { optional criu_features features = 8; optional string cr_errmsg = 9; optional criu_version version = 10; + + optional int32 status = 11; } /* Answer for criu_req_type.VERSION requests */ From 397df9c0358d95ae281b22a576b0893c5330c913 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 17 May 2017 08:07:12 +0300 Subject: [PATCH 1156/4375] lib/py: allow to execute page-server as a child process Signed-off-by: Andrei Vagin --- lib/py/criu.py | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/py/criu.py b/lib/py/criu.py index c4a09ea2b..f10dbc03c 100644 --- a/lib/py/criu.py +++ b/lib/py/criu.py @@ -195,6 +195,7 @@ class criu: def __init__(self): self.use_binary('criu') self.opts = rpc.criu_opts() + self.sk = None def use_sk(self, sk_name): """ @@ -227,13 +228,20 @@ class criu: daemon = True try: - s = self._comm.connect(daemon) + if not self.sk: + s = self._comm.connect(daemon) + else: + s = self.sk + + if req.keep_open: + self.sk = s s.send(req.SerializeToString()) buf = s.recv(len(s.recv(1, socket.MSG_TRUNC | socket.MSG_PEEK))) - self._comm.disconnect() + if not req.keep_open: + self._comm.disconnect() resp = rpc.criu_resp() resp.ParseFromString(buf) @@ -283,3 +291,28 @@ class criu: raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) return resp.restore + + def page_server_chld(self): + req = rpc.criu_req() + req.type = rpc.PAGE_SERVER_CHLD + req.opts.MergeFrom(self.opts) + req.keep_open = True + + resp = self._send_req_and_recv_resp(req) + + if not resp.success: + raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) + + return resp.ps + + def wait_pid(self, pid): + req = rpc.criu_req() + req.type = rpc.WAIT_PID + req.pid = pid + + resp = self._send_req_and_recv_resp(req) + + if not resp.success: + raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) + + return resp.status From 008db0cb7a39ae192ecf0e74012a46f461092366 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 17 May 2017 08:07:13 +0300 Subject: [PATCH 1157/4375] zdtm: run page-server via rpc v2: typo fix v3: run criu pre-dump via rpc v4: don't use status-fd for rpc Signed-off-by: Andrei Vagin --- lib/py/criu.py | 15 ++++++++++++ scripts/travis/travis-tests | 1 + test/zdtm.py | 49 ++++++++++++++++++++++++++++++++----- 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/lib/py/criu.py b/lib/py/criu.py index f10dbc03c..cafaea8f3 100644 --- a/lib/py/criu.py +++ b/lib/py/criu.py @@ -277,6 +277,21 @@ class criu: return resp.dump + def pre_dump(self): + """ + Checkpoint a process/tree identified by opts.pid. + """ + req = rpc.criu_req() + req.type = rpc.PRE_DUMP + req.opts.MergeFrom(self.opts) + + resp = self._send_req_and_recv_resp(req) + + if not resp.success: + raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) + + return resp.dump + def restore(self): """ Restore a process/tree. diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index d4321aed6..3d9d5a221 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -115,6 +115,7 @@ ip net add test # RPC testing ./test/zdtm.py run -t zdtm/static/env00 --rpc # Basic +./test/zdtm.py run -t zdtm/static/env00 --rpc --pre 2 --page-server ./test/zdtm.py run -t zdtm/static/ptrace_sig -f h --rpc # Error handling (crfail test) ./test/zdtm.py run --empty-ns -T zdtm/static/socket-tcp*-local --iter 2 diff --git a/test/zdtm.py b/test/zdtm.py index 5135efaef..d959073f8 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -691,6 +691,14 @@ class criu_cli: return cr.wait() +class criu_rpc_process: + def wait(self): + return self.criu.wait_pid(self.pid) + + def terminate(self): + os.kill(self.pid, signal.SIGTERM) + + class criu_rpc: @staticmethod def __set_opts(criu, args, ctx): @@ -725,6 +733,25 @@ class criu_rpc: if arg == '--external': criu.opts.external.append(args.pop(0)) continue + if arg == '--status-fd': + fd = int(args.pop(0)) + os.write(fd, "\0") + fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC) + continue + if arg == '--port': + criu.opts.ps.port = int(args.pop(0)) + continue + if arg == '--address': + criu.opts.ps.address = args.pop(0) + continue + if arg == '--page-server': + continue + if arg == '--prev-images-dir': + criu.opts.parent_img = args.pop(0) + continue + if arg == '--track-mem': + criu.opts.track_mem = True + continue raise test_fail_exc('RPC for %s required' % arg) @@ -736,17 +763,18 @@ class criu_rpc: raise test_fail_exc('RPC and SAT not supported') if preexec: raise test_fail_exc('RPC and PREEXEC not supported') - if nowait: - raise test_fail_exc("RPC and status-fd not supported") ctx = {} # Object used to keep info untill action is done criu = crpc.criu() criu.use_binary(criu_bin) criu_rpc.__set_opts(criu, args, ctx) + p = None try: if action == 'dump': criu.dump() + elif action == 'pre-dump': + criu.pre_dump() elif action == 'restore': if 'rd' not in ctx: raise test_fail_exc('RPC Non-detached restore is impossible') @@ -755,10 +783,15 @@ class criu_rpc: pidf = ctx.get('pidf') if pidf: open(pidf, 'w').write('%d\n' % res.pid) + elif action == "page-server": + res = criu.page_server_chld() + p = criu_rpc_process() + p.pid = res.pid + p.criu = criu else: raise test_fail_exc('RPC for %s required' % action) - except crpc.CRIUExceptionExternal: - print "Fail" + except crpc.CRIUExceptionExternal, e: + print "Fail", e ret = -1 else: ret = 0 @@ -766,6 +799,10 @@ class criu_rpc: imgd = ctx.get('imgd') if imgd: os.close(imgd) + + if nowait and ret == 0: + return p + return ret @@ -1022,11 +1059,11 @@ class criu: def kill(self): if self.__lazy_pages_p: self.__lazy_pages_p.terminate() - print "criu lazy-pages exited with %s" & self.wait() + print "criu lazy-pages exited with %s" % self.__lazy_pages_p.wait() self.__lazy_pages_p = None if self.__page_server_p: self.__page_server_p.terminate() - print "criu page-server exited with %s" & self.wait() + print "criu page-server exited with %s" % self.__page_server_p.wait() self.__page_server_p = None From 585dda236c28e660fb3d7aaf68439c4eb569cb6c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 25 Jul 2017 15:35:46 +0300 Subject: [PATCH 1158/4375] ia32: Get rid of R_X86_64_32S relocation Distributions starts to supply GCC that is configured to compile -pie and -fPIC code by default due to security reasons. CONFIG_COMPAT was unfriendy to -pie by the reason of R_X86_64_32S relocation in call32.S helper: LINK criu/criu /usr/bin/ld: criu/arch/x86/crtools.built-in.o: relocation R_X86_64_32S against `.text' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: final link failed: Nonrepresentable section on output collect2: error: ld returned 1 exit status make[1]: *** [criu/Makefile:92: criu/criu] Error 1 make: *** [Makefile:225: criu] Error 2 Use %rip-relative addressing to avoid ld errors for shared binary linking. Puff, all needs to be done with bare hands! Now CONFIG_COMPAT can be used with -pie binaries and all should also work for debian toolchain (#315). Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/call32.S | 20 ++++++++++++++------ scripts/feature-tests.mak | 25 +++++++++++++++++++------ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/criu/arch/x86/call32.S b/criu/arch/x86/call32.S index dbed5dec3..c2ddd9fc2 100644 --- a/criu/arch/x86/call32.S +++ b/criu/arch/x86/call32.S @@ -39,19 +39,27 @@ ENTRY(call32_from_64) mov %rsp,(%rdi) mov %rdi,%rsp + /* Push return address and 64-bit segment descriptor */ + sub $4, %rsp + movl $__USER_CS,(%rsp) + sub $4, %rsp + /* Using rip-relative addressing to get rid of R_X86_64_32S relocs */ + leaq 2f(%rip),%r12 + movl %r12d,(%rsp) + /* Switch into compatibility mode */ pushq $__USER32_CS - pushq $1f + /* Using rip-relative addressing to get rid of R_X86_64_32S relocs */ + leaq 1f(%rip), %r12 + pushq %r12 lretq -1: - .code32 +1: .code32 /* Run function and switch back */ call *%esi - jmp $__USER_CS,$1f - .code64 + lret -1: +2: .code64 /* Restore the stack */ mov (%rsp),%rsp add $8, %rdi diff --git a/scripts/feature-tests.mak b/scripts/feature-tests.mak index 12bf54181..e39d97bb1 100644 --- a/scripts/feature-tests.mak +++ b/scripts/feature-tests.mak @@ -106,17 +106,30 @@ define FEATURE_TEST_X86_COMPAT .text ENTRY(call32_from_64) + /* Push return address and 64-bit segment descriptor */ + sub \$$4, %rsp + movl \$$__USER_CS,(%rsp) + sub \$$4, %rsp + /* Using rip-relative addressing to get rid of R_X86_64_32S relocs */ + leaq 2f(%rip),%r12 + movl %r12d,(%rsp) + /* Switch into compatibility mode */ pushq \$$__USER32_CS - pushq \$$1f + /* Using rip-relative addressing to get rid of R_X86_64_32S relocs */ + leaq 1f(%rip), %r12 + pushq %r12 lretq -1: - .code32 + +1: .code32 /* Run function and switch back */ call *%esi - jmp \$$__USER_CS,\$$1f - .code64 -1: + lret + +2: .code64 + /* Restore the stack */ + mov (%rsp),%rsp + add \$$8, %rdi END(call32_from_64) ENTRY(main) From d541bc797ca97bd134b6c6dba0ecbb88201f7e0e Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 19 Jul 2017 21:14:24 +0300 Subject: [PATCH 1159/4375] build: Move generated config.h into include/common/ config.h is a generated file with "build-features" defines. We use it for several purposes: o to check that compiler can do it's job o to complement user-visible API between distributions o to add compile-time options from .config global file It's used in criu and soccr, but compel also needs such thing. Previously, soccr has a link to config.h in criu includes, but it would be much cleaner to move it to other headers, that are shared between sub-projects into include/common. Reported-by: Adrian Reber Signed-off-by: Dmitry Safonov Tested-by: Adrian Reber Signed-off-by: Andrei Vagin --- .gitignore | 3 +-- Makefile | 10 +++------- criu/cgroup-props.c | 2 +- criu/filesystems.c | 2 +- criu/include/cr_options.h | 2 +- criu/include/kerndat.h | 2 +- criu/include/parasite-syscall.h | 2 +- criu/include/parasite-vdso.h | 2 +- criu/include/ptrace-compat.h | 2 +- criu/include/restorer.h | 2 +- criu/include/string.h | 2 +- criu/include/vdso.h | 2 +- criu/kerndat.c | 2 +- criu/lsm.c | 2 +- criu/page-pipe.c | 2 +- criu/parasite-syscall.c | 2 +- criu/pie/parasite.c | 2 +- criu/pie/pie-relocs.h | 2 +- criu/pie/restorer.c | 2 +- criu/seccomp.c | 2 +- criu/shmem.c | 2 +- criu/sk-tcp.c | 2 +- soccr/soccr.h | 2 +- 23 files changed, 25 insertions(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index d1725af2d..048668905 100644 --- a/.gitignore +++ b/.gitignore @@ -28,10 +28,8 @@ criu/arch/*/sys-exec-tbl*.c # x86 syscalls-table is not generated !criu/arch/x86/sys-exec-tbl.c criu/arch/*/syscalls*.S -criu/include/config.h criu/include/syscall-codes*.h criu/include/syscall*.h -soccr/config.h criu/include/version.h criu/pie/restorer-blob.h criu/pie/parasite-blob.h @@ -42,3 +40,4 @@ scripts/build/qemu-user-static/* lib/.crit-setup.files compel/include/asm include/common/asm +include/common/config.h diff --git a/Makefile b/Makefile index 9610151f9..75f328e50 100644 --- a/Makefile +++ b/Makefile @@ -181,7 +181,7 @@ criu-deps += include/common/asm # # Configure variables. -export CONFIG_HEADER := criu/include/config.h +export CONFIG_HEADER := include/common/config.h ifeq ($(filter tags etags cscope clean mrproper,$(MAKECMDGOALS)),) include Makefile.config else @@ -203,13 +203,10 @@ include Makefile.compel # Next the socket CR library # SOCCR_A := soccr/libsoccr.a -SOCCR_CONFIG := soccr/config.h -$(SOCCR_CONFIG): $(CONFIG_HEADER) - $(Q) test -f $@ || ln -s ../$(CONFIG_HEADER) $@ soccr/Makefile: ; -soccr/%: $(SOCCR_CONFIG) .FORCE +soccr/%: $(CONFIG_HEADER) .FORCE $(Q) $(MAKE) $(build)=soccr $@ -soccr/built-in.o: $(SOCCR_CONFIG) .FORCE +soccr/built-in.o: $(CONFIG_HEADER) .FORCE $(Q) $(MAKE) $(build)=soccr all $(SOCCR_A): |soccr/built-in.o criu-deps += $(SOCCR_A) @@ -262,7 +259,6 @@ clean: clean-top mrproper-top: clean-top $(Q) $(RM) $(CONFIG_HEADER) - $(Q) $(RM) $(SOCCR_CONFIG) $(Q) $(RM) $(VERSION_HEADER) $(Q) $(RM) $(COMPEL_VERSION_HEADER) $(Q) $(RM) include/common/asm diff --git a/criu/cgroup-props.c b/criu/cgroup-props.c index 251c4631e..f7032bd7e 100644 --- a/criu/cgroup-props.c +++ b/criu/cgroup-props.c @@ -9,10 +9,10 @@ #include #include "int.h" +#include "common/config.h" #include "common/compiler.h" #include "cgroup-props.h" #include "cr_options.h" -#include "config.h" #include "xmalloc.h" #include "string.h" #include "util.h" diff --git a/criu/filesystems.c b/criu/filesystems.c index 8211e396a..5a88788d7 100644 --- a/criu/filesystems.c +++ b/criu/filesystems.c @@ -4,7 +4,7 @@ #include #include -#include "config.h" +#include "common/config.h" #include "int.h" #include "common/compiler.h" #include "xmalloc.h" diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index af530e9be..8f09fd903 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -2,7 +2,7 @@ #define __CR_OPTIONS_H__ #include -#include "config.h" +#include "common/config.h" #include "common/list.h" /* diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 950755b5e..6ad77e369 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -4,7 +4,7 @@ #include #include "int.h" -#include "config.h" +#include "common/config.h" #ifdef CONFIG_VDSO #include "util-vdso.h" #endif diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 7a09d105e..c9438a6fe 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -3,7 +3,7 @@ #include "pid.h" #include "common/list.h" -#include "config.h" +#include "common/config.h" #include "asm/parasite-syscall.h" struct parasite_dump_thread; diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index 3d6585a01..6667fe5c4 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -1,7 +1,7 @@ #ifndef __CR_PARASITE_VDSO_H__ #define __CR_PARASITE_VDSO_H__ -#include "config.h" +#include "common/config.h" #ifdef CONFIG_VDSO diff --git a/criu/include/ptrace-compat.h b/criu/include/ptrace-compat.h index b23df2dfd..476da3536 100644 --- a/criu/include/ptrace-compat.h +++ b/criu/include/ptrace-compat.h @@ -3,7 +3,7 @@ #include #include -#include "config.h" +#include "common/config.h" #ifndef CONFIG_HAS_PTRACE_PEEKSIGINFO struct ptrace_peeksiginfo_args { diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 6e1c78579..be1b5d7f2 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -5,6 +5,7 @@ #include #include +#include "common/config.h" #include "types.h" #include "int.h" #include "types.h" @@ -13,7 +14,6 @@ #include "common/lock.h" #include "util.h" #include "asm/restorer.h" -#include "config.h" #include "posix-timer.h" #include "timerfd.h" #include "shmem.h" diff --git a/criu/include/string.h b/criu/include/string.h index f9b4a3828..bc5f9d219 100644 --- a/criu/include/string.h +++ b/criu/include/string.h @@ -7,7 +7,7 @@ # include #endif -#include "config.h" +#include "common/config.h" #ifndef CONFIG_HAS_STRLCPY extern size_t strlcpy(char *dest, const char *src, size_t size); diff --git a/criu/include/vdso.h b/criu/include/vdso.h index 3c4c0ecbd..1719f3fb7 100644 --- a/criu/include/vdso.h +++ b/criu/include/vdso.h @@ -4,7 +4,7 @@ #include #include -#include "config.h" +#include "common/config.h" #ifdef CONFIG_VDSO diff --git a/criu/kerndat.c b/criu/kerndat.c index ea4d2a162..164f6cc4b 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -13,6 +13,7 @@ #include /* for sockaddr_in and inet_ntoa() */ #include +#include "common/config.h" #include "int.h" #include "log.h" #include "restorer.h" @@ -25,7 +26,6 @@ #include "util.h" #include "lsm.h" #include "proc_parse.h" -#include "config.h" #include "sk-inet.h" #include #include diff --git a/criu/lsm.c b/criu/lsm.c index 2d77f6277..fd098581f 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -5,8 +5,8 @@ #include #include +#include "common/config.h" #include "kerndat.h" -#include "config.h" #include "pstree.h" #include "util.h" #include "cr_options.h" diff --git a/criu/page-pipe.c b/criu/page-pipe.c index 518248aaf..7da8bebc3 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -3,8 +3,8 @@ #undef LOG_PREFIX #define LOG_PREFIX "page-pipe: " +#include "common/config.h" #include "page.h" -#include "config.h" #include "util.h" #include "criu-log.h" #include "page-pipe.h" diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 8ace6ad66..1fd9142e5 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -5,6 +5,7 @@ #include #include +#include "common/config.h" #include "common/compiler.h" #include "types.h" #include "protobuf.h" @@ -20,7 +21,6 @@ #include "crtools.h" #include "namespaces.h" #include "kerndat.h" -#include "config.h" #include "pstree.h" #include "posix-timer.h" #include "mem.h" diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index f3fa2e39a..db2a75f59 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -7,11 +7,11 @@ #include #include +#include "common/config.h" #include "int.h" #include "types.h" #include #include "parasite.h" -#include "config.h" #include "fcntl.h" #include "prctl.h" #include "common/lock.h" diff --git a/criu/pie/pie-relocs.h b/criu/pie/pie-relocs.h index 5a18d8c9d..6797486c2 100644 --- a/criu/pie/pie-relocs.h +++ b/criu/pie/pie-relocs.h @@ -3,8 +3,8 @@ #include +#include "common/config.h" #include "common/compiler.h" -#include "config.h" #define pie_size(__pie_name) (round_up(sizeof(__pie_name##_blob) + \ __pie_name ## _nr_gotpcrel * sizeof(long), page_size())) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 48b064d95..c2e5b38a5 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -19,6 +19,7 @@ #include "linux/userfaultfd.h" +#include "common/config.h" #include "int.h" #include "types.h" #include "common/compiler.h" @@ -26,7 +27,6 @@ #include #include #include "signal.h" -#include "config.h" #include "prctl.h" #include "criu-log.h" #include "util.h" diff --git a/criu/seccomp.c b/criu/seccomp.c index c5e7a7d93..6416e793c 100644 --- a/criu/seccomp.c +++ b/criu/seccomp.c @@ -3,7 +3,7 @@ #include #include -#include "config.h" +#include "common/config.h" #include "imgset.h" #include "kcmp.h" #include "pstree.h" diff --git a/criu/shmem.c b/criu/shmem.c index 5314cb504..895297f0b 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -4,6 +4,7 @@ #include #include +#include "common/config.h" #include "common/list.h" #include "pid.h" #include "shmem.h" @@ -15,7 +16,6 @@ #include "rst-malloc.h" #include "vma.h" #include "mem.h" -#include "config.h" #include #include "bitops.h" #include "log.h" diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c index 5fe93ab0a..9c73d882f 100644 --- a/criu/sk-tcp.c +++ b/criu/sk-tcp.c @@ -8,6 +8,7 @@ #include "../soccr/soccr.h" +#include "common/config.h" #include "cr_options.h" #include "util.h" #include "common/list.h" @@ -19,7 +20,6 @@ #include "image.h" #include "namespaces.h" #include "xmalloc.h" -#include "config.h" #include "kerndat.h" #include "restorer.h" #include "rst-malloc.h" diff --git a/soccr/soccr.h b/soccr/soccr.h index c9d138bfc..2c34e169b 100644 --- a/soccr/soccr.h +++ b/soccr/soccr.h @@ -5,7 +5,7 @@ #include /* uint32_t */ #include /* sockaddr */ -#include "config.h" +#include "common/config.h" /* All packets with this mark have not to be blocked. */ #define SOCCR_MARK 0xC114 From e6537f3d8d41974e040bb2a7d28d91ecfc03ec01 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 4 Aug 2017 17:20:00 +0300 Subject: [PATCH 1160/4375] fsnotify: open_handle -- Handle multiple mounts with same s_dev When inotify is laying on uovermounted fs we should walk over all mountpoints with same s_dev to find openable path. Note on restore the path is usually already allocated during dump stage so get_mark_path won't call for open_handle(), in turn on dump stage the positive return from open_handle() will cause fsnotify engine to find openable path, thus there is kind of double work to be optimized in future. For example we got a container where systemd-udevd inside opens inotify for /dev/X entry then overmount ./dev path with slave option and in result irmap engine on predump can't figure out where the inotify is sitting causing migrtion to abort. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov --- criu/fsnotify.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 6098b5b4c..955cd106b 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -196,6 +196,7 @@ err: static int open_handle(unsigned int s_dev, unsigned long i_ino, FhEntry *f_handle) { + struct mount_info *m; int mntfd, fd = -1; fh_t handle; @@ -204,19 +205,23 @@ static int open_handle(unsigned int s_dev, unsigned long i_ino, pr_debug("Opening fhandle %x:%Lx...\n", s_dev, (unsigned long long)handle.__handle[0]); - mntfd = open_mount(s_dev); - if (mntfd < 0) { - pr_err("Mount root for %#08x not found\n", s_dev); - goto out; - } + for (m = mntinfo; m; m = m->next) { + if (m->s_dev != s_dev || !mnt_is_dir(m)) + continue; - fd = userns_call(open_by_handle, UNS_FDOUT, &handle, sizeof(handle), mntfd); - if (fd < 0) { - pr_perror("Can't open file handle for %#08x:%#016lx", - s_dev, i_ino); - } + mntfd = __open_mountpoint(m, -1); + if (mntfd < 0) { + pr_err("Can't open mount for s_dev %x, continue\n", s_dev); + continue; + } - close(mntfd); + fd = userns_call(open_by_handle, UNS_FDOUT, &handle, sizeof(handle), mntfd); + if (fd >= 0) { + close(mntfd); + goto out; + } + close(mntfd); + } out: return fd; } From 638c14f2ed61d890007994a283fed0078767bd3f Mon Sep 17 00:00:00 2001 From: root Date: Mon, 4 Sep 2017 10:44:14 -0700 Subject: [PATCH 1161/4375] zdtm: grep errors from page-server.log and lazy-pages.log This can help to investigate logs from Mr Jenkins. Cc: Mike Rapoport Signed-off-by: Andrei Vagin Signed-off-by: Andrei Vagin --- test/zdtm.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index d959073f8..3ed9f2994 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -834,11 +834,13 @@ class criu: def fini(self): if self.__lazy_pages_p: ret = self.__lazy_pages_p.wait() + grep_errors(os.path.join(self.__ddir(), "lazy-pages.log")) self.__lazy_pages_p = None if ret: raise test_fail_exc("criu lazy-pages exited with %s" % ret) if self.__page_server_p: ret = self.__page_server_p.wait() + grep_errors(os.path.join(self.__ddir(), "page-server.log")) self.__page_server_p = None if ret: raise test_fail_exc("criu page-server exited with %s" % ret) @@ -1003,6 +1005,7 @@ class criu: if self.__page_server_p: ret = self.__page_server_p.wait() + grep_errors(os.path.join(self.__ddir(), "page-server.log")) self.__page_server_p = None if ret: raise test_fail_exc("criu page-server exited with %d" % ret) @@ -1060,10 +1063,12 @@ class criu: if self.__lazy_pages_p: self.__lazy_pages_p.terminate() print "criu lazy-pages exited with %s" % self.__lazy_pages_p.wait() + grep_errors(os.path.join(self.__ddir(), "lazy-pages.log")) self.__lazy_pages_p = None if self.__page_server_p: self.__page_server_p.terminate() print "criu page-server exited with %s" % self.__page_server_p.wait() + grep_errors(os.path.join(self.__ddir(), "page-server.log")) self.__page_server_p = None From ffee07723ebf510c1d9b6d60e22585565982f308 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 21 Nov 2017 16:59:03 -0800 Subject: [PATCH 1162/4375] criu: remap soccr log levels to criu levels criu and soccr has different values for log levels, so someone has to remap them. Cc: Cyrill Gorcunov Reported-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin Signed-off-by: Andrei Vagin --- criu/crtools.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/criu/crtools.c b/criu/crtools.c index ebfd1d6a7..741b7b2eb 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -208,6 +208,28 @@ bool deprecated_ok(char *what) return false; } +static void soccr_print_on_level(unsigned int loglevel, const char *format, ...) +{ + va_list args; + int lv; + + switch (loglevel) { + case SOCCR_LOG_DBG: + lv = LOG_DEBUG; + break; + case SOCCR_LOG_ERR: + lv = LOG_ERROR; + break; + default: + lv = LOG_INFO; + break; + } + + va_start(args, format); + vprint_on_level(lv, format, args); + va_end(args); +} + int main(int argc, char *argv[], char *envp[]) { @@ -688,7 +710,7 @@ int main(int argc, char *argv[], char *envp[]) if (log_init(opts.output)) return 1; - libsoccr_set_log(log_level, print_on_level); + libsoccr_set_log(log_level, soccr_print_on_level); compel_log_init(vprint_on_level, log_get_loglevel()); pr_debug("Version: %s (gitid %s)\n", CRIU_VERSION, CRIU_GITID); From 3121d90de05f6f2be9a3117e0ce65c41f81d9f13 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 21 Nov 2017 16:58:41 -0800 Subject: [PATCH 1163/4375] criu: print a criu version with the info level We always ask users what version of criu they use to investigate a problem, so it better to have it in a log. Signed-off-by: Andrei Vagin Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/crtools.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/crtools.c b/criu/crtools.c index 741b7b2eb..de74e483c 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -713,7 +713,7 @@ int main(int argc, char *argv[], char *envp[]) libsoccr_set_log(log_level, soccr_print_on_level); compel_log_init(vprint_on_level, log_get_loglevel()); - pr_debug("Version: %s (gitid %s)\n", CRIU_VERSION, CRIU_GITID); + pr_info("Version: %s (gitid %s)\n", CRIU_VERSION, CRIU_GITID); if (opts.deprecated_ok) pr_debug("DEPRECATED ON\n"); From c31d423eeb5387720ebaaf9157c585a20b1f372c Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 28 Nov 2017 03:38:31 +0300 Subject: [PATCH 1164/4375] compel: use a correct name format for vma files in /proc/pid/map_files/ Currently we use the "map_files/%p-%p" format, but actually it should be "map_files/%lx-%lx". The kernel could handle both formats, but recently Alexey Dobriyan fixed the kernel and it accept only the second format. Signed-off-by: Andrei Vagin Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/src/lib/infect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 9ebc5b5ac..0527481ed 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -695,8 +695,8 @@ static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size) ctl->map_length = round_up(size, page_size()); - fd = ctl->ictx.open_proc(ctl->rpid, O_RDWR, "map_files/%p-%p", - ctl->remote_map, ctl->remote_map + ctl->map_length); + fd = ctl->ictx.open_proc(ctl->rpid, O_RDWR, "map_files/%lx-%lx", + (long)ctl->remote_map, (long)ctl->remote_map + ctl->map_length); if (fd < 0) return -1; From dc384c0e30203092d278f4dfcd7b89729f48b44b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 28 Nov 2017 01:12:23 +0300 Subject: [PATCH 1165/4375] netfilter: use ipv4 iptables rules to block IPv4-mapped IPv6 addresses If ipv6 socket has an IPv4-mapped address, it is used to handle ipv4 connection, so we have to use ipv4 iptables rules to block this connection. Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin --- criu/netfilter.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/criu/netfilter.c b/criu/netfilter.c index 5942eb0f1..991c7181f 100644 --- a/criu/netfilter.c +++ b/criu/netfilter.c @@ -47,6 +47,12 @@ void preload_netfilter_modules(void) close_safe(&fd); } +/* IPv4-Mapped IPv6 Addresses */ +static int ipv6_addr_mapped(u32 *addr) +{ + return (addr[2] == htonl(0x0000ffff)); +} + static int nf_connection_switch_raw(int family, u32 *src_addr, u16 src_port, u32 *dst_addr, u16 dst_port, bool input, bool lock) @@ -56,6 +62,12 @@ static int nf_connection_switch_raw(int family, u32 *src_addr, u16 src_port, char *argv[4] = { "sh", "-c", buf, NULL }; int ret; + if (family == AF_INET6 && ipv6_addr_mapped(dst_addr)) { + family = AF_INET; + src_addr = &src_addr[3]; + dst_addr = &dst_addr[3]; + } + switch (family) { case AF_INET: cmd = iptable_cmd_ipv4; From c949e75968b6e5a6b7779d9a9f93c8616ddd6128 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Fri, 24 Nov 2017 13:50:18 +0000 Subject: [PATCH 1166/4375] crtools: also print the current kernel version In addition to writing the CRIU version to the log file this adds the current kernel version to the log file: (00.000008) Version: 3.5 (gitid v3.5-511-ga8cc6cf) (00.000303) Running on node01 Linux 3.10.0-513.el7.x86_64 #1 SMP Tue Feb 29 06:78:90 EST 2017 x86_64 v2: - small changes as suggested by Dmitry (thanks) Signed-off-by: Adrian Reber Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/crtools.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/criu/crtools.c b/criu/crtools.c index de74e483c..fea2ccc7a 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -19,6 +19,8 @@ #include +#include + #include "int.h" #include "page.h" #include "common/compiler.h" @@ -230,6 +232,20 @@ static void soccr_print_on_level(unsigned int loglevel, const char *format, ...) va_end(args); } +static void print_kernel_version(void) +{ + struct utsname buf; + + if (uname(&buf) < 0) { + pr_perror("Reading kernel version failed!"); + /* This pretty unlikely, just keep on running. */ + return; + } + + pr_info("Running on %s %s %s %s %s\n", buf.nodename, buf.sysname, + buf.release, buf.version, buf.machine); +} + int main(int argc, char *argv[], char *envp[]) { @@ -714,6 +730,9 @@ int main(int argc, char *argv[], char *envp[]) compel_log_init(vprint_on_level, log_get_loglevel()); pr_info("Version: %s (gitid %s)\n", CRIU_VERSION, CRIU_GITID); + + print_kernel_version(); + if (opts.deprecated_ok) pr_debug("DEPRECATED ON\n"); From e3c6784b8f4ffa5d7246e236362ae4318de0419b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 8 Nov 2017 03:36:03 +0300 Subject: [PATCH 1167/4375] parasite: remove restriction to a number of iovec-s vmsplice can't splice more than UIO_MAXIOV, but we can call it a few times from a parasite. v2: s/nr/nr_segs/ Acked-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/page-pipe.c | 8 +------- criu/pie/parasite.c | 29 +++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/criu/page-pipe.c b/criu/page-pipe.c index 7da8bebc3..4eabb5ed5 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -207,15 +207,9 @@ static inline int try_add_page_to(struct page_pipe *pp, struct page_pipe_buf *pp return 1; /* need to add another buf */ } - if (ppb->nr_segs) { - if (iov_grow_page(&ppb->iov[ppb->nr_segs - 1], addr)) + if (ppb->nr_segs && iov_grow_page(&ppb->iov[ppb->nr_segs - 1], addr)) goto out; - if (ppb->nr_segs == UIO_MAXIOV) - /* XXX -- shrink pipe back? */ - return 1; - } - pr_debug("Add iov to page pipe (%u iovs, %u/%u total)\n", ppb->nr_segs, pp->free_iov, pp->nr_iovs); iov_init(&ppb->iov[ppb->nr_segs++], addr); diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index db2a75f59..12b8cb981 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "common/config.h" #include "int.h" @@ -66,6 +67,7 @@ static int dump_pages(struct parasite_dump_pages_args *args) { int p, ret, tsock; struct iovec *iovs; + int off, nr_segs, nr_pages; tsock = parasite_get_rpc_sock(); p = recv_fd(tsock); @@ -73,11 +75,30 @@ static int dump_pages(struct parasite_dump_pages_args *args) return -1; iovs = pargs_iovs(args); - ret = sys_vmsplice(p, &iovs[args->off], args->nr_segs, - SPLICE_F_GIFT | SPLICE_F_NONBLOCK); - if (ret != PAGE_SIZE * args->nr_pages) { + nr_pages = 0; + off = 0; + nr_segs = args->nr_segs; + if (nr_segs > UIO_MAXIOV) + nr_segs = UIO_MAXIOV; + while (1) { + ret = sys_vmsplice(p, &iovs[args->off + off], nr_segs, + SPLICE_F_GIFT | SPLICE_F_NONBLOCK); + if (ret < 0) { + sys_close(p); + pr_err("Can't splice pages to pipe (%d/%d/%d)\n", + ret, nr_segs, args->off + off); + return -1; + } + nr_pages += ret; + off += nr_segs; + if (off == args->nr_segs) + break; + if (off + nr_segs > args->nr_segs) + nr_segs = args->nr_segs - off; + } + if (nr_pages != args->nr_pages * PAGE_SIZE) { sys_close(p); - pr_err("Can't splice pages to pipe (%d/%d)\n", ret, args->nr_pages); + pr_err("Can't splice all pages to pipe (%d/%d)\n", nr_pages, args->nr_pages); return -1; } From 6feebf3aad9855285795f71f8bc58982535e0b91 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 8 Nov 2017 03:36:04 +0300 Subject: [PATCH 1168/4375] page-pipe: move code to resize a pipe in a separate function v2: and move it upper, because it is going to be used in ppb_alloc() Acked-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/page-pipe.c | 65 +++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/criu/page-pipe.c b/criu/page-pipe.c index 4eabb5ed5..0f5e39ee2 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -28,6 +28,41 @@ static inline void iov_init(struct iovec *iov, unsigned long addr) iov->iov_len = PAGE_SIZE; } +static int __ppb_resize_pipe(struct page_pipe_buf *ppb, unsigned long new_size) +{ + int ret; + + ret = fcntl(ppb->p[0], F_SETPIPE_SZ, new_size * PAGE_SIZE); + if (ret < 0) + return -1; + + ret /= PAGE_SIZE; + BUG_ON(ret < ppb->pipe_size); + + pr_debug("Grow pipe %x -> %x\n", ppb->pipe_size, ret); + ppb->pipe_size = ret; + + return 0; +} + +static inline int ppb_resize_pipe(struct page_pipe_buf *ppb) +{ + unsigned long new_size = ppb->pipe_size << 1; + int ret; + + if (ppb->pages_in < ppb->pipe_size) + return 0; + + if (new_size > PIPE_MAX_SIZE) + return 1; + + ret = __ppb_resize_pipe(ppb, new_size); + if (ret < 0) + return 1; /* need to add another buf */ + + return 0; +} + static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp) { struct page_pipe_buf *ppb; @@ -69,23 +104,6 @@ static void ppb_init(struct page_pipe_buf *ppb, unsigned int pages_in, ppb->iov = iov; } -static int ppb_resize_pipe(struct page_pipe_buf *ppb, unsigned long new_size) -{ - int ret; - - ret = fcntl(ppb->p[0], F_SETPIPE_SZ, new_size * PAGE_SIZE); - if (ret < 0) - return -1; - - ret /= PAGE_SIZE; - BUG_ON(ret < ppb->pipe_size); - - pr_debug("Grow pipe %x -> %x\n", ppb->pipe_size, ret); - ppb->pipe_size = ret; - - return 0; -} - static int page_pipe_grow(struct page_pipe *pp, unsigned int flags) { struct page_pipe_buf *ppb; @@ -195,17 +213,8 @@ static inline int try_add_page_to(struct page_pipe *pp, struct page_pipe_buf *pp if (ppb->flags != flags) return 1; - if (ppb->pages_in == ppb->pipe_size) { - unsigned long new_size = ppb->pipe_size << 1; - int ret; - - if (new_size > PIPE_MAX_SIZE) - return 1; - - ret = ppb_resize_pipe(ppb, new_size); - if (ret < 0) - return 1; /* need to add another buf */ - } + if (ppb_resize_pipe(ppb) == 1) + return 1; if (ppb->nr_segs && iov_grow_page(&ppb->iov[ppb->nr_segs - 1], addr)) goto out; From cef1efe5bdae9350678312237b42cf7d5d096260 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 8 Nov 2017 03:36:05 +0300 Subject: [PATCH 1169/4375] page-pipe: allow to share pipes between page pipe buffers Now criu create a new pipe buffer, if a previous one has another set of flags. In this case, a pipe is not full and we can use it for the next page buffer. We need 88 pipes to pre-dump the zdtm/static/fork test without this patch, and we need only 17 pipes with this patch. Acked-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/include/page-pipe.h | 1 + criu/page-pipe.c | 45 +++++++++++++++++++++++++++------------- criu/page-xfer.c | 2 +- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h index 301edaae0..053ae3938 100644 --- a/criu/include/page-pipe.h +++ b/criu/include/page-pipe.h @@ -93,6 +93,7 @@ struct kernel_pipe_buffer { struct page_pipe_buf { int p[2]; /* pipe with pages */ unsigned int pipe_size; /* how many pages can be fit into pipe */ + unsigned int pipe_off; /* where this buf is started in a pipe */ unsigned int pages_in; /* how many pages are there */ unsigned int nr_segs; /* how many iov-s are busy */ #define PPB_LAZY (1 << 0) diff --git a/criu/page-pipe.c b/criu/page-pipe.c index 0f5e39ee2..f7d691d13 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -50,7 +50,7 @@ static inline int ppb_resize_pipe(struct page_pipe_buf *ppb) unsigned long new_size = ppb->pipe_size << 1; int ret; - if (ppb->pages_in < ppb->pipe_size) + if (ppb->pages_in + ppb->pipe_off < ppb->pipe_size) return 0; if (new_size > PIPE_MAX_SIZE) @@ -63,7 +63,7 @@ static inline int ppb_resize_pipe(struct page_pipe_buf *ppb) return 0; } -static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp) +static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp, struct page_pipe_buf *prev) { struct page_pipe_buf *ppb; @@ -72,15 +72,25 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp) return NULL; cnt_add(CNT_PAGE_PIPE_BUFS, 1); - if (pipe(ppb->p)) { - xfree(ppb); - pr_perror("Can't make pipe for page-pipe"); - return NULL; - } - cnt_add(CNT_PAGE_PIPES, 1); + ppb->pipe_off = 0; - ppb->pipe_size = fcntl(ppb->p[0], F_GETPIPE_SZ, 0) / PAGE_SIZE; - pp->nr_pipes++; + if (prev && ppb_resize_pipe(prev) == 0) { + /* The previous pipe isn't full and we can continue to use it. */ + ppb->p[0] = prev->p[0]; + ppb->p[1] = prev->p[1]; + ppb->pipe_off = prev->pages_in + prev->pipe_off; + ppb->pipe_size = prev->pipe_size; + } else { + if (pipe(ppb->p)) { + xfree(ppb); + pr_perror("Can't make pipe for page-pipe"); + return NULL; + } + cnt_add(CNT_PAGE_PIPES, 1); + + ppb->pipe_size = fcntl(ppb->p[0], F_GETPIPE_SZ, 0) / PAGE_SIZE; + pp->nr_pipes++; + } list_add_tail(&ppb->l, &pp->bufs); @@ -89,8 +99,11 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp) static void ppb_destroy(struct page_pipe_buf *ppb) { - close(ppb->p[0]); - close(ppb->p[1]); + /* Check whether a pipe is shared with another ppb */ + if (ppb->pipe_off == 0) { + close(ppb->p[0]); + close(ppb->p[1]); + } xfree(ppb); } @@ -106,7 +119,7 @@ static void ppb_init(struct page_pipe_buf *ppb, unsigned int pages_in, static int page_pipe_grow(struct page_pipe *pp, unsigned int flags) { - struct page_pipe_buf *ppb; + struct page_pipe_buf *ppb, *prev = NULL; struct iovec *free_iov; pr_debug("Will grow page pipe (iov off is %u)\n", pp->free_iov); @@ -120,7 +133,10 @@ static int page_pipe_grow(struct page_pipe *pp, unsigned int flags) if ((pp->flags & PP_CHUNK_MODE) && (pp->nr_pipes == NR_PIPES_PER_CHUNK)) return -EAGAIN; - ppb = ppb_alloc(pp); + /* don't allow to reuse a pipe in the PP_CHUNK_MODE mode */ + if (!(pp->flags & PP_CHUNK_MODE) && !list_empty(&pp->bufs)) + prev = list_entry(pp->bufs.prev, struct page_pipe_buf, l); + ppb = ppb_alloc(pp, prev); if (!ppb) return -1; @@ -374,6 +390,7 @@ int page_pipe_read(struct page_pipe *pp, struct pipe_read_dest *prd, (unsigned long)(*nr_pages) * PAGE_SIZE); *nr_pages = len / PAGE_SIZE; + skip += ppb->pipe_off * PAGE_SIZE; /* we should tee() the requested lenth + the beginning of the pipe */ len += skip; diff --git a/criu/page-xfer.c b/criu/page-xfer.c index df4eb2877..36efd8aa2 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -216,7 +216,7 @@ static int write_pages_loc(struct page_xfer *xfer, ssize_t curr = 0; while (1) { - ret = splice(p, NULL, img_raw_fd(xfer->pi), NULL, len, SPLICE_F_MOVE); + ret = splice(p, NULL, img_raw_fd(xfer->pi), NULL, len - curr, SPLICE_F_MOVE); if (ret == -1) { pr_perror("Unable to spice data"); return -1; From e85646875f4d615d7ce30f0f4e8cae06d0d4e73e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 2 Nov 2017 00:40:35 +0300 Subject: [PATCH 1170/4375] zdtm/maps006: modify test so that file and anon vma-s are mixed Signed-off-by: Andrei Vagin --- test/zdtm/static/maps06.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/test/zdtm/static/maps06.c b/test/zdtm/static/maps06.c index 49602e446..df57fdb40 100644 --- a/test/zdtm/static/maps06.c +++ b/test/zdtm/static/maps06.c @@ -10,8 +10,11 @@ const char *test_author = "Andrei Vagin "; char *filename; TEST_OPTION(filename, string, "file name", 1); +#define TEST_SIZE 10240 + int main(int argc, char ** argv) { + void *start; int fd, i; test_init(argc, argv); @@ -22,17 +25,40 @@ int main(int argc, char ** argv) ftruncate(fd, 4096); - for (i = 0; i < 1024; i++) { - if (mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FILE, fd, 0) == MAP_FAILED) + start = mmap(0, 4096 * TEST_SIZE * 4, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + if (start == MAP_FAILED) + return 1; + + for (i = 0; i < TEST_SIZE; i++) { + int *addr; + addr = mmap(start + i * 3 * 4096, 4096, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FILE | MAP_FIXED, fd, 0); + if (addr == MAP_FAILED) return 1; - if (mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == MAP_FAILED) + addr[0] = i * 2; + addr = mmap(start + (i * 3 + 1) * 4096, 4096, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + if (addr == MAP_FAILED) return 1; + addr[0] = i; } test_daemon(); test_waitsig(); + for (i = 0; i < TEST_SIZE; i++) { + int *addr; + addr = start + i * 3 * 4096;; + if (addr[0] != i * 2) + fail(); + addr = start + (i * 3 + 1) * 4096; + if (addr[0] != i) + fail(); + } + pass(); return 0; From 23d086c263d1bb132bae04e227b818d086fe89cc Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 16 Nov 2017 13:54:05 +0200 Subject: [PATCH 1171/4375] debug_show_page_pipe: add PPB's pipe offset Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/page-pipe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/page-pipe.c b/criu/page-pipe.c index f7d691d13..f33e86a4f 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -428,8 +428,8 @@ void debug_show_page_pipe(struct page_pipe *pp) pr_debug("* %u pipes %u/%u iovs:\n", pp->nr_pipes, pp->free_iov, pp->nr_iovs); list_for_each_entry(ppb, &pp->bufs, l) { - pr_debug("\tbuf %u pages, %u iovs, flags: %x :\n", - ppb->pages_in, ppb->nr_segs, ppb->flags); + pr_debug("\tbuf %u pages, %u iovs, flags: %x pipe_off: %x :\n", + ppb->pages_in, ppb->nr_segs, ppb->flags, ppb->pipe_off); for (i = 0; i < ppb->nr_segs; i++) { iov = &ppb->iov[i]; pr_debug("\t\t%p %lu\n", iov->iov_base, From 7ce804ed9f33dd0f2f24a4bd226be780ed9bc67c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 16 Nov 2017 13:54:06 +0200 Subject: [PATCH 1172/4375] page-xfer: remote-pages: allow receiving partial data Since commit e609267f681062b4370e528a50f635222e0c2330 ("page-pipe: allow to share pipes between page pipe buffers") the assumption that we will receive the exact amount of pages we've requested with PS_IOV_GET does not always hold. In the case we serve pages data from the images using 'page-server --lazy-page' the IOVs seen by the pagemap may cross page-pipe buffer boundaries and read_page_pipe will clamp the pages in the response to those boundaries. Adjust page_server_read so it will not try to receive more pages than page-server is going to send. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 36efd8aa2..c49626c93 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -1084,6 +1084,7 @@ out: struct ps_async_read { unsigned long rb; /* read bytes */ unsigned long goal; + unsigned long nr_pages; struct page_server_iov pi; void *pages; @@ -1096,14 +1097,20 @@ struct ps_async_read { static LIST_HEAD(async_reads); +static inline void async_read_set_goal(struct ps_async_read *ar, int nr_pages) +{ + ar->goal = sizeof(ar->pi) + nr_pages * PAGE_SIZE; + ar->nr_pages = nr_pages; +} + static void init_ps_async_read(struct ps_async_read *ar, void *buf, int nr_pages, ps_async_read_complete complete, void *priv) { ar->pages = buf; ar->rb = 0; - ar->goal = sizeof(ar->pi) + nr_pages * PAGE_SIZE; ar->complete = complete; ar->priv = priv; + async_read_set_goal(ar, nr_pages); } static int page_server_start_async_read(void *buf, int nr_pages, @@ -1139,6 +1146,9 @@ static int page_server_read(struct ps_async_read *ar, int flags) buf = ((void *)&ar->pi) + ar->rb; need = sizeof(ar->pi) - ar->rb; } else { + /* page-serer may return less pages than we asked for */ + if (ar->pi.nr_pages < ar->nr_pages) + async_read_set_goal(ar, ar->pi.nr_pages); /* Page(s) data itself */ buf = ar->pages + (ar->rb - sizeof(ar->pi)); need = ar->goal - ar->rb; From 3dfae093c1bb1b69aee790c5a295eb6b15d0e9a7 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 16 Nov 2017 13:54:07 +0200 Subject: [PATCH 1173/4375] lazy-pages: drop_iovs: mark iov as not queued If we receive only part of the IOV from the page-server we recalculate the IOV so it will point to the area we still have to fetch. During the split, the IOV covering the remaining area may remain marked as 'queued' and we'll never retry fetching it. Marking the IOV as not queued will ensure its pages will be requested again. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/uffd.c b/criu/uffd.c index 740f5e371..93ba0d681 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -460,6 +460,8 @@ static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) addr = start; } + iov->queued = false; + /* * The range completely fits into the current IOV. * If addr equals iov_base we just "drop" the From 06e252dedcc1e5f09772c555a346e61db0abee6c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 22 Nov 2017 21:37:08 +0200 Subject: [PATCH 1174/4375] util: epoll: move comment about timeout decrease to uffd.c The generic epoll_wait wrapper should not do any assumptions about timeout. It's it up to lazy-pages daemon to make (future) policy decisions. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 1 + criu/util.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index 93ba0d681..ee6d2b9a0 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1105,6 +1105,7 @@ static void lazy_pages_summary(struct lazy_pages_info *lpi) static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) { struct lazy_pages_info *lpi, *n; + /* FIXME -- timeout should decrease over time... */ int poll_timeout = POLL_TIMEOUT; int ret; diff --git a/criu/util.c b/criu/util.c index 27bf71e44..f2b3b0a18 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1300,7 +1300,6 @@ int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout bool have_a_break = false; while (1) { - /* FIXME -- timeout should decrease over time... */ ret = epoll_wait(epollfd, evs, nr_fds, timeout); if (ret <= 0) { if (ret < 0) From 2a0a5221b853c34c4883b8d632f7ec7096466b77 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 22 Nov 2017 21:37:09 +0200 Subject: [PATCH 1175/4375] util: epoll: rename revent to read event A bit more readable and will be easy to distinguish from upcoming hevent^Whangup_event. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/include/util.h | 8 +++++++- criu/page-xfer.c | 2 +- criu/uffd.c | 2 +- criu/util.c | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/criu/include/util.h b/criu/include/util.h index 83945a104..2b7e66693 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -322,7 +322,13 @@ int setup_tcp_client(char *addr); struct epoll_rfd { int fd; - int (*revent)(struct epoll_rfd *); + /* + * EPOLLIN notification. The data is available for read in + * rfd->fd. + * @return 0 to resume polling, 1 to stop polling or a + * negative error code + */ + int (*read_event)(struct epoll_rfd *); }; extern int epoll_add_rfd(int epfd, struct epoll_rfd *); diff --git a/criu/page-xfer.c b/criu/page-xfer.c index c49626c93..32c10958a 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -1199,7 +1199,7 @@ int connect_to_page_server_to_recv(int epfd) return -1; ps_rfd.fd = page_server_sk; - ps_rfd.revent = page_server_async_read; + ps_rfd.read_event = page_server_async_read; return epoll_add_rfd(epfd, &ps_rfd); } diff --git a/criu/uffd.c b/criu/uffd.c index ee6d2b9a0..9c1bbe0cf 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -114,7 +114,7 @@ static struct lazy_pages_info *lpi_init(void) INIT_LIST_HEAD(&lpi->iovs); INIT_LIST_HEAD(&lpi->reqs); INIT_LIST_HEAD(&lpi->l); - lpi->lpfd.revent = handle_uffd_event; + lpi->lpfd.read_event = handle_uffd_event; return lpi; } diff --git a/criu/util.c b/criu/util.c index f2b3b0a18..fe640b9f6 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1312,7 +1312,7 @@ int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout struct epoll_rfd *rfd; rfd = (struct epoll_rfd *)evs[i].data.ptr; - ret = rfd->revent(rfd); + ret = rfd->read_event(rfd); if (ret < 0) goto out; if (ret > 0) From dcfe17e7aa8048ae0dfab246c21bd5e1ecaa39d0 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 22 Nov 2017 21:37:10 +0200 Subject: [PATCH 1176/4375] util: epoll: add processing of EPOLL{RD}HUP Currently when we poll a file descriptor, we only process EPOLLIN events and if a connection is closed the receiving side has no means to deal with it. Add a callback for EPOLL{RD}HUP events and the default implementation for these events that removes the file descriptor from epoll and closes it. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/include/util.h | 8 ++++++++ criu/util.c | 43 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/criu/include/util.h b/criu/include/util.h index 2b7e66693..0478e0676 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -329,6 +329,14 @@ struct epoll_rfd { * negative error code */ int (*read_event)(struct epoll_rfd *); + + /* + * EPOLLHUP | EPOLLRDHUP notification. The remote side has + * close the connection for rfd->fd. + * @return 0 to resume polling, 1 to stop polling or a + * negative error code + */ + int (*hangup_event)(struct epoll_rfd *); }; extern int epoll_add_rfd(int epfd, struct epoll_rfd *); diff --git a/criu/util.c b/criu/util.c index fe640b9f6..0ddf4d402 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1274,7 +1274,7 @@ int epoll_add_rfd(int epfd, struct epoll_rfd *rfd) { struct epoll_event ev; - ev.events = EPOLLIN; + ev.events = EPOLLIN | EPOLLRDHUP; ev.data.ptr = rfd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, rfd->fd, &ev) == -1) { pr_perror("epoll_ctl failed"); @@ -1294,6 +1294,24 @@ int epoll_del_rfd(int epfd, struct epoll_rfd *rfd) return 0; } +static int epoll_hangup_event(int epollfd, struct epoll_rfd *rfd) +{ + int ret = 0; + + if (rfd->hangup_event) { + ret = rfd->hangup_event(rfd); + if (ret < 0) + return ret; + } + + if (epoll_del_rfd(epollfd, rfd)) + return -1; + + close_safe(&rfd->fd); + + return ret; +} + int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout) { int ret, i, nr_events; @@ -1310,13 +1328,26 @@ int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout nr_events = ret; for (i = 0; i < nr_events; i++) { struct epoll_rfd *rfd; + uint32_t events; rfd = (struct epoll_rfd *)evs[i].data.ptr; - ret = rfd->read_event(rfd); - if (ret < 0) - goto out; - if (ret > 0) - have_a_break = true; + events = evs[i].events; + + if (events & EPOLLIN) { + ret = rfd->read_event(rfd); + if (ret < 0) + goto out; + if (ret > 0) + have_a_break = true; + } + + if (events & (EPOLLHUP | EPOLLRDHUP)) { + ret = epoll_hangup_event(epollfd, rfd); + if (ret < 0) + goto out; + if (ret > 0) + have_a_break = true; + } } if (have_a_break) From 83e75c3c1d3b4141f4532a73e1e78ffd64f2e8db Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 22 Nov 2017 21:37:11 +0200 Subject: [PATCH 1177/4375] page-server: implement epoll->hangup_event The remote page read has nothing to do if the page-server on the source has closed the connection. Just report an error and abort. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 32c10958a..df6d35e0c 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -1191,6 +1191,12 @@ static int page_server_async_read(struct epoll_rfd *f) return ret; } +static int page_server_hangup_event(struct epoll_rfd *rfd) +{ + pr_err("Remote side closed connection\n"); + return -1; +} + static struct epoll_rfd ps_rfd; int connect_to_page_server_to_recv(int epfd) @@ -1200,6 +1206,7 @@ int connect_to_page_server_to_recv(int epfd) ps_rfd.fd = page_server_sk; ps_rfd.read_event = page_server_async_read; + ps_rfd.hangup_event = page_server_hangup_event; return epoll_add_rfd(epfd, &ps_rfd); } From 8797645636226ed830291b833ce2623d924aefde Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 22 Nov 2017 21:37:12 +0200 Subject: [PATCH 1178/4375] lazy-pages: do not allow background fetch before restore is finished If we start backroung memory fetch before restore is completely finished, we may try to write to the memory areas which were not yet remapped to proper place and are not registered with userfaultfd. Add synchronization between restore and the lazy-pages so that lazy-pages will only handle #PFs before all the tasks are restored. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 3 ++ criu/include/uffd.h | 1 + criu/uffd.c | 83 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 7086c7415..3a1c0cd9e 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2104,6 +2104,9 @@ skip_ns_bouncing: ret = catch_tasks(root_seized, &flag); + if (lazy_pages_finish_restore()) + goto out_kill; + pr_info("Restore finished successfully. Resuming tasks.\n"); __restore_switch_stage(CR_STATE_COMPLETE); diff --git a/criu/include/uffd.h b/criu/include/uffd.h index 79abc1669..814e60f33 100644 --- a/criu/include/uffd.h +++ b/criu/include/uffd.h @@ -8,5 +8,6 @@ extern bool uffd_noncooperative(void); extern int setup_uffd(int pid, struct task_restore_args *task_args); extern int lazy_pages_setup_zombie(int pid); extern int prepare_lazy_pages_socket(void); +extern int lazy_pages_finish_restore(void); #endif /* __CR_UFFD_H_ */ diff --git a/criu/uffd.c b/criu/uffd.c index 9c1bbe0cf..72fc1402d 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -56,6 +56,8 @@ #define LAZY_PAGES_SOCK_NAME "lazy-pages.socket" +#define LAZY_PAGES_RESTORE_FINISHED 0x52535446 /* ReSTore Finished */ + static mutex_t *lazy_sock_mutex; struct lazy_iov { @@ -99,6 +101,8 @@ static LIST_HEAD(lpis); static LIST_HEAD(exiting_lpis); static LIST_HEAD(pending_lpis); static int epollfd; +static bool restore_finished; +static struct epoll_rfd lazy_sk_rfd; static int handle_uffd_event(struct epoll_rfd *lpfd); @@ -1121,6 +1125,10 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) continue; } + /* don't start backround fetch before restore is finished */ + if (!restore_finished) + continue; + if (poll_timeout) pr_debug("Start handling remaining pages\n"); @@ -1151,6 +1159,29 @@ out: } +int lazy_pages_finish_restore(void) +{ + uint32_t fin = LAZY_PAGES_RESTORE_FINISHED; + int fd, ret; + + if (!opts.lazy_pages) + return 0; + + fd = get_service_fd(LAZY_PAGES_SK_OFF); + if (fd < 0) { + pr_err("No lazy-pages socket\n"); + return -1; + } + + ret = send(fd, &fin, sizeof(fin), 0); + if (ret != sizeof(fin)) + pr_perror("Failed sending restore finished indication"); + + close(fd); + + return ret < 0 ? ret : 0; +} + static int prepare_lazy_socket(void) { int listen; @@ -1168,6 +1199,44 @@ static int prepare_lazy_socket(void) return listen; } +static int lazy_sk_read_event(struct epoll_rfd *rfd) +{ + uint32_t fin; + int ret; + + ret = recv(rfd->fd, &fin, sizeof(fin), 0); + /* + * epoll sets POLLIN | POLLHUP for the EOF case, so we get short + * read just befor hangup_event + */ + if (!ret) + return 0; + + if (ret != sizeof(fin)) { + pr_perror("Failed getting restore finished inidication"); + return -1; + } + + if (fin != LAZY_PAGES_RESTORE_FINISHED) { + pr_err("Unexpected response: %x\n", fin); + return -1; + } + + restore_finished = true; + + return 0; +} + +static int lazy_sk_hangup_event(struct epoll_rfd *rfd) +{ + if (!restore_finished) { + pr_err("Restorer unexpectedly closed the connection\n"); + return -1; + } + + return 0; +} + static int prepare_uffds(int listen, int epollfd) { int i; @@ -1193,7 +1262,12 @@ static int prepare_uffds(int listen, int epollfd) goto close_uffd; } - close_safe(&client); + lazy_sk_rfd.fd = client; + lazy_sk_rfd.read_event = lazy_sk_read_event; + lazy_sk_rfd.hangup_event = lazy_sk_hangup_event; + if (epoll_add_rfd(epollfd, &lazy_sk_rfd)) + goto close_uffd; + close(listen); return 0; @@ -1243,7 +1317,12 @@ int cr_lazy_pages(bool daemon) if (close_status_fd()) return -1; - nr_fds = task_entries->nr_tasks + (opts.use_page_server ? 1 : 0); + /* + * we poll nr_tasks userfault fds, UNIX socket between lazy-pages + * daemon and the cr-restore, and, optionally TCP socket for + * remote pages + */ + nr_fds = task_entries->nr_tasks + (opts.use_page_server ? 2 : 1); epollfd = epoll_prepare(nr_fds, &events); if (epollfd < 0) return -1; From d8c974d651bd1172c067a9ef63cd1c298baba827 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 30 Nov 2017 13:46:18 +0200 Subject: [PATCH 1179/4375] zdtm: lib: add {read,write}_data helpers Some tests expect that all the data will be handled in a single invocation of read/write system call. But it possible to have short read/write on a loaded system and this is not an error. Add helper functions that will reliably read/write the entire buffer. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm/lib/streamutil.c | 33 +++++++++++++++++++++++++++++++++ test/zdtm/lib/zdtmtst.h | 2 ++ 2 files changed, 35 insertions(+) diff --git a/test/zdtm/lib/streamutil.c b/test/zdtm/lib/streamutil.c index ba6645872..90305c02a 100644 --- a/test/zdtm/lib/streamutil.c +++ b/test/zdtm/lib/streamutil.c @@ -40,3 +40,36 @@ int pipe_in2out(int infd, int outfd, uint8_t *buffer, int length) } } } + +int read_data(int fd, unsigned char *buf, int size) +{ + int cur = 0; + int ret; + while (cur != size) { + ret = read(fd, buf + cur, size - cur); + if (ret <= 0) { + pr_perror("read(%d) = %d", size - cur, ret); + return -1; + } + cur += ret; + } + + return 0; +} + +int write_data(int fd, const unsigned char *buf, int size) +{ + int cur = 0; + int ret; + + while (cur != size) { + ret = write(fd, buf + cur, size - cur); + if (ret <= 0) { + pr_perror("write(%d) = %d", size - cur, ret); + return -1; + } + cur += ret; + } + + return 0; +} diff --git a/test/zdtm/lib/zdtmtst.h b/test/zdtm/lib/zdtmtst.h index cd513b9c9..737ac77cf 100644 --- a/test/zdtm/lib/zdtmtst.h +++ b/test/zdtm/lib/zdtmtst.h @@ -55,6 +55,8 @@ extern int datasum(const uint8_t *buffer, unsigned length, uint32_t *crc); /* streaming helpers */ extern int set_nonblock(int fd, int on); extern int pipe_in2out(int infd, int outfd, uint8_t *buffer, int length); +extern int read_data(int fd, unsigned char *buf, int len); +extern int write_data(int fd, const unsigned char *buf, int len); /* command line args */ struct long_opt { From 0131a851156a7595c7f79da87f9735602c4bd6b2 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 30 Nov 2017 13:46:19 +0200 Subject: [PATCH 1180/4375] zdtm: use {read,write}_data in fifo tests Reading and writing large buffers may result in short read/write. In cases we expect the entire buffer to be transferred use {read,write}_data rather than plain read/write syscalls. Reported-by: Mr Jenkins Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm/static/fifo-ghost.c | 7 ++----- test/zdtm/static/fifo.c | 7 ++----- test/zdtm/static/fifo_ro.c | 7 ++----- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/test/zdtm/static/fifo-ghost.c b/test/zdtm/static/fifo-ghost.c index 94a8c57f5..f5e11cfa2 100644 --- a/test/zdtm/static/fifo-ghost.c +++ b/test/zdtm/static/fifo-ghost.c @@ -20,7 +20,6 @@ int main(int argc, char **argv) mode_t mode = S_IFIFO | 0700; uint8_t buf[256]; uint32_t crc; - int ret; test_init(argc, argv); @@ -43,8 +42,7 @@ int main(int argc, char **argv) crc = ~0; datagen(buf, sizeof(buf), &crc); - ret = write(fd, buf, sizeof(buf)); - if (ret != sizeof(buf)) { + if (write_data(fd, buf, sizeof(buf))) { pr_perror("write() failed"); return 1; } @@ -59,8 +57,7 @@ int main(int argc, char **argv) test_daemon(); test_waitsig(); - ret = read(fd_ro, buf, sizeof(buf)); - if (ret != sizeof(buf)) { + if (read_data(fd_ro, buf, sizeof(buf))) { pr_perror("read() failed"); return 1; } diff --git a/test/zdtm/static/fifo.c b/test/zdtm/static/fifo.c index c8437d932..ab5674a9e 100644 --- a/test/zdtm/static/fifo.c +++ b/test/zdtm/static/fifo.c @@ -23,7 +23,6 @@ int main(int argc, char **argv) mode_t mode = S_IFIFO | 0700; uint8_t buf[BUF_SIZE]; uint32_t crc; - int ret;; test_init(argc, argv); @@ -40,8 +39,7 @@ int main(int argc, char **argv) crc = ~0; datagen(buf, BUF_SIZE, &crc); - ret = write(fd, buf, BUF_SIZE); - if (ret != BUF_SIZE) { + if (write_data(fd, buf, BUF_SIZE)) { pr_perror("write() failed"); return 1; } @@ -49,8 +47,7 @@ int main(int argc, char **argv) test_daemon(); test_waitsig(); - ret = read(fd, buf, BUF_SIZE); - if (ret != BUF_SIZE) { + if (read_data(fd, buf, BUF_SIZE)) { pr_perror("read() failed"); return 1; } diff --git a/test/zdtm/static/fifo_ro.c b/test/zdtm/static/fifo_ro.c index 63c4d29cf..ea3232937 100644 --- a/test/zdtm/static/fifo_ro.c +++ b/test/zdtm/static/fifo_ro.c @@ -23,7 +23,6 @@ int main(int argc, char **argv) mode_t mode = S_IFIFO | 0700; uint8_t buf[BUF_SIZE]; uint32_t crc; - int ret;; test_init(argc, argv); @@ -46,8 +45,7 @@ int main(int argc, char **argv) crc = ~0; datagen(buf, BUF_SIZE, &crc); - ret = write(fd, buf, BUF_SIZE); - if (ret != BUF_SIZE) { + if (write_data(fd, buf, BUF_SIZE)) { pr_perror("write() failed"); return 1; } @@ -57,8 +55,7 @@ int main(int argc, char **argv) test_daemon(); test_waitsig(); - ret = read(fd_ro, buf, BUF_SIZE); - if (ret != BUF_SIZE) { + if (read_data(fd_ro, buf, BUF_SIZE)) { pr_perror("read() failed"); return 1; } From 5bf9f9b6a6151ee599d99e48c77a4793ca62ec78 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 1 Dec 2017 13:09:55 +0300 Subject: [PATCH 1181/4375] remap: don't free rpath and don't shfree_last gf a) As we shmalloced rpath it can not be xfreed. b) As we shmalloc variables in collect_remap_ghost() far away from open_remap_ghost() where we want to free them, there is no guaranty that our shmalloc was last and we can't use shfree_last(). fixes commit 0c675a5e9d40 ("files: remove link_remaps when everything has been restored") When create_ghost() fails for some reason that produces a segfault for me. Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index d5a97ce60..89ae007eb 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -466,8 +466,6 @@ close_ifd: err: if (gfe) ghost_file_entry__free_unpacked(gfe, NULL); - xfree(gf->remap.rpath); - shfree_last(gf); return -1; } From 6dd3e4e39d84d983254d8dfdf91231640a2e6421 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Dec 2017 00:05:49 +0300 Subject: [PATCH 1182/4375] test: check a pipe with a custom size CRIU doesn't handle correctly pipes with sizes which are bigger than a default one. Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/pipe03.c | 54 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 test/zdtm/static/pipe03.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 0e1db5c5c..fd5905e48 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -192,6 +192,7 @@ TST_NOFILE := \ s390x_mmap_high \ uffd-events \ thread_different_uid_gid \ + pipe03 \ # jobctl00 \ include ../Makefile.inc diff --git a/test/zdtm/static/pipe03.c b/test/zdtm/static/pipe03.c new file mode 100644 index 000000000..a8721e934 --- /dev/null +++ b/test/zdtm/static/pipe03.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check that pipes with a non-default size can be c/r-ed"; +const char *test_author = "Andrei Vagin "; + +#define DATA_SIZE (1 << 20) +#define BUF_SIZE (4096) + +int main(int argc, char **argv) +{ + int p[2], i; + uint8_t buf[BUF_SIZE]; + uint32_t crc; + + test_init(argc, argv); + + if (pipe2(p, O_NONBLOCK)) { + pr_perror("pipe"); + return 1; + } + + if (fcntl(p[1], F_SETPIPE_SZ, DATA_SIZE) == -1) { + pr_perror("Unable to change a pipe size"); + return 1; + } + + crc = ~0; + datagen(buf, BUF_SIZE, &crc); + + for (i = 0; i < DATA_SIZE / BUF_SIZE; i++) { + if (write(p[1], buf, BUF_SIZE) != BUF_SIZE) { + pr_perror("write"); + return 1; + } + } + + test_daemon(); + test_waitsig(); + + for (i = 0; i < DATA_SIZE / BUF_SIZE; i++) { + if (read(p[0], buf, BUF_SIZE) != BUF_SIZE) { + pr_perror("read"); + return 1; + } + } + + pass(); + return 0; +} From 5a4c27a8e108c88c910a5c46bed7ff23835d15a7 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Dec 2017 00:05:50 +0300 Subject: [PATCH 1183/4375] pipe: dump all data from a pipe Currently we use an additional pipe to steal data from a pipe, but we don't check that we steal all data. And the additional pipe can have a smaller size. Signed-off-by: Andrei Vagin --- criu/pipes.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/criu/pipes.c b/criu/pipes.c index f1a66bf5d..8e781c998 100644 --- a/criu/pipes.c +++ b/criu/pipes.c @@ -168,6 +168,16 @@ int restore_pipe_data(int img_type, int pfd, u32 id, struct pipe_data_rst **hash return -1; } + if (pd->pde->has_size) { + pr_info("Restoring size %#x for %#x\n", + pd->pde->size, pd->pde->pipe_id); + ret = fcntl(pfd, F_SETPIPE_SZ, pd->pde->size); + if (ret < 0) { + pr_perror("Can't restore pipe size"); + goto err; + } + } + iov.iov_base = pd->data; iov.iov_len = pd->pde->bytes; @@ -203,15 +213,6 @@ int restore_pipe_data(int img_type, int pfd, u32 id, struct pipe_data_rst **hash pd->data = NULL; out: ret = 0; - if (pd->pde->has_size) { - pr_info("Restoring size %#x for %#x\n", - pd->pde->size, pd->pde->pipe_id); - ret = fcntl(pfd, F_SETPIPE_SZ, pd->pde->size); - if (ret < 0) - pr_perror("Can't restore pipe size"); - else - ret = 0; - } err: return ret; } @@ -442,6 +443,12 @@ int dump_one_pipe_data(struct pipe_data_dump *pd, int lfd, const struct fd_parms goto err; } + /* steal_pipe has to be able to fit all data from a target pipe */ + if (fcntl(steal_pipe[1], F_SETPIPE_SZ, pipe_size) < 0) { + pr_perror("Unable to set a pipe size"); + goto err; + } + bytes = tee(lfd, steal_pipe[1], pipe_size, SPLICE_F_NONBLOCK); if (bytes < 0) { if (errno != EAGAIN) { From 7470b163de6446c31996c6cb6bd191990cb6f1e2 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 30 Nov 2017 20:33:52 +0100 Subject: [PATCH 1184/4375] compel: add missing header required by musl This fix compilation issue regarding undeclared NULL and memcpy when using musl on ARM. Signed-off-by: Pierre-Olivier Mercier --- compel/arch/aarch64/src/lib/infect.c | 1 + compel/arch/arm/src/lib/infect.c | 1 + 2 files changed, 2 insertions(+) diff --git a/compel/arch/aarch64/src/lib/infect.c b/compel/arch/aarch64/src/lib/infect.c index 166ec2363..74e72ad39 100644 --- a/compel/arch/aarch64/src/lib/infect.c +++ b/compel/arch/aarch64/src/lib/infect.c @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/compel/arch/arm/src/lib/infect.c b/compel/arch/arm/src/lib/infect.c index 27d258bc3..c574d00e1 100644 --- a/compel/arch/arm/src/lib/infect.c +++ b/compel/arch/arm/src/lib/infect.c @@ -1,3 +1,4 @@ +#include #include #include #include From 1971cab9fc640fabda4dc81f1dba1305135a1507 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 30 Nov 2017 01:55:36 +0300 Subject: [PATCH 1185/4375] zdtm/tempfs_subns: sync children with the main process All static tests has to stop any activity before C/R. ./tempfs_subns --pidfile=tempfs_subns.pid --outfile=tempfs_subns.out --dirname=tempfs_subns.test Run criu dump Unable to kill 128: [Errno 3] No such process Run criu restore 7: Old mounts lost: [] 7: New mounts appeared: [('/rootfs/criu/test', '/'), ('/', '/proc'), ('/', '/dev/pts')] : Signed-off-by: Andrei Vagin --- test/zdtm/static/tempfs_subns.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/zdtm/static/tempfs_subns.c b/test/zdtm/static/tempfs_subns.c index 42195b57c..610f427d7 100644 --- a/test/zdtm/static/tempfs_subns.c +++ b/test/zdtm/static/tempfs_subns.c @@ -42,26 +42,26 @@ int main(int argc, char **argv) pid = fork(); if (pid == 0) { - if (write(fds[1], &fd, sizeof(fd)) != sizeof(fd)) { - pr_perror("write"); - return 1; - } if (unshare(CLONE_NEWNS)) { pr_perror("unshare"); return 1; } prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); + if (write(fds[1], &fd, sizeof(fd)) != sizeof(fd)) { + pr_perror("write"); + return 1; + } while (1) sleep(1); return 1; } pid = fork(); if (pid == 0) { + prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); if (write(fds[1], &fd, sizeof(fd)) != sizeof(fd)) { pr_perror("write"); return 1; } - prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); while (1) sleep(1); return 1; From b2494eae6144717a5b6a3c129ca12c91391910c8 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 5 Dec 2017 08:05:16 +0300 Subject: [PATCH 1186/4375] test/docker: check a continaer with a read-only file system Now it's probably one valide use case, because there is no way to commit a container when a container is being checkpointed. Signed-off-by: Andrei Vagin --- scripts/travis/docker-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/travis/docker-test.sh b/scripts/travis/docker-test.sh index 2fad42854..8ed02863b 100755 --- a/scripts/travis/docker-test.sh +++ b/scripts/travis/docker-test.sh @@ -40,7 +40,7 @@ docker info criu --version -docker run --security-opt=seccomp:unconfined --name cr -d alpine /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done' +docker run --tmpfs /tmp --tmpfs /run --read-only --security-opt=seccomp:unconfined --name cr -d alpine /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done' sleep 1 for i in `seq 50`; do From 49cd3eb2adac12d40129beac79f369dfa5a0dc4c Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Mon, 2 Oct 2017 23:48:17 +0300 Subject: [PATCH 1187/4375] locks: Add c/r of non broken leases (kernel>=v4.1) Leases in breaking state are not supported. In that case criu will report an error during the dumping. Also lock info in /proc//fdinfo should be presented (since kernel 4.1). Before taking out new lease it modifies process fsuid to match file uid (see fcntl F_SETLEASE). Signed-off-by: Pavel Begunkov Signed-off-by: Andrei Vagin --- criu/file-lock.c | 38 ++++++++++++++++++++++++++++++++++++++ criu/include/file-lock.h | 1 + criu/proc_parse.c | 5 +++++ 3 files changed, 44 insertions(+) diff --git a/criu/file-lock.c b/criu/file-lock.c index 821821f59..834594e4a 100644 --- a/criu/file-lock.c +++ b/criu/file-lock.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "cr_options.h" @@ -292,6 +293,9 @@ int note_file_lock(struct pid *pid, int fd, int lfd, struct fd_parms *p) */ if (fl->fl_owner != pid->real) continue; + } else if (fl->fl_kind == FL_LEASE) { + pr_err("Leases are not supported for kernel <= v4.0"); + return -1; } else /* fl->fl_kind == FL_FLOCK || fl->fl_kind == FL_OFD */ { int ret; @@ -329,6 +333,30 @@ int note_file_lock(struct pid *pid, int fd, int lfd, struct fd_parms *p) return 0; } +static int set_file_lease(int fd, int type) +{ + int old_fsuid, ret; + struct stat st; + + if (fstat(fd, &st)) { + pr_perror("Can't get file stat (%i)\n", fd); + return -1; + } + + /* + * An unprivileged process may take out a lease only if + * uid of the file matches the fsuid of the process. + */ + old_fsuid = setfsuid(st.st_uid); + + ret = fcntl(fd, F_SETLEASE, type); + if (ret < 0) + pr_perror("Can't set lease\n"); + + setfsuid(old_fsuid); + return ret; +} + static int restore_file_lock(FileLockEntry *fle) { int ret = -1; @@ -395,6 +423,16 @@ static int restore_file_lock(FileLockEntry *fle) pr_err("Can not set ofd lock!\n"); goto err; } + } else if (fle->flag & FL_LEASE) { + pr_info("(lease)flag: %d, type: %d, pid: %d, fd: %d, " + "start: %8"PRIx64", len: %8"PRIx64"\n", + fle->flag, fle->type, fle->pid, fle->fd, + fle->start, fle->len); + ret = set_file_lease(fle->fd, fle->type); + if (ret < 0) { + pr_perror("Can't set lease!\n"); + goto err; + } } else { pr_err("Unknown file lock style!\n"); goto err; diff --git a/criu/include/file-lock.h b/criu/include/file-lock.h index c3f2dabf7..f70739adb 100644 --- a/criu/include/file-lock.h +++ b/criu/include/file-lock.h @@ -10,6 +10,7 @@ #define FL_POSIX 1 #define FL_FLOCK 2 #define FL_OFD 4 +#define FL_LEASE 8 /* for posix fcntl() and lockf() */ #ifndef F_RDLCK diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 153618447..127b2ca97 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -2014,6 +2014,8 @@ static int parse_file_lock_buf(char *buf, struct file_lock *fl, fl->fl_kind = FL_FLOCK; else if (!strcmp(fl_flag, "OFDLCK")) fl->fl_kind = FL_OFD; + else if (!strcmp(fl_flag, "LEASE")) + fl->fl_kind = FL_LEASE; else fl->fl_kind = FL_UNKNOWN; @@ -2030,6 +2032,9 @@ static int parse_file_lock_buf(char *buf, struct file_lock *fl, pr_err("Unknown lock option!\n"); return -1; } + } else if (fl->fl_kind == FL_LEASE && !strcmp(fl_type, "BREAKING")) { + pr_err("Breaking leases are not supported (%d): %s\n", + num, buf); } else { if (!strcmp(fl_option, "UNLCK")) { fl->fl_ltype |= F_UNLCK; From 90fc8622e279c62c64fb0f2d6d111c8f84c8fb04 Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Mon, 2 Oct 2017 23:48:18 +0300 Subject: [PATCH 1188/4375] locks: Add c/r of breaking leases (kernel>=v4.1) restore of breaking leases is executed in 2 steps: 1. restore the lease in a state it was before break 2. break it by opening associated file. The patch fixes type of broken leases to 'target lease type', because procfs always returns 'READ' in this case. Also, it adds 'updated' field in lock structure. It's used to remove all duplicated records for single lease from the image, which wasn't corrected by 'correct_lease_type'. Signed-off-by: Pavel Begunkov Signed-off-by: Andrei Vagin --- criu/file-lock.c | 162 ++++++++++++++++++++++++++++++++++++++- criu/files.c | 3 + criu/include/file-lock.h | 6 ++ criu/proc_parse.c | 9 ++- 4 files changed, 173 insertions(+), 7 deletions(-) diff --git a/criu/file-lock.c b/criu/file-lock.c index 834594e4a..8ccebd033 100644 --- a/criu/file-lock.c +++ b/criu/file-lock.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -19,6 +20,8 @@ #include "proc_parse.h" #include "servicefd.h" #include "file-lock.h" +#include "pstree.h" +#include "files-reg.h" struct file_lock_rst { FileLockEntry *fle; @@ -103,6 +106,8 @@ int dump_file_locks(void) continue; } + if (fl->fl_kind == FL_LEASE && !fl->updated) + continue; file_lock_entry__init(&fle); fle.pid = fl->real_owner; @@ -333,6 +338,73 @@ int note_file_lock(struct pid *pid, int fd, int lfd, struct fd_parms *p) return 0; } +int correct_file_leases_type(struct pid *pid, int fd, int lfd) +{ + struct file_lock *fl; + int target_type; + + list_for_each_entry(fl, &file_lock_list, list) { + /* owners_fd should be set before usage */ + if (fl->fl_owner != pid->real || fl->owners_fd != fd) + continue; + + fl->updated = true; + if (fl->fl_kind == FL_LEASE && + (fl->fl_ltype & LEASE_BREAKING)) { + /* + * Set lease type to actual 'target lease type' + * instead of 'READ' returned by procfs. + */ + target_type = fcntl(lfd, F_GETLEASE); + if (target_type < 0) { + perror("Can't get lease type\n"); + return -1; + } + fl->fl_ltype &= ~O_ACCMODE; + fl->fl_ltype |= target_type; + break; + } + } + return 0; +} + +static int open_break_cb(int ns_root_fd, struct reg_file_info *rfi, void *arg) +{ + int fd, flags = *(int *)arg | O_NONBLOCK; + + fd = openat(ns_root_fd, rfi->path, flags); + if (fd >= 0) { + pr_err("Conflicting lease wasn't found\n"); + close(fd); + return -1; + } else if (errno != EWOULDBLOCK) { + pr_perror("Can't break lease\n"); + return -1; + } + return 0; +} + +static int break_lease(int lease_type, struct file_desc *desc) +{ + int target_type = lease_type & (~LEASE_BREAKING); + int break_flags; + + /* + * Flags for open call chosen in a way to even + * 'target lease type' returned by fcntl(F_GETLEASE) + * and lease type from the image. + */ + if (target_type == F_UNLCK) { + break_flags = O_WRONLY; + } else if (target_type == F_RDLCK) { + break_flags = O_RDONLY; + } else { + pr_err("Incorrect target lease type\n"); + return -1; + } + return open_path(desc, open_break_cb, (void *)&break_flags); +} + static int set_file_lease(int fd, int type) { int old_fsuid, ret; @@ -357,6 +429,90 @@ static int set_file_lease(int fd, int type) return ret; } +static int restore_lease_prebreaking_state(int fd, int fd_type) +{ + int access_flags = fd_type & O_ACCMODE; + int lease_type = (access_flags == O_RDONLY) ? F_RDLCK : F_WRLCK; + + return set_file_lease(fd, lease_type); +} + +static struct fdinfo_list_entry *find_fd_unordered(struct pstree_item *task, + int fd) +{ + struct list_head *head = &rsti(task)->fds; + struct fdinfo_list_entry *fle; + + list_for_each_entry_reverse(fle, head, ps_list) { + if (fle->fe->fd == fd) + return fle; + } + return NULL; +} + +static int restore_breaking_file_lease(FileLockEntry *fle) +{ + struct fdinfo_list_entry *fdle; + int ret; + + fdle = find_fd_unordered(current, fle->fd); + if (fdle == NULL) { + pr_err("Can't get file description\n"); + return -1; + } + + ret = restore_lease_prebreaking_state(fle->fd, fdle->desc->ops->type); + if (ret) + return ret; + + /* + * It could be broken by 2 types of open call: + * 1. non-blocking: It failed because of the lease. + * 2. blocking: It had been blocked at the moment + * of dumping, otherwise lease wouldn't be broken. + * Thus, it was canceled by CRIU. + * + * There are no files or leases in image, which will + * conflict with each other. Therefore we should explicitly + * break leases. Restoring can be done in any order. + */ + return break_lease(fle->type, fdle->desc); +} + +static int restore_file_lease(FileLockEntry *fle) +{ + sigset_t blockmask, oldmask; + int signum_fcntl, signum, ret; + + if (fle->type & LEASE_BREAKING) { + signum_fcntl = fcntl(fle->fd, F_GETSIG); + signum = signum_fcntl ? signum_fcntl : SIGIO; + if (signum_fcntl < 0) { + pr_perror("Can't get file i/o signum\n"); + return -1; + } + if (sigemptyset(&blockmask) || + sigaddset(&blockmask, signum) || + sigprocmask(SIG_BLOCK, &blockmask, &oldmask)) { + pr_perror("Can't block file i/o signal\n"); + return -1; + } + + ret = restore_breaking_file_lease(fle); + + if (sigprocmask(SIG_SETMASK, &oldmask, NULL)) { + pr_perror("Can't restore sigmask\n"); + ret = -1; + } + return ret; + } else { + ret = set_file_lease(fle->fd, fle->type); + if (ret < 0) + pr_perror("Can't restore non breaking lease"); + return ret; + } +} + static int restore_file_lock(FileLockEntry *fle) { int ret = -1; @@ -428,11 +584,9 @@ static int restore_file_lock(FileLockEntry *fle) "start: %8"PRIx64", len: %8"PRIx64"\n", fle->flag, fle->type, fle->pid, fle->fd, fle->start, fle->len); - ret = set_file_lease(fle->fd, fle->type); - if (ret < 0) { - pr_perror("Can't set lease!\n"); + ret = restore_file_lease(fle); + if (ret < 0) goto err; - } } else { pr_err("Unknown file lock style!\n"); goto err; diff --git a/criu/files.c b/criu/files.c index 7ac8a2e00..90dd1b0ec 100644 --- a/criu/files.c +++ b/criu/files.c @@ -474,6 +474,9 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, if (note_file_lock(pid, fd, lfd, &p)) return -1; + if (correct_file_leases_type(pid, fd, lfd)) + return -1; + p.fd_ctl = ctl; /* Some dump_opts require this to talk to parasite */ if (S_ISSOCK(p.stat.st_mode)) diff --git a/criu/include/file-lock.h b/criu/include/file-lock.h index f70739adb..14a33b436 100644 --- a/criu/include/file-lock.h +++ b/criu/include/file-lock.h @@ -38,6 +38,9 @@ #define LOCK_WRITE 128 /* which allows concurrent write operations */ #define LOCK_RW 192 /* which allows concurrent read & write ops */ +/* for leases */ +#define LEASE_BREAKING 4 + struct file_lock { long long fl_id; int fl_kind; @@ -53,6 +56,8 @@ struct file_lock { int real_owner; int owners_fd; + + bool updated; /* used to remove duplicate leases */ }; extern struct list_head file_lock_list; @@ -65,6 +70,7 @@ extern struct collect_image_info file_locks_cinfo; struct pid; struct fd_parms; +extern int correct_file_leases_type(struct pid *, int fd, int lfd); extern int note_file_lock(struct pid *, int fd, int lfd, struct fd_parms *); extern int dump_file_locks(void); diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 127b2ca97..9778ec49f 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -2008,6 +2008,8 @@ static int parse_file_lock_buf(char *buf, struct file_lock *fl, return -1; } + fl->updated = false; + if (!strcmp(fl_flag, "POSIX")) fl->fl_kind = FL_POSIX; else if (!strcmp(fl_flag, "FLOCK")) @@ -2019,6 +2021,10 @@ static int parse_file_lock_buf(char *buf, struct file_lock *fl, else fl->fl_kind = FL_UNKNOWN; + if (fl->fl_kind == FL_LEASE && !strcmp(fl_type, "BREAKING")) { + fl->fl_ltype |= LEASE_BREAKING; + } + if (!strcmp(fl_type, "MSNFS")) { fl->fl_ltype |= LOCK_MAND; @@ -2032,9 +2038,6 @@ static int parse_file_lock_buf(char *buf, struct file_lock *fl, pr_err("Unknown lock option!\n"); return -1; } - } else if (fl->fl_kind == FL_LEASE && !strcmp(fl_type, "BREAKING")) { - pr_err("Breaking leases are not supported (%d): %s\n", - num, buf); } else { if (!strcmp(fl_option, "UNLCK")) { fl->fl_ltype |= F_UNLCK; From 8038462d2d2488af2b687fa760df07cef033575d Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Mon, 2 Oct 2017 23:48:19 +0300 Subject: [PATCH 1189/4375] locks: Add leases c/r for kernels v4.0 and older Information about locks in /proc//fdinfo is presented only since kernel v4.1. This patch adds logic to *note_file_lock* to match leases and OFDs. Signed-off-by: Pavel Begunkov Signed-off-by: Andrei Vagin --- criu/file-lock.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/criu/file-lock.c b/criu/file-lock.c index 8ccebd033..b7adc0979 100644 --- a/criu/file-lock.c +++ b/criu/file-lock.c @@ -270,6 +270,80 @@ static int lock_ofd_check_fd(int lfd, struct file_lock *fl) return 1; } +static int lease_check_fd(int fd, int file_flags, struct file_lock *fl) +{ + int file_lease_type, err; + int lease_type = fl->fl_ltype & (~LEASE_BREAKING); + + if ((file_flags & O_ACCMODE) != O_RDONLY) { + /* + * Write OFD conflicts with any lease not associated + * with it, therefore there is can't be other lease + * or OFD for this file. + */ + return 1; + } + + file_lease_type = fcntl(fd, F_GETLEASE); + if (file_lease_type < 0) { + pr_err("Can't get lease type\n"); + return -1; + } + + /* + * Only read OFDs can be present for the file. If + * read and write OFDs with at least one lease had + * presented, it would have conflicted. + */ + if (fl->fl_ltype & LEASE_BREAKING) { + /* + * Only read leases are possible for read OFDs + * and they all should be in breaking state, + * because the current one is. + */ + int compatible_type = file_lease_type; + + if (compatible_type != F_UNLCK) { + pr_err("Lease doesn't conflicts but breaks\n"); + return -1; + } + /* + * Due to activated breaking sequence we can't + * get actual lease type with F_GETLEASE. + * The err == 0 after lease upgrade means, that + * there is already read lease on OFD. Otherwise + * it would fail, because current read lease is + * still set and breaking. + */ + err = fcntl(fd, F_SETLEASE, F_RDLCK); + if (err < 0) { + if (errno != EAGAIN) { + pr_perror("Can't set lease (fd %i)", fd); + return -1; + } + return 0; + } + return 1; + } else { + /* + * The file can have only non-breaking read + * leases, because otherwise the current one + * also would have broke. + */ + if (lease_type != F_RDLCK) { + pr_err("Incorrect lease type\n"); + return -1; + } + + if (file_lease_type == F_UNLCK) + return 0; + if (file_lease_type == F_RDLCK) + return 1; + pr_err("Invalid file lease type\n"); + return -1; + } +} + int note_file_lock(struct pid *pid, int fd, int lfd, struct fd_parms *p) { struct file_lock *fl; @@ -299,8 +373,17 @@ int note_file_lock(struct pid *pid, int fd, int lfd, struct fd_parms *p) if (fl->fl_owner != pid->real) continue; } else if (fl->fl_kind == FL_LEASE) { - pr_err("Leases are not supported for kernel <= v4.0"); - return -1; + if (fl->owners_fd >= 0) + continue; + if (fl->fl_owner != pid->real && + fl->real_owner != -1) + continue; + + ret = lease_check_fd(lfd, p->flags, fl); + if (ret < 0) + return ret; + if (ret == 0) + continue; } else /* fl->fl_kind == FL_FLOCK || fl->fl_kind == FL_OFD */ { int ret; From 0781cb3320a9d124b25174e57284041b9ecbb9e7 Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Mon, 2 Oct 2017 23:48:20 +0300 Subject: [PATCH 1190/4375] zdtm: Add file lease tests Test cases: 0. Basic non-breaking read/write leases. 1. Multiple read leases and OFDs with no lease for the same file. 2. Breaking leases. 3. Multiple fds (dup + inherited) for single lease (mutual OFD). Signed-off-by: Pavel Begunkov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 4 + test/zdtm/static/file_lease00.c | 84 +++++++++++++++++ test/zdtm/static/file_lease00.desc | 1 + test/zdtm/static/file_lease01.c | 88 +++++++++++++++++ test/zdtm/static/file_lease01.desc | 1 + test/zdtm/static/file_lease02.c | 145 +++++++++++++++++++++++++++++ test/zdtm/static/file_lease02.desc | 1 + test/zdtm/static/file_lease03.c | 145 +++++++++++++++++++++++++++++ test/zdtm/static/file_lease03.desc | 1 + 9 files changed, 470 insertions(+) create mode 100644 test/zdtm/static/file_lease00.c create mode 100644 test/zdtm/static/file_lease00.desc create mode 100644 test/zdtm/static/file_lease01.c create mode 120000 test/zdtm/static/file_lease01.desc create mode 100644 test/zdtm/static/file_lease02.c create mode 120000 test/zdtm/static/file_lease02.desc create mode 100644 test/zdtm/static/file_lease03.c create mode 120000 test/zdtm/static/file_lease03.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index fd5905e48..4c452900b 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -249,6 +249,10 @@ TST_FILE = \ sockets00 \ sockets03 \ sockets_dgram \ + file_lease00 \ + file_lease01 \ + file_lease02 \ + file_lease03 \ file_locks00 \ file_locks01 \ file_locks02 \ diff --git a/test/zdtm/static/file_lease00.c b/test/zdtm/static/file_lease00.c new file mode 100644 index 000000000..8413f831b --- /dev/null +++ b/test/zdtm/static/file_lease00.c @@ -0,0 +1,84 @@ +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check c/r of non-breaking leases"; +const char *test_author = "Pavel Begunkov "; + +char *filename; +TEST_OPTION(filename, string, "file name", 1); +char filename_rd[PATH_MAX]; +char filename_wr[PATH_MAX]; + +static void close_files(int fd1, int fd2) +{ + if (fd1 >= 0) + close(fd1); + if (fd2 >= 0) + close(fd2); + + unlink(filename_rd); + unlink(filename_wr); +} + +static int open_files(int *fd_rd, int *fd_wr) +{ + *fd_rd = open(filename_rd, O_RDONLY | O_CREAT, 0666); + *fd_wr = open(filename_wr, O_WRONLY | O_CREAT, 0666); + + if (*fd_rd < 0 || *fd_wr < 0) { + close_files(*fd_rd, *fd_wr); + return -1; + } + return 0; +} + +static int check_lease_type(int fd, int expected_type) +{ + int lease_type = fcntl(fd, F_GETLEASE); + + if (lease_type != expected_type) { + if (lease_type < 0) + pr_perror("Can't acquire lease type\n"); + else + pr_err("Mismatched lease type: %i\n", lease_type); + return -1; + } + return 0; +} + +int main(int argc, char **argv) +{ + int fd_rd = -1, fd_wr = -1; + + test_init(argc, argv); + + snprintf(filename_rd, sizeof(filename_rd), "%s.0", filename); + snprintf(filename_wr, sizeof(filename_wr), "%s.1", filename); + + if (open_files(&fd_rd, &fd_wr)) { + pr_err("Can't open files\n"); + return -1; + } + if (fcntl(fd_rd, F_SETLEASE, F_RDLCK) < 0 || + fcntl(fd_wr, F_SETLEASE, F_WRLCK) < 0) { + pr_perror("Can't set leases\n"); + close_files(fd_rd, fd_wr); + return -1; + } + + test_daemon(); + test_waitsig(); + + if (check_lease_type(fd_rd, F_RDLCK)) + fail("Read lease check failed\n"); + else if (check_lease_type(fd_wr, F_WRLCK)) + fail("Write lease check failed\n"); + else + pass(); + + close_files(fd_rd, fd_wr); + return 0; +} diff --git a/test/zdtm/static/file_lease00.desc b/test/zdtm/static/file_lease00.desc new file mode 100644 index 000000000..f394d0330 --- /dev/null +++ b/test/zdtm/static/file_lease00.desc @@ -0,0 +1 @@ +{'feature': 'fdinfo_lock', 'opts': '--file-locks'} diff --git a/test/zdtm/static/file_lease01.c b/test/zdtm/static/file_lease01.c new file mode 100644 index 000000000..90fa74a1c --- /dev/null +++ b/test/zdtm/static/file_lease01.c @@ -0,0 +1,88 @@ +#include +#include + +#include "zdtmtst.h" + +#define FD_COUNT 3 +#define FD_LEASED1 0 +#define FD_LEASED2 2 +#define FD_LEASE_FREE 1 + +const char *test_doc = "Check that extra leases are not set after c/r"; +const char *test_author = "Pavel Begunkov "; + +char *filename; +TEST_OPTION(filename, string, "file name", 1); + +static void close_files(int fds[FD_COUNT]) +{ + int i; + + for (i = 0; i < FD_COUNT; ++i) + if (fds[i] >= 0) + close(fds[i]); + unlink(filename); +} + +static int open_files(int fds[FD_COUNT]) +{ + int i; + + for (i = 0; i < FD_COUNT; ++i) { + fds[i] = open(filename, O_RDONLY | O_CREAT, 0666); + if (fds[i] < 0) { + close_files(fds); + return -1; + } + } + return 0; +} + +static int check_lease_type(int fd, int expected_type) +{ + int lease_type = fcntl(fd, F_GETLEASE); + + if (lease_type != expected_type) { + if (lease_type < 0) + pr_perror("Can't acquire lease type\n"); + else + pr_err("Mismatched lease type: %i\n", lease_type); + return -1; + } + return 0; +} + +int main(int argc, char **argv) +{ + int fds[FD_COUNT]; + + test_init(argc, argv); + + if (open_files(fds)) { + pr_err("Can't open files\n"); + return -1; + } + + if (fcntl(fds[FD_LEASED1], F_SETLEASE, F_RDLCK) < 0 || + fcntl(fds[FD_LEASED2], F_SETLEASE, F_RDLCK) < 0) { + pr_err("Can't set leases\n"); + close_files(fds); + return -1; + } + + test_daemon(); + test_waitsig(); + + if (check_lease_type(fds[FD_LEASE_FREE], F_UNLCK)) + fail("Unexpected lease was found (%i)\n", fds[FD_LEASE_FREE]); + else if (check_lease_type(fds[FD_LEASED1], F_RDLCK)) + fail("Lease isn't set (%i)\n", fds[FD_LEASED1]); + else if (check_lease_type(fds[FD_LEASED2], F_RDLCK)) + fail("Lease isn't set (%i)\n", fds[FD_LEASED2]); + else + pass(); + + close_files(fds); + return 0; +} + diff --git a/test/zdtm/static/file_lease01.desc b/test/zdtm/static/file_lease01.desc new file mode 120000 index 000000000..fba66d322 --- /dev/null +++ b/test/zdtm/static/file_lease01.desc @@ -0,0 +1 @@ +file_lease00.desc \ No newline at end of file diff --git a/test/zdtm/static/file_lease02.c b/test/zdtm/static/file_lease02.c new file mode 100644 index 000000000..cd7945d31 --- /dev/null +++ b/test/zdtm/static/file_lease02.c @@ -0,0 +1,145 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" + +#define FD_COUNT 3 +#define BREAK_SIGNUM SIGIO + +const char *test_doc = "Check c/r of breaking leases"; +const char *test_author = "Pavel Begunkov "; + +char *filename; +TEST_OPTION(filename, string, "file name", 1); + +char filename1[PATH_MAX]; +char filename2[PATH_MAX]; +char filename3[PATH_MAX]; + +int expected_fd; +int sigaction_error; + +static void break_sigaction(int signo, siginfo_t *info, void *ctx) +{ + if (signo != BREAK_SIGNUM) { + pr_err("Unexpected signal(%i)\n", signo); + sigaction_error = -1; + } else if (info->si_fd != expected_fd) { + pr_err("Unexpected fd(%i)\n", info->si_fd); + sigaction_error = -1; + } + expected_fd = -1; +} + +static int check_lease_type(int fd, int expected_type) +{ + int lease_type = fcntl(fd, F_GETLEASE); + + if (lease_type != expected_type) { + if (lease_type < 0) + pr_perror("Can't acquire lease type\n"); + else + pr_err("Mismatched lease type: %i\n", lease_type); + return -1; + } + return 0; +} + +static int prepare_file(char *file, int file_type, int break_type) +{ + int fd, fd_break; + int lease_type = (file_type == O_RDONLY) ? F_RDLCK : F_WRLCK; + + fd = open(file, file_type | O_CREAT, 0666); + if (fd < 0) { + pr_perror("Can't open file (type %i)\n", file_type); + return fd; + } + if (fcntl(fd, F_SETLEASE, lease_type) < 0) { + pr_perror("Can't set exclusive lease\n"); + goto err; + } + if (fcntl(fd, F_SETSIG, BREAK_SIGNUM) < 0) { + pr_perror("Can't set signum for file i/o\n"); + goto err; + } + + expected_fd = fd; + fd_break = open(file, break_type | O_NONBLOCK); + + if (fd_break >= 0) { + close(fd_break); + pr_err("Conflicting lease not found\n"); + goto err; + } else if (errno != EWOULDBLOCK) { + pr_perror("Can't break lease\n"); + goto err; + } + return fd; +err: + close(fd); + return -1; +} + +static void close_files(int fds[FD_COUNT]) +{ + int i; + + for (i = 0; i < FD_COUNT; ++i) + if (fds[i] >= 0) + close(fds[i]); + + unlink(filename1); + unlink(filename2); + unlink(filename3); +} + +int main(int argc, char **argv) +{ + int fds[FD_COUNT] = {}; + int ret = -1; + struct sigaction act = {}; + + test_init(argc, argv); + + snprintf(filename1, sizeof(filename1), "%s.0", filename); + snprintf(filename2, sizeof(filename2), "%s.1", filename); + snprintf(filename3, sizeof(filename3), "%s.2", filename); + + act.sa_sigaction = break_sigaction; + act.sa_flags = SA_SIGINFO; + + if (sigemptyset(&act.sa_mask) || + sigaddset(&act.sa_mask, BREAK_SIGNUM) || + sigaction(BREAK_SIGNUM, &act, NULL)) { + pr_perror("Can't set signal action\n"); + fail(); + return -1; + } + + sigaction_error = 0; + fds[0] = prepare_file(filename1, O_RDONLY, O_WRONLY); + fds[1] = prepare_file(filename2, O_WRONLY, O_RDONLY); + fds[2] = prepare_file(filename3, O_WRONLY, O_WRONLY); + if (fds[0] < 0 || fds[1] < 0 || fds[2] < 0 || sigaction_error) + goto done; + + test_daemon(); + test_waitsig(); + + ret = 0; + if (sigaction_error) + fail("Ghost signal\n"); + else if (check_lease_type(fds[0], F_UNLCK) || + check_lease_type(fds[1], F_RDLCK) || + check_lease_type(fds[2], F_UNLCK)) + fail("Lease type doesn't match\n"); + else + pass(); +done: + close_files(fds); + return ret; +} + diff --git a/test/zdtm/static/file_lease02.desc b/test/zdtm/static/file_lease02.desc new file mode 120000 index 000000000..fba66d322 --- /dev/null +++ b/test/zdtm/static/file_lease02.desc @@ -0,0 +1 @@ +file_lease00.desc \ No newline at end of file diff --git a/test/zdtm/static/file_lease03.c b/test/zdtm/static/file_lease03.c new file mode 100644 index 000000000..fcdcce137 --- /dev/null +++ b/test/zdtm/static/file_lease03.c @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +#define BREAK_SIGNUM SIGIO + +const char *test_doc = "Check multiple fds on OFD with breaking leases"; +const char *test_author = "Pavel Begunkov "; + +char *filename; +TEST_OPTION(filename, string, "file name", 1); + +int expected_fd; +int sigaction_error; + +static void break_sigaction(int signo, siginfo_t *info, void *ctx) +{ + if (signo != BREAK_SIGNUM) { + pr_err("Unexpected signal(%i)\n", signo); + sigaction_error = -1; + } else if (info->si_fd != expected_fd) { + pr_err("Unexpected fd(%i)\n", info->si_fd); + sigaction_error = -1; + } + expected_fd = -1; +} + +static int check_lease_type(int fd, int expected_type) +{ + int lease_type = fcntl(fd, F_GETLEASE); + + if (lease_type != expected_type) { + if (lease_type < 0) + pr_perror("Can't acquire lease type\n"); + else + pr_err("Mismatched lease type: %i\n", lease_type); + return -1; + } + return 0; +} + +static int prepare_file(char *file, int file_type, int break_type) +{ + int fd, fd_break; + int lease_type = (file_type == O_RDONLY) ? F_RDLCK : F_WRLCK; + + fd = open(file, file_type | O_CREAT, 0666); + if (fd < 0) { + pr_perror("Can't open file (type %i)\n", file_type); + return fd; + } + if (fcntl(fd, F_SETLEASE, lease_type) < 0) { + pr_perror("Can't set exclusive lease\n"); + goto err; + } + if (fcntl(fd, F_SETSIG, BREAK_SIGNUM) < 0) { + pr_perror("Can't set signum for file i/o\n"); + goto err; + } + + expected_fd = fd; + fd_break = open(file, break_type | O_NONBLOCK); + + if (fd_break >= 0) { + close(fd_break); + pr_err("Conflicting lease not found\n"); + goto err; + } else if (errno != EWOULDBLOCK) { + pr_perror("Can't break lease\n"); + goto err; + } + return fd; +err: + close(fd); + return -1; +} + +int main(int argc, char **argv) +{ + int fd = -1, fd_dup = -1; + int ret = -1; + struct sigaction act = {}; + int pid; + + test_init(argc, argv); + + act.sa_sigaction = break_sigaction; + act.sa_flags = SA_SIGINFO; + if (sigemptyset(&act.sa_mask) || + sigaddset(&act.sa_mask, BREAK_SIGNUM) || + sigaction(BREAK_SIGNUM, &act, NULL)) { + pr_perror("Can't set signal action\n"); + return -1; + } + + sigaction_error = 0; + fd = prepare_file(filename, O_RDWR, O_WRONLY); + if (fd < 0 || sigaction_error) + goto done; + + pid = fork(); + if (pid < 0) + return 1; + if (pid == 0) { + test_waitsig(); + if (check_lease_type(fd, F_UNLCK)) + return 1; + close(fd); + return 0; + } + + ret = fd_dup = dup(fd); + if (fd_dup < 0) { + pr_perror("Can't dup fd\n"); + goto done; + } + + ret = 0; + + test_daemon(); + test_waitsig(); + + kill(pid, SIGTERM); + waitpid(pid, NULL, 0); + + if (sigaction_error) + fail("Ghost signal\n"); + else if (check_lease_type(fd, F_UNLCK)) + fail("Lease type doesn't match\n"); + else + pass(); + +done: + if (fd >= 0) + close(fd); + if (fd_dup >= 0) + close(fd_dup); + unlink(filename); + return ret; +} + diff --git a/test/zdtm/static/file_lease03.desc b/test/zdtm/static/file_lease03.desc new file mode 120000 index 000000000..fba66d322 --- /dev/null +++ b/test/zdtm/static/file_lease03.desc @@ -0,0 +1 @@ +file_lease00.desc \ No newline at end of file From 6c86fcb5a7ab4706e625ede5fcfe39295066dd56 Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Tue, 21 Nov 2017 05:54:55 +0300 Subject: [PATCH 1191/4375] locks: Remove duplicated locks CRIU creates dictinct lock record for each file descriptor on the same OFD. The patch removes this duplicates. To do so, it adds new field into struct file_lock, which stores pid of fd, on which lock was found. 'owner pid' is not actually helpful, because the original fd, on which lock have been set, can be already closed. Also it purges crutches doing the same stuff but only for file leases. Signed-off-by: Pavel Begunkov Signed-off-by: Andrei Vagin --- criu/file-lock.c | 20 ++++++++++++++++---- criu/files.c | 3 +++ criu/include/file-lock.h | 6 +++--- criu/proc_parse.c | 3 +-- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/criu/file-lock.c b/criu/file-lock.c index b7adc0979..8be7589df 100644 --- a/criu/file-lock.c +++ b/criu/file-lock.c @@ -58,6 +58,7 @@ struct file_lock *alloc_file_lock(void) INIT_LIST_HEAD(&flock->list); flock->real_owner = -1; flock->owners_fd = -1; + flock->fl_holder = -1; return flock; } @@ -106,8 +107,6 @@ int dump_file_locks(void) continue; } - if (fl->fl_kind == FL_LEASE && !fl->updated) - continue; file_lock_entry__init(&fle); fle.pid = fl->real_owner; @@ -410,6 +409,7 @@ int note_file_lock(struct pid *pid, int fd, int lfd, struct fd_parms *p) continue; } + fl->fl_holder = pid->real; fl->real_owner = pid->ns[0].virt; fl->owners_fd = fd; @@ -421,6 +421,19 @@ int note_file_lock(struct pid *pid, int fd, int lfd, struct fd_parms *p) return 0; } +void discard_dup_locks_tail(pid_t pid, int fd) +{ + struct file_lock *fl, *p; + + list_for_each_entry_safe_reverse(fl, p, &file_lock_list, list) { + if (fl->owners_fd != fd || pid != fl->fl_holder) + break; + + list_del(&fl->list); + xfree(fl); + } +} + int correct_file_leases_type(struct pid *pid, int fd, int lfd) { struct file_lock *fl; @@ -428,10 +441,9 @@ int correct_file_leases_type(struct pid *pid, int fd, int lfd) list_for_each_entry(fl, &file_lock_list, list) { /* owners_fd should be set before usage */ - if (fl->fl_owner != pid->real || fl->owners_fd != fd) + if (fl->fl_holder != pid->real || fl->owners_fd != fd) continue; - fl->updated = true; if (fl->fl_kind == FL_LEASE && (fl->fl_ltype & LEASE_BREAKING)) { /* diff --git a/criu/files.c b/criu/files.c index 90dd1b0ec..16b510608 100644 --- a/criu/files.c +++ b/criu/files.c @@ -309,6 +309,9 @@ int do_dump_gen_file(struct fd_parms *p, int lfd, ret = fd_id_generate(p->pid, e, p); if (ret == 1) /* new ID generated */ ret = ops->dump(lfd, e->id, p); + else + /* Remove locks generated by the fd before going to the next */ + discard_dup_locks_tail(p->pid, e->fd); return ret; } diff --git a/criu/include/file-lock.h b/criu/include/file-lock.h index 14a33b436..dc4f38216 100644 --- a/criu/include/file-lock.h +++ b/criu/include/file-lock.h @@ -46,7 +46,8 @@ struct file_lock { int fl_kind; int fl_ltype; - pid_t fl_owner; + pid_t fl_owner; /* process, which created the lock */ + pid_t fl_holder; /* pid of fd on whose the lock is found */ int maj, min; unsigned long i_no; long long start; @@ -56,8 +57,6 @@ struct file_lock { int real_owner; int owners_fd; - - bool updated; /* used to remove duplicate leases */ }; extern struct list_head file_lock_list; @@ -70,6 +69,7 @@ extern struct collect_image_info file_locks_cinfo; struct pid; struct fd_parms; +extern void discard_dup_locks_tail(pid_t pid, int fd); extern int correct_file_leases_type(struct pid *, int fd, int lfd); extern int note_file_lock(struct pid *, int fd, int lfd, struct fd_parms *); extern int dump_file_locks(void); diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 9778ec49f..e63dee085 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1715,6 +1715,7 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, void *arg) } fl->real_owner = fdinfo->owner; + fl->fl_holder = pid; fl->owners_fd = fd; list_add_tail(&fl->list, &file_lock_list); } @@ -2008,8 +2009,6 @@ static int parse_file_lock_buf(char *buf, struct file_lock *fl, return -1; } - fl->updated = false; - if (!strcmp(fl_flag, "POSIX")) fl->fl_kind = FL_POSIX; else if (!strcmp(fl_flag, "FLOCK")) From 8835e6973efeca876761c39dd7a1b5082e063673 Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Tue, 21 Nov 2017 05:54:56 +0300 Subject: [PATCH 1192/4375] zdtm: Test inherited file leases -- check childs' errors in file_leases03 -- test c/r of lease transfered to child process Signed-off-by: Pavel Begunkov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/file_lease03.c | 9 +- test/zdtm/static/file_lease04.c | 132 +++++++++++++++++++++++++++++ test/zdtm/static/file_lease04.desc | 1 + 4 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 test/zdtm/static/file_lease04.c create mode 120000 test/zdtm/static/file_lease04.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 4c452900b..cd327ab0e 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -253,6 +253,7 @@ TST_FILE = \ file_lease01 \ file_lease02 \ file_lease03 \ + file_lease04 \ file_locks00 \ file_locks01 \ file_locks02 \ diff --git a/test/zdtm/static/file_lease03.c b/test/zdtm/static/file_lease03.c index fcdcce137..4cde2b655 100644 --- a/test/zdtm/static/file_lease03.c +++ b/test/zdtm/static/file_lease03.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include "zdtmtst.h" @@ -82,9 +81,9 @@ err: int main(int argc, char **argv) { int fd = -1, fd_dup = -1; - int ret = -1; + int status, ret = -1; struct sigaction act = {}; - int pid; + pid_t pid; test_init(argc, argv); @@ -125,8 +124,10 @@ int main(int argc, char **argv) test_waitsig(); kill(pid, SIGTERM); - waitpid(pid, NULL, 0); + ret = waitpid(pid, &status, 0); + if (ret < 0 || !WIFEXITED(status) || WEXITSTATUS(status)) + fail(); if (sigaction_error) fail("Ghost signal\n"); else if (check_lease_type(fd, F_UNLCK)) diff --git a/test/zdtm/static/file_lease04.c b/test/zdtm/static/file_lease04.c new file mode 100644 index 000000000..c924f6c5d --- /dev/null +++ b/test/zdtm/static/file_lease04.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" + +#define BREAK_SIGNUM SIGIO + +const char *test_doc = "Check leases with no fds in owner process"; +const char *test_author = "Pavel Begunkov "; + +char *filename; +TEST_OPTION(filename, string, "file name", 1); + +int expected_fd; +int sigaction_error; + +static void break_sigaction(int signo, siginfo_t *info, void *ctx) +{ + if (signo != BREAK_SIGNUM) { + pr_err("Unexpected signal(%i)\n", signo); + sigaction_error = -1; + } else if (info->si_fd != expected_fd) { + pr_err("Unexpected fd(%i)\n", info->si_fd); + sigaction_error = -1; + } + expected_fd = -1; +} + +static int check_lease_type(int fd, int expected_type) +{ + int lease_type = fcntl(fd, F_GETLEASE); + + if (lease_type != expected_type) { + if (lease_type < 0) + pr_perror("Can't acquire lease type\n"); + else + pr_err("Mismatched lease type: %i\n", lease_type); + return -1; + } + return 0; +} + +static int prepare_file(char *file, int file_type, int break_type) +{ + int fd, fd_break; + int lease_type = (file_type == O_RDONLY) ? F_RDLCK : F_WRLCK; + + fd = open(file, file_type | O_CREAT, 0666); + if (fd < 0) { + pr_perror("Can't open file (type %i)\n", file_type); + return fd; + } + if (fcntl(fd, F_SETLEASE, lease_type) < 0) { + pr_perror("Can't set exclusive lease\n"); + goto err; + } + if (fcntl(fd, F_SETSIG, BREAK_SIGNUM) < 0) { + pr_perror("Can't set signum for file i/o\n"); + goto err; + } + + expected_fd = fd; + fd_break = open(file, break_type | O_NONBLOCK); + + if (fd_break >= 0) { + close(fd_break); + pr_err("Conflicting lease not found\n"); + goto err; + } else if (errno != EWOULDBLOCK) { + pr_perror("Can't break lease\n"); + goto err; + } + return fd; +err: + close(fd); + return -1; +} + +int main(int argc, char **argv) +{ + int fd = -1; + int status, ret = -1; + struct sigaction act = {}; + pid_t pid; + + test_init(argc, argv); + + act.sa_sigaction = break_sigaction; + act.sa_flags = SA_SIGINFO; + if (sigemptyset(&act.sa_mask) || + sigaddset(&act.sa_mask, BREAK_SIGNUM) || + sigaction(BREAK_SIGNUM, &act, NULL)) { + pr_perror("Can't set signal action\n"); + return -1; + } + + sigaction_error = 0; + fd = prepare_file(filename, O_RDWR, O_WRONLY); + if (fd < 0 || sigaction_error) + goto done; + + pid = fork(); + if (pid < 0) + return 1; + if (pid == 0) { + test_waitsig(); + if (check_lease_type(fd, F_UNLCK)) + return 1; + close(fd); + return 0; + } + close(fd); + + test_daemon(); + test_waitsig(); + + kill(pid, SIGTERM); + ret = waitpid(pid, &status, 0); + + if (ret < 0 || !WIFEXITED(status) || WEXITSTATUS(status)) + fail(); + else if (sigaction_error) + fail("Ghost signal\n"); + else + pass(); +done: + unlink(filename); + return ret; +} + diff --git a/test/zdtm/static/file_lease04.desc b/test/zdtm/static/file_lease04.desc new file mode 120000 index 000000000..fba66d322 --- /dev/null +++ b/test/zdtm/static/file_lease04.desc @@ -0,0 +1 @@ +file_lease00.desc \ No newline at end of file From 2d7abe53fc6fc0a7bbce85178490a870964108fb Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Tue, 21 Nov 2017 06:00:33 +0300 Subject: [PATCH 1193/4375] locks: skip 'lease correction' for non-regular files Leases can be set only on regular files. Thus, as optimization we can skip attempts to find associated leases in 'correct_file_leases_type' for other fd types. Signed-off-by: Pavel Begunkov Signed-off-by: Andrei Vagin --- criu/files.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/criu/files.c b/criu/files.c index 16b510608..0cbd85951 100644 --- a/criu/files.c +++ b/criu/files.c @@ -477,8 +477,13 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, if (note_file_lock(pid, fd, lfd, &p)) return -1; - if (correct_file_leases_type(pid, fd, lfd)) - return -1; + /* Lease can be set only on regular file */ + if (S_ISREG(p.stat.st_mode)) { + int ret = correct_file_leases_type(pid, fd, lfd); + + if (ret < 0) + return ret; + } p.fd_ctl = ctl; /* Some dump_opts require this to talk to parasite */ From 8bc39c78d8329bdeb3aa33c42a5e1aefce984221 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 7 Dec 2017 12:52:49 +0300 Subject: [PATCH 1194/4375] pr_err: add \n where we miss them Except for several false positives done by: find -type f -name "*.c" -not -path "./test/*" -exec sed -i 's/\(\ Signed-off-by: Andrei Vagin --- compel/arch/s390/src/lib/cpu.c | 2 +- criu/arch/s390/cpu.c | 2 +- criu/arch/x86/crtools.c | 4 ++-- criu/page-xfer.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compel/arch/s390/src/lib/cpu.c b/compel/arch/s390/src/lib/cpu.c index 174575f93..b5c066c90 100644 --- a/compel/arch/s390/src/lib/cpu.c +++ b/compel/arch/s390/src/lib/cpu.c @@ -25,7 +25,7 @@ int compel_cpuid(compel_cpuinfo_t *info) info->hwcap[1] = getauxval(AT_HWCAP2); if (!info->hwcap[0]) { - pr_err("Can't read the hardware capabilities"); + pr_err("Can't read the hardware capabilities\n"); return -1; } diff --git a/criu/arch/s390/cpu.c b/criu/arch/s390/cpu.c index 0c32de5ab..f93666ed6 100644 --- a/criu/arch/s390/cpu.c +++ b/criu/arch/s390/cpu.c @@ -103,7 +103,7 @@ int cpu_validate_cpuinfo(void) goto error; if (cpu_info->n_s390_entry != 1) { - pr_err("No S390 related entry in image"); + pr_err("No S390 related entry in image\n"); goto error; } cpu_s390_entry = cpu_info->s390_entry[0]; diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index af5a315ad..69de23b44 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -59,7 +59,7 @@ int kdat_can_map_vdso(void) } if (waitpid(child, &stat, 0) != child) { - pr_err("Failed to wait for arch_prctl() test"); + pr_err("Failed to wait for arch_prctl() test\n"); kill(child, SIGKILL); return -1; } @@ -154,7 +154,7 @@ static int has_32bit_mmap_bug(void) mmap_bug_test(); if (waitpid(child, &stat, 0) != child) { - pr_err("Failed to wait for mmap test"); + pr_err("Failed to wait for mmap test\n"); kill(child, SIGKILL); return -1; } diff --git a/criu/page-xfer.c b/criu/page-xfer.c index df6d35e0c..853f3ee53 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -222,7 +222,7 @@ static int write_pages_loc(struct page_xfer *xfer, return -1; } if (ret == 0) { - pr_err("A pipe was closed unexpectedly"); + pr_err("A pipe was closed unexpectedly\n"); return -1; } curr += ret; @@ -682,7 +682,7 @@ static int page_server_add(int sk, struct page_server_iov *pi, u32 flags) return -1; } if (chunk == 0) { - pr_err("A socket was closed unexpectedly"); + pr_err("A socket was closed unexpectedly\n"); return -1; } From 53211331e0dc756ace9e0d1c701bcca278914655 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 4 Dec 2017 22:41:10 +0300 Subject: [PATCH 1195/4375] sk-inet: detect corked sockets by getting a proper sock opt Now we block all sockets with non-zero idiag_wqueue, but it doesn't mean that a CORK option is enabled for a socket. A packet can be in a network stack and it is accounted into idiag_wqueue. https://github.com/checkpoint-restore/criu/issues/409 Signed-off-by: Andrei Vagin --- criu/include/sk-inet.h | 1 + criu/sk-inet.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/criu/include/sk-inet.h b/criu/include/sk-inet.h index 3b302ff70..180f48e35 100644 --- a/criu/include/sk-inet.h +++ b/criu/include/sk-inet.h @@ -28,6 +28,7 @@ struct inet_sk_desc { unsigned int src_addr[4]; unsigned int dst_addr[4]; unsigned short shutdown; + bool cork; int rfd; int cpt_reuseaddr; diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 06275c922..115bd4579 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -123,9 +124,14 @@ static int can_dump_inet_sk(const struct inet_sk_desc *sk) if (sk->type == SOCK_DGRAM) { if (sk->wqlen != 0) { - pr_err("Can't dump corked dgram socket %x\n", + if (sk->cork) { + pr_err("Can't dump corked dgram socket %x\n", sk->sd.ino); - return 0; + return 0; + } else { + pr_warn("Write queue of the %x socket isn't empty\n", + sk->sd.ino); + } } if (sk->rqlen) @@ -317,7 +323,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa InetSkEntry ie = INET_SK_ENTRY__INIT; IpOptsEntry ipopts = IP_OPTS_ENTRY__INIT; SkOptsEntry skopts = SK_OPTS_ENTRY__INIT; - int ret = -1, err = -1, proto; + int ret = -1, err = -1, proto, aux; ret = do_dump_opt(lfd, SOL_SOCKET, SO_PROTOCOL, &proto, sizeof(proto)); @@ -336,6 +342,24 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa goto err; } + sk->cork = false; + switch (proto) { + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + if (dump_opt(lfd, SOL_UDP, UDP_CORK, &aux)) + return -1; + if (aux) { + sk->cork = true; + /* + * FIXME: it is possible to dump a corked socket with + * the empty send queue. + */ + pr_err("Can't dump corked dgram socket %x\n", sk->sd.ino); + goto err; + } + break; + } + if (!can_dump_inet_sk(sk)) goto err; From 8720f1da1feedff4686b1d84e0102e3958b2a8d9 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 4 Dec 2017 22:41:11 +0300 Subject: [PATCH 1196/4375] test: check that corked udp sockets are not dumped The kernel doesn't have an interface to get a sent queue for udp sockets, so currently we can't dump them and criu dump has to fail in such cases. Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/socket_udp-corked.c | 76 +++++++++++++++++++++++++ test/zdtm/static/socket_udp-corked.desc | 1 + 3 files changed, 78 insertions(+) create mode 100644 test/zdtm/static/socket_udp-corked.c create mode 100644 test/zdtm/static/socket_udp-corked.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index cd327ab0e..e8b6ecebb 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -28,6 +28,7 @@ TST_NOFILE := \ socket_listen6 \ socket_listen4v6 \ socket_udp \ + socket_udp-corked \ socket6_udp \ socket_udp_shutdown \ sk-freebind \ diff --git a/test/zdtm/static/socket_udp-corked.c b/test/zdtm/static/socket_udp-corked.c new file mode 100644 index 000000000..30cfac5ec --- /dev/null +++ b/test/zdtm/static/socket_udp-corked.c @@ -0,0 +1,76 @@ +#include "zdtmtst.h" + +const char *test_doc = "static test for UDP socket\n"; +const char *test_author = "Pavel Emelyanov \n"; + +/* Description: + * Create two tcp socket, server send asynchronous request on + * read data and clietn write data after migration + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for sockaddr_in and inet_ntoa() */ +#include +#include + +static int port = 8880; + +#define MSG1 "msg1" + +int main(int argc, char **argv) +{ + int ret, sk1; + socklen_t len = sizeof(struct sockaddr_in); + struct sockaddr_in addr1; + int opt; + + test_init(argc, argv); + + sk1 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sk1 < 0) { + pr_perror("Can't create socket"); + return 1; + } + + memset(&addr1, 0, sizeof(addr1)); + addr1.sin_family = AF_INET; + addr1.sin_addr.s_addr = inet_addr("127.0.0.1"); + addr1.sin_port = htons(port); + + ret = bind(sk1, (struct sockaddr *)&addr1, len); + if (ret < 0) { + pr_perror("Can't bind socket"); + return 1; + } + ret = connect(sk1, (struct sockaddr *)&addr1, len); + if (ret < 0) { + pr_perror("Can't connect"); + return 1; + } + + opt = 1; + if (setsockopt(sk1, SOL_UDP, UDP_CORK, &opt, sizeof(opt))) { + pr_perror("Unable to set UDP_CORK"); + return 1; + } + + if (write(sk1, MSG1, sizeof(MSG1)) != sizeof(MSG1)) { + pr_perror("write"); + return 1; + } + + test_daemon(); + test_waitsig(); + + + pass(); + return 0; +} diff --git a/test/zdtm/static/socket_udp-corked.desc b/test/zdtm/static/socket_udp-corked.desc new file mode 100644 index 000000000..ded89879a --- /dev/null +++ b/test/zdtm/static/socket_udp-corked.desc @@ -0,0 +1 @@ +{'flags': 'crfail'} From 88fbd37f530a646c1ad939a0ee6dd74f8c55ed8b Mon Sep 17 00:00:00 2001 From: Vitaly Ostrosablin Date: Tue, 12 Dec 2017 16:12:45 +0300 Subject: [PATCH 1197/4375] criu: Don't fail if ghost file has no parent dirs. Due to way CRIU handles paths (as relative to workdir), there's a case, where migration would fail. Simple example is a ghost file in filesystem root (with root being cwd). For example, "/unlinked" becomes "unlinked". And original code piece scans path for other slashes, which would be missing in this case. But it's still a perfectly valid case, and there's no need to fail. So if there's no parent dir - we just don't need to create one and we can just return 0 here instead of failing. Signed-off-by: Vitaly Ostrosablin Signed-off-by: Andrei Vagin --- criu/files-reg.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 89ae007eb..29a588ccd 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1474,10 +1474,8 @@ static int make_parent_dirs_if_need(int mntns_root, char *path) struct stat st; p = last_delim = strrchr(path, '/'); - if (!p) { - pr_err("Path %s has no parent dir\n", path); - return -1; - } + if (!p) + return 0; *p = '\0'; if (fstatat(mntns_root, path, &st, AT_EMPTY_PATH) == 0) From 03fb0b82230c7a4f89569339b80e459fdc0e4631 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 14 Dec 2017 18:30:03 -0800 Subject: [PATCH 1198/4375] syscall: fix arguments for preadv() It has two arguments "pos_l and "pos_h" instead of one "off". It is used to handle 64-bit offsets on 32-bit kernels. SYSCALL_DEFINE5(preadv, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h) https://github.com/checkpoint-restore/criu/issues/424 Signed-off-by: Andrei Vagin Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/arch/arm/plugins/std/syscalls/syscall.def | 2 +- .../ppc64/plugins/std/syscalls/syscall-ppc64.tbl | 2 +- .../s390/plugins/std/syscalls/syscall-s390.tbl | 2 +- .../arch/x86/plugins/std/syscalls/syscall_32.tbl | 2 +- .../arch/x86/plugins/std/syscalls/syscall_64.tbl | 2 +- compel/plugins/include/uapi/std/syscall-types.h | 16 ++++++++++++++++ 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/compel/arch/arm/plugins/std/syscalls/syscall.def b/compel/arch/arm/plugins/std/syscalls/syscall.def index 9d0e758ae..b68f9f2f2 100644 --- a/compel/arch/arm/plugins/std/syscalls/syscall.def +++ b/compel/arch/arm/plugins/std/syscalls/syscall.def @@ -107,5 +107,5 @@ io_submit 2 246 (aio_context_t ctx_id, long nr, struct iocb **iocbpp) io_getevents 4 245 (aio_context_t ctx, long min_nr, long nr, struct io_event *evs, struct timespec *tmo) seccomp 277 383 (unsigned int op, unsigned int flags, const char *uargs) gettimeofday 169 78 (struct timeval *tv, struct timezone *tz) -preadv 69 361 (int fd, struct iovec *iov, unsigned long nr, loff_t off) +preadv_raw 69 361 (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) userfaultfd 282 388 (int flags) diff --git a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl index 17cfdc6ec..fa0b034ee 100644 --- a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl +++ b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl @@ -104,5 +104,5 @@ __NR_io_getevents 229 sys_io_getevents (aio_context_t ctx_id, long min_nr, long __NR_io_submit 230 sys_io_submit (aio_context_t ctx_id, long nr, struct iocb **iocbpp) __NR_ipc 117 sys_ipc (unsigned int call, int first, unsigned long second, unsigned long third, const void *ptr, long fifth) __NR_gettimeofday 78 sys_gettimeofday (struct timeval *tv, struct timezone *tz) -__NR_preadv 320 sys_preadv (int fd, struct iovec *iov, unsigned long nr, loff_t off) +__NR_preadv 320 sys_preadv_raw (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) __NR_userfaultfd 364 sys_userfaultfd (int flags) diff --git a/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl b/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl index 1670450ce..bc77ae970 100644 --- a/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl +++ b/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl @@ -104,5 +104,5 @@ __NR_io_getevents 245 sys_io_getevents (aio_context_t ctx_id, long min_nr, long __NR_io_submit 246 sys_io_submit (aio_context_t ctx_id, long nr, struct iocb **iocbpp) __NR_ipc 117 sys_ipc (unsigned int call, int first, unsigned long second, unsigned long third, const void *ptr, long fifth) __NR_userfaultfd 355 sys_userfaultfd (int flags) -__NR_preadv 328 sys_preadv (int fd, struct iovec *iov, unsigned long nr, loff_t off) +__NR_preadv 328 sys_preadv_raw (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) __NR_gettimeofday 78 sys_gettimeofday (struct timeval *tv, struct timezone *tz) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl index c67fc4955..9e1de2815 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl @@ -84,7 +84,7 @@ __NR_get_robust_list 312 sys_get_robust_list (int pid, struct robust_list_head __NR_vmsplice 316 sys_vmsplice (int fd, const struct iovec *iov, unsigned int nr_segs, unsigned int flags) __NR_signalfd 321 sys_signalfd (int ufd, const k_rtsigset_t *sigmask, size_t sigsetsize) __NR_timerfd_settime 325 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) -__NR_preadv 333 sys_preadv (int fd, struct iovec *iov, unsigned long nr, loff_t off) +__NR_preadv 333 sys_preadv_raw (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) __NR_rt_tgsigqueueinfo 335 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *uinfo) __NR_fanotify_init 338 sys_fanotify_init (unsigned int flags, unsigned int event_f_flags) __NR_fanotify_mark 339 sys_fanotify_mark (int fanotify_fd, unsigned int flag, uint32_t mask, int dfd, const char *pathname) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl index e1c198929..0200111c7 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl @@ -96,7 +96,7 @@ __NR_seccomp 317 sys_seccomp (unsigned int op, unsigned int flags, const cha __NR_vmsplice 278 sys_vmsplice (int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags) __NR_timerfd_settime 286 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) __NR_signalfd4 289 sys_signalfd (int fd, k_rtsigset_t *mask, size_t sizemask, int flags) -__NR_preadv 295 sys_preadv (int fd, struct iovec *iov, unsigned long nr, loff_t off) +__NR_preadv 295 sys_preadv_raw (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) __NR_rt_tgsigqueueinfo 297 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *info) __NR_fanotify_init 300 sys_fanotify_init (unsigned int flags, unsigned int event_f_flags) __NR_fanotify_mark 301 sys_fanotify_mark (int fanotify_fd, unsigned int flags, uint64_t mask, int dfd, const char *pathname) diff --git a/compel/plugins/include/uapi/std/syscall-types.h b/compel/plugins/include/uapi/std/syscall-types.h index 119edb77e..ddb740c82 100644 --- a/compel/plugins/include/uapi/std/syscall-types.h +++ b/compel/plugins/include/uapi/std/syscall-types.h @@ -15,6 +15,8 @@ #include #include +#include "common/bitsperlong.h" + struct cap_header { uint32_t version; int pid; @@ -53,4 +55,18 @@ typedef int kernel_timer_t; #include + +extern long sys_preadv_raw(int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h); + +static inline long sys_preadv(int fd, struct iovec *iov, unsigned long nr, off_t off) +{ +#if BITS_PER_LONG == 64 + return sys_preadv_raw(fd, iov, nr, off, 0); +#elif BITS_PER_LONG == 32 + return sys_preadv_raw(fd, iov, nr, off, ((uint64_t)off) >> 32); +#else +# error "BITS_PER_LONG isn't defined" +#endif +} + #endif /* COMPEL_SYSCALL_TYPES_H__ */ From 5759076cea5e8afe0064d4d6c8fe4563b91209fc Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 19 Dec 2017 21:08:35 +0300 Subject: [PATCH 1199/4375] criu: Version 3.7 This time we shifted the update one month, due to the amount of changes not being very big. And got pretty big update, including a set of bugfixes and new functionality. Signed-off-by: Pavel Emelyanov --- Makefile.versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index f92388e74..9b0689702 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 6 +CRIU_VERSION_MINOR := 7 CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Alabaster Finch +CRIU_VERSION_NAME := Vinyl Magpie CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From bbbe4f264a7ef3b0b74288afb3fa0be8bb919ea4 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 2 Feb 2017 03:04:22 +0300 Subject: [PATCH 1200/4375] restore: call close_pid_proc() if a child is shared a parent fd table There are a number of global variables around this descriptor (e.g. open_proc_fd) and their values are saved in memory which are not shared between processes. travis-ci: success for Dump and restore nested network namespaces (rev4) Signed-off-by: Andrei Vagin Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov --- criu/cr-restore.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 3a1c0cd9e..72fb55c2b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1233,6 +1233,9 @@ static inline int fork_with_pid(struct pstree_item *item) BUG_ON(pid != INIT_PID); } + if (ca.clone_flags & CLONE_FILES) + close_pid_proc(); + /* * Some kernel modules, such as netwrok packet generator * run kernel thread upon net-namespace creattion taking From 4ea9cf336a41f1381fcc70fe9903589f8e4844de Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 2 Feb 2017 03:04:25 +0300 Subject: [PATCH 1201/4375] netlink: add ns_id as a generic argument to receive_callback ns_id will be used to collect sockets and other per-netns resources travis-ci: success for Dump and restore nested network namespaces (rev4) Signed-off-by: Andrei Vagin Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov --- criu/include/libnetlink.h | 5 +++-- criu/include/sk-packet.h | 2 +- criu/include/sockets.h | 6 +++--- criu/libnetlink.c | 13 +++++++------ criu/net.c | 16 ++++++++-------- criu/sk-inet.c | 2 +- criu/sk-netlink.c | 2 +- criu/sk-packet.c | 2 +- criu/sk-unix.c | 6 +++--- criu/sockets.c | 31 ++++++++++++++++--------------- 10 files changed, 44 insertions(+), 41 deletions(-) diff --git a/criu/include/libnetlink.h b/criu/include/libnetlink.h index 0549ef984..b2980ffbc 100644 --- a/criu/include/libnetlink.h +++ b/criu/include/libnetlink.h @@ -3,9 +3,10 @@ #define CR_NLMSG_SEQ 24680 /* arbitrary chosen */ +struct ns_id; extern int do_rtnl_req(int nl, void *req, int size, - int (*receive_callback)(struct nlmsghdr *h, void *), - int (*error_callback)(int err, void *), void *); + int (*receive_callback)(struct nlmsghdr *h, struct ns_id *ns, void *), + int (*error_callback)(int err, void *), struct ns_id *ns, void *); extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen); diff --git a/criu/include/sk-packet.h b/criu/include/sk-packet.h index fda471f94..a0738ae0c 100644 --- a/criu/include/sk-packet.h +++ b/criu/include/sk-packet.h @@ -15,7 +15,7 @@ extern int dump_socket_map(struct vma_area *vma); extern int collect_socket_map(struct vma_area *); struct nlmsghdr; -extern int packet_receive_one(struct nlmsghdr *h, void *arg); +extern int packet_receive_one(struct nlmsghdr *h, struct ns_id *ns, void *arg); #ifndef PACKET_VNET_HDR #define PACKET_VNET_HDR 15 diff --git a/criu/include/sockets.h b/criu/include/sockets.h index c0f302474..bdf82dd13 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -50,9 +50,9 @@ extern const struct fdtype_ops inet6_dump_ops; extern const struct fdtype_ops netlink_dump_ops; extern const struct fdtype_ops packet_dump_ops; -extern int inet_collect_one(struct nlmsghdr *h, int family, int type); -extern int unix_receive_one(struct nlmsghdr *h, void *); -extern int netlink_receive_one(struct nlmsghdr *hdr, void *arg); +extern int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns); +extern int unix_receive_one(struct nlmsghdr *h, struct ns_id *ns, void *); +extern int netlink_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, void *arg); extern int unix_sk_id_add(unsigned int ino); extern int unix_sk_ids_parse(char *optarg); diff --git a/criu/libnetlink.c b/criu/libnetlink.c index 5f69a3d66..f585f0907 100644 --- a/criu/libnetlink.c +++ b/criu/libnetlink.c @@ -10,8 +10,9 @@ #include "libnetlink.h" #include "util.h" -static int nlmsg_receive(char *buf, int len, int (*cb)(struct nlmsghdr *, void *), - int (*err_cb)(int, void *), void *arg) +static int nlmsg_receive(char *buf, int len, + int (*cb)(struct nlmsghdr *, struct ns_id *ns, void *), + int (*err_cb)(int, void *), struct ns_id *ns, void *arg) { struct nlmsghdr *hdr; @@ -42,7 +43,7 @@ static int nlmsg_receive(char *buf, int len, int (*cb)(struct nlmsghdr *, void * return err_cb(err->error, arg); } - if (cb(hdr, arg)) + if (cb(hdr, ns, arg)) return -1; } @@ -56,8 +57,8 @@ static int rtnl_return_err(int err, void *arg) } int do_rtnl_req(int nl, void *req, int size, - int (*receive_callback)(struct nlmsghdr *h, void *), - int (*error_callback)(int err, void *), void *arg) + int (*receive_callback)(struct nlmsghdr *h, struct ns_id *ns, void *), + int (*error_callback)(int err, void *), struct ns_id *ns, void *arg) { struct msghdr msg; struct sockaddr_nl nladdr; @@ -116,7 +117,7 @@ int do_rtnl_req(int nl, void *req, int size, goto err; } - err = nlmsg_receive(buf, err, receive_callback, error_callback, arg); + err = nlmsg_receive(buf, err, receive_callback, error_callback, ns, arg); if (err < 0) goto err; if (err == 0) diff --git a/criu/net.c b/criu/net.c index dcaf93f88..20da55b0c 100644 --- a/criu/net.c +++ b/criu/net.c @@ -783,7 +783,7 @@ static int dump_one_sit(struct ifinfomsg *ifi, char *kind, return dump_one_netdev(ND_TYPE__SIT, ifi, tb, fds, dump_sit); } -static int dump_one_link(struct nlmsghdr *hdr, void *arg) +static int dump_one_link(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) { struct cr_imgset *fds = arg; struct ifinfomsg *ifi; @@ -833,7 +833,7 @@ unk: return ret; } -static int dump_one_nf(struct nlmsghdr *hdr, void *arg) +static int dump_one_nf(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) { struct cr_img *img = arg; @@ -946,7 +946,7 @@ static int restore_nf_ct(int pid, int type) goto out; nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE; - ret = do_rtnl_req(sk, nlh, nlh->nlmsg_len, NULL, NULL, NULL); + ret = do_rtnl_req(sk, nlh, nlh->nlmsg_len, NULL, NULL, NULL, NULL); if (ret) goto out; } @@ -995,7 +995,7 @@ static int dump_nf_ct(struct cr_imgset *fds, int type) img = img_from_set(fds, type); - ret = do_rtnl_req(sk, &req, sizeof(req), dump_one_nf, NULL, img); + ret = do_rtnl_req(sk, &req, sizeof(req), dump_one_nf, NULL, NULL, img); close(sk); out: return ret; @@ -1026,13 +1026,13 @@ static int dump_links(struct cr_imgset *fds) req.nlh.nlmsg_seq = CR_NLMSG_SEQ; req.g.rtgen_family = AF_PACKET; - ret = do_rtnl_req(sk, &req, sizeof(req), dump_one_link, NULL, fds); + ret = do_rtnl_req(sk, &req, sizeof(req), dump_one_link, NULL, NULL, fds); close(sk); out: return ret; } -static int restore_link_cb(struct nlmsghdr *hdr, void *arg) +static int restore_link_cb(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) { pr_info("Got response on SETLINK =)\n"); return 0; @@ -1116,7 +1116,7 @@ static int do_rtm_link_req(int msg_type, NetDeviceEntry *nde, int nlsk, if (populate_newlink_req(&req, msg_type, nde, link_info, extras) < 0) return -1; - return do_rtnl_req(nlsk, &req, req.h.nlmsg_len, restore_link_cb, NULL, NULL); + return do_rtnl_req(nlsk, &req, req.h.nlmsg_len, restore_link_cb, NULL, NULL, NULL); } int restore_link_parms(NetDeviceEntry *nde, int nlsk) @@ -1270,7 +1270,7 @@ static int userns_restore_one_link(void *arg, int fd, pid_t pid) addattr_l(&req->h, sizeof(*req), IFLA_NET_NS_FD, &fd, sizeof(fd)); - ret = do_rtnl_req(nlsk, req, req->h.nlmsg_len, restore_link_cb, NULL, NULL); + ret = do_rtnl_req(nlsk, req, req->h.nlmsg_len, restore_link_cb, NULL, NULL, NULL); close(nlsk); out: diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 115bd4579..39b344ae0 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -484,7 +484,7 @@ const struct fdtype_ops inet6_dump_ops = { .dump = dump_one_inet6_fd, }; -int inet_collect_one(struct nlmsghdr *h, int family, int type) +int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns) { struct inet_sk_desc *d; struct inet_diag_msg *m = NLMSG_DATA(h); diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c index e15dc0884..45658b987 100644 --- a/criu/sk-netlink.c +++ b/criu/sk-netlink.c @@ -24,7 +24,7 @@ struct netlink_sk_desc { u8 protocol; }; -int netlink_receive_one(struct nlmsghdr *hdr, void *arg) +int netlink_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) { struct nlattr *tb[NETLINK_DIAG_MAX+1]; struct netlink_diag_msg *m; diff --git a/criu/sk-packet.c b/criu/sk-packet.c index f9017b57a..2aa2a2a3a 100644 --- a/criu/sk-packet.c +++ b/criu/sk-packet.c @@ -247,7 +247,7 @@ static int packet_save_mreqs(struct packet_sock_desc *sd, struct nlattr *mc) return 0; } -int packet_receive_one(struct nlmsghdr *hdr, void *arg) +int packet_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) { struct packet_diag_msg *m; struct nlattr *tb[PACKET_DIAG_MAX + 1]; diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 16b4bf3ec..6a9c76fae 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -588,7 +588,7 @@ skip: } static int unix_collect_one(const struct unix_diag_msg *m, - struct nlattr **tb) + struct nlattr **tb, struct ns_id *ns) { struct unix_sk_desc *d; int ret = 0; @@ -679,14 +679,14 @@ skip: return ret; } -int unix_receive_one(struct nlmsghdr *h, void *arg) +int unix_receive_one(struct nlmsghdr *h, struct ns_id *ns, void *arg) { struct unix_diag_msg *m = NLMSG_DATA(h); struct nlattr *tb[UNIX_DIAG_MAX+1]; nlmsg_parse(h, sizeof(struct unix_diag_msg), tb, UNIX_DIAG_MAX, NULL); - return unix_collect_one(m, tb); + return unix_collect_one(m, tb, ns); } static int dump_external_sockets(struct unix_sk_desc *peer) diff --git a/criu/sockets.c b/criu/sockets.c index 70d57b009..3091b9db6 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -116,7 +116,7 @@ bool socket_test_collect_bit(unsigned int family, unsigned int proto) return test_bit(nr, socket_cl_bits) != 0; } -static int probe_recv_one(struct nlmsghdr *h, void *arg) +static int probe_recv_one(struct nlmsghdr *h, struct ns_id *ns, void *arg) { pr_err("PROBE RECEIVED\n"); return -1; @@ -135,7 +135,7 @@ static int probe_err(int err, void *arg) static inline void probe_diag(int nl, struct sock_diag_req *req, int expected_err) { - do_rtnl_req(nl, req, req->hdr.nlmsg_len, probe_recv_one, probe_err, &expected_err); + do_rtnl_req(nl, req, req->hdr.nlmsg_len, probe_recv_one, probe_err, NULL, &expected_err); } void preload_socket_modules(void) @@ -588,7 +588,7 @@ int dump_socket(struct fd_parms *p, int lfd, FdinfoEntry *e) return do_dump_gen_file(p, lfd, ops, e); } -static int inet_receive_one(struct nlmsghdr *h, void *arg) +static int inet_receive_one(struct nlmsghdr *h, struct ns_id *ns, void *arg) { struct inet_diag_req_v2 *i = arg; int type; @@ -606,15 +606,16 @@ static int inet_receive_one(struct nlmsghdr *h, void *arg) return -1; } - return inet_collect_one(h, i->sdiag_family, type); + return inet_collect_one(h, i->sdiag_family, type, ns); } static int do_collect_req(int nl, struct sock_diag_req *req, int size, - int (*receive_callback)(struct nlmsghdr *h, void *), void *arg) + int (*receive_callback)(struct nlmsghdr *h, struct ns_id *ns, void *), + struct ns_id *ns, void *arg) { int tmp; - tmp = do_rtnl_req(nl, req, size, receive_callback, NULL, arg); + tmp = do_rtnl_req(nl, req, size, receive_callback, NULL, ns, arg); if (tmp == 0) set_collect_bit(req->r.n.sdiag_family, req->r.n.sdiag_protocol); @@ -640,7 +641,7 @@ int collect_sockets(struct ns_id *ns) req.r.u.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_VFS | UDIAG_SHOW_PEER | UDIAG_SHOW_ICONS | UDIAG_SHOW_RQLEN; - tmp = do_collect_req(nl, &req, sizeof(req), unix_receive_one, NULL); + tmp = do_collect_req(nl, &req, sizeof(req), unix_receive_one, ns, NULL); if (tmp) err = tmp; @@ -653,7 +654,7 @@ int collect_sockets(struct ns_id *ns) (1 << TCP_FIN_WAIT1) | (1 << TCP_FIN_WAIT2) | (1 << TCP_CLOSE_WAIT) | (1 << TCP_LAST_ACK) | (1 << TCP_CLOSING) | (1 << TCP_SYN_SENT); - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i); + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); if (tmp) err = tmp; @@ -662,7 +663,7 @@ int collect_sockets(struct ns_id *ns) req.r.i.sdiag_protocol = IPPROTO_UDP; req.r.i.idiag_ext = 0; req.r.i.idiag_states = -1; /* All */ - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i); + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); if (tmp) err = tmp; @@ -671,7 +672,7 @@ int collect_sockets(struct ns_id *ns) req.r.i.sdiag_protocol = IPPROTO_UDPLITE; req.r.i.idiag_ext = 0; req.r.i.idiag_states = -1; /* All */ - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i); + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); if (tmp) err = tmp; @@ -684,7 +685,7 @@ int collect_sockets(struct ns_id *ns) (1 << TCP_FIN_WAIT1) | (1 << TCP_FIN_WAIT2) | (1 << TCP_CLOSE_WAIT) | (1 << TCP_LAST_ACK) | (1 << TCP_CLOSING) | (1 << TCP_SYN_SENT); - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i); + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); if (tmp) err = tmp; @@ -693,7 +694,7 @@ int collect_sockets(struct ns_id *ns) req.r.i.sdiag_protocol = IPPROTO_UDP; req.r.i.idiag_ext = 0; req.r.i.idiag_states = -1; /* All */ - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i); + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); if (tmp) err = tmp; @@ -702,7 +703,7 @@ int collect_sockets(struct ns_id *ns) req.r.i.sdiag_protocol = IPPROTO_UDPLITE; req.r.i.idiag_ext = 0; req.r.i.idiag_states = -1; /* All */ - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i); + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); if (tmp) err = tmp; @@ -710,7 +711,7 @@ int collect_sockets(struct ns_id *ns) req.r.p.sdiag_protocol = 0; req.r.p.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MCLIST | PACKET_SHOW_FANOUT | PACKET_SHOW_RING_CFG; - tmp = do_collect_req(nl, &req, sizeof(req), packet_receive_one, NULL); + tmp = do_collect_req(nl, &req, sizeof(req), packet_receive_one, ns, NULL); if (tmp) { pr_warn("The current kernel doesn't support packet_diag\n"); if (ns->ns_pid == 0 || tmp != -ENOENT) /* Fedora 19 */ @@ -720,7 +721,7 @@ int collect_sockets(struct ns_id *ns) req.r.n.sdiag_family = AF_NETLINK; req.r.n.sdiag_protocol = NDIAG_PROTO_ALL; req.r.n.ndiag_show = NDIAG_SHOW_GROUPS; - tmp = do_collect_req(nl, &req, sizeof(req), netlink_receive_one, NULL); + tmp = do_collect_req(nl, &req, sizeof(req), netlink_receive_one, ns, NULL); if (tmp) { pr_warn("The current kernel doesn't support netlink_diag\n"); if (ns->ns_pid == 0 || tmp != -ENOENT) /* Fedora 19 */ From 5902eb2155fb8ab3fee463eff4c6fbf8f76625cc Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 2 Feb 2017 03:04:30 +0300 Subject: [PATCH 1202/4375] net: rename pid into nsid for prepare_net_ns() PID ussualy means processs ID, but prepare_net_ns works with namespaces. travis-ci: success for Dump and restore nested network namespaces (rev4) Signed-off-by: Andrei Vagin Reviewed-by: Dmitry Safonov Signed-off-by: Pavel Emelyanov --- criu/net.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/criu/net.c b/criu/net.c index 20da55b0c..4ee6f79f1 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1902,32 +1902,32 @@ int dump_net_ns(int ns_id) return ret; } -int prepare_net_ns(int pid) +int prepare_net_ns(int nsid) { int ret = 0; NetnsEntry *netns = NULL; if (!(opts.empty_ns & CLONE_NEWNET)) { - ret = restore_netns_conf(pid, &netns); + ret = restore_netns_conf(nsid, &netns); if (!ret) - ret = restore_links(pid, &netns); + ret = restore_links(nsid, &netns); if (netns) netns_entry__free_unpacked(netns, NULL); if (!ret) - ret = restore_ifaddr(pid); + ret = restore_ifaddr(nsid); if (!ret) - ret = restore_route(pid); + ret = restore_route(nsid); if (!ret) - ret = restore_rule(pid); + ret = restore_rule(nsid); if (!ret) - ret = restore_iptables(pid); + ret = restore_iptables(nsid); } if (!ret) - ret = restore_nf_ct(pid, CR_FD_NETNF_CT); + ret = restore_nf_ct(nsid, CR_FD_NETNF_CT); if (!ret) - ret = restore_nf_ct(pid, CR_FD_NETNF_EXP); + ret = restore_nf_ct(nsid, CR_FD_NETNF_EXP); close_service_fd(NS_FD_OFF); From 17f163a6f28f0f70476d6b40e0154bca934d52fd Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 10 Feb 2017 17:33:47 +0300 Subject: [PATCH 1203/4375] usernsd: Add debugging to catch BUG in unsd fd/flags mismatch Signed-off-by: Pavel Emelyanov --- criu/namespaces.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/criu/namespaces.c b/criu/namespaces.c index 285974eae..a283edd87 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -1216,7 +1216,10 @@ static int usernsd(int sk) unsc_msg_pid_fd(&um, &pid, &fd); pr_debug("uns: daemon calls %p (%d, %d, %x)\n", call, pid, fd, flags); - BUG_ON(fd < 0 && flags & UNS_FDOUT); + if (fd < 0 && flags & UNS_FDOUT) { + pr_err("uns: bad flags/fd %p %d %x\n", call, fd, flags); + BUG(); + } /* * Caller has sent us bare address of the routine it From a54d3cf11098b2c853a584277fdae7f358afa7f2 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 15 Feb 2017 02:59:25 +0300 Subject: [PATCH 1204/4375] net: save network namespaces for sockets Each socket has to be restored in a proper namespaces where it has been created. Here is an issue about unconnected and unbound sockets, they are not reported via socket-diag and we can't to get their network namespaces. v2: add a comment before get_socket_ns() remove nsid from sk_packet_entry Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/namespaces.h | 2 ++ criu/include/sockets.h | 3 ++- criu/net.c | 31 +++++++++++++++++++++++++++++++ criu/sk-inet.c | 16 ++++++++++++++-- criu/sk-netlink.c | 14 +++++++++++++- criu/sk-packet.c | 5 ++++- criu/sk-unix.c | 4 +++- criu/sockets.c | 3 ++- images/packet-sock.proto | 1 + images/sk-inet.proto | 1 + images/sk-netlink.proto | 1 + images/sk-unix.proto | 2 ++ 12 files changed, 76 insertions(+), 7 deletions(-) diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index c9f3e8a74..18eafb20f 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -184,4 +184,6 @@ extern int __userns_call(const char *func_name, uns_call_t call, int flags, extern int add_ns_shared_cb(int (*actor)(void *data), void *data); +extern struct ns_id *get_socket_ns(int lfd); + #endif /* __CR_NS_H__ */ diff --git a/criu/include/sockets.h b/criu/include/sockets.h index bdf82dd13..1d0702cb8 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -19,6 +19,7 @@ struct socket_desc { unsigned int family; unsigned int ino; struct socket_desc *next; + struct ns_id *sk_ns; int already_dumped; }; @@ -31,7 +32,7 @@ extern void preload_socket_modules(void); extern bool socket_test_collect_bit(unsigned int family, unsigned int proto); -extern int sk_collect_one(unsigned ino, int family, struct socket_desc *d); +extern int sk_collect_one(unsigned ino, int family, struct socket_desc *d, struct ns_id *ns); struct ns_id; extern int collect_sockets(struct ns_id *); extern struct collect_image_info inet_sk_cinfo; diff --git a/criu/net.c b/criu/net.c index 4ee6f79f1..13cbae1e7 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2151,6 +2151,7 @@ err_nl: goto out; } +static int netns_nr; static int collect_net_ns(struct ns_id *ns, void *oarg) { bool for_dump = (oarg == (void *)1); @@ -2161,6 +2162,8 @@ static int collect_net_ns(struct ns_id *ns, void *oarg) if (ret) return ret; + netns_nr++; + if (!for_dump) return 0; @@ -2175,6 +2178,34 @@ int collect_net_namespaces(bool for_dump) struct ns_desc net_ns_desc = NS_DESC_ENTRY(CLONE_NEWNET, "net"); +static struct ns_id *get_root_netns() +{ + static struct ns_id *root_netns = NULL; + + if (root_netns) + return root_netns; + + if (root_item->ids == NULL) + return NULL; + + root_netns = lookup_ns_by_id(root_item->ids->net_ns_id, &net_ns_desc); + + return root_netns; +} + +/* + * socket_diag doesn't report unbound and unconnected sockets, + * so we have to get their network namesapces explicitly + */ +struct ns_id *get_socket_ns(int lfd) +{ + if (netns_nr == 1) + return get_root_netns(); + + pr_perror("Unable to get a socket net namespace"); + return NULL; +} + static int move_to_bridge(struct external *ext, void *arg) { int s = *(int *)arg; diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 39b344ae0..d86465bba 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -26,6 +26,7 @@ #include "sk-inet.h" #include "protobuf.h" #include "util.h" +#include "namespaces.h" #define PB_ALEN_INET 1 #define PB_ALEN_INET6 4 @@ -210,9 +211,16 @@ static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int { struct inet_sk_desc *sk; union libsoccr_addr address; + struct ns_id *ns = NULL; socklen_t aux; int ret; + if (root_ns_mask & CLONE_NEWNET) { + ns = get_socket_ns(lfd); + if (ns == NULL) + return NULL; + } + sk = xzalloc(sizeof(*sk)); if (!sk) goto err; @@ -279,7 +287,7 @@ static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int sk->state = TCP_CLOSE; - sk_collect_one(sk->sd.ino, sk->sd.family, &sk->sd); + sk_collect_one(sk->sd.ino, sk->sd.family, &sk->sd, ns); return sk; err: @@ -367,6 +375,10 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa ie.id = id; ie.ino = sk->sd.ino; + if (sk->sd.sk_ns) { + ie.ns_id = sk->sd.sk_ns->id; + ie.has_ns_id = true; + } ie.family = family; ie.proto = proto; ie.type = sk->type; @@ -511,7 +523,7 @@ int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns) else pr_err_once("Can't check shutdown state of inet socket\n"); - ret = sk_collect_one(m->idiag_inode, family, &d->sd); + ret = sk_collect_one(m->idiag_inode, family, &d->sd, ns); show_one_inet("Collected", d); diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c index 45658b987..a56f26907 100644 --- a/criu/sk-netlink.c +++ b/criu/sk-netlink.c @@ -12,6 +12,7 @@ #include "images/sk-netlink.pb-c.h" #include "netlink_diag.h" #include "libnetlink.h" +#include "namespaces.h" struct netlink_sk_desc { struct socket_desc sd; @@ -61,7 +62,7 @@ int netlink_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) sd->gsize = 0; } - return sk_collect_one(m->ndiag_ino, PF_NETLINK, &sd->sd); + return sk_collect_one(m->ndiag_ino, PF_NETLINK, &sd->sd, ns); } static bool can_dump_netlink_sk(int lfd) @@ -95,6 +96,8 @@ static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p) if (sk) { BUG_ON(sk->sd.already_dumped); + ne.ns_id = sk->sd.sk_ns->id; + ne.has_ns_id = true; ne.protocol = sk->protocol; ne.portid = sk->portid; ne.groups = sk->groups; @@ -137,9 +140,18 @@ static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p) ne.dst_portid = sk->dst_portid; ne.dst_group = sk->dst_group; } else { /* unconnected and unbound socket */ + struct ns_id *nsid; int val; socklen_t aux = sizeof(val); + if (root_ns_mask & CLONE_NEWNET) { + nsid = get_socket_ns(lfd); + if (nsid == NULL) + return -1; + ne.ns_id = nsid->id; + ne.has_ns_id = true; + } + if (getsockopt(lfd, SOL_SOCKET, SO_PROTOCOL, &val, &aux) < 0) { pr_perror("Unable to get protocol for netlink socket"); goto err; diff --git a/criu/sk-packet.c b/criu/sk-packet.c index 2aa2a2a3a..17432fc00 100644 --- a/criu/sk-packet.c +++ b/criu/sk-packet.c @@ -20,6 +20,7 @@ #include "xmalloc.h" #include "images/packet-sock.pb-c.h" #include "images/fdinfo.pb-c.h" +#include "namespaces.h" struct packet_sock_info { PacketSockEntry *pse; @@ -163,6 +164,8 @@ static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p) sd->sd.already_dumped = 1; psk.id = sd->file_id = id; + psk.ns_id = sd->sd.sk_ns->id; + psk.has_ns_id = true; psk.type = sd->type; psk.flags = p->flags; psk.fown = (FownEntry *)&p->fown; @@ -301,7 +304,7 @@ int packet_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) memcpy(sd->tx, RTA_DATA(tb[PACKET_DIAG_TX_RING]), sizeof(*sd->tx)); } - return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd); + return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd, ns); err: xfree(sd->tx); xfree(sd->rx); diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 6a9c76fae..35aeea682 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -302,6 +302,8 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p) ue->id = id; ue->ino = sk->sd.ino; + ue->ns_id = sk->sd.sk_ns->id; + ue->has_ns_id = true; ue->type = sk->type; ue->state = sk->state; ue->flags = p->flags; @@ -665,7 +667,7 @@ static int unix_collect_one(const struct unix_diag_msg *m, d->wqlen = rq->udiag_wqueue; } - sk_collect_one(m->udiag_ino, AF_UNIX, &d->sd); + sk_collect_one(m->udiag_ino, AF_UNIX, &d->sd, ns); list_add_tail(&d->list, &unix_sockets); show_one_unix("Collected", d); diff --git a/criu/sockets.c b/criu/sockets.c index 3091b9db6..5f0f62991 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -353,13 +353,14 @@ struct socket_desc *lookup_socket(unsigned ino, int family, int proto) return NULL; } -int sk_collect_one(unsigned ino, int family, struct socket_desc *d) +int sk_collect_one(unsigned ino, int family, struct socket_desc *d, struct ns_id *ns) { struct socket_desc **chain; d->ino = ino; d->family = family; d->already_dumped = 0; + d->sk_ns = ns; chain = &sockets[ino % SK_HASH_SIZE]; d->next = *chain; diff --git a/images/packet-sock.proto b/images/packet-sock.proto index f6198c1d4..25875b470 100644 --- a/images/packet-sock.proto +++ b/images/packet-sock.proto @@ -43,4 +43,5 @@ message packet_sock_entry { optional uint32 fanout = 17 [ default = 0xffffffff ]; optional packet_ring rx_ring = 18; optional packet_ring tx_ring = 19; + optional uint32 ns_id = 20; } diff --git a/images/sk-inet.proto b/images/sk-inet.proto index 30f0134b0..4be88adba 100644 --- a/images/sk-inet.proto +++ b/images/sk-inet.proto @@ -39,5 +39,6 @@ message inet_sk_entry { /* for ipv6, we need to send the ifindex to bind(); we keep the ifname * here and convert it on restore */ optional string ifname = 17; + optional uint32 ns_id = 18; optional sk_shutdown shutdown = 19; } diff --git a/images/sk-netlink.proto b/images/sk-netlink.proto index ed24c5026..402281dd9 100644 --- a/images/sk-netlink.proto +++ b/images/sk-netlink.proto @@ -16,4 +16,5 @@ message netlink_sk_entry { required uint32 dst_group = 10; required fown_entry fown = 11; required sk_opts_entry opts = 12; + optional uint32 ns_id = 13; } diff --git a/images/sk-unix.proto b/images/sk-unix.proto index 76e006ddd..2a33fe220 100644 --- a/images/sk-unix.proto +++ b/images/sk-unix.proto @@ -48,4 +48,6 @@ message unix_sk_entry { */ optional string name_dir = 14; optional bool deleted = 15; + + optional uint32 ns_id = 16; } From 6b7393c44ea52c4af7a1cf64fcec95d547becf46 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 15 Feb 2017 02:59:27 +0300 Subject: [PATCH 1205/4375] net: allow to dump and restore more than one network namespace Restore all network namespaces from the root task and then set a proper namespace for each task after restoring sockets, because we need to switch network namespaces to restore sockets. Each socket has to be created in a proper network namespace. v2: fix a typo bug Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 20 +++++---- criu/include/namespaces.h | 4 +- criu/include/net.h | 6 ++- criu/namespaces.c | 6 +-- criu/net.c | 95 ++++++++++++++++++++++++++++++++++++++- criu/pstree.c | 6 +++ 6 files changed, 122 insertions(+), 15 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 72fb55c2b..5b1254c3e 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -865,6 +865,13 @@ static int restore_one_alive_task(int pid, CoreEntry *core) if (prepare_vmas(current, ta)) return -1; + /* + * Sockets have to be restored in their network namespaces, + * so a task namespace has to be restored after sockets. + */ + if (restore_task_net_ns(current)) + return -1; + if (setup_uffd(pid, ta)) return -1; @@ -1551,14 +1558,6 @@ static int restore_task_with_children(void *_arg) if (ret < 0) goto err; - if (ca->clone_flags & CLONE_NEWNET) { - ret = unshare(CLONE_NEWNET); - if (ret) { - pr_perror("Can't unshare net-namespace"); - goto err; - } - } - if (!(ca->clone_flags & CLONE_FILES)) { ret = close_old_fds(); if (ret) @@ -3089,6 +3088,11 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns if (rst_prep_creds(pid, core, &creds_pos)) goto err_nv; + if (current->parent == NULL) { + /* Wait when all tasks restored all files */ + restore_wait_other_tasks(); + } + /* * We're about to search for free VM area and inject the restorer blob * into it. No irrelevant mmaps/mremaps beyond this point, otherwise diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index 18eafb20f..5b39cbdae 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -36,7 +36,8 @@ #define CLONE_ALLNS (CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWCGROUP) /* Nested namespaces are supported only for these types */ -#define CLONE_SUBNS (CLONE_NEWNS) +#define CLONE_SUBNS (CLONE_NEWNS | CLONE_NEWNET) + #define EXTRA_SIZE 20 struct ns_desc { @@ -95,6 +96,7 @@ struct ns_id { } mnt; struct { + int nsfd_id; /* a namespace descriptor id in fdstore */ int nlsk; /* for sockets collection */ int seqsk; /* to talk to parasite daemons */ } net; diff --git a/criu/include/net.h b/criu/include/net.h index deac65f7b..49eca365b 100644 --- a/criu/include/net.h +++ b/criu/include/net.h @@ -12,9 +12,13 @@ struct cr_imgset; extern int dump_net_ns(int ns_id); -extern int prepare_net_ns(int pid); +extern int prepare_net_namespaces(void); +extern void fini_net_namespaces(void); extern int netns_keep_nsfd(void); +struct pstree_item; +extern int restore_task_net_ns(struct pstree_item *current); + struct veth_pair { struct list_head node; char *inside; diff --git a/criu/namespaces.c b/criu/namespaces.c index a283edd87..6ad2eed68 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -1666,9 +1666,6 @@ int prepare_namespace(struct pstree_item *item, unsigned long clone_flags) * tree (i.e. -- mnt_ns restoring) */ - id = ns_per_id ? item->ids->net_ns_id : pid; - if ((clone_flags & CLONE_NEWNET) && prepare_net_ns(id)) - return -1; id = ns_per_id ? item->ids->uts_ns_id : pid; if ((clone_flags & CLONE_NEWUTS) && prepare_utsns(id)) return -1; @@ -1676,6 +1673,9 @@ int prepare_namespace(struct pstree_item *item, unsigned long clone_flags) if ((clone_flags & CLONE_NEWIPC) && prepare_ipc_ns(id)) return -1; + if (prepare_net_namespaces()) + return -1; + /* * This one is special -- there can be several mount * namespaces and prepare_mnt_ns handles them itself. diff --git a/criu/net.c b/criu/net.c index 13cbae1e7..8834dab24 100644 --- a/criu/net.c +++ b/criu/net.c @@ -34,6 +34,7 @@ #include "kerndat.h" #include "util.h" #include "external.h" +#include "fdstore.h" #include "protobuf.h" #include "images/netdev.pb-c.h" @@ -1902,7 +1903,7 @@ int dump_net_ns(int ns_id) return ret; } -int prepare_net_ns(int nsid) +static int prepare_net_ns(int nsid) { int ret = 0; NetnsEntry *netns = NULL; @@ -1929,9 +1930,99 @@ int prepare_net_ns(int nsid) if (!ret) ret = restore_nf_ct(nsid, CR_FD_NETNF_EXP); + return ret; +} + +static int open_net_ns(struct ns_id *nsid, struct rst_info *rst) +{ + int fd, id; + + /* Pin one with a file descriptor */ + fd = open_proc(PROC_SELF, "ns/net"); + if (fd < 0) + return -1; + + id = fdstore_add(fd); + close(fd); + if (id < 0) { + return -1; + } + + nsid->net.nsfd_id = id; + + return 0; +} + +int prepare_net_namespaces() +{ + struct ns_id *nsid; + + if (!(root_ns_mask & CLONE_NEWNET)) + return 0; + + for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { + if (nsid->nd != &net_ns_desc) + continue; + + if (unshare(CLONE_NEWNET)) { + pr_perror("Unable to create a new netns"); + goto err; + } + + if (prepare_net_ns(nsid->id)) + goto err; + + if (open_net_ns(nsid, rsti(root_item))) + goto err; + } + close_service_fd(NS_FD_OFF); - return ret; + return 0; +err: + return -1; +} + +static int do_restore_task_net_ns(struct ns_id *nsid, struct pstree_item *current) +{ + int fd; + + if (!(root_ns_mask & CLONE_NEWNET)) + return 0; + + fd = fdstore_get(nsid->net.nsfd_id); + if (fd < 0) + return -1; + + if (setns(fd, CLONE_NEWNET)) { + pr_perror("Can't restore netns"); + close(fd); + return -1; + } + close(fd); + + return 0; +} + +int restore_task_net_ns(struct pstree_item *current) +{ + if (current->ids && current->ids->has_net_ns_id) { + unsigned int id = current->ids->net_ns_id; + struct ns_id *nsid; + + nsid = lookup_ns_by_id(id, &net_ns_desc); + if (nsid == NULL) { + pr_err("Can't find mount namespace %d\n", id); + return -1; + } + + BUG_ON(nsid->type == NS_CRIU); + + if (do_restore_task_net_ns(nsid, current)) + return -1; + } + + return 0; } int netns_keep_nsfd(void) diff --git a/criu/pstree.c b/criu/pstree.c index e9ddc6aeb..a52ec553a 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -14,6 +14,8 @@ #include "mount.h" #include "dump.h" #include "util.h" +#include "net.h" + #include "protobuf.h" #include "images/pstree.pb-c.h" #include "crtools.h" @@ -475,6 +477,10 @@ static int read_pstree_ids(struct pstree_item *pi) if (rst_add_ns_id(pi->ids->mnt_ns_id, pi, &mnt_ns_desc)) return -1; } + if (pi->ids->has_net_ns_id) { + if (rst_add_ns_id(pi->ids->net_ns_id, pi, &net_ns_desc)) + return -1; + } return 0; } From 2b6ed5bffc7b2b5d32e076529ceaf7d276b7460b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 15 Feb 2017 02:59:28 +0300 Subject: [PATCH 1206/4375] util: move open_proc_fd to service_fd We need this to avoid conflicts with file descriptors, which has to be restored. Currently open_proc_pid() doesn't used during restoring file descriptors, but we are going to use it to restore sockets in proper network namespaces. Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/servicefd.h | 1 + criu/util.c | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h index d47ab665a..b77922394 100644 --- a/criu/include/servicefd.h +++ b/criu/include/servicefd.h @@ -9,6 +9,7 @@ enum sfd_type { LOG_FD_OFF, IMG_FD_OFF, PROC_FD_OFF, /* fd with /proc for all proc_ calls */ + PROC_PID_FD_OFF, CTL_TTY_OFF, SELF_STDIN_OFF, CR_PROC_FD_OFF, /* some other's proc fd. diff --git a/criu/util.c b/criu/util.c index 0ddf4d402..5d5b1b7d4 100644 --- a/criu/util.c +++ b/criu/util.c @@ -291,7 +291,6 @@ int move_fd_from(int *img_fd, int want_fd) */ static pid_t open_proc_pid = PROC_NONE; -static int open_proc_fd = -1; static pid_t open_proc_self_pid; static int open_proc_self_fd = -1; @@ -304,13 +303,18 @@ static inline void set_proc_self_fd(int fd) open_proc_self_pid = getpid(); } -static inline void set_proc_pid_fd(int pid, int fd) +static inline int set_proc_pid_fd(int pid, int fd) { - if (open_proc_fd >= 0) - close(open_proc_fd); + int ret; + + if (fd < 0) + return close_service_fd(PROC_PID_FD_OFF); open_proc_pid = pid; - open_proc_fd = fd; + ret = install_service_fd(PROC_PID_FD_OFF, fd); + close(fd); + + return ret; } static inline int get_proc_fd(int pid) @@ -322,7 +326,7 @@ static inline int get_proc_fd(int pid) } return open_proc_self_fd; } else if (pid == open_proc_pid) - return open_proc_fd; + return get_service_fd(PROC_PID_FD_OFF); else return -1; } @@ -406,7 +410,7 @@ inline int open_pid_proc(pid_t pid) if (pid == PROC_SELF) set_proc_self_fd(fd); else - set_proc_pid_fd(pid, fd); + fd = set_proc_pid_fd(pid, fd); return fd; } From 7a6a42d05bdc1772c7e0b2afaea1456f615ac08c Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 15 Feb 2017 02:59:29 +0300 Subject: [PATCH 1207/4375] net: set a proper network namespace to create a socket Each socket has to be restored from a proper network namespaces where it was created. We set a specified network namespace before restoring a socket. A task network namespace is set after restoring all files. v2: don't set the root netns for transport sockets Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/sockets.h | 2 ++ criu/sk-inet.c | 3 +++ criu/sk-netlink.c | 3 +++ criu/sk-packet.c | 3 +++ criu/sk-unix.c | 7 ++++++- criu/sockets.c | 38 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 55 insertions(+), 1 deletion(-) diff --git a/criu/include/sockets.h b/criu/include/sockets.h index 1d0702cb8..a0f6101ba 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -85,4 +85,6 @@ static inline int sk_decode_shutdown(int val) #define NETLINK_SOCK_DIAG NETLINK_INET_DIAG #endif +extern int set_netns(uint32_t ns_id); + #endif /* __CR_SOCKETS_H__ */ diff --git a/criu/sk-inet.c b/criu/sk-inet.c index d86465bba..a5a092bc7 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -676,6 +676,9 @@ static int open_inet_sk(struct file_desc *d, int *new_fd) if (inet_validate_address(ie)) return -1; + if (set_netns(ie->ns_id)) + return -1; + sk = socket(ie->family, ie->type, ie->proto); if (sk < 0) { pr_perror("Can't create inet socket"); diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c index a56f26907..f26c4dec0 100644 --- a/criu/sk-netlink.c +++ b/criu/sk-netlink.c @@ -200,6 +200,9 @@ static int open_netlink_sk(struct file_desc *d, int *new_fd) pr_info("Opening netlink socket id %#x\n", nse->id); + if (set_netns(nse->ns_id)) + return -1; + sk = socket(PF_NETLINK, SOCK_RAW, nse->protocol); if (sk < 0) { pr_perror("Can't create netlink sock"); diff --git a/criu/sk-packet.c b/criu/sk-packet.c index 17432fc00..ed4cfeb26 100644 --- a/criu/sk-packet.c +++ b/criu/sk-packet.c @@ -475,6 +475,9 @@ static int open_packet_sk(struct file_desc *d, int *new_fd) pr_info("Opening packet socket id %#x\n", pse->id); + if (set_netns(pse->ns_id)) + return -1; + if (pse->type == SOCK_PACKET) return open_packet_sk_spkt(pse, new_fd); diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 35aeea682..928a68477 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1246,6 +1246,9 @@ static int open_unixsk_pair_master(struct unix_sk_info *ui, int *new_fd) pr_info("Opening pair master (id %#x ino %#x peer %#x)\n", ui->ue->id, ui->ue->ino, ui->ue->peer); + if (set_netns(ui->ue->ns_id)) + return -1; + if (socketpair(PF_UNIX, ui->ue->type, 0, sk) < 0) { pr_perror("Can't make socketpair"); return -1; @@ -1301,6 +1304,9 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) pr_info("Opening standalone socket (id %#x ino %#x peer %#x)\n", ui->ue->id, ui->ue->ino, ui->ue->peer); + if (set_netns(ui->ue->ns_id)) + return -1; + /* * Check if this socket was connected to criu service. * If so, put response, that dumping and restoring @@ -1404,7 +1410,6 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) return -1; } - sk = socket(PF_UNIX, ui->ue->type, 0); if (sk < 0) { pr_perror("Can't make unix socket"); diff --git a/criu/sockets.c b/criu/sockets.c index 5f0f62991..caa1d6966 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -24,6 +25,9 @@ #include "net.h" #include "xmalloc.h" #include "fs-magic.h" +#include "pstree.h" +#include "util.h" +#include "fdstore.h" #ifndef SOCK_DIAG_BY_FAMILY #define SOCK_DIAG_BY_FAMILY 20 @@ -744,3 +748,37 @@ int collect_sockets(struct ns_id *ns) return err; } + +static uint32_t last_ns_id = 0; + +int set_netns(uint32_t ns_id) +{ + struct ns_id *ns; + int nsfd; + + if (!(root_ns_mask & CLONE_NEWNET)) + return 0; + + if (ns_id == last_ns_id) + return 0; + + ns = lookup_ns_by_id(ns_id, &net_ns_desc); + if (ns == NULL) { + pr_err("Unable to find a network namespace\n"); + return -1; + } + nsfd = fdstore_get(ns->net.nsfd_id); + if (nsfd < 0) + return -1; + if (setns(nsfd, CLONE_NEWNET)) { + pr_perror("Unable to switch a network namespace"); + close(nsfd); + return -1; + } + last_ns_id = ns_id; + close(nsfd); + + close_pid_proc(); + + return 0; +} From 37ea6ed0cdfa1d706bdce39ca6efe4f2f4efa2ef Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 15 Feb 2017 02:59:30 +0300 Subject: [PATCH 1208/4375] kerndat: check the SIOCGSKNS ioctl This ioctl is called for a socket and returns a file descriptor for network namespace where a socket has been created. Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/cr-check.c | 13 +++++++++++++ criu/include/kerndat.h | 1 + criu/include/sockets.h | 6 ++++++ criu/kerndat.c | 3 +++ criu/net.c | 24 ++++++++++++++++++++++++ 5 files changed, 47 insertions(+) diff --git a/criu/cr-check.c b/criu/cr-check.c index 21d241f68..8f3a965a6 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1062,6 +1062,17 @@ static int check_can_map_vdso(void) return -1; } +static int check_sk_netns(void) +{ + if (kerndat_socket_netns() < 0) + return -1; + + if (!kdat.sk_ns) + return -1; + + return 0; +} + static int (*chk_feature)(void); /* @@ -1168,6 +1179,7 @@ int cr_check(void) ret |= check_can_map_vdso(); ret |= check_uffd(); ret |= check_uffd_noncoop(); + ret |= check_sk_netns(); } /* @@ -1220,6 +1232,7 @@ static struct feature_list feature_list[] = { { "uffd", check_uffd }, { "uffd-noncoop", check_uffd_noncoop }, { "can_map_vdso", check_can_map_vdso}, + { "sk_ns", check_sk_netns }, { NULL, NULL }, }; diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 6ad77e369..a4922f174 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -46,6 +46,7 @@ struct kerndat_s { bool ipv6; enum loginuid_func luid; bool compat_cr; + bool sk_ns; enum pagemap_func pmap; unsigned int has_xtlocks; unsigned long mmap_min_addr; diff --git a/criu/include/sockets.h b/criu/include/sockets.h index a0f6101ba..381244077 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -87,4 +87,10 @@ static inline int sk_decode_shutdown(int val) extern int set_netns(uint32_t ns_id); +#ifndef SIOCGSKNS +#define SIOCGSKNS 0x894C /* get socket network namespace */ +#endif + +extern int kerndat_socket_netns(void); + #endif /* __CR_SOCKETS_H__ */ diff --git a/criu/kerndat.c b/criu/kerndat.c index 164f6cc4b..156b1c617 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -27,6 +27,7 @@ #include "lsm.h" #include "proc_parse.h" #include "sk-inet.h" +#include "sockets.h" #include #include #include "netfilter.h" @@ -873,6 +874,8 @@ int kerndat_init(void) /* Depends on kerndat_vdso_fill_symtable() */ if (!ret) ret = kerndat_vdso_preserves_hint(); + if (!ret) + ret = kerndat_socket_netns(); kerndat_lsm(); kerndat_mmap_min_addr(); diff --git a/criu/net.c b/criu/net.c index 8834dab24..d1723ec05 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2297,6 +2297,30 @@ struct ns_id *get_socket_ns(int lfd) return NULL; } +int kerndat_socket_netns(void) +{ + int sk, ns_fd; + + sk = socket(AF_UNIX, SOCK_DGRAM, 0); + if (sk < 0) { + pr_perror("Unable to create socket"); + return -1; + } + ns_fd = ioctl(sk, SIOCGSKNS); + if (ns_fd < 0) { + pr_warn("Unable to get a socket network namespace\n"); + kdat.sk_ns = false; + close(sk); + return 0; + } + close(sk); + close(ns_fd); + + kdat.sk_ns = true; + + return 0; +} + static int move_to_bridge(struct external *ext, void *arg) { int s = *(int *)arg; From 14731c5210357231b927d597b3f940f1c146a14f Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 15 Feb 2017 02:59:31 +0300 Subject: [PATCH 1209/4375] net: add a way to get a network namespace for a socket Each sockets belongs to one network namespace and operates in this network namespace. socket_diag reports informations about sockets from one network namespace, but it doesn't report sockets which are not bound or connected to somewhere. So we need to have a way to get network namespaces for such sockets. Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/include/namespaces.h | 1 + criu/namespaces.c | 2 +- criu/net.c | 28 ++++++++++++++++++++++++---- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index 5b39cbdae..1b454e0c1 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -187,5 +187,6 @@ extern int __userns_call(const char *func_name, uns_call_t call, int flags, extern int add_ns_shared_cb(int (*actor)(void *data), void *data); extern struct ns_id *get_socket_ns(int lfd); +extern struct ns_id *lookup_ns_by_kid(unsigned int kid, struct ns_desc *nd); #endif /* __CR_NS_H__ */ diff --git a/criu/namespaces.c b/criu/namespaces.c index 6ad2eed68..1fd3f8a2b 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -324,7 +324,7 @@ int rst_add_ns_id(unsigned int id, struct pstree_item *i, struct ns_desc *nd) return 0; } -static struct ns_id *lookup_ns_by_kid(unsigned int kid, struct ns_desc *nd) +struct ns_id *lookup_ns_by_kid(unsigned int kid, struct ns_desc *nd) { struct ns_id *nsid; diff --git a/criu/net.c b/criu/net.c index d1723ec05..6d708f40c 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2290,11 +2290,31 @@ static struct ns_id *get_root_netns() */ struct ns_id *get_socket_ns(int lfd) { - if (netns_nr == 1) - return get_root_netns(); + struct ns_id *ns; + struct stat st; + int ns_fd; - pr_perror("Unable to get a socket net namespace"); - return NULL; + ns_fd = ioctl(lfd, SIOCGSKNS); + if (ns_fd < 0) { + /* backward compatiblity with old kernels */ + if (netns_nr == 1) + return get_root_netns(); + + pr_perror("Unable to get a socket net namespace"); + return NULL; + } + if (fstat(ns_fd, &st)) { + pr_perror("Unable to stat a network namespace"); + return NULL; + } + + ns = lookup_ns_by_kid(st.st_ino, &net_ns_desc); + if (ns == NULL) { + pr_err("Unable to dump a socket from an external network namespace\n"); + return NULL; + } + + return ns; } int kerndat_socket_netns(void) From d7d11e0e00ef0b8e85ed01edb1953e62a9fb16e0 Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Wed, 15 Feb 2017 02:59:32 +0300 Subject: [PATCH 1210/4375] zdtm: add a test for nested network namespaces This tests create a few processes which live in three network namespaces and have a few sockets which are created in different network namespaces. Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/netns_sub.c | 203 ++++++++++++++++++++++++++++++++ test/zdtm/static/netns_sub.desc | 1 + 3 files changed, 205 insertions(+) create mode 100644 test/zdtm/static/netns_sub.c create mode 100644 test/zdtm/static/netns_sub.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index e8b6ecebb..fbf79cc8e 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -194,6 +194,7 @@ TST_NOFILE := \ uffd-events \ thread_different_uid_gid \ pipe03 \ + netns_sub \ # jobctl00 \ include ../Makefile.inc diff --git a/test/zdtm/static/netns_sub.c b/test/zdtm/static/netns_sub.c new file mode 100644 index 000000000..d36fdeeba --- /dev/null +++ b/test/zdtm/static/netns_sub.c @@ -0,0 +1,203 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check dump and restore a few network namespaces"; + +static int fill_name(int nsid, struct sockaddr_un *name) +{ + int len; + + name->sun_family = AF_LOCAL; + snprintf(name->sun_path, 108, "X/zdtm/static/netns_sub-%d", nsid); + len = SUN_LEN(name); + name->sun_path[0] = 0; + + return len; +} + +static int create_socket(int nsid) +{ + struct sockaddr_un name; + int len, sk; + + len = fill_name(nsid, &name); + + sk = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (sk < 0) { + pr_perror("socket"); + return -1; + } + + if (bind(sk, (struct sockaddr *) &name, len) < 0) { + pr_perror("bind"); + close(sk); + return -1; + } + + return sk; +} + +static int check_socket(int nsid, bool success) +{ + struct sockaddr_un name; + int len, sk; + + len = fill_name(nsid, &name); + + sk = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (sk < 0) { + pr_perror("socket"); + return -1; + } + + if (connect(sk, (struct sockaddr *) &name, len) < 0) { + if (!success && errno == ECONNREFUSED) + return 0; + pr_perror("connect to %d", nsid); + close(sk); + return -1; + } + close(sk); + + if (!success) { + pr_err("A sokcet is able to connect to %d\n", nsid); + return -1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + task_waiter_t lock; + pid_t pid1, pid2, pid3, pid0 = getpid(); + int status = -1, sk; + + test_init(argc, argv); + task_waiter_init(&lock); + + sk = create_socket(0); + if (sk < 0) + return 1; + + pid1 = fork(); + if (pid1 < 0) { + pr_perror("fork"); + return -1; + } + if (pid1 == 0) { + close(sk); + unshare(CLONE_NEWNET); + sk = create_socket(1); + if (sk < 0) + return 1; + + pid3 = fork(); + if (pid3 < 0) { + pr_perror("fork"); + return 1; + } + if (pid3 == 0) { + char ns[] = "/proc/0123456789/ns/net"; + int fd; + + snprintf(ns, sizeof(ns), "/proc/%d/ns/net", pid0); + fd = open(ns, O_RDONLY); + if (fd < 0) + return 1; + + if (setns(fd, 0)) + return 1; + close(fd); + + task_waiter_complete(&lock, 3); + test_waitsig(); + + if (check_socket(0, true)) + return 1; + if (check_socket(2, false)) + return 1; + if (check_socket(1, false)) + return 1; + + return 0; + } + /* This socket will be alive in the 3 process */ + close(sk); + + task_waiter_complete(&lock, 1); + test_waitsig(); + + if (check_socket(1, true)) + return 1; + + kill(pid3, SIGTERM); + waitpid(pid3, &status, 0); + if (status) { + fail(); + return 1; + } + + return 0; + } + pid2 = fork(); + if (pid2 < 0) { + pr_perror("fork"); + return -1; + } + if (pid2 == 0) { + unshare(CLONE_NEWNET); + sk = create_socket(2); + if (sk < 0) + return 1; + task_waiter_complete(&lock, 2); + + test_waitsig(); + + if (check_socket(0, false)) + return 1; + if (check_socket(1, false)) + return 1; + if (check_socket(2, true)) + return 1; + + return 0; + } + close(sk); + task_waiter_wait4(&lock, 1); + task_waiter_wait4(&lock, 2); + task_waiter_wait4(&lock, 3); + + test_daemon(); + test_waitsig(); + + kill(pid1, SIGTERM); + waitpid(pid1, &status, 0); + if (status) { + fail(); + return 1; + } + kill(pid2, SIGTERM); + status = -1; + waitpid(pid2, &status, 0); + if (status) { + fail(); + return 1; + } + pass(); + return 0; +} diff --git a/test/zdtm/static/netns_sub.desc b/test/zdtm/static/netns_sub.desc new file mode 100644 index 000000000..7657ba45c --- /dev/null +++ b/test/zdtm/static/netns_sub.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns', 'flags': 'suid'} From ae291308ee0666fc2c357d7d17c64e2329e38504 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 15 Feb 2018 19:51:55 +0300 Subject: [PATCH 1211/4375] test/zdtm/static/netns_sub.c --- test/zdtm/static/netns_sub.c | 1 - 1 file changed, 1 deletion(-) diff --git a/test/zdtm/static/netns_sub.c b/test/zdtm/static/netns_sub.c index d36fdeeba..8428bca74 100644 --- a/test/zdtm/static/netns_sub.c +++ b/test/zdtm/static/netns_sub.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include From b54c7d3d886d9b5fb84464ffcce20c1a3f11da4c Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 24 Feb 2017 14:31:19 +0300 Subject: [PATCH 1212/4375] net: Kill unused argument in open_net_ns() Nobody uses it. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/net.c b/criu/net.c index 6d708f40c..147ad3dff 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1933,7 +1933,7 @@ static int prepare_net_ns(int nsid) return ret; } -static int open_net_ns(struct ns_id *nsid, struct rst_info *rst) +static int open_net_ns(struct ns_id *nsid) { int fd, id; @@ -1972,7 +1972,7 @@ int prepare_net_namespaces() if (prepare_net_ns(nsid->id)) goto err; - if (open_net_ns(nsid, rsti(root_item))) + if (open_net_ns(nsid)) goto err; } From a75f0fa8bc43bbc34b7b2b71995d030dcd7d7305 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 24 Feb 2017 14:31:33 +0300 Subject: [PATCH 1213/4375] ns: Simplify create_net_ns() Merge code with the same functionality in one Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/net.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/criu/net.c b/criu/net.c index 147ad3dff..d29ef6c56 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1953,6 +1953,19 @@ static int open_net_ns(struct ns_id *nsid) return 0; } +static int do_create_net_ns(struct ns_id *ns) +{ + if (unshare(CLONE_NEWNET)) { + pr_perror("Unable to create a new netns"); + return -1; + } + if (prepare_net_ns(ns->id)) + return -1; + if (open_net_ns(ns)) + return -1; + return 0; +} + int prepare_net_namespaces() { struct ns_id *nsid; @@ -1964,15 +1977,7 @@ int prepare_net_namespaces() if (nsid->nd != &net_ns_desc) continue; - if (unshare(CLONE_NEWNET)) { - pr_perror("Unable to create a new netns"); - goto err; - } - - if (prepare_net_ns(nsid->id)) - goto err; - - if (open_net_ns(nsid)) + if (do_create_net_ns(nsid)) goto err; } From dd9e1142765ff92f8f440c16c6a0bbba96151c87 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 17 Dec 2016 06:22:26 +0300 Subject: [PATCH 1214/4375] images: add a network namespace id into images It is possible to assign id for network namespaces and this id will be used by the kernel in some netlink messages. If no id is assigned when the kernel needs it, it will be automatically assigned by the kernel. For example, this id is reported for peer veth devices. v2: add a comment Signed-off-by: Andrei Vagin --- images/netdev.proto | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/images/netdev.proto b/images/netdev.proto index 5f9dae2f5..c15e5246a 100644 --- a/images/netdev.proto +++ b/images/netdev.proto @@ -42,9 +42,22 @@ message net_device_entry { optional macvlan_link_entry macvlan = 11; + optional uint32 peer_ifindex = 12; + optional uint32 peer_nsid = 13; optional sit_entry sit = 15; } +message netns_id { + /* This is CRIU's id which is allocated for each namespace */ + required uint32 target_ns_id = 1; + /* + * This is an id which can be used to address this namespace + * from another network namespace. Each network namespace has + * one set of id-s for other namespaces. + */ + required int32 netnsid_value = 2; +} + message netns_entry { repeated int32 def_conf = 1; repeated int32 all_conf = 2; @@ -54,4 +67,6 @@ message netns_entry { repeated sysctl_entry def_conf6 = 5; repeated sysctl_entry all_conf6 = 6; + + repeated netns_id nsids = 7; } From b79267b58437db6e59466106a7982590f9edc998 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 17 Dec 2016 05:59:22 +0300 Subject: [PATCH 1215/4375] kerndat: check whether a kernel supports netns id-s or not Each network namespaces has a list of ID-s for other namespaces, so if we request infomation about a veth device, we get an id for a namespace of a peer device. These ID-s can be set by users or by kernel when they are required. CRIU has to restore these ID-s for network namespaces. We have to remember that one netns can have different id-s in different network namespaces. Signed-off-by: Andrei Vagin --- criu/cr-check.c | 28 ++++++ criu/include/kerndat.h | 2 + criu/include/net.h | 4 + criu/kerndat.c | 28 ++++++ criu/net.c | 216 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 278 insertions(+) diff --git a/criu/cr-check.c b/criu/cr-check.c index 8f3a965a6..f67b3445f 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1209,6 +1209,32 @@ static int check_tun(void) return check_tun_cr(-1); } +static int check_nsid(void) +{ + if (kerndat_nsid() < 0) + return -1; + + if (!kdat.has_nsid) { + pr_warn("NSID isn't supported\n"); + return -1; + } + + return 0; +} + +static int check_link_nsid(void) +{ + if (kerndat_link_nsid() < 0) + return -1; + + if (!kdat.has_link_nsid) { + pr_warn("NSID isn't supported\n"); + return -1; + } + + return 0; +} + struct feature_list { char *name; int (*func)(); @@ -1233,6 +1259,8 @@ static struct feature_list feature_list[] = { { "uffd-noncoop", check_uffd_noncoop }, { "can_map_vdso", check_can_map_vdso}, { "sk_ns", check_sk_netns }, + { "nsid", check_nsid }, + { "link_nsid", check_link_nsid}, { NULL, NULL }, }; diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index a4922f174..785b13679 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -64,6 +64,8 @@ struct kerndat_s { struct vdso_symtable vdso_sym_compat; #endif #endif + bool has_nsid; + bool has_link_nsid; }; extern struct kerndat_s kdat; diff --git a/criu/include/net.h b/criu/include/net.h index 49eca365b..9af6f4481 100644 --- a/criu/include/net.h +++ b/criu/include/net.h @@ -43,4 +43,8 @@ extern int veth_pair_add(char *in, char *out); extern int macvlan_ext_add(struct external *ext); extern int move_veth_to_bridge(void); +extern int kerndat_link_nsid(void); +extern int net_get_nsid(int rtsk, int fd, int *nsid); +extern int kerndat_nsid(void); + #endif /* __CR_NET_H__ */ diff --git a/criu/kerndat.c b/criu/kerndat.c index 156b1c617..1870721de 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -28,6 +28,7 @@ #include "proc_parse.h" #include "sk-inet.h" #include "sockets.h" +#include "net.h" #include #include #include "netfilter.h" @@ -558,6 +559,27 @@ err: return exit_code; } +int kerndat_nsid(void) +{ + int nsid, sk; + + sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (sk < 0) { + pr_perror("Unable to create a netlink socket"); + return -1; + } + + if (net_get_nsid(sk, getpid(), &nsid) < 0) { + pr_err("NSID is not supported\n"); + close(sk); + return -1; + } + + kdat.has_nsid = true; + close(sk); + return 0; +} + static int kerndat_compat_restore(void) { int ret; @@ -860,6 +882,10 @@ int kerndat_init(void) ret = kerndat_tcp_repair(); if (!ret) ret = kerndat_compat_restore(); + if (!ret) + ret = kerndat_socket_netns(); + if (!ret) + ret = kerndat_nsid(); if (!ret) ret = kerndat_has_memfd_create(); if (!ret) @@ -876,6 +902,8 @@ int kerndat_init(void) ret = kerndat_vdso_preserves_hint(); if (!ret) ret = kerndat_socket_netns(); + if (!ret) + ret = kerndat_nsid(); kerndat_lsm(); kerndat_mmap_min_addr(); diff --git a/criu/net.c b/criu/net.c index d29ef6c56..22e538437 100644 --- a/criu/net.c +++ b/criu/net.c @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include #include "../soccr/soccr.h" @@ -41,6 +43,8 @@ #ifndef IFLA_LINK_NETNSID #define IFLA_LINK_NETNSID 37 +#undef IFLA_MAX +#define IFLA_MAX IFLA_LINK_NETNSID #endif #ifndef RTM_NEWNSID @@ -2430,3 +2434,215 @@ int move_veth_to_bridge(void) return ret; } + +#if NLA_TYPE_MAX < 14 +#define NLA_S32 14 +#endif + +#ifndef NETNSA_MAX +/* Attributes of RTM_NEWNSID/RTM_GETNSID messages */ +enum { + NETNSA_NONE, +#define NETNSA_NSID_NOT_ASSIGNED -1 + NETNSA_NSID, + NETNSA_PID, + NETNSA_FD, + __NETNSA_MAX, +}; + +#define NETNSA_MAX (__NETNSA_MAX - 1) +#endif + +static struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = { + [NETNSA_NONE] = { .type = NLA_UNSPEC }, + [NETNSA_NSID] = { .type = NLA_S32 }, + [NETNSA_PID] = { .type = NLA_U32 }, + [NETNSA_FD] = { .type = NLA_U32 }, +}; + +static int nsid_cb(struct nlmsghdr *msg, struct ns_id *ns, void *arg) +{ + struct nlattr *tb[NETNSA_MAX + 1]; + int err; + + err = nlmsg_parse(msg, sizeof(struct rtgenmsg), tb, + NETNSA_MAX, rtnl_net_policy); + if (err < 0) + return NL_STOP; + + if (tb[NETNSA_NSID]) + *((int *)arg) = nla_get_s32(tb[NETNSA_NSID]); + + return 0; +} + +int net_get_nsid(int rtsk, int pid, int *nsid) +{ + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + char msg[128]; + } req; + int32_t id = INT_MIN; + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); + req.nlh.nlmsg_type = RTM_GETNSID; + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.nlh.nlmsg_seq = CR_NLMSG_SEQ; + if (addattr_l(&req.nlh, sizeof(req), NETNSA_PID, &pid, sizeof(pid))) + return -1; + + if (do_rtnl_req(rtsk, &req, req.nlh.nlmsg_len, nsid_cb, NULL, NULL, (void *) &id) < 0) + return -1; + + if (id == INT_MIN) + return -1; + + *nsid = id; + + return 0; +} + + +static int nsid_link_info(NetDeviceEntry *nde, struct newlink_req *req) +{ + struct rtattr *veth_data, *peer_data; + struct ifinfomsg ifm; + + addattr_l(&req->h, sizeof(*req), IFLA_INFO_KIND, "veth", 4); + + veth_data = NLMSG_TAIL(&req->h); + addattr_l(&req->h, sizeof(*req), IFLA_INFO_DATA, NULL, 0); + peer_data = NLMSG_TAIL(&req->h); + memset(&ifm, 0, sizeof(ifm)); + + ifm.ifi_index = nde->peer_ifindex; + addattr_l(&req->h, sizeof(*req), VETH_INFO_PEER, &ifm, sizeof(ifm)); + + addattr_l(&req->h, sizeof(*req), IFLA_NET_NS_FD, &nde->peer_nsid, sizeof(int)); + peer_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)peer_data; + veth_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)veth_data; + + return 0; +} + +static int check_one_link_nsid(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) +{ + bool *has_link_nsid = arg; + struct ifinfomsg *ifi; + int len = hdr->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)); + struct nlattr *tb[IFLA_MAX + 1]; + + ifi = NLMSG_DATA(hdr); + + if (len < 0) { + pr_err("No iflas for link %d\n", ifi->ifi_index); + return -1; + } + + nlmsg_parse(hdr, sizeof(struct ifinfomsg), tb, IFLA_MAX, NULL); + pr_info("\tLD: Got link %d, type %d\n", ifi->ifi_index, ifi->ifi_type); + + if (tb[IFLA_LINK_NETNSID]) + *has_link_nsid = true; + + return 0; +} + +static int check_link_nsid(int rtsk, void *args) +{ + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + + pr_info("Dumping netns links\n"); + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = sizeof(req); + req.nlh.nlmsg_type = RTM_GETLINK; + req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = CR_NLMSG_SEQ; + req.g.rtgen_family = AF_PACKET; + + return do_rtnl_req(rtsk, &req, sizeof(req), check_one_link_nsid, NULL, NULL, args); +} + +int kerndat_link_nsid() +{ + int status; + pid_t pid; + + pid = fork(); + if (pid < 0) { + pr_perror("Unable to fork a process"); + return -1; + } + + if (pid == 0) { + NetDeviceEntry nde = NET_DEVICE_ENTRY__INIT; + int nsfd, sk, ret; + + sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (sk < 0) { + pr_perror("Unable to create a netlink socket"); + exit(1); + } + + if (unshare(CLONE_NEWNET)) { + pr_perror("Unable create a network namespace"); + exit(1); + } + + nsfd = open_proc(PROC_SELF, "ns/net"); + if (nsfd < 0) + exit(1); + + if (unshare(CLONE_NEWNET)) { + pr_perror("Unable create a network namespace"); + exit(1); + } + + nde.type = ND_TYPE__VETH; + nde.name = "veth"; + nde.ifindex = 10; + nde.mtu = 1500; + nde.peer_nsid = nsfd; + nde.peer_ifindex = 11; + nde.has_peer_ifindex = true; + nde.has_peer_nsid = true; + + ret = restore_one_link(&nde, sk, nsid_link_info, NULL); + if (ret) { + pr_err("Unable to create a veth pair: %d\n", ret); + exit(1); + } + + bool has_link_nsid = false; + if (check_link_nsid(sk, &has_link_nsid)) + exit(1); + + if (!has_link_nsid) + exit(5); + + close(sk); + + exit(0); + } + + if (waitpid(pid, &status, 0) != pid) { + pr_perror("Unable to wait a process"); + return -1; + } + + if (status) { + pr_warn("NSID isn't reported for network links\n"); + return -1; + } + + kdat.has_link_nsid = true; + + return 0; +} From 805dddad0b70a607625f35d41cec10e115ab073b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 17 Dec 2016 06:31:21 +0300 Subject: [PATCH 1216/4375] netlink: add nla_get_s32() This function was added into libnl3 recently, but we have to support old versions of this library. Signed-off-by: Andrei Vagin --- criu/include/libnetlink.h | 2 ++ criu/libnetlink.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/criu/include/libnetlink.h b/criu/include/libnetlink.h index b2980ffbc..bf2eb2474 100644 --- a/criu/include/libnetlink.h +++ b/criu/include/libnetlink.h @@ -11,6 +11,8 @@ extern int do_rtnl_req(int nl, void *req, int size, extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen); +extern int32_t nla_get_s32(const struct nlattr *nla); + #define NLMSG_TAIL(nmsg) \ ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) diff --git a/criu/libnetlink.c b/criu/libnetlink.c index f585f0907..986a05bca 100644 --- a/criu/libnetlink.c +++ b/criu/libnetlink.c @@ -219,3 +219,8 @@ int __wrap_nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), nlmsg_attrlen(nlh, hdrlen), policy); } + +int32_t nla_get_s32(const struct nlattr *nla) +{ + return *(const int32_t *) nla_data(nla); +} From 2e8069f2a5be102a54101288f848da8c1b634ad1 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 17 Dec 2016 09:33:55 +0300 Subject: [PATCH 1217/4375] net: transfer ns_id structures to functions about c/r-ing netns It will be used to get or set netns id-s. Signed-off-by: Andrei Vagin --- criu/include/net.h | 3 ++- criu/namespaces.c | 2 +- criu/net.c | 66 +++++++++++++++++++++++----------------------- 3 files changed, 36 insertions(+), 35 deletions(-) diff --git a/criu/include/net.h b/criu/include/net.h index 9af6f4481..72275b8a4 100644 --- a/criu/include/net.h +++ b/criu/include/net.h @@ -11,7 +11,8 @@ #endif struct cr_imgset; -extern int dump_net_ns(int ns_id); +struct ns_id; +extern int dump_net_ns(struct ns_id *ns); extern int prepare_net_namespaces(void); extern void fini_net_namespaces(void); extern int netns_keep_nsfd(void); diff --git a/criu/namespaces.c b/criu/namespaces.c index 1fd3f8a2b..0e6823025 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -985,7 +985,7 @@ static int do_dump_namespaces(struct ns_id *ns) case CLONE_NEWNET: pr_info("Dump NET namespace info %d via %d\n", ns->id, ns->ns_pid); - ret = dump_net_ns(ns->id); + ret = dump_net_ns(ns); break; default: pr_err("Unknown namespace flag %x\n", ns->nd->cflag); diff --git a/criu/net.c b/criu/net.c index 22e538437..7e8a396c0 100644 --- a/criu/net.c +++ b/criu/net.c @@ -391,7 +391,7 @@ int write_netdev_img(NetDeviceEntry *nde, struct cr_imgset *fds, struct nlattr * } static int dump_one_netdev(int type, struct ifinfomsg *ifi, - struct nlattr **tb, struct cr_imgset *fds, + struct nlattr **tb, struct ns_id *ns, struct cr_imgset *fds, int (*dump)(NetDeviceEntry *, struct cr_imgset *, struct nlattr **info)) { int ret = -1; @@ -507,13 +507,13 @@ static char *link_kind(struct ifinfomsg *ifi, struct nlattr **tb) } static int dump_unknown_device(struct ifinfomsg *ifi, char *kind, - struct nlattr **tb, struct cr_imgset *fds) + struct nlattr **tb, struct ns_id *ns, struct cr_imgset *fds) { int ret; ret = run_plugins(DUMP_EXT_LINK, ifi->ifi_index, ifi->ifi_type, kind); if (ret == 0) - return dump_one_netdev(ND_TYPE__EXTLINK, ifi, tb, fds, NULL); + return dump_one_netdev(ND_TYPE__EXTLINK, ifi, tb, ns, fds, NULL); if (ret == -ENOTSUP) pr_err("Unsupported link %d (type %d kind %s)\n", @@ -588,7 +588,7 @@ static int dump_macvlan(NetDeviceEntry *nde, struct cr_imgset *imgset, struct nl } static int dump_one_ethernet(struct ifinfomsg *ifi, char *kind, - struct nlattr **tb, struct cr_imgset *fds) + struct nlattr **tb, struct ns_id *ns, struct cr_imgset *fds) { if (!strcmp(kind, "veth")) /* @@ -599,11 +599,11 @@ static int dump_one_ethernet(struct ifinfomsg *ifi, char *kind, * Sigh... we have to assume, that the veth device is a * connection to the outer world and just dump this end :( */ - return dump_one_netdev(ND_TYPE__VETH, ifi, tb, fds, NULL); + return dump_one_netdev(ND_TYPE__VETH, ifi, tb, ns, fds, NULL); if (!strcmp(kind, "tun")) - return dump_one_netdev(ND_TYPE__TUN, ifi, tb, fds, dump_tun_link); + return dump_one_netdev(ND_TYPE__TUN, ifi, tb, ns, fds, dump_tun_link); if (!strcmp(kind, "bridge")) - return dump_one_netdev(ND_TYPE__BRIDGE, ifi, tb, fds, dump_bridge); + return dump_one_netdev(ND_TYPE__BRIDGE, ifi, tb, ns, fds, dump_bridge); if (!strcmp(kind, "gretap")) { char *name = (char *)RTA_DATA(tb[IFLA_IFNAME]); @@ -620,31 +620,31 @@ static int dump_one_ethernet(struct ifinfomsg *ifi, char *kind, pr_warn("GRE tap device %s not supported natively\n", name); } if (!strcmp(kind, "macvlan")) - return dump_one_netdev(ND_TYPE__MACVLAN, ifi, tb, fds, dump_macvlan); + return dump_one_netdev(ND_TYPE__MACVLAN, ifi, tb, ns, fds, dump_macvlan); - return dump_unknown_device(ifi, kind, tb, fds); + return dump_unknown_device(ifi, kind, tb, ns, fds); } static int dump_one_gendev(struct ifinfomsg *ifi, char *kind, - struct nlattr **tb, struct cr_imgset *fds) + struct nlattr **tb, struct ns_id *ns, struct cr_imgset *fds) { if (!strcmp(kind, "tun")) - return dump_one_netdev(ND_TYPE__TUN, ifi, tb, fds, dump_tun_link); + return dump_one_netdev(ND_TYPE__TUN, ifi, tb, ns, fds, dump_tun_link); - return dump_unknown_device(ifi, kind, tb, fds); + return dump_unknown_device(ifi, kind, tb, ns, fds); } static int dump_one_voiddev(struct ifinfomsg *ifi, char *kind, - struct nlattr **tb, struct cr_imgset *fds) + struct nlattr **tb, struct ns_id *ns, struct cr_imgset *fds) { if (!strcmp(kind, "venet")) - return dump_one_netdev(ND_TYPE__VENET, ifi, tb, fds, NULL); + return dump_one_netdev(ND_TYPE__VENET, ifi, tb, ns, fds, NULL); - return dump_unknown_device(ifi, kind, tb, fds); + return dump_unknown_device(ifi, kind, tb, ns, fds); } static int dump_one_gre(struct ifinfomsg *ifi, char *kind, - struct nlattr **tb, struct cr_imgset *fds) + struct nlattr **tb, struct ns_id *ns, struct cr_imgset *fds) { if (!strcmp(kind, "gre")) { char *name = (char *)RTA_DATA(tb[IFLA_IFNAME]); @@ -661,7 +661,7 @@ static int dump_one_gre(struct ifinfomsg *ifi, char *kind, pr_warn("GRE tunnel device %s not supported natively\n", name); } - return dump_unknown_device(ifi, kind, tb, fds); + return dump_unknown_device(ifi, kind, tb, ns, fds); } static int dump_sit(NetDeviceEntry *nde, struct cr_imgset *imgset, struct nlattr **info) @@ -807,7 +807,7 @@ static int dump_one_link(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) pr_info("\tLD: Got link %d, type %d\n", ifi->ifi_index, ifi->ifi_type); if (ifi->ifi_type == ARPHRD_LOOPBACK) - return dump_one_netdev(ND_TYPE__LOOPBACK, ifi, tb, fds, NULL); + return dump_one_netdev(ND_TYPE__LOOPBACK, ifi, tb, ns, fds, NULL); kind = link_kind(ifi, tb); if (!kind) @@ -815,23 +815,23 @@ static int dump_one_link(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) switch (ifi->ifi_type) { case ARPHRD_ETHER: - ret = dump_one_ethernet(ifi, kind, tb, fds); + ret = dump_one_ethernet(ifi, kind, tb, ns, fds); break; case ARPHRD_NONE: - ret = dump_one_gendev(ifi, kind, tb, fds); + ret = dump_one_gendev(ifi, kind, tb, ns, fds); break; case ARPHRD_VOID: - ret = dump_one_voiddev(ifi, kind, tb, fds); + ret = dump_one_voiddev(ifi, kind, tb, ns, fds); break; case ARPHRD_IPGRE: - ret = dump_one_gre(ifi, kind, tb, fds); + ret = dump_one_gre(ifi, kind, tb, ns, fds); break; case ARPHRD_SIT: ret = dump_one_sit(ifi, kind, tb, fds); break; default: unk: - ret = dump_unknown_device(ifi, kind, tb, fds); + ret = dump_unknown_device(ifi, kind, tb, ns, fds); break; } @@ -1007,7 +1007,7 @@ out: } -static int dump_links(struct cr_imgset *fds) +static int dump_links(struct ns_id *ns, struct cr_imgset *fds) { int sk, ret; struct { @@ -1031,7 +1031,7 @@ static int dump_links(struct cr_imgset *fds) req.nlh.nlmsg_seq = CR_NLMSG_SEQ; req.g.rtgen_family = AF_PACKET; - ret = do_rtnl_req(sk, &req, sizeof(req), dump_one_link, NULL, NULL, fds); + ret = do_rtnl_req(sk, &req, sizeof(req), dump_one_link, NULL, ns, fds); close(sk); out: return ret; @@ -1610,7 +1610,7 @@ static inline int dump_iptables(struct cr_imgset *fds) return 0; } -static int dump_netns_conf(struct cr_imgset *fds) +static int dump_netns_conf(struct ns_id *ns, struct cr_imgset *fds) { void *buf, *o_buf; int ret = -1; @@ -1871,21 +1871,21 @@ static int mount_ns_sysfs(void) return ns_sysfs_fd >= 0 ? 0 : -1; } -int dump_net_ns(int ns_id) +int dump_net_ns(struct ns_id *ns) { struct cr_imgset *fds; int ret; - fds = cr_imgset_open(ns_id, NETNS, O_DUMP); + fds = cr_imgset_open(ns->id, NETNS, O_DUMP); if (fds == NULL) return -1; ret = mount_ns_sysfs(); if (!(opts.empty_ns & CLONE_NEWNET)) { if (!ret) - ret = dump_netns_conf(fds); + ret = dump_netns_conf(ns, fds); if (!ret) - ret = dump_links(fds); + ret = dump_links(ns, fds); if (!ret) ret = dump_ifaddr(fds); if (!ret) @@ -1907,9 +1907,9 @@ int dump_net_ns(int ns_id) return ret; } -static int prepare_net_ns(int nsid) +static int prepare_net_ns(struct ns_id *ns) { - int ret = 0; + int ret = 0, nsid = ns->id; NetnsEntry *netns = NULL; if (!(opts.empty_ns & CLONE_NEWNET)) { @@ -1963,7 +1963,7 @@ static int do_create_net_ns(struct ns_id *ns) pr_perror("Unable to create a new netns"); return -1; } - if (prepare_net_ns(ns->id)) + if (prepare_net_ns(ns)) return -1; if (open_net_ns(ns)) return -1; From 1db8e1680fb87354d2f0d8c2755ef97b41c5c7fd Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 17 Dec 2016 09:35:35 +0300 Subject: [PATCH 1218/4375] netns: create a netlink route socket out of dump_links() It will be used to dump netns id-s too. Signed-off-by: Andrei Vagin --- criu/net.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/criu/net.c b/criu/net.c index 7e8a396c0..40a8393fa 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1007,9 +1007,8 @@ out: } -static int dump_links(struct ns_id *ns, struct cr_imgset *fds) +static int dump_links(int rtsk, struct ns_id *ns, struct cr_imgset *fds) { - int sk, ret; struct { struct nlmsghdr nlh; struct rtgenmsg g; @@ -1017,12 +1016,6 @@ static int dump_links(struct ns_id *ns, struct cr_imgset *fds) pr_info("Dumping netns links\n"); - ret = sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (sk < 0) { - pr_perror("Can't open rtnl sock for net dump"); - goto out; - } - memset(&req, 0, sizeof(req)); req.nlh.nlmsg_len = sizeof(req); req.nlh.nlmsg_type = RTM_GETLINK; @@ -1031,10 +1024,7 @@ static int dump_links(struct ns_id *ns, struct cr_imgset *fds) req.nlh.nlmsg_seq = CR_NLMSG_SEQ; req.g.rtgen_family = AF_PACKET; - ret = do_rtnl_req(sk, &req, sizeof(req), dump_one_link, NULL, ns, fds); - close(sk); -out: - return ret; + return do_rtnl_req(rtsk, &req, sizeof(req), dump_one_link, NULL, ns, fds); } static int restore_link_cb(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) @@ -1882,10 +1872,19 @@ int dump_net_ns(struct ns_id *ns) ret = mount_ns_sysfs(); if (!(opts.empty_ns & CLONE_NEWNET)) { + int sk; + + sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (sk < 0) { + pr_perror("Can't open rtnl sock for net dump"); + ret = -1; + } + if (!ret) - ret = dump_netns_conf(ns, fds); - if (!ret) - ret = dump_links(ns, fds); + ret = dump_links(sk, ns, fds); + + close(sk); + if (!ret) ret = dump_ifaddr(fds); if (!ret) @@ -1894,6 +1893,8 @@ int dump_net_ns(struct ns_id *ns) ret = dump_rule(fds); if (!ret) ret = dump_iptables(fds); + if (!ret) + ret = dump_netns_conf(ns, fds); } if (!ret) ret = dump_nf_ct(fds, CR_FD_NETNF_CT); From 9a2c99c343a04ab0c28cccefb480c27e6d2621bb Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 20 Dec 2016 01:21:13 +0300 Subject: [PATCH 1219/4375] netns: dump and restore network namespace ID-s In each network namespace we can set an id for another network namespace to be able to address it in netlink messages. For example, we can say that a peer of a veth devices has to be created in a network namespace with a specified id. If we request information about a veth device, a kernel will report where a peer device lives. An user are able to set this ID-s, so we have to dump and restore them. v2: add more commetns v3: make a union of nsfd_id and ns_fd, they are not used together Signed-off-by: Andrei Vagin --- criu/include/namespaces.h | 23 ++++- criu/namespaces.c | 7 ++ criu/net.c | 203 +++++++++++++++++++++++++++++++++++--- 3 files changed, 221 insertions(+), 12 deletions(-) diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index 1b454e0c1..47024d2d9 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -71,6 +71,12 @@ enum ns_type { NS_OTHER, }; +struct netns_id { + unsigned target_ns_id; + unsigned netnsid_value; + struct list_head node; +}; + struct ns_id { unsigned int kid; unsigned int id; @@ -96,9 +102,24 @@ struct ns_id { } mnt; struct { - int nsfd_id; /* a namespace descriptor id in fdstore */ + + /* + * ns_fd is used when network namespaces are being + * restored. On this stage we access these file + * descriptors many times and it is more efficient to + * have them opened rather than to get them from fdstore. + * + * nsfd_id is used to restore sockets. On this stage we + * can't use random file descriptors to not conflict + * with restored file descriptors. + */ + union { + int nsfd_id; /* a namespace descriptor id in fdstore */ + int ns_fd; /* a namespace file descriptor */ + }; int nlsk; /* for sockets collection */ int seqsk; /* to talk to parasite daemons */ + struct list_head ids; } net; }; }; diff --git a/criu/namespaces.c b/criu/namespaces.c index 0e6823025..63933428d 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -299,6 +299,9 @@ struct ns_id *rst_new_ns_id(unsigned int id, pid_t pid, nsid->type = type; nsid_add(nsid, nd, id, pid); nsid->ns_populated = false; + + if (nd == &net_ns_desc) + INIT_LIST_HEAD(&nsid->net.ids); } return nsid; @@ -420,6 +423,10 @@ static unsigned int generate_ns_id(int pid, unsigned int kid, struct ns_desc *nd nsid->ns_populated = true; nsid_add(nsid, nd, ns_next_id++, pid); + if (nd == &net_ns_desc) { + INIT_LIST_HEAD(&nsid->net.ids); + } + found: if (ns_ret) *ns_ret = nsid; diff --git a/criu/net.c b/criu/net.c index 40a8393fa..e88ecfec2 100644 --- a/criu/net.c +++ b/criu/net.c @@ -788,6 +788,11 @@ static int dump_one_sit(struct ifinfomsg *ifi, char *kind, return dump_one_netdev(ND_TYPE__SIT, ifi, tb, fds, dump_sit); } +static int list_one_link(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) +{ + return 0; +} + static int dump_one_link(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) { struct cr_imgset *fds = arg; @@ -1007,6 +1012,34 @@ out: } +/* + * When we request information about a link, the kernel shows + * information about the pair device (netns id and idx). + * If a pair device lives in another namespace and this namespace + * doesn't have a netns ID in the current namespace, the kernel + * will generate it. So we need to list all links, before dumping + * netns indexes. + */ +static int list_links(int rtsk, void *args) +{ + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + + pr_info("Dumping netns links\n"); + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = sizeof(req); + req.nlh.nlmsg_type = RTM_GETLINK; + req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = CR_NLMSG_SEQ; + req.g.rtgen_family = AF_PACKET; + + return do_rtnl_req(rtsk, &req, sizeof(req), list_one_link, NULL, NULL, args); +} + static int dump_links(int rtsk, struct ns_id *ns, struct cr_imgset *fds) { struct { @@ -1612,14 +1645,33 @@ static int dump_netns_conf(struct ns_id *ns, struct cr_imgset *fds) int size6 = ARRAY_SIZE(devconfs6); char def_stable_secret[MAX_STR_CONF_LEN + 1] = {}; char all_stable_secret[MAX_STR_CONF_LEN + 1] = {}; + NetnsId *ids; + struct netns_id *p; + + i = 0; + list_for_each_entry(p, &ns->net.ids, node) + i++; o_buf = buf = xmalloc( + i * (sizeof(NetnsId*) + sizeof(NetnsId)) + size4 * (sizeof(SysctlEntry*) + sizeof(SysctlEntry)) * 2 + size6 * (sizeof(SysctlEntry*) + sizeof(SysctlEntry)) * 2 ); if (!buf) goto out; + netns.nsids = xptr_pull_s(&buf, i * sizeof(NetnsId*)); + ids = xptr_pull_s(&buf, i * sizeof(NetnsId)); + i = 0; + list_for_each_entry(p, &ns->net.ids, node) { + netns_id__init(&ids[i]); + ids[i].target_ns_id = p->target_ns_id; + ids[i].netnsid_value = p->netnsid_value; + netns.nsids[i] = ids + i; + i++; + } + netns.n_nsids = i; + netns.n_def_conf4 = size4; netns.n_all_conf4 = size4; netns.def_conf4 = xptr_pull_s(&buf, size4 * sizeof(SysctlEntry*)); @@ -1861,6 +1913,46 @@ static int mount_ns_sysfs(void) return ns_sysfs_fd >= 0 ? 0 : -1; } +struct net_id_arg { + struct ns_id *ns; + int sk; +}; + +static int collect_netns_id(struct ns_id *ns, void *oarg) +{ + struct net_id_arg *arg = oarg; + struct netns_id *netns_id; + int nsid = -1; + + if (net_get_nsid(arg->sk, ns->ns_pid, &nsid)) + return -1; + + if (nsid == -1) + return 0; + + netns_id = xmalloc(sizeof(*netns_id)); + if (!netns_id) + return -1; + + pr_debug("Fount the %d id for %d in %d\n", nsid, ns->id, arg->ns->id); + netns_id->target_ns_id = ns->id; + netns_id->netnsid_value = nsid; + + list_add(&netns_id->node, &arg->ns->net.ids); + + return 0; +} + +static int dump_netns_ids(int rtsk, struct ns_id *ns) +{ + struct net_id_arg arg = { + .ns = ns, + .sk = rtsk, + }; + return walk_namespaces(&net_ns_desc, collect_netns_id, + (void *)&arg); +} + int dump_net_ns(struct ns_id *ns) { struct cr_imgset *fds; @@ -1880,6 +1972,17 @@ int dump_net_ns(struct ns_id *ns) ret = -1; } + /* + * If a device has a pair in another netns, the kernel generates + * a netns ID for this netns when we request information about + * the link. + * So we need to get information about all links to be sure that + * all related net namespaces have got netns id-s in this netns. + */ + if (!ret) + ret = list_links(sk, NULL); + if (!ret) + ret = dump_netns_ids(sk, ns); if (!ret) ret = dump_links(sk, ns, fds); @@ -1908,6 +2011,45 @@ int dump_net_ns(struct ns_id *ns) return ret; } +static int net_set_nsid(int rtsk, int fd, int nsid); +static int restore_netns_ids(struct ns_id *ns, NetnsEntry *netns) +{ + int i, sk, exit_code = -1; + + sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (sk < 0) { + pr_perror("Can't open rtnl sock for net dump"); + return -1; + } + + for (i = 0; i < netns->n_nsids; i++) { + struct ns_id *tg_ns; + struct netns_id *id; + + id = xmalloc(sizeof(*id)); + if (!id) + goto out; + id->target_ns_id = netns->nsids[i]->target_ns_id; + id->netnsid_value = netns->nsids[i]->netnsid_value; + list_add(&id->node, &ns->net.ids); + + tg_ns = lookup_ns_by_id(id->target_ns_id, &net_ns_desc); + if (tg_ns == NULL) { + pr_err("Unknown namespace: %d\n", id->target_ns_id); + goto out; + } + + if (net_set_nsid(sk, tg_ns->net.ns_fd, id->netnsid_value)) + goto out; + } + + exit_code = 0; +out: + close(sk); + + return exit_code; +} + static int prepare_net_ns(struct ns_id *ns) { int ret = 0, nsid = ns->id; @@ -1915,6 +2057,8 @@ static int prepare_net_ns(struct ns_id *ns) if (!(opts.empty_ns & CLONE_NEWNET)) { ret = restore_netns_conf(nsid, &netns); + if (!ret) + ret = restore_netns_ids(ns, netns); if (!ret) ret = restore_links(nsid, &netns); if (netns) @@ -1935,25 +2079,29 @@ static int prepare_net_ns(struct ns_id *ns) if (!ret) ret = restore_nf_ct(nsid, CR_FD_NETNF_EXP); + if (!ret) { + int fd = ns->net.ns_fd; + + ns->net.nsfd_id = fdstore_add(fd); + if (ns->net.nsfd_id < 0) + ret = -1; + close(fd); + } + + ns->ns_populated = true; + return ret; } static int open_net_ns(struct ns_id *nsid) { - int fd, id; + int fd; /* Pin one with a file descriptor */ fd = open_proc(PROC_SELF, "ns/net"); if (fd < 0) return -1; - - id = fdstore_add(fd); - close(fd); - if (id < 0) { - return -1; - } - - nsid->net.nsfd_id = id; + nsid->net.ns_fd = fd; return 0; } @@ -1964,8 +2112,6 @@ static int do_create_net_ns(struct ns_id *ns) pr_perror("Unable to create a new netns"); return -1; } - if (prepare_net_ns(ns)) - return -1; if (open_net_ns(ns)) return -1; return 0; @@ -1986,6 +2132,17 @@ int prepare_net_namespaces() goto err; } + for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { + if (nsid->nd != &net_ns_desc) + continue; + + if (switch_ns_by_fd(nsid->net.ns_fd, &net_ns_desc, NULL)) + goto err; + + if (prepare_net_ns(nsid)) + goto err; + } + close_service_fd(NS_FD_OFF); return 0; @@ -2477,6 +2634,30 @@ static int nsid_cb(struct nlmsghdr *msg, struct ns_id *ns, void *arg) return 0; } +static int net_set_nsid(int rtsk, int fd, int nsid) +{ + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + char msg[128]; + } req; + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); + req.nlh.nlmsg_type = RTM_NEWNSID; + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.nlh.nlmsg_seq = CR_NLMSG_SEQ; + if (addattr_l(&req.nlh, sizeof(req), NETNSA_FD, &fd, sizeof(fd))) + return -1; + if (addattr_l(&req.nlh, sizeof(req), NETNSA_NSID, &nsid, sizeof(nsid))) + return -1; + + if (do_rtnl_req(rtsk, &req, req.nlh.nlmsg_len, NULL, NULL, NULL, NULL) < 0) + return -1; + + return 0; +} + int net_get_nsid(int rtsk, int pid, int *nsid) { struct { From 7dc4b34e1c6c38f06224a905c46681bc4b73a479 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 7 Feb 2017 23:11:42 +0300 Subject: [PATCH 1220/4375] net: give ns_id to link_info functions It will be used to restore links in different net namesapces. Signed-off-by: Andrei Vagin --- criu/net.c | 72 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/criu/net.c b/criu/net.c index e88ecfec2..3f3316e24 100644 --- a/criu/net.c +++ b/criu/net.c @@ -765,7 +765,7 @@ skip:; } static int dump_one_sit(struct ifinfomsg *ifi, char *kind, - struct nlattr **tb, struct cr_imgset *fds) + struct nlattr **tb, struct ns_id *ns, struct cr_imgset *fds) { char *name; @@ -785,7 +785,7 @@ static int dump_one_sit(struct ifinfomsg *ifi, char *kind, return 0; } - return dump_one_netdev(ND_TYPE__SIT, ifi, tb, fds, dump_sit); + return dump_one_netdev(ND_TYPE__SIT, ifi, tb, ns, fds, dump_sit); } static int list_one_link(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) @@ -832,7 +832,7 @@ static int dump_one_link(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) ret = dump_one_gre(ifi, kind, tb, ns, fds); break; case ARPHRD_SIT: - ret = dump_one_sit(ifi, kind, tb, fds); + ret = dump_one_sit(ifi, kind, tb, ns, fds); break; default: unk: @@ -1080,8 +1080,11 @@ struct newlink_extras { int target_netns; /* IFLA_NET_NS_FD */ }; -static int populate_newlink_req(struct newlink_req *req, int msg_type, NetDeviceEntry *nde, - int (*link_info)(NetDeviceEntry *, struct newlink_req *), struct newlink_extras *extras) +typedef int (*link_info_t)(struct ns_id *ns, NetDeviceEntry *, struct newlink_req *); + +static int populate_newlink_req(struct ns_id *ns, struct newlink_req *req, + int msg_type, NetDeviceEntry *nde, + link_info_t link_info, struct newlink_extras *extras) { memset(req, 0, sizeof(*req)); @@ -1125,7 +1128,7 @@ static int populate_newlink_req(struct newlink_req *req, int msg_type, NetDevice linkinfo = NLMSG_TAIL(&req->h); addattr_l(&req->h, sizeof(*req), IFLA_LINKINFO, NULL, 0); - ret = link_info(nde, req); + ret = link_info(ns, nde, req); if (ret < 0) return ret; @@ -1135,13 +1138,13 @@ static int populate_newlink_req(struct newlink_req *req, int msg_type, NetDevice return 0; } -static int do_rtm_link_req(int msg_type, NetDeviceEntry *nde, int nlsk, - int (*link_info)(NetDeviceEntry *, struct newlink_req *), - struct newlink_extras *extras) +static int do_rtm_link_req(int msg_type, + NetDeviceEntry *nde, int nlsk, struct ns_id *ns, + link_info_t link_info, struct newlink_extras *extras) { struct newlink_req req; - if (populate_newlink_req(&req, msg_type, nde, link_info, extras) < 0) + if (populate_newlink_req(ns, &req, msg_type, nde, link_info, extras) < 0) return -1; return do_rtnl_req(nlsk, &req, req.h.nlmsg_len, restore_link_cb, NULL, NULL, NULL); @@ -1149,15 +1152,14 @@ static int do_rtm_link_req(int msg_type, NetDeviceEntry *nde, int nlsk, int restore_link_parms(NetDeviceEntry *nde, int nlsk) { - return do_rtm_link_req(RTM_SETLINK, nde, nlsk, NULL, NULL); + return do_rtm_link_req(RTM_SETLINK, nde, nlsk, NULL, NULL, NULL); } -static int restore_one_link(NetDeviceEntry *nde, int nlsk, - int (*link_info)(NetDeviceEntry *, struct newlink_req *), - struct newlink_extras *extras) +static int restore_one_link(struct ns_id *ns, NetDeviceEntry *nde, int nlsk, + link_info_t link_info, struct newlink_extras *extras) { pr_info("Restoring netdev %s idx %d\n", nde->name, nde->ifindex); - return do_rtm_link_req(RTM_NEWLINK, nde, nlsk, link_info, extras); + return do_rtm_link_req(RTM_NEWLINK, nde, nlsk, ns, link_info, extras); } #ifndef VETH_INFO_MAX @@ -1188,7 +1190,7 @@ static void veth_peer_info(NetDeviceEntry *nde, struct newlink_req *req) } } -static int veth_link_info(NetDeviceEntry *nde, struct newlink_req *req) +static int veth_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req) { int ns_fd = get_service_fd(NS_FD_OFF); struct rtattr *veth_data, *peer_data; @@ -1211,7 +1213,7 @@ static int veth_link_info(NetDeviceEntry *nde, struct newlink_req *req) return 0; } -static int venet_link_info(NetDeviceEntry *nde, struct newlink_req *req) +static int venet_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req) { int ns_fd = get_service_fd(NS_FD_OFF); struct rtattr *venet_data; @@ -1227,7 +1229,7 @@ static int venet_link_info(NetDeviceEntry *nde, struct newlink_req *req) return 0; } -static int bridge_link_info(NetDeviceEntry *nde, struct newlink_req *req) +static int bridge_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req) { struct rtattr *bridge_data; @@ -1253,7 +1255,7 @@ static int changeflags(int s, char *name, short flags) return 0; } -static int macvlan_link_info(NetDeviceEntry *nde, struct newlink_req *req) +static int macvlan_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req) { struct rtattr *macvlan_data; MacvlanLinkEntry *macvlan = nde->macvlan; @@ -1307,7 +1309,7 @@ out: return ret; } -static int restore_one_macvlan(NetDeviceEntry *nde, int nlsk, int criu_nlsk) +static int restore_one_macvlan(struct ns_id *ns, NetDeviceEntry *nde, int nlsk, int criu_nlsk) { struct newlink_extras extras = { .link = -1, @@ -1342,7 +1344,7 @@ static int restore_one_macvlan(NetDeviceEntry *nde, int nlsk, int criu_nlsk) { struct newlink_req req; - if (populate_newlink_req(&req, RTM_NEWLINK, nde, macvlan_link_info, &extras) < 0) + if (populate_newlink_req(ns, &req, RTM_NEWLINK, nde, macvlan_link_info, &extras) < 0) goto out; if (userns_call(userns_restore_one_link, 0, &req, sizeof(req), my_netns) < 0) { @@ -1358,7 +1360,7 @@ out: return ret; } -static int sit_link_info(NetDeviceEntry *nde, struct newlink_req *req) +static int sit_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req) { struct rtattr *sit_data; SitEntry *se = nde->sit; @@ -1446,7 +1448,7 @@ skip:; return 0; } -static int restore_link(NetDeviceEntry *nde, int nlsk, int criu_nlsk) +static int restore_link(struct ns_id *ns, NetDeviceEntry *nde, int nlsk, int criu_nlsk) { pr_info("Restoring link %s type %d\n", nde->name, nde->type); @@ -1455,17 +1457,17 @@ static int restore_link(NetDeviceEntry *nde, int nlsk, int criu_nlsk) case ND_TYPE__EXTLINK: /* see comment in images/netdev.proto */ return restore_link_parms(nde, nlsk); case ND_TYPE__VENET: - return restore_one_link(nde, nlsk, venet_link_info, NULL); + return restore_one_link(ns, nde, nlsk, venet_link_info, NULL); case ND_TYPE__VETH: - return restore_one_link(nde, nlsk, veth_link_info, NULL); + return restore_one_link(ns, nde, nlsk, veth_link_info, NULL); case ND_TYPE__TUN: return restore_one_tun(nde, nlsk); case ND_TYPE__BRIDGE: - return restore_one_link(nde, nlsk, bridge_link_info, NULL); + return restore_one_link(ns, nde, nlsk, bridge_link_info, NULL); case ND_TYPE__MACVLAN: - return restore_one_macvlan(nde, nlsk, criu_nlsk); + return restore_one_macvlan(ns, nde, nlsk, criu_nlsk); case ND_TYPE__SIT: - return restore_one_link(nde, nlsk, sit_link_info, NULL); + return restore_one_link(ns, nde, nlsk, sit_link_info, NULL); default: pr_err("Unsupported link type %d\n", nde->type); break; @@ -1474,13 +1476,13 @@ static int restore_link(NetDeviceEntry *nde, int nlsk, int criu_nlsk) return -1; } -static int restore_links(int pid, NetnsEntry **netns) +static int restore_links(struct ns_id *ns, NetnsEntry **netns) { - int nlsk, criu_nlsk = -1, ret = -1; + int nlsk, criu_nlsk = -1, ret = -1, id = ns->id; struct cr_img *img; NetDeviceEntry *nde; - img = open_image(CR_FD_NETDEV, O_RSTR, pid); + img = open_image(CR_FD_NETDEV, O_RSTR, id); if (!img) return -1; @@ -1498,7 +1500,7 @@ static int restore_links(int pid, NetnsEntry **netns) if (ret <= 0) break; - ret = restore_link(nde, nlsk, criu_nlsk); + ret = restore_link(ns, nde, nlsk, criu_nlsk); if (ret) { pr_err("Can't restore link\n"); goto exit; @@ -2060,7 +2062,7 @@ static int prepare_net_ns(struct ns_id *ns) if (!ret) ret = restore_netns_ids(ns, netns); if (!ret) - ret = restore_links(nsid, &netns); + ret = restore_links(ns, &netns); if (netns) netns_entry__free_unpacked(netns, NULL); @@ -2687,7 +2689,7 @@ int net_get_nsid(int rtsk, int pid, int *nsid) } -static int nsid_link_info(NetDeviceEntry *nde, struct newlink_req *req) +static int nsid_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req) { struct rtattr *veth_data, *peer_data; struct ifinfomsg ifm; @@ -2796,7 +2798,7 @@ int kerndat_link_nsid() nde.has_peer_ifindex = true; nde.has_peer_nsid = true; - ret = restore_one_link(&nde, sk, nsid_link_info, NULL); + ret = restore_one_link(NULL, &nde, sk, nsid_link_info, NULL); if (ret) { pr_err("Unable to create a veth pair: %d\n", ret); exit(1); From 6aa4a9c2f1f7444abea2fbf88cd19d50e98838f7 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 17 Dec 2016 09:10:27 +0300 Subject: [PATCH 1221/4375] netns: restore internal veth devices When we dump a veth device, the kernel reports where a peer device lives and we use this information to restore this veth pair. On restore we set a net ns id for a peer and it is created in the required netns. v2: add more comments Signed-off-by: Andrei Vagin --- criu/include/namespaces.h | 7 +++ criu/namespaces.c | 5 +- criu/net.c | 101 +++++++++++++++++++++++++++++++--- scripts/build/Dockerfile.tmpl | 1 + scripts/travis/travis-tests | 2 +- 5 files changed, 106 insertions(+), 10 deletions(-) diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index 47024d2d9..15b9699c0 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -77,6 +77,12 @@ struct netns_id { struct list_head node; }; +struct net_link { + unsigned int ifindex; + bool created; + struct list_head node; +}; + struct ns_id { unsigned int kid; unsigned int id; @@ -120,6 +126,7 @@ struct ns_id { int nlsk; /* for sockets collection */ int seqsk; /* to talk to parasite daemons */ struct list_head ids; + struct list_head links; } net; }; }; diff --git a/criu/namespaces.c b/criu/namespaces.c index 63933428d..0f1e1a6fe 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -300,8 +300,10 @@ struct ns_id *rst_new_ns_id(unsigned int id, pid_t pid, nsid_add(nsid, nd, id, pid); nsid->ns_populated = false; - if (nd == &net_ns_desc) + if (nd == &net_ns_desc) { INIT_LIST_HEAD(&nsid->net.ids); + INIT_LIST_HEAD(&nsid->net.links); + } } return nsid; @@ -425,6 +427,7 @@ static unsigned int generate_ns_id(int pid, unsigned int kid, struct ns_desc *nd if (nd == &net_ns_desc) { INIT_LIST_HEAD(&nsid->net.ids); + INIT_LIST_HEAD(&nsid->net.links); } found: diff --git a/criu/net.c b/criu/net.c index 3f3316e24..92aa6d9d1 100644 --- a/criu/net.c +++ b/criu/net.c @@ -390,12 +390,22 @@ int write_netdev_img(NetDeviceEntry *nde, struct cr_imgset *fds, struct nlattr * return pb_write_one(img_from_set(fds, CR_FD_NETDEV), nde, PB_NETDEV); } +static int lookup_net_by_netid(struct ns_id *ns, int net_id) +{ + struct netns_id *p; + + list_for_each_entry(p, &ns->net.ids, node) + if (p->netnsid_value == net_id) + return p->target_ns_id; + + return -1; +} + static int dump_one_netdev(int type, struct ifinfomsg *ifi, struct nlattr **tb, struct ns_id *ns, struct cr_imgset *fds, int (*dump)(NetDeviceEntry *, struct cr_imgset *, struct nlattr **info)) { - int ret = -1; - int i; + int ret = -1, i, peer_ifindex; NetDeviceEntry netdev = NET_DEVICE_ENTRY__INIT; SysctlEntry *confs4 = NULL; int size4 = ARRAY_SIZE(devconfs4); @@ -415,6 +425,39 @@ static int dump_one_netdev(int type, struct ifinfomsg *ifi, netdev.flags = ifi->ifi_flags; netdev.name = RTA_DATA(tb[IFLA_IFNAME]); + if (kdat.has_nsid) { + s32 nsid = -1; + + peer_ifindex = ifi->ifi_index; + if (tb[IFLA_LINK]) + peer_ifindex = nla_get_u32(tb[IFLA_LINK]); + + netdev.has_peer_ifindex = true; + netdev.peer_ifindex = peer_ifindex; + + if (tb[IFLA_LINK_NETNSID]) + nsid = nla_get_s32(tb[IFLA_LINK_NETNSID]); + + pr_debug("The peer link is in the %d netns with the %u index\n", + nsid, netdev.peer_ifindex); + + if (nsid == -1) + nsid = ns->id; + else + nsid = lookup_net_by_netid(ns, nsid); + if (nsid < 0) { + pr_warn("The %s veth is in an external netns\n", + netdev.name); + } else { + netdev.has_peer_nsid = true; + netdev.peer_nsid = nsid; + } + } + /* + * If kdat.has_nsid is false, a multiple network namespaces are not dumped, + * so if we are here, this means only one netns is dumped. + */ + if (tb[IFLA_ADDRESS] && (type != ND_TYPE__LOOPBACK)) { netdev.has_address = true; netdev.address.data = nla_data(tb[IFLA_ADDRESS]); @@ -1176,9 +1219,11 @@ enum { #define IFLA_NET_NS_FD 28 #endif -static void veth_peer_info(NetDeviceEntry *nde, struct newlink_req *req) +static int veth_peer_info(NetDeviceEntry *nde, struct newlink_req *req, + struct ns_id *ns, int ns_fd) { char key[100], *val; + struct ns_id *peer_ns = NULL; snprintf(key, sizeof(key), "veth[%s]", nde->name); val = external_lookup_by_key(key); @@ -1187,7 +1232,47 @@ static void veth_peer_info(NetDeviceEntry *nde, struct newlink_req *req) aux = strchrnul(val, '@'); addattr_l(&req->h, sizeof(*req), IFLA_IFNAME, val, aux - val); + addattr_l(&req->h, sizeof(*req), IFLA_NET_NS_FD, &ns_fd, sizeof(ns_fd)); + return 0; } + + if (nde->has_peer_nsid) { + if (ns && nde->peer_nsid == ns->id) { + struct net_link *link; + + list_for_each_entry(link, &ns->net.links, node) + if (link->ifindex == nde->peer_ifindex && link->created) { + pr_err("%d\n", nde->peer_ifindex); + req->h.nlmsg_type = RTM_SETLINK; + return 0; + } + } + peer_ns = lookup_ns_by_id(nde->peer_nsid, &net_ns_desc); + if (peer_ns->ns_populated) { + req->h.nlmsg_type = RTM_SETLINK; + return 0; + } + } + + if (peer_ns) { + if (ns && nde->peer_nsid == ns->id) { + struct net_link *link; + + link = xmalloc(sizeof(*link)); + if (link == NULL) + return -1; + + link->ifindex = nde->ifindex; + link->created = true; + list_add(&link->node, &ns->net.links); + } + + addattr_l(&req->h, sizeof(*req), IFLA_NET_NS_FD, &peer_ns->net.ns_fd, sizeof(int)); + return 0; + } + + pr_err("Unknown peer net namespace"); + return -1; } static int veth_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req) @@ -1196,17 +1281,17 @@ static int veth_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_ struct rtattr *veth_data, *peer_data; struct ifinfomsg ifm; - BUG_ON(ns_fd < 0); - addattr_l(&req->h, sizeof(*req), IFLA_INFO_KIND, "veth", 4); veth_data = NLMSG_TAIL(&req->h); addattr_l(&req->h, sizeof(*req), IFLA_INFO_DATA, NULL, 0); peer_data = NLMSG_TAIL(&req->h); memset(&ifm, 0, sizeof(ifm)); + + ifm.ifi_index = nde->peer_ifindex; addattr_l(&req->h, sizeof(*req), VETH_INFO_PEER, &ifm, sizeof(ifm)); - veth_peer_info(nde, req); - addattr_l(&req->h, sizeof(*req), IFLA_NET_NS_FD, &ns_fd, sizeof(ns_fd)); + + veth_peer_info(nde, req, ns, ns_fd); peer_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)peer_data; veth_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)veth_data; @@ -1502,7 +1587,7 @@ static int restore_links(struct ns_id *ns, NetnsEntry **netns) ret = restore_link(ns, nde, nlsk, criu_nlsk); if (ret) { - pr_err("Can't restore link\n"); + pr_err("Can't restore link: %d\n", ret); goto exit; } diff --git a/scripts/build/Dockerfile.tmpl b/scripts/build/Dockerfile.tmpl index ec0242965..c562af329 100644 --- a/scripts/build/Dockerfile.tmpl +++ b/scripts/build/Dockerfile.tmpl @@ -13,6 +13,7 @@ RUN apt-get update && apt-get install -y \ libcap-dev \ iptables \ libnl-3-dev \ + libnl-route-3-dev \ libselinux-dev \ pkg-config \ git-core \ diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 3d9d5a221..6cfc81f52 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -4,7 +4,7 @@ set -x -e TRAVIS_PKGS="protobuf-c-compiler libprotobuf-c0-dev libaio-dev libprotobuf-dev protobuf-compiler python-ipaddr libcap-dev libnl-3-dev gcc-multilib gdb bash python-protobuf - libnet-dev util-linux asciidoc xmlto" + libnet-dev util-linux asciidoc xmlto libnl-route-3-dev" travis_prep () { [ -n "$SKIP_TRAVIS_PREP" ] && return From 8cb26b02e6b3b81848300a13cd7dbc3d423d4889 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 22 Mar 2017 02:50:05 +0300 Subject: [PATCH 1222/4375] net: split restore_links on read and restore parts It's a preparation for enumirating links a few times. Signed-off-by: Andrei Vagin --- criu/include/namespaces.h | 4 +- criu/namespaces.c | 1 + criu/net.c | 161 +++++++++++++++++++++++--------------- 3 files changed, 103 insertions(+), 63 deletions(-) diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index 15b9699c0..d68a7b76c 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -4,6 +4,7 @@ #include "common/compiler.h" #include "files.h" #include "common/list.h" +#include "images/netdev.pb-c.h" #ifndef CLONE_NEWNS #define CLONE_NEWNS 0x00020000 @@ -78,7 +79,7 @@ struct netns_id { }; struct net_link { - unsigned int ifindex; + NetDeviceEntry *nde; bool created; struct list_head node; }; @@ -127,6 +128,7 @@ struct ns_id { int seqsk; /* to talk to parasite daemons */ struct list_head ids; struct list_head links; + NetnsEntry *netns; } net; }; }; diff --git a/criu/namespaces.c b/criu/namespaces.c index 0f1e1a6fe..c237d79c7 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -303,6 +303,7 @@ struct ns_id *rst_new_ns_id(unsigned int id, pid_t pid, if (nd == &net_ns_desc) { INIT_LIST_HEAD(&nsid->net.ids); INIT_LIST_HEAD(&nsid->net.links); + nsid->net.netns = NULL; } } diff --git a/criu/net.c b/criu/net.c index 92aa6d9d1..39ffafd6b 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1241,7 +1241,7 @@ static int veth_peer_info(NetDeviceEntry *nde, struct newlink_req *req, struct net_link *link; list_for_each_entry(link, &ns->net.links, node) - if (link->ifindex == nde->peer_ifindex && link->created) { + if (link->nde->ifindex == nde->peer_ifindex && link->created) { pr_err("%d\n", nde->peer_ifindex); req->h.nlmsg_type = RTM_SETLINK; return 0; @@ -1262,7 +1262,6 @@ static int veth_peer_info(NetDeviceEntry *nde, struct newlink_req *req, if (link == NULL) return -1; - link->ifindex = nde->ifindex; link->created = true; list_add(&link->node, &ns->net.links); } @@ -1394,7 +1393,7 @@ out: return ret; } -static int restore_one_macvlan(struct ns_id *ns, NetDeviceEntry *nde, int nlsk, int criu_nlsk) +static int restore_one_macvlan(struct ns_id *ns, NetDeviceEntry *nde, int nlsk) { struct newlink_extras extras = { .link = -1, @@ -1533,7 +1532,7 @@ skip:; return 0; } -static int restore_link(struct ns_id *ns, NetDeviceEntry *nde, int nlsk, int criu_nlsk) +static int __restore_link(struct ns_id *ns, NetDeviceEntry *nde, int nlsk) { pr_info("Restoring link %s type %d\n", nde->name, nde->type); @@ -1550,7 +1549,7 @@ static int restore_link(struct ns_id *ns, NetDeviceEntry *nde, int nlsk, int cri case ND_TYPE__BRIDGE: return restore_one_link(ns, nde, nlsk, bridge_link_info, NULL); case ND_TYPE__MACVLAN: - return restore_one_macvlan(ns, nde, nlsk, criu_nlsk); + return restore_one_macvlan(ns, nde, nlsk); case ND_TYPE__SIT: return restore_one_link(ns, nde, nlsk, sit_link_info, NULL); default: @@ -1561,9 +1560,9 @@ static int restore_link(struct ns_id *ns, NetDeviceEntry *nde, int nlsk, int cri return -1; } -static int restore_links(struct ns_id *ns, NetnsEntry **netns) +static int read_links(struct ns_id *ns) { - int nlsk, criu_nlsk = -1, ret = -1, id = ns->id; + int ret = -1, id = ns->id; struct cr_img *img; NetDeviceEntry *nde; @@ -1571,54 +1570,87 @@ static int restore_links(struct ns_id *ns, NetnsEntry **netns) if (!img) return -1; - nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (nlsk < 0) { - pr_perror("Can't create nlk socket"); - close_image(img); - return -1; - } - while (1) { - NetnsEntry **def_netns = netns; + struct net_link *link; ret = pb_read_one_eof(img, &nde, PB_NETDEV); if (ret <= 0) break; - ret = restore_link(ns, nde, nlsk, criu_nlsk); - if (ret) { - pr_err("Can't restore link: %d\n", ret); - goto exit; + link = xmalloc(sizeof(*link)); + if (link == NULL) { + ret = -1; + net_device_entry__free_unpacked(nde, NULL); + break; } - /* - * optimize restore of devices configuration except lo - * lo is created with namespace and before default is set - * so we can't optimize its restore - */ - if (nde->type == ND_TYPE__LOOPBACK) - def_netns = NULL; + link->nde = nde; + link->created = 0; + list_add(&link->node, &ns->net.links); + } + close_image(img); - if (nde->conf4) - ret = ipv4_conf_op(nde->name, nde->conf4, nde->n_conf4, CTL_WRITE, def_netns ? (*def_netns)->def_conf4 : NULL); - else if (nde->conf) - ret = ipv4_conf_op_old(nde->name, nde->conf, nde->n_conf, CTL_WRITE, def_netns ? (*def_netns)->def_conf : NULL); - if (ret) - goto exit; + return 0; +} - if (nde->conf6) - ret = ipv6_conf_op(nde->name, nde->conf6, nde->n_conf6, CTL_WRITE, def_netns ? (*def_netns)->def_conf6 : NULL); -exit: - net_device_entry__free_unpacked(nde, NULL); - if (ret) - break; +static int restore_link(int nlsk, struct ns_id *ns, struct net_link *link) +{ + NetDeviceEntry *nde = link->nde; + NetnsEntry **def_netns = &ns->net.netns; + int ret; + + ret = __restore_link(ns, nde, nlsk); + if (ret) { + pr_err("Can't restore link: %d\n", ret); + goto exit; } - close(nlsk); - close_image(img); + /* + * optimize restore of devices configuration except lo + * lo is created with namespace and before default is set + * so we can't optimize its restore + */ + if (nde->type == ND_TYPE__LOOPBACK) + def_netns = NULL; + + if (nde->conf4) + ret = ipv4_conf_op(nde->name, nde->conf4, nde->n_conf4, CTL_WRITE, def_netns ? (*def_netns)->def_conf4 : NULL); + else if (nde->conf) + ret = ipv4_conf_op_old(nde->name, nde->conf, nde->n_conf, CTL_WRITE, def_netns ? (*def_netns)->def_conf : NULL); + if (ret) + goto exit; + + if (nde->conf6) + ret = ipv6_conf_op(nde->name, nde->conf6, nde->n_conf6, CTL_WRITE, def_netns ? (*def_netns)->def_conf6 : NULL); +exit: return ret; } +static int restore_links(struct ns_id *ns) +{ + struct net_link *link, *t; + int exit_code = -1, nlsk; + + nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (nlsk < 0) { + pr_perror("Can't create nlk socket"); + return -1; + } + + list_for_each_entry_safe(link, t, &ns->net.links, node) { + if (restore_link(nlsk, ns, link)) + goto out; + xfree(link); + } + + exit_code = 0; +out: + close(nlsk); + + return exit_code; +} + + static int run_ip_tool(char *arg1, char *arg2, char *arg3, char *arg4, int fdin, int fdout, unsigned flags) { char *ip_tool_cmd; @@ -1913,12 +1945,13 @@ out: return ret; } -static int restore_netns_conf(int pid, NetnsEntry **netns) +static int restore_netns_conf(struct ns_id *ns) { + NetnsEntry *netns; int ret = 0; struct cr_img *img; - img = open_image(CR_FD_NETNS, O_RSTR, pid); + img = open_image(CR_FD_NETNS, O_RSTR, ns->id); if (!img) return -1; @@ -1926,35 +1959,37 @@ static int restore_netns_conf(int pid, NetnsEntry **netns) /* Backward compatibility */ goto out; - ret = pb_read_one(img, netns, PB_NETNS); + ret = pb_read_one(img, &netns, PB_NETNS); if (ret < 0) { pr_err("Can not read netns object\n"); return -1; } - if ((*netns)->def_conf4) { - ret = ipv4_conf_op("all", (*netns)->all_conf4, (*netns)->n_all_conf4, CTL_WRITE, NULL); + if ((netns)->def_conf4) { + ret = ipv4_conf_op("all", (netns)->all_conf4, (netns)->n_all_conf4, CTL_WRITE, NULL); if (ret) goto out; - ret = ipv4_conf_op("default", (*netns)->def_conf4, (*netns)->n_def_conf4, CTL_WRITE, NULL); + ret = ipv4_conf_op("default", (netns)->def_conf4, (netns)->n_def_conf4, CTL_WRITE, NULL); if (ret) goto out; - } else if ((*netns)->def_conf) { + } else if ((netns)->def_conf) { /* Backward compatibility */ - ret = ipv4_conf_op_old("all", (*netns)->all_conf, (*netns)->n_all_conf, CTL_WRITE, NULL); + ret = ipv4_conf_op_old("all", (netns)->all_conf, (netns)->n_all_conf, CTL_WRITE, NULL); if (ret) goto out; - ret = ipv4_conf_op_old("default", (*netns)->def_conf, (*netns)->n_def_conf, CTL_WRITE, NULL); + ret = ipv4_conf_op_old("default", (netns)->def_conf, (netns)->n_def_conf, CTL_WRITE, NULL); if (ret) goto out; } - if ((*netns)->def_conf6) { - ret = ipv6_conf_op("all", (*netns)->all_conf6, (*netns)->n_all_conf6, CTL_WRITE, NULL); + if ((netns)->def_conf6) { + ret = ipv6_conf_op("all", (netns)->all_conf6, (netns)->n_all_conf6, CTL_WRITE, NULL); if (ret) goto out; - ret = ipv6_conf_op("default", (*netns)->def_conf6, (*netns)->n_def_conf6, CTL_WRITE, NULL); + ret = ipv6_conf_op("default", (netns)->def_conf6, (netns)->n_def_conf6, CTL_WRITE, NULL); } + + ns->net.netns = netns; out: close_image(img); return ret; @@ -2099,7 +2134,7 @@ int dump_net_ns(struct ns_id *ns) } static int net_set_nsid(int rtsk, int fd, int nsid); -static int restore_netns_ids(struct ns_id *ns, NetnsEntry *netns) +static int restore_netns_ids(struct ns_id *ns) { int i, sk, exit_code = -1; @@ -2109,15 +2144,15 @@ static int restore_netns_ids(struct ns_id *ns, NetnsEntry *netns) return -1; } - for (i = 0; i < netns->n_nsids; i++) { + for (i = 0; i < ns->net.netns->n_nsids; i++) { struct ns_id *tg_ns; struct netns_id *id; id = xmalloc(sizeof(*id)); if (!id) goto out; - id->target_ns_id = netns->nsids[i]->target_ns_id; - id->netnsid_value = netns->nsids[i]->netnsid_value; + id->target_ns_id = ns->net.netns->nsids[i]->target_ns_id; + id->netnsid_value = ns->net.netns->nsids[i]->netnsid_value; list_add(&id->node, &ns->net.ids); tg_ns = lookup_ns_by_id(id->target_ns_id, &net_ns_desc); @@ -2140,16 +2175,18 @@ out: static int prepare_net_ns(struct ns_id *ns) { int ret = 0, nsid = ns->id; - NetnsEntry *netns = NULL; if (!(opts.empty_ns & CLONE_NEWNET)) { - ret = restore_netns_conf(nsid, &netns); + ret = restore_netns_conf(ns); if (!ret) - ret = restore_netns_ids(ns, netns); + ret = restore_netns_ids(ns); if (!ret) - ret = restore_links(ns, &netns); - if (netns) - netns_entry__free_unpacked(netns, NULL); + ret = read_links(ns); + if (!ret) + ret = restore_links(ns); + + if (ns->net.netns) + netns_entry__free_unpacked(ns->net.netns, NULL); if (!ret) ret = restore_ifaddr(nsid); From 5b617ecde5ddcad0f5ff7849ca3ad18cb2534ce7 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 8 Feb 2017 02:55:19 +0300 Subject: [PATCH 1223/4375] net: create a list of all links We will need to enumirate links a few times Signed-off-by: Andrei Vagin --- criu/include/net.h | 3 +- criu/include/tun.h | 3 +- criu/net.c | 183 ++++++++++++++++++++++++++------------------- criu/tun.c | 5 +- 4 files changed, 114 insertions(+), 80 deletions(-) diff --git a/criu/include/net.h b/criu/include/net.h index 72275b8a4..796dcc415 100644 --- a/criu/include/net.h +++ b/criu/include/net.h @@ -38,7 +38,8 @@ extern struct ns_desc net_ns_desc; #include "images/netdev.pb-c.h" extern int write_netdev_img(NetDeviceEntry *nde, struct cr_imgset *fds, struct nlattr **info); extern int read_ns_sys_file(char *path, char *buf, int len); -extern int restore_link_parms(NetDeviceEntry *nde, int nlsk); +struct net_link; +extern int restore_link_parms(struct net_link *link, int nlsk); extern int veth_pair_add(char *in, char *out); extern int macvlan_ext_add(struct external *ext); diff --git a/criu/include/tun.h b/criu/include/tun.h index c1434aea7..2d0aa8e08 100644 --- a/criu/include/tun.h +++ b/criu/include/tun.h @@ -11,7 +11,8 @@ extern const struct fdtype_ops tunfile_dump_ops; extern int dump_tun_link(NetDeviceEntry *nde, struct cr_imgset *fds, struct nlattr **info); -extern int restore_one_tun(NetDeviceEntry *nde, int nlsk); +struct net_link; +extern int restore_one_tun(struct net_link *link, int nlsk); extern struct collect_image_info tunfile_cinfo; extern int check_tun_cr(int no_tun_err); diff --git a/criu/net.c b/criu/net.c index 39ffafd6b..ca404ca7f 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1123,12 +1123,14 @@ struct newlink_extras { int target_netns; /* IFLA_NET_NS_FD */ }; -typedef int (*link_info_t)(struct ns_id *ns, NetDeviceEntry *, struct newlink_req *); +typedef int (*link_info_t)(struct ns_id *ns, struct net_link *, struct newlink_req *); static int populate_newlink_req(struct ns_id *ns, struct newlink_req *req, - int msg_type, NetDeviceEntry *nde, + int msg_type, struct net_link * link, link_info_t link_info, struct newlink_extras *extras) { + NetDeviceEntry *nde = link->nde; + memset(req, 0, sizeof(*req)); req->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); @@ -1171,7 +1173,7 @@ static int populate_newlink_req(struct ns_id *ns, struct newlink_req *req, linkinfo = NLMSG_TAIL(&req->h); addattr_l(&req->h, sizeof(*req), IFLA_LINKINFO, NULL, 0); - ret = link_info(ns, nde, req); + ret = link_info(ns, link, req); if (ret < 0) return ret; @@ -1182,27 +1184,27 @@ static int populate_newlink_req(struct ns_id *ns, struct newlink_req *req, } static int do_rtm_link_req(int msg_type, - NetDeviceEntry *nde, int nlsk, struct ns_id *ns, + struct net_link *link, int nlsk, struct ns_id *ns, link_info_t link_info, struct newlink_extras *extras) { struct newlink_req req; - if (populate_newlink_req(ns, &req, msg_type, nde, link_info, extras) < 0) + if (populate_newlink_req(ns, &req, msg_type, link, link_info, extras) < 0) return -1; return do_rtnl_req(nlsk, &req, req.h.nlmsg_len, restore_link_cb, NULL, NULL, NULL); } -int restore_link_parms(NetDeviceEntry *nde, int nlsk) +int restore_link_parms(struct net_link *link, int nlsk) { - return do_rtm_link_req(RTM_SETLINK, nde, nlsk, NULL, NULL, NULL); + return do_rtm_link_req(RTM_SETLINK, link, nlsk, NULL, NULL, NULL); } -static int restore_one_link(struct ns_id *ns, NetDeviceEntry *nde, int nlsk, +static int restore_one_link(struct ns_id *ns, struct net_link *link, int nlsk, link_info_t link_info, struct newlink_extras *extras) { - pr_info("Restoring netdev %s idx %d\n", nde->name, nde->ifindex); - return do_rtm_link_req(RTM_NEWLINK, nde, nlsk, ns, link_info, extras); + pr_info("Restoring netdev %s idx %d\n", link->nde->name, link->nde->ifindex); + return do_rtm_link_req(RTM_NEWLINK, link, nlsk, ns, link_info, extras); } #ifndef VETH_INFO_MAX @@ -1219,9 +1221,10 @@ enum { #define IFLA_NET_NS_FD 28 #endif -static int veth_peer_info(NetDeviceEntry *nde, struct newlink_req *req, +static int veth_peer_info(struct net_link *link, struct newlink_req *req, struct ns_id *ns, int ns_fd) { + NetDeviceEntry *nde = link->nde; char key[100], *val; struct ns_id *peer_ns = NULL; @@ -1237,46 +1240,33 @@ static int veth_peer_info(NetDeviceEntry *nde, struct newlink_req *req, } if (nde->has_peer_nsid) { - if (ns && nde->peer_nsid == ns->id) { - struct net_link *link; + struct net_link *plink; - list_for_each_entry(link, &ns->net.links, node) - if (link->nde->ifindex == nde->peer_ifindex && link->created) { - pr_err("%d\n", nde->peer_ifindex); - req->h.nlmsg_type = RTM_SETLINK; - return 0; - } - } peer_ns = lookup_ns_by_id(nde->peer_nsid, &net_ns_desc); - if (peer_ns->ns_populated) { - req->h.nlmsg_type = RTM_SETLINK; - return 0; + if (!peer_ns) + goto out; + list_for_each_entry(plink, &peer_ns->net.links, node) { + if (plink->nde->ifindex == nde->peer_ifindex && plink->created) { + req->h.nlmsg_type = RTM_SETLINK; + return 0; + } } } + link->created = true; if (peer_ns) { - if (ns && nde->peer_nsid == ns->id) { - struct net_link *link; - - link = xmalloc(sizeof(*link)); - if (link == NULL) - return -1; - - link->created = true; - list_add(&link->node, &ns->net.links); - } - addattr_l(&req->h, sizeof(*req), IFLA_NET_NS_FD, &peer_ns->net.ns_fd, sizeof(int)); return 0; } - +out: pr_err("Unknown peer net namespace"); return -1; } -static int veth_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req) +static int veth_link_info(struct ns_id *ns, struct net_link *link, struct newlink_req *req) { int ns_fd = get_service_fd(NS_FD_OFF); + NetDeviceEntry *nde = link->nde; struct rtattr *veth_data, *peer_data; struct ifinfomsg ifm; @@ -1290,14 +1280,14 @@ static int veth_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_ ifm.ifi_index = nde->peer_ifindex; addattr_l(&req->h, sizeof(*req), VETH_INFO_PEER, &ifm, sizeof(ifm)); - veth_peer_info(nde, req, ns, ns_fd); + veth_peer_info(link, req, ns, ns_fd); peer_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)peer_data; veth_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)veth_data; return 0; } -static int venet_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req) +static int venet_link_info(struct ns_id *ns, struct net_link *link, struct newlink_req *req) { int ns_fd = get_service_fd(NS_FD_OFF); struct rtattr *venet_data; @@ -1313,7 +1303,7 @@ static int venet_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink return 0; } -static int bridge_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req) +static int bridge_link_info(struct ns_id *ns, struct net_link *link, struct newlink_req *req) { struct rtattr *bridge_data; @@ -1339,9 +1329,10 @@ static int changeflags(int s, char *name, short flags) return 0; } -static int macvlan_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req) +static int macvlan_link_info(struct ns_id *ns, struct net_link *link, struct newlink_req *req) { struct rtattr *macvlan_data; + NetDeviceEntry *nde = link->nde; MacvlanLinkEntry *macvlan = nde->macvlan; if (!macvlan) { @@ -1393,7 +1384,7 @@ out: return ret; } -static int restore_one_macvlan(struct ns_id *ns, NetDeviceEntry *nde, int nlsk) +static int restore_one_macvlan(struct ns_id *ns, struct net_link *link, int nlsk) { struct newlink_extras extras = { .link = -1, @@ -1401,6 +1392,7 @@ static int restore_one_macvlan(struct ns_id *ns, NetDeviceEntry *nde, int nlsk) }; char key[100], *val; int my_netns = -1, ret = -1; + NetDeviceEntry *nde = link->nde; snprintf(key, sizeof(key), "macvlan[%s]", nde->name); val = external_lookup_data(key); @@ -1428,7 +1420,7 @@ static int restore_one_macvlan(struct ns_id *ns, NetDeviceEntry *nde, int nlsk) { struct newlink_req req; - if (populate_newlink_req(ns, &req, RTM_NEWLINK, nde, macvlan_link_info, &extras) < 0) + if (populate_newlink_req(ns, &req, RTM_NEWLINK, link, macvlan_link_info, &extras) < 0) goto out; if (userns_call(userns_restore_one_link, 0, &req, sizeof(req), my_netns) < 0) { @@ -1444,8 +1436,9 @@ out: return ret; } -static int sit_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req) +static int sit_link_info(struct ns_id *ns, struct net_link *link, struct newlink_req *req) { + NetDeviceEntry *nde = link->nde; struct rtattr *sit_data; SitEntry *se = nde->sit; @@ -1532,28 +1525,30 @@ skip:; return 0; } -static int __restore_link(struct ns_id *ns, NetDeviceEntry *nde, int nlsk) +static int __restore_link(struct ns_id *ns, struct net_link *link, int nlsk) { + NetDeviceEntry *nde = link->nde; + pr_info("Restoring link %s type %d\n", nde->name, nde->type); switch (nde->type) { case ND_TYPE__LOOPBACK: /* fallthrough */ case ND_TYPE__EXTLINK: /* see comment in images/netdev.proto */ - return restore_link_parms(nde, nlsk); + return restore_link_parms(link, nlsk); case ND_TYPE__VENET: - return restore_one_link(ns, nde, nlsk, venet_link_info, NULL); + return restore_one_link(ns, link, nlsk, venet_link_info, NULL); case ND_TYPE__VETH: - return restore_one_link(ns, nde, nlsk, veth_link_info, NULL); + return restore_one_link(ns, link, nlsk, veth_link_info, NULL); case ND_TYPE__TUN: - return restore_one_tun(nde, nlsk); + return restore_one_tun(link, nlsk); case ND_TYPE__BRIDGE: - return restore_one_link(ns, nde, nlsk, bridge_link_info, NULL); + return restore_one_link(ns, link, nlsk, bridge_link_info, NULL); case ND_TYPE__MACVLAN: - return restore_one_macvlan(ns, nde, nlsk); + return restore_one_macvlan(ns, link, nlsk); case ND_TYPE__SIT: - return restore_one_link(ns, nde, nlsk, sit_link_info, NULL); + return restore_one_link(ns, link, nlsk, sit_link_info, NULL); default: - pr_err("Unsupported link type %d\n", nde->type); + pr_err("Unsupported link type %d\n", link->nde->type); break; } @@ -1599,7 +1594,7 @@ static int restore_link(int nlsk, struct ns_id *ns, struct net_link *link) NetnsEntry **def_netns = &ns->net.netns; int ret; - ret = __restore_link(ns, nde, nlsk); + ret = __restore_link(ns, link, nlsk); if (ret) { pr_err("Can't restore link: %d\n", ret); goto exit; @@ -1626,26 +1621,35 @@ exit: return ret; } -static int restore_links(struct ns_id *ns) +static int restore_links() { struct net_link *link, *t; - int exit_code = -1, nlsk; + int exit_code = -1, nlsk = -1; + struct ns_id *nsid; - nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (nlsk < 0) { - pr_perror("Can't create nlk socket"); - return -1; - } + for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { + if (nsid->nd != &net_ns_desc) + continue; - list_for_each_entry_safe(link, t, &ns->net.links, node) { - if (restore_link(nlsk, ns, link)) + if (switch_ns_by_fd(nsid->net.ns_fd, &net_ns_desc, NULL)) goto out; - xfree(link); + + nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (nlsk < 0) { + pr_perror("Can't create nlk socket"); + return -1; + } + + list_for_each_entry_safe(link, t, &nsid->net.links, node) { + if (restore_link(nlsk, nsid, link)) + goto out; + } + close_safe(&nlsk); } exit_code = 0; out: - close(nlsk); + close_safe(&nlsk); return exit_code; } @@ -2172,19 +2176,27 @@ out: return exit_code; } -static int prepare_net_ns(struct ns_id *ns) +static int prepare_net_ns_first_stage(struct ns_id *ns) +{ + int ret = 0; + + if (opts.empty_ns & CLONE_NEWNET) + return 0; + + ret = restore_netns_conf(ns); + if (!ret) + ret = restore_netns_ids(ns); + if (!ret) + ret = read_links(ns); + + return ret; +} + +static int prepare_net_ns_second_stage(struct ns_id *ns) { int ret = 0, nsid = ns->id; if (!(opts.empty_ns & CLONE_NEWNET)) { - ret = restore_netns_conf(ns); - if (!ret) - ret = restore_netns_ids(ns); - if (!ret) - ret = read_links(ns); - if (!ret) - ret = restore_links(ns); - if (ns->net.netns) netns_entry__free_unpacked(ns->net.netns, NULL); @@ -2263,7 +2275,21 @@ int prepare_net_namespaces() if (switch_ns_by_fd(nsid->net.ns_fd, &net_ns_desc, NULL)) goto err; - if (prepare_net_ns(nsid)) + if (prepare_net_ns_first_stage(nsid)) + goto err; + } + + if (restore_links()) + goto err; + + for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { + if (nsid->nd != &net_ns_desc) + continue; + + if (switch_ns_by_fd(nsid->net.ns_fd, &net_ns_desc, NULL)) + goto err; + + if (prepare_net_ns_second_stage(nsid)) goto err; } @@ -2811,8 +2837,9 @@ int net_get_nsid(int rtsk, int pid, int *nsid) } -static int nsid_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req) +static int nsid_link_info(struct ns_id *ns, struct net_link *link, struct newlink_req *req) { + NetDeviceEntry *nde = link->nde; struct rtattr *veth_data, *peer_data; struct ifinfomsg ifm; @@ -2889,6 +2916,10 @@ int kerndat_link_nsid() if (pid == 0) { NetDeviceEntry nde = NET_DEVICE_ENTRY__INIT; + struct net_link link = { + .created = false, + .nde = &nde, + }; int nsfd, sk, ret; sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); @@ -2920,7 +2951,7 @@ int kerndat_link_nsid() nde.has_peer_ifindex = true; nde.has_peer_nsid = true; - ret = restore_one_link(NULL, &nde, sk, nsid_link_info, NULL); + ret = restore_one_link(NULL, &link, sk, nsid_link_info, NULL); if (ret) { pr_err("Unable to create a veth pair: %d\n", ret); exit(1); diff --git a/criu/tun.c b/criu/tun.c index 8dd95df59..acd40ea1e 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -439,8 +439,9 @@ int dump_tun_link(NetDeviceEntry *nde, struct cr_imgset *fds, struct nlattr **in return write_netdev_img(nde, fds, info); } -int restore_one_tun(NetDeviceEntry *nde, int nlsk) +int restore_one_tun(struct net_link *link, int nlsk) { + NetDeviceEntry *nde = link->nde; int fd, ret = -1, aux; if (!nde->tun) { @@ -489,7 +490,7 @@ int restore_one_tun(NetDeviceEntry *nde, int nlsk) goto out; } - if (restore_link_parms(nde, nlsk)) { + if (restore_link_parms(link, nlsk)) { pr_err("Error restoring %s link params\n", nde->name); goto out; } From f06369b9e287259c8e628939b98d76ac7ee69cb6 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 21 Dec 2016 05:05:18 +0300 Subject: [PATCH 1224/4375] net: dump and restore connected to a bridge links A network device, which is connected to a bridge, is restored after the bridge. In this case we can set the master attribute and the device will be connected to the bridge automatically. Signed-off-by: Andrei Vagin --- criu/net.c | 155 ++++++++++++++++++++++++++++++-------------- images/netdev.proto | 1 + 2 files changed, 107 insertions(+), 49 deletions(-) diff --git a/criu/net.c b/criu/net.c index ca404ca7f..9b5f1e492 100644 --- a/criu/net.c +++ b/criu/net.c @@ -467,6 +467,11 @@ static int dump_one_netdev(int type, struct ifinfomsg *ifi, (int)netdev.address.len, netdev.name); } + if (tb[IFLA_MASTER]) { + netdev.has_master = true; + netdev.master = nla_get_u32(tb[IFLA_MASTER]); + } + netdev.n_conf4 = size4; netdev.conf4 = xmalloc(sizeof(SysctlEntry *) * size4); if (!netdev.conf4) @@ -566,36 +571,6 @@ static int dump_unknown_device(struct ifinfomsg *ifi, char *kind, static int dump_bridge(NetDeviceEntry *nde, struct cr_imgset *imgset, struct nlattr **info) { - char spath[IFNAMSIZ + 16]; /* len("class/net//brif") + 1 for null */ - int ret, fd; - - ret = snprintf(spath, sizeof(spath), "class/net/%s/brif", nde->name); - if (ret < 0 || ret >= sizeof(spath)) - return -1; - - /* Let's only allow dumping empty bridges for now. To do a full bridge - * restore, we need to make sure the bridge and slaves are restored in - * the right order and attached correctly. It looks like the veth code - * supports this, but we need some way to do ordering. - */ - fd = openat(ns_sysfs_fd, spath, O_DIRECTORY, 0); - if (fd < 0) { - pr_perror("opening %s failed", spath); - return -1; - } - - ret = is_empty_dir(fd); - close(fd); - if (ret < 0) { - pr_perror("problem testing %s for emptiness", spath); - return -1; - } - - if (!ret) { - pr_err("dumping bridges with attached slaves not supported currently\n"); - return -1; - } - return write_netdev_img(nde, imgset, info); } @@ -1621,37 +1596,110 @@ exit: return ret; } -static int restore_links() +static int restore_master_link(int nlsk, struct ns_id *ns, struct net_link *link) +{ + struct newlink_req req; + + memset(&req, 0, sizeof(req)); + + req.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.h.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE; + req.h.nlmsg_type = RTM_SETLINK; + req.h.nlmsg_seq = CR_NLMSG_SEQ; + req.i.ifi_family = AF_PACKET; + req.i.ifi_index = link->nde->ifindex; + req.i.ifi_flags = link->nde->flags; + + addattr_l(&req.h, sizeof(req), IFLA_MASTER, + &link->nde->master, sizeof(link->nde->master)); + + return do_rtnl_req(nlsk, &req, req.h.nlmsg_len, restore_link_cb, NULL, NULL, NULL); +} + +struct net_link *lookup_net_link(struct ns_id *ns, uint32_t ifindex) +{ + struct net_link *link; + + list_for_each_entry(link, &ns->net.links, node) + if (link->nde->ifindex == ifindex) + return link; + + return NULL; +} + +static int __restore_links(struct ns_id *nsid, int *nrlinks, int *nrcreated) { struct net_link *link, *t; - int exit_code = -1, nlsk = -1; - struct ns_id *nsid; + int ret; - for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { - if (nsid->nd != &net_ns_desc) + list_for_each_entry_safe(link, t, &nsid->net.links, node) { + struct net_link *mlink = NULL; + + if (link->created) continue; - if (switch_ns_by_fd(nsid->net.ns_fd, &net_ns_desc, NULL)) - goto out; + (*nrlinks)++; - nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (nlsk < 0) { - pr_perror("Can't create nlk socket"); + pr_debug("Try to restore a link %d:%d:%s", + nsid->id, link->nde->ifindex, link->nde->name); + if (link->nde->has_master) { + mlink = lookup_net_link(nsid, link->nde->master); + if (mlink == NULL) { + pr_err("Unable to find the %d master\n", link->nde->master); + return -1; + } + + if (!mlink->created) { + pr_debug("The master %d:%d:%s isn't created yet", + nsid->id, mlink->nde->ifindex, mlink->nde->name); + continue; + } + } + + ret = restore_link(nsid->net.nlsk, nsid, link); + if (ret < 0) return -1; - } - list_for_each_entry_safe(link, t, &nsid->net.links, node) { - if (restore_link(nlsk, nsid, link)) - goto out; + if (ret == 0) { + (*nrcreated)++; + link->created = true; + + if (mlink && restore_master_link(nsid->net.nlsk, nsid, link)) + return -1; } - close_safe(&nlsk); } - exit_code = 0; -out: - close_safe(&nlsk); + return 0; +} - return exit_code; +static int restore_links() +{ + int nrcreated, nrlinks; + struct ns_id *nsid; + + while (true) { + nrcreated = 0; + nrlinks = 0; + for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { + if (nsid->nd != &net_ns_desc) + continue; + + if (switch_ns_by_fd(nsid->net.ns_fd, &net_ns_desc, NULL)) + return -1; + + if (__restore_links(nsid, &nrlinks, &nrcreated)) + return -1; + } + + if (nrcreated == nrlinks) + break; + if (nrcreated == 0) { + pr_err("Unable to restore network links"); + return -1; + } + } + + return 0; } @@ -2277,6 +2325,13 @@ int prepare_net_namespaces() if (prepare_net_ns_first_stage(nsid)) goto err; + + nsid->net.nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (nsid->net.nlsk < 0) { + pr_perror("Can't create nlk socket"); + goto err; + } + } if (restore_links()) @@ -2291,6 +2346,8 @@ int prepare_net_namespaces() if (prepare_net_ns_second_stage(nsid)) goto err; + + close_safe(&nsid->net.nlsk); } close_service_fd(NS_FD_OFF); diff --git a/images/netdev.proto b/images/netdev.proto index c15e5246a..b4b64d2cc 100644 --- a/images/netdev.proto +++ b/images/netdev.proto @@ -44,6 +44,7 @@ message net_device_entry { optional uint32 peer_ifindex = 12; optional uint32 peer_nsid = 13; + optional uint32 master = 14; optional sit_entry sit = 15; } From 98b5542c77463e8732d62e1603674eb7c8d2af51 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 17 Dec 2016 06:30:41 +0300 Subject: [PATCH 1225/4375] test: check veth devices from two network namespaces We shave a test case for external veth devices. This test case checks veth devices which are living in two dumped network namespaces. Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/netns_sub_veth.c | 179 +++++++++++++++++++++++++++ test/zdtm/static/netns_sub_veth.desc | 6 + 3 files changed, 186 insertions(+) create mode 100644 test/zdtm/static/netns_sub_veth.c create mode 100644 test/zdtm/static/netns_sub_veth.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index fbf79cc8e..fb288ca6c 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -195,6 +195,7 @@ TST_NOFILE := \ thread_different_uid_gid \ pipe03 \ netns_sub \ + netns_sub_veth \ # jobctl00 \ include ../Makefile.inc diff --git a/test/zdtm/static/netns_sub_veth.c b/test/zdtm/static/netns_sub_veth.c new file mode 100644 index 000000000..626245604 --- /dev/null +++ b/test/zdtm/static/netns_sub_veth.c @@ -0,0 +1,179 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check dump and restore a few network namespaces"; + +#define ID_MAP "0 0 1" +static int init_proc_id_maps(pid_t pid) +{ + char path[128]; + int fd; + + snprintf(path, sizeof(path), "/proc/%d/uid_map", pid); + fd = open(path, O_WRONLY); + if (fd < 0) { + pr_perror("Unable to open %s", path); + return -1; + } + if (write(fd, ID_MAP, sizeof(ID_MAP)) != sizeof(ID_MAP)) { + pr_perror("Unable to write into %s", path); + return -1; + } + close(fd); + + snprintf(path, sizeof(path), "/proc/%d/gid_map", pid); + fd = open(path, O_WRONLY); + if (fd < 0) { + pr_perror("Unable to open %s", path); + return -1; + } + if (write(fd, ID_MAP, sizeof(ID_MAP)) != sizeof(ID_MAP)) { + pr_perror("Unable to write into %s", path); + return -1; + } + close(fd); + + return 0; +} + +#ifndef NSIO +#define NSIO 0xb7 +#define NS_GET_USERNS _IO(NSIO, 0x1) +#define NS_GET_PARENT _IO(NSIO, 0x2) +#endif + +int main(int argc, char **argv) +{ + task_waiter_t lock; + pid_t pid[2]; + int status = -1, ret, i; + struct rtnl_link *link = NULL, *new; + struct nl_sock *sk; + int has_index = 1; + bool userns; + + test_init(argc, argv); + task_waiter_init(&lock); + + userns = getenv("ZDTM_USERNS") != NULL; + if (userns) { + int fd, ufd; + fd = open("/proc/self/ns/net", O_RDONLY); + if (fd < 0) { + pr_perror("Unable to open /proc/self/ns/net"); + return 1; + } + ufd = ioctl(fd, NS_GET_USERNS); + if (ufd < 0) { + userns = false; + } else + close(ufd); + close(fd); + } + + for (i = 0; i < 2; i++) { + pid[i] = fork(); + if (pid[i] < 0) { + pr_perror("fork"); + return -1; + } + if (pid[i] == 0) { + if (userns && unshare(CLONE_NEWUSER)) + return 1; + if (unshare(CLONE_NEWNET)) + return 1; + + task_waiter_complete(&lock, i); + test_waitsig(); + + return 0; + } + task_waiter_wait4(&lock, i); + if (userns && init_proc_id_maps(pid[i])) + return 1; + } + + sk = nl_socket_alloc(); + if (sk == NULL) + return -1; + + ret = nl_connect(sk, NETLINK_ROUTE); + if (ret < 0) { + nl_socket_free(sk); + pr_err("Unable to connect socket: %s", nl_geterror(ret)); + return -1; + } + + if (system("ip link add name zdtmbr type bridge")) + return -1; + + for (i = 0; i < 2; i++) { + char cmd[4096]; + + snprintf(cmd, sizeof(cmd), "ip link add name zdtm%d index %d netns %d type veth peer name zdtm%d index %d", + i, i * 10 + 12, pid[i], i, i * 10 + 12); + if (system(cmd)) { + has_index = 0; + snprintf(cmd, sizeof(cmd), "ip link add name zdtm%d netns %d type veth peer name zdtm%d", i, pid[i], i); + if (system(cmd)) + return 1; + } + snprintf(cmd, sizeof(cmd), "ip link set dev zdtm%d master zdtmbr", i); + if (system(cmd)) + return 1; + } + + test_daemon(); + test_waitsig(); + + for (i = 0; i < 2; i++) { + link = rtnl_link_alloc(); + new = rtnl_link_alloc(); + if (has_index) + rtnl_link_set_ifindex(link, i * 10 + 12); + else { + char name[43]; + snprintf(name, sizeof(name), "zdtm%d", i); + rtnl_link_set_name(link, name); + rtnl_link_set_name(new, name); + } + rtnl_link_set_flags(new, IFF_UP); + ret = rtnl_link_change(sk, link, new, 0); + if (ret) { + fail("Unable to up the link: %s", nl_geterror(ret)); + return 1; + } + } + + for (i = 0; i < 2; i++) { + kill(pid[i], SIGTERM); + waitpid(pid[i], &status, 0); + if (status) { + fail(); + return 1; + } + } + + pass(); + return 0; +} diff --git a/test/zdtm/static/netns_sub_veth.desc b/test/zdtm/static/netns_sub_veth.desc new file mode 100644 index 000000000..ea9e15c8a --- /dev/null +++ b/test/zdtm/static/netns_sub_veth.desc @@ -0,0 +1,6 @@ +{ + 'deps': ['/sbin/ip', '/bin/sh'], + 'flags': 'suid', + 'flavor': 'ns uns', + 'feature': 'link_nsid', +} From 35ad233fb98695ee8309bb84a54489cf1bb0bb93 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 15 Feb 2018 21:34:28 +0300 Subject: [PATCH 1226/4375] test/zdtm/static/netns_sub_veth.c --- test/zdtm/static/netns_sub_veth.c | 55 ------------------------------- 1 file changed, 55 deletions(-) diff --git a/test/zdtm/static/netns_sub_veth.c b/test/zdtm/static/netns_sub_veth.c index 626245604..927827199 100644 --- a/test/zdtm/static/netns_sub_veth.c +++ b/test/zdtm/static/netns_sub_veth.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include @@ -23,39 +22,6 @@ const char *test_doc = "Check dump and restore a few network namespaces"; -#define ID_MAP "0 0 1" -static int init_proc_id_maps(pid_t pid) -{ - char path[128]; - int fd; - - snprintf(path, sizeof(path), "/proc/%d/uid_map", pid); - fd = open(path, O_WRONLY); - if (fd < 0) { - pr_perror("Unable to open %s", path); - return -1; - } - if (write(fd, ID_MAP, sizeof(ID_MAP)) != sizeof(ID_MAP)) { - pr_perror("Unable to write into %s", path); - return -1; - } - close(fd); - - snprintf(path, sizeof(path), "/proc/%d/gid_map", pid); - fd = open(path, O_WRONLY); - if (fd < 0) { - pr_perror("Unable to open %s", path); - return -1; - } - if (write(fd, ID_MAP, sizeof(ID_MAP)) != sizeof(ID_MAP)) { - pr_perror("Unable to write into %s", path); - return -1; - } - close(fd); - - return 0; -} - #ifndef NSIO #define NSIO 0xb7 #define NS_GET_USERNS _IO(NSIO, 0x1) @@ -70,27 +36,10 @@ int main(int argc, char **argv) struct rtnl_link *link = NULL, *new; struct nl_sock *sk; int has_index = 1; - bool userns; test_init(argc, argv); task_waiter_init(&lock); - userns = getenv("ZDTM_USERNS") != NULL; - if (userns) { - int fd, ufd; - fd = open("/proc/self/ns/net", O_RDONLY); - if (fd < 0) { - pr_perror("Unable to open /proc/self/ns/net"); - return 1; - } - ufd = ioctl(fd, NS_GET_USERNS); - if (ufd < 0) { - userns = false; - } else - close(ufd); - close(fd); - } - for (i = 0; i < 2; i++) { pid[i] = fork(); if (pid[i] < 0) { @@ -98,8 +47,6 @@ int main(int argc, char **argv) return -1; } if (pid[i] == 0) { - if (userns && unshare(CLONE_NEWUSER)) - return 1; if (unshare(CLONE_NEWNET)) return 1; @@ -109,8 +56,6 @@ int main(int argc, char **argv) return 0; } task_waiter_wait4(&lock, i); - if (userns && init_proc_id_maps(pid[i])) - return 1; } sk = nl_socket_alloc(); From 453a90e5805589fca1b6a05925ab221fea4db029 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Sat, 1 Apr 2017 14:37:55 +0300 Subject: [PATCH 1227/4375] ns: Fix wrong opened net ns file Since net ns is assigned after prepare_fds() and, in common case, at the moment of open_ns_fd() call task points to a net ns, which differs to its target net ns, we can't get the ns from a task. So, get it from fdstore. Also, support userns ns fds. v2: Add comment Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/namespaces.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/criu/namespaces.c b/criu/namespaces.c index c237d79c7..b17666c44 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -25,6 +25,7 @@ #include "namespaces.h" #include "net.h" #include "cgroup.h" +#include "fdstore.h" #include "protobuf.h" #include "util.h" @@ -515,8 +516,21 @@ static int open_ns_fd(struct file_desc *d, int *new_fd) struct ns_file_info *nfi = container_of(d, struct ns_file_info, d); struct pstree_item *item, *t; struct ns_desc *nd = NULL; + struct ns_id *ns; + int nsfd_id, fd; char path[64]; - int fd; + + for (ns = ns_ids; ns != NULL; ns = ns->next) { + if (ns->id != nfi->nfe->ns_id) + continue; + /* Check for CLONE_XXX as we use fdstore only if flag is set */ + if (ns->nd == &net_ns_desc && (root_ns_mask & CLONE_NEWNET)) + nsfd_id = ns->net.nsfd_id; + else + break; + fd = fdstore_get(nsfd_id); + goto check_open; + } /* * Find out who can open us. @@ -534,6 +548,10 @@ static int open_ns_fd(struct file_desc *d, int *new_fd) item = t; nd = &net_ns_desc; break; + } else if (ids->user_ns_id == nfi->nfe->ns_id) { + item = t; + nd = &user_ns_desc; + break; } else if (ids->ipc_ns_id == nfi->nfe->ns_id) { item = t; nd = &ipc_ns_desc; @@ -567,6 +585,7 @@ static int open_ns_fd(struct file_desc *d, int *new_fd) path[sizeof(path) - 1] = '\0'; fd = open(path, nfi->nfe->flags); +check_open: if (fd < 0) { pr_perror("Can't open file %s on restore", path); return fd; From b5225915df71f0c041cddd1244567dcf3d18fc3f Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 5 May 2017 19:12:36 +0300 Subject: [PATCH 1228/4375] ns: Do not change net_ns in prepare_net_namespaces() In next patches usernsd will need to create transport socket in the same net_ns as other tasks do their TRANSPORT_FD_OFF sockets. Choose criu net_ns for that: this allows usernsd to do not wait for creation of other net_ns, i.e. to do not introduce new dependencies between tasks. In case of (root_ns_mask & CLONE_NEWUSER) != 0 root_item's user_ns does not allow to restore criu net_ns, so do prepare_net_namespaces() in sub-process to do not lose criu net. v3: Introduce __prepare_net_namespaces and execute it in cloned task. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/net.c | 14 ++++++++++---- test/zdtm/static/tun.desc | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/criu/net.c b/criu/net.c index 9b5f1e492..12f544f35 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2301,13 +2301,10 @@ static int do_create_net_ns(struct ns_id *ns) return 0; } -int prepare_net_namespaces() +static int __prepare_net_namespaces(void *unused) { struct ns_id *nsid; - if (!(root_ns_mask & CLONE_NEWNET)) - return 0; - for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { if (nsid->nd != &net_ns_desc) continue; @@ -2357,6 +2354,15 @@ err: return -1; } + +int prepare_net_namespaces(void) +{ + if (!(root_ns_mask & CLONE_NEWNET)) + return 0; + + return call_in_child_process(__prepare_net_namespaces, NULL); +} + static int do_restore_task_net_ns(struct ns_id *nsid, struct pstree_item *current) { int fd; diff --git a/test/zdtm/static/tun.desc b/test/zdtm/static/tun.desc index 8c7cfe860..eac32c2d0 100644 --- a/test/zdtm/static/tun.desc +++ b/test/zdtm/static/tun.desc @@ -1 +1 @@ -{'flavor': 'ns uns', 'flags': 'suid', 'feature': 'tun'} +{'flavor': 'ns uns', 'flags': 'suid noauto', 'feature': 'tun'} From a877a89484b9e71d9822b46cba43d0d18b2d8184 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 5 May 2017 19:12:36 +0300 Subject: [PATCH 1229/4375] util: add a function to run an action is a child process The action is run in a very lightweight process. Signed-off-by: Andrei Vagin --- criu/include/util.h | 2 ++ criu/util.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/criu/include/util.h b/criu/include/util.h index 0478e0676..3c3c37961 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -344,4 +344,6 @@ extern int epoll_del_rfd(int epfd, struct epoll_rfd *rfd); extern int epoll_run_rfds(int epfd, struct epoll_event *evs, int nr_fds, int tmo); extern int epoll_prepare(int nr_events, struct epoll_event **evs); +extern int call_in_child_process(int (*fn)(void *), void *arg); + #endif /* __CR_UTIL_H__ */ diff --git a/criu/util.c b/criu/util.c index 5d5b1b7d4..16ab2b2b4 100644 --- a/criu/util.c +++ b/criu/util.c @@ -47,6 +47,7 @@ #include "namespaces.h" #include "criu-log.h" +#include "clone-noasan.h" #include "cr_options.h" #include "servicefd.h" #include "cr-service.h" @@ -1381,3 +1382,32 @@ free_events: xfree(*events); return -1; } + +int call_in_child_process(int (*fn)(void *), void *arg) +{ + int status, ret = -1; + pid_t pid; + /* + * Parent freezes till child exit, so child may use the same stack. + * No SIGCHLD flag, so it's not need to block signal. + */ + pid = clone_noasan(fn, CLONE_VFORK | CLONE_VM | CLONE_FILES | + CLONE_IO | CLONE_SIGHAND | CLONE_SYSVSEM, arg); + if (pid == -1) { + pr_perror("Can't clone"); + return -1; + } + errno = 0; + if (waitpid(pid, &status, __WALL) != pid || !WIFEXITED(status) || WEXITSTATUS(status)) { + pr_err("Can't wait or bad status: errno=%d, status=%d\n", errno, status); + goto out; + } + ret = 0; + /* + * Child opened PROC_SELF for pid. If we create one more child + * with the same pid later, it will try to reuse this /proc/self. + */ +out: + close_pid_proc(); + return ret; +} From badf42caa49c0124fa683bf1f1e23b5e09b96b2b Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 7 Apr 2017 11:52:33 +0300 Subject: [PATCH 1230/4375] restore: Block SIGCHLD during root_item initialization (Was "user_ns: Block SIGCHLD during namespaces generation") We don't want asynchronous signal handler during creation of namespaces (for example, in create_user_ns_hierarhy()) as we do wait() synchronous. So we need to block the signal. Do this once globally. v2: Set initial ret = 0 v3: Block signal globally in root_item before its children are created. v4: Move block to prepare_namespace() Suggested-by: Andrew Vagin Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/include/util.h | 21 +++++++++++++++++++++ criu/namespaces.c | 21 +++++++++++++++------ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/criu/include/util.h b/criu/include/util.h index 3c3c37961..f95e0ae8f 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -346,4 +346,25 @@ extern int epoll_prepare(int nr_events, struct epoll_event **evs); extern int call_in_child_process(int (*fn)(void *), void *arg); +#define block_sigmask(saved_mask, sig_mask) ({ \ + sigset_t ___blocked_mask; \ + int ___ret = 0; \ + sigemptyset(&___blocked_mask); \ + sigaddset(&___blocked_mask, sig_mask); \ + if (sigprocmask(SIG_BLOCK, &___blocked_mask, saved_mask) == -1) { \ + pr_perror("Can not set mask of blocked signals"); \ + ___ret = -1; \ + } \ + ___ret; \ + }) + +#define restore_sigmask(saved_mask) ({ \ + int ___ret = 0; \ + if (sigprocmask(SIG_SETMASK, saved_mask, NULL) == -1) { \ + pr_perror("Can not unset mask of blocked signals"); \ + ___ret = -1; \ + } \ + ___ret; \ + }) + #endif /* __CR_UTIL_H__ */ diff --git a/criu/namespaces.c b/criu/namespaces.c index b17666c44..67fa2f57a 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -1682,11 +1682,15 @@ err_out: int prepare_namespace(struct pstree_item *item, unsigned long clone_flags) { pid_t pid = vpid(item); - int id; + sigset_t sig_mask; + int id, ret = -1; pr_info("Restoring namespaces %d flags 0x%lx\n", vpid(item), clone_flags); + if (block_sigmask(&sig_mask, SIGCHLD) < 0) + return -1; + if ((clone_flags & CLONE_NEWUSER) && prepare_userns_creds()) return -1; @@ -1698,22 +1702,27 @@ int prepare_namespace(struct pstree_item *item, unsigned long clone_flags) id = ns_per_id ? item->ids->uts_ns_id : pid; if ((clone_flags & CLONE_NEWUTS) && prepare_utsns(id)) - return -1; + goto out; id = ns_per_id ? item->ids->ipc_ns_id : pid; if ((clone_flags & CLONE_NEWIPC) && prepare_ipc_ns(id)) - return -1; + goto out; if (prepare_net_namespaces()) - return -1; + goto out; /* * This one is special -- there can be several mount * namespaces and prepare_mnt_ns handles them itself. */ if (prepare_mnt_ns()) - return -1; + goto out; - return 0; + ret = 0; +out: + if (restore_sigmask(&sig_mask) < 0) + ret = -1; + + return ret; } int prepare_namespace_before_tasks(void) From ef65d98a782ce08a6dfd3e7573149efcf789e656 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 17 May 2017 17:37:05 +0300 Subject: [PATCH 1231/4375] clone_noasan: Allow to create CLONE_VM|CLONE_VFORK processes Picked from patch "[PATCH RFC] namespaces: use CLONE_VFORK with CLONE_VM when it is possible" by Andrew Vagin. Currenly parent touches child's stack, as in moment of clone() call its stack pointer is above the child's (we allocate char stack[128] on parent's stack). This prevents to create CLONE_VM|CLONE_VFORK processes, because the child uses stack addresses occupied by parent. The patch changes clone_noasan() behaviour and allows to do that with the same memory consumption. We give a child memory, which is not used by parent clone(), so parent's and child's stacks have no tntersection. This allows to create CLONE_VM|CLONE_VFORK processes. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/clone-noasan.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/criu/clone-noasan.c b/criu/clone-noasan.c index c5171b11f..0d98c2ed8 100644 --- a/criu/clone-noasan.c +++ b/criu/clone-noasan.c @@ -1,5 +1,7 @@ #include #include "common/compiler.h" +#include "log.h" +#include "common/bug.h" /* * ASan doesn't play nicely with clone if we use current stack for @@ -19,15 +21,11 @@ */ int clone_noasan(int (*fn)(void *), int flags, void *arg) { + void *stack_ptr = (void *)round_down((unsigned long)&stack_ptr - 256, 16); + BUG_ON((flags & CLONE_VM) && !(flags & CLONE_VFORK)); /* - * Reserve some space for clone() to locate arguments - * and retcode in this place + * Reserve some bytes for clone() internal needs + * and use as stack the address above this area. */ - char stack[128] __stack_aligned__; - char *stack_ptr = &stack[sizeof(stack)]; - int ret; - - ret = clone(fn, stack_ptr, flags, arg); - return ret; + return clone(fn, stack_ptr, flags, arg); } - From 95f2d40769586fb38fc8fbc769f155404db25090 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 4 May 2017 23:27:46 +0300 Subject: [PATCH 1232/4375] restore: create the root netns before running setup-namespaces scripts runc restore executes criu with --emptyns network and set a setup-namespaces script to restore a network namespace. https://github.com/xemul/criu/issues/314 Looks-good-to: Pavel Emelyanov Reviewed-by: Kirill Tkhai Fixes: 2189b9c71d3d ("net: allow to dump and restore more than one network namespace") Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 21 +++++++++++++++++---- criu/net.c | 17 +++++++++++++++-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 5b1254c3e..3da8f39f7 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1564,10 +1564,23 @@ static int restore_task_with_children(void *_arg) goto err; } - /* Wait prepare_userns */ - if (current->parent == NULL && - restore_finish_ns_stage(CR_STATE_ROOT_TASK, CR_STATE_PREPARE_NAMESPACES) < 0) - goto err; + if (current->parent == NULL) { + /* + * The root task has to be in its namespaces before executing + * ACT_SETUP_NS scripts, so the root netns has to be created here + */ + if (root_ns_mask & CLONE_NEWNET) { + ret = unshare(CLONE_NEWNET); + if (ret) { + pr_perror("Can't unshare net-namespace"); + goto err; + } + } + + /* Wait prepare_userns */ + if (restore_finish_ns_stage(CR_STATE_ROOT_TASK, CR_STATE_PREPARE_NAMESPACES) < 0) + goto err; + } /* * Call this _before_ forking to optimize cgroups diff --git a/criu/net.c b/criu/net.c index 12f544f35..23f3e45c2 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2172,6 +2172,9 @@ int dump_net_ns(struct ns_id *ns) ret = dump_iptables(fds); if (!ret) ret = dump_netns_conf(ns, fds); + } else if (ns->type != NS_ROOT) { + pr_err("Unable to dump more than one netns if the --emptyns is set\n"); + ret = -1; } if (!ret) ret = dump_nf_ct(fds, CR_FD_NETNF_CT); @@ -2304,13 +2307,23 @@ static int do_create_net_ns(struct ns_id *ns) static int __prepare_net_namespaces(void *unused) { struct ns_id *nsid; + int root_ns; + root_ns = open_proc(PROC_SELF, "ns/net"); + if (root_ns < 0) + return -1; + + /* Pin one with a file descriptor */ for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { if (nsid->nd != &net_ns_desc) continue; - if (do_create_net_ns(nsid)) - goto err; + if (nsid->type == NS_ROOT) { + nsid->net.ns_fd = root_ns; + } else { + if (do_create_net_ns(nsid)) + goto err; + } } for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { From 71e2bdc9687a8a807e747557e5d8e23198c201cb Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 16 Jun 2017 18:19:19 +0300 Subject: [PATCH 1233/4375] net: Fix links collection retcode There's a if (bad_thing) { ret = -1; break; } code above this hunk, whose intention is to propagate -1 back to caller. This propagation is obviously broken. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/net.c b/criu/net.c index 23f3e45c2..eff1195d4 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1560,7 +1560,7 @@ static int read_links(struct ns_id *ns) } close_image(img); - return 0; + return ret; } static int restore_link(int nlsk, struct ns_id *ns, struct net_link *link) From fc3ffd82828b93bcf654f84a746cccb59606bed5 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 5 Oct 2017 20:58:47 +0300 Subject: [PATCH 1234/4375] net: handle a case when --empty net is set only for criu dump The origin idea was to set --empty net for criu dump and criu restore, but before cde33dcb0639 ("empty-ns: Don't C/R iptables too (v2)"), criu restore worked without --empty net and we didn't notice that docker doesn't set this option on restore. After a small brainstorm, we decided that it is better to remove this requirement. Docker has to set this option, but with this changes, the docker issue will be less urgent. https://github.com/checkpoint-restore/criu/issues/393 Signed-off-by: Andrei Vagin --- criu/net.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/net.c b/criu/net.c index eff1195d4..d257eeb8d 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2193,6 +2193,9 @@ static int restore_netns_ids(struct ns_id *ns) { int i, sk, exit_code = -1; + if (!ns->net.netns) + return 0; + sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (sk < 0) { pr_perror("Can't open rtnl sock for net dump"); From 677b6cb0f23da7e4129b065639271db8f4e49aac Mon Sep 17 00:00:00 2001 From: Dmitry Safonov <0x7f454c46@gmail.com> Date: Sat, 27 Jan 2018 15:56:26 +0000 Subject: [PATCH 1235/4375] kdat/net: Init kerndat even if nsid aren't supported We should continue even if kdat feature isn't supported: [criu]# ./criu/criu dump -t `pidof pypy` --shell-job Warn (criu/kerndat.c:804): Can't load /run/criu.kdat Warn (criu/libnetlink.c:55): ERROR -95 reported by netlink Error (criu/net.c:3042): Unable to create a veth pair: -95 Warn (criu/net.c:3064): NSID isn't reported for network links Cc: Andrei Vagin Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> --- criu/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/net.c b/criu/net.c index d257eeb8d..f4abc72ab 100644 --- a/criu/net.c +++ b/criu/net.c @@ -3055,7 +3055,7 @@ int kerndat_link_nsid() if (status) { pr_warn("NSID isn't reported for network links\n"); - return -1; + return 0; } kdat.has_link_nsid = true; From 0d9bed0ec69eea3c64344f3e105f5d54d2d9583e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 11 Jan 2018 21:16:55 +0300 Subject: [PATCH 1236/4375] kerndat: call kerndat_link_nsid() It was droped during one of rebases. Signed-off-by: Andrei Vagin --- criu/kerndat.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/kerndat.c b/criu/kerndat.c index 1870721de..3fe8b6d15 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -886,6 +886,8 @@ int kerndat_init(void) ret = kerndat_socket_netns(); if (!ret) ret = kerndat_nsid(); + if (!ret) + ret = kerndat_link_nsid(); if (!ret) ret = kerndat_has_memfd_create(); if (!ret) From 2bed6e9f3b37301562f586a1862ff28651b4e1a8 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 11 Dec 2017 19:07:18 +0300 Subject: [PATCH 1237/4375] mount: add mnt_is_overmounted helper to check mount visibility note: leave it __maybe_unused yet Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/criu/mount.c b/criu/mount.c index bb63ecc85..d290299cd 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1096,6 +1096,44 @@ static char *get_clean_mnt(struct mount_info *mi, char *mnt_path_tmp, char *mnt_ return mnt_path; } +/* + * Our children mount can have same mountpoint as it's parent, + * call these - children-overmount. + * Sibling mount's mountpoint can be a subpath of our mountpoint + * call these - sibling-overmount. + * In both above cases our mountpoint is not visible from the + * root of our mount namespace as it is covered by other mount. + * mnt_is_overmounted() checks if mount is not visible. + */ +static __maybe_unused bool mnt_is_overmounted(struct mount_info *mi) +{ + struct mount_info *t, *c, *m = mi; + + while (m->parent) { + /* Check there is no sibling-overmount */ + list_for_each_entry(t, &m->parent->children, siblings) { + if (m == t) + continue; + if (issubpath(m->mountpoint, t->mountpoint)) + return true; + } + + /* + * If parent has sibling-overmount we are not visible too, + * note that children-overmounts for parent are already + * checked as our sibling overmounts. + */ + m = m->parent; + } + + /* Check there is no children-overmount */ + list_for_each_entry(c, &mi->children, siblings) + if (!strcmp(c->mountpoint, mi->mountpoint)) + return true; + + return false; +} + #define MNT_UNREACHABLE INT_MIN int open_mountpoint(struct mount_info *pm) { From d17bad63cc9a94ff66316576c958763603688c63 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 11 Dec 2017 19:07:19 +0300 Subject: [PATCH 1238/4375] mount: add __umount_children_overmounts helper to make mount visible note: leave it __maybe_unused yet Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/criu/mount.c b/criu/mount.c index d290299cd..20c475572 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1134,6 +1134,41 @@ static __maybe_unused bool mnt_is_overmounted(struct mount_info *mi) return false; } +/* + * __umount_children_overmounts() assumes that the mountpoint and + * it's ancestors have no sibling-overmounts, so we can see children + * of these mount. Unmount our children-overmounts now. + */ +static __maybe_unused int __umount_children_overmounts(struct mount_info *mi) +{ + struct mount_info *c, *m = mi; + + /* + * Our children-overmount can itself have children-overmount + * which covers it, so find deepest children-overmount which + * is visible for us now. + */ +again: + list_for_each_entry(c, &m->children, siblings) { + if (!strcmp(c->mountpoint, m->mountpoint)) { + m = c; + goto again; + } + } + + /* Unmout children-overmounts in the order of visibility */ + while (m != mi) { + if (umount2(m->mountpoint, MNT_DETACH)) { + pr_perror("Unable to umount child-overmount %s", m->mountpoint); + return -1; + } + BUG_ON(!m->parent); + m = m->parent; + } + + return 0; +} + #define MNT_UNREACHABLE INT_MIN int open_mountpoint(struct mount_info *pm) { From 83df86494b4aa81f390a807cfab8f71b18046735 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 11 Dec 2017 19:07:20 +0300 Subject: [PATCH 1239/4375] mount add umount_overmounts helper to make mount visible also remove __maybe_unused for __umount_children_overmounts note: leave it __maybe_unused yet Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/criu/mount.c b/criu/mount.c index 20c475572..7af2acdb2 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1139,7 +1139,7 @@ static __maybe_unused bool mnt_is_overmounted(struct mount_info *mi) * it's ancestors have no sibling-overmounts, so we can see children * of these mount. Unmount our children-overmounts now. */ -static __maybe_unused int __umount_children_overmounts(struct mount_info *mi) +static int __umount_children_overmounts(struct mount_info *mi) { struct mount_info *c, *m = mi; @@ -1169,6 +1169,70 @@ again: return 0; } +/* Makes the mountpoint visible except for children-overmounts. */ +static int __umount_overmounts(struct mount_info *m) +{ + struct mount_info *t, *ovm; + int ovm_len, ovm_len_min = 0; + + /* Root mount has no sibling-overmounts */ + if (!m->parent) + return 0; + + /* + * If parent is sibling-overmounted we are not visible + * too, so first try to unmount overmounts for parent. + */ + if (__umount_overmounts(m->parent)) + return -1; + + /* Unmount sibling-overmounts in visibility order */ +next: + ovm = NULL; + ovm_len = strlen(m->mountpoint) + 1; + list_for_each_entry(t, &m->parent->children, siblings) { + if (m == t) + continue; + if (issubpath(m->mountpoint, t->mountpoint)) { + int t_len = strlen(t->mountpoint); + + if (t_len < ovm_len && t_len > ovm_len_min) { + ovm = t; + ovm_len = t_len; + } + } + } + + if (ovm) { + ovm_len_min = ovm_len; + + /* Our sibling-overmount can have children-overmount covering it */ + if (__umount_children_overmounts(ovm)) + return -1; + + if (umount2(ovm->mountpoint, MNT_DETACH)) { + pr_perror("Unable to umount %s", ovm->mountpoint); + return -1; + } + + goto next; + } + + return 0; +} + +/* Make our mountpoint fully visible */ +static __maybe_unused int umount_overmounts(struct mount_info *m) +{ + if (__umount_overmounts(m)) + return -1; + + if (__umount_children_overmounts(m)) + return -1; + + return 0; +} + #define MNT_UNREACHABLE INT_MIN int open_mountpoint(struct mount_info *pm) { From b364f4fd52be125ddc6690452bec3336d77ad102 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 22 Dec 2017 11:22:26 +0300 Subject: [PATCH 1240/4375] mount: make open_mountpoint handle overmouts properly dump of VZ7 ct fails, if we have overmounted tmpfs inside: [root@silo ~]# prlctl enter su-test-2 entered into CT CT-829e7b28 /# mkdir /mnt/overmntedtmp CT-829e7b28 /# mount -t tmpfs tmpfs /mnt/overmntedtmp/ CT-829e7b28 /# mount -t tmpfs tmpfs /mnt CT-829e7b28 /# logout [root@silo ~]# prlctl suspend su-test-2 Suspending the CT... Failed to suspend the CT: PRL_ERR_VZCTL_OPERATION_FAILED (Details: Will skip in-flight TCP connections (01.657913) Error (criu/mount.c:1202): mnt: Can't open ./mnt/overmntedtmp: No such file or directory (01.662528) Error (criu/util.c:709): exited, status=1 (01.664329) Error (criu/util.c:709): exited, status=1 (01.664694) Error (criu/cr-dump.c:2005): Dumping FAILED. Failed to checkpoint the Container All dump files and logs were saved to /vz/private/829e7b28-f204-4bce-b09f-d203b99befd4/dump/Dump.fail Checkpointing failed ) Criu wants to dump the contents of /mnt/overmntedtmp/ mount but it is unavailable. So we copy the mount namespace in such a case and unmount overmounts to access what we want to dump. Actual usecase here is dumping CT with active mariadb and ssh connection. Together they happen to create such overmount. As by default systemd creates a separate mount namespace for mysql and also mounts tmpfs to /run/user in it, and when ssh(root) is connected - systemd also mounts tmpfs in container root mount namespace to /run/user/0 for user files. As /run is slave mount /run/user/0 also propagates to mysql's mount namespace and initially becomes overmounted by /run/user. https://jira.sw.ru/browse/PSBM-57362 remove __maybe_unused for mnt_is_overmounted and umount_overmounts changes in v2: 1) Use clone not fork, share resources with parent same as in call_in_child_process. 2) Do not enter userns (create helper) for non-overmounted mounts. Thus return back setns/resorens logic. 3) Helper opens fd for parent directly due to CLONE_FILES, remove futex. 4) Check helper exit status properly. 5) Add get_clean_fd helper. 6) Add better comments. changes in v3: 1) Pass fd from helper through args instead of ret code, fix ret code checking. 2) Add \n to pr_err in open_mountpoint changes in v5: Make comments even better. Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/filesystems.c | 2 +- criu/include/mount.h | 2 + criu/mount.c | 170 +++++++++++++++++++++++++++++++------------ 3 files changed, 125 insertions(+), 49 deletions(-) diff --git a/criu/filesystems.c b/criu/filesystems.c index 5a88788d7..fa6d96ecf 100644 --- a/criu/filesystems.c +++ b/criu/filesystems.c @@ -387,7 +387,7 @@ static int tmpfs_dump(struct mount_info *pm) fd = open_mountpoint(pm); if (fd < 0) - return fd; + return MNT_UNREACHABLE; /* if fd happens to be 0 here, we need to move it to something * non-zero, because cr_system_userns closes STDIN_FILENO as we are not diff --git a/criu/include/mount.h b/criu/include/mount.h index e60dd348f..ed771ffac 100644 --- a/criu/include/mount.h +++ b/criu/include/mount.h @@ -12,6 +12,8 @@ struct ns_id; #define MOUNT_INVALID_DEV (0) +#define MNT_UNREACHABLE INT_MIN + struct mount_info { int mnt_id; int parent_mnt_id; diff --git a/criu/mount.c b/criu/mount.c index 7af2acdb2..8ce4225d6 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -26,6 +26,7 @@ #include "path.h" #include "files-reg.h" #include "external.h" +#include "clone-noasan.h" #include "images/mnt.pb-c.h" @@ -1096,6 +1097,19 @@ static char *get_clean_mnt(struct mount_info *mi, char *mnt_path_tmp, char *mnt_ return mnt_path; } +static int get_clean_fd(struct mount_info *mi) +{ + char *mnt_path = NULL; + char mnt_path_tmp[] = "/tmp/cr-tmpfs.XXXXXX"; + char mnt_path_root[] = "/cr-tmpfs.XXXXXX"; + + mnt_path = get_clean_mnt(mi, mnt_path_tmp, mnt_path_root); + if (!mnt_path) + return -1; + + return open_detach_mount(mnt_path); +} + /* * Our children mount can have same mountpoint as it's parent, * call these - children-overmount. @@ -1105,7 +1119,7 @@ static char *get_clean_mnt(struct mount_info *mi, char *mnt_path_tmp, char *mnt_ * root of our mount namespace as it is covered by other mount. * mnt_is_overmounted() checks if mount is not visible. */ -static __maybe_unused bool mnt_is_overmounted(struct mount_info *mi) +static bool mnt_is_overmounted(struct mount_info *mi) { struct mount_info *t, *c, *m = mi; @@ -1222,7 +1236,7 @@ next: } /* Make our mountpoint fully visible */ -static __maybe_unused int umount_overmounts(struct mount_info *m) +static int umount_overmounts(struct mount_info *m) { if (__umount_overmounts(m)) return -1; @@ -1233,40 +1247,79 @@ static __maybe_unused int umount_overmounts(struct mount_info *m) return 0; } -#define MNT_UNREACHABLE INT_MIN -int open_mountpoint(struct mount_info *pm) +struct clone_arg { + struct mount_info *mi; + int *fd; +}; + +/* + * Get access to the mountpoint covered by overmounts + * and open it's cleaned copy (without children mounts). + */ +int ns_open_mountpoint(void *arg) { - struct mount_info *c; - int fd = -1, ns_old = -1; - char mnt_path_tmp[] = "/tmp/cr-tmpfs.XXXXXX"; - char mnt_path_root[] = "/cr-tmpfs.XXXXXX"; - char *mnt_path = mnt_path_tmp; - int cwd_fd; + struct clone_arg *ca = arg; + struct mount_info *mi = ca->mi; + int *fd = ca->fd; /* - * If a mount doesn't have children, we can open a mount point, - * otherwise we need to create a "private" copy. + * We should enter user namespace owning mount namespace of our mount + * before creating helper mount namespace. Else all mounts in helper + * mount namespace will be locked (MNT_LOCKED) and we won't be able to + * unmount them (see CL_UNPRIVILEGED in sys_umount(), clone_mnt() and + * copy_mnt_ns() in linux kernel code). */ - if (list_empty(&pm->children)) - return __open_mountpoint(pm, -1); + if ((root_ns_mask & CLONE_NEWUSER) && + switch_ns(root_item->pid->real, &user_ns_desc, NULL) < 0) + goto err; - pr_info("Something is mounted on top of %s\n", pm->mountpoint); - - list_for_each_entry(c, &pm->children, siblings) { - if (!strcmp(c->mountpoint, pm->mountpoint)) { - pr_debug("%d:%s is overmounted\n", pm->mnt_id, pm->mountpoint); - return MNT_UNREACHABLE; - } + /* + * Create a helper mount namespace in which we can safely do unmounts + * without breaking dumping process' environment. + */ + if (unshare(CLONE_NEWNS)) { + pr_perror("Unable to unshare a mount namespace"); + goto err; } - /* - * To create a "private" copy, the target mount is bind-mounted - * in a temporary place w/o MS_REC (non-recursively). - * A mount point can't be bind-mounted in criu's namespace, it will be - * mounted in a target namespace. The sequence of actions is - * mkdtemp, setns(tgt), mount, open, detach, setns(old). - */ + /* Remount all mounts as private to disable propagation */ + if (mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)) + goto err; + if (umount_overmounts(mi)) + goto err; + + /* Save fd which we opened for parent due to CLONE_FILES flag */ + *fd = get_clean_fd(mi); + if (*fd < 0) + goto err; + + return 0; +err: + return 1; +} + +int open_mountpoint(struct mount_info *pm) +{ + int fd, cwd_fd, ns_old = -1; + + /* No overmounts and children - the entire mount is visible */ + if (list_empty(&pm->children) && !mnt_is_overmounted(pm)) + return __open_mountpoint(pm, -1); + + pr_info("Mount is not fully visible %s\n", pm->mountpoint); + + /* + * We do two things below: + * a) If mount has children mounts in it which partially cover it's + * content, to get access to the content we create a "private" copy of + * such a mount, bind-mounting mount w/o MS_REC in a temporary place. + * b) If mount is overmounted we create a private copy of it's mount + * namespace so that we can safely get rid of overmounts and get an + * access to the mount. + * In both cases we can't do the thing from criu's mount namespace, so + * we need to switch to mount's mount namespace, and later swtich back. + */ cwd_fd = open(".", O_DIRECTORY); if (cwd_fd < 0) { pr_perror("Unable to open cwd"); @@ -1274,33 +1327,54 @@ int open_mountpoint(struct mount_info *pm) } if (switch_ns(pm->nsid->ns_pid, &mnt_ns_desc, &ns_old) < 0) - goto out; + goto err; + + if (!mnt_is_overmounted(pm)) { + pr_info("\tmount has children %s\n", pm->mountpoint); + + fd = get_clean_fd(pm); + if (fd < 0) + goto err; + } else { + int pid, status; + struct clone_arg ca = { + .mi = pm, + .fd = &fd + }; + + pr_info("\tmount is overmounted %s\n", pm->mountpoint); - mnt_path = get_clean_mnt(pm, mnt_path_tmp, mnt_path_root); - if (mnt_path == NULL) { /* - * We probably can't create a temporary direcotry, - * so we can try to clone the mount namespace, open - * the required mount and destroy this mount namespace - * by calling restore_ns() below in this function. + * We are overmounted - not accessible in a regular way. We + * need to clone "private" copy of mount's monut namespace and + * unmount all covering overmounts in it. We also need to enter + * user namespace owning these mount namespace just before that + * (see explanation in ns_open_mountpoint). Thus we also have + * to create helper process here as entering user namespace is + * irreversible operation. */ - if (unshare(CLONE_NEWNS)) { - pr_perror("Unable to clone a mount namespace"); - goto out; + pid = clone_noasan(ns_open_mountpoint, CLONE_VFORK | CLONE_VM + | CLONE_FILES | CLONE_IO | CLONE_SIGHAND + | CLONE_SYSVSEM, &ca); + if (pid == -1) { + pr_perror("Can't clone helper process"); + return -1; } - fd = open(pm->mountpoint, O_RDONLY | O_DIRECTORY, 0); - if (fd < 0) - pr_perror("Can't open directory %s: %d", pm->mountpoint, fd); - } else - fd = open_detach_mount(mnt_path); - if (fd < 0) - goto out; + errno = 0; + if (waitpid(pid, &status, __WALL) != pid || !WIFEXITED(status) + || WEXITSTATUS(status)) { + pr_err("Can't wait or bad status: errno=%d, status=%d\n", + errno, status); + return -1; + } + } if (restore_ns(ns_old, &mnt_ns_desc)) { ns_old = -1; - goto out; + goto err; } + if (fchdir(cwd_fd)) { pr_perror("Unable to restore cwd"); close(cwd_fd); @@ -1310,9 +1384,9 @@ int open_mountpoint(struct mount_info *pm) close(cwd_fd); return __open_mountpoint(pm, fd); -out: +err: if (ns_old >= 0) - restore_ns(ns_old, &mnt_ns_desc); + restore_ns(ns_old, &mnt_ns_desc); close_safe(&fd); if (fchdir(cwd_fd)) pr_perror("Unable to restore cwd"); From dd104ddbe129e2ffc9b491bc3b4771c94091fcbd Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 11 Dec 2017 19:07:22 +0300 Subject: [PATCH 1241/4375] zdtm: now tempfs_overmounted will pass so remove crfail Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm/static/tempfs_overmounted.desc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/tempfs_overmounted.desc b/test/zdtm/static/tempfs_overmounted.desc index 0d8b7f2b4..7657ba45c 100644 --- a/test/zdtm/static/tempfs_overmounted.desc +++ b/test/zdtm/static/tempfs_overmounted.desc @@ -1 +1 @@ -{'flavor': 'ns uns', 'flags': 'suid crfail'} +{'flavor': 'ns uns', 'flags': 'suid'} From 84d6c7304256ade3f8b447b007b23c794827851d Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 11 Dec 2017 19:07:23 +0300 Subject: [PATCH 1242/4375] mount: fix mnt_resort_siblings to work as described We should add new entry _before_ first entry with less depth to sort in descending order. e.g: entries in list have depths [7,5,3], adding new entry m with depth 4 we would break list_for_each_entry loop on p with depth 3, before patch we would get [7,5,3,4] after list_add, which is wrong. Also we can relax "<=" check to "<" to avoid unnecessary reordering. Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 8ce4225d6..ad02d11c2 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -446,10 +446,10 @@ static void mnt_resort_siblings(struct mount_info *tree) depth = mnt_depth(m); list_for_each_entry(p, &list, siblings) - if (mnt_depth(p) <= depth) + if (mnt_depth(p) < depth) break; - list_add(&m->siblings, &p->siblings); + list_add_tail(&m->siblings, &p->siblings); mnt_resort_siblings(m); } From a9ec5829bc83f6d1cfb1989c25332ebf65a229c6 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 11 Dec 2017 19:07:24 +0300 Subject: [PATCH 1243/4375] mount: fix try_remap_mount Remaps in mnt_remap_list should follow same descending order which was setup in mnt_resort_siblings(), so don't reorder them. For instance if we have sibling mounts with mountpoints: 1) /dir1/dir2/dir3 2) /dir1/dir2 3) /dir1 Here (2) is sibling-overmount for (1). Mount (3) is sibling-overmount for both (1) and (2). So when we move overmounts back in fixup_remap_mounts() we should first move (2) and only then (3). Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/mount.c b/criu/mount.c index ad02d11c2..562f3fc57 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2507,7 +2507,7 @@ static int try_remap_mount(struct mount_info *m) return -1; r->mi = m; - list_add(&r->node, &mnt_remap_list); + list_add_tail(&r->node, &mnt_remap_list); return 0; } From 0709e3ce76083b6232ae215c9f21610d1cec66f7 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 11 Dec 2017 19:07:25 +0300 Subject: [PATCH 1244/4375] mount: do remaps for child-overmount of another overmount In case we have mounts: 1 /mnt/ 2 /mnt/a with parent 1 3 /mnt/a/b with parent 1 4 /mnt/a with parent 2 We determine 2 as needing remap with does_mnt_overmount() and remap it. Next we mount 4 on top of 2. Next in fixup_remap_mounts() we want to move 2 back to it's parent 1, but instead move 4 there. So in these case children-overmounts need to be remapped too. Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 562f3fc57..5357d1782 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -629,7 +629,7 @@ static struct mount_info *find_fsroot_mount_for(struct mount_info *bm) return NULL; } -static bool does_mnt_overmount(struct mount_info *m) +static bool mnt_needs_remap(struct mount_info *m) { struct mount_info *t; @@ -643,6 +643,14 @@ static bool does_mnt_overmount(struct mount_info *m) return true; } + /* + * If we are children-overmount and parent is remapped, we should be + * remapped too, else fixup_remap_mounts() won't be able to move parent + * to it's real place, it will move child instead. + */ + if (!strcmp(m->parent->mountpoint, m->mountpoint)) + return mnt_needs_remap(m->parent); + return false; } @@ -2497,7 +2505,7 @@ static int try_remap_mount(struct mount_info *m) { struct mnt_remap_entry *r; - if (!does_mnt_overmount(m)) + if (!mnt_needs_remap(m)) return 0; BUG_ON(!m->parent); From 8fdacca5274d8b6e1dead7bb8e865904b15fb365 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 11 Dec 2017 19:07:26 +0300 Subject: [PATCH 1245/4375] zdtm: improve tempfs_overmounted test Unchanged test provided by Andrew. Signed-off-by: Andrei Vagin Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm/static/tempfs_overmounted.c | 36 +++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/test/zdtm/static/tempfs_overmounted.c b/test/zdtm/static/tempfs_overmounted.c index 56c3d2ed8..29eca00f4 100644 --- a/test/zdtm/static/tempfs_overmounted.c +++ b/test/zdtm/static/tempfs_overmounted.c @@ -19,11 +19,38 @@ int main(int argc, char **argv) test_init(argc, argv); mkdir(dirname, 0700); - if (mount("none", dirname, "tmpfs", 0, "") < 0) { + if (chdir(dirname)) { + pr_perror("chdir"); + return 1; + } + + mkdir("a", 0777); + mkdir("a/b", 0777); + + mount(NULL, "/", NULL, MS_PRIVATE, ""); + if (mount("none", "a/b", "tmpfs", 0, "") < 0) { fail("Can't mount tmpfs"); return 1; } - if (mount("none", dirname, "tmpfs", 0, "") < 0) { + if (mount("none", "a/b", "tmpfs", 0, "") < 0) { + fail("Can't mount tmpfs"); + return 1; + } + mkdir("a/b/c", 0777); + if (mount("none", "a/b/c", "tmpfs", 0, "") < 0) { + fail("Can't mount tmpfs"); + return 1; + } + if (mount("none", "a", "tmpfs", 0, "") < 0) { + fail("Can't mount tmpfs"); + return 1; + } + if (mount("none", "a", "tmpfs", 0, "") < 0) { + fail("Can't mount tmpfs"); + return 1; + } + mkdir("a/b", 0777); + if (mount("none", "a/b", "tmpfs", 0, "") < 0) { fail("Can't mount tmpfs"); return 1; } @@ -31,6 +58,11 @@ int main(int argc, char **argv) test_daemon(); test_waitsig(); + if (umount("a/b") || umount("a") || umount("a") || umount("a/b/c") || umount("a/b") || umount("a/b")) { + pr_err("umount"); + return 1; + } + pass(); return 0; } From 6d40803eea3a5e41533d69e8c521097e658384cd Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 1 Jun 2017 14:34:42 +0300 Subject: [PATCH 1246/4375] autofs: Add FD_TYPES__AUTOFS_PIPE type Add a fake fd type for autofs. This allows functions like find_file_desc() work as expected, without having two different file_desc with the same type and same id. Also, later, it will allow to delete autofs_create_fle() and to use generic helper. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/autofs.c | 2 ++ images/fdinfo.proto | 3 +++ 2 files changed, 5 insertions(+) diff --git a/criu/autofs.c b/criu/autofs.c index 6432b4213..8cf5e8ec0 100644 --- a/criu/autofs.c +++ b/criu/autofs.c @@ -892,6 +892,7 @@ static int autofs_create_pipe(struct pstree_item *task, autofs_info_t *i, return -1; memcpy(ops, pi->d.ops, sizeof(*ops)); ops->open = autofs_open_pipefd; + ops->type = FD_TYPES__AUTOFS_PIPE; pe = shmalloc(sizeof(*pe)); if (!pe) @@ -910,6 +911,7 @@ static int autofs_create_pipe(struct pstree_item *task, autofs_info_t *i, fe = dup_fdinfo(ple->fe, fd, flags); if (!fe) return -1; + fe->type = FD_TYPES__AUTOFS_PIPE; pr_info("autofs: adding pipe fd %d, flags %#x to %d (with post_open)\n", fe->fd, fe->flags, vpid(task)); diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 0a6f3ee74..3d4e50701 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -36,6 +36,9 @@ enum fd_types { TUNF = 15; EXT = 16; TIMERFD = 17; + + /* Any number above the real used. Not stored to image */ + AUTOFS_PIPE = 65535; } message fdinfo_entry { From 8b51779520bed4ed8a985bc27070a47fefef1357 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 1 Jun 2017 14:35:09 +0300 Subject: [PATCH 1247/4375] files: Unexport collect_task_fd() It has only one user, so unexport it. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 2 +- criu/include/files.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/files.c b/criu/files.c index 0cbd85951..26b094730 100644 --- a/criu/files.c +++ b/criu/files.c @@ -124,7 +124,7 @@ struct fdinfo_list_entry *find_used_fd(struct pstree_item *task, int fd) return NULL; } -void collect_task_fd(struct fdinfo_list_entry *new_fle, struct rst_info *ri) +static void collect_task_fd(struct fdinfo_list_entry *new_fle, struct rst_info *ri) { struct fdinfo_list_entry *fle; diff --git a/criu/include/files.h b/criu/include/files.h index 0f134c99d..a75445cf2 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -111,7 +111,6 @@ struct file_desc_ops { }; int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info, bool ghost); -void collect_task_fd(struct fdinfo_list_entry *new_fle, struct rst_info *ri); struct fdinfo_list_entry *collect_fd_to(int pid, FdinfoEntry *e, struct rst_info *rst_info, struct file_desc *fdesc, bool fake); From 28af7aa0377e91ce118f8ebc03c56011087d8503 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 30 May 2017 21:13:32 +0300 Subject: [PATCH 1248/4375] kdat: Add fetching files stat Will need it to unlimit the files allocation for service fd reserving and later for parasite code run (which is implemented in vz7 instance and soon will be ported into vanilla). Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/kerndat.h | 4 ++- criu/kerndat.c | 69 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 785b13679..d966edf8b 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -2,7 +2,6 @@ #define __CR_KERNDAT_H__ #include - #include "int.h" #include "common/config.h" #ifdef CONFIG_VDSO @@ -20,6 +19,7 @@ extern int kerndat_init(void); extern int kerndat_get_dirty_track(void); extern int kerndat_fdinfo_has_lock(void); extern int kerndat_loginuid(void); +extern int kerndat_files_stat(bool early); enum pagemap_func { PM_UNKNOWN, @@ -66,6 +66,8 @@ struct kerndat_s { #endif bool has_nsid; bool has_link_nsid; + unsigned int sysctl_nr_open; + unsigned long files_stat_max_files; }; extern struct kerndat_s kdat; diff --git a/criu/kerndat.c b/criu/kerndat.c index 3fe8b6d15..d20f1e26e 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -152,6 +152,74 @@ static void kerndat_mmap_min_addr(void) (unsigned long)kdat.mmap_min_addr); } +int kerndat_files_stat(bool early) +{ + static const uint32_t NR_OPEN_DEFAULT = 1024 * 1024; + static const uint64_t MAX_FILES_DEFAULT = 8192; + uint64_t max_files; + uint32_t nr_open; + + struct sysctl_req req[] = { + { + .name = "fs/file-max", + .arg = &max_files, + .type = CTL_U64, + }, + { + .name = "fs/nr_open", + .arg = &nr_open, + .type = CTL_U32, + }, + }; + + if (!early) { + if (sysctl_op(req, ARRAY_SIZE(req), CTL_READ, 0)) { + pr_warn("Can't fetch file_stat, using kernel defaults\n"); + nr_open = NR_OPEN_DEFAULT; + max_files = MAX_FILES_DEFAULT; + } + } else { + char buf[64]; + int fd1, fd2; + ssize_t ret; + + fd1 = open("/proc/sys/fs/file-max", O_RDONLY); + fd2 = open("/proc/sys/fs/nr_open", O_RDONLY); + + nr_open = NR_OPEN_DEFAULT; + max_files = MAX_FILES_DEFAULT; + + if (fd1 < 0 || fd2 < 0) { + pr_warn("Can't fetch file_stat, using kernel defaults\n"); + } else { + ret = read(fd1, buf, sizeof(buf) - 1); + if (ret > 0) { + buf[ret] = '\0'; + max_files = atol(buf); + } + ret = read(fd2, buf, sizeof(buf)); + if (ret > 0) { + buf[ret] = '\0'; + nr_open = atol(buf); + } + } + + if (fd1 >= 0) + close(fd1); + if (fd2 >= 0) + close(fd2); + } + + kdat.sysctl_nr_open = nr_open; + kdat.files_stat_max_files = max_files; + + pr_debug("files stat: %s %lu, %s %u\n", + req[0].name, kdat.files_stat_max_files, + req[1].name, kdat.sysctl_nr_open); + + return 0; +} + static int kerndat_get_shmemdev(void) { void *map; @@ -909,6 +977,7 @@ int kerndat_init(void) kerndat_lsm(); kerndat_mmap_min_addr(); + kerndat_files_stat(false); if (!ret) kerndat_save_cache(); From cc5dbf51d8894f628b5f61e04d07650d027ee2c6 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 30 May 2017 21:13:33 +0300 Subject: [PATCH 1249/4375] sfd: Lift up own fd limit on bootup This minimize chances to hit problem where files used for page transfer are trying to use same number reserved for service fd. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/crtools.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/criu/crtools.c b/criu/crtools.c index fea2ccc7a..05ff91ac4 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -21,6 +21,9 @@ #include +#include +#include + #include "int.h" #include "page.h" #include "common/compiler.h" @@ -246,6 +249,20 @@ static void print_kernel_version(void) buf.release, buf.version, buf.machine); } +static void rlimit_unlimit_nofile_self(void) +{ + struct rlimit new; + + new.rlim_cur = kdat.sysctl_nr_open; + new.rlim_max = kdat.sysctl_nr_open; + + if (prlimit(getpid(), RLIMIT_NOFILE, &new, NULL)) { + pr_perror("rlimir: Can't setup RLIMIT_NOFILE for self"); + return; + } else + pr_debug("rlimit: RLIMIT_NOFILE unlimited for self\n"); +} + int main(int argc, char *argv[], char *envp[]) { @@ -352,6 +369,24 @@ int main(int argc, char *argv[], char *envp[]) init_opts(); + /* + * Service fd engine implies that file descritprs + * used won't be borrowed by the rest of the code + * and default 1024 limit is not enough for high + * loaded test/containers. Thus use kdat engine + * to fetch current system level limit for numbers + * of files allowed to open up and lift up own + * limits. + * + * Note we have to do it before the service fd + * get inited and we dont exit with errors here + * because in worst scenario where clash of fd + * happen we simply exit with explicit error + * during real action stage. + */ + if (!kerndat_files_stat(true)) + rlimit_unlimit_nofile_self(); + if (init_service_fd()) return 1; From 0fcaeea9122e381b1585e52574bedb1414e59e39 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 20 Mar 2017 15:11:58 +0300 Subject: [PATCH 1250/4375] files: Do not close transport socket twice We close it in sigreturn_restore() for unification with other service fds, so kill the second close() from here. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/files.c b/criu/files.c index 26b094730..4a2440a67 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1304,7 +1304,6 @@ int prepare_fds(struct pstree_item *me) ret = open_fdinfos(me); - close_service_fd(TRANSPORT_FD_OFF); if (rsti(me)->fdt) futex_inc_and_wake(&rsti(me)->fdt->fdt_lock); out: From 563efd3f25c6c3634dfcb2243379fbc5670ad2f5 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 5 May 2017 19:13:04 +0300 Subject: [PATCH 1251/4375] pstree: Change type of init_pstree_helper() and check for parent This is refactoring, which will be used in next patches. BUG_ON() just to mention that parent must be set before call of this function. v5: New Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files-reg.c | 5 ++++- criu/include/pstree.h | 2 +- criu/pstree.c | 14 +++++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 29a588ccd..10165d61d 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -532,13 +532,16 @@ static int collect_remap_dead_process(struct reg_file_info *rfi, return 0; } - init_pstree_helper(helper); helper->sid = root_item->sid; helper->pgid = root_item->pgid; helper->pid->ns[0].virt = rfe->remap_id; helper->parent = root_item; helper->ids = root_item->ids; + if (init_pstree_helper(helper)) { + pr_err("Can't init helper\n"); + return -1; + } list_add_tail(&helper->sibling, &root_item->children); pr_info("Added a helper for restoring /proc/%d\n", vpid(helper)); diff --git a/criu/include/pstree.h b/criu/include/pstree.h index b082e3586..34f9bbe6f 100644 --- a/criu/include/pstree.h +++ b/criu/include/pstree.h @@ -87,7 +87,7 @@ static inline bool task_alive(struct pstree_item *i) extern void free_pstree(struct pstree_item *root_item); extern struct pstree_item *__alloc_pstree_item(bool rst); #define alloc_pstree_item() __alloc_pstree_item(false) -extern void init_pstree_helper(struct pstree_item *ret); +extern int init_pstree_helper(struct pstree_item *ret); extern struct pstree_item *lookup_create_item(pid_t pid); extern void pstree_insert_pid(struct pid *pid_node); diff --git a/criu/pstree.c b/criu/pstree.c index a52ec553a..975412d85 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -229,11 +229,13 @@ struct pstree_item *__alloc_pstree_item(bool rst) return item; } -void init_pstree_helper(struct pstree_item *ret) +int init_pstree_helper(struct pstree_item *ret) { + BUG_ON(!ret->parent); ret->pid->state = TASK_HELPER; rsti(ret)->clone_flags = CLONE_FILES | CLONE_FS; task_entries->nr_helpers++; + return 0; } /* Deep first search on children */ @@ -675,7 +677,10 @@ static int prepare_pstree_ids(void) helper->ids = root_item->ids; list_add_tail(&helper->sibling, &helpers); } - init_pstree_helper(helper); + if (init_pstree_helper(helper)) { + pr_err("Can't init helper\n"); + return -1; + } pr_info("Add a helper %d for restoring SID %d\n", vpid(helper), helper->sid); @@ -763,13 +768,16 @@ static int prepare_pstree_ids(void) continue; helper = pid->item; - init_pstree_helper(helper); helper->sid = item->sid; helper->pgid = item->pgid; helper->pid->ns[0].virt = item->pgid; helper->parent = item; helper->ids = item->ids; + if (init_pstree_helper(helper)) { + pr_err("Can't init helper\n"); + return -1; + } list_add(&helper->sibling, &item->children); rsti(item)->pgrp_leader = helper; From 72e5006564312ed38f25024d90982c40eba2bef2 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 5 May 2017 19:13:13 +0300 Subject: [PATCH 1252/4375] files: Make possible task helpers to use shared_fdt_prepare() Next patches will create transport sockets in task helpers. As helpers are forked using CLONE_FILES, they must resolve shared fds to create their own service fds. This patch allows that. I've digged in the code, and there is no a reason, we need pid_rst_prio() during choosing of fdt restorer. So, this case may be safely deleted, which guarantees, that in case of TASK_HELPER, the restorer of fdt will be parent, i.e., no one TASK_HELPER will be restorer of fdt. v5: New Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/files.c b/criu/files.c index 4a2440a67..85fcb17d2 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1302,6 +1302,7 @@ int prepare_fds(struct pstree_item *me) } } + BUG_ON(current->pid->state == TASK_HELPER); ret = open_fdinfos(me); if (rsti(me)->fdt) @@ -1442,8 +1443,6 @@ int shared_fdt_prepare(struct pstree_item *item) rsti(item)->fdt = fdt; rsti(item)->service_fd_id = fdt->nr; fdt->nr++; - if (pid_rst_prio(vpid(item), fdt->pid)) - fdt->pid = vpid(item); return 0; } From 7952c6a78d9aa3f081cfc0a67fcf7ef722c929a5 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 5 May 2017 19:13:23 +0300 Subject: [PATCH 1253/4375] cr-restore: Open transport socket earlier I need named socket to communicate with pid_ns helpers (see next patches) and receive answer from them (it's impossible to send answer to unnamed socket). As we already have transport socket, we'll reuse it for the above goal too. This patch makes transport sockets be created before creation of children tasks. Also, now they are created not only for alive tasks (so we need additional manipulations for TASK_HELPERS, e.g., to call prepare_fdt()). v5: Return CLONE_FILES clone() argument during task helpers creation. Also get rid of fdt_mutex as CLONE_FILES processes does not close old files after clone, and we don't have intertersections between them. Also, socket() system call can't return a fd in service fds range, which was the main reason to have this mutex. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 23 ++++++++++++++--------- criu/files.c | 17 +++++++---------- criu/pstree.c | 2 ++ 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 3da8f39f7..a19fc7ab7 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1064,6 +1064,9 @@ static int restore_one_helper(void) { siginfo_t info; + if (prepare_fds(current)) + return -1; + if (!child_death_expected()) { /* * Restoree has no children that should die, during restore, @@ -1108,7 +1111,7 @@ static int restore_one_helper(void) static int restore_one_task(int pid, CoreEntry *core) { - int ret; + int i, ret; /* No more fork()-s => no more per-pid logs */ @@ -1118,6 +1121,10 @@ static int restore_one_task(int pid, CoreEntry *core) ret = restore_one_zombie(core); else if (current->pid->state == TASK_HELPER) { ret = restore_one_helper(); + close_image_dir(); + close_proc(); + for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) + close_service_fd(i); } else { pr_err("Unknown state in code %d\n", (int)core->tc->task_state); ret = -1; @@ -1541,11 +1548,9 @@ static int restore_task_with_children(void *_arg) if ( !(ca->clone_flags & CLONE_FILES)) close_safe(&ca->fd); - if (current->pid->state != TASK_HELPER) { - ret = clone_service_fd(rsti(current)->service_fd_id); - if (ret) - goto err; - } + ret = clone_service_fd(rsti(current)->service_fd_id); + if (ret) + goto err; pid = getpid(); if (vpid(current) != pid) { @@ -1641,6 +1646,9 @@ static int restore_task_with_children(void *_arg) kill(getpid(), SIGKILL); } + if (open_transport_socket()) + goto err; + timing_start(TIME_FORK); if (create_children_and_session()) @@ -1653,9 +1661,6 @@ static int restore_task_with_children(void *_arg) restore_pgid(); - if (open_transport_socket()) - return -1; - if (current->parent == NULL) { /* * Wait when all tasks passed the CR_STATE_FORKING stage. diff --git a/criu/files.c b/criu/files.c index 85fcb17d2..b4ae1dcfa 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1739,34 +1739,31 @@ int inherit_fd_fini() int open_transport_socket(void) { - struct fdt *fdt = rsti(current)->fdt; pid_t pid = vpid(current); struct sockaddr_un saddr; - int sock, slen; - - if (!task_alive(current) || (fdt && fdt->pid != pid)) - return 0; + int sock, slen, ret = -1; sock = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (sock < 0) { pr_perror("Can't create socket"); - return -1; + goto out; } transport_name_gen(&saddr, &slen, pid); if (bind(sock, (struct sockaddr *)&saddr, slen) < 0) { pr_perror("Can't bind transport socket %s", saddr.sun_path + 1); close(sock); - return -1; + goto out; } if (install_service_fd(TRANSPORT_FD_OFF, sock) < 0) { close(sock); - return -1; + goto out; } close(sock); - - return 0; + ret = 0; +out: + return ret; } static int collect_one_file_entry(FileEntry *fe, u_int32_t id, ProtobufCMessage *base, diff --git a/criu/pstree.c b/criu/pstree.c index 975412d85..dfd68b7ca 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -234,6 +234,8 @@ int init_pstree_helper(struct pstree_item *ret) BUG_ON(!ret->parent); ret->pid->state = TASK_HELPER; rsti(ret)->clone_flags = CLONE_FILES | CLONE_FS; + if (shared_fdt_prepare(ret) < 0) + return -1; task_entries->nr_helpers++; return 0; } From 0f7e6928d7090aa9893c826f7cc166d82263b6ba Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 23 Feb 2017 18:15:26 +0300 Subject: [PATCH 1254/4375] proc: Close CR_PROC_FD_OFF and TRANSPORT_FD_OFF later CR_PROC_FD_OFF is need for accessing to foreign tasks fds, and will be used in the future. TRANSPORT_FD_OFF is for uniformity. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 ++ criu/files.c | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index a19fc7ab7..55e6f7fe7 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3382,6 +3382,8 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns close_image_dir(); close_proc(); + close_service_fd(TRANSPORT_FD_OFF); + close_service_fd(CR_PROC_FD_OFF); close_service_fd(ROOT_FD_OFF); close_service_fd(USERNSD_SK); close_service_fd(FDSTORE_SK_OFF); diff --git a/criu/files.c b/criu/files.c index b4ae1dcfa..9ca0d7a7c 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1308,7 +1308,6 @@ int prepare_fds(struct pstree_item *me) if (rsti(me)->fdt) futex_inc_and_wake(&rsti(me)->fdt->fdt_lock); out: - close_service_fd(CR_PROC_FD_OFF); tty_fini_fds(); return ret; } From bda944e175729caec41fa80fe9ae313965115c50 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 5 May 2017 19:12:49 +0300 Subject: [PATCH 1255/4375] mnt: Put root fd to fdstore mntns_get_root_fd() may be called by a task from !root_user_ns, and it fails if so. Put root fd to fdstore to allow use it every task. v3: New Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/include/namespaces.h | 2 +- criu/mount.c | 19 +++++++++++++------ criu/sk-unix.c | 13 +++++++++++-- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index d68a7b76c..77b726767 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -105,7 +105,7 @@ struct ns_id { struct mount_info *mntinfo_list; struct mount_info *mntinfo_tree; int ns_fd; - int root_fd; + int root_fd_id; } mnt; struct { diff --git a/criu/mount.c b/criu/mount.c index 5357d1782..34a497bbe 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -27,6 +27,7 @@ #include "files-reg.h" #include "external.h" #include "clone-noasan.h" +#include "fdstore.h" #include "images/mnt.pb-c.h" @@ -3007,7 +3008,6 @@ void fini_restore_mntns(void) if (nsid->nd != &mnt_ns_desc) continue; close_safe(&nsid->mnt.ns_fd); - close_safe(&nsid->mnt.root_fd); nsid->ns_populated = true; } } @@ -3212,7 +3212,7 @@ void cleanup_mnt_ns(void) int prepare_mnt_ns(void) { - int ret = -1, rst = -1; + int ret = -1, rst = -1, fd; struct ns_id ns = { .type = NS_CRIU, .ns_pid = PROC_SELF, .nd = &mnt_ns_desc }; struct ns_id *nsid; @@ -3299,10 +3299,17 @@ int prepare_mnt_ns(void) if (cr_pivot_root(path)) goto err; - /* root_fd is used to restore file mappings */ - nsid->mnt.root_fd = open_proc(PROC_SELF, "root"); - if (nsid->mnt.root_fd < 0) + /* root fd is used to restore file mappings */ + fd = open_proc(PROC_SELF, "root"); + if (fd < 0) goto err; + nsid->mnt.root_fd_id = fdstore_add(fd); + if (nsid->mnt.root_fd_id < 0) { + pr_err("Can't add root fd\n"); + close(fd); + goto err; + } + close(fd); /* And return back to regain the access to the roots yard */ if (setns(rst, CLONE_NEWNS)) { @@ -3417,7 +3424,7 @@ int mntns_get_root_fd(struct ns_id *mntns) if (!mntns->ns_populated) { int fd; - fd = open_proc(vpid(root_item), "fd/%d", mntns->mnt.root_fd); + fd = fdstore_get(mntns->mnt.root_fd_id); if (fd < 0) return -1; diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 928a68477..87f292965 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -28,6 +28,7 @@ #include "pstree.h" #include "external.h" #include "crtools.h" +#include "fdstore.h" #include "protobuf.h" #include "images/sk-unix.pb-c.h" @@ -1036,6 +1037,7 @@ static void revert_unix_sk_cwd(int *prev_cwd_fd, int *root_fd) static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd, int *prev_root_fd) { static struct ns_id *root = NULL; + int fd; *prev_cwd_fd = open(".", O_RDONLY); if (*prev_cwd_fd < 0) { @@ -1052,10 +1054,17 @@ static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd, int *prev goto err; } - if (fchdir(root->mnt.root_fd)) { - pr_perror("Unable to change current working dir"); + fd = fdstore_get(root->mnt.root_fd_id); + if (fd < 0) { + pr_err("Can't get root fd\n"); goto err; } + if (fchdir(fd)) { + pr_perror("Unable to change current working dir"); + close(fd); + goto err; + } + close(fd); if (chroot(".")) { pr_perror("Unable to change root directory"); goto err; From 4c68ed7d7e7d0f0b2fcdd4b955e9ceeb59700f35 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 28 Jun 2017 18:53:57 +0300 Subject: [PATCH 1256/4375] mnt_ns: Move open_proc() up in prepare_mnt_ns() The both branches need this, so move it up. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/mount.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 34a497bbe..53861512c 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -3266,9 +3266,11 @@ int prepare_mnt_ns(void) goto err; } - if (nsid->type == NS_ROOT) { - int fd; + fd = open_proc(PROC_SELF, "ns/mnt"); + if (fd < 0) + goto err; + if (nsid->type == NS_ROOT) { /* * We need to create a mount namespace which will be * used to clean up remap files @@ -3277,9 +3279,6 @@ int prepare_mnt_ns(void) * namespace, because there are file descriptors * linked with it (e.g. to bind-mount slave pty-s). */ - fd = open_proc(PROC_SELF, "ns/mnt"); - if (fd < 0) - goto err; if (setns(rst, CLONE_NEWNS)) { pr_perror("Can't restore mntns back"); goto err; @@ -3288,9 +3287,7 @@ int prepare_mnt_ns(void) rst = fd; } else { /* Pin one with a file descriptor */ - nsid->mnt.ns_fd = open_proc(PROC_SELF, "ns/mnt"); - if (nsid->mnt.ns_fd < 0) - goto err; + nsid->mnt.ns_fd = fd; } /* Set its root */ From d433a3e902116a3dba87d1caa4cf0e059a2ffbe2 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 28 Jun 2017 18:54:07 +0300 Subject: [PATCH 1257/4375] utils: Introduce SWAP() helper to exchange two variables Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- include/common/compiler.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/common/compiler.h b/include/common/compiler.h index 235413070..ada79f293 100644 --- a/include/common/compiler.h +++ b/include/common/compiler.h @@ -85,6 +85,13 @@ type __max2 = (y); \ __max1 > __max2 ? __max1: __max2; }) +#define SWAP(x, y) \ + do { \ + typeof(x) ____val = x; \ + x = y; \ + y = ____val; \ + } while (0) + #define is_log2(v) (((v) & ((v) - 1)) == 0) #endif /* __CR_COMPILER_H__ */ From 58b3b9ee3fb475f029f2b4e45c84de912ac637aa Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 28 Jun 2017 18:54:16 +0300 Subject: [PATCH 1258/4375] mnt: Move ns_fd assignment down in prepare_mnt_ns() No functional changes. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/mount.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 53861512c..df015c81c 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -3283,13 +3283,12 @@ int prepare_mnt_ns(void) pr_perror("Can't restore mntns back"); goto err; } - nsid->mnt.ns_fd = rst; - rst = fd; - } else { - /* Pin one with a file descriptor */ - nsid->mnt.ns_fd = fd; + SWAP(rst, fd); } + /* Pin one with a file descriptor */ + nsid->mnt.ns_fd = fd; + /* Set its root */ path[0] = '/'; print_ns_root(nsid, 0, path + 1, sizeof(path) - 1); From dcac6d66c54c1c637e2621b97eb7e07b62021204 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 28 Jun 2017 18:54:25 +0300 Subject: [PATCH 1259/4375] mnt_ns: Use fdstore to keep mount namespaces This allows to decrese number of file descriptors, which are passed to children, and that is need to close in close_old_files(). Signed-off-by: Kirill Tkhai : Signed-off-by: Andrei Vagin --- criu/include/namespaces.h | 2 +- criu/mount.c | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index 77b726767..abe63802f 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -104,7 +104,7 @@ struct ns_id { struct { struct mount_info *mntinfo_list; struct mount_info *mntinfo_tree; - int ns_fd; + int nsfd_id; int root_fd_id; } mnt; diff --git a/criu/mount.c b/criu/mount.c index df015c81c..936587b03 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2947,7 +2947,7 @@ static int do_restore_task_mnt_ns(struct ns_id *nsid, struct pstree_item *curren { int fd; - fd = open_proc(vpid(root_item), "fd/%d", nsid->mnt.ns_fd); + fd = fdstore_get(nsid->mnt.nsfd_id); if (fd < 0) return -1; @@ -3007,7 +3007,6 @@ void fini_restore_mntns(void) for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { if (nsid->nd != &mnt_ns_desc) continue; - close_safe(&nsid->mnt.ns_fd); nsid->ns_populated = true; } } @@ -3287,7 +3286,12 @@ int prepare_mnt_ns(void) } /* Pin one with a file descriptor */ - nsid->mnt.ns_fd = fd; + nsid->mnt.nsfd_id = fdstore_add(fd); + close(fd); + if (nsid->mnt.nsfd_id < 0) { + pr_err("Can't add ns fd\n"); + goto err; + } /* Set its root */ path[0] = '/'; From 2fe6081834b6c5d07306510c11db5cc94b6aa37d Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 28 Jun 2017 18:54:33 +0300 Subject: [PATCH 1260/4375] forking: Always close pid proc before child creation Child does not know about parent's pid proc fd, and it can't close it by fd. Next patch will do close_old_files() optional, and it will base on the fact there is no leftover fds. So, close pid proc directly. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 55e6f7fe7..b2befd89c 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1247,9 +1247,6 @@ static inline int fork_with_pid(struct pstree_item *item) BUG_ON(pid != INIT_PID); } - if (ca.clone_flags & CLONE_FILES) - close_pid_proc(); - /* * Some kernel modules, such as netwrok packet generator * run kernel thread upon net-namespace creattion taking @@ -1262,6 +1259,7 @@ static inline int fork_with_pid(struct pstree_item *item) * The cgroup namespace is also unshared explicitly in the * move_in_cgroup(), so drop this flag here as well. */ + close_pid_proc(); ret = clone_noasan(restore_task_with_children, (ca.clone_flags & ~(CLONE_NEWNET | CLONE_NEWCGROUP)) | SIGCHLD, &ca); if (ret < 0) { From f11a0ce0ebea453fa9b5eab377b01532afaf1e52 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 28 Jun 2017 18:54:42 +0300 Subject: [PATCH 1261/4375] restore: Use vpid in log_init_by_pid() instead of getpid() When task is in pid namespace, getpid() can't be used to identify it. So, use vpid instead of that. Also, move log_init_by_pid() above pid check. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 8 ++++---- criu/include/criu-log.h | 2 +- criu/log.c | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index b2befd89c..6f44a9478 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1550,6 +1550,10 @@ static int restore_task_with_children(void *_arg) if (ret) goto err; + ret = log_init_by_pid(vpid(current)); + if (ret < 0) + goto err; + pid = getpid(); if (vpid(current) != pid) { pr_err("Pid %d do not match expected %d\n", pid, vpid(current)); @@ -1557,10 +1561,6 @@ static int restore_task_with_children(void *_arg) goto err; } - ret = log_init_by_pid(); - if (ret < 0) - goto err; - if (!(ca->clone_flags & CLONE_FILES)) { ret = close_old_fds(); if (ret) diff --git a/criu/include/criu-log.h b/criu/include/criu-log.h index ce6018860..b4a522bb9 100644 --- a/criu/include/criu-log.h +++ b/criu/include/criu-log.h @@ -24,7 +24,7 @@ extern int log_init(const char *output); extern void log_fini(void); -extern int log_init_by_pid(void); +extern int log_init_by_pid(pid_t pid); extern void log_closedir(void); extern int log_keep_err(void); extern char *log_first_err(void); diff --git a/criu/log.c b/criu/log.c index a2beabdb0..100ddc796 100644 --- a/criu/log.c +++ b/criu/log.c @@ -171,7 +171,7 @@ err: return -1; } -int log_init_by_pid(void) +int log_init_by_pid(pid_t pid) { char path[PATH_MAX]; @@ -182,14 +182,14 @@ int log_init_by_pid(void) reset_buf_off(); if (!opts.log_file_per_pid) { - buf_off += snprintf(buffer + buf_off, sizeof buffer - buf_off, "%6d: ", getpid()); + buf_off += snprintf(buffer + buf_off, sizeof buffer - buf_off, "%6d: ", pid); return 0; } if (!opts.output) return 0; - snprintf(path, PATH_MAX, "%s.%d", opts.output, getpid()); + snprintf(path, PATH_MAX, "%s.%d", opts.output, pid); return log_init(path); } From 66f55b5e0c0aef5457e97fd9e42c0322af1b4159 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 28 Jun 2017 18:54:51 +0300 Subject: [PATCH 1262/4375] restore: Do not iterate over parent's files to find leftovers This patch speeds up creation of child process by disabling iteration over open files for the most cases. Really, we don't need that now, as previous patches make parent files do not leak: mnt namespace fds are stored in fdstore, pid proc files are closed directly. So, now we can skip closing old files for the most cases, except some CLONE_FILES cases: we need that only if parent have CLONE_FILES in its flags (and for root_item). Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 6f44a9478..b3189322c 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1002,6 +1002,30 @@ static int restore_one_zombie(CoreEntry *core) return -1; } +static int setup_newborn_fds(struct pstree_item *me) +{ + if (clone_service_fd(rsti(me)->service_fd_id)) + return -1; + + if (!me->parent || + (rsti(me->parent)->fdt && !(rsti(me)->clone_flags & CLONE_FILES))) { + /* + * When our parent has shared fd table, some of the table owners + * may be already created. Files, they open, will be inherited + * by current process, and here we close them. Also, service fds + * of parent are closed here. And root_item closes the files, + * that were inherited from criu process. + */ + if (close_old_fds()) + return -1; + } + + if (log_init_by_pid(vpid(me))) + return -1; + + return 0; +} + static int check_core(CoreEntry *core, struct pstree_item *me) { int ret = -1; @@ -1546,12 +1570,7 @@ static int restore_task_with_children(void *_arg) if ( !(ca->clone_flags & CLONE_FILES)) close_safe(&ca->fd); - ret = clone_service_fd(rsti(current)->service_fd_id); - if (ret) - goto err; - - ret = log_init_by_pid(vpid(current)); - if (ret < 0) + if (setup_newborn_fds(current)) goto err; pid = getpid(); @@ -1561,12 +1580,6 @@ static int restore_task_with_children(void *_arg) goto err; } - if (!(ca->clone_flags & CLONE_FILES)) { - ret = close_old_fds(); - if (ret) - goto err; - } - if (current->parent == NULL) { /* * The root task has to be in its namespaces before executing From 832c9aef36cfba130cae8af67edb66779d94f5a1 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 28 Jun 2017 13:45:42 +0300 Subject: [PATCH 1263/4375] files: Fix crossing unused and service fds of shared fd tables service_fd_id is id of a specific task, while other tasks in shared fd table group may have bigger id numbers. In this case given unused fd intersects with service fds of such tasks. This leads to undefined behaviour. Fix that. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 4 ++-- criu/include/servicefd.h | 4 +++- criu/util.c | 10 ++++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/criu/files.c b/criu/files.c index 9ca0d7a7c..b133b570d 100644 --- a/criu/files.c +++ b/criu/files.c @@ -148,7 +148,7 @@ unsigned int find_unused_fd(struct pstree_item *task, int hint_fd) goto out; } - prev_fd = service_fd_min_fd() - 1; + prev_fd = service_fd_min_fd(task) - 1; head = &rsti(task)->fds; list_for_each_entry_reverse(fle, head, ps_list) { @@ -888,7 +888,7 @@ int prepare_fd_pid(struct pstree_item *item) if (ret <= 0) break; - if (e->fd >= service_fd_min_fd()) { + if (e->fd >= service_fd_min_fd(item)) { ret = -1; pr_err("Too big FD number to restore %d\n", e->fd); break; diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h index b77922394..29e5b0bdb 100644 --- a/criu/include/servicefd.h +++ b/criu/include/servicefd.h @@ -28,6 +28,8 @@ enum sfd_type { SERVICE_FD_MAX }; +struct pstree_item; + extern int clone_service_fd(int id); extern int init_service_fd(void); extern int get_service_fd(enum sfd_type type); @@ -36,6 +38,6 @@ extern int install_service_fd(enum sfd_type type, int fd); extern int close_service_fd(enum sfd_type type); extern bool is_service_fd(int fd, enum sfd_type type); extern bool is_any_service_fd(int fd); -extern int service_fd_min_fd(void); +extern int service_fd_min_fd(struct pstree_item *); #endif /* __CR_SERVICE_FD_H__ */ diff --git a/criu/util.c b/criu/util.c index 16ab2b2b4..0746ab649 100644 --- a/criu/util.c +++ b/criu/util.c @@ -52,6 +52,7 @@ #include "servicefd.h" #include "cr-service.h" #include "files.h" +#include "pstree.h" #include "cr-errno.h" @@ -461,9 +462,14 @@ static int __get_service_fd(enum sfd_type type, int service_fd_id) return service_fd_rlim_cur - type - SERVICE_FD_MAX * service_fd_id; } -int service_fd_min_fd(void) +int service_fd_min_fd(struct pstree_item *item) { - return service_fd_rlim_cur - (SERVICE_FD_MAX - 1) - SERVICE_FD_MAX * service_fd_id; + struct fdt *fdt = rsti(item)->fdt; + int id = 0; + + if (fdt) + id = fdt->nr - 1; + return service_fd_rlim_cur - (SERVICE_FD_MAX - 1) - SERVICE_FD_MAX * id; } static DECLARE_BITMAP(sfd_map, SERVICE_FD_MAX); From e4c25f2b3fb0b798afa6c388bf268acfd0b68b8f Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 28 Dec 2017 16:08:55 +0300 Subject: [PATCH 1264/4375] files: Close ctl tty via generic engine Just mark the fle as "fake" and the engine will do all the work. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 2 +- criu/tty.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/files.c b/criu/files.c index b133b570d..31c64f283 100644 --- a/criu/files.c +++ b/criu/files.c @@ -854,7 +854,7 @@ int prepare_ctl_tty(int pid, struct rst_info *rst_info, u32 ctl_tty_id) e->fd = reserve_service_fd(CTL_TTY_OFF); e->type = FD_TYPES__TTY; - if (collect_fd(pid, e, rst_info, false)) { + if (collect_fd(pid, e, rst_info, true)) { xfree(e); return -1; } diff --git a/criu/tty.c b/criu/tty.c index cd2370ba9..7546b52c8 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -733,7 +733,6 @@ out: close(slave); err: pty_free_fake_reg(&fake); - close(fd); return ret ? -1 : 0; } From 8a9460001887870c2ff618613d5548da26a62848 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 28 Dec 2017 16:09:04 +0300 Subject: [PATCH 1265/4375] files: Move prepare_ctl_tty() to criu/tty.c Move the function and reduce its arguments number. This is cleanup needed to keep all tty code together. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 27 --------------------------- criu/include/files.h | 1 - criu/tty.c | 31 ++++++++++++++++++++++++++++--- 3 files changed, 28 insertions(+), 31 deletions(-) diff --git a/criu/files.c b/criu/files.c index 31c64f283..bb0e00c94 100644 --- a/criu/files.c +++ b/criu/files.c @@ -835,33 +835,6 @@ int dup_fle(struct pstree_item *task, struct fdinfo_list_entry *ple, return collect_fd(vpid(task), e, rsti(task), false); } -int prepare_ctl_tty(int pid, struct rst_info *rst_info, u32 ctl_tty_id) -{ - FdinfoEntry *e; - - if (!ctl_tty_id) - return 0; - - pr_info("Requesting for ctl tty %#x into service fd\n", ctl_tty_id); - - e = xmalloc(sizeof(*e)); - if (!e) - return -1; - - fdinfo_entry__init(e); - - e->id = ctl_tty_id; - e->fd = reserve_service_fd(CTL_TTY_OFF); - e->type = FD_TYPES__TTY; - - if (collect_fd(pid, e, rst_info, true)) { - xfree(e); - return -1; - } - - return 0; -} - int prepare_fd_pid(struct pstree_item *item) { int ret = 0; diff --git a/criu/include/files.h b/criu/include/files.h index a75445cf2..27ae1a04b 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -158,7 +158,6 @@ extern void show_saved_files(void); extern int prepare_fds(struct pstree_item *me); extern int prepare_fd_pid(struct pstree_item *me); -extern int prepare_ctl_tty(int pid, struct rst_info *rst_info, u32 ctl_tty_id); extern int prepare_files(void); extern int restore_fs(struct pstree_item *); extern int prepare_fs_pid(struct pstree_item *); diff --git a/criu/tty.c b/criu/tty.c index 7546b52c8..13209dfe7 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -1229,6 +1229,33 @@ static struct pstree_item *find_first_sid(int sid) return NULL; } +static int prepare_ctl_tty(struct pstree_item *item, u32 ctl_tty_id) +{ + FdinfoEntry *e; + + if (!ctl_tty_id) + return 0; + + pr_info("Requesting for ctl tty %#x into service fd\n", ctl_tty_id); + + e = xmalloc(sizeof(*e)); + if (!e) + return -1; + + fdinfo_entry__init(e); + + e->id = ctl_tty_id; + e->fd = reserve_service_fd(CTL_TTY_OFF); + e->type = FD_TYPES__TTY; + + if (collect_fd(vpid(item), e, rsti(item), true)) { + xfree(e); + return -1; + } + + return 0; +} + static int tty_find_restoring_task(struct tty_info *info) { struct pstree_item *item; @@ -1306,9 +1333,7 @@ static int tty_find_restoring_task(struct tty_info *info) if (item && vpid(item) == item->sid) { pr_info("Set a control terminal %#x to %d\n", info->tfe->id, info->tie->sid); - return prepare_ctl_tty(vpid(item), - rsti(item), - info->tfe->id); + return prepare_ctl_tty(item, info->tfe->id); } goto notask; From 7a6fe6f0ca1413ec91fc23fadec3522499403e18 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 28 Dec 2017 16:09:13 +0300 Subject: [PATCH 1266/4375] files: Move CTL_TTY_OFF fixup to generic file engine There are two problems. The first is CTL_TTY_OFF occupies one of the biggest available fds in the system. It's a number near service_fd_rlim_cur. Next patches want to allocate service fds lower, than service_fd_rlim_cur, and they want to know max used fd from file fles after the image reading. But since one of fds is already set very big (CTL_TTY_OFF) on a stage of collection fles, the only availabe service fds are near service_fd_rlim_cur. It's vicious circle, and the only way is to change ctl tty fd allocation way. The second problem is ctl tty is ugly out of generic file engine fixup (see open_fd()). This is made because ctl tty is the only slave fle, which needs additional actions (see tty_restore_ctl_terminal()). Another file types just receive their slave fle, and do not do anything else. This patch moves ctl tty to generic engine and solves all the above problems. To do that, we implement new CTL_TTY file type, which open method waits till slave tty is received and then calls tty_restore_ctl_terminal() for that. It fits to generic engine well, and allocates fd via find_unused_fd(), and do not polute file table by big fd numbers. Next patch will kill currently unneed CTL_TTY leftovers and will remove CTL_TTY_OFF service fd from criu. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 13 ++---- criu/include/tty.h | 2 - criu/tty.c | 111 +++++++++++++++++++++++++++++++++++++++----- images/fdinfo.proto | 1 + 4 files changed, 104 insertions(+), 23 deletions(-) diff --git a/criu/files.c b/criu/files.c index bb0e00c94..1174700ce 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1090,7 +1090,7 @@ static int open_fd(struct fdinfo_list_entry *fle) ret = receive_fd(fle); if (ret != 0) return ret; - goto fixup_ctty; + goto out; } /* @@ -1111,16 +1111,9 @@ static int open_fd(struct fdinfo_list_entry *fle) if (setup_and_serve_out(fle, new_fd) < 0) return -1; } -fixup_ctty: - if (ret == 0) { - if (fle->fe->fd == get_service_fd(CTL_TTY_OFF)) { - ret = tty_restore_ctl_terminal(fle->desc, fle->fe->fd); - if (ret == -1) - return ret; - } - +out: + if (ret == 0) fle->stage = FLE_RESTORED; - } return ret; } diff --git a/criu/include/tty.h b/criu/include/tty.h index 5550a72c4..25fa1c42c 100644 --- a/criu/include/tty.h +++ b/criu/include/tty.h @@ -34,8 +34,6 @@ extern int devpts_restore(struct mount_info *pm); extern int tty_prep_fds(void); extern void tty_fini_fds(void); -extern int tty_restore_ctl_terminal(struct file_desc *d, int fd); - extern int devpts_check_bindmount(struct mount_info *m); #define OPT_SHELL_JOB "shell-job" diff --git a/criu/tty.c b/criu/tty.c index 13209dfe7..76c826765 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -686,7 +686,7 @@ static int tty_set_prgp(int fd, int group) return 0; } -int tty_restore_ctl_terminal(struct file_desc *d, int fd) +static int tty_restore_ctl_terminal(struct file_desc *d) { struct tty_info *info = container_of(d, struct tty_info, d); struct tty_driver *driver = info->driver; @@ -694,8 +694,6 @@ int tty_restore_ctl_terminal(struct file_desc *d, int fd) struct file_desc *slave_d; int slave = -1, ret = -1, index = -1; - BUG_ON(!is_service_fd(fd, CTL_TTY_OFF)); - if (driver->type == TTY_TYPE__EXT_TTY) { slave = -1; if (!inherited_fd(&info->d, &slave) && slave < 0) @@ -1229,23 +1227,18 @@ static struct pstree_item *find_first_sid(int sid) return NULL; } -static int prepare_ctl_tty(struct pstree_item *item, u32 ctl_tty_id) +static int add_fake_fle(struct pstree_item *item, u32 desc_id) { FdinfoEntry *e; - if (!ctl_tty_id) - return 0; - - pr_info("Requesting for ctl tty %#x into service fd\n", ctl_tty_id); - e = xmalloc(sizeof(*e)); if (!e) return -1; fdinfo_entry__init(e); - e->id = ctl_tty_id; - e->fd = reserve_service_fd(CTL_TTY_OFF); + e->id = desc_id; + e->fd = find_unused_fd(item, -1); e->type = FD_TYPES__TTY; if (collect_fd(vpid(item), e, rsti(item), true)) { @@ -1253,7 +1246,103 @@ static int prepare_ctl_tty(struct pstree_item *item, u32 ctl_tty_id) return -1; } + return e->fd; +} + +struct ctl_tty { + struct file_desc desc; + struct fdinfo_list_entry *real_tty; +}; + +static int ctl_tty_open(struct file_desc *d, int *new_fd) +{ + struct fdinfo_list_entry *fle; + int ret; + + fle = container_of(d, struct ctl_tty, desc)->real_tty; + if (fle->stage != FLE_RESTORED) + return 1; + + ret = tty_restore_ctl_terminal(fle->desc); + if (!ret) { + /* + * Generic engine expects we return a new_fd. + * Return this one just to return something. + */ + *new_fd = dup(fle->fe->fd); + if (*new_fd < 0) { + pr_perror("dup() failed"); + ret = -1; + } else + ret = 0; + } + return ret; +} + +/* + * This is a fake type to handle ctl tty. The problem + * is sometimes we need to do tty_set_sid() from slave + * fle, while generic file engine allows to call open + * method for file masters only. So, this type allows + * to add fake masters, which will call open for slave + * fles of type FD_TYPES__TTY indirectly. + */ +static struct file_desc_ops ctl_tty_desc_ops = { + .type = FD_TYPES__CTL_TTY, + .open = ctl_tty_open, +}; + +static int prepare_ctl_tty(struct pstree_item *item, u32 ctl_tty_id) +{ + struct fdinfo_list_entry *fle; + struct ctl_tty *ctl_tty; + FdinfoEntry *e; + int fd; + + if (!ctl_tty_id) + return 0; + + pr_info("Requesting for ctl tty %#x into service fd\n", ctl_tty_id); + + /* Add a fake fle to make generic engine deliver real tty desc to task */ + fd = add_fake_fle(item, ctl_tty_id); + if (fd < 0) + return -1; + + fle = find_used_fd(item, fd); + BUG_ON(!fle); + /* + * Add a fake ctl_tty depending on the above fake fle, which will + * actually restore the session. + */ + ctl_tty = xmalloc(sizeof(*ctl_tty)); + e = xmalloc(sizeof(*e)); + + if (!ctl_tty || !e) + goto err; + + ctl_tty->real_tty = fle; + + /* + * Use the same ctl_tty_id id for ctl_tty as it's unique among + * FD_TYPES__CTL_TTY (as it's unique for FD_TYPES__TTY type). + */ + file_desc_add(&ctl_tty->desc, ctl_tty_id, &ctl_tty_desc_ops); + + fdinfo_entry__init(e); + + e->id = ctl_tty_id; + e->fd = find_unused_fd(item, -1); + e->type = FD_TYPES__CTL_TTY; + + if (collect_fd(vpid(item), e, rsti(item), true)) + goto err; + return 0; +err: + xfree(ctl_tty); + xfree(e); + return -1; } static int tty_find_restoring_task(struct tty_info *info) diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 3d4e50701..ed82ceffe 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -38,6 +38,7 @@ enum fd_types { TIMERFD = 17; /* Any number above the real used. Not stored to image */ + CTL_TTY = 65534; AUTOFS_PIPE = 65535; } From 0da7d97117823ce549a9569412cfad81f7e82f76 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 28 Dec 2017 16:09:21 +0300 Subject: [PATCH 1267/4375] files: Kill unused CTL_TTY_OFF leftovers CTL_TTY_OFF and reserve_service_fd() are unused now, so purge them from the code. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/include/servicefd.h | 2 -- criu/util.c | 10 ---------- 2 files changed, 12 deletions(-) diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h index 29e5b0bdb..175e53023 100644 --- a/criu/include/servicefd.h +++ b/criu/include/servicefd.h @@ -10,7 +10,6 @@ enum sfd_type { IMG_FD_OFF, PROC_FD_OFF, /* fd with /proc for all proc_ calls */ PROC_PID_FD_OFF, - CTL_TTY_OFF, SELF_STDIN_OFF, CR_PROC_FD_OFF, /* some other's proc fd. * For dump -- target ns' proc @@ -33,7 +32,6 @@ struct pstree_item; extern int clone_service_fd(int id); extern int init_service_fd(void); extern int get_service_fd(enum sfd_type type); -extern int reserve_service_fd(enum sfd_type type); extern int install_service_fd(enum sfd_type type, int fd); extern int close_service_fd(enum sfd_type type); extern bool is_service_fd(int fd, enum sfd_type type); diff --git a/criu/util.c b/criu/util.c index 0746ab649..75b6571f8 100644 --- a/criu/util.c +++ b/criu/util.c @@ -474,16 +474,6 @@ int service_fd_min_fd(struct pstree_item *item) static DECLARE_BITMAP(sfd_map, SERVICE_FD_MAX); -int reserve_service_fd(enum sfd_type type) -{ - int sfd = __get_service_fd(type, service_fd_id); - - BUG_ON((int)type <= SERVICE_FD_MIN || (int)type >= SERVICE_FD_MAX); - - set_bit(type, sfd_map); - return sfd; -} - int install_service_fd(enum sfd_type type, int fd) { int sfd = __get_service_fd(type, service_fd_id); From 820bad96290d61507f8aeec66f76170deab8445d Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 28 Dec 2017 13:50:37 +0300 Subject: [PATCH 1268/4375] zdtm: Export sys_clone_unified() to headers Make it possible to use this function by tests. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- test/zdtm/lib/zdtmtst.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/zdtm/lib/zdtmtst.h b/test/zdtm/lib/zdtmtst.h index 737ac77cf..cd8e9592e 100644 --- a/test/zdtm/lib/zdtmtst.h +++ b/test/zdtm/lib/zdtmtst.h @@ -151,5 +151,7 @@ struct zdtm_tcp_opts { }; extern int tcp_init_server_with_opts(int family, int *port, struct zdtm_tcp_opts *opts); +extern pid_t sys_clone_unified(unsigned long flags, void *child_stack, void *parent_tid, + void *child_tid, unsigned long newtls); #endif /* _VIMITESU_H_ */ From ec761499e5b3569134e41ffe73a0110d4456368e Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 28 Dec 2017 13:50:45 +0300 Subject: [PATCH 1269/4375] restore: Call prepare_fds() in restore_one_zombie() Zombie may be choosen as parent for task helper during solving pgid dependences. In this situation, it becomes to share fdt with the helper and it has to call prepare_fds() to decrement fdt->nr. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index b3189322c..ecb19b7a7 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -963,6 +963,9 @@ static int restore_one_zombie(CoreEntry *core) pr_info("Restoring zombie with %d code\n", exit_code); + if (prepare_fds(current)) + return -1; + if (inherit_fd_fini() < 0) return -1; From e23806f3d04a7fd7bc3c6bb7c17dbfa4663f42ac Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 28 Dec 2017 13:50:54 +0300 Subject: [PATCH 1270/4375] restore: Split restore_one_helper() and wait exiting zombie children Zombie is also can be choosen as a parent for task helper like any other task. If the task helper exits between restore_finish_stage(CR_STATE_RESTORE) and zombie_prepare_signals()->SIG_UNBLOCK, the standard criu SIGCHLD handler is called, and the restore fails: (00.057762) 41: Error (criu/cr-restore.c:1557): 40 exited, status=0 (00.057815) Error (criu/cr-restore.c:2465): Restoring FAILED. This patch makes restore_one_zombie() behave as restore_one_helper() and to wait children exits before allowing SIGCHLD. This makes us safe against races with exiting children. See next patch for test details. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index ecb19b7a7..a84e5848c 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -957,6 +957,8 @@ static int wait_on_helpers_zombies(void) return 0; } +static int wait_exiting_children(void); + static int restore_one_zombie(CoreEntry *core) { int exit_code = core->tc->exit_code; @@ -975,7 +977,7 @@ static int restore_one_zombie(CoreEntry *core) prctl(PR_SET_NAME, (long)(void *)core->tc->comm, 0, 0, 0); if (task_entries != NULL) { - restore_finish_stage(task_entries, CR_STATE_RESTORE); + wait_exiting_children(); zombie_prepare_signals(); } @@ -1079,21 +1081,10 @@ static bool child_death_expected(void) return false; } -/* - * Restore a helper process - artificially created by criu - * to restore attributes of process tree. - * - sessions for each leaders are dead - * - process groups with dead leaders - * - dead tasks for which /proc//... is opened by restoring task - * - whatnot - */ -static int restore_one_helper(void) +static int wait_exiting_children(void) { siginfo_t info; - if (prepare_fds(current)) - return -1; - if (!child_death_expected()) { /* * Restoree has no children that should die, during restore, @@ -1136,6 +1127,22 @@ static int restore_one_helper(void) return 0; } +/* + * Restore a helper process - artificially created by criu + * to restore attributes of process tree. + * - sessions for each leaders are dead + * - process groups with dead leaders + * - dead tasks for which /proc//... is opened by restoring task + * - whatnot + */ +static int restore_one_helper(void) +{ + if (prepare_fds(current)) + return -1; + + return wait_exiting_children(); +} + static int restore_one_task(int pid, CoreEntry *core) { int i, ret; From fa098801658a5882a347df24f1434d4e9bbba3f8 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 14 Jul 2017 15:40:23 +0300 Subject: [PATCH 1271/4375] zdtm: Add sys_clone_unified() Cleanup fork() definition and make a generic function for all archs. It may be useful, when you want to add more clone flags to fork(), or if you want to pass more, than one argument to child function (glibc's clone alows only one). Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/include/util.h | 3 +++ test/zdtm/lib/test.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/criu/include/util.h b/criu/include/util.h index f95e0ae8f..70130ce7c 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -61,6 +61,9 @@ extern int open_pid_proc(pid_t pid); extern int close_pid_proc(void); extern int set_proc_fd(int fd); +extern pid_t sys_clone_unified(unsigned long flags, void *child_stack, void *parent_tid, + void *child_tid, unsigned long newtls); + /* * Values for pid argument of the proc opening routines below. * SELF would open file under /proc/self diff --git a/test/zdtm/lib/test.c b/test/zdtm/lib/test.c index 562fa56c6..2c3108850 100644 --- a/test/zdtm/lib/test.c +++ b/test/zdtm/lib/test.c @@ -296,3 +296,17 @@ void test_waitsig(void) { futex_wait_while(&sig_received, 0); } + +pid_t sys_clone_unified(unsigned long flags, void *child_stack, void *parent_tid, + void *child_tid, unsigned long newtls) +{ +#ifdef __x86_64__ + return (pid_t)syscall(__NR_clone, flags, child_stack, parent_tid, child_tid, newtls); +#elif (__i386__ || __arm__ || __aarch64__ ||__powerpc64__) + return (pid_t)syscall(__NR_clone, flags, child_stack, parent_tid, newtls, child_tid); +#elif __s390x__ + return (pid_t)syscall(__NR_clone, child_stack, flags, parent_tid, child_tid, newtls); +#else +#error "Unsupported architecture" +#endif +} From 7b87f1635e311ef199e5ec57c5d53d821b7a0db4 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 28 Dec 2017 13:51:03 +0300 Subject: [PATCH 1272/4375] zdtm: Add zombie01 test Create a zombie with specific pgid and check that pgid remains the same after restore. This test hangs criu restore without any of two previous patches: 1)without "restore: Call prepare_fds() in restore_one_zombie()" in 100% cases; 2)without "restore: Split restore_one_helper() and wait exiting zombie children" fail is racy, but you can add something like criu/cr-restore.c: ## -1130,6 +1130,8 @@ static int restore_one_zombie(CoreEntry *core) if (task_entries != NULL) { restore_finish_stage(task_entries, CR_STATE_RESTORE); + if (current->parent->pid->state == TASK_ALIVE) + sleep(2); zombie_prepare_signals(); } and it will fail with almost 100% probability. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/zombie01.c | 80 ++++++++++++++++++++++++++++++++++ test/zdtm/static/zombie01.desc | 1 + 3 files changed, 82 insertions(+) create mode 100644 test/zdtm/static/zombie01.c create mode 100644 test/zdtm/static/zombie01.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index fb288ca6c..b88a86346 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -10,6 +10,7 @@ TST_NOFILE := \ caps00 \ wait00 \ zombie00 \ + zombie01 \ fpu00 \ fpu01 \ arm-neon00 \ diff --git a/test/zdtm/static/zombie01.c b/test/zdtm/static/zombie01.c new file mode 100644 index 000000000..6e904c047 --- /dev/null +++ b/test/zdtm/static/zombie01.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check that zombie pgid is restored"; +const char *test_author = "Kirill Tkhai "; + +int main(int argc, char **argv) +{ + pid_t pid, pgrp; + siginfo_t info; + int status; + + test_init(argc, argv); + + pid = fork(); + if (pid < 0) { + fail("fork"); + exit(1); + } + + if (!pid) { + /* Child */ + if (setpgid(0, 0) < 0) { + fail("setpgid"); + exit(1); + } + pid = sys_clone_unified(CLONE_PARENT|SIGCHLD, NULL, NULL, NULL, 0); + if (pid < 0) { + fail("fork"); + exit(1); + } + + exit(0); + } + + if (waitpid(pid, &status, 0) < 0) { + fail("waitpid"); + exit(1); + } + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + pr_err("Exited with problems: status=%d\n", status); + fail("fail"); + exit(1); + } + + if (waitid(P_ALL, 0, &info, WEXITED|WNOWAIT) < 0) { + fail("waitpid"); + exit(1); + } + + test_daemon(); + test_waitsig(); + + if (waitid(P_ALL, 0, &info, WEXITED|WNOWAIT) < 0) { + fail("waitpid"); + exit(1); + } + + pgrp = getpgid(info.si_pid); + if (pgrp < 0) { + fail("getpgrp"); + exit(1); + } + + if (pgrp != pid) { + pr_err("Wrong pgrp: %d != %d\n", pgrp, pid); + fail("fail"); + exit(1); + } + + pass(); + return 0; +} diff --git a/test/zdtm/static/zombie01.desc b/test/zdtm/static/zombie01.desc new file mode 100644 index 000000000..2eac7e654 --- /dev/null +++ b/test/zdtm/static/zombie01.desc @@ -0,0 +1 @@ +{'flags': 'suid'} From 64e2791319f3ec05fc66a670736d9bbe461ec275 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:00:32 +0300 Subject: [PATCH 1273/4375] core: Init fdstore even earlier Next patch will move SELF_STDIN_OFF sfd to fdstore. This patch moves fdstore_init() before tty_prep_fds(). v4: New Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index a84e5848c..25ec4ef8b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2282,6 +2282,9 @@ int cr_restore_tasks(void) if (prepare_pstree() < 0) goto err; + if (fdstore_init()) + goto err; + if (crtools_prepare_shared() < 0) goto err; From 854342a50afee7815bc48b3d9141fc9c8309ec40 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:00:39 +0300 Subject: [PATCH 1274/4375] sfds: Kill SELF_STDIN_OFF via fdstore Place stdin in fdstore. Kill SELF_STDIN_OFF. v4: New Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 1 - criu/include/servicefd.h | 1 - criu/include/tty.h | 1 - criu/tty.c | 15 ++++++--------- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/criu/files.c b/criu/files.c index 1174700ce..05f54c2cb 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1274,7 +1274,6 @@ int prepare_fds(struct pstree_item *me) if (rsti(me)->fdt) futex_inc_and_wake(&rsti(me)->fdt->fdt_lock); out: - tty_fini_fds(); return ret; } diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h index 175e53023..0c4d6c102 100644 --- a/criu/include/servicefd.h +++ b/criu/include/servicefd.h @@ -10,7 +10,6 @@ enum sfd_type { IMG_FD_OFF, PROC_FD_OFF, /* fd with /proc for all proc_ calls */ PROC_PID_FD_OFF, - SELF_STDIN_OFF, CR_PROC_FD_OFF, /* some other's proc fd. * For dump -- target ns' proc * For restore -- CRIU ns' proc diff --git a/criu/include/tty.h b/criu/include/tty.h index 25fa1c42c..95ced8396 100644 --- a/criu/include/tty.h +++ b/criu/include/tty.h @@ -32,7 +32,6 @@ struct mount_info; extern int devpts_restore(struct mount_info *pm); extern int tty_prep_fds(void); -extern void tty_fini_fds(void); extern int devpts_check_bindmount(struct mount_info *m); diff --git a/criu/tty.c b/criu/tty.c index 76c826765..52d571c08 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -125,6 +125,7 @@ struct tty_dump_info { static bool stdin_isatty = false; static LIST_HEAD(collected_ttys); static LIST_HEAD(all_ttys); +static int self_stdin_fdid = -1; /* * Usually an application has not that many ttys opened. @@ -1000,9 +1001,9 @@ static int pty_open_unpaired_slave(struct file_desc *d, struct tty_info *slave) return -1; } - fd = dup(get_service_fd(SELF_STDIN_OFF)); + fd = fdstore_get(self_stdin_fdid); if (fd < 0) { - pr_perror("Can't dup SELF_STDIN_OFF"); + pr_err("Can't get self_stdin_fdid\n"); return -1; } @@ -2330,19 +2331,15 @@ int tty_prep_fds(void) else stdin_isatty = true; - if (install_service_fd(SELF_STDIN_OFF, STDIN_FILENO) < 0) { - pr_err("Can't dup stdin to SELF_STDIN_OFF\n"); + self_stdin_fdid = fdstore_add(STDIN_FILENO); + if (self_stdin_fdid < 0) { + pr_err("Can't place stdin fd to fdstore\n"); return -1; } return 0; } -void tty_fini_fds(void) -{ - close_service_fd(SELF_STDIN_OFF); -} - static int open_pty(void *arg, int flags) { int dfd = (unsigned long) arg; From 8a22e343f7830bb421af61b1edf743dd44f323d8 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:00:48 +0300 Subject: [PATCH 1275/4375] files: Do not close PROC_PID_FD_OFF sfd in prepare_fds() Here we need to close proc self fd only, as it's not a service fd, and it can occupy real task fd number. Closing of PROC_PID_FD_OFF is useless action here, because it's already occupy a service fd number. So, we skip this excess syscall, and leave PROC_PID_FD_OFF open. v4: New Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 2 +- criu/include/servicefd.h | 1 + criu/util.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/criu/files.c b/criu/files.c index 05f54c2cb..439108d0c 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1248,7 +1248,7 @@ int prepare_fds(struct pstree_item *me) * set than its parent */ close_service_fd(CGROUP_YARD); - close_pid_proc(); /* flush any proc cached fds we may have */ + set_proc_self_fd(-1); /* flush any proc cached fds we may have */ if (rsti(me)->fdt) { struct fdt *fdt = rsti(me)->fdt; diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h index 0c4d6c102..6266b5324 100644 --- a/criu/include/servicefd.h +++ b/criu/include/servicefd.h @@ -28,6 +28,7 @@ enum sfd_type { struct pstree_item; +extern void set_proc_self_fd(int fd); extern int clone_service_fd(int id); extern int init_service_fd(void); extern int get_service_fd(enum sfd_type type); diff --git a/criu/util.c b/criu/util.c index 75b6571f8..7b7923f22 100644 --- a/criu/util.c +++ b/criu/util.c @@ -296,7 +296,7 @@ static pid_t open_proc_pid = PROC_NONE; static pid_t open_proc_self_pid; static int open_proc_self_fd = -1; -static inline void set_proc_self_fd(int fd) +void set_proc_self_fd(int fd) { if (open_proc_self_fd >= 0) close(open_proc_self_fd); From 86289c568e04de467ea893a0231585bc1d65d63a Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:00:57 +0300 Subject: [PATCH 1276/4375] mnt: Remove useless closes in __mntns_get_root_fd() 1)Further mntns_set_root_fd() calls install_service_fd(), which silently closes already open fd. So, kill close_service_fd() and make __mntns_get_root_fd() atomical in ROOT_FD_OFF modifications. 2)close_pid_proc() is not need here, as it's about root_item's /proc directory and __mntns_get_root_fd() actions don't act on it. v4: New Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/mount.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 936587b03..a54c42139 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -3349,8 +3349,6 @@ int __mntns_get_root_fd(pid_t pid) if (mntns_root_pid == pid) /* The required root is already opened */ return get_service_fd(ROOT_FD_OFF); - close_service_fd(ROOT_FD_OFF); - if (!(root_ns_mask & CLONE_NEWNS)) { /* * If criu and tasks we dump live in the same mount @@ -3389,7 +3387,6 @@ int __mntns_get_root_fd(pid_t pid) } fd = openat(pfd, "root", O_RDONLY | O_DIRECTORY, 0); - close_pid_proc(); if (fd < 0) { pr_perror("Can't open the task root"); return -1; From c8449dbb0493325a6acddd00cf75a1f90ed69225 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:01:06 +0300 Subject: [PATCH 1277/4375] socket: Remove useless close_pid_proc() from set_netns() Net namespace does not act on /proc/[pid] context, so this close is completely useless. v4: New Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sockets.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/criu/sockets.c b/criu/sockets.c index caa1d6966..a942a6ba6 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -778,7 +778,5 @@ int set_netns(uint32_t ns_id) last_ns_id = ns_id; close(nsfd); - close_pid_proc(); - return 0; } From 2f3017868ea8a23053b6d9bed499e46c491e2b67 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:01:15 +0300 Subject: [PATCH 1278/4375] utils: Add print_stack_trace() Function to print call trace of a process. Borrowed from this fm: https://www.gnu.org/software/libc/manual/html_node/Backtraces.html backtrace() and backtrace_symbols() are not implemented in alpine, so we use __GLIBC__ ifdef to do not compile this function there. v4: New Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/include/util.h | 5 +++++ criu/util.c | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/criu/include/util.h b/criu/include/util.h index 70130ce7c..7324fee8b 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -348,6 +348,11 @@ extern int epoll_run_rfds(int epfd, struct epoll_event *evs, int nr_fds, int tmo extern int epoll_prepare(int nr_events, struct epoll_event **evs); extern int call_in_child_process(int (*fn)(void *), void *arg); +#ifdef __GLIBC__ +extern void print_stack_trace(pid_t pid); +#else +static inline void print_stack_trace(pid_t pid) {} +#endif #define block_sigmask(saved_mask, sig_mask) ({ \ sigset_t ___blocked_mask; \ diff --git a/criu/util.c b/criu/util.c index 7b7923f22..dea0a307d 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1407,3 +1407,21 @@ out: close_pid_proc(); return ret; } + +#ifdef __GLIBC__ +#include +void print_stack_trace(pid_t pid) +{ + void *array[10]; + char **strings; + size_t size, i; + + size = backtrace(array, 10); + strings = backtrace_symbols(array, size); + + for (i = 0; i < size; i++) + pr_err("stack %d#%zu: %s\n", pid, i, strings[i]); + + free(strings); +} +#endif From f326061d985c32bb0e298b97d0804e897be9c6cf Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 12 Jan 2018 11:55:27 +0300 Subject: [PATCH 1279/4375] sfds: Protect service fds reuse This patch introduces sfds_protected, which allows to mask areas, where modifications of sfds are prohibited. That guarantees, that populated sfds won't be reused. v4: New v5: Add comment and print sfd type before BUG(). Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/include/servicefd.h | 1 + criu/util.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h index 6266b5324..812396310 100644 --- a/criu/include/servicefd.h +++ b/criu/include/servicefd.h @@ -27,6 +27,7 @@ enum sfd_type { }; struct pstree_item; +extern bool sfds_protected; extern void set_proc_self_fd(int fd); extern int clone_service_fd(int id); diff --git a/criu/util.c b/criu/util.c index dea0a307d..cf2e04c9b 100644 --- a/criu/util.c +++ b/criu/util.c @@ -473,12 +473,27 @@ int service_fd_min_fd(struct pstree_item *item) } static DECLARE_BITMAP(sfd_map, SERVICE_FD_MAX); +/* + * Variable for marking areas of code, where service fds modifications + * are prohibited. It's used to safe them from reusing their numbers + * by ordinary files. See install_service_fd() and close_service_fd(). + */ +bool sfds_protected = false; + +static void sfds_protection_bug(enum sfd_type type) +{ + pr_err("Service fd %u is being modified in protected context\n", type); + print_stack_trace(current ? vpid(current) : 0); + BUG(); +} int install_service_fd(enum sfd_type type, int fd) { int sfd = __get_service_fd(type, service_fd_id); BUG_ON((int)type <= SERVICE_FD_MIN || (int)type >= SERVICE_FD_MAX); + if (sfds_protected && !test_bit(type, sfd_map)) + sfds_protection_bug(type); if (dup3(fd, sfd, O_CLOEXEC) != sfd) { pr_perror("Dup %d -> %d failed", fd, sfd); @@ -508,6 +523,9 @@ int close_service_fd(enum sfd_type type) { int fd; + if (sfds_protected) + sfds_protection_bug(type); + fd = get_service_fd(type); if (fd < 0) return 0; From f4cbf3849880412ca14ad67727b6e2b887c800f1 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:01:33 +0300 Subject: [PATCH 1280/4375] mnt: Populate ROOT_FD_OFF This patch populates and occupies ROOT_FD_OFF fd, which guarantees it won't be reused by ordinary fds. v4: New Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 25ec4ef8b..d1d07196e 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -383,6 +383,23 @@ err: return ret; } +/* This actually populates and occupies ROOT_FD_OFF sfd */ +static int populate_root_fd_off(void) +{ + struct ns_id *mntns = NULL; + int ret; + + if (root_ns_mask & CLONE_NEWNS) { + mntns = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc); + BUG_ON(!mntns); + } + + ret = mntns_get_root_fd(mntns); + if (ret < 0) + pr_err("Can't get root fd\n"); + return ret >= 0 ? 0 : -1; +} + static rt_sigaction_t sigchld_act; /* * If parent's sigaction has blocked SIGKILL (which is non-sence), @@ -1651,6 +1668,9 @@ static int restore_task_with_children(void *_arg) if (root_prepare_shared()) goto err; + + if (populate_root_fd_off()) + goto err; } if (restore_task_mnt_ns(current)) From 79bebdda96d27088927980019c3959b06732421a Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:01:51 +0300 Subject: [PATCH 1281/4375] sfds: Populate pid proc This patch populates/occupies PROC_FD_OFF fd number, which is goint to be replaced atomically in next patches. v4: New Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index d1d07196e..0ed655d50 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -400,6 +400,15 @@ static int populate_root_fd_off(void) return ret >= 0 ? 0 : -1; } +static int populate_pid_proc(void) +{ + if (open_pid_proc(vpid(current)) < 0) { + pr_err("Can't open PROC_SELF\n"); + return -1; + } + return 0; +} + static rt_sigaction_t sigchld_act; /* * If parent's sigaction has blocked SIGKILL (which is non-sence), @@ -1697,6 +1706,9 @@ static int restore_task_with_children(void *_arg) timing_stop(TIME_FORK); + if (populate_pid_proc()) + goto err; + if (unmap_guard_pages(current)) goto err; From 71ccb4a074e1c37c33857aa619004951997818e2 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:02:00 +0300 Subject: [PATCH 1282/4375] sfds: Protect service fds Mark area, where service fds modifications are prohibited. v4: New Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 4 ++++ criu/files.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 0ed655d50..fe322641c 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1181,6 +1181,7 @@ static int restore_one_task(int pid, CoreEntry *core) ret = restore_one_zombie(core); else if (current->pid->state == TASK_HELPER) { ret = restore_one_helper(); + sfds_protected = false; close_image_dir(); close_proc(); for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) @@ -1709,6 +1710,8 @@ static int restore_task_with_children(void *_arg) if (populate_pid_proc()) goto err; + sfds_protected = true; + if (unmap_guard_pages(current)) goto err; @@ -3436,6 +3439,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns if (restore_fs(current)) goto err; + sfds_protected = false; close_image_dir(); close_proc(); close_service_fd(TRANSPORT_FD_OFF); diff --git a/criu/files.c b/criu/files.c index 439108d0c..38a36895f 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1247,7 +1247,9 @@ int prepare_fds(struct pstree_item *me) * correct /tasks file if it is in a different cgroup * set than its parent */ + sfds_protected = false; close_service_fd(CGROUP_YARD); + sfds_protected = true; set_proc_self_fd(-1); /* flush any proc cached fds we may have */ if (rsti(me)->fdt) { From ab36e28dd8f8012ead606bd76ad44cf72478de64 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:02:09 +0300 Subject: [PATCH 1283/4375] files: Rename service_fd_rlim_cur to service_fd_base_cur Next patches will make service fds numbers not connected not rlimit. Change the name to better fit its goal. Also, leave service_fd_rlim_cur variable to have cached access to rlimit value. Signed-off-by: Kirill Tkhai v2: More comments Signed-off-by: Andrei Vagin --- criu/include/util.h | 2 ++ criu/util.c | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/criu/include/util.h b/criu/include/util.h index 7324fee8b..5c18e69f7 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -37,6 +37,8 @@ struct vma_area; struct list_head; +extern int service_fd_rlim_cur; + extern void pr_vma(unsigned int loglevel, const struct vma_area *vma_area); #define pr_info_vma(vma_area) pr_vma(LOG_INFO, vma_area) diff --git a/criu/util.c b/criu/util.c index cf2e04c9b..f91c09f2c 100644 --- a/criu/util.c +++ b/criu/util.c @@ -434,7 +434,11 @@ int do_open_proc(pid_t pid, int flags, const char *fmt, ...) return openat(dirfd, path, flags); } -static int service_fd_rlim_cur; +/* Max potentially possible fd to be open by criu process */ +int service_fd_rlim_cur; +/* Base of current process service fds set */ +static int service_fd_base; +/* Id of current process in shared fdt */ static int service_fd_id = 0; int init_service_fd(void) @@ -452,14 +456,15 @@ int init_service_fd(void) } service_fd_rlim_cur = (int)rlimit.rlim_cur; - BUG_ON(service_fd_rlim_cur < SERVICE_FD_MAX); + service_fd_base = service_fd_rlim_cur; + BUG_ON(service_fd_base < SERVICE_FD_MAX); return 0; } static int __get_service_fd(enum sfd_type type, int service_fd_id) { - return service_fd_rlim_cur - type - SERVICE_FD_MAX * service_fd_id; + return service_fd_base - type - SERVICE_FD_MAX * service_fd_id; } int service_fd_min_fd(struct pstree_item *item) From 72c1c1a6ab203c7c74da879d41f4e6ae47fe00ca Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:02:18 +0300 Subject: [PATCH 1284/4375] files: Count inh_fd_max This patch counts maximum of inherited fds. The value will be used in next patch. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 5 +++++ criu/include/files.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/criu/files.c b/criu/files.c index 38a36895f..9cb3f7937 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1455,6 +1455,8 @@ struct inherit_fd { dev_t inh_rdev; }; +int inh_fd_max = -1; + /* * Return 1 if inherit fd has been closed or reused, 0 otherwise. * @@ -1551,6 +1553,9 @@ int inherit_fd_add(int fd, char *key) if (inh == NULL) return -1; + if (fd > inh_fd_max) + inh_fd_max = fd; + inh->inh_id = key; inh->inh_fd = fd; inh->inh_dev = sbuf.st_dev; diff --git a/criu/include/files.h b/criu/include/files.h index 27ae1a04b..b3330cf82 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -91,6 +91,8 @@ struct fdinfo_list_entry { u8 fake:1; }; +extern int inh_fd_max; + /* reports whether fd_a takes prio over fd_b */ static inline int fdinfo_rst_prio(struct fdinfo_list_entry *fd_a, struct fdinfo_list_entry *fd_b) { From dfb7705df09a05647ee75a85abef403d37fd9195 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:02:27 +0300 Subject: [PATCH 1285/4375] files: Pass pstree_item argument to clone_service_fd() Refactoring for next patches. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- criu/include/servicefd.h | 2 +- criu/util.c | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index fe322641c..9717b17d1 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1035,7 +1035,7 @@ static int restore_one_zombie(CoreEntry *core) static int setup_newborn_fds(struct pstree_item *me) { - if (clone_service_fd(rsti(me)->service_fd_id)) + if (clone_service_fd(me)) return -1; if (!me->parent || diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h index 812396310..25cb68bdd 100644 --- a/criu/include/servicefd.h +++ b/criu/include/servicefd.h @@ -30,7 +30,7 @@ struct pstree_item; extern bool sfds_protected; extern void set_proc_self_fd(int fd); -extern int clone_service_fd(int id); +extern int clone_service_fd(struct pstree_item *me); extern int init_service_fd(void); extern int get_service_fd(enum sfd_type type); extern int install_service_fd(enum sfd_type type, int fd); diff --git a/criu/util.c b/criu/util.c index f91c09f2c..43a975d07 100644 --- a/criu/util.c +++ b/criu/util.c @@ -542,9 +542,11 @@ int close_service_fd(enum sfd_type type) return 0; } -int clone_service_fd(int id) +int clone_service_fd(struct pstree_item *me) { - int ret = -1, i; + int id, i, ret = -1; + + id = rsti(me)->service_fd_id; if (service_fd_id == id) return 0; From d076328ce067baeeb38682b246a6739753e5f582 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:02:35 +0300 Subject: [PATCH 1286/4375] files: Close old service fd in clone_service_fd() Next patches will make service_fd_base not contant. It will be "floating" and change from task to task. This patch makes preparation for that: it closes old service fd after it's duplicated. Currently the code is unused as in case of !(rsti(me)->clone_flags & CLONE_FILES), the child has the same id as its parent, and the duplication just does not occur. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/util.c b/criu/util.c index 43a975d07..4a6ca8444 100644 --- a/criu/util.c +++ b/criu/util.c @@ -563,6 +563,8 @@ int clone_service_fd(struct pstree_item *me) continue; pr_perror("Unable to clone %d->%d", old, new); } + if (ret >= 0 && !(rsti(me)->clone_flags & CLONE_FILES)) + close(old); } service_fd_id = id; From 37b99ebe5bc65bf48218d8bfe079bc59bc0a39a9 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:02:44 +0300 Subject: [PATCH 1287/4375] files: Do setup_newborn_fds() later This patch makes the call of service fds relocation after root_prepare_shared()->prepare_fd_pid(). Next patches will make service_fd_base depend on task's max fd used, and for root_item we need to read all fles to know the maximum of them. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 9717b17d1..e08e6ed6f 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1051,9 +1051,6 @@ static int setup_newborn_fds(struct pstree_item *me) return -1; } - if (log_init_by_pid(vpid(me))) - return -1; - return 0; } @@ -1607,9 +1604,6 @@ static int restore_task_with_children(void *_arg) if ( !(ca->clone_flags & CLONE_FILES)) close_safe(&ca->fd); - if (setup_newborn_fds(current)) - goto err; - pid = getpid(); if (vpid(current) != pid) { pr_err("Pid %d do not match expected %d\n", pid, vpid(current)); @@ -1617,6 +1611,9 @@ static int restore_task_with_children(void *_arg) goto err; } + if (log_init_by_pid(vpid(current))) + return -1; + if (current->parent == NULL) { /* * The root task has to be in its namespaces before executing @@ -1683,6 +1680,9 @@ static int restore_task_with_children(void *_arg) goto err; } + if (setup_newborn_fds(current)) + goto err; + if (restore_task_mnt_ns(current)) goto err; From 6c4b0de065404f4b0a5365f4d33797027af35709 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:02:53 +0300 Subject: [PATCH 1288/4375] files: Refactor clone_service_fd() This patch just moves part of clone_service_fd() to separate function, that change readability of the code. There are no functional changes, only refactoring. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/util.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/criu/util.c b/criu/util.c index 4a6ca8444..7deb34ee6 100644 --- a/criu/util.c +++ b/criu/util.c @@ -542,30 +542,34 @@ int close_service_fd(enum sfd_type type) return 0; } +static void move_service_fd(struct pstree_item *me, int type, int new_id, int new_base) +{ + int old = get_service_fd(type); + int new = __get_service_fd(type, new_id); + int ret; + + if (old < 0) + return; + ret = dup2(old, new); + if (ret == -1) { + if (errno != EBADF) + pr_perror("Unable to clone %d->%d", old, new); + } else if (!(rsti(me)->clone_flags & CLONE_FILES)) + close(old); +} + int clone_service_fd(struct pstree_item *me) { - int id, i, ret = -1; + int id, new_base, i, ret = -1; + new_base = service_fd_base; id = rsti(me)->service_fd_id; if (service_fd_id == id) return 0; - for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) { - int old = get_service_fd(i); - int new = __get_service_fd(i, id); - - if (old < 0) - continue; - ret = dup2(old, new); - if (ret == -1) { - if (errno == EBADF) - continue; - pr_perror("Unable to clone %d->%d", old, new); - } - if (ret >= 0 && !(rsti(me)->clone_flags & CLONE_FILES)) - close(old); - } + for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) + move_service_fd(me, i, id, new_base); service_fd_id = id; ret = 0; From 928d116d910ec40cfd31db79e67973d889704d5b Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:03:02 +0300 Subject: [PATCH 1289/4375] files: Prepare clone_service_fd() for overlaping ranges. In normal life this is impossible. But in case of big fdt::nr number (many processes, sharing the same files), and custom service_fd_base, normal (!CLONE_FILES) child of such process may have overlaping service fds with parent's fdt. This patch introduces "memmove()" behavior (currently there is "memcpy()" behavior) and this will be used in next patch. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/util.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/criu/util.c b/criu/util.c index 7deb34ee6..0758c7b80 100644 --- a/criu/util.c +++ b/criu/util.c @@ -568,8 +568,13 @@ int clone_service_fd(struct pstree_item *me) if (service_fd_id == id) return 0; - for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) - move_service_fd(me, i, id, new_base); + /* Dup sfds in memmove() style: they may overlap */ + if (get_service_fd(LOG_FD_OFF) > __get_service_fd(LOG_FD_OFF, id)) + for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) + move_service_fd(me, i, id, new_base); + else + for (i = SERVICE_FD_MAX - 1; i > SERVICE_FD_MIN; i--) + move_service_fd(me, i, id, new_base); service_fd_id = id; ret = 0; From 64ae0364d1c07cf4dfe187f900d2b98da0a2f983 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:03:10 +0300 Subject: [PATCH 1290/4375] files: Make tasks set their own service_fd_base Currently, we set rlim(RLIMIT_NOFILE) unlimited and service_fd_rlim_cur to place service fds. This leads to a signify problem: every task uses the biggest possible files_struct in kernel, and it consumes excess memory after restore in comparation to dump. In some situations this may end in restore fail as there is no enough memory in memory cgroup of on node. The patch fixes the problem by introducing task-measured service_fd_base. It's calculated in dependence of max used file fd and is placed near the right border of kernel-allocated memory hunk for task's fds (see alloc_fdtable() for details). This reduces kernel-allocated files_struct to 512 fds for the most process in standard linux system (I've analysed the processes in my work system). Also, since the "standard processes" will have the same service_fd_base, clone_service_fd() won't have to actualy dup() their service fds for them like we have at the moment. This is the one of reasons why we still keep service fds as a range of fds, and do not try to use unused holes in task fds. Signed-off-by: Kirill Tkhai v2: Add a handle for very big fd numbers near service_fd_rlim_cur. v3: Fix excess accounting for nr equal to pow 2 minus 1. Signed-off-by: Andrei Vagin --- criu/util.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/criu/util.c b/criu/util.c index 0758c7b80..cc47d1778 100644 --- a/criu/util.c +++ b/criu/util.c @@ -545,7 +545,7 @@ int close_service_fd(enum sfd_type type) static void move_service_fd(struct pstree_item *me, int type, int new_id, int new_base) { int old = get_service_fd(type); - int new = __get_service_fd(type, new_id); + int new = new_base - type - SERVICE_FD_MAX * new_id; int ret; if (old < 0) @@ -558,24 +558,73 @@ static void move_service_fd(struct pstree_item *me, int type, int new_id, int ne close(old); } +static int choose_service_fd_base(struct pstree_item *me) +{ + int nr, real_nr, fdt_nr = 1, id = rsti(me)->service_fd_id; + + if (rsti(me)->fdt) { + /* The base is set by owner of fdt (id 0) */ + if (id != 0) + return service_fd_base; + fdt_nr = rsti(me)->fdt->nr; + } + /* Now find process's max used fd number */ + if (!list_empty(&rsti(me)->fds)) + nr = list_entry(rsti(me)->fds.prev, + struct fdinfo_list_entry, ps_list)->fe->fd; + else + nr = -1; + + nr = max(nr, inh_fd_max); + /* + * Service fds go after max fd near right border of alignment: + * + * ...|max_fd|max_fd+1|...|sfd first|...|sfd last (aligned)| + * + * So, they take maximum numbers of area allocated by kernel. + * See linux alloc_fdtable() for details. + */ + nr += (SERVICE_FD_MAX - SERVICE_FD_MIN) * fdt_nr; + nr += 16; /* Safety pad */ + real_nr = nr; + + nr /= (1024 / sizeof(void *)); + nr = 1 << (32 - __builtin_clz(nr)); + nr *= (1024 / sizeof(void *)); + + if (nr > service_fd_rlim_cur) { + /* Right border is bigger, than rlim. OK, then just aligned value is enough */ + nr = round_down(service_fd_rlim_cur, (1024 / sizeof(void *))); + if (nr < real_nr) { + pr_err("Can't chose service_fd_base: %d %d\n", nr, real_nr); + return -1; + } + } + + return nr; +} + int clone_service_fd(struct pstree_item *me) { int id, new_base, i, ret = -1; - new_base = service_fd_base; + new_base = choose_service_fd_base(me); id = rsti(me)->service_fd_id; - if (service_fd_id == id) + if (new_base == -1) + return -1; + if (service_fd_base == new_base && service_fd_id == id) return 0; /* Dup sfds in memmove() style: they may overlap */ - if (get_service_fd(LOG_FD_OFF) > __get_service_fd(LOG_FD_OFF, id)) + if (get_service_fd(LOG_FD_OFF) > new_base - LOG_FD_OFF - SERVICE_FD_MAX * id) for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) move_service_fd(me, i, id, new_base); else for (i = SERVICE_FD_MAX - 1; i > SERVICE_FD_MIN; i--) move_service_fd(me, i, id, new_base); + service_fd_base = new_base; service_fd_id = id; ret = 0; From 248a04e086087a7f5fdf9c589ca5f588fd606274 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 10 Jan 2018 17:03:19 +0300 Subject: [PATCH 1291/4375] zdtm: Add fd01 test Fork tasks and create fds with different numbers. Some children share file with parent (CLONE_FILES). Check, than we can suspend and resume in this case. v2: New Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/fd01.c | 106 +++++++++++++++++++++++++++++++++++++ test/zdtm/static/fd01.desc | 1 + 3 files changed, 108 insertions(+) create mode 100644 test/zdtm/static/fd01.c create mode 100644 test/zdtm/static/fd01.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index b88a86346..db022b856 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -173,6 +173,7 @@ TST_NOFILE := \ aio00 \ aio01 \ fd \ + fd01 \ apparmor \ seccomp_strict \ seccomp_filter \ diff --git a/test/zdtm/static/fd01.c b/test/zdtm/static/fd01.c new file mode 100644 index 000000000..7f0256a03 --- /dev/null +++ b/test/zdtm/static/fd01.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" +#include "lock.h" + +const char *test_doc = "Create file descriptors with different numbers. Check that they do not intersect with service fds"; +const char *test_author = "Kirill Tkhai "; + +int main(int argc, char **argv) +{ + unsigned int i, max_nr, flags; + int fd, status, ret; + struct rlimit rlim; + char buf[16]; + pid_t pid; + + test_init(argc, argv); + + fd = open("/proc/sys/fs/nr_open", O_RDONLY); + if (fd < 0) { + fail("Can't open /proc/sys/fs/nr_open"); + exit(1); + } + + ret = read(fd, buf, sizeof(buf)); + if (ret <= 0) { + fail("Can't read"); + exit(1); + } + buf[ret] = '\0'; + + max_nr = (unsigned int)atol(buf); + if (max_nr == 0) { + fail("max_nr"); + exit(1); + } + + if (getrlimit(RLIMIT_NOFILE, &rlim)) { + fail("getrlimit"); + exit(1); + } + + rlim.rlim_cur = rlim.rlim_max; + if (max_nr < rlim.rlim_cur) + rlim.rlim_cur = max_nr; + + if (prlimit(getpid(), RLIMIT_NOFILE, &rlim, NULL)) { + fail("rlimir: Can't setup RLIMIT_NOFILE for self"); + exit(1); + } + + + for (i = 1; (fd = (1 << i)) < (rlim.rlim_cur >> 1); i++) { + FILE *fp = tmpfile(); + if (!fp) { + fail("tmpfile"); + exit(1); + } + + /* This fd really exists, skip it */ + if (fcntl(fd, F_GETFL) >= 0) + continue; + + if (dup2(fileno(fp), fd) < 0) { + fail("dup2"); + exit(1); + } + + flags = SIGCHLD; + if (i % 2 == 0) + flags |= CLONE_FILES; + + pid = sys_clone_unified(flags, NULL, NULL, NULL, 0); + if (pid < 0) { + fail("fork"); + exit(1); + } else if (!pid) { + pause(); + exit(0); + } + } + + test_daemon(); + test_waitsig(); + + /* Cleanup */ + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { + if (kill(pid, SIGTERM) == 0) + waitpid(-1, &status, 0); /* Ignore errors */ + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/fd01.desc b/test/zdtm/static/fd01.desc new file mode 100644 index 000000000..2eac7e654 --- /dev/null +++ b/test/zdtm/static/fd01.desc @@ -0,0 +1 @@ +{'flags': 'suid'} From f7934aa31b80fe8ebfc6420acccc824a5a9d140d Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 17 Jan 2018 10:56:07 +0300 Subject: [PATCH 1292/4375] files: make convert_path_from_another_mp always return relative path If dmi->ns_mountpoint is "/" then in dst we will return "/..." - absolute path but we want here path relative to dmi mount. Adding "./" before the path guaranties that it will be always relative. https://jira.sw.ru/browse/PSBM-72351 Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 10165d61d..12bf6db2a 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1347,7 +1347,7 @@ static void convert_path_from_another_mp(char *src, char *dst, int dlen, * Absolute path to the mount point + difference between source * and destination roots + path relative to the mountpoint. */ - snprintf(dst, dlen, "%s/%s/%s", + snprintf(dst, dlen, "./%s/%s/%s", dmi->ns_mountpoint + 1, smi->root + strlen(dmi->root), src + off); From 9ffe2f338d938af90c05ab542299109e5f70f135 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 17 Jan 2018 10:56:08 +0300 Subject: [PATCH 1293/4375] zdtm: check ghost restores on readonly fs if it is also a ghost in other writable bind It is a test for convert_path_from_another_mp fix, it is a bit tricky as we don't fully support ghosts on readonly fs, but only if the ghost can be remaped on some _other_ bindmount (luckily we have same ghost on other bind). Moreover wrong absolute path generated with old convert_path_from _another_mp for lnkat don't always fail, only in case we want to do linkat on mount in _other_ mountns and absolute path makes us do it in local mountns and local path is readonly and we fail. =) v2: remove unused headers Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/mntns_ghost01.c | 120 ++++++++++++++++++++++++++++ test/zdtm/static/mntns_ghost01.desc | 1 + 3 files changed, 122 insertions(+) create mode 100644 test/zdtm/static/mntns_ghost01.c create mode 100644 test/zdtm/static/mntns_ghost01.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index db022b856..f5e0230d3 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -307,6 +307,7 @@ TST_DIR = \ mntns_open \ mntns_link_remap \ mntns_ghost \ + mntns_ghost01 \ mntns_ro_root \ mntns_link_ghost \ mntns_shared_bind \ diff --git a/test/zdtm/static/mntns_ghost01.c b/test/zdtm/static/mntns_ghost01.c new file mode 100644 index 000000000..665e1e162 --- /dev/null +++ b/test/zdtm/static/mntns_ghost01.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check ghost file is restored on readonly fs if it was ghost-remaped on writable bind"; +const char *test_author = "Pavel Tikhomirov "; + +char *dirname; +TEST_OPTION(dirname, string, "directory name", 1); + + +int main(int argc, char **argv) +{ + char ghost_path[PATH_MAX]; + task_waiter_t lock; + pid_t pid = -1; + int status = 1; + int pfd; + + test_init(argc, argv); + task_waiter_init(&lock); + + if (mkdir(dirname, 0600) < 0) { + pr_perror("mkdir"); + return 1; + } + + snprintf(ghost_path, PATH_MAX, "%s/test.ghost", dirname); + + pfd = open(ghost_path, O_CREAT | O_WRONLY, 0600); + if (pfd < 0) { + pr_perror("open"); + return 1; + } + close(pfd); + + pfd = open(ghost_path, O_RDONLY); + if (pfd < 0) { + pr_perror("open"); + return 1; + } + + pid = fork(); + if (pid < 0) { + pr_perror("fork"); + return 1; + } + + if (pid == 0) { + int fd; + + if (unshare(CLONE_NEWNS)) { + pr_perror("unshare"); + return 1; + } + + if (mount(NULL, "/", NULL, MS_PRIVATE | MS_REC, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(dirname, dirname, NULL, MS_BIND, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, dirname, NULL, MS_RDONLY|MS_REMOUNT|MS_BIND, NULL)) { + pr_perror("remount"); + return 1; + } + + fd = open(ghost_path, O_RDONLY); + if (fd < 0) { + pr_perror("open"); + return 1; + } + + task_waiter_complete(&lock, 1); + test_waitsig(); + + if (close(fd)) { + pr_perror("close"); + return 1; + } + + return 0; + } + + task_waiter_wait4(&lock, 1); + + if (unlink(ghost_path)) { + pr_perror("unlink"); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (close(pfd)) { + pr_perror("close"); + return 1; + } + + kill(pid, SIGTERM); + wait(&status); + if (status) { + fail("Test died"); + return 1; + } + pass(); + + return 0; +} diff --git a/test/zdtm/static/mntns_ghost01.desc b/test/zdtm/static/mntns_ghost01.desc new file mode 100644 index 000000000..8a1ef8a3d --- /dev/null +++ b/test/zdtm/static/mntns_ghost01.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns', 'flags': 'suid', 'feature': 'mnt_id', 'opts': '--link-remap'} From 0d9d27120329cfefcc0e8f32ef39c5ce9ec909c0 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 17 Jan 2018 10:56:09 +0300 Subject: [PATCH 1294/4375] files: change error to warning in linkat_hard error path We print errors in all error cases when calling linkat_hard anyway, but for some errors like EEXIST we are fine and just skip them, so we should not print error here. Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 12bf6db2a..c0b9b2fe2 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1366,7 +1366,7 @@ static int linkat_hard(int odir, char *opath, int ndir, char *npath, uid_t uid, if (!( (errno == EPERM || errno == EOVERFLOW) && (root_ns_mask & CLONE_NEWUSER) )) { errno_save = errno; - pr_perror("Can't link %s -> %s", opath, npath); + pr_warn("Can't link %s -> %s", opath, npath); errno = errno_save; return ret; } From ecbec8be076b444511c0cc74033fa9c5e66929bb Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 25 Jan 2018 16:46:59 -0800 Subject: [PATCH 1295/4375] bfd: avoid out-of-bound access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Write a nullbyte only if there is enought space for it. Cc: Stephen Röttger Reported-by: Stephen Röttger Signed-off-by: Andrei Vagin --- criu/bfd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/criu/bfd.c b/criu/bfd.c index 8269ab1a2..500737a8e 100644 --- a/criu/bfd.c +++ b/criu/bfd.c @@ -196,6 +196,11 @@ again: if (!b->sz) return NULL; + if (b->sz == BUFSIZE) { + pr_err("The bfd buffer is too small\n"); + ERR_PTR(-EIO); + return NULL; + } /* * Last bytes may lack the \n at the * end, need to report this as full From 9c93e0d3ef29129bdc02519c45305d8c48d92db8 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 25 Jan 2018 17:27:19 -0800 Subject: [PATCH 1296/4375] criu: fix two issue with possible out-of-bound access Signed-off-by: Andrei Vagin --- criu/kerndat.c | 2 +- criu/pie/parasite.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/kerndat.c b/criu/kerndat.c index d20f1e26e..3477f88ca 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -197,7 +197,7 @@ int kerndat_files_stat(bool early) buf[ret] = '\0'; max_files = atol(buf); } - ret = read(fd2, buf, sizeof(buf)); + ret = read(fd2, buf, sizeof(buf) - 1); if (ret > 0) { buf[ret] = '\0'; nr_open = atol(buf); diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index 12b8cb981..7a48f324e 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -630,7 +630,7 @@ static int parasite_dump_cgroup(struct parasite_dump_cgroup_args *args) return -1; } - if (len == sizeof(*args)) { + if (len == sizeof(args->contents)) { pr_warn("/proc/self/cgroup was bigger than the page size\n"); return -1; } From 901d0de945ca876421a60662c7668632fdcec34f Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 28 Jan 2018 23:11:33 +0300 Subject: [PATCH 1297/4375] zdtm: suppress useless error messages Start test ./mxcsr --pidfile=mxcsr.pid --outfile=mxcsr.out Run criu dump Unable to kill 44: [Errno 3] No such process <--------------- this one Run criu restore Run criu dump Signed-off-by: Andrei Vagin Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> --- test/zdtm.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 3ed9f2994..98cbfa23f 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -313,8 +313,7 @@ def wait_pid_die(pid, who, tmo = 30): while stime < tmo: try: os.kill(int(pid), 0) - except Exception, e: - print "Unable to kill %d: %s" % (pid, e) + except OSError, e: break print "Wait for %s(%d) to die for %f" % (who, pid, stime) From 455b96c0785f09419fbd43e7ca842acc7d3a532f Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 29 Jan 2018 11:21:07 +0300 Subject: [PATCH 1298/4375] mount: fix uninitialized use of fd on switch_ns error close_safe can operate uninitialized fd in case of error in switch_ns, found by Coverity Scan: *** CID 187164: Uninitialized variables (UNINIT) /criu/mount.c: 1313 in open_mountpoint() 1307 err: 1308 return 1; 1309 } 1310 1311 int open_mountpoint(struct mount_info *pm) 1312 { >>> CID 187164: Uninitialized variables (UNINIT) >>> Declaring variable "fd" without initializer. 1313 int fd, cwd_fd, ns_old = -1; 1314 1315 /* No overmounts and children - the entire mount is visible */ 1316 if (list_empty(&pm->children) && !mnt_is_overmounted(pm)) 1317 return __open_mountpoint(pm, -1); 1318 Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/mount.c b/criu/mount.c index a54c42139..89a3ac90d 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1310,7 +1310,7 @@ err: int open_mountpoint(struct mount_info *pm) { - int fd, cwd_fd, ns_old = -1; + int fd = -1, cwd_fd, ns_old = -1; /* No overmounts and children - the entire mount is visible */ if (list_empty(&pm->children) && !mnt_is_overmounted(pm)) From f48bf9825fcdc169f20d3ec6ef7d509d87c8bc46 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 29 Jan 2018 11:21:08 +0300 Subject: [PATCH 1299/4375] mount: fix cwd_fd leak on clone error We should close cwd_fd on error paths, found by Coverity Scan: *** CID 187162: Resource leaks (RESOURCE_LEAK) /criu/mount.c: 1370 in open_mountpoint() 1364 */ 1365 pid = clone_noasan(ns_open_mountpoint, CLONE_VFORK | CLONE_VM 1366 | CLONE_FILES | CLONE_IO | CLONE_SIGHAND 1367 | CLONE_SYSVSEM, &ca); 1368 if (pid == -1) { 1369 pr_perror("Can't clone helper process"); >>> CID 187162: Resource leaks (RESOURCE_LEAK) >>> Handle variable "cwd_fd" going out of scope leaks the handle. 1370 return -1; 1371 } 1372 1373 errno = 0; 1374 if (waitpid(pid, &status, __WALL) != pid || !WIFEXITED(status) 1375 || WEXITSTATUS(status)) { Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 89a3ac90d..1beff348f 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1367,7 +1367,7 @@ int open_mountpoint(struct mount_info *pm) | CLONE_SYSVSEM, &ca); if (pid == -1) { pr_perror("Can't clone helper process"); - return -1; + goto err; } errno = 0; @@ -1375,7 +1375,7 @@ int open_mountpoint(struct mount_info *pm) || WEXITSTATUS(status)) { pr_err("Can't wait or bad status: errno=%d, status=%d\n", errno, status); - return -1; + goto err; } } From 4fe32e5d44bda19e02ac3c00f2080f8d79f86cc2 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 1 Feb 2018 17:54:12 +0300 Subject: [PATCH 1300/4375] zdtm: Fix fd01 cleanup waitpid() does not return child pid, when child has not exited. So, we can't use it to find pids of children. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- test/zdtm/static/fd01.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/test/zdtm/static/fd01.c b/test/zdtm/static/fd01.c index 7f0256a03..4e7875110 100644 --- a/test/zdtm/static/fd01.c +++ b/test/zdtm/static/fd01.c @@ -22,11 +22,19 @@ int main(int argc, char **argv) unsigned int i, max_nr, flags; int fd, status, ret; struct rlimit rlim; + futex_t *futex; char buf[16]; pid_t pid; test_init(argc, argv); + futex = mmap(NULL, sizeof(*futex), PROT_WRITE | PROT_READ, MAP_ANONYMOUS|MAP_SHARED, -1, 0); + if (futex == MAP_FAILED) { + fail("mmap"); + exit(1); + } + futex_init(futex); + fd = open("/proc/sys/fs/nr_open", O_RDONLY); if (fd < 0) { fail("Can't open /proc/sys/fs/nr_open"); @@ -86,7 +94,7 @@ int main(int argc, char **argv) fail("fork"); exit(1); } else if (!pid) { - pause(); + futex_wait_while(futex, 0); exit(0); } } @@ -95,9 +103,12 @@ int main(int argc, char **argv) test_waitsig(); /* Cleanup */ - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { - if (kill(pid, SIGTERM) == 0) - waitpid(-1, &status, 0); /* Ignore errors */ + futex_set_and_wake(futex, 1); + while (wait(&status) > 0) { + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + fail("Wrong exit status: %d", status); + exit(1); + } } pass(); From 7f936f3bbb171ad6ab2ee454b803483ec0799f19 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 2 Feb 2018 00:55:29 +0300 Subject: [PATCH 1301/4375] zdtm: fix a lint warning $ make lint flake8 --config=scripts/flake8.cfg test/zdtm.py test/zdtm.py:323:19: F841 local variable 'e' is assigned to but never used Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index 98cbfa23f..f74275036 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -314,6 +314,8 @@ def wait_pid_die(pid, who, tmo = 30): try: os.kill(int(pid), 0) except OSError, e: + if e.errno != errno.ESRCH: + print e break print "Wait for %s(%d) to die for %f" % (who, pid, stime) From 4ca191148924d6496e8d8a523bc504a03d5c8898 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 2 Feb 2018 10:19:35 +0300 Subject: [PATCH 1302/4375] travis: don't fail a build when the s390 job failed Builds for s390x fail due to a qemu bug. Signed-off-by: Andrei Vagin --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index ff2e09b83..b6766a01c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,7 @@ matrix: - env: TR_ARCH=docker-test - env: TR_ARCH=fedora-rawhide - env: TR_ARCH=fedora-rawhide-aarch64 + - env: TR_ARCH=s390x script: - sudo make CCACHE=1 -C scripts/travis $TR_ARCH after_success: From 7d1eeee729930fd85c2bc92ed7a87f2bd7bd90a2 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:41:02 +0300 Subject: [PATCH 1303/4375] zdtm: Add scm05 test Create socketpair and epoll. Add one end of the socketpair to epoll and then twice send it over another end. After restore check, that epoll can be received via socket, and that it contains event. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/scm05.c | 139 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 test/zdtm/static/scm05.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index f5e0230d3..2cf264719 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -170,6 +170,7 @@ TST_NOFILE := \ scm02 \ scm03 \ scm04 \ + scm05 \ aio00 \ aio01 \ fd \ diff --git a/test/zdtm/static/scm05.c b/test/zdtm/static/scm05.c new file mode 100644 index 000000000..c17bddda3 --- /dev/null +++ b/test/zdtm/static/scm05.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check that SCM_RIGHTS are preserved"; +const char *test_author = "Kirill Tkhai "; + +static int send_fd(int via, int fd) +{ + struct msghdr h = {}; + struct cmsghdr *ch; + struct iovec iov; + char buf[CMSG_SPACE(sizeof(int))]; + char c = '\0'; + int *fdp; + + memset(buf, 0, sizeof(buf)); + h.msg_control = buf; + h.msg_controllen = sizeof(buf); + ch = CMSG_FIRSTHDR(&h); + ch->cmsg_level = SOL_SOCKET; + ch->cmsg_type = SCM_RIGHTS; + ch->cmsg_len = CMSG_LEN(sizeof(int)); + fdp = (int *)CMSG_DATA(ch); + fdp[0] = fd; + + h.msg_iov = &iov; + h.msg_iovlen = 1; + iov.iov_base = &c; + iov.iov_len = sizeof(c); + + if (sendmsg(via, &h, 0) <= 0) + return -1; + + return 0; +} + +static int recv_fd(int via, int *fd) +{ + struct msghdr h = {}; + struct cmsghdr *ch; + struct iovec iov; + char buf[CMSG_SPACE(sizeof(int))]; + char c; + int *fdp; + + h.msg_control = buf; + h.msg_controllen = sizeof(buf); + h.msg_iov = &iov; + h.msg_iovlen = 1; + iov.iov_base = &c; + iov.iov_len = sizeof(c); + + if (recvmsg(via, &h, 0) <= 0) + return -1; + + if (h.msg_flags & MSG_CTRUNC) { + test_msg("CTR\n"); + return -2; + } + + /* No 2 SCM-s here, kernel merges them upon send */ + ch = CMSG_FIRSTHDR(&h); + if (h.msg_flags & MSG_TRUNC) + return -2; + if (ch == NULL) + return -3; + if (ch->cmsg_type != SCM_RIGHTS) + return -4; + + fdp = (int *)CMSG_DATA(ch); + *fd = fdp[0]; + return 0; +} + +int main(int argc, char **argv) +{ + struct epoll_event event = { + .events = EPOLLIN, + }; + int sk[2], ep, ret; + + test_init(argc, argv); + + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sk) < 0) { + pr_perror("Can't make unix pair"); + exit(1); + } + + ep = epoll_create(1); + if (ep < 0) { + perror("Can't create epoll"); + exit(1); + } + + event.data.fd = sk[1]; + if (epoll_ctl(ep, EPOLL_CTL_ADD, sk[1], &event) < 0) { + perror("Can't add fd"); + exit(1); + } + + if (send_fd(sk[0], ep) < 0) { + pr_perror("Can't send epoll"); + exit(1); + } + if (send_fd(sk[0], ep) < 0) { + pr_perror("Can't send epoll"); + exit(1); + } + + close(ep); + memset(&event, 0, sizeof(event)); + + test_daemon(); + test_waitsig(); + + if (recv_fd(sk[1], &ep) < 0) { + fail("Can't recv epoll back"); + ret = -1; + goto out; + } + + ret = epoll_wait(ep, &event, 1, 0); + if (ret != 1) { + fail("Can't get epoll event"); + ret = -1; + goto out; + } + + pass(); + ret = 0; +out: + return ret; +} From 8377abeb1f02dbba2e8fe05b25be01faa2f433ae Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:41:10 +0300 Subject: [PATCH 1304/4375] files: Allow epolls sent over unix socket Since epoll restore is split in two parts, epoll_create() does not depend on another files state. Since epoll is created, it can be sent to everywhere. So, there is no circular dependences, and we allow epolls sent over unix socket. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-queue.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/criu/sk-queue.c b/criu/sk-queue.c index f3ebd6c64..7f5aa1d58 100644 --- a/criu/sk-queue.c +++ b/criu/sk-queue.c @@ -102,11 +102,10 @@ static int dump_scm_rights(struct cmsghdr *ch, SkPacketEntry *pe) return -1; /* - * Unix sent over Unix or Epoll with some other sh*t - * sent over unix (maybe with this very unix polled) - * are tricky and not supported for now. (XXX -- todo) + * Unix sent over Unix are tricky and not supported + * for now. (XXX -- todo). */ - if (ftyp == FD_TYPES__UNIXSK || ftyp == FD_TYPES__EVENTPOLL) { + if (ftyp == FD_TYPES__UNIXSK) { pr_err("Can't dump send %d (unix/epoll) fd\n", ftyp); return -1; } From de27a7c656fbcd3720984313336ae563cae464e9 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:41:20 +0300 Subject: [PATCH 1305/4375] unix: Move post_open_unix_sk() to open_unixsk_standalone() and rename it Since this function is used by standalone sockets only, we move it to appropriate place. No functional changes. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 87f292965..77f32dc39 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1088,7 +1088,7 @@ err: return -1; } -static int post_open_unix_sk(struct file_desc *d, int fd) +static int post_open_standalone(struct file_desc *d, int fd) { struct unix_sk_info *ui; struct unix_sk_info *peer; @@ -1308,10 +1308,14 @@ static int open_unixsk_pair_slave(struct unix_sk_info *ui, int *new_fd) static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) { + struct fdinfo_list_entry *fle; int sk; pr_info("Opening standalone socket (id %#x ino %#x peer %#x)\n", ui->ue->id, ui->ue->ino, ui->ue->peer); + fle = file_master(&ui->d); + if (fle->stage == FLE_OPEN) + return post_open_standalone(&ui->d, fle->fe->fd); if (set_netns(ui->ue->ns_id)) return -1; @@ -1459,7 +1463,6 @@ out: static int open_unix_sk(struct file_desc *d, int *new_fd) { - struct fdinfo_list_entry *fle; struct unix_sk_info *ui; int ret; @@ -1471,10 +1474,6 @@ static int open_unix_sk(struct file_desc *d, int *new_fd) return 1; } - fle = file_master(d); - if (fle->stage >= FLE_OPEN) - return post_open_unix_sk(d, fle->fe->fd); - if (inherited_fd(d, new_fd)) { ui->ue->uflags |= USK_INHERIT; ret = *new_fd >= 0 ? 0 : -1; From de8318c34114a7551ad9d1a1c22b991159ed3e51 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:41:29 +0300 Subject: [PATCH 1306/4375] files: Add force_master argument to collect_desc_fle() This functional allows to make a fle a master on the time of collection. We will use it to add fake files when we need to do this after add_fake_fds_masters(). This will be used to add second end of socketpair as a fake fle (as the first end is placed in the right place, we will force add the second end there). See next patches. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 24 ++++++++++++++++++------ criu/include/files.h | 3 ++- criu/sk-unix.c | 2 +- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/criu/files.c b/criu/files.c index 9cb3f7937..09a2b8194 100644 --- a/criu/files.c +++ b/criu/files.c @@ -760,27 +760,39 @@ static struct fdinfo_list_entry *alloc_fle(int pid, FdinfoEntry *fe) return fle; } -static void collect_desc_fle(struct fdinfo_list_entry *new_le, struct file_desc *fdesc) +static void __collect_desc_fle(struct fdinfo_list_entry *new_le, struct file_desc *fdesc) { struct fdinfo_list_entry *le; - new_le->desc = fdesc; - list_for_each_entry(le, &fdesc->fd_info_head, desc_list) if (pid_rst_prio(new_le->pid, le->pid)) break; list_add_tail(&new_le->desc_list, &le->desc_list); } +static void collect_desc_fle(struct fdinfo_list_entry *new_le, + struct file_desc *fdesc, bool force_master) +{ + new_le->desc = fdesc; + + if (!force_master) + __collect_desc_fle(new_le, fdesc); + else { + /* Link as first entry */ + list_add(&new_le->desc_list, &fdesc->fd_info_head); + } +} + struct fdinfo_list_entry *collect_fd_to(int pid, FdinfoEntry *e, - struct rst_info *rst_info, struct file_desc *fdesc, bool fake) + struct rst_info *rst_info, struct file_desc *fdesc, + bool fake, bool force_master) { struct fdinfo_list_entry *new_le; new_le = alloc_fle(pid, e); if (new_le) { new_le->fake = (!!fake); - collect_desc_fle(new_le, fdesc); + collect_desc_fle(new_le, fdesc, force_master); collect_task_fd(new_le, rst_info); } @@ -800,7 +812,7 @@ int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info, bool fake) return -1; } - if (!collect_fd_to(pid, e, rst_info, fdesc, fake)) + if (!collect_fd_to(pid, e, rst_info, fdesc, fake, false)) return -1; return 0; diff --git a/criu/include/files.h b/criu/include/files.h index b3330cf82..fb18206d8 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -114,7 +114,8 @@ struct file_desc_ops { int collect_fd(int pid, FdinfoEntry *e, struct rst_info *rst_info, bool ghost); struct fdinfo_list_entry *collect_fd_to(int pid, FdinfoEntry *e, - struct rst_info *rst_info, struct file_desc *fdesc, bool fake); + struct rst_info *rst_info, struct file_desc *fdesc, + bool fake, bool force_master); unsigned int find_unused_fd(struct pstree_item *, int hint_fd); struct fdinfo_list_entry *find_used_fd(struct pstree_item *, int fd); diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 77f32dc39..7dca7b693 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -895,7 +895,7 @@ static struct fdinfo_list_entry *get_fle_for_scm(struct file_desc *tgt, * Make this fle fake, so that files collecting engine * closes them at the end. */ - return collect_fd_to(vpid(owner), e, rsti(owner), tgt, true); + return collect_fd_to(vpid(owner), e, rsti(owner), tgt, true, false); } int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ids) From 60f47e910775eb5624cc36271e812e48171d3261 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:41:39 +0300 Subject: [PATCH 1307/4375] unix: Generalize get_fle_for_scm() This adds a new argument and changes debug print (it will be used for any fle, not only for scm). Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 7dca7b693..c4e81ee5c 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -842,8 +842,8 @@ static struct unix_sk_info *find_queuer_for(int id) return NULL; } -static struct fdinfo_list_entry *get_fle_for_scm(struct file_desc *tgt, - struct pstree_item *owner) +static struct fdinfo_list_entry *get_fle_for_task(struct file_desc *tgt, + struct pstree_item *owner, bool force_master) { struct fdinfo_list_entry *fle; FdinfoEntry *e = NULL; @@ -865,7 +865,7 @@ static struct fdinfo_list_entry *get_fle_for_scm(struct file_desc *tgt, * we're another user of it. */ fd = find_unused_fd(owner, -1); - pr_info("`- will add SCM-only %d fd\n", fd); + pr_info("`- will add fake %d fd\n", fd); if (e != NULL) { e = dup_fdinfo(e, fd, 0); @@ -895,7 +895,7 @@ static struct fdinfo_list_entry *get_fle_for_scm(struct file_desc *tgt, * Make this fle fake, so that files collecting engine * closes them at the end. */ - return collect_fd_to(vpid(owner), e, rsti(owner), tgt, true, false); + return collect_fd_to(vpid(owner), e, rsti(owner), tgt, true, force_master); } int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ids) @@ -936,7 +936,7 @@ int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ids) if (!sfle) return -1; - sfle->fle = get_fle_for_scm(tgt, owner); + sfle->fle = get_fle_for_task(tgt, owner, false); if (!sfle->fle) { pr_err("Can't request new fle for scm\n"); return -1; From cc0c57d98881c15696b8dbb899f3ed451de19793 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:41:47 +0300 Subject: [PATCH 1308/4375] sk-unix: Remove unused code in interconnected_pair() Since new file engine was introduced, we don't care which particular pid should be master or slave. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index c4e81ee5c..c8e61c844 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1630,22 +1630,8 @@ static void set_peer(struct unix_sk_info *ui, struct unix_sk_info *peer) static void interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *peer) { - struct fdinfo_list_entry *fle, *fle_peer; - /* - * Select who will restore the pair. Check is identical to - * the one in pipes.c and makes sure tasks wait for each other - * in pids sorting order (ascending). - */ - fle = file_master(&ui->d); - fle_peer = file_master(&peer->d); - - if (fdinfo_rst_prio(fle, fle_peer)) { - ui->flags |= USK_PAIR_MASTER; - peer->flags |= USK_PAIR_SLAVE; - } else { - peer->flags |= USK_PAIR_MASTER; - ui->flags |= USK_PAIR_SLAVE; - } + ui->flags |= USK_PAIR_MASTER; + peer->flags |= USK_PAIR_SLAVE; } static int fixup_unix_peer(struct unix_sk_info *ui) From 0f6f224656d6eac998714833cef9828e801fd464 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:41:56 +0300 Subject: [PATCH 1309/4375] unix: Add fake interconnected sockets We're going to split interconnected pair restore on two stages. Since we need the second end to restore message queue in (future) post open, we add it to the process, who is owner of the first end. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index c8e61c844..cd53a8f74 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1249,12 +1249,18 @@ done: static int open_unixsk_pair_master(struct unix_sk_info *ui, int *new_fd) { - int sk[2]; + struct fdinfo_list_entry *fle, *fle_peer; struct unix_sk_info *peer = ui->peer; + int sk[2]; pr_info("Opening pair master (id %#x ino %#x peer %#x)\n", ui->ue->id, ui->ue->ino, ui->ue->peer); + fle = file_master(&ui->d); + fle_peer = file_master(&peer->d); + + BUG_ON(fle->task != fle_peer->task); /* See interconnected_pair() */ + if (set_netns(ui->ue->ns_id)) return -1; @@ -1628,10 +1634,32 @@ static void set_peer(struct unix_sk_info *ui, struct unix_sk_info *peer) peer->queuer = ui->ue->id; } -static void interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *peer) +/* This function is called from post prepare only */ +static int interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *peer) { + struct fdinfo_list_entry *fle, *fle_peer; + ui->flags |= USK_PAIR_MASTER; peer->flags |= USK_PAIR_SLAVE; + + fle = file_master(&ui->d); + fle_peer = file_master(&peer->d); + + /* + * Since queue restore is delayed, every socket of the pair + * should have another end to send the queue packets. + * To fit that, we make the both file_master's to be owned + * by the only task. + * This function is called from run_post_prepare() and + * after add_fake_fds_masters(), so we must not add masters, + * which fle->task has no permissions to restore. But + * it has permissions on ui, so it has permissions on peer. + */ + if (fle->task != fle_peer->task && + !get_fle_for_task(&peer->d, fle->task, true)) + return -1; + + return 0; } static int fixup_unix_peer(struct unix_sk_info *ui) @@ -1649,7 +1677,8 @@ static int fixup_unix_peer(struct unix_sk_info *ui) pr_info("Connected %#x -> %#x (%#x) flags %#x\n", ui->ue->ino, ui->ue->peer, peer->ue->ino, ui->flags); /* socketpair or interconnected sockets */ - interconnected_pair(ui, peer); + if (interconnected_pair(ui, peer)) + return -1; } return 0; From 6648656dec30856c6a905c452466421574c4edeb Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:42:05 +0300 Subject: [PATCH 1310/4375] files: Export setup_and_serve_out() Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 2 +- criu/include/files.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/files.c b/criu/files.c index 09a2b8194..f1299102c 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1069,7 +1069,7 @@ out: return ret; } -static int setup_and_serve_out(struct fdinfo_list_entry *fle, int new_fd) +int setup_and_serve_out(struct fdinfo_list_entry *fle, int new_fd) { struct file_desc *d = fle->desc; pid_t pid = fle->pid; diff --git a/criu/include/files.h b/criu/include/files.h index fb18206d8..d9597ad9a 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -152,6 +152,7 @@ extern struct fdinfo_list_entry *try_file_master(struct file_desc *d); extern struct fdinfo_list_entry *file_master(struct file_desc *d); extern struct file_desc *find_file_desc_raw(int type, u32 id); +extern int setup_and_serve_out(struct fdinfo_list_entry *fle, int new_fd); extern int recv_desc_from_peer(struct file_desc *d, int *fd); extern int send_desc_to_peer(int fd, struct file_desc *d); extern int restore_fown(int fd, FownEntry *fown); From 58ec2ddf731b2b2476f765268c70c34bbfdb13d2 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:42:13 +0300 Subject: [PATCH 1311/4375] unix: Rework peer transfer in open_unixsk_pair_master() After previous patch, master and slave ends of socketpair are owned by the only task. So, we may avoid using of send_desc_to_peer() of the second end, and just reopen it with right pid. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 52 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index cd53a8f74..d13fb6492 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1251,7 +1251,7 @@ static int open_unixsk_pair_master(struct unix_sk_info *ui, int *new_fd) { struct fdinfo_list_entry *fle, *fle_peer; struct unix_sk_info *peer = ui->peer; - int sk[2]; + int sk[2], tmp; pr_info("Opening pair master (id %#x ino %#x peer %#x)\n", ui->ue->id, ui->ue->ino, ui->ue->peer); @@ -1269,6 +1269,26 @@ static int open_unixsk_pair_master(struct unix_sk_info *ui, int *new_fd) return -1; } + if (sk[0] == fle_peer->fe->fd) { + /* + * Below setup_and_serve_out() will reuse this fd, + * so this dups it in something else. + */ + tmp = dup(sk[0]); + if (tmp < 0) { + pr_perror("Can't dup()"); + return -1; + } + close(sk[0]); + sk[0] = tmp; + } + + if (setup_and_serve_out(fle_peer, sk[1])) { + pr_err("Can't send pair slave\n"); + return -1; + } + sk[1] = fle_peer->fe->fd; + if (restore_sk_queue(sk[0], peer->ue->id)) return -1; if (restore_sk_queue(sk[1], ui->ue->id)) @@ -1280,12 +1300,11 @@ static int open_unixsk_pair_master(struct unix_sk_info *ui, int *new_fd) if (restore_sk_common(sk[0], ui)) return -1; - if (send_desc_to_peer(sk[1], &peer->d)) { - pr_err("Can't send pair slave\n"); + if (bind_unix_sk(sk[1], peer)) return -1; - } - close(sk[1]); + if (restore_sk_common(sk[1], peer)) + return -1; *new_fd = sk[0]; return 0; @@ -1293,23 +1312,14 @@ static int open_unixsk_pair_master(struct unix_sk_info *ui, int *new_fd) static int open_unixsk_pair_slave(struct unix_sk_info *ui, int *new_fd) { - int sk, ret; + struct fdinfo_list_entry *fle_peer; - ret = recv_desc_from_peer(&ui->d, &sk); - if (ret != 0) { - if (ret != 1) - pr_err("Can't recv pair slave\n"); - return ret; - } - - if (bind_unix_sk(sk, ui)) - return -1; - - if (restore_sk_common(sk, ui)) - return -1; - - *new_fd = sk; - return 0; + fle_peer = file_master(&ui->peer->d); + /* + * All the work is made in master. Slave just says it's restored + * after it sees the master is restored. + */ + return (fle_peer->stage != FLE_RESTORED); } static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) From f44b542264333393d2049905cbb1b50add833d78 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:42:22 +0300 Subject: [PATCH 1312/4375] unix: Move queue restore of interconnected pair to post open Actually, there is no functional changes. We just postpone restore of the queues. This will be used in the further patches to restore unix sockets sent over unix sockets. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index d13fb6492..5e985b304 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1247,6 +1247,30 @@ done: return ret; } +static int post_open_interconnected_master(struct unix_sk_info *ui) +{ + struct fdinfo_list_entry *fle, *fle_peer; + struct unix_sk_info *peer = ui->peer; + + fle = file_master(&ui->d); + fle_peer = file_master(&peer->d); + BUG_ON(fle->task != fle_peer->task); /* See interconnected_pair() */ + + if (restore_sk_queue(fle->fe->fd, peer->ue->id)) + return -1; + + if (restore_sk_queue(fle_peer->fe->fd, ui->ue->id)) + return -1; + + if (restore_sk_common(fle->fe->fd, ui)) + return -1; + + if (restore_sk_common(fle_peer->fe->fd, peer)) + return -1; + + return 0; +} + static int open_unixsk_pair_master(struct unix_sk_info *ui, int *new_fd) { struct fdinfo_list_entry *fle, *fle_peer; @@ -1257,6 +1281,9 @@ static int open_unixsk_pair_master(struct unix_sk_info *ui, int *new_fd) ui->ue->id, ui->ue->ino, ui->ue->peer); fle = file_master(&ui->d); + if (fle->stage == FLE_OPEN) + return post_open_interconnected_master(ui); + fle_peer = file_master(&peer->d); BUG_ON(fle->task != fle_peer->task); /* See interconnected_pair() */ @@ -1289,25 +1316,14 @@ static int open_unixsk_pair_master(struct unix_sk_info *ui, int *new_fd) } sk[1] = fle_peer->fe->fd; - if (restore_sk_queue(sk[0], peer->ue->id)) - return -1; - if (restore_sk_queue(sk[1], ui->ue->id)) - return -1; - if (bind_unix_sk(sk[0], ui)) return -1; - if (restore_sk_common(sk[0], ui)) - return -1; - if (bind_unix_sk(sk[1], peer)) return -1; - if (restore_sk_common(sk[1], peer)) - return -1; - *new_fd = sk[0]; - return 0; + return 1; } static int open_unixsk_pair_slave(struct unix_sk_info *ui, int *new_fd) From b0493135c5670fae40b5c5488c1bf4b1b8aefba1 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:42:31 +0300 Subject: [PATCH 1313/4375] unix: Make unix_sk_info::queuer pointer Use pointer to the queuer instead of its id. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 5e985b304..23b7837d0 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -805,7 +805,7 @@ struct unix_sk_info { * once although it may be open by more than one tid. This is the peer * that should do the queueing. */ - u32 queuer; + struct unix_sk_info *queuer; u8 bound:1; u8 listen:1; }; @@ -835,7 +835,7 @@ static struct unix_sk_info *find_queuer_for(int id) struct unix_sk_info *ui; list_for_each_entry(ui, &unix_sockets, list) { - if (ui->queuer == id) + if (ui->queuer->ue->id == id) return ui; } @@ -1126,7 +1126,7 @@ static int post_open_standalone(struct file_desc *d, int fd) revert_unix_sk_cwd(&cwd_fd, &root_fd); - if (peer->queuer == ui->ue->id && restore_sk_queue(fd, peer->ue->id)) + if (peer->queuer == ui && restore_sk_queue(fd, peer->ue->id)) return -1; return restore_sk_common(fd, ui); @@ -1598,7 +1598,7 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) } else ui->name = NULL; - ui->queuer = 0; + ui->queuer = NULL; ui->peer = NULL; ui->bound = 0; ui->listen = 0; @@ -1657,7 +1657,7 @@ static void set_peer(struct unix_sk_info *ui, struct unix_sk_info *peer) ui->peer = peer; list_add(&ui->node, &peer->connected); if (!peer->queuer) - peer->queuer = ui->ue->id; + peer->queuer = ui; } /* This function is called from post prepare only */ From 22371247328f543f119d9d4f779564bef592282c Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:42:39 +0300 Subject: [PATCH 1314/4375] unix: Postpone restore_sk_common() of standalone sockets restore_sk_common() may shutdown a socket, and queuer won't be able to connect to it. So, this action must be postponed. We have this problem since long ago, but we are lucky we haven't bumped in it. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 48 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 23b7837d0..0b506ae49 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -806,8 +806,14 @@ struct unix_sk_info { * that should do the queueing. */ struct unix_sk_info *queuer; + /* + * These bits are set by task-owner of this unix_sk_info. + * Another tasks can only read them. + */ u8 bound:1; u8 listen:1; + u8 is_connected:1; + u8 peer_queue_restored:1; /* Set in 1 after we restore peer's queue */ }; struct scm_fle { @@ -985,6 +991,20 @@ static bool peer_is_not_prepared(struct unix_sk_info *peer) return (!peer->listen); } +static int restore_unix_queue(int fd, struct unix_sk_info *peer) +{ + struct pstree_item *task; + + if (restore_sk_queue(fd, peer->ue->id)) + return -1; + if (peer->queuer) + peer->queuer->peer_queue_restored = true; + + task = file_master(&peer->d)->task; + set_fds_event(vpid(task)); + return 0; +} + static int shutdown_unix_sk(int sk, struct unix_sk_info *ui) { int how; @@ -1100,7 +1120,8 @@ static int post_open_standalone(struct file_desc *d, int fd) (ui->ue->uflags & (USK_CALLBACK | USK_INHERIT))); peer = ui->peer; - BUG_ON(peer == NULL); + if (!peer || ui->is_connected) + goto restore_sk_common; /* Skip external sockets */ if (!list_empty(&peer->d.fd_info_head)) @@ -1123,12 +1144,17 @@ static int post_open_standalone(struct file_desc *d, int fd) revert_unix_sk_cwd(&cwd_fd, &root_fd); return -1; } + ui->is_connected = true; revert_unix_sk_cwd(&cwd_fd, &root_fd); - if (peer->queuer == ui && restore_sk_queue(fd, peer->ue->id)) + if (peer->queuer == ui && + !(peer->ue->uflags & USK_EXTERN) && + restore_unix_queue(fd, peer)) return -1; - +restore_sk_common: + if (ui->queuer && !ui->queuer->peer_queue_restored) + return 1; return restore_sk_common(fd, ui); } @@ -1256,10 +1282,10 @@ static int post_open_interconnected_master(struct unix_sk_info *ui) fle_peer = file_master(&peer->d); BUG_ON(fle->task != fle_peer->task); /* See interconnected_pair() */ - if (restore_sk_queue(fle->fe->fd, peer->ue->id)) + if (restore_unix_queue(fle->fe->fd, peer)) return -1; - if (restore_sk_queue(fle_peer->fe->fd, ui->ue->id)) + if (restore_unix_queue(fle_peer->fe->fd, ui)) return -1; if (restore_sk_common(fle->fe->fd, ui)) @@ -1395,7 +1421,7 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) * Restore queue at the one end, * before closing the second one. */ - if (restore_sk_queue(sks[1], ui->ue->id)) { + if (restore_unix_queue(sks[1], ui)) { pr_perror("Can't restore socket queue"); return -1; } @@ -1431,7 +1457,7 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) * This must be after the connect() hack, because * connect() flushes receive queue. */ - if (restore_sk_queue(sks[1], ui->ue->id)) { + if (restore_unix_queue(sks[1], ui)) { pr_perror("Can't restore socket queue"); return -1; } @@ -1475,11 +1501,13 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) wake_connected_sockets(ui); } - if (ui->peer) { + if (ui->peer || ui->queuer) { /* - * We need to connect() to the peer, but the + * 1)We need to connect() to the peer, but the * guy might have not bind()-ed himself, so * let's postpone this. + * 2)Queuer won't be able to connect, if we do + * shutdown, so postpone it. */ *new_fd = sk; return 1; @@ -1602,6 +1630,8 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) ui->peer = NULL; ui->bound = 0; ui->listen = 0; + ui->is_connected = 0; + ui->peer_queue_restored = 0; INIT_LIST_HEAD(&ui->connected); INIT_LIST_HEAD(&ui->node); INIT_LIST_HEAD(&ui->scm_fles); From 7a5919cc3e1ee7488f737cc8b1e67068b89cf60c Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:42:48 +0300 Subject: [PATCH 1315/4375] files: Implement find_unused_file_desc_id() This function will be used to allocate id for fake files (don't confuse with fake fds, e.g. fles). Suggested-by: Pavel Emelyanov Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/files.c | 11 +++++++++++ criu/include/files.h | 1 + 2 files changed, 12 insertions(+) diff --git a/criu/files.c b/criu/files.c index f1299102c..a1b228889 100644 --- a/criu/files.c +++ b/criu/files.c @@ -57,6 +57,8 @@ static struct hlist_head file_desc_hash[FDESC_HASH_SIZE]; /* file_desc's, which fle is not owned by a process, that is able to open them */ static LIST_HEAD(fake_master_head); +static u32 max_file_desc_id = 0; + static void init_fdesc_hash(void) { int i; @@ -79,6 +81,10 @@ int file_desc_add(struct file_desc *d, u32 id, struct file_desc_ops *ops) { file_desc_init(d, id, ops); hlist_add_head(&d->hash, &file_desc_hash[id % FDESC_HASH_SIZE]); + + if (id > max_file_desc_id) + max_file_desc_id = id; + return 0; /* this is to make tail-calls in collect_one_foo look nice */ } @@ -108,6 +114,11 @@ static inline struct file_desc *find_file_desc(FdinfoEntry *fe) return find_file_desc_raw(fe->type, fe->id); } +u32 find_unused_file_desc_id(void) +{ + return max_file_desc_id + 1; +} + struct fdinfo_list_entry *find_used_fd(struct pstree_item *task, int fd) { struct list_head *head; diff --git a/criu/include/files.h b/criu/include/files.h index d9597ad9a..e69022d41 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -117,6 +117,7 @@ struct fdinfo_list_entry *collect_fd_to(int pid, FdinfoEntry *e, struct rst_info *rst_info, struct file_desc *fdesc, bool fake, bool force_master); +u32 find_unused_file_desc_id(void); unsigned int find_unused_fd(struct pstree_item *, int hint_fd); struct fdinfo_list_entry *find_used_fd(struct pstree_item *, int fd); From aae41a636782af0b5ab72a449d6762cee0f06378 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:42:57 +0300 Subject: [PATCH 1316/4375] unix: Split collect_one_unixsk() Extract the functionality, which makes socket memory initialization. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 0b506ae49..6c89b5fc3 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1607,24 +1607,19 @@ static int post_prepare_unix_sk(struct pprep_head *ph) return 0; } -static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) +static int init_unix_sk_info(struct unix_sk_info *ui, UnixSkEntry *ue) { - struct unix_sk_info *ui = o; - char *uname, *prefix = ""; - int ulen; - - ui->ue = pb_msg(base, UnixSkEntry); - ui->name_dir = (void *)ui->ue->name_dir; - - if (ui->ue->name.len) { - if (ui->ue->name.len > UNIX_PATH_MAX) { - pr_err("Bad unix name len %d\n", (int)ui->ue->name.len); + ui->ue = ue; + if (ue->name.len) { + if (ue->name.len > UNIX_PATH_MAX) { + pr_err("Bad unix name len %d\n", (int)ue->name.len); return -1; } - ui->name = (void *)ui->ue->name.data; + ui->name = (void *)ue->name.data; } else ui->name = NULL; + ui->name_dir = (void *)ue->name_dir; ui->queuer = NULL; ui->peer = NULL; @@ -1637,6 +1632,18 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) INIT_LIST_HEAD(&ui->scm_fles); ui->flags = 0; + return 0; +} + +static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) +{ + struct unix_sk_info *ui = o; + char *uname, *prefix = ""; + int ulen; + + if (init_unix_sk_info(ui, pb_msg(base, UnixSkEntry))) + return -1; + uname = ui->name; ulen = ui->ue->name.len; if (ulen > 0 && uname[0] == 0) { From d8ae190ef62e569460d28ce4876e71f1decd864b Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:43:06 +0300 Subject: [PATCH 1317/4375] unix: Add fake queuer for standalone stream sockets in established state This makes the second end of socketpair to live till post_open. We need it alive if we want to restore message queue later. Otherwise, we do not have a queuer, which fd is used to actually write messages. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 4 ++ criu/include/sockets.h | 1 + criu/sk-unix.c | 115 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 111 insertions(+), 9 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index e08e6ed6f..3b2ffdd0d 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -378,6 +378,10 @@ static int root_prepare_shared(void) if (ret) goto err; + ret = add_fake_unix_queuers(); + if (ret) + goto err; + show_saved_files(); err: return ret; diff --git a/criu/include/sockets.h b/criu/include/sockets.h index 381244077..304134cd3 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -37,6 +37,7 @@ struct ns_id; extern int collect_sockets(struct ns_id *); extern struct collect_image_info inet_sk_cinfo; extern struct collect_image_info unix_sk_cinfo; +extern int add_fake_unix_queuers(void); extern int fix_external_unix_sockets(void); extern int prepare_scms(void); extern int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ids); diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 6c89b5fc3..eba58adae 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -54,6 +54,8 @@ #define USK_CALLBACK (1 << 2) #define USK_INHERIT (1 << 3) +#define FAKE_INO 0 + typedef struct { char *dir; unsigned int udiag_vfs_dev; @@ -1123,6 +1125,11 @@ static int post_open_standalone(struct file_desc *d, int fd) if (!peer || ui->is_connected) goto restore_sk_common; + if (ui->ue->ino == FAKE_INO) { + BUG_ON(ui->queuer); + goto restore_queue; + } + /* Skip external sockets */ if (!list_empty(&peer->d.fd_info_head)) if (peer_is_not_prepared(peer)) @@ -1148,6 +1155,7 @@ static int post_open_standalone(struct file_desc *d, int fd) revert_unix_sk_cwd(&cwd_fd, &root_fd); +restore_queue: if (peer->queuer == ui && !(peer->ue->uflags & USK_EXTERN) && restore_unix_queue(fd, peer)) @@ -1364,8 +1372,39 @@ static int open_unixsk_pair_slave(struct unix_sk_info *ui, int *new_fd) return (fle_peer->stage != FLE_RESTORED); } +/* + * When sks[0]'s fle requires to create socketpair, and sks[1] is also + * somebody's fle, this makes file engine to make note the second_end + * is also open. + */ +static int setup_second_end(int *sks, struct fdinfo_list_entry *second_end) +{ + int ret; + + if (sks[0] == second_end->fe->fd) { + /* + * Below setup_and_serve_out() will reuse this fd, + * so this dups it in something else. + */ + ret = dup(sks[0]); + if (ret < 0) { + pr_perror("Can't dup()"); + return -1; + } + close(sks[0]); + sks[0] = ret; + } + + if (setup_and_serve_out(second_end, sks[1])) { + pr_err("Can't send pair slave\n"); + return -1; + } + return 0; +} + static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) { + struct unix_sk_info *queuer = ui->queuer; struct fdinfo_list_entry *fle; int sk; @@ -1375,6 +1414,10 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) if (fle->stage == FLE_OPEN) return post_open_standalone(&ui->d, fle->fe->fd); + /* Fake socket will be restored by its peer */ + if (!(ui->ue->uflags & USK_EXTERN) && ui->ue->ino == FAKE_INO) + return 1; + if (set_netns(ui->ue->ns_id)) return -1; @@ -1396,7 +1439,7 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) close(sks[1]); sk = sks[0]; - } else if ((ui->ue->state == TCP_ESTABLISHED) && !ui->ue->peer) { + } else if (ui->ue->state == TCP_ESTABLISHED && queuer && queuer->ue->ino == FAKE_INO) { int ret, sks[2]; if (ui->ue->type != SOCK_STREAM) { @@ -1417,16 +1460,9 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) return -1; } - /* - * Restore queue at the one end, - * before closing the second one. - */ - if (restore_unix_queue(sks[1], ui)) { - pr_perror("Can't restore socket queue"); + if (setup_second_end(sks, file_master(&queuer->d))) return -1; - } - close(sks[1]); sk = sks[0]; } else if (ui->ue->type == SOCK_DGRAM && !ui->queuer) { struct sockaddr_un addr; @@ -1697,6 +1733,67 @@ static void set_peer(struct unix_sk_info *ui, struct unix_sk_info *peer) peer->queuer = ui; } +static int add_fake_queuer(struct unix_sk_info *ui) +{ + struct unix_sk_info *peer; + struct pstree_item *task; + UnixSkEntry *peer_ue; + SkOptsEntry *skopts; + FownEntry *fown; + + if (ui->ue->ino == FAKE_INO) + return 0; + + peer = xzalloc(sizeof(struct unix_sk_info) + + sizeof(UnixSkEntry) + + sizeof(SkOptsEntry) + + sizeof(FownEntry)); + if (peer == NULL) + return -1; + + peer_ue = (void *) peer + sizeof(struct unix_sk_info); + skopts = (void *) peer_ue + sizeof(UnixSkEntry); + fown = (void *) skopts + sizeof(SkOptsEntry); + memcpy(skopts, ui->ue->opts, sizeof(SkOptsEntry)); + memcpy(fown, ui->ue->fown, sizeof(FownEntry)); + memcpy(peer_ue, ui->ue, sizeof(UnixSkEntry)); + peer_ue->opts = skopts; + peer_ue->file_perms = NULL; + peer_ue->fown = fown; + peer_ue->name.len = 0; + peer_ue->name_dir = NULL; + + if (init_unix_sk_info(peer, peer_ue)) + return -1; + + peer_ue->id = find_unused_file_desc_id(); + set_peer(peer, ui); + + /* Note, that this fake fdesc has no ino */ + peer->ue->ino = FAKE_INO; + file_desc_add(&peer->d, peer_ue->id, &unix_desc_ops); + list_del_init(&peer->d.fake_master_list); + list_add(&peer->list, &unix_sockets); + task = file_master(&ui->d)->task; + + return (get_fle_for_task(&peer->d, task, true) == NULL); +} + +int add_fake_unix_queuers(void) +{ + struct unix_sk_info *ui; + + list_for_each_entry(ui, &unix_sockets, list) { + if ((ui->ue->uflags & USK_EXTERN) || ui->queuer) + continue; + if (!(ui->ue->state == TCP_ESTABLISHED && !ui->peer)) + continue; + if (add_fake_queuer(ui)) + return -1; + } + return 0; +} + /* This function is called from post prepare only */ static int interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *peer) { From 254958ce723657e352463090a40659b4e5b2a642 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:43:14 +0300 Subject: [PATCH 1318/4375] unix: Add fake queuer for standalone dgram sockets Similar to previous patch, this makes the second end of dgram socketpair to be open till post open. This allows to delay restore of message queue. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index eba58adae..b2e7e8b2a 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1464,7 +1464,7 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) return -1; sk = sks[0]; - } else if (ui->ue->type == SOCK_DGRAM && !ui->queuer) { + } else if (ui->ue->type == SOCK_DGRAM && queuer && queuer->ue->ino == FAKE_INO) { struct sockaddr_un addr; int sks[2]; @@ -1483,21 +1483,18 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) * to sks[0] (see unix_dgram_connect()->unix_may_send()). * The below is hack: we use that connect with AF_UNSPEC * clears socket's peer. + * Note, that connect hack flushes receive queue, + * so restore_unix_queue() must be after it. */ if (connect(sk, (struct sockaddr *)&addr, sizeof(addr.sun_family))) { pr_perror("Can't clear socket's peer"); return -1; } - /* - * This must be after the connect() hack, because - * connect() flushes receive queue. - */ - if (restore_unix_queue(sks[1], ui)) { - pr_perror("Can't restore socket queue"); + if (setup_second_end(sks, file_master(&queuer->d))) return -1; - } - close(sks[1]); + + sk = sks[0]; } else { if (ui->ue->uflags & USK_CALLBACK) { sk = run_plugins(RESTORE_UNIX_SK, ui->ue->ino); @@ -1786,7 +1783,8 @@ int add_fake_unix_queuers(void) list_for_each_entry(ui, &unix_sockets, list) { if ((ui->ue->uflags & USK_EXTERN) || ui->queuer) continue; - if (!(ui->ue->state == TCP_ESTABLISHED && !ui->peer)) + if (!(ui->ue->state == TCP_ESTABLISHED && !ui->peer) && + ui->ue->type != SOCK_DGRAM) continue; if (add_fake_queuer(ui)) return -1; From fdb7bde5c7b38ea674e33db52b8a3a4aedb792da Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:43:23 +0300 Subject: [PATCH 1319/4375] unix: Move dump_sk_queue() before peer resolution When we allow unix sockets sent over unix sockets, dump_sk_queue() may dump and resolve some peers. So, we need run it firstly and avoid linking our peer_node to peer's peer_list. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index b2e7e8b2a..4b3a47036 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -347,6 +347,18 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p) sk_encode_shutdown(ue, sk->shutdown); + /* + * If a stream listening socket has non-zero rqueue, this + * means there are in-flight connections waiting to get + * accept()-ed. We handle them separately with the "icons" + * (i stands for in-flight, cons -- for connections) things. + */ + if (sk->rqlen != 0 && !(sk->type == SOCK_STREAM && + sk->state == TCP_LISTEN)) { + if (dump_sk_queue(lfd, id)) + goto err; + } + if (ue->peer) { peer = (struct unix_sk_desc *)lookup_socket(ue->peer, PF_UNIX, 0); if (IS_ERR_OR_NULL(peer)) { @@ -444,17 +456,6 @@ dump: if (dump_socket_opts(lfd, skopts)) goto err; - /* - * If a stream listening socket has non-zero rqueue, this - * means there are in-flight connections waiting to get - * accept()-ed. We handle them separately with the "icons" - * (i stands for in-flight, cons -- for connections) things. - */ - if (sk->rqlen != 0 && !(sk->type == SOCK_STREAM && - sk->state == TCP_LISTEN)) - if (dump_sk_queue(lfd, id)) - goto err; - pr_info("Dumping unix socket at %d\n", p->fd); show_one_unix("Dumping", sk); @@ -478,6 +479,7 @@ dump: if (write_unix_entry(psk)) return -1; + psk->sd.already_dumped = 1; } return 0; From 75be843cddada59b5e72fcc1035102fe6cf8fdf9 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 30 Jan 2018 18:43:32 +0300 Subject: [PATCH 1320/4375] files: Allow to send unix sockets over unix sockets Everything is ready. Message queue restores are in the second stage of open for all types of unix sockets. We just need to make scm wait before restore_unix_queue() and allow to dump such scm context. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/sk-queue.c | 9 --------- criu/sk-unix.c | 12 ++++++------ 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/criu/sk-queue.c b/criu/sk-queue.c index 7f5aa1d58..b5fb6b76c 100644 --- a/criu/sk-queue.c +++ b/criu/sk-queue.c @@ -100,15 +100,6 @@ static int dump_scm_rights(struct cmsghdr *ch, SkPacketEntry *pe) if (dump_my_file(fds[i], &scme->rights[i], &ftyp)) return -1; - - /* - * Unix sent over Unix are tricky and not supported - * for now. (XXX -- todo). - */ - if (ftyp == FD_TYPES__UNIXSK) { - pr_err("Can't dump send %d (unix/epoll) fd\n", ftyp); - return -1; - } } i = pe->n_scm++; diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 4b3a47036..6ce42ff92 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1123,6 +1123,9 @@ static int post_open_standalone(struct file_desc *d, int fd) BUG_ON((ui->flags & (USK_PAIR_MASTER | USK_PAIR_SLAVE)) || (ui->ue->uflags & (USK_CALLBACK | USK_INHERIT))); + if (chk_restored_scms(ui)) + return 1; + peer = ui->peer; if (!peer || ui->is_connected) goto restore_sk_common; @@ -1292,6 +1295,9 @@ static int post_open_interconnected_master(struct unix_sk_info *ui) fle_peer = file_master(&peer->d); BUG_ON(fle->task != fle_peer->task); /* See interconnected_pair() */ + if (chk_restored_scms(ui) || chk_restored_scms(peer)) + return 0; + if (restore_unix_queue(fle->fe->fd, peer)) return -1; @@ -1563,12 +1569,6 @@ static int open_unix_sk(struct file_desc *d, int *new_fd) ui = container_of(d, struct unix_sk_info, d); - /* FIXME -- only queue restore may be postponed */ - if (chk_restored_scms(ui)) { - pr_info("scm: Wait for tgt to restore\n"); - return 1; - } - if (inherited_fd(d, new_fd)) { ui->ue->uflags |= USK_INHERIT; ret = *new_fd >= 0 ? 0 : -1; From c670abb8d80527597148af38f240ed698704c36e Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 1 Feb 2018 20:10:17 +0300 Subject: [PATCH 1321/4375] zdtm: Add scm06 test This test makes looped unix sockets queues and tries to iterate over them after the restore. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/scm06.c | 147 ++++++++++++++++++++++++++++++++++++ test/zdtm/static/scm06.desc | 1 + 3 files changed, 149 insertions(+) create mode 100644 test/zdtm/static/scm06.c create mode 100644 test/zdtm/static/scm06.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 2cf264719..b6bf88db2 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -171,6 +171,7 @@ TST_NOFILE := \ scm03 \ scm04 \ scm05 \ + scm06 \ aio00 \ aio01 \ fd \ diff --git a/test/zdtm/static/scm06.c b/test/zdtm/static/scm06.c new file mode 100644 index 000000000..6c9a78b4d --- /dev/null +++ b/test/zdtm/static/scm06.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check a send of looped unix sockets"; +const char *test_author = "Kirill Tkhai "; + +static int send_fd(int via, int fd) +{ + struct msghdr h = {}; + struct cmsghdr *ch; + struct iovec iov; + char buf[CMSG_SPACE(sizeof(int))]; + char c = '\0'; + int *fdp; + + memset(buf, 0, sizeof(buf)); + h.msg_control = buf; + h.msg_controllen = sizeof(buf); + ch = CMSG_FIRSTHDR(&h); + ch->cmsg_level = SOL_SOCKET; + ch->cmsg_type = SCM_RIGHTS; + ch->cmsg_len = CMSG_LEN(sizeof(int)); + fdp = (int *)CMSG_DATA(ch); + fdp[0] = fd; + + h.msg_iov = &iov; + h.msg_iovlen = 1; + iov.iov_base = &c; + iov.iov_len = sizeof(c); + + if (sendmsg(via, &h, 0) <= 0) + return -1; + + return 0; +} + +static int recv_fd(int via, int *fd) +{ + struct msghdr h = {}; + struct cmsghdr *ch; + struct iovec iov; + char buf[CMSG_SPACE(sizeof(int))]; + char c; + int *fdp; + + h.msg_control = buf; + h.msg_controllen = sizeof(buf); + h.msg_iov = &iov; + h.msg_iovlen = 1; + iov.iov_base = &c; + iov.iov_len = sizeof(c); + + if (recvmsg(via, &h, 0) <= 0) + return -1; + + if (h.msg_flags & MSG_CTRUNC) { + test_msg("CTR\n"); + return -2; + } + + /* No 2 SCM-s here, kernel merges them upon send */ + ch = CMSG_FIRSTHDR(&h); + if (h.msg_flags & MSG_TRUNC) + return -2; + if (ch == NULL) + return -3; + if (ch->cmsg_type != SCM_RIGHTS) + return -4; + + fdp = (int *)CMSG_DATA(ch); + *fd = fdp[0]; + return 0; +} + +int main(int argc, char **argv) +{ + int ska[2], skc, i, j, ret; + struct sockaddr_un addr; + socklen_t len; + + test_init(argc, argv); + + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, ska) < 0) { + fail("Can't make unix pair"); + exit(1); + } + + addr.sun_family = AF_UNIX; + for (i = 0; i < 2; i++) { + addr.sun_path[0] = '\0'; + addr.sun_path[1] = i; + if (bind(ska[i], (struct sockaddr *)&addr, + sizeof(addr.sun_family) + 2)) { + fail("Can't bind"); + exit(1); + } + } + + /* Make the vinaigrette */ + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + if (send_fd(ska[i], ska[j]) < 0) { + fail("Can't send sk"); + exit(1); + } + } + } + + test_daemon(); + test_waitsig(); + + ret = -1; + skc = ska[0]; + for (i = 0; i < 3; i++) { + if (recv_fd(skc, &skc) < 0) { + fail("Can't recv"); + goto out; + } + + len = sizeof(addr.sun_family) + 2; + + if (getsockname(skc, (struct sockaddr *)&addr, &len)) { + fail("Can't getsockname()"); + goto out; + } + + if (addr.sun_path[1] != (i % 2)) { + fail("Wrong socket or path"); + goto out; + } + } + + pass(); + ret = 0; +out: + return ret; +} diff --git a/test/zdtm/static/scm06.desc b/test/zdtm/static/scm06.desc new file mode 100644 index 000000000..2eac7e654 --- /dev/null +++ b/test/zdtm/static/scm06.desc @@ -0,0 +1 @@ +{'flags': 'suid'} From 3b3384352dd355407edd97a9d529b9bb27db87a7 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 7 Feb 2018 02:40:09 +0000 Subject: [PATCH 1322/4375] Fix typos Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/autofs.c | 6 +++--- criu/bfd.c | 2 +- criu/cgroup-props.c | 2 +- criu/cgroup.c | 2 +- criu/clone-noasan.c | 2 +- criu/cr-check.c | 2 +- criu/cr-dump.c | 8 ++++---- criu/cr-restore.c | 12 +++++++----- criu/cr-service.c | 4 ++-- criu/fault-injection.c | 8 ++++---- criu/fdstore.c | 2 +- criu/files-reg.c | 14 +++++++------- criu/files.c | 4 ++-- criu/include/cr_options.h | 4 ++-- criu/irmap.c | 2 +- criu/kerndat.c | 2 +- criu/log.c | 4 ++-- criu/mem.c | 12 ++++++------ criu/mount.c | 26 +++++++++++++------------- criu/namespaces.c | 2 +- criu/netfilter.c | 2 +- criu/page-pipe.c | 2 +- criu/page-xfer.c | 4 ++-- criu/pagemap.c | 2 +- criu/rst-malloc.c | 2 +- criu/seize.c | 4 ++-- criu/shmem.c | 8 ++++---- criu/sk-tcp.c | 6 +++--- criu/sk-unix.c | 4 ++-- criu/sysfs_parse.c | 2 +- criu/tty.c | 2 +- criu/tun.c | 2 +- criu/uffd.c | 4 ++-- criu/vdso-compat.c | 2 +- criu/vdso.c | 4 ++-- lib/py/criu.py | 4 ++-- 36 files changed, 88 insertions(+), 86 deletions(-) diff --git a/criu/autofs.c b/criu/autofs.c index 8cf5e8ec0..576edef68 100644 --- a/criu/autofs.c +++ b/criu/autofs.c @@ -345,7 +345,7 @@ free_str: /* * To access the mount point we have to set proper mount namespace. - * But, unfortunatelly, we have to set proper pid namespace as well, + * But, unfortunately, we have to set proper pid namespace as well, * because otherwise autofs driver won't find the autofs master. */ static int access_autofs_mount(struct mount_info *pm) @@ -642,7 +642,7 @@ static int autofs_mnt_set_pipefd(const autofs_info_t *i, int mnt_fd) { struct autofs_dev_ioctl param; - /* Restore pipe and pgrp only for non-cataonic mounts */ + /* Restore pipe and pgrp only for non-catatonic mounts */ if (i->entry->fd == AUTOFS_CATATONIC_FD) return 0; @@ -828,7 +828,7 @@ static autofs_info_t *autofs_create_info(const struct mount_info *mi, memcpy(i->entry, info->entry, sizeof(*info->entry)); i->mnt_dev = info->mnt_dev; - /* We need mountpoint to be able to opne mount in autofs_post_open() + /* We need mountpoint to be able to open mount in autofs_post_open() * callback. And this have to be internal path, because process cwd * will be changed already. That's why ns_mountpoint is used. */ strcpy(i->mnt_path, mi->ns_mountpoint); diff --git a/criu/bfd.c b/criu/bfd.c index 500737a8e..76ae56a31 100644 --- a/criu/bfd.c +++ b/criu/bfd.c @@ -220,7 +220,7 @@ again: /* * small optimization -- we've scanned b->sz - * symols already, no need to re-scan them after + * symbols already, no need to re-scan them after * the buffer refill. */ ss = b->sz; diff --git a/criu/cgroup-props.c b/criu/cgroup-props.c index f7032bd7e..ecd959352 100644 --- a/criu/cgroup-props.c +++ b/criu/cgroup-props.c @@ -264,7 +264,7 @@ static int cgp_parse_stream(char *stream, size_t len) } if (!eat_word(&stream, &len, "\"strategy\":", 11, true)) { - pr_err("Expected \'stategy:\' keyword in controller's %s stream\n", + pr_err("Expected \'strategy:\' keyword in controller's %s stream\n", cgp_entry->cgp.name); goto err_parse; } diff --git a/criu/cgroup.c b/criu/cgroup.c index ecf24f612..b3478b8ac 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -396,7 +396,7 @@ static int dump_cg_props_array(const char *fpath, struct cgroup_dir *ncd, const } if (asprintf(&new, "%d", disable) < 0) { - pr_err("couldn't aloocate new oom value\n"); + pr_err("couldn't allocate new oom value\n"); free_cgroup_prop(prop); free_all_cgroup_props(ncd); return -1; diff --git a/criu/clone-noasan.c b/criu/clone-noasan.c index 0d98c2ed8..c44e71969 100644 --- a/criu/clone-noasan.c +++ b/criu/clone-noasan.c @@ -13,7 +13,7 @@ * We need a real stack for clone(). * * To workaround this we add clone_noasan() not-instrumented wrapper for - * clone(). Unfortunately we can't use __attrbute__((no_sanitize_addresss)) + * clone(). Unfortunately we can't use __attribute__((no_sanitize_address)) * for this because of bug in GCC > 6: * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69863 * diff --git a/criu/cr-check.c b/criu/cr-check.c index f67b3445f..922349c57 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -250,7 +250,7 @@ static int check_fcntl(void) return -1; if (fcntl(fd, F_GETOWNER_UIDS, (long)v)) { - pr_perror("Can'r fetch file owner UIDs"); + pr_perror("Can't fetch file owner UIDs"); close(fd); return -1; } diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 35ca7019e..7ceff4c19 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1098,7 +1098,7 @@ static int dump_zombies(void) return -1; /* - * We dump zombies separately becase for pid-ns case + * We dump zombies separately because for pid-ns case * we'd have to resolve their pids w/o parasite via * target ns' proc. */ @@ -1669,18 +1669,18 @@ static int cr_dump_finish(int ret) * - error happened during checkpoint: just clean up * everything and continue execution of the dumpee; * - * - dump successed but post-dump script returned + * - dump succeeded but post-dump script returned * some ret code: same as in previous scenario -- * just clean up everything and continue execution, * we will return script ret code back to criu caller * and it's up to a caller what to do with running instance * of the dumpee -- either kill it, or continue running; * - * - dump successed but -R option passed, pointing that + * - dump succeeded but -R option passed, pointing that * we're asked to continue execution of the dumpee. It's * assumed that a user will use post-dump script to keep * consistency of the FS and other resources, we simply - * start rollback procedure and cleanup everyhting. + * start rollback procedure and cleanup everything. */ if (ret || post_dump_ret || opts.final_state == TASK_ALIVE) { network_unlock(); diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 3b2ffdd0d..db5a8cbf7 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -160,7 +160,7 @@ static inline int stage_current_participants(int next_stage) case CR_STATE_RESTORE: /* * Each thread has to be reported about this stage, - * so if we want to wait all other tast, we have to + * so if we want to wait all other tasks, we have to * exclude all threads of the current process. * It is supposed that we will wait other tasks, * before creating threads of the current task. @@ -295,7 +295,7 @@ static struct collect_image_info *cinfos_files[] = { &ext_file_cinfo, }; -/* These images are requered to restore namespaces */ +/* These images are required to restore namespaces */ static struct collect_image_info *before_ns_cinfos[] = { &tty_info_cinfo, /* Restore devpts content */ &tty_cdata, @@ -415,7 +415,7 @@ static int populate_pid_proc(void) static rt_sigaction_t sigchld_act; /* - * If parent's sigaction has blocked SIGKILL (which is non-sence), + * If parent's sigaction has blocked SIGKILL (which is non-sense), * this parent action is non-valid and shouldn't be inherited. * Used to mark parent_act* no more valid. */ @@ -2508,8 +2508,10 @@ static inline int decode_posix_timer(PosixTimerEntry *pte, } if (pte->vsec == 0 && pte->vnsec == 0) { - // Remaining time was too short. Set it to - // interval to make the timer armed and work. + /* + * Remaining time was too short. Set it to + * interval to make the timer armed and work. + */ pt->val.it_value.tv_sec = pte->isec; pt->val.it_value.tv_nsec = pte->insec; } else { diff --git a/criu/cr-service.c b/criu/cr-service.c index 33d417329..0928df880 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -559,7 +559,7 @@ static int dump_using_req(int sk, CriuOpts *req) /* * FIXME -- cr_dump_tasks() may return code from custom * scripts, that can be positive. However, right now we - * don't have ability to push scripts via RPC, so psitive + * don't have ability to push scripts via RPC, so positive * ret values are impossible here. */ if (cr_dump_tasks(req->pid)) @@ -899,7 +899,7 @@ static int handle_feature_check(int sk, CriuReq * msg) /* * If this point is reached the information about the features * is transmitted from the forked CRIU process (here). - * If an error occured earlier, the feature check response will be + * If an error occurred earlier, the feature check response will be * be send from the parent process. */ ret = send_criu_msg(sk, &resp); diff --git a/criu/fault-injection.c b/criu/fault-injection.c index f239fd9db..4128814d5 100644 --- a/criu/fault-injection.c +++ b/criu/fault-injection.c @@ -6,17 +6,17 @@ enum faults fi_strategy; int fault_injection_init() { char *val; - int strat; + int start; val = getenv("CRIU_FAULT"); if (val == NULL) return 0; - strat = atoi(val); + start = atoi(val); - if (strat <= 0 || strat >= FI_MAX) + if (start <= 0 || start >= FI_MAX) return -1; - fi_strategy = strat; + fi_strategy = start; return 0; } diff --git a/criu/fdstore.c b/criu/fdstore.c index d9bed4d5e..8d3a6c89b 100644 --- a/criu/fdstore.c +++ b/criu/fdstore.c @@ -54,7 +54,7 @@ int fdstore_init(void) * This socket is connected to itself, so all messages are queued to * its receive queue. Here we are going to use this socket to store * file descriptors. For that we need to send a file descriptor in - * a queue and remeber its sequence number. Then we can set SO_PEEK_OFF + * a queue and remember its sequence number. Then we can set SO_PEEK_OFF * to get a file descriptor without dequeuing it. */ if (bind(sk, (struct sockaddr *) &addr, addrlen)) { diff --git a/criu/files-reg.c b/criu/files-reg.c index c0b9b2fe2..8fb447ff8 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -302,7 +302,7 @@ static int ghost_apply_metadata(const char *path, GhostFileEntry *gfe) tv[1].tv_sec = gfe->mtim->tv_sec; tv[1].tv_usec = gfe->mtim->tv_usec; if (lutimes(path, tv)) { - pr_perror("Can't set access and modufication times on ghost %s", path); + pr_perror("Can't set access and modification times on ghost %s", path); goto err; } } @@ -669,7 +669,7 @@ static int clean_one_remap(struct remap_info *ri) rmntns_root = open(path, O_RDONLY); if (rmntns_root < 0) { - pr_perror("Unbale to open %s", path); + pr_perror("Unable to open %s", path); return -1; } @@ -1199,7 +1199,7 @@ static int check_path_remap(struct fd_link *link, const struct fd_parms *parms, /* * Linked file, but path is not accessible (unless any * other error occurred). We can create a temporary link to it - * uning linkat with AT_EMPTY_PATH flag and remap it to this + * using linkat with AT_EMPTY_PATH flag and remap it to this * name. */ @@ -1220,7 +1220,7 @@ static int check_path_remap(struct fd_link *link, const struct fd_parms *parms, * FIXME linked file, but the name we see it by is reused * by somebody else. We can dump it with linked remaps, but * we'll have difficulties on restore -- we will have to - * move the exisint file aside, then restore this one, + * move the existing file aside, then restore this one, * unlink, then move the original file back. It's fairly * easy to do, but we don't do it now, since unlinked files * have the "(deleted)" suffix in proc and name conflict @@ -1372,7 +1372,7 @@ static int linkat_hard(int odir, char *opath, int ndir, char *npath, uid_t uid, } /* - * Kernel before 4.3 has strange secutiry restrictions about + * Kernel before 4.3 has strange security restrictions about * linkat. If the fsuid of the caller doesn't equals * the uid of the file and the file is not "safe" * one, then only global CAP_CHOWN will be allowed @@ -1778,7 +1778,7 @@ struct filemap_ctx { * put a new one into ctx. * * True is used by premap, so that it just calls vm_open - * in sequence, immediatelly mmap()s the file, then it + * in sequence, immediately mmap()s the file, then it * can be closed. * * False is used by open_vmas() which pre-opens the files @@ -1829,7 +1829,7 @@ static int open_filemap(int pid, struct vma_area *vma) int ret; /* - * Thevma->fd should have been assigned in collect_filemap + * The vma->fd should have been assigned in collect_filemap * * We open file w/o lseek, as mappings don't care about it */ diff --git a/criu/files.c b/criu/files.c index a1b228889..18fa4dab6 100644 --- a/criu/files.c +++ b/criu/files.c @@ -249,7 +249,7 @@ void show_saved_files(void) * * This is here only to support the Linux Kernel between versions * 3.18 and 4.2. After that, this workaround is not needed anymore, - * but it will work properly on both a kernel with and withouth the bug. + * but it will work properly on both a kernel with and without the bug. * * When a process has a file open in an OverlayFS directory, * the information in /proc//fd/ and /proc//fdinfo/ @@ -1118,7 +1118,7 @@ static int open_fd(struct fdinfo_list_entry *fle) /* * Open method returns the following values: - * 0 -- restore is successefuly finished; + * 0 -- restore is successfully finished; * 1 -- restore is in process or can't be started * yet, because of it depends on another fles, * so the method should be called once again; diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index 8f09fd903..5b17130ad 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -12,7 +12,7 @@ #define CPU_CAP_ALL (-1u) #define CPU_CAP_FPU (1u) /* Only FPU capability required */ #define CPU_CAP_CPU (2u) /* Strict CPU capability required */ -#define CPU_CAP_INS (4u) /* Instructions CPU capatibility */ +#define CPU_CAP_INS (4u) /* Instructions CPU capability */ #define CPU_CAP_DEFAULT (CPU_CAP_FPU) struct cg_root_opt { @@ -95,7 +95,7 @@ struct cr_options { bool autodetect_ext_mounts; int enable_external_sharing; int enable_external_masters; - bool aufs; /* auto-deteced, not via cli */ + bool aufs; /* auto-detected, not via cli */ bool overlayfs; #ifdef CONFIG_BINFMT_MISC_VIRTUALIZED bool has_binfmt_misc; /* auto-detected */ diff --git a/criu/irmap.c b/criu/irmap.c index 107e0f294..e72984216 100644 --- a/criu/irmap.c +++ b/criu/irmap.c @@ -5,7 +5,7 @@ * so that we can restore inotify/fanotify-s. * * Scanning _is_ slow, so we limit it with hints, which are - * heurisitical known places where notifies are typically put. + * heuristically known places where notifies are typically put. */ #include diff --git a/criu/kerndat.c b/criu/kerndat.c index 3477f88ca..d8e940130 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -703,7 +703,7 @@ static int kerndat_detect_stack_guard_gap(void) /* * When reading /proc/$pid/[s]maps the - * start/end addresses migh be cutted off + * start/end addresses might be cutted off * with PAGE_SIZE on kernels prior 4.12 * (see kernel commit 1be7107fbe18ee). * diff --git a/criu/log.c b/criu/log.c index 100ddc796..be3e4499e 100644 --- a/criu/log.c +++ b/criu/log.c @@ -112,7 +112,7 @@ static void log_note_err(char *msg) /* * In any action other than restore this locking is * actually not required, but ... it's error path - * anyway, so it doesn't make much sence to try hard + * anyway, so it doesn't make much sense to try hard * and optimize this out. */ mutex_lock(&first_err->l); @@ -142,7 +142,7 @@ int log_init(const char *output) if (output && !strncmp(output, "-", 2)) { new_logfd = dup(STDOUT_FILENO); if (new_logfd < 0) { - pr_perror("Cant't dup stdout stream"); + pr_perror("Can't dup stdout stream"); return -1; } } else if (output) { diff --git a/criu/mem.c b/criu/mem.c index f3b2c224d..162e98a28 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -734,7 +734,7 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void pr_debug("\tpremap %#016"PRIx64"-%#016"PRIx64" -> %016lx\n", vma->e->start, vma->e->end, (unsigned long)addr); - if (vma_has_guard_gap_hidden(vma)) { /* Skip gurad page */ + if (vma_has_guard_gap_hidden(vma)) { /* Skip guard page */ vma->e->start += PAGE_SIZE; vma->premmaped_addr += PAGE_SIZE; } @@ -851,7 +851,7 @@ static int restore_priv_vma_content(struct pstree_item *t, struct page_read *pr) unsigned int nr_restored = 0; unsigned int nr_shared = 0; - unsigned int nr_droped = 0; + unsigned int nr_dropped = 0; unsigned int nr_compared = 0; unsigned int nr_lazy = 0; unsigned long va; @@ -1019,7 +1019,7 @@ err_read: return -1; } i++; - nr_droped++; + nr_dropped++; } } @@ -1029,7 +1029,7 @@ err_read: pr_info("nr_restored_pages: %d\n", nr_restored); pr_info("nr_shared_pages: %d\n", nr_shared); - pr_info("nr_droped_pages: %d\n", nr_droped); + pr_info("nr_dropped_pages: %d\n", nr_dropped); pr_info("nr_lazy: %d\n", nr_lazy); return 0; @@ -1152,7 +1152,7 @@ bool vma_has_guard_gap_hidden(struct vma_area *vma) } /* - * A gard page must be unmapped after restoring content and + * A guard page must be unmapped after restoring content and * forking children to restore COW memory. */ int unmap_guard_pages(struct pstree_item *t) @@ -1204,7 +1204,7 @@ int open_vmas(struct pstree_item *t) /* * File mappings have vm_open set to open_filemap which, in * turn, puts the VMA_CLOSE bit itself. For all the rest we - * need to put it by hads, so that the restorer closes the fd + * need to put it by hands, so that the restorer closes the fd */ if (!(vma_area_is(vma, VMA_FILE_PRIVATE) || vma_area_is(vma, VMA_FILE_SHARED))) diff --git a/criu/mount.c b/criu/mount.c index 1beff348f..a291934fa 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -554,12 +554,12 @@ static int validate_shared(struct mount_info *m) /* * Check that all mounts in one shared group has the same set of * children. Only visible children are accounted. A non-root bind-mount - * doesn't see children out of its root and it's excpected case. + * doesn't see children out of its root and it's expected case. * * Here is a few conditions: * 1. t is wider than m * 2. We search a wider mount in the same direction, so when we - * enumirate all mounts, we can't be sure that all of them + * enumerate all mounts, we can't be sure that all of them * has the same set of children. */ @@ -572,7 +572,7 @@ static int validate_shared(struct mount_info *m) */ return 0; - /* Search a child, which is visiable in both mounts. */ + /* Search a child, which is visible in both mounts. */ list_for_each_entry(ct, &t->children, siblings) { struct mount_info *cm; @@ -1047,7 +1047,7 @@ int __open_mountpoint(struct mount_info *pm, int mnt_fd) } if (pm->s_dev_rt == MOUNT_INVALID_DEV) { - pr_err("Resolving over unvalid device for %#x %s %s\n", + pr_err("Resolving over invalid device for %#x %s %s\n", pm->s_dev, pm->fstype->name, pm->ns_mountpoint); goto err; } @@ -1673,7 +1673,7 @@ err: * _fn_f - pre-order traversal function * _fn_f - post-order traversal function * _plist - a postpone list. _el is added to this list, if _fn_f returns - * a positive value, and all lower elements are not enumirated. + * a positive value, and all lower elements are not enumerated. */ #define MNT_TREE_WALK(_r, _el, _fn_f, _fn_r, _plist, _prgs) do { \ struct mount_info *_mi = _r; \ @@ -1857,7 +1857,7 @@ static int propagate_siblings(struct mount_info *mi) /* * Find all mounts, which must be bind-mounted from this one - * to inherite shared group or master id + * to inherit shared group or master id */ list_for_each_entry(t, &mi->mnt_share, mnt_share) { if (t->mounted) @@ -2064,7 +2064,7 @@ static int do_new_mount(struct mount_info *mi) sflags |= MS_RDONLY; if (userns_call(apply_sb_flags, 0, &sflags, sizeof(sflags), fd)) { - pr_perror("Unable to apply mount falgs %d for %s", + pr_perror("Unable to apply mount flags %d for %s", mi->sb_flags, mi->mountpoint); close(fd); return -1; @@ -2334,8 +2334,8 @@ static bool can_mount_now(struct mount_info *mi) /* * We're the slave peer: * - Make sure the master peer is already mounted - * - Make sure all children is mounted as well to - * eliminame mounts duplications + * - Make sure all children are mounted as well to + * eliminate mounts duplications */ if (mi->master_id > 0) { struct mount_info *c; @@ -2470,7 +2470,7 @@ static int do_umount_one(struct mount_info *mi) } /* - * If a mount overmounts other mounts, it is restored separetly in the roots + * If a mount overmounts other mounts, it is restored separately in the roots * yard and then moved to the right place. * * mnt_remap_entry is created for each such mount and it's added into @@ -3036,7 +3036,7 @@ static int populate_roots_yard(void) /* * mnt_remap_list is filled in find_remap_mounts() and - * contains mounts which has to be restored separatly + * contains mounts which has to be restored separately */ list_for_each_entry(r, &mnt_remap_list, node) { if (mkdirpat(AT_FDCWD, r->mi->mountpoint, 0755)) { @@ -3253,7 +3253,7 @@ int prepare_mnt_ns(void) if (rst < 0) return -1; - /* resotre non-root namespaces */ + /* restore non-root namespaces */ for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { char path[PATH_MAX]; @@ -3439,7 +3439,7 @@ struct ns_id *lookup_nsid_by_mnt_id(int mnt_id) * Kernel before 3.15 doesn't show mnt_id for file descriptors. * mnt_id isn't saved for files, if mntns isn't dumped. * In both these cases we have only one root, so here - * is not matter which mount will be restured. + * is not matter which mount will be restored. */ if (mnt_id == -1) mi = mntinfo; diff --git a/criu/namespaces.c b/criu/namespaces.c index 67fa2f57a..18b45e8f3 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -1548,7 +1548,7 @@ static int prepare_userns_creds(void) /* * This flag is dropped after entering userns, but is * required to access files in /proc, so put one here - * temoprarily. It will be set to proper value at the + * temporarily. It will be set to proper value at the * very end. */ if (prctl(PR_SET_DUMPABLE, 1, 0)) { diff --git a/criu/netfilter.c b/criu/netfilter.c index 991c7181f..368651c71 100644 --- a/criu/netfilter.c +++ b/criu/netfilter.c @@ -19,7 +19,7 @@ static char buf[512]; /* * Need to configure simple netfilter rules for blocking connections - * ANy brave soul to write it using xtables-devel? + * Any brave soul to write it using xtables-devel? */ #define NF_CONN_CMD "%s %s -t filter %s %s --protocol tcp " \ diff --git a/criu/page-pipe.c b/criu/page-pipe.c index f33e86a4f..eb09882c7 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -391,7 +391,7 @@ int page_pipe_read(struct page_pipe *pp, struct pipe_read_dest *prd, *nr_pages = len / PAGE_SIZE; skip += ppb->pipe_off * PAGE_SIZE; - /* we should tee() the requested lenth + the beginning of the pipe */ + /* we should tee() the requested length + the beginning of the pipe */ len += skip; ret = tee(ppb->p[0], prd->p[1], len, 0); diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 853f3ee53..c70aec5fb 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -81,7 +81,7 @@ static int decode_pm(u64 dst_id, unsigned long *id) /* * Magic numbers below came from the older CRIU versions that - * errorneously used the changing CR_FD_* constants. The + * erroneously used the changing CR_FD_* constants. The * changes were made when we merged images together and moved * the CR_FD_-s at the tail of the enum */ @@ -665,7 +665,7 @@ static int page_server_add(int sk, struct page_server_iov *pi, u32 flags) /* * Splicing into a pipe may end up blocking if pipe is "full", * and we need the SPLICE_F_NONBLOCK flag here. At the same time - * splcing from UNIX socket with this flag aborts splice with + * splicing from UNIX socket with this flag aborts splice with * the EAGAIN if there's no data in it (TCP looks at the socket * O_NONBLOCK flag _only_ and waits for data), so before doing * the non-blocking splice we need to explicitly wait. diff --git a/criu/pagemap.c b/criu/pagemap.c index e6470651f..b106f883e 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -630,7 +630,7 @@ static void init_compat_pagemap_entry(PagemapEntry *pe) /* * pagemap image generated with older version will either * contain a hole because the pages are in the parent - * shanpshot or a pagemap that should be marked with + * snapshot or a pagemap that should be marked with * PE_PRESENT */ if (pe->has_in_parent && pe->in_parent) diff --git a/criu/rst-malloc.c b/criu/rst-malloc.c index 4f7357ca2..ff96797e2 100644 --- a/criu/rst-malloc.c +++ b/criu/rst-malloc.c @@ -72,7 +72,7 @@ static int grow_remap(struct rst_mem_type_s *t, int flag, unsigned long size) /* * Anon shared memory cannot grow with * mremap, anon-shmem file size doesn't - * chage and memory access generates + * change and memory access generates * SIGBUS. We should truncate the guy, * but for now we don't need it. */ diff --git a/criu/seize.c b/criu/seize.c index 635c0c088..bc689d265 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -142,7 +142,7 @@ static int seize_cgroup_tree(char *root_path, const char *state) if (stat(buf, &st) == -1 && errno == ENOENT) continue; /* - * fails when meets a zombie, or eixting process: + * fails when meets a zombie, or exiting process: * there is a small race in a kernel -- the process * may start exiting and we are trying to freeze it * before it compete exit procedure. The caller simply @@ -350,7 +350,7 @@ static int freeze_processes(void) nr_attempts = (10 * 1000000) / step_ms; } - pr_debug("freezing processes: %lu attempst with %lu ms steps\n", + pr_debug("freezing processes: %lu attempts with %lu ms steps\n", nr_attempts, step_ms); snprintf(path, sizeof(path), "%s/freezer.state", opts.freeze_cgroup); diff --git a/criu/shmem.c b/criu/shmem.c index 895297f0b..358d848db 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -31,7 +31,7 @@ #endif /* - * Hash table and routines for keeping shmid -> shmem_xinfo mappings + * Hash table and routines for keeping shmid -> shmem_xinfo mappings */ /* @@ -66,7 +66,7 @@ struct shmem_info { int fd; /* - * 0. lock is initilized to zero + * 0. lock is initialized to zero * 1. the master opens a descriptor and set lock to 1 * 2. slaves open their descriptors and increment lock * 3. the master waits all slaves on lock. After that @@ -272,7 +272,7 @@ int fixup_sysv_shmems(void) } /* - * See comment in open_shmem_sysv() about this PROT_EXEC + * See comment in open_shmem_sysv() about this PROT_EXEC */ if (si->want_write) att->first->prot |= PROT_EXEC; @@ -324,7 +324,7 @@ static int open_shmem_sysv(int pid, struct vma_area *vma) * whether to create the segment rw or ro, but the * first vma can have different protection. So the * segment ro-ness is marked with PROT_EXEC bit in - * the first vma. Unfortunatelly, we only know this + * the first vma. Unfortunately, we only know this * after we scan all the vmas, so this bit is set * at the end in fixup_sysv_shmems(). */ diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c index 9c73d882f..427467195 100644 --- a/criu/sk-tcp.c +++ b/criu/sk-tcp.c @@ -31,7 +31,7 @@ static LIST_HEAD(cpt_tcp_repair_sockets); static LIST_HEAD(rst_tcp_repair_sockets); -static int tcp_repair_establised(int fd, struct inet_sk_desc *sk) +static int tcp_repair_established(int fd, struct inet_sk_desc *sk) { int ret; struct libsoccr_sk *socr; @@ -223,7 +223,7 @@ int dump_one_tcp(int fd, struct inet_sk_desc *sk) pr_info("Dumping TCP connection\n"); - if (tcp_repair_establised(fd, sk)) + if (tcp_repair_established(fd, sk)) return -1; if (dump_tcp_conn_state(sk)) @@ -387,7 +387,7 @@ int prepare_tcp_socks(struct task_restore_args *ta) /* * rst_tcp_repair_sockets contains all sockets, so we need to - * select sockets which restored in a current porcess. + * select sockets which restored in a current process. */ if (ii->sk_fd == -1) continue; diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 6ce42ff92..fb7659c99 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -403,8 +403,8 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p) /* * Usually this doesn't happen, however it's possible if * socket was shut down before connect() (see sockets03.c test). - * On restore we will shutdown both end (iow socktes will be in - * matched state). This shoudn't be a problem, since kernel seems + * On restore we will shutdown both end (iow sockets will be in + * matched state). This shouldn't be a problem, since kernel seems * to check both ends on read()/write(). Thus mismatched sockets behave * the same way as matched. */ diff --git a/criu/sysfs_parse.c b/criu/sysfs_parse.c index bd678a6e5..922e5d41d 100644 --- a/criu/sysfs_parse.c +++ b/criu/sysfs_parse.c @@ -242,7 +242,7 @@ int parse_aufs_branches(struct mount_info *mi) fclose(fp); /* - * Log branch information for extenal utitilies that + * Log branch information for external utitilies that * want to recreate the process's AUFS filesystem * before calling criu restore. * diff --git a/criu/tty.c b/criu/tty.c index 52d571c08..30e3d7288 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -2150,7 +2150,7 @@ static int tty_do_dump_queued_data(struct tty_dump_info *dinfo) ret, (int)off, dinfo->driver->name, dinfo->id); if (off >= size) { - pr_err("The tty (%s %#x) queued data overrflow %zu bytes limit\n", + pr_err("The tty (%s %#x) queued data overflow %zu bytes limit\n", dinfo->driver->name, dinfo->id, size); off = size; break; diff --git a/criu/tun.c b/criu/tun.c index acd40ea1e..dfca4b125 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -292,7 +292,7 @@ static int dump_tunfile(int lfd, u32 id, const struct fd_parms *p) /* * Otherwise this is just opened file with not yet attached - * tun device. Go agead an write the respective entry. + * tun device. Go ahead an write the respective entry. */ } else { tfe.netdev = ifr.ifr_name; diff --git a/criu/uffd.c b/criu/uffd.c index 72fc1402d..97d2d05ba 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -808,7 +808,7 @@ static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) /* * Seek for the requested address in the pagemap. If it is found, the * subsequent call to pr->page_read will bring us the data. If the - * address is not found in the pagemap, but no error occured, the + * address is not found in the pagemap, but no error occurred, the * address should be mapped to zero pfn. * * Returns 0 for zero pages, 1 for "real" pages and negative value on @@ -1213,7 +1213,7 @@ static int lazy_sk_read_event(struct epoll_rfd *rfd) return 0; if (ret != sizeof(fin)) { - pr_perror("Failed getting restore finished inidication"); + pr_perror("Failed getting restore finished indication"); return -1; } diff --git a/criu/vdso-compat.c b/criu/vdso-compat.c index 6d7632814..a68c0bace 100644 --- a/criu/vdso-compat.c +++ b/criu/vdso-compat.c @@ -66,7 +66,7 @@ void compat_vdso_helper(struct vdso_maps *native, int pipe_fd, ret = syscall(__NR_read, pipe_fd, &vdso_addr, sizeof(void *)); if (ret != sizeof(void *)) - exit_on(-1, err_fd, "Error: Can't read size of mmaped vdso from pipe\n"); + exit_on(-1, err_fd, "Error: Can't read size of mapped vdso from pipe\n"); memcpy(vdso_buf, vdso_addr, vdso_size); diff --git a/criu/vdso.c b/criu/vdso.c index 731f94165..ea142ea84 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -167,14 +167,14 @@ static void drop_rt_vdso(struct vm_area_list *vma_area_list, } } - pr_debug("vdso: Droppping marked vdso at %lx\n", + pr_debug("vdso: Dropping marked vdso at %lx\n", (long)rt_vdso_marked->e->start); list_del(&rt_vdso_marked->list); xfree(rt_vdso_marked); vma_area_list->nr--; if (rt_vvar_marked) { - pr_debug("vdso: Droppping marked vvar at %lx\n", + pr_debug("vdso: Dropping marked vvar at %lx\n", (long)rt_vvar_marked->e->start); list_del(&rt_vvar_marked->list); xfree(rt_vvar_marked); diff --git a/lib/py/criu.py b/lib/py/criu.py index cafaea8f3..e4e46b52b 100644 --- a/lib/py/criu.py +++ b/lib/py/criu.py @@ -56,7 +56,7 @@ class _criu_comm_sk(_criu_comm): class _criu_comm_fd(_criu_comm): """ - Commnunication class for file descriptor. + Communication class for file descriptor. """ def __init__(self, fd): self.comm_type = self.COMM_FD @@ -164,7 +164,7 @@ class CRIUExceptionExternal(CRIUException): s = "%s failed: " % (rpc.criu_req_type.Name(self.typ), ) if self.typ != self.resp_typ: - s += "Unxecpected response type %d: " % (self.resp_typ, ) + s += "Unexpected response type %d: " % (self.resp_typ, ) s += "Error(%d): " % (self.errno, ) From 23dad9829d299d5b0885b8287c07c691b928f517 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 8 Feb 2018 18:00:54 +0300 Subject: [PATCH 1323/4375] inotify: Do not DDOS by debug message on restore watch descriptor Imagine, we have to restore inotify with watch descriptor 0x34d71d6. Then we have: 1.235021 5578: fsnotify: Watch got 0x1 but 0x34d71d6 expected ... ... 527.378042 5578: fsnotify: Watch got 0x34d71d3 but 0x34d71d6 expected 527.378042 5578: fsnotify: Watch got 0x34d71d4 but 0x34d71d6 expected 527.378042 5578: fsnotify: Watch got 0x34d71d5 but 0x34d71d6 expected Stop doing this and stop generating GBs of debug messages. We already have print message before restore_one_inotify(). Let's add just one more after it. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/fsnotify.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 955cd106b..de288551f 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -589,7 +589,6 @@ static int restore_one_inotify(int inotify_fd, struct fsnotify_mark_info *info) break; } - pr_debug("\t\tWatch got 0x%x but 0x%x expected\n", wd, iwe->wd); inotify_rm_watch(inotify_fd, wd); } @@ -689,6 +688,7 @@ static int open_inotify_fd(struct file_desc *d, int *new_fd) close_safe(&tmp); break; } + pr_info("\t 0x%x wd for %#08x is restored\n", wd_info->iwe->wd, wd_info->iwe->id); } if (restore_fown(tmp, info->ife->fown)) From f89aa7f35b430136579ec3941d342c71ca9187fc Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 8 Feb 2018 18:01:14 +0300 Subject: [PATCH 1324/4375] inotify: Fix open_*notify_fd() never fails We ignore restore_one_*notify() error code, while we mustn't. Make open function fail when we can't restore them. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/fsnotify.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index de288551f..5fb26d0e9 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -686,7 +686,7 @@ static int open_inotify_fd(struct file_desc *d, int *new_fd) pr_info("\tRestore 0x%x wd for %#08x\n", wd_info->iwe->wd, wd_info->iwe->id); if (restore_one_inotify(tmp, wd_info)) { close_safe(&tmp); - break; + return -1; } pr_info("\t 0x%x wd for %#08x is restored\n", wd_info->iwe->wd, wd_info->iwe->id); } @@ -723,7 +723,7 @@ static int open_fanotify_fd(struct file_desc *d, int *new_fd) pr_info("\tRestore fanotify for %#08x\n", mark->fme->id); if (restore_one_fanotify(ret, mark)) { close_safe(&ret); - break; + return -1; } } From 3b71b95a190cfea5ecef73b059fe942bef485e7d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 7 Feb 2018 12:48:46 +0000 Subject: [PATCH 1325/4375] x86/crtools: Add fork() err-path handle Error-path for failed fork(). Looks originally forgotten, oops! Also print a message on failed fork(). Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 69de23b44..d7b21e7c9 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -40,8 +40,10 @@ int kdat_can_map_vdso(void) * it for criu accidentally. */ child = fork(); - if (child < 0) + if (child < 0) { + pr_perror("%s(): failed to fork()", __func__); return -1; + } if (child == 0) { int ret; @@ -150,6 +152,11 @@ static int has_32bit_mmap_bug(void) pid_t child = fork(); int stat; + if (child < 0) { + pr_perror("%s(): failed to fork()", __func__); + return -1; + } + if (child == 0) mmap_bug_test(); From a41cc56cd805ae929d00d8668bab991d21cd12c3 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 7 Feb 2018 12:48:47 +0000 Subject: [PATCH 1326/4375] x86/kerndat: Add a check for ptrace() bug on Skylake We need to know if ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, iov) returns xsave without FP state part. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 75 ++++++++++++++++++++++++++++ criu/arch/x86/include/asm/restorer.h | 2 + criu/include/kerndat.h | 1 + criu/kerndat.c | 18 +++++++ 4 files changed, 96 insertions(+) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index d7b21e7c9..e13b39b90 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -3,10 +3,12 @@ #include #include #include +#include #include #include #include #include +#include #include "types.h" #include "log.h" @@ -30,6 +32,7 @@ #include "images/core.pb-c.h" #include "images/creds.pb-c.h" +/* XXX: Move all kerndat features to per-arch kerndat .c */ int kdat_can_map_vdso(void) { pid_t child; @@ -188,6 +191,78 @@ int kdat_compatible_cr(void) } #endif +static int kdat_x86_has_ptrace_fpu_xsave_bug_child(void *arg) +{ + ptrace(PTRACE_TRACEME, 0, 0, 0); + kill(getpid(), SIGSTOP); + pr_err("Continue after SIGSTOP.. Urr what?\n"); + _exit(1); +} + +/* + * Pre v4.14 kernels have a bug on Skylake CPUs: + * copyout_from_xsaves() creates fpu state for + * ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) + * without MXCSR and MXCSR_FLAGS if there is SSE/YMM state, but no FP state. + * That is xfeatures had either/both XFEATURE_MASK_{SSE,YMM} set, but not + * XFEATURE_MASK_FP. + * But we *really* need to C/R MXCSR & MXCSR_FLAGS if SSE/YMM active, + * as mxcsr store part of the state. + */ +int kdat_x86_has_ptrace_fpu_xsave_bug(void) +{ + user_fpregs_struct_t xsave = { }; + struct iovec iov; + char stack[PAGE_SIZE]; + int flags = CLONE_VM | CLONE_FILES | CLONE_UNTRACED | SIGCHLD; + int ret = -1; + pid_t child; + int stat; + + /* OSXSAVE can't be changed during boot. */ + if (!compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) + return 0; + + child = clone(kdat_x86_has_ptrace_fpu_xsave_bug_child, + stack + ARRAY_SIZE(stack), flags, 0); + if (child < 0) { + pr_perror("%s(): failed to clone()", __func__); + return -1; + } + + if (waitpid(child, &stat, WUNTRACED) != child) { + /* + * waitpid() may end with ECHILD if SIGCHLD == SIG_IGN, + * and the child has stopped already. + */ + pr_perror("Failed to wait for %s() test\n", __func__); + goto out_kill; + } + + if (!WIFSTOPPED(stat)) { + pr_err("Born child is unstoppable! (might be dead)\n"); + goto out_kill; + } + + iov.iov_base = &xsave; + iov.iov_len = sizeof(xsave); + + if (ptrace(PTRACE_GETREGSET, child, (unsigned)NT_X86_XSTATE, &iov) < 0) { + pr_perror("Can't obtain FPU registers for %d", child); + goto out_kill; + } + /* + * MXCSR should be never 0x0: e.g., it should contain either: + * R+/R-/RZ/RN to determine rounding model. + */ + ret = !xsave.i387.mxcsr; + +out_kill: + kill(child, SIGKILL); + waitpid(child, &stat, 0); + return ret; +} + int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) { CoreEntry *core = x; diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index e39675d95..179f1942f 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -80,8 +80,10 @@ static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) # define ARCH_MAP_VDSO_64 0x2003 #endif +/* XXX: Introduce per-arch kerndat header */ extern int kdat_compatible_cr(void); extern int kdat_can_map_vdso(void); +extern int kdat_x86_has_ptrace_fpu_xsave_bug(void); static inline void __setup_sas_compat(struct ucontext_ia32* uc, ThreadSasEntry *sas) diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index d966edf8b..5476b26ef 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -68,6 +68,7 @@ struct kerndat_s { bool has_link_nsid; unsigned int sysctl_nr_open; unsigned long files_stat_max_files; + bool x86_has_ptrace_fpu_xsave_bug; }; extern struct kerndat_s kdat; diff --git a/criu/kerndat.c b/criu/kerndat.c index d8e940130..3a3d9f66e 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -737,6 +737,22 @@ err: return ret; } +int __attribute__((weak)) kdat_x86_has_ptrace_fpu_xsave_bug(void) +{ + return 0; +} + +static int kerndat_x86_has_ptrace_fpu_xsave_bug(void) +{ + int ret = kdat_x86_has_ptrace_fpu_xsave_bug(); + + if (ret < 0) + return ret; + + kdat.x86_has_ptrace_fpu_xsave_bug = !!ret; + return 0; +} + #define KERNDAT_CACHE_FILE KDAT_RUNDIR"/criu.kdat" #define KERNDAT_CACHE_FILE_TMP KDAT_RUNDIR"/.criu.kdat" @@ -974,6 +990,8 @@ int kerndat_init(void) ret = kerndat_socket_netns(); if (!ret) ret = kerndat_nsid(); + if (!ret) + ret = kerndat_x86_has_ptrace_fpu_xsave_bug(); kerndat_lsm(); kerndat_mmap_min_addr(); From d59276f08ad54c645966d0f9cf97e117abfaa483 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 7 Feb 2018 12:48:48 +0000 Subject: [PATCH 1327/4375] compel/infect: Unite save_regs_t with save_regs() declaration As we anyway define save_regs_t for other purposes, use it in the function declaration. To unify infect_ctx style, add make_sigframe_t. Mere cleanup. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 3264e923f..d9bf069b2 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -96,6 +96,8 @@ struct rt_sigframe; typedef int (*open_proc_fn)(int pid, int mode, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); +typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); +typedef int (*make_sigframe_t)(void *, struct rt_sigframe *, struct rt_sigframe *, k_rtsigset_t *); struct infect_ctx { int sock; @@ -103,8 +105,8 @@ struct infect_ctx { /* * Regs manipulation context. */ - int (*save_regs)(void *, user_regs_struct_t *, user_fpregs_struct_t *); - int (*make_sigframe)(void *, struct rt_sigframe *, struct rt_sigframe *, k_rtsigset_t *); + save_regs_t save_regs; + make_sigframe_t make_sigframe; void *regs_arg; unsigned long task_size; @@ -151,7 +153,6 @@ struct parasite_blob_desc { extern struct parasite_blob_desc *compel_parasite_blob_desc(struct parasite_ctl *); -typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *); extern int compel_get_thread_regs(struct parasite_thread_ctl *, save_regs_t, void *); extern void compel_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *elf_relocs, size_t nr_relocs); From 8a8717da5ac182e4b7b3d5b8c3aa02b2c2030755 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 7 Feb 2018 12:48:49 +0000 Subject: [PATCH 1328/4375] compel: Add ctx flags to get_task_regs() get_task_regs() needs to know if it needs to use workaround for a Skylake ptrace() bug. The next patch will introduce a new flag for that. I also thought about making 3 versions of get_task_regs() and adding them to ictx->get_task_regs() depending on the flags.. But get_task_regs() is a private function and infect_ctx is a uapi.. So, let's just pass context flags to get_task_regs(). Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/infect.c | 3 ++- compel/arch/arm/src/lib/infect.c | 3 ++- compel/arch/ppc64/src/lib/infect.c | 3 ++- compel/arch/s390/src/lib/infect.c | 2 +- compel/arch/x86/src/lib/infect.c | 3 ++- compel/include/infect-priv.h | 3 ++- compel/src/lib/infect.c | 5 +++-- 7 files changed, 14 insertions(+), 8 deletions(-) diff --git a/compel/arch/aarch64/src/lib/infect.c b/compel/arch/aarch64/src/lib/infect.c index 74e72ad39..c4a2fde20 100644 --- a/compel/arch/aarch64/src/lib/infect.c +++ b/compel/arch/aarch64/src/lib/infect.c @@ -57,7 +57,8 @@ int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, return 0; } -int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, void *arg) +int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, + void *arg, __maybe_unused unsigned long flags) { struct iovec iov; user_fpregs_struct_t fpsimd; diff --git a/compel/arch/arm/src/lib/infect.c b/compel/arch/arm/src/lib/infect.c index c574d00e1..c17cb9c9b 100644 --- a/compel/arch/arm/src/lib/infect.c +++ b/compel/arch/arm/src/lib/infect.c @@ -66,7 +66,8 @@ int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, } #define PTRACE_GETVFPREGS 27 -int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, void *arg) +int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, + void *arg, __maybe_unused unsigned long flags) { user_fpregs_struct_t vfp; int ret = -1; diff --git a/compel/arch/ppc64/src/lib/infect.c b/compel/arch/ppc64/src/lib/infect.c index 1fa333e00..96e1f3ba6 100644 --- a/compel/arch/ppc64/src/lib/infect.c +++ b/compel/arch/ppc64/src/lib/infect.c @@ -371,7 +371,8 @@ static int __get_task_regs(pid_t pid, user_regs_struct_t *regs, return 0; } -int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, void *arg) +int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, + void *arg, __maybe_unused unsigned long flags) { user_fpregs_struct_t fpregs; int ret; diff --git a/compel/arch/s390/src/lib/infect.c b/compel/arch/s390/src/lib/infect.c index abc1e6cd3..940d04418 100644 --- a/compel/arch/s390/src/lib/infect.c +++ b/compel/arch/s390/src/lib/infect.c @@ -312,7 +312,7 @@ static int s390_disable_ri_bit(pid_t pid, user_regs_struct_t *regs) * Prepare task registers for restart */ int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, - void *arg) + void *arg, __maybe_unused unsigned long flags) { user_fpregs_struct_t fpregs; struct iovec iov; diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index e546ee376..cdf468339 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -225,7 +225,8 @@ int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \ (int32_t)((pregs)->compat.name)) -int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, void *arg) +int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, + void *arg, __maybe_unused unsigned long flags) { user_fpregs_struct_t xsave = { }, *xs = NULL; diff --git a/compel/include/infect-priv.h b/compel/include/infect-priv.h index 00671e71f..ec6dd455d 100644 --- a/compel/include/infect-priv.h +++ b/compel/include/infect-priv.h @@ -58,7 +58,8 @@ extern void *remote_mmap(struct parasite_ctl *ctl, void *addr, size_t length, int prot, int flags, int fd, off_t offset); extern bool arch_can_dump_task(struct parasite_ctl *ctl); -extern int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, void *arg); +extern int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, + void *arg, unsigned long flags); extern int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s); extern int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, user_regs_struct_t *regs, diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 0527481ed..ecc6599b1 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -667,7 +667,8 @@ static int parasite_start_daemon(struct parasite_ctl *ctl) * while in daemon it is not such. */ - if (get_task_regs(pid, &ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) { + if (get_task_regs(pid, &ctl->orig.regs, ictx->save_regs, + ictx->regs_arg, ictx->flags)) { pr_err("Can't obtain regs for thread %d\n", pid); return -1; } @@ -1569,7 +1570,7 @@ k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl) int compel_get_thread_regs(struct parasite_thread_ctl *tctl, save_regs_t save, void * arg) { - return get_task_regs(tctl->tid, &tctl->th.regs, save, arg); + return get_task_regs(tctl->tid, &tctl->th.regs, save, arg, tctl->ctl->ictx.flags); } struct infect_ctx *compel_infect_ctx(struct parasite_ctl *ctl) From 0e609f8cabf2fc3f58f093d26a9737bbb121e68d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 7 Feb 2018 12:48:50 +0000 Subject: [PATCH 1329/4375] compel/x86: Separate functions used to get fpu state Mere cleanup. For Skylake workaround I'll call one after another, so it's better separate it in a small helpers. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/infect.c | 40 ++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index cdf468339..d95299b3b 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -225,12 +225,35 @@ int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \ (int32_t)((pregs)->compat.name)) +static int get_task_xsave(pid_t pid, user_fpregs_struct_t *xsave) +{ + struct iovec iov; + + iov.iov_base = xsave; + iov.iov_len = sizeof(*xsave); + + if (ptrace(PTRACE_GETREGSET, pid, (unsigned int)NT_X86_XSTATE, &iov) < 0) { + pr_perror("Can't obtain FPU registers for %d", pid); + return -1; + } + + return 0; +} + +static int get_task_fpregs(pid_t pid, user_fpregs_struct_t *xsave) +{ + if (ptrace(PTRACE_GETFPREGS, pid, NULL, xsave)) { + pr_perror("Can't obtain FPU registers for %d", pid); + return -1; + } + + return 0; +} + int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, void *arg, __maybe_unused unsigned long flags) { - user_fpregs_struct_t xsave = { }, *xs = NULL; - - struct iovec iov; + user_fpregs_struct_t xsave = { }, *xs = NULL; int ret = -1; pr_info("Dumping general registers for %d in %s mode\n", pid, @@ -264,18 +287,11 @@ int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, pr_info("Dumping GP/FPU registers for %d\n", pid); if (compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) { - iov.iov_base = &xsave; - iov.iov_len = sizeof(xsave); - - if (ptrace(PTRACE_GETREGSET, pid, (unsigned int)NT_X86_XSTATE, &iov) < 0) { - pr_perror("Can't obtain FPU registers for %d", pid); + if (get_task_xsave(pid, &xsave)) goto err; - } } else { - if (ptrace(PTRACE_GETFPREGS, pid, NULL, &xsave)) { - pr_perror("Can't obtain FPU registers for %d", pid); + if (get_task_fpregs(pid, &xsave)) goto err; - } } xs = &xsave; From 5f185caa73d7e1dd31cc278fbeea630df56b347f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 7 Feb 2018 12:48:51 +0000 Subject: [PATCH 1330/4375] compel/x86: Add workaround on ptrace() bug on Skylake On Skylake processors and kernel older than v4.14 ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, iov) may return not full xstate, ommiting FP part (that is XFEATURE_MASK_FP). There is a patch which describes this bug: https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1318800.html Anyway, it's fixed in v4.14 kernel by (what we believe with Andrey) this: https://patchwork.kernel.org/patch/9567939/ As we still support kernels from v3.10 and newer, we need to have a workaround for this kernel bug on Skylake CPUs. Big thanks to Shlomi for the reports, the effort and for providing an Amazon VM to test this. I wish more bug reporters were like you. Reported-by: Shlomi Matichin Provided-test-env: Shlomi Matichin Investigated-with: Andrei Vagin Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/infect.c | 22 ++++++++++++++++------ compel/include/uapi/infect.h | 2 ++ criu/parasite-syscall.c | 2 ++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index d95299b3b..85c93ad8a 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -251,7 +251,7 @@ static int get_task_fpregs(pid_t pid, user_fpregs_struct_t *xsave) } int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, - void *arg, __maybe_unused unsigned long flags) + void *arg, unsigned long flags) { user_fpregs_struct_t xsave = { }, *xs = NULL; int ret = -1; @@ -286,14 +286,24 @@ int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, pr_info("Dumping GP/FPU registers for %d\n", pid); - if (compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) { - if (get_task_xsave(pid, &xsave)) - goto err; + if (!compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) { + ret = get_task_fpregs(pid, &xsave); + } else if (unlikely(flags & INFECT_X86_PTRACE_MXCSR_BUG)) { + /* + * get_task_fpregs() will fill FP state, + * get_task_xsave() will overwrite rightly sse/mmx/etc + */ + pr_warn("Skylake xsave fpu bug workaround used\n"); + ret = get_task_fpregs(pid, &xsave); + if (!ret) + ret = get_task_xsave(pid, &xsave); } else { - if (get_task_fpregs(pid, &xsave)) - goto err; + ret = get_task_xsave(pid, &xsave); } + if (ret) + goto err; + xs = &xsave; out: ret = save(arg, regs, xs); diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index d9bf069b2..e0ff233e7 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -127,6 +127,8 @@ extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *); #define INFECT_FAIL_CONNECT 0x2 /* make parasite connect() fail */ #define INFECT_NO_BREAKPOINTS 0x4 /* no breakpoints in pie tracking */ #define INFECT_COMPATIBLE 0x8 /* can run parasite inside compat tasks */ +/* Workaround for ptrace bug on Skylake CPUs with kernels older than v4.14 */ +#define INFECT_X86_PTRACE_MXCSR_BUG 0x10 /* * There are several ways to describe a blob to compel diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 1fd9142e5..267d3fa07 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -511,6 +511,8 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ictx->flags |= INFECT_NO_BREAKPOINTS; if (kdat.compat_cr) ictx->flags |= INFECT_COMPATIBLE; + if (kdat.x86_has_ptrace_fpu_xsave_bug) + ictx->flags |= INFECT_X86_PTRACE_MXCSR_BUG; ictx->log_fd = log_get_fd(); From d302f600a36b269148807a191ea071d98634bfe9 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 7 Feb 2018 12:48:52 +0000 Subject: [PATCH 1331/4375] compel: Cleanup INFECT_* definitions Ugh, I've spent 25 mins at 4 A.M. to figure out why the tests are failing. And the reason is stupied me, who defined a new flag after 0x8 as 0x16, not as 0x10. Simplify those definitions for such simple-minded living creatures like Dima. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index e0ff233e7..f087f21f3 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -123,12 +123,16 @@ struct infect_ctx { extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *); -#define INFECT_NO_MEMFD 0x1 /* don't use memfd() */ -#define INFECT_FAIL_CONNECT 0x2 /* make parasite connect() fail */ -#define INFECT_NO_BREAKPOINTS 0x4 /* no breakpoints in pie tracking */ -#define INFECT_COMPATIBLE 0x8 /* can run parasite inside compat tasks */ +/* Don't use memfd() */ +#define INFECT_NO_MEMFD (1UL << 0) +/* Make parasite connect() fail */ +#define INFECT_FAIL_CONNECT (1UL << 1) +/* No breakpoints in pie tracking */ +#define INFECT_NO_BREAKPOINTS (1UL << 2) +/* Can run parasite inside compat tasks */ +#define INFECT_COMPATIBLE (1UL << 3) /* Workaround for ptrace bug on Skylake CPUs with kernels older than v4.14 */ -#define INFECT_X86_PTRACE_MXCSR_BUG 0x10 +#define INFECT_X86_PTRACE_MXCSR_BUG (1UL << 4) /* * There are several ways to describe a blob to compel From ba1b93d35767ab88564809a7e0730921337db9a5 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 7 Feb 2018 12:48:53 +0000 Subject: [PATCH 1332/4375] zdtm/x86: Add a mxcsr preserving fpu test It helped a bit to debug Skylake ptrace() bug, let's put it in. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/fpu02.c | 88 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 test/zdtm/static/fpu02.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index b6bf88db2..da2bf0f45 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -13,6 +13,7 @@ TST_NOFILE := \ zombie01 \ fpu00 \ fpu01 \ + fpu02 \ arm-neon00 \ futex \ futex-rl \ diff --git a/test/zdtm/static/fpu02.c b/test/zdtm/static/fpu02.c new file mode 100644 index 000000000..660fc7d59 --- /dev/null +++ b/test/zdtm/static/fpu02.c @@ -0,0 +1,88 @@ +#include +#include +#include + +#include + +#include "zdtmtst.h" + +#if defined(__i386__) || defined(__x86_64__) + +#include "cpuid.h" + +const char *test_doc = "Test preserve of mxcsr in FPU"; +const char *test_author = "Dmitry Safonov <0x7f454c46@gmail.com>"; + +static int verify_cpu(void) +{ + unsigned int eax, ebx, ecx, edx; + + /* Do we have xsave? */ + cpuid(1, &eax, &ebx, &ecx, &edx); + if (!(ecx & (1u << 27))) + return -1; + + /* Is YMM here? */ + cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx); + if ((eax & (0x4)) != 0x4) + return -1; + + return 0; +} + +#define __aligned __attribute__((aligned(64))) + +static int fpu_test(void) +{ + uint32_t before, after; + + asm volatile("stmxcsr %0\n" + : "+m"(before)); + + test_daemon(); + test_waitsig(); + + asm volatile("stmxcsr %0\n" + : "+m"(after)); + + test_msg("before: %x, after: %x\n", before, after); + + return (before != after); +} + +static int bare_run(void) +{ + test_msg("Your cpu doesn't support ymm registers, skipping\n"); + + test_daemon(); + test_waitsig(); + + return 0; +} + +int main(int argc, char *argv[]) +{ + int ret = 0; + + test_init(argc, argv); + + ret = verify_cpu() ? bare_run() : fpu_test(); + + if (!ret) + pass(); + else + fail(); + + return 0; +} + +#else + +int main(int argc, char *argv[]) +{ + test_init(argc, argv); + skip("Unsupported arch"); + return 0; +} + +#endif From 7ca30056545f52613f3d5a9edcc3bf2236b85757 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 7 Feb 2018 12:48:54 +0000 Subject: [PATCH 1333/4375] compel: Explicitely align all containers of i387_fxsave_struct As it's aligned to 16, all structures that contain it should be also aligned to 16. In the kernel there is no such align as there two separate definitions of i387_fxsave_struct: one for ia32 and another for x86_64. Fixes newly introduced align warning in gcc-8.1: In file included from compel/include/uapi/compel/asm/sigframe.h:7, from compel/plugins/std/infect.c:13: compel/include/uapi/compel/asm/fpu.h:89:1: error: alignment 1 of 'struct xsave_struct_ia32' is less than 16 [-Werror=packed-not-aligned] } __packed; ^ It doesn't change the current align of the struct, as containing structures are __packed and it aligned already *by fact*. It only affects the function users of the struct's local variables: now they lay aligned on a stack. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/include/uapi/asm/fpu.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h index f60112b9b..dca280bdb 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h @@ -8,6 +8,7 @@ #include #define FP_MIN_ALIGN_BYTES 64 +#define FXSAVE_ALIGN_BYTES 16 #define FP_XSTATE_MAGIC1 0x46505853U #define FP_XSTATE_MAGIC2 0x46505845U @@ -61,7 +62,7 @@ struct i387_fxsave_struct { uint32_t sw_reserved[12]; }; -} __aligned(16); +} __aligned(FXSAVE_ALIGN_BYTES); struct xsave_hdr_struct { uint64_t xstate_bv; @@ -86,7 +87,7 @@ struct xsave_struct_ia32 { struct i387_fxsave_struct i387; struct xsave_hdr_struct xsave_hdr; struct ymmh_struct ymmh; -} __packed; +} __aligned(FXSAVE_ALIGN_BYTES) __packed; typedef struct { /* @@ -123,8 +124,8 @@ typedef struct { union { struct xsave_struct_ia32 xsave; uint8_t __pad[sizeof(struct xsave_struct) + FP_XSTATE_MAGIC2_SIZE]; - } __packed; -} __packed fpu_state_ia32_t; + } __aligned(FXSAVE_ALIGN_BYTES) __packed; +} __aligned(FXSAVE_ALIGN_BYTES) __packed fpu_state_ia32_t; /* * This one is used in restorer. From 7f5e8649b08d860701b37753ff5c716005317387 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 4 Feb 2018 08:22:58 +0300 Subject: [PATCH 1334/4375] zdtm: fix gcc-8 warnings fs.c:78:5: error: 'strncpy' specified bound 64 equals destination size [-Werror=stringop-truncation] strncpy(m->fsname, fsname, sizeof(m->fsname)); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Andrei Vagin --- test/zdtm/lib/fs.c | 3 ++- test/zdtm/lib/zdtmtst.h | 10 +++++++++ test/zdtm/static/binfmt_misc.c | 2 +- test/zdtm/static/cgroup01.c | 3 ++- test/zdtm/static/cgroup02.c | 8 +++---- test/zdtm/static/cgroup03.c | 4 ++-- test/zdtm/static/cgroup04.c | 8 +++---- test/zdtm/static/cgroup_stray.c | 4 ++-- test/zdtm/static/cgroupns.c | 10 ++++----- test/zdtm/static/del_standalone_un.c | 2 +- test/zdtm/static/mntns_overmount.c | 4 ++-- test/zdtm/static/mntns_root_bind.c | 14 ++++++------- test/zdtm/static/mount_paths.c | 6 +++--- .../static/overmount_with_shared_parent.c | 10 ++++----- test/zdtm/static/shared_mount_propagation.c | 21 +++++++++---------- test/zdtm/static/sk-unix-rel.c | 7 +++++-- test/zdtm/static/sk-unix-unconn.c | 6 +++++- test/zdtm/static/sockets00.c | 7 +++++-- test/zdtm/static/sockets03.c | 7 +++++-- test/zdtm/static/tempfs.c | 6 +++--- 20 files changed, 83 insertions(+), 59 deletions(-) diff --git a/test/zdtm/lib/fs.c b/test/zdtm/lib/fs.c index 37f5e4191..0decfc37b 100644 --- a/test/zdtm/lib/fs.c +++ b/test/zdtm/lib/fs.c @@ -75,7 +75,8 @@ mnt_info_t *get_cwd_mnt_info(void) strncpy(m->root, root, sizeof(m->root)); strncpy(m->mountpoint, mountpoint, sizeof(m->mountpoint)); - strncpy(m->fsname, fsname, sizeof(m->fsname)); + strncpy(m->fsname, fsname, sizeof(m->fsname) - 1); + m->fsname[sizeof(m->fsname) - 1] = 0; } } diff --git a/test/zdtm/lib/zdtmtst.h b/test/zdtm/lib/zdtmtst.h index cd8e9592e..dbe825cbc 100644 --- a/test/zdtm/lib/zdtmtst.h +++ b/test/zdtm/lib/zdtmtst.h @@ -4,6 +4,7 @@ #include #include #include +#include #define INPROGRESS ".inprogress" @@ -154,4 +155,13 @@ extern int tcp_init_server_with_opts(int family, int *port, struct zdtm_tcp_opts extern pid_t sys_clone_unified(unsigned long flags, void *child_stack, void *parent_tid, void *child_tid, unsigned long newtls); +#define ssprintf(s, fmt, ...) ({ \ + int ___ret; \ + \ + ___ret = snprintf(s, sizeof(s), fmt, ##__VA_ARGS__); \ + if (___ret >= sizeof(s)) \ + abort(); \ + ___ret; \ +}) + #endif /* _VIMITESU_H_ */ diff --git a/test/zdtm/static/binfmt_misc.c b/test/zdtm/static/binfmt_misc.c index 26f8b8192..316c4b667 100644 --- a/test/zdtm/static/binfmt_misc.c +++ b/test/zdtm/static/binfmt_misc.c @@ -143,7 +143,7 @@ int main(int argc, char **argv) close(fd); /* Disable one of the entries */ - sprintf(path, "%s/%s", dirname, NAME[0]); + ssprintf(path, "%s/%s", dirname, NAME[0]); fd = open(path, O_WRONLY); if (fd < 0 || write(fd, "0", 1) != 1) { fail("Can't disable %s\n", path); diff --git a/test/zdtm/static/cgroup01.c b/test/zdtm/static/cgroup01.c index 384f86053..cf54c1d9e 100644 --- a/test/zdtm/static/cgroup01.c +++ b/test/zdtm/static/cgroup01.c @@ -83,7 +83,8 @@ int main(int argc, char **argv) test_msg("found cgroup at %s\n", aux); for (i = 0; i < 2; i++) { - sprintf(paux, "%s/%s/%s.%d", aux, subname, empty, i); + ssprintf(paux, "%s/%s/%s.%d", aux, subname, empty, i); + if (stat(paux, &st)) { fail("couldn't stat %s\n", paux); ret = -1; diff --git a/test/zdtm/static/cgroup02.c b/test/zdtm/static/cgroup02.c index ac6e9c0fd..6de22226f 100644 --- a/test/zdtm/static/cgroup02.c +++ b/test/zdtm/static/cgroup02.c @@ -39,14 +39,14 @@ int mount_and_add(const char *controller, const char *prefix, const char *path) goto err_rd; } - sprintf(paux, "%s/%s", subdir, prefix); + ssprintf(paux, "%s/%s", subdir, prefix); mkdir(paux, 0600); - sprintf(paux, "%s/%s/%s", subdir, prefix, path); + ssprintf(paux, "%s/%s/%s", subdir, prefix, path); mkdir(paux, 0600); l = sprintf(aux, "%d", getpid()); - sprintf(paux, "%s/%s/%s/tasks", subdir, prefix, path); + ssprintf(paux, "%s/%s/%s/tasks", subdir, prefix, path); cgfd = open(paux, O_WRONLY); if (cgfd < 0) { @@ -78,7 +78,7 @@ bool test_exists(char *mountinfo_line, char *path) sscanf(mountinfo_line, "%*d %*d %*d:%*d %*s %s", aux); test_msg("found cgroup at %s\n", aux); - sprintf(paux, "%s/%s", aux, path); + ssprintf(paux, "%s/%s", aux, path); if (stat(paux, &st)) { return false; } diff --git a/test/zdtm/static/cgroup03.c b/test/zdtm/static/cgroup03.c index c6c4938ba..0b5db2345 100644 --- a/test/zdtm/static/cgroup03.c +++ b/test/zdtm/static/cgroup03.c @@ -38,11 +38,11 @@ int mount_and_add(const char *controller, const char *path) goto err_rd; } - sprintf(paux, "%s/%s", subdir, path); + ssprintf(paux, "%s/%s", subdir, path); mkdir(paux, 0600); l = sprintf(aux, "%d", getpid()); - sprintf(paux, "%s/%s/tasks", subdir, path); + ssprintf(paux, "%s/%s/tasks", subdir, path); cgfd = open(paux, O_WRONLY); if (cgfd < 0) { diff --git a/test/zdtm/static/cgroup04.c b/test/zdtm/static/cgroup04.c index 6998358ef..8ec0cff37 100644 --- a/test/zdtm/static/cgroup04.c +++ b/test/zdtm/static/cgroup04.c @@ -59,19 +59,19 @@ int mount_and_add(const char *controller, const char *path, const char *prop, co goto err_rd; } - sprintf(paux, "%s/%s", subdir, path); + ssprintf(paux, "%s/%s", subdir, path); mkdir(paux, 0600); - sprintf(paux, "%s/%s/%s", subdir, path, prop); + ssprintf(paux, "%s/%s/%s", subdir, path, prop); if (write_value(paux, value) < 0) goto err_rs; sprintf(aux, "%d", getpid()); - sprintf(paux, "%s/%s/tasks", subdir, path); + ssprintf(paux, "%s/%s/tasks", subdir, path); if (write_value(paux, aux) < 0) goto err_rs; - sprintf(paux, "%s/%s/special_prop_check", subdir, path); + ssprintf(paux, "%s/%s/special_prop_check", subdir, path); mkdir(paux, 0600); return 0; diff --git a/test/zdtm/static/cgroup_stray.c b/test/zdtm/static/cgroup_stray.c index 235434ed2..16db9ba54 100644 --- a/test/zdtm/static/cgroup_stray.c +++ b/test/zdtm/static/cgroup_stray.c @@ -53,11 +53,11 @@ static int add_to_cg(const char *controller, const char *path) int cgfd, l; sprintf(subdir, "%s/%s", dirname, controller); - sprintf(paux, "%s/%s", subdir, path); + ssprintf(paux, "%s/%s", subdir, path); mkdir(paux, 0600); l = sprintf(aux, "%d", getpid()); - sprintf(paux, "%s/%s/tasks", subdir, path); + ssprintf(paux, "%s/%s/tasks", subdir, path); cgfd = open(paux, O_WRONLY); if (cgfd < 0) { diff --git a/test/zdtm/static/cgroupns.c b/test/zdtm/static/cgroupns.c index cee704353..7bb0b1fda 100644 --- a/test/zdtm/static/cgroupns.c +++ b/test/zdtm/static/cgroupns.c @@ -34,23 +34,23 @@ int mount_and_add(const char *controller, const char *path) return -1; } - sprintf(subdir, "%s/%s", dirname, controller); + ssprintf(subdir, "%s/%s", dirname, controller); if (mkdir(subdir, 0700) < 0) { pr_perror("Can't make dir"); return -1; } - sprintf(aux, "none,name=%s", controller); + ssprintf(aux, "none,name=%s", controller); if (mount("none", subdir, "cgroup", 0, aux)) { pr_perror("Can't mount cgroups"); goto err_rd; } - sprintf(paux, "%s/%s", subdir, path); + ssprintf(paux, "%s/%s", subdir, path); mkdir(paux, 0600); - l = sprintf(aux, "%d", getpid()); - sprintf(paux, "%s/%s/tasks", subdir, path); + l = ssprintf(aux, "%d", getpid()); + ssprintf(paux, "%s/%s/tasks", subdir, path); cgfd = open(paux, O_WRONLY); if (cgfd < 0) { diff --git a/test/zdtm/static/del_standalone_un.c b/test/zdtm/static/del_standalone_un.c index f62edb2ed..d8200068b 100644 --- a/test/zdtm/static/del_standalone_un.c +++ b/test/zdtm/static/del_standalone_un.c @@ -25,7 +25,7 @@ static int fill_sock_name(struct sockaddr_un *name, const char *filename) return -1; name->sun_family = AF_LOCAL; - sprintf(name->sun_path, "%s/%s", cwd, filename); + ssprintf(name->sun_path, "%s/%s", cwd, filename); return 0; } diff --git a/test/zdtm/static/mntns_overmount.c b/test/zdtm/static/mntns_overmount.c index aa297a055..ba23afca8 100644 --- a/test/zdtm/static/mntns_overmount.c +++ b/test/zdtm/static/mntns_overmount.c @@ -42,8 +42,8 @@ int main(int argc, char **argv) return 1; } - snprintf(f1, sizeof(f1), "%s/devices", d1); - snprintf(f2, sizeof(f2), "%s/devices", d2); + ssprintf(f1, "%s/devices", d1); + ssprintf(f2, "%s/devices", d2); if (mount("zdtm_d1", d1, "tmpfs", 0, NULL)) { pr_perror("mount"); diff --git a/test/zdtm/static/mntns_root_bind.c b/test/zdtm/static/mntns_root_bind.c index 3f15a2726..978143ec2 100644 --- a/test/zdtm/static/mntns_root_bind.c +++ b/test/zdtm/static/mntns_root_bind.c @@ -38,14 +38,14 @@ int main(int argc, char **argv) mount(NULL, "/", NULL, MS_SHARED, NULL); - snprintf(subdir1, sizeof(subdir1), "%s/subdir1", dirname); - snprintf(path, sizeof(path), "%s/test", subdir1); - snprintf(bpath, sizeof(bpath), "%s/test.bind", subdir1); - snprintf(spath, sizeof(spath), "%s/test/sub", subdir1); - snprintf(bspath, sizeof(bspath), "%s/test.bind/sub", subdir1); + ssprintf(subdir1, "%s/subdir1", dirname); + ssprintf(path, "%s/test", subdir1); + ssprintf(bpath, "%s/test.bind", subdir1); + ssprintf(spath, "%s/test/sub", subdir1); + ssprintf(bspath, "%s/test.bind/sub", subdir1); - snprintf(subdir2, sizeof(subdir2), "%s/subdir2", dirname); - snprintf(bsubdir2, sizeof(bsubdir2), "%s/bsubdir2", dirname); + ssprintf(subdir2, "%s/subdir2", dirname); + ssprintf(bsubdir2, "%s/bsubdir2", dirname); if (mkdir(dirname, 0700) || mkdir(subdir1, 0777) || diff --git a/test/zdtm/static/mount_paths.c b/test/zdtm/static/mount_paths.c index a42b0eb3d..ee05adb46 100644 --- a/test/zdtm/static/mount_paths.c +++ b/test/zdtm/static/mount_paths.c @@ -19,13 +19,13 @@ TEST_OPTION(dirname, string, "directory name", 1); int main(int argc, char **argv) { int ret = 1; - char buf[1024], test_dir[PATH_MAX], fname[PATH_MAX]; + char test_dir[PATH_MAX], fname[PATH_MAX]; test_init(argc, argv); mkdir(dirname, 0700); - snprintf(test_dir, sizeof(test_dir), "%s/%s", dirname, TEST_DIR); + ssprintf(test_dir, "%s/%s", dirname, TEST_DIR); mkdir(test_dir, 0700); if (mount("", test_dir, "tmpfs", 0, NULL)) { @@ -33,7 +33,7 @@ int main(int argc, char **argv) return 1; } - snprintf(fname, sizeof(buf), "%s/\\\t \\\\ \\tt", test_dir); + ssprintf(fname, "%s/\\\t \\\\ \\tt", test_dir); if (mkdir(fname, 0700)) { pr_perror("mkdir"); return 1; diff --git a/test/zdtm/static/overmount_with_shared_parent.c b/test/zdtm/static/overmount_with_shared_parent.c index 8261fb969..1fcb5a5cb 100644 --- a/test/zdtm/static/overmount_with_shared_parent.c +++ b/test/zdtm/static/overmount_with_shared_parent.c @@ -29,13 +29,13 @@ int main(int argc, char **argv) return 1; } - snprintf(dir_a, sizeof(dir_a), "%s/a", dirname); - snprintf(dir_d, sizeof(dir_d), "%s/d", dirname); + ssprintf(dir_a, "%s/a", dirname); + ssprintf(dir_d, "%s/d", dirname); mkdir(dir_a, 0700); mkdir(dir_d, 0700); - snprintf(dir_b, sizeof(dir_a), "%s/b", dir_a); - snprintf(dir_c, sizeof(dir_c), "%s/c", dir_b); + ssprintf(dir_b, "%s/b", dir_a); + ssprintf(dir_c, "%s/c", dir_b); mkdir(dir_b, 0700); mkdir(dir_c, 0700); @@ -44,7 +44,7 @@ int main(int argc, char **argv) return 1; } - snprintf(dir_a_c, sizeof(dir_a_c), "%s/c", dir_a); + ssprintf(dir_a_c, "%s/c", dir_a); if (mount(dir_d, dir_a_c, NULL, MS_BIND, NULL)) { pr_perror("Unable to bind mount %s to %s", dir_d, dir_a_c); diff --git a/test/zdtm/static/shared_mount_propagation.c b/test/zdtm/static/shared_mount_propagation.c index 9fe58487f..4e81b9ec6 100644 --- a/test/zdtm/static/shared_mount_propagation.c +++ b/test/zdtm/static/shared_mount_propagation.c @@ -35,17 +35,17 @@ int main(int argc, char **argv) return 1; } - snprintf(dir_a, sizeof(dir_a), "%s/a", dirname); - snprintf(dir_d, sizeof(dir_d), "%s/d", dirname); - snprintf(dir_e, sizeof(dir_e), "%s/e", dirname); - snprintf(dir_f, sizeof(dir_f), "%s/f", dirname); + ssprintf(dir_a, "%s/a", dirname); + ssprintf(dir_d, "%s/d", dirname); + ssprintf(dir_e, "%s/e", dirname); + ssprintf(dir_f, "%s/f", dirname); mkdir(dir_a, 0700); mkdir(dir_d, 0700); mkdir(dir_e, 0700); mkdir(dir_f, 0700); - snprintf(dir_b, sizeof(dir_a), "%s/b", dir_a); - snprintf(dir_c, sizeof(dir_c), "%s/c", dir_b); + ssprintf(dir_b, "%s/b", dir_a); + ssprintf(dir_c, "%s/c", dir_b); mkdir(dir_b, 0700); mkdir(dir_c, 0700); @@ -64,7 +64,7 @@ int main(int argc, char **argv) return 1; } - snprintf(test_file, sizeof(test_file), "%s/file", dir_f); + ssprintf(test_file, "%s/file", dir_f); fd = open(test_file, O_CREAT | O_WRONLY | O_EXCL, 0600); if (fd < 0) { pr_perror("Unable to open %s", test_file); @@ -75,10 +75,9 @@ int main(int argc, char **argv) test_daemon(); test_waitsig(); - snprintf(test_bind_file1, sizeof(test_bind_file1), "%s/file", dir_c); - snprintf(test_bind_file2, sizeof(test_bind_file2), "%s/b/c/file", dir_d); - snprintf(test_bind_file3, sizeof(test_bind_file3), "%s/c/file", dir_e); - + ssprintf(test_bind_file1, "%s/file", dir_c); + ssprintf(test_bind_file2, "%s/b/c/file", dir_d); + ssprintf(test_bind_file3, "%s/c/file", dir_e); if (access(test_file, F_OK)) { pr_perror("%s doesn't exist", test_file); diff --git a/test/zdtm/static/sk-unix-rel.c b/test/zdtm/static/sk-unix-rel.c index 4f0b186d1..5b3e85289 100644 --- a/test/zdtm/static/sk-unix-rel.c +++ b/test/zdtm/static/sk-unix-rel.c @@ -48,8 +48,11 @@ int main(int argc, char *argv[]) unlink(path); addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, filename, sizeof(addr.sun_path)); - addrlen = sizeof(addr.sun_family) + strlen(filename); + addrlen = strlen(filename); + if (addrlen > sizeof(addr.sun_path)) + return 1; + memcpy(addr.sun_path, filename, addrlen); + addrlen += sizeof(addr.sun_family); sock[0] = socket(AF_UNIX, SOCK_STREAM, 0); sock[1] = socket(AF_UNIX, SOCK_STREAM, 0); diff --git a/test/zdtm/static/sk-unix-unconn.c b/test/zdtm/static/sk-unix-unconn.c index abf59e39b..72d1348a8 100644 --- a/test/zdtm/static/sk-unix-unconn.c +++ b/test/zdtm/static/sk-unix-unconn.c @@ -33,8 +33,12 @@ int main(int argc, char ** argv) len = snprintf(path, sizeof(path), "X/zdtm-%s-%d/X", argv[0], getpid()); + if (len >= sizeof(addr.sun_path)) { + pr_err("%s\n", path); + return 1; + } addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, path, sizeof(addr.sun_path)); + memcpy(addr.sun_path, path, len); addrlen = sizeof(addr.sun_family) + len; addr.sun_path[0] = 0; addr.sun_path[len - 1] = 0; diff --git a/test/zdtm/static/sockets00.c b/test/zdtm/static/sockets00.c index ab5d2e450..41c64c717 100644 --- a/test/zdtm/static/sockets00.c +++ b/test/zdtm/static/sockets00.c @@ -52,8 +52,11 @@ int main(int argc, char *argv[]) unlink(path); addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, path, sizeof(addr.sun_path)); - addrlen = sizeof(addr.sun_family) + strlen(path); + addrlen = strlen(path); + if (addrlen >= sizeof(addr.sun_path)) + return 1; + memcpy(addr.sun_path, path, addrlen); + addrlen += sizeof(addr.sun_family); ssk_icon[0] = socket(AF_UNIX, SOCK_STREAM, 0); ssk_icon[1] = socket(AF_UNIX, SOCK_STREAM, 0); diff --git a/test/zdtm/static/sockets03.c b/test/zdtm/static/sockets03.c index f62f565c0..e4c647d4c 100644 --- a/test/zdtm/static/sockets03.c +++ b/test/zdtm/static/sockets03.c @@ -46,8 +46,11 @@ int main(int argc, char *argv[]) unlink(path); addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, path, sizeof(addr.sun_path)); - addrlen = sizeof(addr.sun_family) + strlen(path); + addrlen = strlen(path); + if (addrlen >= sizeof(addr.sun_path)) + return 1; + memcpy(addr.sun_path, path, addrlen); + addrlen += sizeof(addr.sun_family); sk[0] = socket(AF_UNIX, SOCK_STREAM, 0); sk[1] = socket(AF_UNIX, SOCK_STREAM, 0); diff --git a/test/zdtm/static/tempfs.c b/test/zdtm/static/tempfs.c index 66c51a5eb..8a103be6d 100644 --- a/test/zdtm/static/tempfs.c +++ b/test/zdtm/static/tempfs.c @@ -30,7 +30,7 @@ int main(int argc, char **argv) return 1; } - snprintf(fname, sizeof(buf), "%s/test.file", dirname); + ssprintf(fname, "%s/test.file", dirname); fdo = open(fname, O_RDWR | O_CREAT, 0644); if (fdo < 0) { pr_perror("open failed"); @@ -42,10 +42,10 @@ int main(int argc, char **argv) goto err; } - snprintf(overmount, sizeof(buf), "%s/test", dirname); + ssprintf(overmount, "%s/test", dirname); mkdir(overmount, 0700); - snprintf(fname, sizeof(buf), "%s/test.file", overmount); + ssprintf(fname, "%s/test.file", overmount); fd = open(fname, O_RDWR | O_CREAT, 0644); if (fd < 0) { pr_perror("open failed"); From 4130507209ed58ffff0c6c3c5dbd7a318a2a449e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 4 Feb 2018 08:22:59 +0300 Subject: [PATCH 1335/4375] criu: fix gcc-8 warnings criu/sk-packet.c:443:3: error: 'strncpy' output may be truncated copying 14 bytes from a string of length 15 strncpy(addr_spkt.sa_data, req.ifr_name, sa_data_size); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ criu/img-remote.c:383:3: error: 'strncpy' specified bound 4096 equals destination size strncpy(snapshot_id, li->snapshot_id, PATHLEN); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ criu/img-remote.c:384:3: error: 'strncpy' specified bound 4096 equals destination size strncpy(path, li->name, PATHLEN); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ criu/files.c:288:3: error: 'strncpy' output may be truncated copying 4095 bytes from a string of length 4096 strncpy(buf, link->name, PATH_MAX - 1); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ criu/sk-unix.c:239:36: error: '/' directive output may be truncated writing 1 byte into a region of size between 0 and 4095 snprintf(path, sizeof(path), ".%s/%s", dir, sk->name); ^ criu/sk-unix.c:239:3: note: 'snprintf' output 3 or more bytes (assuming 4098) into a destination of size 4096 snprintf(path, sizeof(path), ".%s/%s", dir, sk->name); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ criu/mount.c:2563:3: error: 'strncpy' specified bound 4096 equals destination size strncpy(path, m->mountpoint, PATH_MAX); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ criu/cr-restore.c:3647:2: error: 'strncpy' specified bound 16 equals destination size strncpy(task_args->comm, core->tc->comm, sizeof(task_args->comm)); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 3 ++- criu/files.c | 3 ++- criu/include/files.h | 2 +- criu/mount.c | 3 ++- criu/sk-packet.c | 2 +- criu/sk-unix.c | 5 ++++- lib/c/criu.c | 11 +++++++++-- 7 files changed, 21 insertions(+), 8 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index db5a8cbf7..82ce90007 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3337,7 +3337,8 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns log_get_logstart(&task_args->logstart); task_args->sigchld_act = sigchld_act; - strncpy(task_args->comm, core->tc->comm, sizeof(task_args->comm)); + strncpy(task_args->comm, core->tc->comm, TASK_COMM_LEN - 1); + task_args->comm[TASK_COMM_LEN - 1] = 0; /* * Fill up per-thread data. diff --git a/criu/files.c b/criu/files.c index 18fa4dab6..ac0d1715e 100644 --- a/criu/files.c +++ b/criu/files.c @@ -284,7 +284,8 @@ static int fixup_overlayfs(struct fd_parms *p, struct fd_link *link) char buf[PATH_MAX]; int n; - strncpy(buf, link->name, PATH_MAX - 1); + strncpy(buf, link->name, PATH_MAX); + buf[PATH_MAX - 1] = 0; n = snprintf(link->name, PATH_MAX, "%s/%s", m->mountpoint, buf + 2); if (n >= PATH_MAX) { pr_err("Not enough space to replace %s\n", buf); diff --git a/criu/include/files.h b/criu/include/files.h index e69022d41..945c7b4fb 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -25,7 +25,7 @@ struct fd_link { union { /* Link info for generic file (path) */ struct { - char name[PATH_MAX + 1]; + char name[PATH_MAX]; size_t len; }; diff --git a/criu/mount.c b/criu/mount.c index a291934fa..0a8406c80 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2560,7 +2560,8 @@ static int fixup_remap_mounts() char path[PATH_MAX]; int len; - strncpy(path, m->mountpoint, PATH_MAX); + strncpy(path, m->mountpoint, PATH_MAX - 1); + path[PATH_MAX - 1] = 0; len = print_ns_root(m->nsid, 0, path, PATH_MAX); path[len] = '/'; diff --git a/criu/sk-packet.c b/criu/sk-packet.c index ed4cfeb26..796aa6e83 100644 --- a/criu/sk-packet.c +++ b/criu/sk-packet.c @@ -440,7 +440,7 @@ static int open_packet_sk_spkt(PacketSockEntry *pse, int *new_fd) goto err; } - strncpy(addr_spkt.sa_data, req.ifr_name, sa_data_size); + memcpy(addr_spkt.sa_data, req.ifr_name, sa_data_size); addr_spkt.sa_data[sa_data_size - 1] = 0; if (bind(sk, &addr_spkt, sizeof(addr_spkt)) < 0) { diff --git a/criu/sk-unix.c b/criu/sk-unix.c index fb7659c99..604206585 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -238,7 +238,10 @@ static int resolve_rel_name(struct unix_sk_desc *sk, const struct fd_parms *p) } dir[ret] = 0; - snprintf(path, sizeof(path), ".%s/%s", dir, sk->name); + if (snprintf(path, sizeof(path), ".%s/%s", dir, sk->name) >= sizeof(path)) { + pr_err("The path .%s/%s is too long", dir, sk->name); + goto err; + } if (fstatat(mntns_root, path, &st, 0)) { if (errno == ENOENT) continue; diff --git a/lib/c/criu.c b/lib/c/criu.c index 08806c6ea..931d691ec 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -1075,9 +1075,16 @@ static int criu_connect(criu_opts *opts, bool d) memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_LOCAL; - strncpy(addr.sun_path, opts->service_address, sizeof(addr.sun_path)); + addr_len = strlen(opts->service_address); + if (addr_len >= sizeof(addr.sun_path)) { + fprintf(stderr, "The service address %s is too long", + opts->service_address); + close(fd); + return -1; + } + memcpy(addr.sun_path, opts->service_address, addr_len); - addr_len = strlen(opts->service_address) + sizeof(addr.sun_family); + addr_len += sizeof(addr.sun_family); ret = connect(fd, (struct sockaddr *) &addr, addr_len); if (ret < 0) { From 8d98d86467fe27060c3ac704c9ac1e4038f207f8 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov <0x7f454c46@gmail.com> Date: Wed, 14 Feb 2018 01:41:19 +0000 Subject: [PATCH 1336/4375] zdtm/fpu02: Don't run the test on !x86 platforms Fixes: commit 925451c12b2e ("zdtm/x86: Add a mxcsr preserving fpu test") Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- test/zdtm/static/fpu02.desc | 1 + 1 file changed, 1 insertion(+) create mode 100644 test/zdtm/static/fpu02.desc diff --git a/test/zdtm/static/fpu02.desc b/test/zdtm/static/fpu02.desc new file mode 100644 index 000000000..d2f501de2 --- /dev/null +++ b/test/zdtm/static/fpu02.desc @@ -0,0 +1 @@ +{'arch': 'x86_64'} From a91b2e90a7ba7e8690c8abbfdc4b2fba704c32df Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 11 Feb 2018 15:53:15 +0200 Subject: [PATCH 1337/4375] page-pipe: do not allow pipe sharing between different PPB types Currently, if pipe is shared between lazy and non-lazy PPBs lazy migration fails because data that should be transfered on demand is spliced into the images. Preventing pipe sharing between PPBs of different type resolves this issue. In order to still minimize pipe fragmentation, we track the last pipe that was used for certain PPB type and re-use it for the PPB of the same type. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/include/page-pipe.h | 11 ++++++++++ criu/page-pipe.c | 43 ++++++++++++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h index 053ae3938..8fa1bfa5e 100644 --- a/criu/include/page-pipe.h +++ b/criu/include/page-pipe.h @@ -102,12 +102,23 @@ struct page_pipe_buf { struct list_head l; /* links into page_pipe->bufs */ }; +/* + * Page pipe buffers with different flags cannot share the same pipe. + * We track the last ppb that was used for each type separately in the + * prev[] array in the struct page_pipe (below). + * Currently we have 2 types: the buffers that are always stored in + * the images and the buffers that are lazily migrated + */ +#define PP_PIPE_TYPES 2 + #define PP_HOLE_PARENT (1 << 0) struct page_pipe { unsigned int nr_pipes; /* how many page_pipe_bufs in there */ struct list_head bufs; /* list of bufs */ struct list_head free_bufs; /* list of bufs */ + struct page_pipe_buf *prev[PP_PIPE_TYPES]; /* last ppb of each type + for pipe sharing */ unsigned int nr_iovs; /* number of iovs */ unsigned int free_iov; /* first free iov */ struct iovec *iovs; /* iovs. They are provided into create_page_pipe diff --git a/criu/page-pipe.c b/criu/page-pipe.c index eb09882c7..c32b89332 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -10,6 +10,7 @@ #include "page-pipe.h" #include "fcntl.h" #include "stats.h" +#include "cr_options.h" /* can existing iov accumulate the page? */ static inline bool iov_grow_page(struct iovec *iov, unsigned long addr) @@ -63,8 +64,39 @@ static inline int ppb_resize_pipe(struct page_pipe_buf *ppb) return 0; } -static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp, struct page_pipe_buf *prev) +static struct page_pipe_buf *pp_prev_ppb(struct page_pipe *pp, + unsigned int ppb_flags) { + int type = 0; + + /* don't allow to reuse a pipe in the PP_CHUNK_MODE mode */ + if (pp->flags & PP_CHUNK_MODE) + return NULL; + + if (list_empty(&pp->bufs)) + return NULL; + + if (ppb_flags & PPB_LAZY && opts.lazy_pages) + type = 1; + + return pp->prev[type]; +} + +static void pp_update_prev_ppb(struct page_pipe *pp, struct page_pipe_buf *ppb, + unsigned int ppb_flags) +{ + int type = 0; + + if (ppb_flags & PPB_LAZY && opts.lazy_pages) + type = 1; + + pp->prev[type] = ppb; +} + +static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp, + unsigned int ppb_flags) +{ + struct page_pipe_buf *prev = pp_prev_ppb(pp, ppb_flags); struct page_pipe_buf *ppb; ppb = xmalloc(sizeof(*ppb)); @@ -94,6 +126,8 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp, struct page_pipe_bu list_add_tail(&ppb->l, &pp->bufs); + pp_update_prev_ppb(pp, ppb, ppb_flags); + return ppb; } @@ -119,7 +153,7 @@ static void ppb_init(struct page_pipe_buf *ppb, unsigned int pages_in, static int page_pipe_grow(struct page_pipe *pp, unsigned int flags) { - struct page_pipe_buf *ppb, *prev = NULL; + struct page_pipe_buf *ppb; struct iovec *free_iov; pr_debug("Will grow page pipe (iov off is %u)\n", pp->free_iov); @@ -133,10 +167,7 @@ static int page_pipe_grow(struct page_pipe *pp, unsigned int flags) if ((pp->flags & PP_CHUNK_MODE) && (pp->nr_pipes == NR_PIPES_PER_CHUNK)) return -EAGAIN; - /* don't allow to reuse a pipe in the PP_CHUNK_MODE mode */ - if (!(pp->flags & PP_CHUNK_MODE) && !list_empty(&pp->bufs)) - prev = list_entry(pp->bufs.prev, struct page_pipe_buf, l); - ppb = ppb_alloc(pp, prev); + ppb = ppb_alloc(pp, flags); if (!ppb) return -1; From 3f6145ad79c785ca53293f43c0fc4e9c752323ec Mon Sep 17 00:00:00 2001 From: Dmitry Safonov <0x7f454c46@gmail.com> Date: Sun, 11 Feb 2018 14:00:51 +0000 Subject: [PATCH 1338/4375] zdtm/cgroup_ifpriomap: Find cgroup's controller's name to mount I've also dropped `noauto' in this patch, reverting the commit be98273cf137 ("zdtm: mark static/cgroup_ifpriomap as noauto") Don't see any sense to separate it as another patch. Fixes: #383 Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- test/zdtm/static/cgroup_ifpriomap.c | 96 ++++++++++++++++++++++++-- test/zdtm/static/cgroup_ifpriomap.desc | 2 +- test/zdtm/static/cgroup_ifpriomap.hook | 9 ++- 3 files changed, 101 insertions(+), 6 deletions(-) diff --git a/test/zdtm/static/cgroup_ifpriomap.c b/test/zdtm/static/cgroup_ifpriomap.c index d14508060..ac186eaf0 100644 --- a/test/zdtm/static/cgroup_ifpriomap.c +++ b/test/zdtm/static/cgroup_ifpriomap.c @@ -42,12 +42,12 @@ static int mount_cg(const char *controller) pr_perror("Can't make dir"); return -1; } - if (mkdir(mnt_point, 0700) < 0) { + if (mkdir(mnt_point, 0700) < 0 && errno != EEXIST) { pr_perror("Can't make dir `%s'", mnt_point); return -1; } if (mount("none", mnt_point, "cgroup", 0, controller)) { - pr_perror("Can't mount cgroups"); + pr_perror("Can't mount `%s' cgroup", controller); goto err_rm; } if (mkdir(subdir, 0700) < 0 && errno != EEXIST) { @@ -224,20 +224,107 @@ static int compare_maps(void) return 0; } +static ssize_t parse_cgroup_line(FILE *fcgroup, size_t *buf_sz, char **buf) +{ + ssize_t line_sz; + + /* Reading cgroup mount nr */ + errno = 0; + line_sz = getdelim(buf, buf_sz, ':', fcgroup); + if (errno) { + pr_perror("failed to read from file"); + return -1; + } + + if (line_sz == -1) /* EOF */ + return 0; + + /* Reading mounted controller name */ + errno = 0; + line_sz = getdelim(buf, buf_sz, ':', fcgroup); + if (line_sz == -1) { /* no EOF here */ + pr_perror("failed to read from file"); + return -1; + } + + /* + * Reading the rest of the line. + * It's zdtm's test, no need to optimize = use fgetc() + */ + do { + int c = fgetc(fcgroup); + + if (c == '\n' || c == EOF) + break; + } while (true); + + return line_sz; +} + +/* + * Controller's name may differ depending on the kernel's config: + * `net_prio' if only CONFIG_CGROUP_NET_PRIO is set + * `net_cls,net_prio' if also CONFIG_CGROUP_NET_CLASSID is set + */ +static int get_controller_name(char **name) +{ + FILE *self_cgroup = fopen("/proc/self/cgroup", "r"); + size_t buf_sz = 0; + int ret = -1; + + *name = NULL; + if (!self_cgroup) { + pr_perror("failed to open self/cgroup"); + return -1; + } + + do { + ssize_t len = parse_cgroup_line(self_cgroup, &buf_sz, name); + + if (len < 0) { + free(*name); + goto out_close; + } + + if (len == 0) /* EOF */ + break; + + if (strstr(*name, "net_prio")) { + /* erasing ':' delimiter */ + (*name)[len-1] = '\0'; + ret = 0; + goto out_close; + } + } while(1); + + /* self/cgroup has no mount for net_prio - try to map it */ + *name = "net_prio"; + ret = 0; + +out_close: + fclose(self_cgroup); + return ret; +} + int main(int argc, char **argv) { char subdir[PATH_MAX]; char path[PATH_MAX]; int ret = -1; + char *controller_name; srand(time(NULL)); test_init(argc, argv); - if (mount_cg("net_prio") < 0) + if (get_controller_name(&controller_name)) return -1; - sprintf(path, "%s/net_prio/%s/net_prio.ifpriomap", dirname, cgname); + if (mount_cg(controller_name) < 0) + return -1; + + sprintf(path, "%s/%s/%s/net_prio.ifpriomap", + dirname, controller_name, cgname); if (read_map(path, maps, PRIOMAPS_SZ)) goto out_umount; @@ -266,6 +353,7 @@ out_umount: sprintf(subdir, "%s/%s/%s", dirname, "net_prio", cgname); rmdir(subdir); umount_cg("net_prio"); + free(controller_name); return ret; } diff --git a/test/zdtm/static/cgroup_ifpriomap.desc b/test/zdtm/static/cgroup_ifpriomap.desc index 3bb68f00a..5fa9d5079 100644 --- a/test/zdtm/static/cgroup_ifpriomap.desc +++ b/test/zdtm/static/cgroup_ifpriomap.desc @@ -1 +1 @@ -{'flavor': 'h', 'flags': 'suid excl noauto', 'opts': '--manage-cgroups=full'} +{'flavor': 'h', 'flags': 'suid excl', 'opts': '--manage-cgroups=full'} diff --git a/test/zdtm/static/cgroup_ifpriomap.hook b/test/zdtm/static/cgroup_ifpriomap.hook index 692c5ebe2..926ffee0c 100755 --- a/test/zdtm/static/cgroup_ifpriomap.hook +++ b/test/zdtm/static/cgroup_ifpriomap.hook @@ -2,8 +2,15 @@ [ "$1" == "--clean" -o "$1" == "--pre-restore" ] || exit 0 +# Controller's name may differ depending on the kernel's config: +# `net_prio' if only CONFIG_CGROUP_NET_PRIO is set +# `net_cls,net_prio' if also CONFIG_CGROUP_NET_CLASSID is set +controller=$(sed -n '/net_prio/s/.*:\([^:]*net_prio[^:]*\):.*/\1/p' /proc/self/cgroup) + +echo "Controller's name '$controller'" + tname=$(mktemp -d cgclean.XXXXXX) -mount -t cgroup none $tname -o "net_prio" +mount -t cgroup foobar $tname -o "$controller" echo "Cleaning $tname" From 31d84043fffe5ecd64b2f3c873b9e48d1deda6b8 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov <0x7f454c46@gmail.com> Date: Sun, 11 Feb 2018 14:00:52 +0000 Subject: [PATCH 1339/4375] zdtm/cgroup_ifpriomap: Fix Coverity warning *** CID 185302: Null pointer dereferences (NULL_RETURNS) /test/zdtm/static/cgroup_ifpriomap.c: 107 in read_one_priomap() >>> Dereferencing a pointer that might be null "out->ifname" when calling "strncpy". There is also a warning about using rand(), but.. Not sure that we need to entangle everything just for pleasing Coverity: >>> CID 185301: Security best practices violations (DC.WEAK_CRYPTO) >>> "rand" should not be used for security related applications, as linear congruential algorithms are too easy to break. Leaving that as-is and marking in Coverity as WONTFIX. Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- test/zdtm/static/cgroup_ifpriomap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/zdtm/static/cgroup_ifpriomap.c b/test/zdtm/static/cgroup_ifpriomap.c index ac186eaf0..f043b365b 100644 --- a/test/zdtm/static/cgroup_ifpriomap.c +++ b/test/zdtm/static/cgroup_ifpriomap.c @@ -104,6 +104,11 @@ static int read_one_priomap(char *prop_line, struct ifpriomap_t *out) len = space - prop_line; out->ifname = malloc(len + 1); + if (!out->ifname) { + pr_perror("malloc() failed\n"); + return -1; + } + strncpy(out->ifname, prop_line, len); out->ifname[len] = '\0'; /* poor man's strlcpy() */ out->prio = (uint32_t)strtol(space + 1, NULL, 10); From 93b539378bf54f38fe1bdda9d3f2a7745938ae01 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 2 Feb 2018 11:41:01 +0300 Subject: [PATCH 1340/4375] criu: fix leaks detected by coverity scan part 2 *** CID 179043: (USE_AFTER_FREE) close bfd fd safe so that we won't have double close *** CID 179041: Resource leaks (RESOURCE_LEAK) don't forget to close fd on error Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/bfd.c | 2 +- criu/kerndat.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/bfd.c b/criu/bfd.c index 76ae56a31..1a1850780 100644 --- a/criu/bfd.c +++ b/criu/bfd.c @@ -91,7 +91,7 @@ static void buf_put(struct xbuf *xb) static int bfdopen(struct bfd *f, bool writable) { if (buf_get(&f->b)) { - close(f->fd); + close_safe(&f->fd); return -1; } diff --git a/criu/kerndat.c b/criu/kerndat.c index 3a3d9f66e..e0d0c7b52 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -769,6 +769,7 @@ static int kerndat_try_load_cache(void) ret = read(fd, &kdat, sizeof(kdat)); if (ret < 0) { pr_perror("Can't read kdat cache"); + close(fd); return -1; } From 5f94389c6bf46c00c4ac248bc2b2889ef5e954ae Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 6 Feb 2018 04:56:00 +0300 Subject: [PATCH 1341/4375] cgroups: don't leak memory on a error path CID 161693 (#1 of 1): Resource leak (RESOURCE_LEAK) 5. leaked_storage: Variable new going out of scope leaks the storage it points to. Signed-off-by: Andrei Vagin --- lib/c/criu.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/c/criu.c b/lib/c/criu.c index 931d691ec..832a54d10 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -771,17 +771,21 @@ int criu_local_add_cg_props_file(criu_opts *opts, char *path) int criu_local_add_cg_dump_controller(criu_opts *opts, char *name) { - char **new; + char **new, *ctrl_name; size_t nr; + ctrl_name = strdup(name); + if (!ctrl_name) + return -ENOMEM; + nr = opts->rpc->n_cgroup_dump_controller + 1; new = realloc(opts->rpc->cgroup_dump_controller, nr * sizeof(char *)); - if (!new) + if (!new) { + free(ctrl_name); return -ENOMEM; + } - new[opts->rpc->n_cgroup_dump_controller] = strdup(name); - if (!new[opts->rpc->n_cgroup_dump_controller]) - return -ENOMEM; + new[opts->rpc->n_cgroup_dump_controller] = ctrl_name; opts->rpc->n_cgroup_dump_controller = nr; opts->rpc->cgroup_dump_controller = new; From 7a5d310ddc3cace4bd311d2a5729b016161a9d95 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 6 Feb 2018 05:04:06 +0300 Subject: [PATCH 1342/4375] util: print all errors in a log CID 154076 (#1 of 1): Unchecked return value from library (CHECKED_RETURN) 1. check_return: Calling setsockopt(sk, 6, 1, &val, 4U) without checking return value. This library function may fail and return an error code. Signed-off-by: Andrei Vagin --- criu/util.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/criu/util.c b/criu/util.c index cc47d1778..6a5180c4c 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1143,13 +1143,15 @@ const char *ns_to_string(unsigned int ns) void tcp_cork(int sk, bool on) { int val = on ? 1 : 0; - setsockopt(sk, SOL_TCP, TCP_CORK, &val, sizeof(val)); + if (setsockopt(sk, SOL_TCP, TCP_CORK, &val, sizeof(val))) + pr_perror("Unable to restore TCP_CORK (%d)", val); } void tcp_nodelay(int sk, bool on) { int val = on ? 1 : 0; - setsockopt(sk, SOL_TCP, TCP_NODELAY, &val, sizeof(val)); + if (setsockopt(sk, SOL_TCP, TCP_NODELAY, &val, sizeof(val))) + pr_perror("Unable to restore TCP_NODELAY (%d)", val); } static inline void pr_xsym(unsigned char *data, size_t len, int pos) From 526f491a26390646139a1f021ed471175fa2f05e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 8 Feb 2018 20:49:22 +0300 Subject: [PATCH 1343/4375] soccr: don't leak memory on error paths CID 172198 (#1 of 1): Resource leak (RESOURCE_LEAK) 9. leaked_storage: Variable sk going out of scope leaks the storage it points to. Signed-off-by: Andrei Vagin --- criu/sk-tcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c index 427467195..f4dd13ecf 100644 --- a/criu/sk-tcp.c +++ b/criu/sk-tcp.c @@ -419,8 +419,10 @@ int restore_one_tcp(int fd, struct inet_sk_info *ii) if (!sk) return -1; - if (restore_tcp_conn_state(fd, sk, ii)) + if (restore_tcp_conn_state(fd, sk, ii)) { + libsoccr_release(sk); return -1; + } return 0; } From fd9f0aaa35618fd6c34a8b3b58b8667755a2c69c Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 8 Feb 2018 21:18:22 +0300 Subject: [PATCH 1344/4375] cgroup: print errors for umount and rmdir CID 155804 (#1 of 1): Unchecked return value (CHECKED_RETURN) 2. check_return: Calling umount2 without checking return value (as is done elsewhere 8 out of 9 times). Signed-off-by: Andrei Vagin --- criu/cgroup.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index b3478b8ac..51759786e 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -1163,8 +1163,10 @@ void fini_cgroup(void) return; close_service_fd(CGROUP_YARD); - umount2(cg_yard, MNT_DETACH); - rmdir(cg_yard); + if (umount2(cg_yard, MNT_DETACH)) + pr_perror("Unable to umount %s", cg_yard); + if (rmdir(cg_yard)) + pr_perror("Unable to remove %s", cg_yard); xfree(cg_yard); cg_yard = NULL; } From 8c87d345759f8a19ba899f98db5424cf0df34b21 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 8 Feb 2018 21:21:07 +0300 Subject: [PATCH 1345/4375] restore: print a error if ptrace() failed CID 85039 (#1 of 1): Unchecked return value (CHECKED_RETURN) 6. check_return: Calling ptrace without checking return value (as is done elsewhere 44 out of 49 times). Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 82ce90007..dcc823be2 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1361,7 +1361,8 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) if (!current && WIFSTOPPED(status) && WSTOPSIG(status) == SIGCHLD) { /* The root task is ptraced. Allow it to handle SIGCHLD */ - ptrace(PTRACE_CONT, siginfo->si_pid, 0, SIGCHLD); + if (ptrace(PTRACE_CONT, pid, 0, SIGCHLD)) + pr_perror("Unable to resume %d", pid); return; } From d499aeadf6d609d4f1a7b85c84092d8c90aef9f5 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 18 Feb 2018 21:57:05 +0200 Subject: [PATCH 1346/4375] zdtm: enable lazy migration testing The --lazy-migrate option allows testing of lazy migration when running ns or uns flavor. Signed-off-by: Andrei Vagin Signed-off-by: Mike Rapoport --- test/zdtm.py | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index f74275036..649353798 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -487,6 +487,10 @@ class zdtm_test: def getropts(self): return self.__getcropts() + self.__freezer.getropts() + self.__desc.get('ropts', '').split() + def unlink_pidfile(self): + self.__pid = 0 + os.unlink(self.__pidfile()) + def gone(self, force = True): if not self.auto_reap: pid, status = os.waitpid(int(self.__pid), 0) @@ -817,6 +821,7 @@ class criu: self.__remote_lazy_pages = (opts['remote_lazy_pages'] and True or False) self.__lazy_pages = (self.__remote_lazy_pages or opts['lazy_pages'] and True or False) + self.__lazy_migrate = (opts['lazy_migrate'] and True or False) self.__restore_sibling = (opts['sibling'] and True or False) self.__join_ns = (opts['join_ns'] and True or False) self.__empty_ns = (opts['empty_ns'] and True or False) @@ -831,8 +836,11 @@ class criu: self.__show_stats = (opts['show_stats'] and True or False) self.__lazy_pages_p = None self.__page_server_p = None + self.__dump_process = None def fini(self): + if self.__lazy_migrate: + ret = self.__dump_process.wait() if self.__lazy_pages_p: ret = self.__lazy_pages_p.wait() grep_errors(os.path.join(self.__ddir(), "lazy-pages.log")) @@ -845,6 +853,12 @@ class criu: self.__page_server_p = None if ret: raise test_fail_exc("criu page-server exited with %s" % ret) + if self.__dump_process: + ret = self.__dump_process.wait() + grep_errors(os.path.join(self.__ddir(), "dump.log")) + self.__dump_process = None + if ret: + raise test_fail_exc("criu dump exited with %s" % ret) return def logs(self): @@ -994,7 +1008,11 @@ class criu: if self.__empty_ns: a_opts += ['--empty-ns', 'net'] - self.__criu_act(action, opts = a_opts + opts) + nowait = False + if self.__lazy_migrate: + a_opts += ["--lazy-pages", "--port", "12345"] + nowait = True + self.__dump_process = self.__criu_act(action, opts = a_opts + opts, nowait = nowait) if self.__mdedup and self.__iter > 1: self.__criu_act("dedup", opts = []) @@ -1030,10 +1048,11 @@ class criu: r_opts.append('--external') r_opts.append('mnt[zdtm]:%s' % criu_dir) - if self.__lazy_pages: + if self.__lazy_pages or self.__lazy_migrate: lp_opts = [] - if self.__remote_lazy_pages: + if self.__remote_lazy_pages or self.__lazy_migrate: lp_opts += ['--page-server', "--port", "12345"] + if self.__remote_lazy_pages: ps_opts = ["--pidfile", "ps.pid", "--port", "12345", "--lazy-pages"] self.__page_server_p = self.__criu_act("page-server", opts = ps_opts, nowait = True) @@ -1071,6 +1090,11 @@ class criu: print "criu page-server exited with %s" % self.__page_server_p.wait() grep_errors(os.path.join(self.__ddir(), "page-server.log")) self.__page_server_p = None + if self.__dump_process: + self.__dump_process.terminate() + print "criu dump exited with %s" % self.__dump_process.wait() + grep_errors(os.path.join(self.__ddir(), "dump.log")) + self.__dump_process = None def try_run_hook(test, args): @@ -1136,7 +1160,10 @@ def cr(cr_api, test, opts): else: try_run_hook(test, ["--pre-dump"]) cr_api.dump("dump") - test.gone() + if not opts['lazy_migrate']: + test.gone() + else: + test.unlink_pidfile() sbs('pre-restore') try_run_hook(test, ["--pre-restore"]) cr_api.restore() @@ -1522,7 +1549,7 @@ class Launcher: nd = ('nocr', 'norst', 'pre', 'iters', 'page_server', 'sibling', 'stop', 'empty_ns', 'fault', 'keep_img', 'report', 'snaps', 'sat', 'script', 'rpc', 'lazy_pages', 'join_ns', 'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup', - 'remote_lazy_pages', 'show_stats') + 'remote_lazy_pages', 'show_stats', 'lazy_migrate') arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd})) if self.__use_log: @@ -1752,7 +1779,7 @@ def run_tests(opts): if subprocess.Popen(["ip", "netns", "exec", "zdtm_netns", "ip", "link", "set", "up", "dev", "lo"]).wait(): raise Exception("ip link set up dev lo") - if opts['lazy_pages'] or opts['remote_lazy_pages']: + if opts['lazy_pages'] or opts['remote_lazy_pages'] or opts['lazy_migrate']: uffd = criu.check("uffd") uffd_noncoop = criu.check("uffd-noncoop") if not uffd: @@ -1810,7 +1837,7 @@ def run_tests(opts): launcher.skip(t, "samens test in the same namespace") continue - if opts['lazy_pages'] or opts['remote_lazy_pages']: + if opts['lazy_pages'] or opts['remote_lazy_pages'] or opts['lazy_migrate']: if test_flag(tdesc, 'nolazy'): launcher.skip(t, "lazy pages are not supported") continue @@ -2055,6 +2082,7 @@ rp.add_argument("--report", help = "Generate summary report in directory") rp.add_argument("--keep-going", help = "Keep running tests in spite of failures", action = 'store_true') rp.add_argument("--ignore-taint", help = "Don't care about a non-zero kernel taint flag", action = 'store_true') rp.add_argument("--lazy-pages", help = "restore pages on demand", action = 'store_true') +rp.add_argument("--lazy-migrate", help = "restore pages on demand", action = 'store_true') rp.add_argument("--remote-lazy-pages", help = "simulate lazy migration", action = 'store_true') rp.add_argument("--title", help = "A test suite title", default = "criu") rp.add_argument("--show-stats", help = "Show criu statistics", action = 'store_true') From 455b5aea2bb055910ba746f93b6510104cb88e64 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 18 Feb 2018 21:57:06 +0200 Subject: [PATCH 1347/4375] test/jenkins: add script for lazy migration testing Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/jenkins/criu-lazy-migration.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 test/jenkins/criu-lazy-migration.sh diff --git a/test/jenkins/criu-lazy-migration.sh b/test/jenkins/criu-lazy-migration.sh new file mode 100644 index 000000000..d0b3a5912 --- /dev/null +++ b/test/jenkins/criu-lazy-migration.sh @@ -0,0 +1,28 @@ +# Check lazy-pages +set -e +source `dirname $0`/criu-lib.sh +prep + +KERN_MAJ=`uname -r | cut -d. -f1` +KERN_MIN=`uname -r | cut -d. -f2` +if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then + LAZY_EXCLUDE="-x cmdlinenv00" +else + LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns + -x socket_listen -x socket_listen6 -x cmdlinenv00 + -x socket_close_data01 -x file_read" +fi + +# These tests seem to require complete separation of dump and restore namespaces +LAZY_MIGRATE_EXCLUDE="-x fifo_loop -x file_locks -x ptrace_sig -x overmount_file -x file_lease -x cr_veth -x fifo -x overmount_sock -x unlink_largefile -x socket_udp-corked -x netns_sub_veth" + +# lazy restore from images +./test/zdtm.py run --all --keep-going --report report --parallel 4 -f uns \ + --lazy-pages $LAZY_EXCLUDE $LAZY_MIGRATE_EXCLUDE || fail + +# During pre-dump + lazy-pages we leave VM_NOHUGEPAGE set +LAZY_EXCLUDE="$LAZY_EXCLUDE -x maps02" + +# lazy restore from images with pre-dumps +./test/zdtm.py run --all --keep-going --report report --parallel 4 -f uns \ + --lazy-pages --pre 2 $LAZY_EXCLUDE $LAZY_MIGRATE_EXCLUDE || fail From a58e1f6ff936b2225ee80756a568fd1bd1474bcf Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 15 Feb 2018 21:08:04 +0000 Subject: [PATCH 1348/4375] kerndat: Separate per-arch kerndat x86's kerndat section in crtools.c has grown too much. Let's make it more readable and *looking at cleared include-list*, it'll better parallelize build. Maybe we should turn __weak function into 0-defines. Or clean 0-defines with ifdefs in generic file. I have no strong opinion on that. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/include/asm/kerndat.h | 7 + criu/arch/aarch64/include/asm/restorer.h | 2 - criu/arch/arm/include/asm/kerndat.h | 7 + criu/arch/arm/include/asm/restorer.h | 2 - criu/arch/ppc64/include/asm/kerndat.h | 7 + criu/arch/ppc64/include/asm/restorer.h | 2 - criu/arch/s390/include/asm/kerndat.h | 7 + criu/arch/s390/include/asm/restorer.h | 2 - criu/arch/x86/Makefile | 1 + criu/arch/x86/crtools.c | 269 +---------------------- criu/arch/x86/include/asm/kerndat.h | 8 + criu/arch/x86/include/asm/restorer.h | 5 - criu/arch/x86/kerndat.c | 249 +++++++++++++++++++++ criu/include/kerndat.h | 1 + 14 files changed, 295 insertions(+), 274 deletions(-) create mode 100644 criu/arch/aarch64/include/asm/kerndat.h create mode 100644 criu/arch/arm/include/asm/kerndat.h create mode 100644 criu/arch/ppc64/include/asm/kerndat.h create mode 100644 criu/arch/s390/include/asm/kerndat.h create mode 100644 criu/arch/x86/include/asm/kerndat.h create mode 100644 criu/arch/x86/kerndat.c diff --git a/criu/arch/aarch64/include/asm/kerndat.h b/criu/arch/aarch64/include/asm/kerndat.h new file mode 100644 index 000000000..60956b573 --- /dev/null +++ b/criu/arch/aarch64/include/asm/kerndat.h @@ -0,0 +1,7 @@ +#ifndef __CR_ASM_KERNDAT_H__ +#define __CR_ASM_KERNDAT_H__ + +#define kdat_compatible_cr() 0 +#define kdat_can_map_vdso() 0 + +#endif /* __CR_ASM_KERNDAT_H__ */ diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h index bef85f3a3..f502cdcaf 100644 --- a/criu/arch/aarch64/include/asm/restorer.h +++ b/criu/arch/aarch64/include/asm/restorer.h @@ -52,8 +52,6 @@ : "sp", "x0", "memory") -#define kdat_compatible_cr() 0 -#define kdat_can_map_vdso() 0 #define arch_map_vdso(map, compat) -1 int restore_gpregs(struct rt_sigframe *f, UserAarch64RegsEntry *r); diff --git a/criu/arch/arm/include/asm/kerndat.h b/criu/arch/arm/include/asm/kerndat.h new file mode 100644 index 000000000..60956b573 --- /dev/null +++ b/criu/arch/arm/include/asm/kerndat.h @@ -0,0 +1,7 @@ +#ifndef __CR_ASM_KERNDAT_H__ +#define __CR_ASM_KERNDAT_H__ + +#define kdat_compatible_cr() 0 +#define kdat_can_map_vdso() 0 + +#endif /* __CR_ASM_KERNDAT_H__ */ diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h index d9208185f..217d920e8 100644 --- a/criu/arch/arm/include/asm/restorer.h +++ b/criu/arch/arm/include/asm/restorer.h @@ -53,8 +53,6 @@ : "memory") -#define kdat_compatible_cr() 0 -#define kdat_can_map_vdso() 0 #define arch_map_vdso(map, compat) -1 int restore_gpregs(struct rt_sigframe *f, UserArmRegsEntry *r); diff --git a/criu/arch/ppc64/include/asm/kerndat.h b/criu/arch/ppc64/include/asm/kerndat.h new file mode 100644 index 000000000..60956b573 --- /dev/null +++ b/criu/arch/ppc64/include/asm/kerndat.h @@ -0,0 +1,7 @@ +#ifndef __CR_ASM_KERNDAT_H__ +#define __CR_ASM_KERNDAT_H__ + +#define kdat_compatible_cr() 0 +#define kdat_can_map_vdso() 0 + +#endif /* __CR_ASM_KERNDAT_H__ */ diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h index 3fffa833c..d48d833d6 100644 --- a/criu/arch/ppc64/include/asm/restorer.h +++ b/criu/arch/ppc64/include/asm/restorer.h @@ -48,8 +48,6 @@ "r"(&thread_args[i]) /* %6 */ \ : "memory","0","3","4","5","6","7","14","15") -#define kdat_compatible_cr() 0 -#define kdat_can_map_vdso() 0 #define arch_map_vdso(map, compat) -1 int restore_gpregs(struct rt_sigframe *f, UserPpc64RegsEntry *r); diff --git a/criu/arch/s390/include/asm/kerndat.h b/criu/arch/s390/include/asm/kerndat.h new file mode 100644 index 000000000..60956b573 --- /dev/null +++ b/criu/arch/s390/include/asm/kerndat.h @@ -0,0 +1,7 @@ +#ifndef __CR_ASM_KERNDAT_H__ +#define __CR_ASM_KERNDAT_H__ + +#define kdat_compatible_cr() 0 +#define kdat_can_map_vdso() 0 + +#endif /* __CR_ASM_KERNDAT_H__ */ diff --git a/criu/arch/s390/include/asm/restorer.h b/criu/arch/s390/include/asm/restorer.h index 63e099863..cfdefcab9 100644 --- a/criu/arch/s390/include/asm/restorer.h +++ b/criu/arch/s390/include/asm/restorer.h @@ -39,8 +39,6 @@ "d"(&thread_args[i]) \ : "0", "1", "2", "3", "4", "5", "6", "cc", "memory") -#define kdat_compatible_cr() 0 -#define kdat_can_map_vdso() 0 #define arch_map_vdso(map, compat) -1 int restore_gpregs(struct rt_sigframe *f, UserS390RegsEntry *r); diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index 669dc073a..75fa782c8 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -11,6 +11,7 @@ ldflags-y += -r -z noexecstack obj-y += cpu.o obj-y += crtools.o +obj-y += kerndat.o obj-y += sigframe.o ifeq ($(CONFIG_COMPAT),y) obj-y += sigaction_compat.o diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index e13b39b90..0b5a0acd6 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -1,267 +1,14 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "types.h" -#include "log.h" -#include "asm/compat.h" -#include "asm/parasite-syscall.h" -#include "asm/restorer.h" -#include -#include "asm/dump.h" - -#include "cr_options.h" -#include "common/compiler.h" -#include "restorer.h" -#include "parasite-syscall.h" -#include "util.h" +#include "compel/asm/fpu.h" +#include "compel/compel.h" +#include "compel/plugins/std/syscall-codes.h" #include "cpu.h" -#include -#include "kerndat.h" -#include - -#include "protobuf.h" +#include "cr_options.h" #include "images/core.pb-c.h" -#include "images/creds.pb-c.h" +#include "log.h" +#include "protobuf.h" +#include "types.h" -/* XXX: Move all kerndat features to per-arch kerndat .c */ -int kdat_can_map_vdso(void) -{ - pid_t child; - int stat; - - /* - * Running under fork so if vdso_64 is disabled - don't create - * it for criu accidentally. - */ - child = fork(); - if (child < 0) { - pr_perror("%s(): failed to fork()", __func__); - return -1; - } - - if (child == 0) { - int ret; - - ret = syscall(SYS_arch_prctl, ARCH_MAP_VDSO_32, 0); - if (ret == 0) - exit(1); - /* - * Mapping vDSO while have not unmap it yet: - * this is restricted by API if ARCH_MAP_VDSO_* is supported. - */ - if (ret == -1 && errno == EEXIST) - exit(1); - exit(0); - } - - if (waitpid(child, &stat, 0) != child) { - pr_err("Failed to wait for arch_prctl() test\n"); - kill(child, SIGKILL); - return -1; - } - - if (!WIFEXITED(stat)) - return -1; - - return WEXITSTATUS(stat); - -} - -#ifdef CONFIG_COMPAT -void *mmap_ia32(void *addr, size_t len, int prot, - int flags, int fildes, off_t off) -{ - struct syscall_args32 s; - - s.nr = __NR32_mmap2; - s.arg0 = (uint32_t)(uintptr_t)addr; - s.arg1 = (uint32_t)len; - s.arg2 = prot; - s.arg3 = flags; - s.arg4 = fildes; - s.arg5 = (uint32_t)off; - - do_full_int80(&s); - - return (void *)(uintptr_t)s.nr; -} - -/* - * The idea of the test: - * From kernel's top-down allocator we assume here that - * 1. A = mmap(0, ...); munmap(A); - * 2. B = mmap(0, ...); - * results in A == B. - * ...but if we have 32-bit mmap() bug, then A will have only lower - * 4 bytes of 64-bit address allocated with mmap(). - * That means, that the next mmap() will return B != A - * (as munmap(A) hasn't really unmapped A mapping). - * - * As mapping with lower 4 bytes of A may really exist, we run - * this test under fork(). - * - * Another approach to test bug's presence would be to parse - * /proc/self/maps before and after 32-bit mmap(), but that would - * be soo slow. - */ -static void mmap_bug_test(void) -{ - void *map1, *map2; - int err; - - map1 = mmap_ia32(0, PAGE_SIZE, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); - /* 32-bit error, not sign-extended - can't use IS_ERR_VALUE() here */ - err = (uintptr_t)map1 % PAGE_SIZE; - if (err) { - pr_err("ia32 mmap() failed: %d\n", err); - exit(1); - } - - if (munmap(map1, PAGE_SIZE)) { - pr_err("Failed to unmap() 32-bit mapping: %m\n"); - exit(1); - } - - map2 = mmap_ia32(0, PAGE_SIZE, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); - err = (uintptr_t)map2 % PAGE_SIZE; - if (err) { - pr_err("ia32 mmap() failed: %d\n", err); - exit(1); - } - - if (map1 != map2) - exit(1); - exit(0); -} - -/* - * Pre v4.12 kernels have a bug: for a process started as 64-bit - * 32-bit mmap() may return 8 byte pointer. - * Which is fatal for us: after 32-bit C/R a task will map 64-bit - * addresses, cut upper 4 bytes and try to use lower 4 bytes. - * This is a check if the bug was fixed in the kernel. - */ -static int has_32bit_mmap_bug(void) -{ - pid_t child = fork(); - int stat; - - if (child < 0) { - pr_perror("%s(): failed to fork()", __func__); - return -1; - } - - if (child == 0) - mmap_bug_test(); - - if (waitpid(child, &stat, 0) != child) { - pr_err("Failed to wait for mmap test\n"); - kill(child, SIGKILL); - return -1; - } - - if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0) - return 1; - return 0; -} - -int kdat_compatible_cr(void) -{ - if (!kdat.can_map_vdso) - return 0; - - if (has_32bit_mmap_bug()) - return 0; - - return 1; -} -#else /* !CONFIG_COMPAT */ -int kdat_compatible_cr(void) -{ - return 0; -} -#endif - -static int kdat_x86_has_ptrace_fpu_xsave_bug_child(void *arg) -{ - ptrace(PTRACE_TRACEME, 0, 0, 0); - kill(getpid(), SIGSTOP); - pr_err("Continue after SIGSTOP.. Urr what?\n"); - _exit(1); -} - -/* - * Pre v4.14 kernels have a bug on Skylake CPUs: - * copyout_from_xsaves() creates fpu state for - * ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) - * without MXCSR and MXCSR_FLAGS if there is SSE/YMM state, but no FP state. - * That is xfeatures had either/both XFEATURE_MASK_{SSE,YMM} set, but not - * XFEATURE_MASK_FP. - * But we *really* need to C/R MXCSR & MXCSR_FLAGS if SSE/YMM active, - * as mxcsr store part of the state. - */ -int kdat_x86_has_ptrace_fpu_xsave_bug(void) -{ - user_fpregs_struct_t xsave = { }; - struct iovec iov; - char stack[PAGE_SIZE]; - int flags = CLONE_VM | CLONE_FILES | CLONE_UNTRACED | SIGCHLD; - int ret = -1; - pid_t child; - int stat; - - /* OSXSAVE can't be changed during boot. */ - if (!compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) - return 0; - - child = clone(kdat_x86_has_ptrace_fpu_xsave_bug_child, - stack + ARRAY_SIZE(stack), flags, 0); - if (child < 0) { - pr_perror("%s(): failed to clone()", __func__); - return -1; - } - - if (waitpid(child, &stat, WUNTRACED) != child) { - /* - * waitpid() may end with ECHILD if SIGCHLD == SIG_IGN, - * and the child has stopped already. - */ - pr_perror("Failed to wait for %s() test\n", __func__); - goto out_kill; - } - - if (!WIFSTOPPED(stat)) { - pr_err("Born child is unstoppable! (might be dead)\n"); - goto out_kill; - } - - iov.iov_base = &xsave; - iov.iov_len = sizeof(xsave); - - if (ptrace(PTRACE_GETREGSET, child, (unsigned)NT_X86_XSTATE, &iov) < 0) { - pr_perror("Can't obtain FPU registers for %d", child); - goto out_kill; - } - /* - * MXCSR should be never 0x0: e.g., it should contain either: - * R+/R-/RZ/RN to determine rounding model. - */ - ret = !xsave.i387.mxcsr; - -out_kill: - kill(child, SIGKILL); - waitpid(child, &stat, 0); - return ret; -} +#include "asm/compat.h" int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) { diff --git a/criu/arch/x86/include/asm/kerndat.h b/criu/arch/x86/include/asm/kerndat.h new file mode 100644 index 000000000..903bc80f7 --- /dev/null +++ b/criu/arch/x86/include/asm/kerndat.h @@ -0,0 +1,8 @@ +#ifndef __CR_ASM_KERNDAT_H__ +#define __CR_ASM_KERNDAT_H__ + +extern int kdat_compatible_cr(void); +extern int kdat_can_map_vdso(void); +extern int kdat_x86_has_ptrace_fpu_xsave_bug(void); + +#endif /* __CR_ASM_KERNDAT_H__ */ diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index 179f1942f..15867aa12 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -80,11 +80,6 @@ static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) # define ARCH_MAP_VDSO_64 0x2003 #endif -/* XXX: Introduce per-arch kerndat header */ -extern int kdat_compatible_cr(void); -extern int kdat_can_map_vdso(void); -extern int kdat_x86_has_ptrace_fpu_xsave_bug(void); - static inline void __setup_sas_compat(struct ucontext_ia32* uc, ThreadSasEntry *sas) { diff --git a/criu/arch/x86/kerndat.c b/criu/arch/x86/kerndat.c new file mode 100644 index 000000000..a67017d34 --- /dev/null +++ b/criu/arch/x86/kerndat.c @@ -0,0 +1,249 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "compel/asm/fpu.h" +#include "compel/plugins/std/syscall-codes.h" +#include "cpu.h" +#include "kerndat.h" +#include "log.h" +#include "types.h" + +#include "asm/compat.h" +#include "asm/dump.h" + +int kdat_can_map_vdso(void) +{ + pid_t child; + int stat; + + /* + * Running under fork so if vdso_64 is disabled - don't create + * it for criu accidentally. + */ + child = fork(); + if (child < 0) { + pr_perror("%s(): failed to fork()", __func__); + return -1; + } + + if (child == 0) { + int ret; + + ret = syscall(SYS_arch_prctl, ARCH_MAP_VDSO_32, 0); + if (ret == 0) + exit(1); + /* + * Mapping vDSO while have not unmap it yet: + * this is restricted by API if ARCH_MAP_VDSO_* is supported. + */ + if (ret == -1 && errno == EEXIST) + exit(1); + exit(0); + } + + if (waitpid(child, &stat, 0) != child) { + pr_err("Failed to wait for arch_prctl() test\n"); + kill(child, SIGKILL); + return -1; + } + + if (!WIFEXITED(stat)) + return -1; + + return WEXITSTATUS(stat); + +} + +#ifdef CONFIG_COMPAT +void *mmap_ia32(void *addr, size_t len, int prot, + int flags, int fildes, off_t off) +{ + struct syscall_args32 s; + + s.nr = __NR32_mmap2; + s.arg0 = (uint32_t)(uintptr_t)addr; + s.arg1 = (uint32_t)len; + s.arg2 = prot; + s.arg3 = flags; + s.arg4 = fildes; + s.arg5 = (uint32_t)off; + + do_full_int80(&s); + + return (void *)(uintptr_t)s.nr; +} + +/* + * The idea of the test: + * From kernel's top-down allocator we assume here that + * 1. A = mmap(0, ...); munmap(A); + * 2. B = mmap(0, ...); + * results in A == B. + * ...but if we have 32-bit mmap() bug, then A will have only lower + * 4 bytes of 64-bit address allocated with mmap(). + * That means, that the next mmap() will return B != A + * (as munmap(A) hasn't really unmapped A mapping). + * + * As mapping with lower 4 bytes of A may really exist, we run + * this test under fork(). + * + * Another approach to test bug's presence would be to parse + * /proc/self/maps before and after 32-bit mmap(), but that would + * be soo slow. + */ +static void mmap_bug_test(void) +{ + void *map1, *map2; + int err; + + map1 = mmap_ia32(0, PAGE_SIZE, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); + /* 32-bit error, not sign-extended - can't use IS_ERR_VALUE() here */ + err = (uintptr_t)map1 % PAGE_SIZE; + if (err) { + pr_err("ia32 mmap() failed: %d\n", err); + exit(1); + } + + if (munmap(map1, PAGE_SIZE)) { + pr_err("Failed to unmap() 32-bit mapping: %m\n"); + exit(1); + } + + map2 = mmap_ia32(0, PAGE_SIZE, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); + err = (uintptr_t)map2 % PAGE_SIZE; + if (err) { + pr_err("ia32 mmap() failed: %d\n", err); + exit(1); + } + + if (map1 != map2) + exit(1); + exit(0); +} + +/* + * Pre v4.12 kernels have a bug: for a process started as 64-bit + * 32-bit mmap() may return 8 byte pointer. + * Which is fatal for us: after 32-bit C/R a task will map 64-bit + * addresses, cut upper 4 bytes and try to use lower 4 bytes. + * This is a check if the bug was fixed in the kernel. + */ +static int has_32bit_mmap_bug(void) +{ + pid_t child = fork(); + int stat; + + if (child < 0) { + pr_perror("%s(): failed to fork()", __func__); + return -1; + } + + if (child == 0) + mmap_bug_test(); + + if (waitpid(child, &stat, 0) != child) { + pr_err("Failed to wait for mmap test\n"); + kill(child, SIGKILL); + return -1; + } + + if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0) + return 1; + return 0; +} + +int kdat_compatible_cr(void) +{ + if (!kdat.can_map_vdso) + return 0; + + if (has_32bit_mmap_bug()) + return 0; + + return 1; +} +#else /* !CONFIG_COMPAT */ +int kdat_compatible_cr(void) +{ + return 0; +} +#endif + +static int kdat_x86_has_ptrace_fpu_xsave_bug_child(void *arg) +{ + ptrace(PTRACE_TRACEME, 0, 0, 0); + kill(getpid(), SIGSTOP); + pr_err("Continue after SIGSTOP.. Urr what?\n"); + _exit(1); +} + +/* + * Pre v4.14 kernels have a bug on Skylake CPUs: + * copyout_from_xsaves() creates fpu state for + * ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) + * without MXCSR and MXCSR_FLAGS if there is SSE/YMM state, but no FP state. + * That is xfeatures had either/both XFEATURE_MASK_{SSE,YMM} set, but not + * XFEATURE_MASK_FP. + * But we *really* need to C/R MXCSR & MXCSR_FLAGS if SSE/YMM active, + * as mxcsr store part of the state. + */ +int kdat_x86_has_ptrace_fpu_xsave_bug(void) +{ + user_fpregs_struct_t xsave = { }; + struct iovec iov; + char stack[PAGE_SIZE]; + int flags = CLONE_VM | CLONE_FILES | CLONE_UNTRACED | SIGCHLD; + int ret = -1; + pid_t child; + int stat; + + /* OSXSAVE can't be changed during boot. */ + if (!compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) + return 0; + + child = clone(kdat_x86_has_ptrace_fpu_xsave_bug_child, + stack + ARRAY_SIZE(stack), flags, 0); + if (child < 0) { + pr_perror("%s(): failed to clone()", __func__); + return -1; + } + + if (waitpid(child, &stat, WUNTRACED) != child) { + /* + * waitpid() may end with ECHILD if SIGCHLD == SIG_IGN, + * and the child has stopped already. + */ + pr_perror("Failed to wait for %s() test\n", __func__); + goto out_kill; + } + + if (!WIFSTOPPED(stat)) { + pr_err("Born child is unstoppable! (might be dead)\n"); + goto out_kill; + } + + iov.iov_base = &xsave; + iov.iov_len = sizeof(xsave); + + if (ptrace(PTRACE_GETREGSET, child, (unsigned)NT_X86_XSTATE, &iov) < 0) { + pr_perror("Can't obtain FPU registers for %d", child); + goto out_kill; + } + /* + * MXCSR should be never 0x0: e.g., it should contain either: + * R+/R-/RZ/RN to determine rounding model. + */ + ret = !xsave.i387.mxcsr; + +out_kill: + kill(child, SIGKILL); + waitpid(child, &stat, 0); + return ret; +} diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 5476b26ef..98e3ccc93 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -4,6 +4,7 @@ #include #include "int.h" #include "common/config.h" +#include "asm/kerndat.h" #ifdef CONFIG_VDSO #include "util-vdso.h" #endif From 33c58d94d7d1294e8263205de96c796ac5632b5d Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 11:51:12 +0300 Subject: [PATCH 1349/4375] net: Fix namespace fd leak in get_socket_ns() We open ns_fd via ioctl(SIOCGSKNS), but never close. Fix that. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/net.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/net.c b/criu/net.c index f4abc72ab..da8fb0cce 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2701,8 +2701,10 @@ struct ns_id *get_socket_ns(int lfd) } if (fstat(ns_fd, &st)) { pr_perror("Unable to stat a network namespace"); + close(ns_fd); return NULL; } + close(ns_fd); ns = lookup_ns_by_kid(st.st_ino, &net_ns_desc); if (ns == NULL) { From 900025dbda12649bf80ddca56e99bd3fe1d29a36 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 26 Feb 2018 03:19:07 +0300 Subject: [PATCH 1350/4375] net: save all attributes of sit devices Currently we save only attributes with non-zero values. For example, a default value for IFLA_IPTUN_PROTO is IPPROTO_IPV6 (41), so we have to save even attributes with zero values. https://github.com/checkpoint-restore/criu/issues/445 Fixes: 4a044e6af93f ("net: Dump regular sit device") Cc: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/net.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/net.c b/criu/net.c index da8fb0cce..85deab745 100644 --- a/criu/net.c +++ b/criu/net.c @@ -705,8 +705,7 @@ static int dump_sit(NetDeviceEntry *nde, struct cr_imgset *imgset, struct nlattr #define ENCODE_ENTRY(__type, __ifla, __proto) do { \ if (data[__ifla]) { \ se.__proto = *(__type *)nla_data(data[__ifla]); \ - if (se.__proto) \ - se.has_##__proto = true; \ + se.has_##__proto = true; \ } \ } while (0) From b24735429b0636485102236f14f7cd677a23350b Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 20 Feb 2018 12:28:52 +0300 Subject: [PATCH 1351/4375] zdtm: Fix race in zdtm/transition/epoll.c test Child may see close() result before it receives signal, while it shouldn't see it. Instead of games with later close(), just stop do it. sys_exit() after program finish will close them all. Reported-by: Andrey Vagin Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- test/zdtm/transition/epoll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/transition/epoll.c b/test/zdtm/transition/epoll.c index f89d96d41..4eac5214c 100644 --- a/test/zdtm/transition/epoll.c +++ b/test/zdtm/transition/epoll.c @@ -175,8 +175,8 @@ int main(int argc, char **argv) test_waitsig(); - killall(); for (i = 0; i < scale; i++) { + kill(pids[i], SIGUSR2); if (waitpid(pids[i], &rv, 0) < 0) { fail("waitpid error: %m\n"); counter++; From ce437d3dc568775f17727ecf7bfeea42ee6f7caa Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 27 Feb 2018 13:42:55 +0000 Subject: [PATCH 1352/4375] x86/kdat: Check PTRACE_TRACEME return value Coverity has informed: *** CID 188251: Error handling issues (CHECKED_RETURN) /criu/arch/x86/crtools.c: 196 in kdat_x86_has_ptrace_fpu_xsave_bug_child() 190 return 0; 191 } 192 #endif 193 194 static int kdat_x86_has_ptrace_fpu_xsave_bug_child(void *arg) 195 { >>> CID 188251: Error handling issues (CHECKED_RETURN) >>> Calling "ptrace" without checking return value (as is done elsewhere 46 out of 51 times). 196 ptrace(PTRACE_TRACEME, 0, 0, 0); 197 kill(getpid(), SIGSTOP); 198 pr_err("Continue after SIGSTOP.. Urr what?\n"); 199 _exit(1); 200 } 201 Also added checks for kill() and waitpid(). Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/kerndat.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/criu/arch/x86/kerndat.c b/criu/arch/x86/kerndat.c index a67017d34..006196829 100644 --- a/criu/arch/x86/kerndat.c +++ b/criu/arch/x86/kerndat.c @@ -178,8 +178,14 @@ int kdat_compatible_cr(void) static int kdat_x86_has_ptrace_fpu_xsave_bug_child(void *arg) { - ptrace(PTRACE_TRACEME, 0, 0, 0); - kill(getpid(), SIGSTOP); + if (ptrace(PTRACE_TRACEME, 0, 0, 0)) { + pr_perror("%d: ptrace(PTRACE_TRACEME) failed", getpid()); + _exit(1); + } + + if (kill(getpid(), SIGSTOP)) + pr_perror("%d: failed to kill myself", getpid()); + pr_err("Continue after SIGSTOP.. Urr what?\n"); _exit(1); } @@ -243,7 +249,10 @@ int kdat_x86_has_ptrace_fpu_xsave_bug(void) ret = !xsave.i387.mxcsr; out_kill: - kill(child, SIGKILL); - waitpid(child, &stat, 0); + if (kill(child, SIGKILL)) + pr_perror("Failed to kill my own child"); + if (waitpid(child, &stat, 0) < 0) + pr_perror("Failed wait for a dead child"); + return ret; } From c21e09cfe2f226cd14058ef5c4b0cbf7421293d2 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 13 Mar 2018 15:42:34 +0300 Subject: [PATCH 1353/4375] criu: Version 3.8 We've slowed down a little, but still new features and bugfixes appear. This time we've improved lazy migration, completed SCM messages support, added nesting netns support (now we have two of them -- net and mnt) and did many small fixes here and there. Signed-off-by: Pavel Emelyanov --- Makefile.versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index 9b0689702..d42a6cde6 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 7 +CRIU_VERSION_MINOR := 8 CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Vinyl Magpie +CRIU_VERSION_NAME := Snow Bunting CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From c297c994bc6a808ff8be998285e61c71d910b4bc Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 27 Mar 2018 20:48:25 +0300 Subject: [PATCH 1354/4375] restore: don't call fdstore_init twice When the "core: Init fdstore even earlier" commit was moved into the master branch, one hunk was lost. https://github.com/checkpoint-restore/criu/issues/460 Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index dcc823be2..acc99e3f9 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1648,9 +1648,6 @@ static int restore_task_with_children(void *_arg) /* Restore root task */ if (current->parent == NULL) { - if (fdstore_init()) - goto err; - if (join_namespaces()) { pr_perror("Join namespaces failed"); goto err; From 137ce1a5fa8412497a284c69214a628474ee4e11 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 29 Mar 2018 21:58:56 +0300 Subject: [PATCH 1355/4375] criu: Version 3.8.1 A bug sneaked into the --shell-job restore while doing 3.8 merge. Signed-off-by: Pavel Emelyanov --- Makefile.versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.versions b/Makefile.versions index d42a6cde6..facac17b7 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -2,7 +2,7 @@ # CRIU version. CRIU_VERSION_MAJOR := 3 CRIU_VERSION_MINOR := 8 -CRIU_VERSION_SUBLEVEL := +CRIU_VERSION_SUBLEVEL := 1 CRIU_VERSION_EXTRA := CRIU_VERSION_NAME := Snow Bunting CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) From 463951aabf38d1c7a134c532bfe0c5f2e218bd05 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 5 Apr 2018 21:33:12 +0300 Subject: [PATCH 1356/4375] test: set uid_map so that INVALID_UID was out of this map https://github.com/checkpoint-restore/criu/issues/466 Signed-off-by: Andrei Vagin --- test/zdtm/lib/ns.c | 2 +- test/zdtm/static/pty01.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/zdtm/lib/ns.c b/test/zdtm/lib/ns.c index 7a0949f22..bf8ca1979 100644 --- a/test/zdtm/lib/ns.c +++ b/test/zdtm/lib/ns.c @@ -350,7 +350,7 @@ int ns_init(int argc, char **argv) exit(1); } -#define UID_MAP "0 100000 100000\n100000 200000 50000" +#define UID_MAP "0 20000 20000\n100000 200000 50000" #define GID_MAP "0 400000 50000\n50000 500000 100000" void ns_create(int argc, char **argv) { diff --git a/test/zdtm/static/pty01.c b/test/zdtm/static/pty01.c index 29b20601f..cb7fff9af 100644 --- a/test/zdtm/static/pty01.c +++ b/test/zdtm/static/pty01.c @@ -25,7 +25,7 @@ int main(int argc, char *argv[]) char *slavename; struct stat st; - uid_t new_uid = 33333; + uid_t new_uid = 13333; gid_t new_gid = 44444; test_init(argc, argv); From 8fadf2b3192b35185bb5f05dcab2509771a3919b Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 21 Mar 2017 12:04:31 +0300 Subject: [PATCH 1357/4375] ns: export prepare_userns_creds() Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/include/namespaces.h | 1 + criu/namespaces.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index abe63802f..c0ad0f419 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -157,6 +157,7 @@ extern int dump_mnt_namespaces(void); extern int dump_namespaces(struct pstree_item *item, unsigned int ns_flags); extern int prepare_namespace_before_tasks(void); extern int prepare_namespace(struct pstree_item *item, unsigned long clone_flags); +extern int prepare_userns_creds(void); extern int switch_ns(int pid, struct ns_desc *nd, int *rst); extern int switch_ns_by_fd(int nsfd, struct ns_desc *nd, int *rst); diff --git a/criu/namespaces.c b/criu/namespaces.c index 18b45e8f3..87a8dadb2 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -1537,7 +1537,7 @@ int collect_namespaces(bool for_dump) return 0; } -static int prepare_userns_creds(void) +int prepare_userns_creds(void) { /* UID and GID must be set after restoring /proc/PID/{uid,gid}_maps */ if (setuid(0) || setgid(0) || setgroups(0, NULL)) { From 36ad24a1938bad90695b1df7102b8a385fa10119 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 7 Jun 2017 14:29:32 +0300 Subject: [PATCH 1358/4375] user_ns: Prepare creds of newly created task Sockets are sent via SCM_CREDENTIALS, and this kernel interface needs to have uid and gid mapped (see __scm_send() in kernel). So, set them before send_fds() use. Also, move prep_usernsd_transport() below to be after this for uniformity. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index acc99e3f9..4aa811270 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1242,6 +1242,11 @@ static void maybe_clone_parent(struct pstree_item *item, } } +static bool needs_prep_creds(struct pstree_item *item) +{ + return (!item->parent && (root_ns_mask & CLONE_NEWUSER)); +} + static inline int fork_with_pid(struct pstree_item *item) { struct cr_clone_arg ca; @@ -1637,6 +1642,9 @@ static int restore_task_with_children(void *_arg) goto err; } + if (needs_prep_creds(current) && (prepare_userns_creds())) + goto err; + /* * Call this _before_ forking to optimize cgroups * restore -- if all tasks live in one set of cgroups From de25f4cebcca4859c2ddefb765e71c9ecdf1ad25 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 19 Feb 2018 18:59:42 +0300 Subject: [PATCH 1359/4375] service_fd: Place lazy pages sk to fdstore LAZY_PAGES_SK_OF is need only once for every process, and it's not frequently used, so we can place it to fdstore. https://travis-ci.org/tkhai/criu/builds/343405755 Signed-off-by: Kirill Tkhai --- criu/include/servicefd.h | 1 - criu/uffd.c | 31 ++++++++++++++++++------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h index 25cb68bdd..bddf71c09 100644 --- a/criu/include/servicefd.h +++ b/criu/include/servicefd.h @@ -21,7 +21,6 @@ enum sfd_type { TRANSPORT_FD_OFF, /* to transfer file descriptors */ RPC_SK_OFF, FDSTORE_SK_OFF, - LAZY_PAGES_SK_OFF, /* socket for communication with lazy-pages daemon */ SERVICE_FD_MAX }; diff --git a/criu/uffd.c b/criu/uffd.c index 97d2d05ba..088e3ea7f 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -38,6 +38,7 @@ #include "page-xfer.h" #include "common/lock.h" #include "rst-malloc.h" +#include "fdstore.h" #include "util.h" #undef LOG_PREFIX @@ -103,6 +104,8 @@ static LIST_HEAD(pending_lpis); static int epollfd; static bool restore_finished; static struct epoll_rfd lazy_sk_rfd; +/* socket for communication with lazy-pages daemon */ +static int lazy_pages_sk_id = -1; static int handle_uffd_event(struct epoll_rfd *lpfd); @@ -173,7 +176,7 @@ static int send_uffd(int sendfd, int pid) if (sendfd < 0) return -1; - fd = get_service_fd(LAZY_PAGES_SK_OFF); + fd = fdstore_get(lazy_pages_sk_id); if (fd < 0) { pr_err("%s: get_service_fd\n", __func__); return -1; @@ -292,8 +295,7 @@ err: int prepare_lazy_pages_socket(void) { - int fd, new_fd; - int len; + int fd, len, ret = -1; struct sockaddr_un sun; if (!opts.lazy_pages) @@ -311,19 +313,22 @@ int prepare_lazy_pages_socket(void) if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) return -1; - new_fd = install_service_fd(LAZY_PAGES_SK_OFF, fd); - close(fd); - if (new_fd < 0) - return -1; - len = offsetof(struct sockaddr_un, sun_path) + strlen(sun.sun_path); - if (connect(new_fd, (struct sockaddr *) &sun, len) < 0) { + if (connect(fd, (struct sockaddr *) &sun, len) < 0) { pr_perror("connect to %s failed", sun.sun_path); - close(new_fd); - return -1; + goto out; } - return 0; + lazy_pages_sk_id = fdstore_add(fd); + if (lazy_pages_sk_id < 0) { + pr_perror("Can't add fd to fdstore"); + goto out; + } + + ret = 0; +out: + close(fd); + return ret; } static int server_listen(struct sockaddr_un *saddr) @@ -1167,7 +1172,7 @@ int lazy_pages_finish_restore(void) if (!opts.lazy_pages) return 0; - fd = get_service_fd(LAZY_PAGES_SK_OFF); + fd = fdstore_get(lazy_pages_sk_id); if (fd < 0) { pr_err("No lazy-pages socket\n"); return -1; From 8f9553a0d2e3b72c67aaf765bc599fd49ab6c77c Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 2 Mar 2018 15:46:20 +0300 Subject: [PATCH 1360/4375] net: Extrack ioctl() call from kerndat_socket_netns() Refactoring, no functional change. Signed-off-by: Kirill Tkhai --- criu/include/net.h | 1 + criu/net.c | 26 +++++++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/criu/include/net.h b/criu/include/net.h index 796dcc415..74f0969ad 100644 --- a/criu/include/net.h +++ b/criu/include/net.h @@ -48,5 +48,6 @@ extern int move_veth_to_bridge(void); extern int kerndat_link_nsid(void); extern int net_get_nsid(int rtsk, int fd, int *nsid); extern int kerndat_nsid(void); +extern void check_has_netns_ioc(int fd, bool *kdat_val, const char *name); #endif /* __CR_NET_H__ */ diff --git a/criu/net.c b/criu/net.c index 85deab745..2baa69b33 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2714,26 +2714,30 @@ struct ns_id *get_socket_ns(int lfd) return ns; } +void check_has_netns_ioc(int fd, bool *kdat_val, const char *name) +{ + int ns_fd; + + ns_fd = ioctl(fd, SIOCGSKNS); + *kdat_val = (ns_fd >= 0); + + if (ns_fd < 0) + pr_warn("Unable to get %s network namespace\n", name); + else + close(ns_fd); +} + int kerndat_socket_netns(void) { - int sk, ns_fd; + int sk; sk = socket(AF_UNIX, SOCK_DGRAM, 0); if (sk < 0) { pr_perror("Unable to create socket"); return -1; } - ns_fd = ioctl(sk, SIOCGSKNS); - if (ns_fd < 0) { - pr_warn("Unable to get a socket network namespace\n"); - kdat.sk_ns = false; - close(sk); - return 0; - } + check_has_netns_ioc(sk, &kdat.sk_ns, "socket"); close(sk); - close(ns_fd); - - kdat.sk_ns = true; return 0; } From fe7d8a922de4a9cc5d51669ff1d2c26ca48f8d79 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 2 Mar 2018 15:46:28 +0300 Subject: [PATCH 1361/4375] tun: Check tun has ioctl() cmd SIOCGSKNS Signed-off-by: Kirill Tkhai --- criu/cr-check.c | 8 ++++++++ criu/include/kerndat.h | 1 + criu/include/tun.h | 1 + criu/kerndat.c | 8 ++++++++ criu/tun.c | 20 ++++++++++++++++++++ 5 files changed, 38 insertions(+) diff --git a/criu/cr-check.c b/criu/cr-check.c index 922349c57..8cbf789f1 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1209,6 +1209,13 @@ static int check_tun(void) return check_tun_cr(-1); } +static int check_tun_netns(void) +{ + bool has = false; + check_tun_netns_cr(&has); + return has ? 0 : -1; +} + static int check_nsid(void) { if (kerndat_nsid() < 0) @@ -1246,6 +1253,7 @@ static struct feature_list feature_list[] = { { "aio_remap", check_aio_remap }, { "timerfd", check_timerfd }, { "tun", check_tun }, + { "tun_ns", check_tun_netns }, { "userns", check_userns }, { "fdinfo_lock", check_fdinfo_lock }, { "seccomp_suspend", check_ptrace_suspend_seccomp }, diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 98e3ccc93..035b8fba4 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -48,6 +48,7 @@ struct kerndat_s { enum loginuid_func luid; bool compat_cr; bool sk_ns; + bool tun_ns; enum pagemap_func pmap; unsigned int has_xtlocks; unsigned long mmap_min_addr; diff --git a/criu/include/tun.h b/criu/include/tun.h index 2d0aa8e08..2ccd007c2 100644 --- a/criu/include/tun.h +++ b/criu/include/tun.h @@ -15,5 +15,6 @@ struct net_link; extern int restore_one_tun(struct net_link *link, int nlsk); extern struct collect_image_info tunfile_cinfo; extern int check_tun_cr(int no_tun_err); +extern int check_tun_netns_cr(bool *result); #endif /* __CR_TUN_H__ */ diff --git a/criu/kerndat.c b/criu/kerndat.c index e0d0c7b52..8cbc355b0 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -29,6 +29,7 @@ #include "sk-inet.h" #include "sockets.h" #include "net.h" +#include "tun.h" #include #include #include "netfilter.h" @@ -933,6 +934,11 @@ out_unmap: return ret; } +static int kerndat_tun_netns(void) +{ + return check_tun_netns_cr(&kdat.tun_ns); +} + int kerndat_init(void) { int ret; @@ -969,6 +975,8 @@ int kerndat_init(void) ret = kerndat_compat_restore(); if (!ret) ret = kerndat_socket_netns(); + if (!ret) + ret = kerndat_tun_netns(); if (!ret) ret = kerndat_nsid(); if (!ret) diff --git a/criu/tun.c b/criu/tun.c index dfca4b125..117d30aa3 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -19,6 +19,7 @@ #include "net.h" #include "namespaces.h" #include "xmalloc.h" +#include "kerndat.h" #include "images/tun.pb-c.h" @@ -70,6 +71,25 @@ int check_tun_cr(int no_tun_err) return ret; } +int check_tun_netns_cr(bool *result) +{ + bool val; + int tun; + + tun = open(TUN_DEV_GEN_PATH, O_RDONLY); + if (tun < 0) { + pr_perror("Unable to create tun"); + return -1; + } + check_has_netns_ioc(tun, &val, "tun"); + close(tun); + + if (result) + *result = val; + + return 0; +} + static LIST_HEAD(tun_links); struct tun_link { From 62d7780166c6736be64e52a71f7ad6e46e8fdf40 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 2 Mar 2018 15:46:37 +0300 Subject: [PATCH 1362/4375] tun: Check that net ns of tun device is dumped Similar to socket logic, abort the dump, if tun is not related to any net ns, seen before. Signed-off-by: Kirill Tkhai --- criu/tun.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/criu/tun.c b/criu/tun.c index 117d30aa3..a6cd372d3 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -290,6 +290,7 @@ static int dump_tunfile(int lfd, u32 id, const struct fd_parms *p) struct cr_img *img; FileEntry fe = FILE_ENTRY__INIT; TunfileEntry tfe = TUNFILE_ENTRY__INIT; + struct ns_id *ns; struct ifreq ifr; if (!(root_ns_mask & CLONE_NEWNET)) { @@ -297,6 +298,14 @@ static int dump_tunfile(int lfd, u32 id, const struct fd_parms *p) return -1; } + if (kdat.tun_ns) { + ns = get_socket_ns(lfd); + if (!ns) { + pr_err("No net_ns for tun device\n"); + return -1; + } + } + if (dump_one_reg_file(lfd, id, p)) return -1; From cd7dac19a7228fcedc228e4999ead29a20acc44e Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Fri, 2 Mar 2018 15:46:45 +0300 Subject: [PATCH 1363/4375] net: Dump tun device net id in img This adds new tunfile_entry::ns_id field and populates it in standard socket way. Restore uses this ns_id to choose correct namespace. Note, we could completelly skip set_netns() on restore in case of !has_ns_id, but using top_net_ns invents some definite behaviour. Signed-off-by: Andrew Vagin ktkhai: comment written/code movings Signed-off-by: Kirill Tkhai --- criu/tun.c | 9 ++++++++- images/tun.proto | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/criu/tun.c b/criu/tun.c index a6cd372d3..742816afc 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -20,6 +20,7 @@ #include "namespaces.h" #include "xmalloc.h" #include "kerndat.h" +#include "sockets.h" #include "images/tun.pb-c.h" @@ -304,6 +305,8 @@ static int dump_tunfile(int lfd, u32 id, const struct fd_parms *p) pr_err("No net_ns for tun device\n"); return -1; } + tfe.has_ns_id = true; + tfe.ns_id = ns->id; } if (dump_one_reg_file(lfd, id, p)) @@ -356,7 +359,7 @@ struct tunfile_info { static int tunfile_open(struct file_desc *d, int *new_fd) { - int fd; + int fd, ns_id; struct tunfile_info *ti; struct ifreq ifr; struct tun_link *tl; @@ -366,6 +369,10 @@ static int tunfile_open(struct file_desc *d, int *new_fd) if (fd < 0) return -1; + ns_id = ti->tfe->has_ns_id ? ti->tfe->ns_id : top_net_ns->id; + if (set_netns(ns_id)) + return -1; + if (!ti->tfe->netdev) /* just-opened tun file */ goto ok;; diff --git a/images/tun.proto b/images/tun.proto index 796e1f5d9..b70c9ed67 100644 --- a/images/tun.proto +++ b/images/tun.proto @@ -6,6 +6,7 @@ message tunfile_entry { required uint32 id = 1; optional string netdev = 2; optional bool detached = 3; + optional uint32 ns_id = 4; }; message tun_link_entry { From 7e355e7b12edb39e7cc3fe17c2b4bb4d894abf76 Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Fri, 2 Mar 2018 15:46:53 +0300 Subject: [PATCH 1364/4375] zdtm: Add tun_ns test tun test in nested net ns wrapper. Signed-off-by: Andrew Vagin ktkhai: Makefile hunks Signed-off-by: Kirill Tkhai --- test/zdtm/static/Makefile | 2 ++ test/zdtm/static/tun.c | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index da2bf0f45..fa0316f02 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -155,6 +155,7 @@ TST_NOFILE := \ grow_map02 \ grow_map03 \ tun \ + tun_ns \ stopped \ stopped01 \ stopped02 \ @@ -472,6 +473,7 @@ socket_listen4v6: CFLAGS += -D ZDTM_IPV4V6 socket-tcp6-closed: CFLAGS += -D ZDTM_IPV6 socket-tcp6-closed: CFLAGS += -D ZDTM_IPV4V6 socket-tcp-closed-last-ack: CFLAGS += -D ZDTM_TCP_LAST_ACK +tun_ns: CFLAGS += -DTUN_NS mnt_ext_manual: CFLAGS += -D ZDTM_EXTMAP_MANUAL sigpending: LDLIBS += -lrt vdso01: LDLIBS += -lrt diff --git a/test/zdtm/static/tun.c b/test/zdtm/static/tun.c index c53b8fa88..98519e5d2 100644 --- a/test/zdtm/static/tun.c +++ b/test/zdtm/static/tun.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "zdtmtst.h" @@ -118,7 +119,10 @@ int main(int argc, char **argv) char addr[ETH_ALEN], a2[ETH_ALEN]; test_init(argc, argv); - +#ifdef TUN_NS + unshare(CLONE_NEWNET); + system("ip link set up dev lo"); +#endif /* fd[0] -- opened file */ fds[0] = __open_tun(); if (fds[0] < 0) { From c90c7bd5e6b5023a4e740104c1912d45d20140c1 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 12 May 2018 01:02:36 +0300 Subject: [PATCH 1365/4375] net: set_netns should set a root net ns if ns_id is zero We need this to save backward compatibility with old images. It is zero only if it is absent in an image file. Signed-off-by: Andrei Vagin --- criu/include/net.h | 1 + criu/net.c | 4 ++-- criu/sockets.c | 9 ++++++++- criu/tun.c | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/criu/include/net.h b/criu/include/net.h index 74f0969ad..1f6be068d 100644 --- a/criu/include/net.h +++ b/criu/include/net.h @@ -47,6 +47,7 @@ extern int move_veth_to_bridge(void); extern int kerndat_link_nsid(void); extern int net_get_nsid(int rtsk, int fd, int *nsid); +extern struct ns_id *net_get_root_ns(); extern int kerndat_nsid(void); extern void check_has_netns_ioc(int fd, bool *kdat_val, const char *name); diff --git a/criu/net.c b/criu/net.c index 2baa69b33..d02c4fdb8 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2664,7 +2664,7 @@ int collect_net_namespaces(bool for_dump) struct ns_desc net_ns_desc = NS_DESC_ENTRY(CLONE_NEWNET, "net"); -static struct ns_id *get_root_netns() +struct ns_id *net_get_root_ns() { static struct ns_id *root_netns = NULL; @@ -2693,7 +2693,7 @@ struct ns_id *get_socket_ns(int lfd) if (ns_fd < 0) { /* backward compatiblity with old kernels */ if (netns_nr == 1) - return get_root_netns(); + return net_get_root_ns(); pr_perror("Unable to get a socket net namespace"); return NULL; diff --git a/criu/sockets.c b/criu/sockets.c index a942a6ba6..b7591bf80 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -762,7 +762,14 @@ int set_netns(uint32_t ns_id) if (ns_id == last_ns_id) return 0; - ns = lookup_ns_by_id(ns_id, &net_ns_desc); + /* + * The 0 ns_id means that it was not set. We need + * this to be compatible with old images. + */ + if (ns_id == 0) + ns = net_get_root_ns(); + else + ns = lookup_ns_by_id(ns_id, &net_ns_desc); if (ns == NULL) { pr_err("Unable to find a network namespace\n"); return -1; diff --git a/criu/tun.c b/criu/tun.c index 742816afc..e88e7797a 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -369,7 +369,7 @@ static int tunfile_open(struct file_desc *d, int *new_fd) if (fd < 0) return -1; - ns_id = ti->tfe->has_ns_id ? ti->tfe->ns_id : top_net_ns->id; + ns_id = ti->tfe->ns_id; if (set_netns(ns_id)) return -1; From 3ba08939cbca76ef70fafeba5ad9235e6153bb0c Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 23 Mar 2018 12:09:31 +0300 Subject: [PATCH 1366/4375] zdtm: Actually add tun_ns test Previous patch missed "git add", so simlink and .desc file were not sent... Signed-off-by: Kirill Tkhai --- test/zdtm/static/tun_ns.c | 1 + test/zdtm/static/tun_ns.desc | 1 + 2 files changed, 2 insertions(+) create mode 120000 test/zdtm/static/tun_ns.c create mode 100644 test/zdtm/static/tun_ns.desc diff --git a/test/zdtm/static/tun_ns.c b/test/zdtm/static/tun_ns.c new file mode 120000 index 000000000..bbc509ae9 --- /dev/null +++ b/test/zdtm/static/tun_ns.c @@ -0,0 +1 @@ +tun.c \ No newline at end of file diff --git a/test/zdtm/static/tun_ns.desc b/test/zdtm/static/tun_ns.desc new file mode 100644 index 000000000..cea7cfd49 --- /dev/null +++ b/test/zdtm/static/tun_ns.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns', 'flags': 'suid', 'feature': 'tun tun_ns'} From 6dd7eaccfa8612504791d26b8b7ff3258dfc009e Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 31 May 2017 20:51:48 +0300 Subject: [PATCH 1367/4375] zdtm: Make possible to claim for features list Currently, one feature is supported. Add possibility for a test to depend on several features. v2: Delete excess "if" as suggested by Andrey Vagin. Rename variables to decrise patch size. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- test/zdtm.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 649353798..2e0f2b64e 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1810,15 +1810,18 @@ def run_tests(opts): launcher.skip(t, "manual run only") continue - feat = tdesc.get('feature', None) - if feat: + feat_list = tdesc.get('feature', "") + for feat in feat_list.split(): if feat not in features: print "Checking feature %s" % feat features[feat] = criu.check(feat) if not features[feat]: launcher.skip(t, "no %s feature" % feat) - continue + feat_list = None + break + if feat_list is None: + continue if self_checkskip(t): launcher.skip(t, "checkskip failed") From db1f00024c7f339fea89be32672eb618abda6a23 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 14 Feb 2018 18:37:10 +0300 Subject: [PATCH 1368/4375] kdat: Add check for inotify() INOTIFY_IOC_SETNEXTWD cmd This is a new ioctl, which allows to request next descriptor allocated by inotify_add_watch(). https://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git/commit/?h=for_next&id=e1603b6effe177210701d3d7132d1b68e7bd2c93 The patch checks this cmd is supported by kernel. Signed-off-by: Kirill Tkhai --- criu/include/fsnotify.h | 4 ++++ criu/include/kerndat.h | 1 + criu/kerndat.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/criu/include/fsnotify.h b/criu/include/fsnotify.h index 7bf5af455..935dd60f4 100644 --- a/criu/include/fsnotify.h +++ b/criu/include/fsnotify.h @@ -8,6 +8,10 @@ #define KERNEL_FS_EVENT_ON_CHILD 0x08000000 +#ifndef INOTIFY_IOC_SETNEXTWD +#define INOTIFY_IOC_SETNEXTWD _IOW('I', 0, __s32) +#endif + extern int is_inotify_link(char *link); extern int is_fanotify_link(char *link); extern const struct fdtype_ops inotify_dump_ops; diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 035b8fba4..849d3c05f 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -71,6 +71,7 @@ struct kerndat_s { unsigned int sysctl_nr_open; unsigned long files_stat_max_files; bool x86_has_ptrace_fpu_xsave_bug; + bool has_inotify_setnextwd; }; extern struct kerndat_s kdat; diff --git a/criu/kerndat.c b/criu/kerndat.c index 8cbc355b0..a3b482238 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -12,6 +12,8 @@ #include #include /* for sockaddr_in and inet_ntoa() */ #include +#include + #include "common/config.h" #include "int.h" @@ -33,6 +35,7 @@ #include #include #include "netfilter.h" +#include "fsnotify.h" #include "linux/userfaultfd.h" #include "prctl.h" #include "uffd.h" @@ -738,6 +741,29 @@ err: return ret; } +int kerndat_has_inotify_setnextwd(void) +{ + int ret = 0; + int fd; + + fd = inotify_init(); + if (fd < 0) { + pr_perror("Can't create inotify"); + return -1; + } + + if (ioctl(fd, INOTIFY_IOC_SETNEXTWD, 0x10)) { + if (errno != ENOTTY) { + pr_perror("Can't call ioctl"); + ret = -1; + } + } else + kdat.has_inotify_setnextwd = true; + + close(fd); + return ret; +} + int __attribute__((weak)) kdat_x86_has_ptrace_fpu_xsave_bug(void) { return 0; @@ -1001,6 +1027,8 @@ int kerndat_init(void) ret = kerndat_nsid(); if (!ret) ret = kerndat_x86_has_ptrace_fpu_xsave_bug(); + if (!ret) + ret = kerndat_has_inotify_setnextwd(); kerndat_lsm(); kerndat_mmap_min_addr(); From 001ea533884bc83c0889f80de4b90f677e45a45b Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 14 Feb 2018 18:37:18 +0300 Subject: [PATCH 1369/4375] inotify: Use fast way of obtaining desired watch descriptor number This patch makes restore_one_inotify() to request specific watch descriptor number instead of iterating in (possible) long-duration loop if system supports it. Signed-off-by: Kirill Tkhai --- criu/fsnotify.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 5fb26d0e9..73dae3938 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -35,6 +35,7 @@ #include "files-reg.h" #include "file-ids.h" #include "criu-log.h" +#include "kerndat.h" #include "common/list.h" #include "common/lock.h" #include "irmap.h" @@ -569,11 +570,13 @@ static int restore_one_inotify(int inotify_fd, struct fsnotify_mark_info *info) iwe->mask, mask); } - /* - * FIXME The kernel allocates wd-s sequentially, - * this is suboptimal, but the kernel doesn't - * provide and API for this yet :( - */ + if (kdat.has_inotify_setnextwd) { + if (ioctl(inotify_fd, INOTIFY_IOC_SETNEXTWD, iwe->wd)) { + pr_perror("Can't set next inotify wd"); + return -1; + } + } + while (1) { int wd; @@ -589,6 +592,9 @@ static int restore_one_inotify(int inotify_fd, struct fsnotify_mark_info *info) break; } + if (kdat.has_inotify_setnextwd) + return -1; + inotify_rm_watch(inotify_fd, wd); } From 780d6ea01dde079afdddb67db87de83c51edd789 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 8 Mar 2018 19:46:06 +0000 Subject: [PATCH 1370/4375] Print CRIU and kernel version also in RPC mode The newly introduced output of the CRIU and kernel version does not happen when running CRIU under RPC. This moves the print_versions() function util.c and calls it from cr-service.c Signed-off-by: Adrian Reber --- criu/cr-service.c | 2 ++ criu/crtools.c | 18 +----------------- criu/include/util.h | 2 ++ criu/util.c | 18 ++++++++++++++++++ 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 0928df880..d1323dbce 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -307,6 +307,8 @@ static int setup_opts_from_req(int sk, CriuOpts *req) goto err; } + print_versions(); + /* checking flags from client */ if (req->has_leave_running && req->leave_running) opts.final_state = TASK_ALIVE; diff --git a/criu/crtools.c b/criu/crtools.c index 05ff91ac4..07ee2acef 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -235,20 +235,6 @@ static void soccr_print_on_level(unsigned int loglevel, const char *format, ...) va_end(args); } -static void print_kernel_version(void) -{ - struct utsname buf; - - if (uname(&buf) < 0) { - pr_perror("Reading kernel version failed!"); - /* This pretty unlikely, just keep on running. */ - return; - } - - pr_info("Running on %s %s %s %s %s\n", buf.nodename, buf.sysname, - buf.release, buf.version, buf.machine); -} - static void rlimit_unlimit_nofile_self(void) { struct rlimit new; @@ -764,9 +750,7 @@ int main(int argc, char *argv[], char *envp[]) libsoccr_set_log(log_level, soccr_print_on_level); compel_log_init(vprint_on_level, log_get_loglevel()); - pr_info("Version: %s (gitid %s)\n", CRIU_VERSION, CRIU_GITID); - - print_kernel_version(); + print_versions(); if (opts.deprecated_ok) pr_debug("DEPRECATED ON\n"); diff --git a/criu/include/util.h b/criu/include/util.h index 5c18e69f7..757defd55 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -377,4 +377,6 @@ static inline void print_stack_trace(pid_t pid) {} ___ret; \ }) +extern void print_versions(void); + #endif /* __CR_UTIL_H__ */ diff --git a/criu/util.c b/criu/util.c index 6a5180c4c..a3bf3a3c6 100644 --- a/criu/util.c +++ b/criu/util.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "bitops.h" #include "page.h" @@ -53,6 +54,7 @@ #include "cr-service.h" #include "files.h" #include "pstree.h" +#include "version.h" #include "cr-errno.h" @@ -1512,3 +1514,19 @@ void print_stack_trace(pid_t pid) free(strings); } #endif + +void print_versions(void) +{ + struct utsname buf; + + pr_info("Version: %s (gitid %s)\n", CRIU_VERSION, CRIU_GITID); + + if (uname(&buf) < 0) { + pr_perror("Reading kernel version failed!"); + /* This pretty unlikely, just keep on running. */ + return; + } + + pr_info("Running on %s %s %s %s %s\n", buf.nodename, buf.sysname, + buf.release, buf.version, buf.machine); +} From 0a4d83798bfa0f40e75dae918acc385bfa6b7d4b Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 15 Mar 2018 14:09:37 -0700 Subject: [PATCH 1371/4375] Fix zdtm with Ubuntu Bionic/arm/clang In Ubuntu Bionic for armhf, clang is compiled for armv8l rather than armv7l (as it was and still is for gcc) and so it uses armv8 by default. This breaks compilation of tests using smp_mb(): > error: instruction requires: data-barriers The fix is to add "-march=armv7-a" to CFLAGS which we already do, except not for the tests. Signed-off-by: Kir Kolyshkin --- test/zdtm/Makefile.inc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index 5e8836e90..673fa1bc6 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -21,6 +21,16 @@ endif SRCARCH ?= $(ARCH) +ifeq ($(ARCH),arm) + ARMV := $(shell echo $(UNAME-M) | sed -nr 's/armv([[:digit:]]).*/\1/p; t; i7') + + ifeq ($(ARMV),6) + USERCFLAGS += -march=armv6 + else ifeq ($(ARMV),7) + USERCFLAGS += -march=armv7-a + endif +endif + CC := gcc CFLAGS += -g -O2 -Wall -Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS += $(USERCFLAGS) From 7c4ddebc35ab5c22460bdf4d9377faeebcc29c41 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 15 Mar 2018 14:09:38 -0700 Subject: [PATCH 1372/4375] scripts/build/Dockerfiles: nitpicks 1. Sort lists of packages to be installed, unify indentation. 2. Merge "ccache -s" and "ccache -z". Signed-off-by: Kir Kolyshkin --- scripts/build/Dockerfile.alpine | 44 ++++++++++++++-------------- scripts/build/Dockerfile.fedora.tmpl | 26 +++++++++++++--- scripts/build/Dockerfile.tmpl | 36 +++++++++++------------ 3 files changed, 62 insertions(+), 44 deletions(-) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index ac13d344e..fa8258187 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -3,34 +3,34 @@ ARG CC=gcc ARG ENV1=FOOBAR RUN apk update && apk add \ - build-base \ - coreutils \ - git \ - protobuf-c-dev \ - protobuf-dev \ - python \ - libaio-dev \ - libcap-dev \ - libnl3-dev \ - pkgconfig \ - libnet-dev \ - ccache \ - $CC + $CC \ + build-base \ + ccache \ + coreutils \ + git \ + libaio-dev \ + libcap-dev \ + libnet-dev \ + libnl3-dev \ + pkgconfig \ + protobuf-c-dev \ + protobuf-dev \ + python COPY . /criu WORKDIR /criu ENV CC="ccache $CC" CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes -RUN mv .ccache /tmp && make mrproper && ccache -s && ccache -z &&\ +RUN mv .ccache /tmp && make mrproper && ccache -sz && \ date && make -j $(nproc) CC="$CC" && date && ccache -s -# Run a test -RUN apk add py-yaml \ - py-pip \ - ip6tables \ - iptables \ - iproute2 \ - tar \ - bash +RUN apk add \ + py-yaml \ + py-pip \ + ip6tables \ + iptables \ + iproute2 \ + tar \ + bash RUN pip install protobuf ipaddr RUN make -C test/zdtm diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index 38a0e54e6..399ec316c 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -1,15 +1,33 @@ ARG CC=gcc ARG ENV1=FOOBAR -RUN dnf install -y git gcc make -RUN dnf install -y protobuf-devel protobuf-c-devel libaio-devel libcap-devel libnl3-devel libnet-devel -RUN dnf install -y python ccache libasan findutils tar python-yaml protobuf-python iptables iproute python-ipaddr procps-ng +RUN dnf install -y \ + ccache \ + findutils \ + gcc \ + git \ + iproute \ + iptables \ + libaio-devel \ + libasan \ + libcap-devel \ + libnet-devel \ + libnl3-devel \ + make \ + procps-ng \ + protobuf-c-devel \ + protobuf-devel \ + protobuf-python \ + python \ + python-ipaddr \ + python-yaml \ + tar COPY . /criu WORKDIR /criu ENV CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes -RUN mv .ccache /tmp && make mrproper && ccache -s && ccache -z && \ +RUN mv .ccache /tmp && make mrproper && ccache -sz && \ date && make -j $(nproc) CC="$CC" && date && ccache -s RUN make -C test/zdtm -j $(nproc) diff --git a/scripts/build/Dockerfile.tmpl b/scripts/build/Dockerfile.tmpl index c562af329..f1fff3a52 100644 --- a/scripts/build/Dockerfile.tmpl +++ b/scripts/build/Dockerfile.tmpl @@ -2,24 +2,24 @@ ARG CC=gcc ARG ENV1=FOOBAR RUN apt-get update && apt-get install -y \ - build-essential \ - protobuf-c-compiler \ - libprotobuf-c0-dev \ - libprotobuf-dev \ - bsdmainutils \ - protobuf-compiler \ - python-minimal \ - libaio-dev \ - libcap-dev \ - iptables \ - libnl-3-dev \ - libnl-route-3-dev \ - libselinux-dev \ - pkg-config \ - git-core \ - libnet-dev \ - ccache \ - $CC + ccache \ + libnet-dev \ + libnl-route-3-dev \ + $CC \ + bsdmainutils \ + build-essential \ + git-core \ + iptables \ + libaio-dev \ + libcap-dev \ + libnl-3-dev \ + libprotobuf-c0-dev \ + libprotobuf-dev \ + libselinux-dev \ + pkg-config \ + protobuf-c-compiler \ + protobuf-compiler \ + python-minimal COPY . /criu WORKDIR /criu From c75cb2b58bde9f574ef9b377faa2e88c66a51790 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 15 Mar 2018 14:09:39 -0700 Subject: [PATCH 1373/4375] CI: fix Fedora rawhide Fix Fedora rawhide CI failure caused by coreutils-single and our way of running under QEMU. Signed-off-by: Kir Kolyshkin --- scripts/build/Dockerfile.fedora.tmpl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index 399ec316c..039cb1131 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -23,6 +23,12 @@ RUN dnf install -y \ python-yaml \ tar +# Replace coreutils-single with "traditional" coreutils +# to fix the following error on Fedora 28/rawhide while +# running under QEMU: +# > sh: /usr/bin/sort: /usr/bin/coreutils: bad interpreter: No such file or directory +RUN dnf install -y --allowerasing coreutils + COPY . /criu WORKDIR /criu From a2ab074eca6c634e8206cec6d4d17e6bf3b73cd6 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 15 Mar 2018 14:09:40 -0700 Subject: [PATCH 1374/4375] scripts/build/Dockerfile.rawhide: rm It is not used, probably was committed by mistake. Fixes: 2d093a170227 ("travis: add a job to test on the fedora rawhide") Signed-off-by: Kir Kolyshkin --- scripts/build/Dockerfile.rawhide | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 scripts/build/Dockerfile.rawhide diff --git a/scripts/build/Dockerfile.rawhide b/scripts/build/Dockerfile.rawhide deleted file mode 100644 index b5080d416..000000000 --- a/scripts/build/Dockerfile.rawhide +++ /dev/null @@ -1,14 +0,0 @@ -FROM fedora:rawhide - -ARG CC=gcc - -RUN dnf install -y git gcc make -RUN dnf install -y protobuf-devel protobuf-c-devel libaio-devel libcap-devel libnl3-devel libnet-devel -RUN dnf install -y python ccache libasan findutils tar python-yaml protobuf-python iptables iproute python-ipaddr procps-ng - -COPY . /criu -WORKDIR /criu -RUN make mrproper && make -j $(nproc) - -RUN pip install protobuf -RUN make -C test/zdtm/static env00 From 0284e70f4d8fe97de34a31a87cc91e1218287339 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 15 Mar 2018 14:09:41 -0700 Subject: [PATCH 1375/4375] scripts/build/binfmt_misc: fix for bash There was a "; done" leftover here, somehow ignored by dash but not bash. Remove it. Signed-off-by: Kir Kolyshkin --- scripts/build/binfmt_misc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/binfmt_misc b/scripts/build/binfmt_misc index adbac080d..bf2a2ecad 100755 --- a/scripts/build/binfmt_misc +++ b/scripts/build/binfmt_misc @@ -7,7 +7,7 @@ test -f /proc/sys/fs/binfmt_misc/aarch64 || echo ':aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-aarch64-static:' > /proc/sys/fs/binfmt_misc/register test -f /proc/sys/fs/binfmt_misc/ppc64le || - echo ':ppc64le:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00:\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00:/usr/bin/qemu-ppc64le-static:' > /proc/sys/fs/binfmt_misc/register; done + echo ':ppc64le:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00:\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00:/usr/bin/qemu-ppc64le-static:' > /proc/sys/fs/binfmt_misc/register test -f /proc/sys/fs/binfmt_misc/s390x || echo ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-s390x-static:' > /proc/sys/fs/binfmt_misc/register From a3f152be600f84c935acb0caae009a87940b3969 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 22 Mar 2018 16:39:34 +0300 Subject: [PATCH 1376/4375] unix: Fix nil dereference in find_queuer_for When walking over unix sockets make sure the queuer is present before accessing it. https://jira.sw.ru/browse/PSBM-82796 Reported-by: Vitaly Ostrosablin Signed-off-by: Cyrill Gorcunov Reviewed-by: Kirill Tkhai --- criu/sk-unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 604206585..b79116574 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -848,7 +848,7 @@ static struct unix_sk_info *find_queuer_for(int id) struct unix_sk_info *ui; list_for_each_entry(ui, &unix_sockets, list) { - if (ui->queuer->ue->id == id) + if (ui->queuer && ui->queuer->ue->id == id) return ui; } From 7da537fdcb88ad33a409e6279423683fa388086a Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Fri, 16 Mar 2018 20:24:22 +0300 Subject: [PATCH 1377/4375] zdtm: check unix sockets in two mount namespaces Unix file sockets have to be restored in proper mount namespaces. Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/sk-unix-mntns.c | 159 ++++++++++++++++++++++++++++ test/zdtm/static/sk-unix-mntns.desc | 5 + 3 files changed, 165 insertions(+) create mode 100644 test/zdtm/static/sk-unix-mntns.c create mode 100644 test/zdtm/static/sk-unix-mntns.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index fa0316f02..8c517aa61 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -331,6 +331,7 @@ TST_DIR = \ mnt_enablefs \ autofs \ del_standalone_un \ + sk-unix-mntns \ TST_DIR_FILE = \ chroot \ diff --git a/test/zdtm/static/sk-unix-mntns.c b/test/zdtm/static/sk-unix-mntns.c new file mode 100644 index 000000000..84e65ee13 --- /dev/null +++ b/test/zdtm/static/sk-unix-mntns.c @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Test that unix sockets are restored in proper mount namespaces\n"; +const char *test_author = "Andrei Vagin "; + +char *dirname; +TEST_OPTION(dirname, string, "socket file name", 1); + +#define TEST_MODE 0640 + +int main(int argc, char *argv[]) +{ + struct sockaddr_un addr; + unsigned int addrlen; + int sk, csk; + pid_t pid; + char path[PATH_MAX]; + char sbuf[256], rbuf[256]; + char *cwd; + int ret, status, i; + task_waiter_t t; + + test_init(argc, argv); + + task_waiter_init(&t); + cwd = get_current_dir_name(); + if (!cwd) { + fail("getcwd\n"); + exit(1); + } + + mkdir(dirname, 0777); + + pid = fork(); + if (pid < 0) { + pr_perror("fork"); + return 1; + } + + if (pid == 0) { + unshare(CLONE_NEWNS); + if (mount(NULL, "/", NULL, MS_PRIVATE | MS_REC, NULL)) { + pr_perror("mount"); + return 1; + } + if (mount("test", dirname, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + } + + addrlen = snprintf(path, sizeof(path), "%s/%s/%s", cwd, dirname, "test.socket"); + unlink(path); + + addr.sun_family = AF_UNIX; + if (addrlen > sizeof(addr.sun_path)) + return 1; + memcpy(addr.sun_path, path, addrlen); + addrlen += sizeof(addr.sun_family); + + sk = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0); + if (sk < 0) { + pr_perror("socket\n"); + exit(1); + } + csk = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0); + if (csk < 0) { + pr_perror("socket\n"); + exit(1); + } + + ret = bind(sk, (struct sockaddr *) &addr, addrlen); + if (ret) { + fail("bind\n"); + exit(1); + } + + if (connect(csk, (struct sockaddr *) &addr, addrlen)) { + fail("connect\n"); + exit(1); + } + + if (pid) { + task_waiter_wait4(&t, pid); + test_daemon(); + } else { + task_waiter_complete(&t, getpid()); + } + + test_waitsig(); + + if (pid) + kill(pid, SIGTERM); + + for (i = 0; i < 2; i++) { + int len; + + memset(sbuf, 0, sizeof(sbuf)); + len = ssprintf(sbuf, "%d-%d test test test", getpid(), i); + if (write(csk, sbuf, len) != len) { + pr_perror("write"); + return 1; + } + memset(rbuf, 0, sizeof(rbuf)); + if (read(sk, &rbuf, sizeof(rbuf)) != len) { + pr_perror("read"); + return 1; + } + + if (strncmp(rbuf, sbuf, len)) { + fail("data corrupted\n"); + exit(1); + } + + close(csk); + csk = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0); + if (csk < 0) { + pr_perror("socket\n"); + exit(1); + } + if (connect(csk, (struct sockaddr *) &addr, addrlen)) { + pr_perror("connect"); + exit(1); + } + } + close(sk); + close(csk); + unlink(path); + + if (pid) { + if (waitpid(pid, &status, 0) != pid) { + pr_perror("waitpid"); + return 1; + } + + if (status) { + fail("A child process returned %d", status); + return 1; + } + } + + pass(); + return 0; +} diff --git a/test/zdtm/static/sk-unix-mntns.desc b/test/zdtm/static/sk-unix-mntns.desc new file mode 100644 index 000000000..71e5eae16 --- /dev/null +++ b/test/zdtm/static/sk-unix-mntns.desc @@ -0,0 +1,5 @@ +{ + 'feature': 'mnt_id sk_unix_file', + 'flags': 'suid', + 'flavor': 'ns uns', +} From 8ebf1c48f80ccc6b33a8121a6643d1bb11d0bde4 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Fri, 16 Mar 2018 20:24:23 +0300 Subject: [PATCH 1378/4375] unix: handle sockets with USK_CALLBACK as external sockets The USK_CALLBACK flag means that a socket is externel and will be restored by a plugin. open_unixsk_standalone should not be called to these sockets. $ make -C test/others/unix-callback/ run ... (00.109338) 7471: sk unix: Opening standalone socket (id 0xd ino 0 peer 0x63b) (00.109376) 7471: Error (criu/sk-unix.c:1128): sk unix: BUG at criu/sk-unix.c:1128 Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index b79116574..85d7f3f51 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1786,7 +1786,7 @@ int add_fake_unix_queuers(void) struct unix_sk_info *ui; list_for_each_entry(ui, &unix_sockets, list) { - if ((ui->ue->uflags & USK_EXTERN) || ui->queuer) + if ((ui->ue->uflags & (USK_EXTERN | USK_CALLBACK)) || ui->queuer) continue; if (!(ui->ue->state == TCP_ESTABLISHED && !ui->peer) && ui->ue->type != SOCK_DGRAM) From 0286752b452e9d8d2fbed2035b37359c69d38cf2 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Fri, 16 Mar 2018 20:24:24 +0300 Subject: [PATCH 1379/4375] kerndat: check the SIOCUNIXFILE ioctl for unix sockets This ioctl opens a file to which a socket is bound and returns a file descriptor. This file descriptor can be used to get mnt_id and a file path. Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-check.c | 9 +++++++++ criu/include/kerndat.h | 1 + criu/include/sockets.h | 1 + criu/kerndat.c | 2 ++ criu/sk-unix.c | 30 ++++++++++++++++++++++++++++++ 5 files changed, 43 insertions(+) diff --git a/criu/cr-check.c b/criu/cr-check.c index 8cbf789f1..3e920c12e 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1073,6 +1073,14 @@ static int check_sk_netns(void) return 0; } +static int check_sk_unix_file(void) +{ + if (!kdat.sk_unix_file) + return -1; + + return 0; +} + static int (*chk_feature)(void); /* @@ -1267,6 +1275,7 @@ static struct feature_list feature_list[] = { { "uffd-noncoop", check_uffd_noncoop }, { "can_map_vdso", check_can_map_vdso}, { "sk_ns", check_sk_netns }, + { "sk_unix_file", check_sk_unix_file }, { "nsid", check_nsid }, { "link_nsid", check_link_nsid}, { NULL, NULL }, diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 849d3c05f..10e56f187 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -48,6 +48,7 @@ struct kerndat_s { enum loginuid_func luid; bool compat_cr; bool sk_ns; + bool sk_unix_file; bool tun_ns; enum pagemap_func pmap; unsigned int has_xtlocks; diff --git a/criu/include/sockets.h b/criu/include/sockets.h index 304134cd3..0dc92dc35 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -93,5 +93,6 @@ extern int set_netns(uint32_t ns_id); #endif extern int kerndat_socket_netns(void); +extern int kerndat_socket_unix_file(void); #endif /* __CR_SOCKETS_H__ */ diff --git a/criu/kerndat.c b/criu/kerndat.c index a3b482238..ba8d93808 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -1003,6 +1003,8 @@ int kerndat_init(void) ret = kerndat_socket_netns(); if (!ret) ret = kerndat_tun_netns(); + if (!ret) + ret = kerndat_socket_unix_file(); if (!ret) ret = kerndat_nsid(); if (!ret) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 85d7f3f51..bb74eb833 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -29,6 +30,7 @@ #include "external.h" #include "crtools.h" #include "fdstore.h" +#include "kerndat.h" #include "protobuf.h" #include "images/sk-unix.pb-c.h" @@ -196,6 +198,34 @@ static int write_unix_entry(struct unix_sk_desc *sk) return ret; } +#ifndef SIOCUNIXFILE +#define SIOCUNIXFILE (SIOCPROTOPRIVATE + 0) /* open a socket file with O_PATH */ +#endif + +int kerndat_socket_unix_file(void) +{ + int sk, fd; + + sk = socket(AF_UNIX, SOCK_DGRAM, 0); + if (sk < 0) { + pr_perror("Unable to create socket"); + return -1; + } + fd = ioctl(sk, SIOCUNIXFILE); + if (fd < 0 && errno != ENOENT) { + pr_warn("Unable to open a socket file: %m\n"); + kdat.sk_unix_file = false; + close(sk); + return 0; + } + close(sk); + close(fd); + + kdat.sk_unix_file = true; + + return 0; +} + static int resolve_rel_name(struct unix_sk_desc *sk, const struct fd_parms *p) { rel_name_desc_t *rel_name = sk->rel_name; From 6d785e6cdd14a111b8ab6bdedbcba9e60b3678f9 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Fri, 16 Mar 2018 20:24:25 +0300 Subject: [PATCH 1380/4375] unix: resolve a socket file when a socket descriptor is available unix_process_name() are called when sockets are being collected, but at this moment we don't have socket descriptors. A socket descriptor is reuired to get mnt_id, what will allow to resolve a socket path in its mount namespace. Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 185 ++++++++++++++++++++++++++----------------------- 1 file changed, 97 insertions(+), 88 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index bb74eb833..6a777bc31 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -30,6 +30,7 @@ #include "external.h" #include "crtools.h" #include "fdstore.h" +#include "fdinfo.h" #include "kerndat.h" #include "protobuf.h" @@ -58,12 +59,6 @@ #define FAKE_INO 0 -typedef struct { - char *dir; - unsigned int udiag_vfs_dev; - unsigned int udiag_vfs_ino; -} rel_name_desc_t; - struct unix_sk_desc { struct socket_desc sd; unsigned int type; @@ -73,9 +68,12 @@ struct unix_sk_desc { unsigned int wqlen; unsigned int namelen; char *name; - rel_name_desc_t *rel_name; unsigned int nr_icons; unsigned int *icons; + + unsigned int vfs_dev; + unsigned int vfs_ino; + unsigned char shutdown; bool deleted; @@ -226,9 +224,8 @@ int kerndat_socket_unix_file(void) return 0; } -static int resolve_rel_name(struct unix_sk_desc *sk, const struct fd_parms *p) +static int resolve_rel_name(u32 id, struct unix_sk_desc *sk, const struct fd_parms *p, char **pdir) { - rel_name_desc_t *rel_name = sk->rel_name; const char *dirs[] = { "cwd", "root" }; struct pstree_item *task; int mntns_root, i; @@ -278,13 +275,13 @@ static int resolve_rel_name(struct unix_sk_desc *sk, const struct fd_parms *p) goto err; } - if ((st.st_ino == rel_name->udiag_vfs_ino) && - phys_stat_dev_match(st.st_dev, rel_name->udiag_vfs_dev, ns, &path[1])) { - rel_name->dir = xstrdup(dir); - if (!rel_name->dir) + if ((st.st_ino == sk->vfs_ino) && + phys_stat_dev_match(st.st_dev, sk->vfs_dev, ns, &path[1])) { + *pdir = xstrdup(dir); + if (!*pdir) return -ENOMEM; - pr_debug("Resolved relative socket name to dir %s\n", rel_name->dir); + pr_debug("Resolved relative socket name to dir %s\n", *pdir); sk->mode = st.st_mode; sk->uid = st.st_uid; sk->gid = st.st_gid; @@ -293,10 +290,12 @@ static int resolve_rel_name(struct unix_sk_desc *sk, const struct fd_parms *p) } err: - pr_err("Can't resolve name for socket %#x\n", rel_name->udiag_vfs_ino); + pr_err("Can't resolve name for socket %#x\n", id); return -ENOENT; } +static int unix_resolve_name(u32 id, struct unix_sk_desc *d, + UnixSkEntry *ue, const struct fd_parms *p); static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p) { struct unix_sk_desc *sk, *peer; @@ -349,11 +348,8 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p) ue->opts = skopts; ue->uflags = 0; - if (sk->rel_name) { - if (resolve_rel_name(sk, p)) - goto err; - ue->name_dir = sk->rel_name->dir; - } + if (unix_resolve_name(id, sk, ue, p)) + goto err; /* * Check if this socket is connected to criu service. @@ -528,12 +524,87 @@ const struct fdtype_ops unix_dump_ops = { .dump = dump_one_unix_fd, }; +static int unix_resolve_name(u32 id, struct unix_sk_desc *d, + UnixSkEntry *ue, const struct fd_parms *p) +{ + char *name = d->name; + bool deleted = false; + char rpath[PATH_MAX]; + struct ns_id *ns; + struct stat st; + int mntns_root; + int ret; + + if (d->namelen == 0 || name[0] == '\0') + return 0; + + ns = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc); + if (!ns) { + ret = -ENOENT; + goto out; + } + + mntns_root = mntns_get_root_fd(ns); + if (mntns_root < 0) { + ret = -ENOENT; + goto out; + } + + if (name[0] != '/') { + /* + * Relative names are be resolved later at first + * dump attempt. + */ + + ret = resolve_rel_name(id, d, p, &ue->name_dir); + if (ret < 0) + goto out; + goto postprone; + } + + snprintf(rpath, sizeof(rpath), ".%s", name); + if (fstatat(mntns_root, rpath, &st, 0)) { + if (errno != ENOENT) { + pr_warn("Can't stat socket %#x(%s), skipping: %m (err %d)\n", + id, rpath, errno); + goto skip; + } + + pr_info("unix: Dropping path %s for unlinked sk %#x\n", + name, id); + deleted = true; + } else if ((st.st_ino != d->vfs_ino) || + !phys_stat_dev_match(st.st_dev, d->vfs_dev, ns, name)) { + pr_info("unix: Dropping path %s for unlinked bound " + "sk %#x.%#x real %#x.%#x\n", + name, (int)st.st_dev, (int)st.st_ino, + (int)d->vfs_dev, (int)d->vfs_ino); + deleted = true; + } + + d->mode = st.st_mode; + d->uid = st.st_uid; + d->gid = st.st_gid; + + d->deleted = deleted; + +postprone: + return 0; + +out: + xfree(name); + return ret; +skip: + ret = 1; + goto out; +} + /* * Returns: < 0 on error, 0 if OK, 1 to skip the socket */ static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg *m, struct nlattr **tb) { - int len, ret; + int len; char *name; len = nla_len(tb[UNIX_DIAG_NAME]); @@ -544,87 +615,25 @@ static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg memcpy(name, nla_data(tb[UNIX_DIAG_NAME]), len); name[len] = '\0'; - if (name[0] != '\0') { + if (name[0]) { struct unix_diag_vfs *uv; - bool deleted = false; - char rpath[PATH_MAX]; - struct ns_id *ns; - struct stat st; - int mntns_root; if (!tb[UNIX_DIAG_VFS]) { pr_err("Bound socket w/o inode %#x\n", m->udiag_ino); goto skip; } - ns = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc); - if (!ns) { - ret = -ENOENT; - goto out; - } - - mntns_root = mntns_get_root_fd(ns); - if (mntns_root < 0) { - ret = -ENOENT; - goto out; - } - uv = RTA_DATA(tb[UNIX_DIAG_VFS]); - if (name[0] != '/') { - /* - * Relative names are be resolved later at first - * dump attempt. - */ - rel_name_desc_t *rel_name = xzalloc(sizeof(*rel_name)); - if (!rel_name) { - ret = -ENOMEM; - goto out; - } - rel_name->udiag_vfs_dev = uv->udiag_vfs_dev; - rel_name->udiag_vfs_ino = uv->udiag_vfs_ino; - - d->rel_name = rel_name; - goto postprone; - } - - snprintf(rpath, sizeof(rpath), ".%s", name); - if (fstatat(mntns_root, rpath, &st, 0)) { - if (errno != ENOENT) { - pr_warn("Can't stat socket %#x(%s), skipping: %m (err %d)\n", - m->udiag_ino, rpath, errno); - goto skip; - } - - pr_info("unix: Dropping path %s for unlinked sk %#x\n", - name, m->udiag_ino); - deleted = true; - } else if ((st.st_ino != uv->udiag_vfs_ino) || - !phys_stat_dev_match(st.st_dev, uv->udiag_vfs_dev, ns, name)) { - pr_info("unix: Dropping path %s for unlinked bound " - "sk %#x.%#x real %#x.%#x\n", - name, (int)st.st_dev, (int)st.st_ino, - (int)uv->udiag_vfs_dev, (int)uv->udiag_vfs_ino); - deleted = true; - } - - d->mode = st.st_mode; - d->uid = st.st_uid; - d->gid = st.st_gid; - - d->deleted = deleted; + d->vfs_dev = uv->udiag_vfs_dev; + d->vfs_ino = uv->udiag_vfs_ino; } -postprone: d->namelen = len; d->name = name; return 0; - -out: - xfree(name); - return ret; skip: - ret = 1; - goto out; + xfree(name); + return 1; } static int unix_collect_one(const struct unix_diag_msg *m, From 019ebec03ea2bae127bd2eedcb70a22c32f05d49 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Fri, 16 Mar 2018 20:24:26 +0300 Subject: [PATCH 1381/4375] unix: restore sockets on correct mount points Currently we restore all sockets in the root mount namespace, because we were not able to get any information about a mount point where a socket is bound. It is obviously incorrect in some cases. In 4.10 kernel, we added the SIOCUNIXFILE ioctl for unix sockets. This ioctl opens a file to which a socket is bound and returns a file descriptor. This new ioctl allows us to get mnt_id by reading fdinfo, and mnt_id is enough to find a proper mount point and a mount namespace. The logic of this patch is straight forward. On dump, we save mnt_id for sockets, on restore we find a mount namespace by mnt_id and restore this socket in its mount namespace. Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 114 ++++++++++++++++++++++++++++++++++--------- images/sk-unix.proto | 1 + 2 files changed, 92 insertions(+), 23 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 6a777bc31..6379c5ccb 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -224,6 +224,27 @@ int kerndat_socket_unix_file(void) return 0; } +static int get_mnt_id(int lfd, int *mnt_id) +{ + struct fdinfo_common fdinfo = { .mnt_id = -1 }; + int ret, fd; + + fd = ioctl(lfd, SIOCUNIXFILE); + if (fd < 0) { + pr_perror("Unable to get a socker file descriptor"); + return -1; + } + + ret = parse_fdinfo(fd, FD_TYPES__UND, &fdinfo); + close(fd); + if (ret < 0) + return -1; + + *mnt_id = fdinfo.mnt_id; + + return 0; +} + static int resolve_rel_name(u32 id, struct unix_sk_desc *sk, const struct fd_parms *p, char **pdir) { const char *dirs[] = { "cwd", "root" }; @@ -294,7 +315,7 @@ err: return -ENOENT; } -static int unix_resolve_name(u32 id, struct unix_sk_desc *d, +static int unix_resolve_name(int lfd, u32 id, struct unix_sk_desc *d, UnixSkEntry *ue, const struct fd_parms *p); static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p) { @@ -348,7 +369,7 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p) ue->opts = skopts; ue->uflags = 0; - if (unix_resolve_name(id, sk, ue, p)) + if (unix_resolve_name(lfd, id, sk, ue, p)) goto err; /* @@ -524,7 +545,7 @@ const struct fdtype_ops unix_dump_ops = { .dump = dump_one_unix_fd, }; -static int unix_resolve_name(u32 id, struct unix_sk_desc *d, +static int unix_resolve_name(int lfd, u32 id, struct unix_sk_desc *d, UnixSkEntry *ue, const struct fd_parms *p) { char *name = d->name; @@ -533,12 +554,22 @@ static int unix_resolve_name(u32 id, struct unix_sk_desc *d, struct ns_id *ns; struct stat st; int mntns_root; - int ret; + int ret, mnt_id; if (d->namelen == 0 || name[0] == '\0') return 0; - ns = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc); + if (kdat.sk_unix_file && (root_ns_mask & CLONE_NEWNS)) { + if (get_mnt_id(lfd, &mnt_id)) + return -1; + ue->mnt_id = mnt_id; + ue->has_mnt_id = mnt_id; + } + + if (ue->mnt_id >= 0) + ns = lookup_nsid_by_mnt_id(ue->mnt_id); + else + ns = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc); if (!ns) { ret = -ENOENT; goto out; @@ -1083,12 +1114,17 @@ static int restore_sk_common(int fd, struct unix_sk_info *ui) return 0; } -static void revert_unix_sk_cwd(int *prev_cwd_fd, int *root_fd) +static int revert_unix_sk_cwd(int *prev_cwd_fd, int *root_fd, int *ns_fd) { + int ret = 0; + + if (*ns_fd >= 0 && restore_ns(*ns_fd, &mnt_ns_desc)) + ret = -1; if (*root_fd >= 0) { if (fchdir(*root_fd) || chroot(".")) pr_perror("Can't revert root directory"); close_safe(root_fd); + ret = -1; } if (prev_cwd_fd && *prev_cwd_fd >= 0) { if (fchdir(*prev_cwd_fd)) @@ -1097,14 +1133,38 @@ static void revert_unix_sk_cwd(int *prev_cwd_fd, int *root_fd) pr_debug("Reverted working dir\n"); close(*prev_cwd_fd); *prev_cwd_fd = -1; + ret = -1; } + + return ret; } -static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd, int *prev_root_fd) +static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd, + int *prev_root_fd, int *prev_mntns_fd) { - static struct ns_id *root = NULL; + static struct ns_id *root = NULL, *ns; int fd; + if (prev_mntns_fd && ui->name[0] && ui->ue->mnt_id >= 0) { + struct ns_id *mntns = lookup_nsid_by_mnt_id(ui->ue->mnt_id); + int ns_fd; + + if (mntns == NULL) { + pr_err("Unable to find the %d mount\n", ui->ue->mnt_id); + return -1; + } + + ns_fd = fdstore_get(mntns->mnt.nsfd_id); + if (ns_fd < 0) + return -1; + + if (switch_ns_by_fd(ns_fd, &mnt_ns_desc, prev_mntns_fd)) + return -1; + + set_proc_self_fd(-1); + close(ns_fd); + } + *prev_cwd_fd = open(".", O_RDONLY); if (*prev_cwd_fd < 0) { pr_perror("Can't open current dir"); @@ -1112,15 +1172,23 @@ static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd, int *prev } if (prev_root_fd && (root_ns_mask & CLONE_NEWNS)) { - if (root == NULL) - root = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc); + if (ui->ue->mnt_id >= 0) { + ns = lookup_nsid_by_mnt_id(ui->ue->mnt_id); + if (ns == NULL) + goto err; + } else { + if (root == NULL) + root = lookup_ns_by_id(root_item->ids->mnt_ns_id, + &mnt_ns_desc); + ns = root; + } *prev_root_fd = open("/", O_RDONLY); if (*prev_root_fd < 0) { pr_perror("Can't open current root"); goto err; } - fd = fdstore_get(root->mnt.root_fd_id); + fd = fdstore_get(ns->mnt.root_fd_id); if (fd < 0) { pr_err("Can't get root fd\n"); goto err; @@ -1159,7 +1227,7 @@ static int post_open_standalone(struct file_desc *d, int fd) struct unix_sk_info *ui; struct unix_sk_info *peer; struct sockaddr_un addr; - int cwd_fd = -1, root_fd = -1; + int cwd_fd = -1, root_fd = -1, ns_fd = -1; ui = container_of(d, struct unix_sk_info, d); BUG_ON((ui->flags & (USK_PAIR_MASTER | USK_PAIR_SLAVE)) || @@ -1188,19 +1256,19 @@ static int post_open_standalone(struct file_desc *d, int fd) pr_info("\tConnect %#x to %#x\n", ui->ue->ino, peer->ue->ino); - if (prep_unix_sk_cwd(peer, &cwd_fd, NULL)) + if (prep_unix_sk_cwd(peer, &cwd_fd, NULL, &ns_fd)) return -1; if (connect(fd, (struct sockaddr *)&addr, sizeof(addr.sun_family) + peer->ue->name.len) < 0) { pr_perror("Can't connect %#x socket", ui->ue->ino); - revert_unix_sk_cwd(&cwd_fd, &root_fd); + revert_unix_sk_cwd(&cwd_fd, &root_fd, &ns_fd); return -1; } ui->is_connected = true; - revert_unix_sk_cwd(&cwd_fd, &root_fd); + revert_unix_sk_cwd(&cwd_fd, &root_fd, &ns_fd); restore_queue: if (peer->queuer == ui && @@ -1216,7 +1284,7 @@ restore_sk_common: static int bind_unix_sk(int sk, struct unix_sk_info *ui) { struct sockaddr_un addr; - int cwd_fd = -1, root_fd = -1; + int cwd_fd = -1, root_fd = -1, ns_fd = -1; int ret = -1; if (ui->ue->name.len == 0) @@ -1238,10 +1306,10 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) addr.sun_family = AF_UNIX; memcpy(&addr.sun_path, ui->name, ui->ue->name.len); - if (prep_unix_sk_cwd(ui, &cwd_fd, NULL)) - return -1; - if (ui->ue->name.len) { + if (ui->name[0] && prep_unix_sk_cwd(ui, &cwd_fd, NULL, &ns_fd)) + return -1; + ret = bind(sk, (struct sockaddr *)&addr, sizeof(addr.sun_family) + ui->ue->name.len); if (ret < 0) { @@ -1324,7 +1392,7 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) ret = 0; done: - revert_unix_sk_cwd(&cwd_fd, &root_fd); + revert_unix_sk_cwd(&cwd_fd, &root_fd, &ns_fd); return ret; } @@ -1651,12 +1719,12 @@ static struct file_desc_ops unix_desc_ops = { */ static void unlink_stale(struct unix_sk_info *ui) { - int ret, cwd_fd = -1, root_fd = -1; + int ret, cwd_fd = -1, root_fd = -1, ns_fd = -1; if (ui->name[0] == '\0' || (ui->ue->uflags & USK_EXTERN)) return; - if (prep_unix_sk_cwd(ui, &cwd_fd, &root_fd)) + if (prep_unix_sk_cwd(ui, &cwd_fd, &root_fd, NULL)) return; ret = unlinkat(AT_FDCWD, ui->name, 0) ? -1 : 0; @@ -1666,7 +1734,7 @@ static void unlink_stale(struct unix_sk_info *ui) ui->name ? (ui->name[0] ? ui->name : &ui->name[1]) : "-", ui->name_dir ? ui->name_dir : "-"); } - revert_unix_sk_cwd(&cwd_fd, &root_fd); + revert_unix_sk_cwd(&cwd_fd, &root_fd, &ns_fd); } static void try_resolve_unix_peer(struct unix_sk_info *ui); diff --git a/images/sk-unix.proto b/images/sk-unix.proto index 2a33fe220..c59644f6e 100644 --- a/images/sk-unix.proto +++ b/images/sk-unix.proto @@ -50,4 +50,5 @@ message unix_sk_entry { optional bool deleted = 15; optional uint32 ns_id = 16; + optional sint32 mnt_id = 17 [default = -1]; } From 3347c6efeca307d98e1cf301cdfad68f3ce49750 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Fri, 16 Mar 2018 20:24:27 +0300 Subject: [PATCH 1382/4375] unix: split bind_unix_sk() for readability Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 79 ++++++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 6379c5ccb..fb0e545b0 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1281,6 +1281,49 @@ restore_sk_common: return restore_sk_common(fd, ui); } +static int bind_deleted_unix_sk(int sk, struct unix_sk_info *ui, + struct sockaddr_un *addr) +{ + char temp[PATH_MAX]; + int ret; + + pr_info("found duplicate unix socket bound at %s\n", addr->sun_path); + + ret = snprintf(temp, sizeof(temp), + "%s-%s-%d", addr->sun_path, "criu-temp", getpid()); + /* this shouldn't happen, since sun_addr is only 108 chars long */ + if (ret < 0 || ret >= sizeof(temp)) { + pr_err("snprintf of %s failed?\n", addr->sun_path); + return -1;; + } + + ret = rename(addr->sun_path, temp); + if (ret < 0) { + pr_perror("couldn't move socket for binding"); + return -1; + } + + ret = bind(sk, (struct sockaddr *)addr, + sizeof(addr->sun_family) + ui->ue->name.len); + if (ret < 0) { + pr_perror("Can't bind socket after move"); + return -1;; + } + + ret = rename(temp, addr->sun_path); + if (ret < 0) { + pr_perror("couldn't move socket back"); + return -1; + } + + /* we've handled the deleted-ness of this + * socket and we don't want to delete it later + * since it's not /this/ socket. + */ + ui->ue->deleted = false; + return 0; +} + static int bind_unix_sk(int sk, struct unix_sk_info *ui) { struct sockaddr_un addr; @@ -1314,42 +1357,8 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) sizeof(addr.sun_family) + ui->ue->name.len); if (ret < 0) { if (ui->ue->has_deleted && ui->ue->deleted && errno == EADDRINUSE) { - char temp[PATH_MAX]; - - pr_info("found duplicate unix socket bound at %s\n", addr.sun_path); - - ret = snprintf(temp, sizeof(temp), "%s-%s-%d", addr.sun_path, "criu-temp", getpid()); - /* this shouldn't happen, since sun_addr is only 108 chars long */ - if (ret < 0 || ret >= sizeof(temp)) { - pr_err("snprintf of %s failed?\n", addr.sun_path); + if (bind_deleted_unix_sk(sk, ui, &addr)) goto done; - } - - ret = rename(addr.sun_path, temp); - if (ret < 0) { - pr_perror("couldn't move socket for binding"); - goto done; - } - - ret = bind(sk, (struct sockaddr *)&addr, - sizeof(addr.sun_family) + ui->ue->name.len); - if (ret < 0) { - pr_perror("Can't bind socket after move"); - goto done; - } - - ret = rename(temp, addr.sun_path); - if (ret < 0) { - pr_perror("couldn't move socket back"); - goto done; - } - - /* we've handled the deleted-ness of this - * socket and we don't want to delete it later - * since it's not /this/ socket. - */ - ui->ue->deleted = false; - } else { pr_perror("Can't bind socket"); goto done; From c1ad0f8f6dff8280688152c1e2ad4204c97f9044 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Fri, 16 Mar 2018 20:24:28 +0300 Subject: [PATCH 1383/4375] unit: don't check ui->ue->name.len twice in bind_unix_sk() Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 76 ++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index fb0e545b0..7bcc9c50a 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1349,51 +1349,49 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) addr.sun_family = AF_UNIX; memcpy(&addr.sun_path, ui->name, ui->ue->name.len); - if (ui->ue->name.len) { - if (ui->name[0] && prep_unix_sk_cwd(ui, &cwd_fd, NULL, &ns_fd)) - return -1; + if (ui->name[0] && prep_unix_sk_cwd(ui, &cwd_fd, NULL, &ns_fd)) + return -1; - ret = bind(sk, (struct sockaddr *)&addr, - sizeof(addr.sun_family) + ui->ue->name.len); - if (ret < 0) { - if (ui->ue->has_deleted && ui->ue->deleted && errno == EADDRINUSE) { - if (bind_deleted_unix_sk(sk, ui, &addr)) - goto done; - } else { - pr_perror("Can't bind socket"); + ret = bind(sk, (struct sockaddr *)&addr, + sizeof(addr.sun_family) + ui->ue->name.len); + if (ret < 0) { + if (ui->ue->has_deleted && ui->ue->deleted && errno == EADDRINUSE) { + if (bind_deleted_unix_sk(sk, ui, &addr)) goto done; - } - } - - if (*ui->name && ui->ue->file_perms) { - FilePermsEntry *perms = ui->ue->file_perms; - char fname[PATH_MAX]; - - if (ui->ue->name.len >= sizeof(fname)) { - pr_err("The file name is too long\n"); - goto done; - } - - memcpy(fname, ui->name, ui->ue->name.len); - fname[ui->ue->name.len] = '\0'; - - if (fchownat(AT_FDCWD, fname, perms->uid, perms->gid, 0) == -1) { - pr_perror("Unable to change file owner and group"); - goto done; - } - - if (fchmodat(AT_FDCWD, fname, perms->mode, 0) == -1) { - pr_perror("Unable to change file mode bits"); - goto done; - } - } - - if (ui->ue->deleted && unlink((char *)ui->ue->name.data) < 0) { - pr_perror("failed to unlink %s", ui->ue->name.data); + } else { + pr_perror("Can't bind socket"); goto done; } } + if (*ui->name && ui->ue->file_perms) { + FilePermsEntry *perms = ui->ue->file_perms; + char fname[PATH_MAX]; + + if (ui->ue->name.len >= sizeof(fname)) { + pr_err("The file name is too long\n"); + goto done; + } + + memcpy(fname, ui->name, ui->ue->name.len); + fname[ui->ue->name.len] = '\0'; + + if (fchownat(AT_FDCWD, fname, perms->uid, perms->gid, 0) == -1) { + pr_perror("Unable to change file owner and group"); + goto done; + } + + if (fchmodat(AT_FDCWD, fname, perms->mode, 0) == -1) { + pr_perror("Unable to change file mode bits"); + goto done; + } + } + + if (ui->ue->deleted && unlink((char *)ui->ue->name.data) < 0) { + pr_perror("failed to unlink %s", ui->ue->name.data); + goto done; + } + if (ui->ue->state != TCP_LISTEN) { ui->bound = 1; wake_connected_sockets(ui); From 1b52bb436edc951b7c3088a7d3d0badc22ce5b6e Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Fri, 16 Mar 2018 20:24:29 +0300 Subject: [PATCH 1384/4375] unix: fix an error code in bind_unix_sk() Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 7bcc9c50a..b898f815d 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1328,7 +1328,7 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) { struct sockaddr_un addr; int cwd_fd = -1, root_fd = -1, ns_fd = -1; - int ret = -1; + int ret, exit_code = -1; if (ui->ue->name.len == 0) return 0; @@ -1341,8 +1341,7 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) * restored we should walk those temp names and rename * some of them back to real ones. */ - ret = 0; - goto done; + return 0; } memset(&addr, 0, sizeof(addr)); @@ -1397,10 +1396,10 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) wake_connected_sockets(ui); } - ret = 0; + exit_code = 0; done: revert_unix_sk_cwd(&cwd_fd, &root_fd, &ns_fd); - return ret; + return exit_code; } static int post_open_interconnected_master(struct unix_sk_info *ui) From faf4f72a1f2914a213c86b25364802d70d02d57d Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Fri, 16 Mar 2018 20:24:30 +0300 Subject: [PATCH 1385/4375] unix: split dump_external_sockets() for readability Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 75 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index b898f815d..7fd55f7ab 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -769,48 +769,63 @@ int unix_receive_one(struct nlmsghdr *h, struct ns_id *ns, void *arg) return unix_collect_one(m, tb, ns); } +static int __dump_external_socket(struct unix_sk_desc *sk, + struct unix_sk_desc *peer) +{ + int ret; + + ret = run_plugins(DUMP_UNIX_SK, sk->fd, sk->sd.ino); + if (ret < 0 && ret != -ENOTSUP) + return -1; + + if (ret == 0) { + sk->ue->uflags |= USK_CALLBACK; + return 0; + } + + if (unix_sk_exception_lookup_id(sk->sd.ino)) { + pr_debug("found exception for unix name-less external socket.\n"); + return 0; + } + + /* Legacy -x|--ext-unix-sk option handling */ + if (!opts.ext_unix_sk) { + show_one_unix("Runaway socket", peer); + pr_err("External socket is used. " + "Consider using --" USK_EXT_PARAM " option.\n"); + return -1; + } + + if (peer->type != SOCK_DGRAM) { + show_one_unix("Ext stream not supported", peer); + pr_err("Can't dump half of stream unix connection.\n"); + return -1; + } + + if (!peer->name) { + show_one_unix("Ext dgram w/o name", peer); + pr_err("Can't dump name-less external socket.\n"); + pr_err("%d\n", sk->fd); + return -1; + } + + return 0; +} + static int dump_external_sockets(struct unix_sk_desc *peer) { struct unix_sk_desc *sk; - int ret; while (!list_empty(&peer->peer_list)) { sk = list_first_entry(&peer->peer_list, struct unix_sk_desc, peer_node); - ret = run_plugins(DUMP_UNIX_SK, sk->fd, sk->sd.ino); - if (ret == -ENOTSUP) { - if (unix_sk_exception_lookup_id(sk->sd.ino)) { - pr_debug("found exception for unix name-less external socket.\n"); - } else { - /* Legacy -x|--ext-unix-sk option handling */ - if (!opts.ext_unix_sk) { - show_one_unix("Runaway socket", peer); - pr_err("External socket is used. " - "Consider using --" USK_EXT_PARAM " option.\n"); - return -1; - } - - if (peer->type != SOCK_DGRAM) { - show_one_unix("Ext stream not supported", peer); - pr_err("Can't dump half of stream unix connection.\n"); - return -1; - } - - if (!peer->name) { - show_one_unix("Ext dgram w/o name", peer); - pr_err("Can't dump name-less external socket.\n"); - pr_err("%d\n", sk->fd); - return -1; - } - } - } else if (ret < 0) + if (__dump_external_socket(sk, peer)) return -1; - else - sk->ue->uflags |= USK_CALLBACK; if (write_unix_entry(sk)) return -1; close_safe(&sk->fd); + list_del_init(&sk->peer_node); } From 4960d44129cf8c464285b480a16571ec50a01c16 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 23 Mar 2018 01:01:37 +0300 Subject: [PATCH 1386/4375] zdtm.py: fix a logic about determing a test flavor in a error case The get() method requires a key and now we are using an index. That will never work correctly as it is now. Acked-by: Adrian Reber Reported-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/zdtm.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 2e0f2b64e..b25de3a3a 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -282,6 +282,7 @@ class userns_flavor(ns_flavor): flavors = {'h': host_flavor, 'ns': ns_flavor, 'uns': userns_flavor} +flavors_codes = dict(zip(xrange(len(flavors)), sorted(flavors.keys()))) # # Helpers @@ -289,11 +290,11 @@ flavors = {'h': host_flavor, 'ns': ns_flavor, 'uns': userns_flavor} def encode_flav(f): - return (flavors.keys().index(f) + 128) + return sorted(flavors.keys()).index(f) + 128 def decode_flav(i): - return flavors.get(i - 128, "unknown") + return flavors_codes.get(i - 128, "unknown") def tail(path): From 6a66b87e12b15089f5526c72e757274d2cd5cc16 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Thu, 8 Mar 2018 01:43:07 +0300 Subject: [PATCH 1387/4375] zdtm: check an exit code of a straced restore Currently zdtm doesn't detect when restore failed, if it is executed with strace. With this patch, fake-restore.sh creates a test file, and zdtm is able to distinguish when restore failed. Signed-off-by: Andrei Vagin --- scripts/fake-restore.sh | 1 + test/zdtm.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/fake-restore.sh b/scripts/fake-restore.sh index e3c368614..2728fb30d 100755 --- a/scripts/fake-restore.sh +++ b/scripts/fake-restore.sh @@ -8,6 +8,7 @@ # criu restore --action-script $(pwd)/scripts/fake-restore.sh # if [ "$CRTOOLS_SCRIPT_ACTION" == "post-restore" ]; then + touch restore-succeeded exit 1 else exit 0 diff --git a/test/zdtm.py b/test/zdtm.py index b25de3a3a..d61e71105 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -959,7 +959,8 @@ class criu: grep_errors(os.path.join(__ddir, log)) if ret == 0: return - if self.__test.blocking() or (self.__sat and action == 'restore'): + rst_succeeded = os.access(os.path.join(__ddir, "restore-succeeded"), os.F_OK) + if self.__test.blocking() or (self.__sat and action == 'restore' and rst_succeeded): raise test_fail_expected_exc(action) else: raise test_fail_exc("CRIU %s" % action) From 6115934bce8006293cdd2f0de458d263d4507ff7 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 25 Mar 2018 16:27:21 +0300 Subject: [PATCH 1388/4375] lazy-pages: explicitly set process exited condition Instead of relying on length of various lists add a boolean variable to lazy_pages_info to make it clean when the process has exited Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 088e3ea7f..62faa2f2f 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -78,6 +78,7 @@ struct lp_req { struct lazy_pages_info { int pid; + bool exited; struct list_head iovs; struct list_head reqs; @@ -709,6 +710,7 @@ static int handle_exit(struct lazy_pages_info *lpi) free_iovs(lpi); close(lpi->lpfd.fd); lpi->lpfd.fd = 0; + lpi->exited = true; /* keep it for tracking in-flight requests and for the summary */ list_move_tail(&lpi->l, &lpis); @@ -767,6 +769,14 @@ static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr lpi = container_of(pr, struct lazy_pages_info, pr); + /* + * The process may exit while we still have requests in + * flight. We just drop the request and the received data in + * this case to avoid making uffd unhappy + */ + if (lpi->exited) + return 0; + list_for_each_entry(req, &lpi->reqs, l) { if (req->img_addr == img_addr) { addr = req->addr; @@ -776,14 +786,6 @@ static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr } } - /* - * The process may exit while we still have requests in - * flight. We just drop the request and the received data in - * this case to avoid making uffd unhappy - */ - if (list_empty(&lpi->iovs)) - return 0; - BUG_ON(!addr); if (uffd_copy(lpi, addr, nr)) From eff067a33b5849c579387bb22f1c8b9a1e59541c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 25 Mar 2018 16:27:22 +0300 Subject: [PATCH 1389/4375] lazy-pages: split_iov: always create the new iov above the one being split Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 62faa2f2f..16637d31f 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -390,7 +390,7 @@ static struct lazy_iov *find_iov(struct lazy_pages_info *lpi, return NULL; } -static int split_iov(struct lazy_iov *iov, unsigned long addr, bool new_below) +static int split_iov(struct lazy_iov *iov, unsigned long addr) { struct lazy_iov *new; @@ -398,21 +398,11 @@ static int split_iov(struct lazy_iov *iov, unsigned long addr, bool new_below) if (!new) return -1; - if (new_below) { - new->base = iov->base; - new->img_base = iov->img_base; - new->len = addr - iov->base; - iov->base = addr; - iov->img_base += new->len; - iov->len -= new->len; - list_add_tail(&new->l, &iov->l); - } else { - new->base = addr; - new->img_base = iov->img_base + addr - iov->base; - new->len = iov->len - (addr - iov->base); - iov->len -= new->len; - list_add(&new->l, &iov->l); - } + new->base = addr; + new->img_base = iov->img_base + addr - iov->base; + new->len = iov->len - (addr - iov->base); + iov->len -= new->len; + list_add(&new->l, &iov->l); return 0; } @@ -485,7 +475,7 @@ static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) iov->img_base += len; iov->len -= len; } else { - if (split_iov(iov, addr + len, false)) + if (split_iov(iov, addr + len)) return -1; iov->len -= len; } @@ -533,14 +523,18 @@ static int remap_iovs(struct lazy_pages_info *lpi, unsigned long from, from = iov->base; } - if (from > iov->base) - if (split_iov(iov, from, true)) - return -1; - if (from + len < iov_end) - if (split_iov(iov, from + len, false)) + if (from > iov->base) { + if (split_iov(iov, from)) return -1; + list_safe_reset_next(iov, n, l); + continue; + } - list_safe_reset_next(iov, n, l); + if (from + len < iov_end) { + if (split_iov(iov, from + len)) + return -1; + list_safe_reset_next(iov, n, l); + } /* here we have iov->base = from, iov_end <= from + len */ from = iov_end; From 8e2f957468498ba29fffb2fe32fd3451dd21f296 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 25 Mar 2018 16:27:23 +0300 Subject: [PATCH 1390/4375] lazy-pages: lazy_iov: use end instead of len Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 16637d31f..b0031c621 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -64,8 +64,8 @@ static mutex_t *lazy_sock_mutex; struct lazy_iov { struct list_head l; unsigned long base; /* run-time start address, tracks remaps */ + unsigned long end; /* run-time end address, tracks remaps */ unsigned long img_base; /* start address at the dump time */ - unsigned long len; bool queued; }; @@ -384,7 +384,7 @@ static struct lazy_iov *find_iov(struct lazy_pages_info *lpi, struct lazy_iov *iov; list_for_each_entry(iov, &lpi->iovs, l) - if (addr >= iov->base && addr < iov->base + iov->len) + if (addr >= iov->base && addr < iov->end) return iov; return NULL; @@ -400,8 +400,8 @@ static int split_iov(struct lazy_iov *iov, unsigned long addr) new->base = addr; new->img_base = iov->img_base + addr - iov->base; - new->len = iov->len - (addr - iov->base); - iov->len -= new->len; + new->end = iov->end; + iov->end = addr; list_add(&new->l, &iov->l); return 0; @@ -419,12 +419,12 @@ static int copy_iovs(struct lazy_pages_info *src, struct lazy_pages_info *dst) new->base = iov->base; new->img_base = iov->img_base; - new->len = iov->len; + new->end = iov->end; list_add_tail(&new->l, &dst->iovs); - if (new->len > max_iov_len) - max_iov_len = new->len; + if (new->end - new->base > max_iov_len) + max_iov_len = new->end - new->base; } if (posix_memalign(&dst->buf, PAGE_SIZE, max_iov_len)) @@ -447,7 +447,7 @@ static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) list_for_each_entry_safe(iov, n, &lpi->iovs, l) { unsigned long start = iov->base; - unsigned long end = start + iov->len; + unsigned long end = iov->end; if (len <= 0 || addr + len < start) break; @@ -473,11 +473,10 @@ static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) if (addr == start) { iov->base += len; iov->img_base += len; - iov->len -= len; } else { if (split_iov(iov, addr + len)) return -1; - iov->len -= len; + iov->end = addr; } break; } @@ -492,7 +491,7 @@ static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) list_del(&iov->l); xfree(iov); } else { - iov->len -= (end - addr); + iov->end = addr; } len -= (end - addr); @@ -510,9 +509,7 @@ static int remap_iovs(struct lazy_pages_info *lpi, unsigned long from, LIST_HEAD(remaps); list_for_each_entry_safe(iov, n, &lpi->iovs, l) { - unsigned long iov_end = iov->base + iov->len; - - if (from >= iov_end) + if (from >= iov->end) continue; if (len <= 0 || from + len < iov->base) @@ -530,16 +527,17 @@ static int remap_iovs(struct lazy_pages_info *lpi, unsigned long from, continue; } - if (from + len < iov_end) { + if (from + len < iov->end) { if (split_iov(iov, from + len)) return -1; list_safe_reset_next(iov, n, l); } - /* here we have iov->base = from, iov_end <= from + len */ - from = iov_end; - len -= iov->len; + /* here we have iov->base = from, iov->end <= from + len */ + from = iov->end; + len -= iov->end - iov->base; iov->base += off; + iov->end += off; list_move_tail(&iov->l, &remaps); } @@ -602,7 +600,7 @@ static int collect_iovs(struct lazy_pages_info *lpi) len = min_t(uint64_t, end, vma->end) - start; iov->base = start; iov->img_base = start; - iov->len = len; + iov->end = iov->base + len; list_add_tail(&iov->l, &lpi->iovs); if (len > max_iov_len) @@ -863,7 +861,7 @@ static bool is_iov_queued(struct lazy_pages_info *lpi, struct lazy_iov *iov) struct lp_req *req; list_for_each_entry(req, &lpi->reqs, l) - if (req->addr >= iov->base && req->addr < iov->base + iov->len) + if (req->addr >= iov->base && req->addr < iov->end) return true; return false; @@ -882,18 +880,18 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) if (is_iov_queued(lpi, iov)) return 0; - nr_pages = iov->len / PAGE_SIZE; - req = xzalloc(sizeof(*req)); if (!req) return -1; req->addr = iov->base; req->img_addr = iov->img_base; - req->len = iov->len; + req->len = iov->end - iov->base; list_add(&req->l, &lpi->reqs); iov->queued = true; + nr_pages = req->len / PAGE_SIZE; + err = uffd_handle_pages(lpi, req->img_addr, nr_pages, PR_ASYNC | PR_ASAP); if (err < 0) { lp_err(lpi, "Error during UFFD copy\n"); From 971e395e6770e2837dfcc74b5545ae63b43dc437 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 25 Mar 2018 16:27:24 +0300 Subject: [PATCH 1391/4375] lazy-pages: rename iov->*base to iov->*start Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 64 ++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index b0031c621..77625d582 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -63,9 +63,9 @@ static mutex_t *lazy_sock_mutex; struct lazy_iov { struct list_head l; - unsigned long base; /* run-time start address, tracks remaps */ + unsigned long start; /* run-time start address, tracks remaps */ unsigned long end; /* run-time end address, tracks remaps */ - unsigned long img_base; /* start address at the dump time */ + unsigned long img_start; /* start address at the dump time */ bool queued; }; @@ -384,7 +384,7 @@ static struct lazy_iov *find_iov(struct lazy_pages_info *lpi, struct lazy_iov *iov; list_for_each_entry(iov, &lpi->iovs, l) - if (addr >= iov->base && addr < iov->end) + if (addr >= iov->start && addr < iov->end) return iov; return NULL; @@ -398,8 +398,8 @@ static int split_iov(struct lazy_iov *iov, unsigned long addr) if (!new) return -1; - new->base = addr; - new->img_base = iov->img_base + addr - iov->base; + new->start = addr; + new->img_start = iov->img_start + addr - iov->start; new->end = iov->end; iov->end = addr; list_add(&new->l, &iov->l); @@ -417,14 +417,14 @@ static int copy_iovs(struct lazy_pages_info *src, struct lazy_pages_info *dst) if (!new) return -1; - new->base = iov->base; - new->img_base = iov->img_base; + new->start = iov->start; + new->img_start = iov->img_start; new->end = iov->end; list_add_tail(&new->l, &dst->iovs); - if (new->end - new->base > max_iov_len) - max_iov_len = new->end - new->base; + if (new->end - new->start > max_iov_len) + max_iov_len = new->end - new->start; } if (posix_memalign(&dst->buf, PAGE_SIZE, max_iov_len)) @@ -446,7 +446,7 @@ static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) struct lazy_iov *iov, *n; list_for_each_entry_safe(iov, n, &lpi->iovs, l) { - unsigned long start = iov->base; + unsigned long start = iov->start; unsigned long end = iov->end; if (len <= 0 || addr + len < start) @@ -464,15 +464,15 @@ static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) /* * The range completely fits into the current IOV. - * If addr equals iov_base we just "drop" the + * If addr equals iov_start we just "drop" the * beginning of the IOV. Otherwise, we make the IOV to * end at addr, and add a new IOV start starts at * addr + len. */ if (addr + len < end) { if (addr == start) { - iov->base += len; - iov->img_base += len; + iov->start += len; + iov->img_start += len; } else { if (split_iov(iov, addr + len)) return -1; @@ -483,7 +483,7 @@ static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) /* * The range spawns beyond the end of the current IOV. - * If addr equals iov_base we just "drop" the entire + * If addr equals iov_start we just "drop" the entire * IOV. Otherwise, we cut the beginning of the IOV * and continue to the next one with the updated range */ @@ -512,15 +512,15 @@ static int remap_iovs(struct lazy_pages_info *lpi, unsigned long from, if (from >= iov->end) continue; - if (len <= 0 || from + len < iov->base) + if (len <= 0 || from + len < iov->start) break; - if (from < iov->base) { - len -= (iov->base - from); - from = iov->base; + if (from < iov->start) { + len -= (iov->start - from); + from = iov->start; } - if (from > iov->base) { + if (from > iov->start) { if (split_iov(iov, from)) return -1; list_safe_reset_next(iov, n, l); @@ -533,22 +533,22 @@ static int remap_iovs(struct lazy_pages_info *lpi, unsigned long from, list_safe_reset_next(iov, n, l); } - /* here we have iov->base = from, iov->end <= from + len */ + /* here we have iov->start = from, iov->end <= from + len */ from = iov->end; - len -= iov->end - iov->base; - iov->base += off; + len -= iov->end - iov->start; + iov->start += off; iov->end += off; list_move_tail(&iov->l, &remaps); } list_for_each_entry_safe(iov, n, &remaps, l) { list_for_each_entry(p, &lpi->iovs, l) { - if (iov->base < p->base) { + if (iov->start < p->start) { list_move_tail(&iov->l, &p->l); break; } if (list_is_last(&p->l, &lpi->iovs) && - iov->base > p->base) { + iov->start > p->start) { list_move(&iov->l, &p->l); break; } @@ -598,9 +598,9 @@ static int collect_iovs(struct lazy_pages_info *lpi) goto free_iovs; len = min_t(uint64_t, end, vma->end) - start; - iov->base = start; - iov->img_base = start; - iov->end = iov->base + len; + iov->start = start; + iov->img_start = start; + iov->end = iov->start + len; list_add_tail(&iov->l, &lpi->iovs); if (len > max_iov_len) @@ -861,7 +861,7 @@ static bool is_iov_queued(struct lazy_pages_info *lpi, struct lazy_iov *iov) struct lp_req *req; list_for_each_entry(req, &lpi->reqs, l) - if (req->addr >= iov->base && req->addr < iov->end) + if (req->addr >= iov->start && req->addr < iov->end) return true; return false; @@ -884,9 +884,9 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) if (!req) return -1; - req->addr = iov->base; - req->img_addr = iov->img_base; - req->len = iov->end - iov->base; + req->addr = iov->start; + req->img_addr = iov->img_start; + req->len = iov->end - iov->start; list_add(&req->l, &lpi->reqs); iov->queued = true; @@ -1034,7 +1034,7 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) if (!req) return -1; req->addr = address; - req->img_addr = iov->img_base + (address - iov->base); + req->img_addr = iov->img_start + (address - iov->start); req->len = PAGE_SIZE; list_add(&req->l, &lpi->reqs); From cbee7c04e75ff78b01bd9ae08325353944e528f2 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 25 Mar 2018 16:27:25 +0300 Subject: [PATCH 1392/4375] lazy-pages: rework requests queueing We already have a queue for the requested memory ranges which contains 'lp_req' objects. These objects hold the same information as the lazy_iov: start address of the range, end address and the address that the range had at the dump time. Rather than keep this information twice and use double bookkeeping, we can extract the requested range from lpi->iovs and move it to lpi->reqs. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 99 +++++++++++++++++++++-------------------------------- 1 file changed, 39 insertions(+), 60 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 77625d582..c7f79b2c9 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -66,14 +66,6 @@ struct lazy_iov { unsigned long start; /* run-time start address, tracks remaps */ unsigned long end; /* run-time end address, tracks remaps */ unsigned long img_start; /* start address at the dump time */ - bool queued; -}; - -struct lp_req { - unsigned long addr; /* actual #PF (or background) destination */ - unsigned long img_addr; /* the corresponding address at the dump time */ - unsigned long len; - struct list_head l; }; struct lazy_pages_info { @@ -135,6 +127,11 @@ static void free_iovs(struct lazy_pages_info *lpi) list_del(&p->l); xfree(p); } + + list_for_each_entry_safe(p, n, &lpi->reqs, l) { + list_del(&p->l); + xfree(p); + } } static void lpi_fini(struct lazy_pages_info *lpi) @@ -460,8 +457,6 @@ static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) addr = start; } - iov->queued = false; - /* * The range completely fits into the current IOV. * If addr equals iov_start we just "drop" the @@ -501,6 +496,25 @@ static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) return 0; } +static struct lazy_iov *extract_range(struct lazy_iov *iov, + unsigned long start, + unsigned long end) +{ + /* move the IOV tail into a new IOV */ + if (end < iov->end) + if (split_iov(iov, end)) + return NULL; + + if (start == iov->start) + return iov; + + /* after splitting the IOV head we'll need the ->next IOV */ + if (split_iov(iov, start)) + return NULL; + + return list_entry(iov->l.next, struct lazy_iov, l); +} + static int remap_iovs(struct lazy_pages_info *lpi, unsigned long from, unsigned long to, unsigned long len) { @@ -757,7 +771,7 @@ static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr { struct lazy_pages_info *lpi; unsigned long addr = 0; - struct lp_req *req; + struct lazy_iov *req; lpi = container_of(pr, struct lazy_pages_info, pr); @@ -770,8 +784,8 @@ static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr return 0; list_for_each_entry(req, &lpi->reqs, l) { - if (req->img_addr == img_addr) { - addr = req->addr; + if (req->img_start == img_addr) { + addr = req->start; list_del(&req->l); xfree(req); break; @@ -780,10 +794,7 @@ static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr BUG_ON(!addr); - if (uffd_copy(lpi, addr, nr)) - return -1; - - return drop_iovs(lpi, addr, nr * PAGE_SIZE); + return uffd_copy(lpi, addr, nr); } static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) @@ -847,52 +858,23 @@ static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr, static struct lazy_iov *first_pending_iov(struct lazy_pages_info *lpi) { - struct lazy_iov *iov; - - list_for_each_entry(iov, &lpi->iovs, l) - if (!iov->queued) - return iov; - - return NULL; -} - -static bool is_iov_queued(struct lazy_pages_info *lpi, struct lazy_iov *iov) -{ - struct lp_req *req; - - list_for_each_entry(req, &lpi->reqs, l) - if (req->addr >= iov->start && req->addr < iov->end) - return true; - - return false; + return list_first_entry(&lpi->iovs, struct lazy_iov, l); } static int handle_remaining_pages(struct lazy_pages_info *lpi) { struct lazy_iov *iov; - struct lp_req *req; int nr_pages, err; iov = first_pending_iov(lpi); if (!iov) return 0; - if (is_iov_queued(lpi, iov)) - return 0; + list_move(&iov->l, &lpi->reqs); - req = xzalloc(sizeof(*req)); - if (!req) - return -1; + nr_pages = (iov->end - iov->start) / PAGE_SIZE; - req->addr = iov->start; - req->img_addr = iov->img_start; - req->len = iov->end - iov->start; - list_add(&req->l, &lpi->reqs); - iov->queued = true; - - nr_pages = req->len / PAGE_SIZE; - - err = uffd_handle_pages(lpi, req->img_addr, nr_pages, PR_ASYNC | PR_ASAP); + err = uffd_handle_pages(lpi, iov->img_start, nr_pages, PR_ASYNC | PR_ASAP); if (err < 0) { lp_err(lpi, "Error during UFFD copy\n"); return -1; @@ -1003,10 +985,10 @@ static int complete_forks(int epollfd, struct epoll_event **events, int *nr_fds) static bool is_page_queued(struct lazy_pages_info *lpi, unsigned long addr) { - struct lp_req *req; + struct lazy_iov *req; list_for_each_entry(req, &lpi->reqs, l) - if (addr >= req->addr && addr < req->addr + req->len) + if (addr >= req->start && addr < req->end) return true; return false; @@ -1014,7 +996,6 @@ static bool is_page_queued(struct lazy_pages_info *lpi, unsigned long addr) static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) { - struct lp_req *req; struct lazy_iov *iov; __u64 address; int ret; @@ -1030,15 +1011,13 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) if (!iov) return uffd_zero(lpi, address, 1); - req = xzalloc(sizeof(*req)); - if (!req) + iov = extract_range(iov, address, address + PAGE_SIZE); + if (!iov) return -1; - req->addr = address; - req->img_addr = iov->img_start + (address - iov->start); - req->len = PAGE_SIZE; - list_add(&req->l, &lpi->reqs); - ret = uffd_handle_pages(lpi, req->img_addr, 1, PR_ASYNC | PR_ASAP); + list_move(&iov->l, &lpi->reqs); + + ret = uffd_handle_pages(lpi, iov->img_start, 1, PR_ASYNC | PR_ASAP); if (ret < 0) { lp_err(lpi, "Error during regular page copy\n"); return -1; From cc5aa7643857d76e44f562ab81f361b6ed10be6e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 25 Mar 2018 16:27:26 +0300 Subject: [PATCH 1393/4375] lazy-pages: rename first_pending_iov to pick_next_range The function anyway pick the next page range to transfer it's just doing it in very simple FIFO manner. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index c7f79b2c9..1233b3bd1 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -856,7 +856,7 @@ static int uffd_handle_pages(struct lazy_pages_info *lpi, __u64 address, int nr, return 0; } -static struct lazy_iov *first_pending_iov(struct lazy_pages_info *lpi) +static struct lazy_iov *pick_next_range(struct lazy_pages_info *lpi) { return list_first_entry(&lpi->iovs, struct lazy_iov, l); } @@ -866,7 +866,7 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) struct lazy_iov *iov; int nr_pages, err; - iov = first_pending_iov(lpi); + iov = pick_next_range(lpi); if (!iov) return 0; From 71a3f9aaee93027d2a64f65d6eddcce13cd20b45 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 25 Mar 2018 16:27:27 +0300 Subject: [PATCH 1394/4375] lazy-pages: rename handle_remaining_pages to xfer_pages The intention is to use this function for transferring all the pages that didn't cause a #PF. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 1233b3bd1..8bbfb5c64 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -861,7 +861,7 @@ static struct lazy_iov *pick_next_range(struct lazy_pages_info *lpi) return list_first_entry(&lpi->iovs, struct lazy_iov, l); } -static int handle_remaining_pages(struct lazy_pages_info *lpi) +static int xfer_pages(struct lazy_pages_info *lpi) { struct lazy_iov *iov; int nr_pages, err; @@ -1121,7 +1121,7 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) remaining = true; if (!list_empty(&lpi->iovs)) { - ret = handle_remaining_pages(lpi); + ret = xfer_pages(lpi); if (ret < 0) goto out; break; From b11f5796268e3f66c5ad41909916ca751c29f4bd Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 25 Mar 2018 16:27:28 +0300 Subject: [PATCH 1395/4375] lazy-pages: simplify background transfer logic First check if there are pages we need to transfer and only afterwards check if there are outstanding requests. Also, instead checking 'bool remaining' to see if there is more work to do we can simply check if all the lpi's have been already serviced. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 8bbfb5c64..14a7ab41b 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1092,8 +1092,6 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) int ret; for (;;) { - bool remaining = false; - ret = epoll_run_rfds(epollfd, events, nr_fds, poll_timeout); if (ret < 0) goto out; @@ -1112,23 +1110,21 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) poll_timeout = 0; list_for_each_entry_safe(lpi, n, &lpis, l) { - if (list_empty(&lpi->iovs) && list_empty(&lpi->reqs)) { - lazy_pages_summary(lpi); - list_del(&lpi->l); - lpi_fini(lpi); - continue; - } - - remaining = true; if (!list_empty(&lpi->iovs)) { ret = xfer_pages(lpi); if (ret < 0) goto out; break; } + + if (list_empty(&lpi->reqs)) { + lazy_pages_summary(lpi); + list_del(&lpi->l); + lpi_fini(lpi); + } } - if (!remaining) + if (list_empty(&lpis)) break; } From f68dcdde83640c73375044c5cd84aa047becbfd4 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 25 Mar 2018 16:27:29 +0300 Subject: [PATCH 1396/4375] lazy-pages: make complete_forks more robust The complete_forks function presumes that it always has a work to do because we assume that fork event is the only case when we drop out of epoll_run_rfds with positive return value. Teach complete_forks to bail out when there is no pending forks to process to allow exiting epoll_run_rfds for different reasons. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/uffd.c b/criu/uffd.c index 14a7ab41b..45c1df51d 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -965,6 +965,9 @@ static int complete_forks(int epollfd, struct epoll_event **events, int *nr_fds) { struct lazy_pages_info *lpi, *n; + if (list_empty(&pending_lpis)) + return 0; + list_for_each_entry(lpi, &pending_lpis, l) (*nr_fds)++; From 333005426fc9b1fac69832107bbd11610b57abc5 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 25 Mar 2018 16:27:30 +0300 Subject: [PATCH 1397/4375] lazy-pages: add ability to limit background transfer size Currently, once we get to transfer pages in the "background", we try to fetch the entire IOV at once. For large IOVs this may impact #PF latency for the #PF events occurred during the transfer. Let's add a simple heuristic for controlling size of the background transfers. Initially, the transfer will be limited to some default value. Every time we transfer a chunk we increase the transfer size until it reaches a pre-defined maximal size. A page fault event resets the background transfer size to its initial value. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index 45c1df51d..85c8a5c65 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -59,6 +59,15 @@ #define LAZY_PAGES_RESTORE_FINISHED 0x52535446 /* ReSTore Finished */ +/* + * Backround transfer parameters. + * The default xfer length is arbitraty set to 64Kbytes + * The limit of 4Mbytes matches the maximal chunk size we can have in + * a pipe in the page-server + */ +#define DEFAULT_XFER_LEN (64 << 10) +#define MAX_XFER_LEN (4 << 20) + static mutex_t *lazy_sock_mutex; struct lazy_iov { @@ -80,6 +89,7 @@ struct lazy_pages_info { struct page_read pr; + unsigned long xfer_len; /* in pages */ unsigned long total_pages; unsigned long copied_pages; @@ -115,6 +125,7 @@ static struct lazy_pages_info *lpi_init(void) INIT_LIST_HEAD(&lpi->reqs); INIT_LIST_HEAD(&lpi->l); lpi->lpfd.read_event = handle_uffd_event; + lpi->xfer_len = DEFAULT_XFER_LEN; return lpi; } @@ -861,19 +872,45 @@ static struct lazy_iov *pick_next_range(struct lazy_pages_info *lpi) return list_first_entry(&lpi->iovs, struct lazy_iov, l); } +/* + * This is very simple heurstics for backgroud transfer control. + * The idea is to transfer larger chunks when there is no page faults + * and drop the backgroud transfer size each time #PF occurs to some + * default value. The default is empirically set to 64Kbytes + */ +static void update_xfer_len(struct lazy_pages_info *lpi, bool pf) +{ + if (pf) + lpi->xfer_len = DEFAULT_XFER_LEN; + else + lpi->xfer_len += DEFAULT_XFER_LEN; + + if (lpi->xfer_len > MAX_XFER_LEN) + lpi->xfer_len = MAX_XFER_LEN; +} + static int xfer_pages(struct lazy_pages_info *lpi) { struct lazy_iov *iov; - int nr_pages, err; + unsigned int nr_pages; + unsigned long len; + int err; iov = pick_next_range(lpi); if (!iov) return 0; + len = min(iov->end - iov->start, lpi->xfer_len); + + iov = extract_range(iov, iov->start, iov->start + len); + if (!iov) + return -1; list_move(&iov->l, &lpi->reqs); nr_pages = (iov->end - iov->start) / PAGE_SIZE; + update_xfer_len(lpi, false); + err = uffd_handle_pages(lpi, iov->img_start, nr_pages, PR_ASYNC | PR_ASAP); if (err < 0) { lp_err(lpi, "Error during UFFD copy\n"); @@ -1020,6 +1057,8 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) list_move(&iov->l, &lpi->reqs); + update_xfer_len(lpi, true); + ret = uffd_handle_pages(lpi, iov->img_start, 1, PR_ASYNC | PR_ASAP); if (ret < 0) { lp_err(lpi, "Error during regular page copy\n"); From 13f955cdf97373276b822158cf900c54ba1e38fc Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 25 Mar 2018 16:27:31 +0300 Subject: [PATCH 1398/4375] lazy-pages: kill POLL_TIMEOUT In the current model we haven't started the background page transfer until POLL_TIMEOUT time has elapsed since the last uffd or socket event. If the restored process will do memory access one in (POLL_TIMEOUT - eplsilon) the filling of its memory can take ages. This patch changes them model in the following way: * poll for the events indefinitely until the restore is complete * the restore completion event causes reset of the poll timeout to zero and * starts the background transfers * after each transfer we return to check if there are any uffd events to handle Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 85c8a5c65..7a9e97e94 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1124,13 +1124,10 @@ static void lazy_pages_summary(struct lazy_pages_info *lpi) #endif } -#define POLL_TIMEOUT 1000 - static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) { struct lazy_pages_info *lpi, *n; - /* FIXME -- timeout should decrease over time... */ - int poll_timeout = POLL_TIMEOUT; + int poll_timeout = -1; int ret; for (;;) { @@ -1140,19 +1137,13 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) if (ret > 0) { if (complete_forks(epollfd, &events, &nr_fds)) return -1; - continue; + if (!restore_finished) + continue; } - /* don't start backround fetch before restore is finished */ - if (!restore_finished) - continue; - - if (poll_timeout) - pr_debug("Start handling remaining pages\n"); - poll_timeout = 0; list_for_each_entry_safe(lpi, n, &lpis, l) { - if (!list_empty(&lpi->iovs)) { + if (!list_empty(&lpi->iovs) && list_empty(&lpi->reqs)) { ret = xfer_pages(lpi); if (ret < 0) goto out; @@ -1240,7 +1231,7 @@ static int lazy_sk_read_event(struct epoll_rfd *rfd) restore_finished = true; - return 0; + return 1; } static int lazy_sk_hangup_event(struct epoll_rfd *rfd) From bb2af52190a3bda4b1018b88da0f7a07b057ed37 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 16 Apr 2018 19:58:57 +0300 Subject: [PATCH 1399/4375] test: lazy-pages: exclude maps007 With userfaultfd we cannot reliably service process_vm_readv calls. The maps007 test that uses these calls passed previously by sheer luck. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 2 +- test/jenkins/criu-lazy-migration.sh | 2 +- test/jenkins/criu-lazy-pages.sh | 2 +- test/jenkins/criu-remote-lazy-pages.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 6cfc81f52..7a2bd51d4 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -80,7 +80,7 @@ chmod 0777 test/zdtm/transition KERN_MAJ=`uname -r | cut -d. -f1` KERN_MIN=`uname -r | cut -d. -f2` if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then - LAZY_EXCLUDE="-x cmdlinenv00" + LAZY_EXCLUDE="-x cmdlinenv00 -x maps007" else LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns -x socket_listen -x socket_listen6 -x cmdlinenv00 diff --git a/test/jenkins/criu-lazy-migration.sh b/test/jenkins/criu-lazy-migration.sh index d0b3a5912..78ea2bfce 100644 --- a/test/jenkins/criu-lazy-migration.sh +++ b/test/jenkins/criu-lazy-migration.sh @@ -6,7 +6,7 @@ prep KERN_MAJ=`uname -r | cut -d. -f1` KERN_MIN=`uname -r | cut -d. -f2` if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then - LAZY_EXCLUDE="-x cmdlinenv00" + LAZY_EXCLUDE="-x cmdlinenv00 -x maps007" else LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns -x socket_listen -x socket_listen6 -x cmdlinenv00 diff --git a/test/jenkins/criu-lazy-pages.sh b/test/jenkins/criu-lazy-pages.sh index 474cb3c6b..f31098c7a 100755 --- a/test/jenkins/criu-lazy-pages.sh +++ b/test/jenkins/criu-lazy-pages.sh @@ -6,7 +6,7 @@ prep KERN_MAJ=`uname -r | cut -d. -f1` KERN_MIN=`uname -r | cut -d. -f2` if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then - LAZY_EXCLUDE="-x cmdlinenv00" + LAZY_EXCLUDE="-x cmdlinenv00 -x maps007" else LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns -x socket_listen -x socket_listen6 -x cmdlinenv00 diff --git a/test/jenkins/criu-remote-lazy-pages.sh b/test/jenkins/criu-remote-lazy-pages.sh index 7d671029d..122aea72c 100755 --- a/test/jenkins/criu-remote-lazy-pages.sh +++ b/test/jenkins/criu-remote-lazy-pages.sh @@ -6,7 +6,7 @@ prep KERN_MAJ=`uname -r | cut -d. -f1` KERN_MIN=`uname -r | cut -d. -f2` if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then - LAZY_EXCLUDE="-x cmdlinenv00" + LAZY_EXCLUDE="-x cmdlinenv00 -x maps007" else LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns -x socket_listen -x socket_listen6 -x cmdlinenv00 From 82b7e843e136fab0c7e9dab6d9cbe373c780a6d3 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 16 Apr 2018 19:58:58 +0300 Subject: [PATCH 1400/4375] lazy-pages: introduce merge_iov_lists helper Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 7a9e97e94..180ac4817 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -415,6 +415,25 @@ static int split_iov(struct lazy_iov *iov, unsigned long addr) return 0; } +static void merge_iov_lists(struct list_head *src, struct list_head *dst) +{ + struct lazy_iov *iov, *p, *n; + + list_for_each_entry_safe(iov, n, src, l) { + list_for_each_entry(p, dst, l) { + if (iov->start < p->start) { + list_move_tail(&iov->l, &p->l); + break; + } + if (list_is_last(&p->l, dst) && + iov->start > p->start) { + list_move(&iov->l, &p->l); + break; + } + } + } +} + static int copy_iovs(struct lazy_pages_info *src, struct lazy_pages_info *dst) { struct lazy_iov *iov, *new; @@ -530,14 +549,14 @@ static int remap_iovs(struct lazy_pages_info *lpi, unsigned long from, unsigned long to, unsigned long len) { unsigned long off = to - from; - struct lazy_iov *iov, *n, *p; + struct lazy_iov *iov, *n; LIST_HEAD(remaps); list_for_each_entry_safe(iov, n, &lpi->iovs, l) { if (from >= iov->end) continue; - if (len <= 0 || from + len < iov->start) + if (len <= 0 || from + len <= iov->start) break; if (from < iov->start) { @@ -566,19 +585,7 @@ static int remap_iovs(struct lazy_pages_info *lpi, unsigned long from, list_move_tail(&iov->l, &remaps); } - list_for_each_entry_safe(iov, n, &remaps, l) { - list_for_each_entry(p, &lpi->iovs, l) { - if (iov->start < p->start) { - list_move_tail(&iov->l, &p->l); - break; - } - if (list_is_last(&p->l, &lpi->iovs) && - iov->start > p->start) { - list_move(&iov->l, &p->l); - break; - } - } - } + merge_iov_lists(&remaps, &lpi->iovs); return 0; } From 315c4418fe255510da1c3c99544203265e1b13de Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 16 Apr 2018 19:58:59 +0300 Subject: [PATCH 1401/4375] lazy-pages: merge_iov_lists: fix corner case of empty destination Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/criu/uffd.c b/criu/uffd.c index 180ac4817..55de798ab 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -419,6 +419,14 @@ static void merge_iov_lists(struct list_head *src, struct list_head *dst) { struct lazy_iov *iov, *p, *n; + if (list_empty(src)) + return; + + if (list_empty(dst)) { + iov = list_first_entry(src, struct lazy_iov, l); + list_move(&iov->l, dst); + } + list_for_each_entry_safe(iov, n, src, l) { list_for_each_entry(p, dst, l) { if (iov->start < p->start) { From 2ad16d4c5073d6c947039392f7c4f192ec0e8835 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 16 Apr 2018 19:59:00 +0300 Subject: [PATCH 1402/4375] lazy-pages: handle_requests: fix return value propagation When we return from epoll_run_rfds with positive return value it means that event handling loop was interrupted because the event should be handled outside of that loop. Is always the case with UFFD_EVENT_FORK. It may happen that the event occurred after we've completed the memory transfer and we are on the way to successful return from the handle_requests() function, but instead of returning 0 we will return the positive value we've got from epoll_run_rfds. Explicitly assigning return value of complete_forks() fixes this issue. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 55de798ab..0343f9348 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1150,8 +1150,9 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) if (ret < 0) goto out; if (ret > 0) { - if (complete_forks(epollfd, &events, &nr_fds)) - return -1; + ret = complete_forks(epollfd, &events, &nr_fds); + if (ret) + goto out; if (!restore_finished) continue; } From 93f3fa3484bbdb0d4444e39094d8863927eafc9e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 16 Apr 2018 19:59:01 +0300 Subject: [PATCH 1403/4375] lazy-pages: cache buffer size in the lazy_pages_info Instead of recalculating required for lazy_pages_info->buf when copying IOVs at fork() time, keep the size of the buffer in the lazy_pages_info struct. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 0343f9348..755980c16 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -97,6 +97,7 @@ struct lazy_pages_info { struct list_head l; + unsigned long buf_size; void *buf; }; @@ -445,7 +446,6 @@ static void merge_iov_lists(struct list_head *src, struct list_head *dst) static int copy_iovs(struct lazy_pages_info *src, struct lazy_pages_info *dst) { struct lazy_iov *iov, *new; - int max_iov_len = 0; list_for_each_entry(iov, &src->iovs, l) { new = xzalloc(sizeof(*new)); @@ -457,12 +457,10 @@ static int copy_iovs(struct lazy_pages_info *src, struct lazy_pages_info *dst) new->end = iov->end; list_add_tail(&new->l, &dst->iovs); - - if (new->end - new->start > max_iov_len) - max_iov_len = new->end - new->start; } - if (posix_memalign(&dst->buf, PAGE_SIZE, max_iov_len)) + dst->buf_size = src->buf_size; + if (posix_memalign(&dst->buf, PAGE_SIZE, dst->buf_size)) goto free_iovs; return 0; @@ -653,7 +651,8 @@ static int collect_iovs(struct lazy_pages_info *lpi) } } - if (posix_memalign(&lpi->buf, PAGE_SIZE, max_iov_len)) + lpi->buf_size = max_iov_len; + if (posix_memalign(&lpi->buf, PAGE_SIZE, lpi->buf_size)) goto free_iovs; ret = nr_pages; From b6917ef4ca392a98d053af704e68296c07eca84f Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 16 Apr 2018 19:59:02 +0300 Subject: [PATCH 1404/4375] lazy-pages: update events handling to take requests into account Since the memory mapping is now split between ->iovs and ->reqs lists, any update to memory layout should take into account both lists. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 69 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 12 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 755980c16..39273e755 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -443,11 +443,11 @@ static void merge_iov_lists(struct list_head *src, struct list_head *dst) } } -static int copy_iovs(struct lazy_pages_info *src, struct lazy_pages_info *dst) +static int __copy_iov_list(struct list_head *src, struct list_head *dst) { struct lazy_iov *iov, *new; - list_for_each_entry(iov, &src->iovs, l) { + list_for_each_entry(iov, src, l) { new = xzalloc(sizeof(*new)); if (!new) return -1; @@ -456,9 +456,27 @@ static int copy_iovs(struct lazy_pages_info *src, struct lazy_pages_info *dst) new->img_start = iov->img_start; new->end = iov->end; - list_add_tail(&new->l, &dst->iovs); + list_add_tail(&new->l, dst); } + + return 0; +} + +static int copy_iovs(struct lazy_pages_info *src, struct lazy_pages_info *dst) +{ + if (__copy_iov_list(&src->iovs, &dst->iovs)) + goto free_iovs; + + if (__copy_iov_list(&src->reqs, &dst->reqs)) + goto free_iovs; + + /* + * The IOVs aready in flight for the parent process need to be + * transferred again for the child process + */ + merge_iov_lists(&dst->reqs, &src->iovs); + dst->buf_size = src->buf_size; if (posix_memalign(&dst->buf, PAGE_SIZE, dst->buf_size)) goto free_iovs; @@ -474,11 +492,11 @@ free_iovs: * Purge range (addr, addr + len) from lazy_iovs. The range may * cover several continuous IOVs. */ -static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) +static int __drop_iovs(struct list_head *iovs, unsigned long addr, int len) { struct lazy_iov *iov, *n; - list_for_each_entry_safe(iov, n, &lpi->iovs, l) { + list_for_each_entry_safe(iov, n, iovs, l) { unsigned long start = iov->start; unsigned long end = iov->end; @@ -532,6 +550,18 @@ static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) return 0; } +static int drop_iovs(struct lazy_pages_info *lpi, unsigned long addr, int len) +{ + if (__drop_iovs(&lpi->iovs, addr, len)) + return -1; + + if (__drop_iovs(&lpi->reqs, addr, len)) + return -1; + + return 0; +} + + static struct lazy_iov *extract_range(struct lazy_iov *iov, unsigned long start, unsigned long end) @@ -551,14 +581,15 @@ static struct lazy_iov *extract_range(struct lazy_iov *iov, return list_entry(iov->l.next, struct lazy_iov, l); } -static int remap_iovs(struct lazy_pages_info *lpi, unsigned long from, - unsigned long to, unsigned long len) +static int __remap_iovs(struct list_head *iovs, unsigned long from, + unsigned long to, unsigned long len) { - unsigned long off = to - from; - struct lazy_iov *iov, *n; LIST_HEAD(remaps); - list_for_each_entry_safe(iov, n, &lpi->iovs, l) { + unsigned long off = to - from; + struct lazy_iov *iov, *n; + + list_for_each_entry_safe(iov, n, iovs, l) { if (from >= iov->end) continue; @@ -591,7 +622,19 @@ static int remap_iovs(struct lazy_pages_info *lpi, unsigned long from, list_move_tail(&iov->l, &remaps); } - merge_iov_lists(&remaps, &lpi->iovs); + merge_iov_lists(&remaps, iovs); + + return 0; +} + +static int remap_iovs(struct lazy_pages_info *lpi, unsigned long from, + unsigned long to, unsigned long len) +{ + if (__remap_iovs(&lpi->iovs, from, to, len)) + return -1; + + if (__remap_iovs(&lpi->reqs, from, to, len)) + return -1; return 0; } @@ -817,7 +860,9 @@ static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr } } - BUG_ON(!addr); + /* the request may be already gone because if uname/remove */ + if (!addr) + return 0; return uffd_copy(lpi, addr, nr); } From 312e97f1c29fe164e5702e757272bfdfeb071f0b Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 16 Apr 2018 19:59:03 +0300 Subject: [PATCH 1405/4375] lazy-pages: return to epoll_wait after completing forks If we get fork() event just before transferring last IOV of the parent process, continuing to background fetch after completing fork event handling will cause lazy-pages daemon to exit and nothing will monitor the child process memory. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 39273e755..4022fc5a7 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1062,7 +1062,7 @@ static int complete_forks(int epollfd, struct epoll_event **events, int *nr_fds) struct lazy_pages_info *lpi, *n; if (list_empty(&pending_lpis)) - return 0; + return 1; list_for_each_entry(lpi, &pending_lpis, l) (*nr_fds)++; @@ -1195,12 +1195,15 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) goto out; if (ret > 0) { ret = complete_forks(epollfd, &events, &nr_fds); - if (ret) + if (ret < 0) goto out; if (!restore_finished) continue; } + /* make sure we return success if there is nothing to xfer */ + ret = 0; + poll_timeout = 0; list_for_each_entry_safe(lpi, n, &lpis, l) { if (!list_empty(&lpi->iovs) && list_empty(&lpi->reqs)) { From fb7873c97c457f3d389b86a59ffa9f0cb4141f44 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 16 Apr 2018 19:59:04 +0300 Subject: [PATCH 1406/4375] lazy-pages: don't try to uffd_copy to removed memory regions It is possible that when pages request from the remove source arrive, part of the memory range covered by the request would be already gone because of madvise(MADV_DONTNEED), mremap() etc. Ensure we are not trying to uffd_copy more than we are allowed. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/criu/uffd.c b/criu/uffd.c index 4022fc5a7..7f6a59c71 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -839,6 +839,7 @@ static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr { struct lazy_pages_info *lpi; unsigned long addr = 0; + int req_pages; struct lazy_iov *req; lpi = container_of(pr, struct lazy_pages_info, pr); @@ -864,6 +865,14 @@ static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr if (!addr) return 0; + /* + * by the time we get the pages from the remote source, parts + * of the request may already be gone because of + * UFFD_EVENT_{REMAP,REMOVE,UNMAP} + */ + req_pages = (req->end - req->start) / PAGE_SIZE; + nr = min(nr, req_pages); + return uffd_copy(lpi, addr, nr); } From 7ffaf883bd6616b00fe4ed1caf1234d77d237295 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 30 Apr 2018 18:17:53 +0300 Subject: [PATCH 1407/4375] lazy-pages: actually return to epoll_wait after completing forks Commit 9cb20327aa4 ("return to epoll_wait after completing forks") was only half way there. Adding the other half. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index 7f6a59c71..0b26c7d8a 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1066,6 +1066,11 @@ out: return -1; } +/* + * We may exit epoll_run_rfds() loop because of non-fork() event. In + * such case we return 1 rather than 0 to let the caller know that no + * fork() events were pending + */ static int complete_forks(int epollfd, struct epoll_event **events, int *nr_fds) { struct lazy_pages_info *lpi, *n; @@ -1206,7 +1211,7 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) ret = complete_forks(epollfd, &events, &nr_fds); if (ret < 0) goto out; - if (!restore_finished) + if (!restore_finished || !ret) continue; } From 95ea4e92a8167ad762fcb9d6941ad2267f3fa400 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 7 May 2018 21:50:02 +0300 Subject: [PATCH 1408/4375] lazy-pages: fork: fix duplication of IOV lists Instead of merging unfinished requests with child's IOVs we queued them into parent's IOV list. Fix it. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index 0b26c7d8a..21db369cc 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -475,7 +475,7 @@ static int copy_iovs(struct lazy_pages_info *src, struct lazy_pages_info *dst) * The IOVs aready in flight for the parent process need to be * transferred again for the child process */ - merge_iov_lists(&dst->reqs, &src->iovs); + merge_iov_lists(&dst->reqs, &dst->iovs); dst->buf_size = src->buf_size; if (posix_memalign(&dst->buf, PAGE_SIZE, dst->buf_size)) From 7e10b43b4f8fdc7d3dedeae49be86e7b6e46b2a5 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 9 May 2018 18:03:48 +0300 Subject: [PATCH 1409/4375] lazy-pages: factor out insertion to sorted IOV list Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 21db369cc..f019eee02 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -416,31 +416,37 @@ static int split_iov(struct lazy_iov *iov, unsigned long addr) return 0; } +static void iov_list_insert(struct lazy_iov *new, struct list_head *dst) +{ + struct lazy_iov *iov; + + if (list_empty(dst)) { + list_move(&new->l, dst); + return; + } + + list_for_each_entry(iov, dst, l) { + if (new->start < iov->start) { + list_move_tail(&new->l, &iov->l); + break; + } + if (list_is_last(&iov->l, dst) && + new->start > iov->start) { + list_move(&new->l, &iov->l); + break; + } + } +} + static void merge_iov_lists(struct list_head *src, struct list_head *dst) { - struct lazy_iov *iov, *p, *n; + struct lazy_iov *iov, *n; if (list_empty(src)) return; - if (list_empty(dst)) { - iov = list_first_entry(src, struct lazy_iov, l); - list_move(&iov->l, dst); - } - - list_for_each_entry_safe(iov, n, src, l) { - list_for_each_entry(p, dst, l) { - if (iov->start < p->start) { - list_move_tail(&iov->l, &p->l); - break; - } - if (list_is_last(&p->l, dst) && - iov->start > p->start) { - list_move(&iov->l, &p->l); - break; - } - } - } + list_for_each_entry_safe(iov, n, src, l) + iov_list_insert(iov, dst); } static int __copy_iov_list(struct list_head *src, struct list_head *dst) From 8d91b2e3fceff2da4afccdeb1c43a0e5f61fdb32 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 9 May 2018 18:03:49 +0300 Subject: [PATCH 1410/4375] lazy-pages: make uffd_io_complete more robust Make sure we handle various corner cases: * we received less pages than requested * the request was capped because of unmap/remap etc * the process has exited underneath us Currently we are freeing the request once we've found the address to use with uffd_copy(). Instead, let's keep the request object around, use it to properly calculate number of pages we pass to uffd_copy() and then re-add tailing range (if any) to the IOVs list. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index f019eee02..f803f2aa2 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -845,7 +845,7 @@ static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr { struct lazy_pages_info *lpi; unsigned long addr = 0; - int req_pages; + int req_pages, ret; struct lazy_iov *req; lpi = container_of(pr, struct lazy_pages_info, pr); @@ -861,25 +861,39 @@ static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr list_for_each_entry(req, &lpi->reqs, l) { if (req->img_start == img_addr) { addr = req->start; - list_del(&req->l); - xfree(req); break; } } - /* the request may be already gone because if uname/remove */ + /* the request may be already gone because if unmap/remove */ if (!addr) return 0; /* - * by the time we get the pages from the remote source, parts - * of the request may already be gone because of - * UFFD_EVENT_{REMAP,REMOVE,UNMAP} + * By the time we get the pages from the remote source, parts + * of the request may already be gone because of unmap/remove + * OTOH, the remote side may send less pages than we requested. + * Make sure we are not trying to uffd_copy more memory than + * we should. */ req_pages = (req->end - req->start) / PAGE_SIZE; nr = min(nr, req_pages); - return uffd_copy(lpi, addr, nr); + ret = uffd_copy(lpi, addr, nr); + if (ret < 0) + return ret; + + /* recheck if the process exited, it may be detected in uffd_copy */ + if (lpi->exited) + return 0; + + /* + * Since the completed request length may differ from the + * actual data we've received we re-insert the request to IOVs + * list and let drop_iovs do the range math, free memory etc. + */ + iov_list_insert(req, &lpi->iovs); + return drop_iovs(lpi, addr, nr * PAGE_SIZE); } static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) From 3e66125e9bf2e1150eecf7f68bbb1234ef561009 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 2 Mar 2018 00:49:12 +0300 Subject: [PATCH 1411/4375] [v2] criu: add -fprofile-update=atomic for builds with gcov Sometimes we see errors like this: criu/cr-restore.gcda:Merge mismatch for function 106 It proabably means that this gcda file was corrupted. According to the gcc man page, the -fprofile-update=atomic should fix this problem. v2: this options appered in gcc7, so we need to install it. Reported-by: Mr Travis CI Signed-off-by: Andrei Vagin --- .travis.yml | 3 ++- Makefile | 2 +- scripts/travis/travis-tests | 9 ++++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b6766a01c..f03dbc392 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ cache: ccache services: - docker env: - - TR_ARCH=local GCOV=1 + - TR_ARCH=local - TR_ARCH=local CLANG=1 - TR_ARCH=alpine - TR_ARCH=fedora-asan @@ -22,6 +22,7 @@ env: - TR_ARCH=docker-test - TR_ARCH=fedora-rawhide - TR_ARCH=fedora-rawhide-aarch64 + - TR_ARCH=local GCOV=1 matrix: allow_failures: - env: TR_ARCH=docker-test diff --git a/Makefile b/Makefile index 75f328e50..b9cc42286 100644 --- a/Makefile +++ b/Makefile @@ -91,7 +91,7 @@ DEFINES += -D_GNU_SOURCE WARNINGS := -Wall -Wformat-security -CFLAGS-GCOV := --coverage -fno-exceptions -fno-inline +CFLAGS-GCOV := --coverage -fno-exceptions -fno-inline -fprofile-update=atomic export CFLAGS-GCOV ifneq ($(GCOV),) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 7a2bd51d4..863a31057 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -20,6 +20,13 @@ travis_prep () { CC=clang fi + [ -n "$GCOV" ] && { + apt-add-repository -y "ppa:ubuntu-toolchain-r/test" + apt-get update -yq + apt-get -yq --no-install-suggests --no-install-recommends --force-yes install g++-7 + CC=gcc-7 + } + # ccache support, only enable for non-GCOV case if [ "$CCACHE" = "1" -a -z "$GCOV" ]; then # ccache is installed by default, need to set it up @@ -99,7 +106,7 @@ bash ./test/jenkins/criu-inhfd.sh make -C test/others/mnt-ext-dev/ run #make -C test/others/exec/ run -make -C test/others/make/ run +make -C test/others/make/ run CC="$CC" ./test/zdtm.py run -t zdtm/static/env00 --sibling From f872b43152139dc3d78eb294359dae6afbb68cdc Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 6 Apr 2018 02:52:33 +0300 Subject: [PATCH 1412/4375] travis: don't fail a build due to the GCOV job It fails too often due to installing gcc-7. Signed-off-by: Andrei Vagin --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f03dbc392..4d239edc2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,7 @@ matrix: - env: TR_ARCH=fedora-rawhide - env: TR_ARCH=fedora-rawhide-aarch64 - env: TR_ARCH=s390x + - env: TR_ARCH=local GCOV=1 script: - sudo make CCACHE=1 -C scripts/travis $TR_ARCH after_success: From 72d5e41abd6276f359bda4065aeb00dd1faa8911 Mon Sep 17 00:00:00 2001 From: Radoslaw Burny Date: Tue, 10 Apr 2018 13:35:04 +0300 Subject: [PATCH 1413/4375] sfds: Fix UB in choose_service_fd_base due to calling __builtin_clz(0) __builtin_clz(0) leads to undefined behaviour: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html Set nr = 1 directly to avoid this. Link: https://github.com/checkpoint-restore/criu/issues/470 Signed-off-by: Radoslaw Burny Acked-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/util.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/criu/util.c b/criu/util.c index a3bf3a3c6..7b97a4c05 100644 --- a/criu/util.c +++ b/criu/util.c @@ -591,7 +591,10 @@ static int choose_service_fd_base(struct pstree_item *me) real_nr = nr; nr /= (1024 / sizeof(void *)); - nr = 1 << (32 - __builtin_clz(nr)); + if (nr) + nr = 1 << (32 - __builtin_clz(nr)); + else + nr = 1; nr *= (1024 / sizeof(void *)); if (nr > service_fd_rlim_cur) { From f992f469e8eba2d37c2b994698839d753ab08071 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 29 Mar 2018 20:24:52 +0300 Subject: [PATCH 1414/4375] jenkins: add a pipeline file for criu-lazy-migration Signed-off-by: Andrei Vagin --- test/jenkins/criu-lazy-migration.pipeline | 34 +++++++++++++++++++++++ test/jenkins/criu-lazy-migration.sh | 0 2 files changed, 34 insertions(+) create mode 100644 test/jenkins/criu-lazy-migration.pipeline mode change 100644 => 100755 test/jenkins/criu-lazy-migration.sh diff --git a/test/jenkins/criu-lazy-migration.pipeline b/test/jenkins/criu-lazy-migration.pipeline new file mode 100644 index 000000000..7d655513c --- /dev/null +++ b/test/jenkins/criu-lazy-migration.pipeline @@ -0,0 +1,34 @@ +pipeline { + options { + buildDiscarder(logRotator(numToKeepStr: '30', artifactNumToKeepStr: '30')) + } + agent { + node { + label 'x86_64' + } + } + triggers { + cron('H H/4 * * *') + } + stages { + stage('Build') { + steps { + sh 'make' + sh 'make -C test/zdtm' + } + } + stage('Test'){ + steps { + sh './test/jenkins/run_ct sh -c "mount --make-rprivate / && mount --rbind . /mnt && cd /mnt && ./test/jenkins/criu-lazy-migration.sh"' + junit 'test/report/criu-testreport*.xml' + } + } + } + post { + failure { + emailext attachLog: true, body: '''$DEFAULT_CONTENT + +${FILE,path="test/report/output"}''', compressLog: true, subject: '$DEFAULT_SUBJECT', to: "${env.CRIU_RECIPIENTS}" + } + } +} diff --git a/test/jenkins/criu-lazy-migration.sh b/test/jenkins/criu-lazy-migration.sh old mode 100644 new mode 100755 From 47513625b205ec4bb989c971957d73f95c029263 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 26 Feb 2018 03:43:29 +0300 Subject: [PATCH 1415/4375] zdtm: add a test to check O_TMPFILE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit man 2 open: ... O_TMPFILE (since Linux 3.11) Create an unnamed temporary file. The pathname argument speci‐ fies a directory; an unnamed inode will be created in that directory's filesystem. Anything written to the resulting file will be lost when the last file descriptor is closed, unless the file is given a name. ... Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 2 ++ test/zdtm/static/unlink_fstat00.c | 6 ++++++ test/zdtm/static/unlink_fstat041.c | 1 + 3 files changed, 9 insertions(+) create mode 120000 test/zdtm/static/unlink_fstat041.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 8c517aa61..fda601eeb 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -307,6 +307,7 @@ TST_DIR = \ cgroup_ifpriomap \ cgroup_stray \ unlink_fstat04 \ + unlink_fstat041 \ mntns_remap \ mntns_open \ mntns_link_remap \ @@ -489,6 +490,7 @@ mlock_setuid: get_smaps_bits.o inotify01: CFLAGS += -DINOTIFY01 unlink_fstat01+: CFLAGS += -DUNLINK_OVER unlink_fstat04: CFLAGS += -DUNLINK_FSTAT04 +unlink_fstat041: CFLAGS += -DUNLINK_FSTAT041 -DUNLINK_FSTAT04 ghost_holes01: CFLAGS += -DTAIL_HOLE ghost_holes02: CFLAGS += -DHEAD_HOLE sk-freebind-false: CFLAGS += -DZDTM_FREEBIND_FALSE diff --git a/test/zdtm/static/unlink_fstat00.c b/test/zdtm/static/unlink_fstat00.c index 88a864776..faafb1b7f 100644 --- a/test/zdtm/static/unlink_fstat00.c +++ b/test/zdtm/static/unlink_fstat00.c @@ -40,7 +40,11 @@ int main(int argc, char ** argv) mkdir(dirname, 0700); #endif +#ifndef UNLINK_FSTAT041 fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644); +#else + fd = open(dirname, O_RDWR | O_TMPFILE, 0644); +#endif if (fd < 0) { pr_perror("can't open %s", filename); exit(1); @@ -58,10 +62,12 @@ int main(int argc, char ** argv) goto failed; } +#ifndef UNLINK_FSTAT041 if (unlink(filename) < 0) { pr_perror("can't unlink %s", filename); goto failed; } +#endif /* Change file size */ if (fst.st_size != 0) { pr_perror("%s file size eq %ld", filename, (long)fst.st_size); diff --git a/test/zdtm/static/unlink_fstat041.c b/test/zdtm/static/unlink_fstat041.c new file mode 120000 index 000000000..f51b3c63b --- /dev/null +++ b/test/zdtm/static/unlink_fstat041.c @@ -0,0 +1 @@ +unlink_fstat00.c \ No newline at end of file From 93b34b6cb8c119d7c873045703299a9df12b7574 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 27 Feb 2018 00:33:23 +0300 Subject: [PATCH 1416/4375] files: drop O_TMPFILE from file descriptor flags Unnamed temporary files are restored as ghost files. If O_TMPFILE is set for the open() syscall, the pathname argument specifies a directory, but criu gives a path to a ghost file. (00.107450) 36: Error (criu/files-reg.c:1757): Can't open file tmp/#42274874 on restore: Not a directory Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/files-reg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/files-reg.c b/criu/files-reg.c index 8fb447ff8..5da7a8ea8 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1713,6 +1713,9 @@ int do_open_reg_noseek_flags(int ns_root_fd, struct reg_file_info *rfi, void *ar u32 flags = *(u32 *)arg; int fd; + /* unnamed temporary files are restored as ghost files */ + flags &= ~O_TMPFILE; + fd = openat(ns_root_fd, rfi->path, flags); if (fd < 0) { pr_perror("Can't open file %s on restore", rfi->path); From dc62a93010c52fdba10a8a08e41ebe67d38eed07 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 24 Apr 2018 11:27:15 +0300 Subject: [PATCH 1417/4375] files: define O_TMPFILE These fixes compilation on VZ7: https://ci.openvz.org/job/CRIU/job/CRIU-virtuozzo/job/criu-dev/3605/console https://jira.sw.ru/browse/PSBM-83713 Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/include/fcntl.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/criu/include/fcntl.h b/criu/include/fcntl.h index ce8abda34..d9c5c5e7b 100644 --- a/criu/include/fcntl.h +++ b/criu/include/fcntl.h @@ -38,4 +38,12 @@ struct f_owner_ex { # define O_PATH 010000000 #endif +#ifndef __O_TMPFILE +#define __O_TMPFILE 020000000 +#endif + +#ifndef O_TMPFILE +#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) +#endif + #endif /* __CR_ASM_GENERIC_FCNTL_H__ */ From ef78b890d2489cb125c904562292f5f6470ac30b Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 17 Apr 2018 18:15:06 +0300 Subject: [PATCH 1418/4375] files: fix clone_service_fd overlap handling Though LOG_FD_OFF < IMG_FD_OFF, get_service_fd(LOG_FD_OFF) is > than get_service_fd(IMG_FD_OFF), see __get_service_fd, so the check here should be twisted. Also add bug_on to track possible __get_service_fd change which can break these check again. We have a problem when USERNSD_SK replaces LOG_FD_OFF, latter when writing to log, instead we actually send crazy commands to usernsd, which fails to handle them and BUGs or crashes. https://jira.sw.ru/browse/PSBM-83472 Also we had similar problem when __userns_call receives bad repsonse, likely it has the same background: https://api.travis-ci.org/v3/job/352164661/log.txt fixes commit 129bb14611c3 ("files: Prepare clone_service_fd() for overlaping ranges.") v2: move BUG_ON to main() to check it only once, use min+1 and max-1 Signed-off-by: Pavel Tikhomirov Acked-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/crtools.c | 3 +++ criu/util.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/criu/crtools.c b/criu/crtools.c index 07ee2acef..42cfd91e9 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -343,6 +343,9 @@ int main(int argc, char *argv[], char *envp[]) BUILD_BUG_ON(PAGE_SIZE != PAGE_IMAGE_SIZE); BUILD_BUG_ON(CTL_32 != SYSCTL_TYPE__CTL_32); BUILD_BUG_ON(__CTL_STR != SYSCTL_TYPE__CTL_STR); + /* We use it for fd overlap handling in clone_service_fd() */ + BUG_ON(get_service_fd(SERVICE_FD_MIN+1) < + get_service_fd(SERVICE_FD_MAX-1)); if (fault_injection_init()) return 1; diff --git a/criu/util.c b/criu/util.c index 7b97a4c05..d6d03a502 100644 --- a/criu/util.c +++ b/criu/util.c @@ -622,7 +622,7 @@ int clone_service_fd(struct pstree_item *me) return 0; /* Dup sfds in memmove() style: they may overlap */ - if (get_service_fd(LOG_FD_OFF) > new_base - LOG_FD_OFF - SERVICE_FD_MAX * id) + if (get_service_fd(LOG_FD_OFF) < new_base - LOG_FD_OFF - SERVICE_FD_MAX * id) for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) move_service_fd(me, i, id, new_base); else From 4a6cf33be3c36ce0fef19eff674f9c27a6a76e85 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 9 Apr 2018 12:14:57 +0100 Subject: [PATCH 1419/4375] net: Remove trailing whitespace Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/net.c b/criu/net.c index d02c4fdb8..5fa10de87 100644 --- a/criu/net.c +++ b/criu/net.c @@ -828,7 +828,7 @@ static int dump_one_link(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) nlmsg_parse(hdr, sizeof(struct ifinfomsg), tb, IFLA_MAX, NULL); pr_info("\tLD: Got link %d, type %d\n", ifi->ifi_index, ifi->ifi_type); - if (ifi->ifi_type == ARPHRD_LOOPBACK) + if (ifi->ifi_type == ARPHRD_LOOPBACK) return dump_one_netdev(ND_TYPE__LOOPBACK, ifi, tb, ns, fds, NULL); kind = link_kind(ifi, tb); From 348b169518bb6700504639c61cd2cebfc4a7e4d3 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 9 Apr 2018 12:14:58 +0100 Subject: [PATCH 1420/4375] Remove redundant semicolons Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/arch/ppc64/vdso-pie.c | 2 +- criu/net.c | 2 +- criu/pie/restorer.c | 2 +- criu/proc_parse.c | 2 +- criu/pstree.c | 2 +- criu/sk-tcp.c | 2 +- criu/sk-unix.c | 4 ++-- criu/sysctl.c | 2 +- criu/tun.c | 2 +- soccr/soccr.c | 2 +- test/zdtm/static/maps06.c | 2 +- test/zdtm/static/mountpoints.c | 2 +- test/zdtm/static/session01.c | 2 +- test/zdtm/static/sk-netlink.c | 6 +++--- test/zdtm/transition/netlink00.c | 2 +- 15 files changed, 18 insertions(+), 18 deletions(-) diff --git a/criu/arch/ppc64/vdso-pie.c b/criu/arch/ppc64/vdso-pie.c index 2dd3030dc..a7e017342 100644 --- a/criu/arch/ppc64/vdso-pie.c +++ b/criu/arch/ppc64/vdso-pie.c @@ -116,7 +116,7 @@ static unsigned long put_trampoline(unsigned long at, struct vdso_symtable *sym) static inline void put_trampoline_call(unsigned long at, unsigned long to, unsigned long tr) { - uint32_t *addr = (uint32_t *)at;; + uint32_t *addr = (uint32_t *)at; *addr++ = 0x7C0802a6; /* mflr r0 */ *addr++ = 0x48000001 | ((long)(tr-at-4) & 0x3fffffc); /* bl tr */ diff --git a/criu/net.c b/criu/net.c index 5fa10de87..cacb69256 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2459,7 +2459,7 @@ static int iptables_restore(bool ipv6, char *buf, int size) int pfd[2], ret = -1; char *cmd4[] = {"iptables-restore", "-w", "--noflush", NULL}; char *cmd6[] = {"ip6tables-restore", "-w", "--noflush", NULL}; - char **cmd = ipv6 ? cmd6 : cmd4;; + char **cmd = ipv6 ? cmd6 : cmd4; if (pipe(pfd) < 0) { pr_perror("Unable to create pipe"); diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index c2e5b38a5..86b0c7a3c 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -374,7 +374,7 @@ static int restore_signals(siginfo_t *ptr, int nr, bool group) if (ret) { pr_err("Unable to send siginfo %d %x with code %d\n", info->si_signo, info->si_code, ret); - return -1;; + return -1; } } diff --git a/criu/proc_parse.c b/criu/proc_parse.c index e63dee085..f2388e631 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1645,7 +1645,7 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, void *arg) struct bfd f; char *str; bool entry_met = false; - int ret, exit_code = -1;; + int ret, exit_code = -1; f.fd = open_proc(pid, "fdinfo/%d", fd); if (f.fd < 0) diff --git a/criu/pstree.c b/criu/pstree.c index dfd68b7ca..928fe2d17 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -435,7 +435,7 @@ void pstree_insert_pid(struct pid *pid_node) struct pstree_item *lookup_create_item(pid_t pid) { - struct pid *node;; + struct pid *node; node = lookup_create_pid(pid, NULL); if (!node) diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c index f4dd13ecf..353125f2b 100644 --- a/criu/sk-tcp.c +++ b/criu/sk-tcp.c @@ -292,7 +292,7 @@ static int restore_tcp_conn_state(int sk, struct libsoccr_sk *socr, struct inet_ goto err_c; } - data.state = ii->ie->state;; + data.state = ii->ie->state; data.inq_len = tse->inq_len; data.inq_seq = tse->inq_seq; data.outq_len = tse->outq_len; diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 7fd55f7ab..ea8d22d90 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1309,7 +1309,7 @@ static int bind_deleted_unix_sk(int sk, struct unix_sk_info *ui, /* this shouldn't happen, since sun_addr is only 108 chars long */ if (ret < 0 || ret >= sizeof(temp)) { pr_err("snprintf of %s failed?\n", addr->sun_path); - return -1;; + return -1; } ret = rename(addr->sun_path, temp); @@ -1322,7 +1322,7 @@ static int bind_deleted_unix_sk(int sk, struct unix_sk_info *ui, sizeof(addr->sun_family) + ui->ue->name.len); if (ret < 0) { pr_perror("Can't bind socket after move"); - return -1;; + return -1; } ret = rename(temp, addr->sun_path); diff --git a/criu/sysctl.c b/criu/sysctl.c index 4b15e1506..e48476560 100644 --- a/criu/sysctl.c +++ b/criu/sysctl.c @@ -351,7 +351,7 @@ out: static int __nonuserns_sysctl_op(struct sysctl_req *req, size_t nr_req, int op) { - int ret, exit_code = -1;; + int ret, exit_code = -1; while (nr_req--) { int fd; diff --git a/criu/tun.c b/criu/tun.c index e88e7797a..04bb87df4 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -375,7 +375,7 @@ static int tunfile_open(struct file_desc *d, int *new_fd) if (!ti->tfe->netdev) /* just-opened tun file */ - goto ok;; + goto ok; tl = find_tun_link(ti->tfe->netdev); if (!tl) { diff --git a/soccr/soccr.c b/soccr/soccr.c index 2d49766dc..d63a2ce2b 100644 --- a/soccr/soccr.c +++ b/soccr/soccr.c @@ -593,7 +593,7 @@ static int send_fin(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, uint32_t dst_v4 = sk->dst_addr->v4.sin_addr.s_addr; int ret, exit_code = -1, family; char errbuf[LIBNET_ERRBUF_SIZE]; - int mark = SOCCR_MARK;; + int mark = SOCCR_MARK; int libnet_type; libnet_t *l; diff --git a/test/zdtm/static/maps06.c b/test/zdtm/static/maps06.c index df57fdb40..14dd90f43 100644 --- a/test/zdtm/static/maps06.c +++ b/test/zdtm/static/maps06.c @@ -51,7 +51,7 @@ int main(int argc, char ** argv) for (i = 0; i < TEST_SIZE; i++) { int *addr; - addr = start + i * 3 * 4096;; + addr = start + i * 3 * 4096; if (addr[0] != i * 2) fail(); addr = start + (i * 3 + 1) * 4096; diff --git a/test/zdtm/static/mountpoints.c b/test/zdtm/static/mountpoints.c index 17fa9311c..00475cdc5 100644 --- a/test/zdtm/static/mountpoints.c +++ b/test/zdtm/static/mountpoints.c @@ -56,7 +56,7 @@ int ns_child(void *_arg) test_waitsig(); if (pid) { - int status = 1;; + int status = 1; kill(pid, SIGTERM); wait(&status); if (status) diff --git a/test/zdtm/static/session01.c b/test/zdtm/static/session01.c index 155e9a460..7e6dee255 100644 --- a/test/zdtm/static/session01.c +++ b/test/zdtm/static/session01.c @@ -202,7 +202,7 @@ int main(int argc, char ** argv) test_init(argc, argv); - testcases[0].master.pid = getpid();; + testcases[0].master.pid = getpid(); if (child(0)) goto err; diff --git a/test/zdtm/static/sk-netlink.c b/test/zdtm/static/sk-netlink.c index f334246e2..7f06f0259 100644 --- a/test/zdtm/static/sk-netlink.c +++ b/test/zdtm/static/sk-netlink.c @@ -76,7 +76,7 @@ int main(int argc, char ** argv) return 1; } - addr.nl_pid = getpid();; + addr.nl_pid = getpid(); addr.nl_groups = 1 << (UDEV_MONITOR_TEST - 1); if (connect(csk, (struct sockaddr *) &addr, sizeof(struct sockaddr_nl))) { pr_perror("connect"); @@ -98,7 +98,7 @@ int main(int argc, char ** argv) msg.msg_iovlen = 1; iov.iov_base = (void *) &req; - iov.iov_len = sizeof(req);; + iov.iov_len = sizeof(req); if (sendmsg(csk, &msg, 0) < 0) { pr_perror("Can't send request message"); @@ -134,7 +134,7 @@ int main(int argc, char ** argv) msg.msg_iovlen = 1; iov.iov_base = (void *) &req; - iov.iov_len = sizeof(req);; + iov.iov_len = sizeof(req); if (sendmsg(dsk, &msg, 0) < 0) { pr_perror("Can't send request message"); diff --git a/test/zdtm/transition/netlink00.c b/test/zdtm/transition/netlink00.c index 9a2ed1680..e69d579ba 100644 --- a/test/zdtm/transition/netlink00.c +++ b/test/zdtm/transition/netlink00.c @@ -285,7 +285,7 @@ int form_request_add() ((char *)rtap) + sizeof(struct rtattr)); req.nl.nlmsg_len = NLMSG_ALIGN(req.nl.nlmsg_len) + RTA_ALIGN(rtap->rta_len); - rtap = NLMSG_TAIL(&req.nl);; + rtap = NLMSG_TAIL(&req.nl); rtap->rta_type = RTA_OIF;//Output interface index rtap->rta_len = RTA_LENGTH(sizeof(int)); memcpy(((char *)rtap) + sizeof(struct rtattr), From c12409fc5fe79c0ef800ab6e4502b83070829863 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Tue, 24 Apr 2018 21:18:45 +0300 Subject: [PATCH 1421/4375] zdtm: calling futex via syscall saves error codes in errno man 2 futex: In the event of an error (and assuming that futex() was invoked via syscall(2)), all operations return -1 and set errno to indicate the cause of the error. Signed-off-by: Andrei Vagin --- test/zdtm/lib/lock.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/zdtm/lib/lock.h b/test/zdtm/lib/lock.h index db9e96d0e..972ed5769 100644 --- a/test/zdtm/lib/lock.h +++ b/test/zdtm/lib/lock.h @@ -144,7 +144,9 @@ static void inline mutex_lock(mutex_t *m) while ((c = atomic_inc(&m->raw))) { ret = sys_futex(&m->raw, FUTEX_WAIT, c + 1, NULL, NULL, 0); - BUG_ON(ret < 0 && ret != -EWOULDBLOCK); + if (ret < 0) + pr_perror("futex"); + BUG_ON(ret < 0 && errno != -EWOULDBLOCK); } } From e52add949a9f4685f97bd4ab4322d495db2da7f5 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 24 Apr 2018 19:50:03 +0100 Subject: [PATCH 1422/4375] test/make: Include .d files Include deps files to recompile tests when dependency has changed. Cc: Cyrill Gorcunov Reported-by: Andrei Vagin Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/lib/Makefile | 1 + test/zdtm/static/Makefile | 2 ++ test/zdtm/transition/Makefile | 1 + 3 files changed, 4 insertions(+) diff --git a/test/zdtm/lib/Makefile b/test/zdtm/lib/Makefile index d2d9f1cc3..d0a667862 100644 --- a/test/zdtm/lib/Makefile +++ b/test/zdtm/lib/Makefile @@ -16,6 +16,7 @@ LDLIBS := $(LIB) TARGETS := $(LIB) $(BIN) include ../Makefile.inc +include $(DEP) all: $(TARGETS) .PHONY: all diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index fda601eeb..b01f5bf48 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -364,6 +364,8 @@ OUT = $(TST:%=%.out) STATE = $(TST_STATE:%=%.state) STATE_OUT = $(TST_STATE:%=%.out) +include $(DEP) + all: $(TST) criu-rtc.so install: all .PHONY: all install diff --git a/test/zdtm/transition/Makefile b/test/zdtm/transition/Makefile index f482a8a09..c64e4289d 100644 --- a/test/zdtm/transition/Makefile +++ b/test/zdtm/transition/Makefile @@ -38,6 +38,7 @@ PID = $(TST:%=%.pid) OUT = $(TST:%=%.out) include ../Makefile.inc +include $(DEP) all: $(TST) install: all From 8f7a52946f0dc7bfc9cd5f26f7e923fec566c392 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 23 Apr 2018 23:52:58 +0300 Subject: [PATCH 1423/4375] service: don't cache a service descriptor Service descriptros can be moved in a child process. v2: handle errors of install_service_fd() properly Signed-off-by: Andrei Vagin --- criu/action-scripts.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/criu/action-scripts.c b/criu/action-scripts.c index 4fa8e2843..3cbe89ee4 100644 --- a/criu/action-scripts.c +++ b/criu/action-scripts.c @@ -43,7 +43,6 @@ enum { }; static int scripts_mode = SCRIPTS_NONE; -static int rpc_sk; static LIST_HEAD(scripts); static int run_shell_scripts(const char *action) @@ -103,10 +102,13 @@ static int run_shell_scripts(const char *action) int rpc_send_fd(enum script_actions act, int fd) { const char *action = action_names[act]; + int rpc_sk; if (scripts_mode != SCRIPTS_RPC) return -1; + rpc_sk = get_service_fd(RPC_SK_OFF); + pr_debug("\tRPC\n"); return send_criu_rpc_script(act, (char *)action, rpc_sk, fd); } @@ -122,7 +124,10 @@ int run_scripts(enum script_actions act) return 0; if (scripts_mode == SCRIPTS_RPC) { + int rpc_sk; + pr_debug("\tRPC\n"); + rpc_sk = get_service_fd(RPC_SK_OFF); ret = send_criu_rpc_script(act, (char *)action, rpc_sk, -1); goto out; } @@ -161,7 +166,8 @@ int add_rpc_notify(int sk) BUG_ON(scripts_mode == SCRIPTS_SHELL); scripts_mode = SCRIPTS_RPC; - rpc_sk = install_service_fd(RPC_SK_OFF, sk); + if (install_service_fd(RPC_SK_OFF, sk) < 0) + return -1; return 0; } From 3d5ee999744749e5b45859226187c22fdeca3c62 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 28 Apr 2018 09:02:31 +0300 Subject: [PATCH 1424/4375] zdtm: always run criu dump with --track-mem if --snaps is set Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index d61e71105..ac60d3a38 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1147,7 +1147,7 @@ def cr(cr_api, test, opts): pres = iter_parm(opts['pre'], 0) for p in pres[0]: if opts['snaps']: - cr_api.dump("dump", opts = ["--leave-running"]) + cr_api.dump("dump", opts = ["--leave-running", "--track-mem"]) else: cr_api.dump("pre-dump") try_run_hook(test, ["--post-pre-dump"]) From c2876c2f250cd20e0d732e980a3f4e203321bfe7 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 19 Apr 2018 04:22:53 +0100 Subject: [PATCH 1425/4375] nmk: Don't redefine MAKEFLAGS $(MAKEFLAGS) already contains -r -R and --no-print-directory: those flags are being added in include.mk.. which is included two lines above. There is no comment and I see no big sense in erasing $(MAKEFLAGS), rather than adding those flags. So I considered this as a typo. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- scripts/nmk/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/nmk/Makefile b/scripts/nmk/Makefile index baab57b94..ba4aca88c 100644 --- a/scripts/nmk/Makefile +++ b/scripts/nmk/Makefile @@ -3,8 +3,6 @@ export __nmk_dir include $(__nmk_dir)include.mk -MAKEFLAGS := -r -R --no-print-directory - help: @echo ' Targets:' @echo ' install dir= - Install scripts into directory ' From 919f54881350cce75ea590a4a361e6138ead5763 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 19 Apr 2018 04:22:54 +0100 Subject: [PATCH 1426/4375] test/make: Drop implicit make variables Let's drop usage of COMPILE.c, OUTPUT_OPTION. It will allow run submake with -R. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/Makefile.inc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index 673fa1bc6..12fa86e08 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -54,14 +54,13 @@ ifeq ($(ARCH),x86) endif endif -DEPEND.c = $(COMPILE.c) -MM -MP -%.d: %.c - $(E) " DEP " $*.d - $(Q)$(DEPEND.c) $(OUTPUT_OPTION) $< +%.d: %.c + $(E) " DEP " $@ + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -MM -MP -c $< -o $@ %.o: %.c | %.d $(E) " CC " $@ - $(Q)$(COMPILE.c) $(OUTPUT_OPTION) $< + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ %: %.o $(LDLIBS) @echo $@ >> .gitignore From f54942c62a46ffaa1cee9d634af5a79e29e93ad0 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 19 Apr 2018 04:22:55 +0100 Subject: [PATCH 1427/4375] make: Don't set $(MAKEFLAGS) We shouldn't set MAKEFLAGS by the following reasons: 1. User may want to specify some make parameter (e.g., `-d` for debug) 2. We lose parallel build. No `-j` is passed to submake and it looks like, gnu/make will not deal with parallel recursive make if $(MAKEFLAGS) is unset back. Easy to verify: Add `sleep 3` to build rule in Makefile.inc and you'll find only one sleep process at a time. After the patch if you specify say `-j5` to make - you'll have 5 sleep processes. Reverts: commit e9beed7bb3f3 ("build: zdtm -- Add implicit rules into zdtm building"). Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index b9cc42286..6522d91df 100644 --- a/Makefile +++ b/Makefile @@ -278,11 +278,11 @@ docs: .PHONY: docs zdtm: all - $(Q) MAKEFLAGS= $(MAKE) -C test/zdtm all + $(Q) $(MAKE) -C test/zdtm all .PHONY: zdtm test: zdtm - $(Q) MAKEFLAGS= $(MAKE) -C test + $(Q) $(MAKE) -C test .PHONY: test # From 345250b89fed6ca568e3a176efa678a35bcbda61 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 30 Apr 2018 02:10:59 +0300 Subject: [PATCH 1428/4375] zdtm: include lock.h after zdtmtst.h In file included from s390x_gs_threads.c:10:0: ../lib/lock.h: In function 'mutex_lock': ../lib/lock.h:148:4: error: implicit declaration of function 'pr_perror' [-Werror=implicit-function-declaration] pr_perror("futex"); Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin --- test/zdtm/static/s390x_gs_threads.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/s390x_gs_threads.c b/test/zdtm/static/s390x_gs_threads.c index 486b32087..7d3a07521 100644 --- a/test/zdtm/static/s390x_gs_threads.c +++ b/test/zdtm/static/s390x_gs_threads.c @@ -7,8 +7,8 @@ #include #include -#include "lock.h" #include "zdtmtst.h" +#include "lock.h" #define NR_THREADS 4 #define GS_ENABLE 0 From 5d3ea878fbab690dbad7d616de4069783183b46c Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 8 May 2018 02:08:44 +0300 Subject: [PATCH 1429/4375] travis: rollback to fedora 27 We have a few issues with fc28. For example: https://github.com/checkpoint-restore/criu/issues/469 Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.fedora-asan.hdr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Dockerfile.fedora-asan.hdr b/scripts/build/Dockerfile.fedora-asan.hdr index 328af2433..8c77c2551 100644 --- a/scripts/build/Dockerfile.fedora-asan.hdr +++ b/scripts/build/Dockerfile.fedora-asan.hdr @@ -1,2 +1,2 @@ -FROM fedora:latest +FROM fedora:27 ENV ASAN=1 From a80f1da90c2cecc0caf9b6e3a7353e99f0e096e3 Mon Sep 17 00:00:00 2001 From: Joel Nider Date: Tue, 8 May 2018 10:33:27 +0300 Subject: [PATCH 1430/4375] compel: std_vprint_num returns a null-terminated string This function is an analogue to vsprintf(), and is used in very much the same way. The caller expects the modified string pointer to be pointing to a null-terminated string. Signed-off-by: Joel Nider Signed-off-by: Andrei Vagin --- compel/plugins/std/log.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compel/plugins/std/log.c b/compel/plugins/std/log.c index 2d622d658..81611d1f1 100644 --- a/compel/plugins/std/log.c +++ b/compel/plugins/std/log.c @@ -143,6 +143,7 @@ int std_vprint_num(char *buf, int blen, int num, char **ps) char *s; s = &buf[blen - 1]; + *s-- = 0; /* make sure the returned string is NULL terminated */ if (num < 0) { neg = 1; @@ -166,15 +167,14 @@ int std_vprint_num(char *buf, int blen, int num, char **ps) done: s++; *ps = s; - return blen - (s - buf); + return blen - (s - buf) - 1; } static void print_num(int num, struct simple_buf *b) { char buf[12], *s; - buf[11] = '\0'; - std_vprint_num(buf, sizeof(buf) - 1, num, &s); + std_vprint_num(buf, sizeof(buf), num, &s); print_string(s, b); } From 0f5705b08a9ad814917b5ef76e4eb8ddd311181a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 14 Feb 2018 00:29:47 +0300 Subject: [PATCH 1431/4375] log: pr_warn_once -- Fix formatting Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/log.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/criu/include/log.h b/criu/include/log.h index 9c4c28386..797be1bb2 100644 --- a/criu/include/log.h +++ b/criu/include/log.h @@ -61,7 +61,9 @@ extern void print_on_level(unsigned int loglevel, const char *format, ...) __FILE__, __LINE__, ##__VA_ARGS__) #define pr_warn_once(fmt, ...) \ - print_once(LOG_WARN, fmt, ##__VA_ARGS__) + print_once(LOG_WARN, \ + "Warn (%s:%d): " LOG_PREFIX fmt, \ + __FILE__, __LINE__, ##__VA_ARGS__) #define pr_debug(fmt, ...) \ print_on_level(LOG_DEBUG, \ From 8a85222afed4bf52addf0a89b04ee56d8a32d32e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 9 May 2018 23:53:17 +0300 Subject: [PATCH 1432/4375] zdtm: create /run in a test root iptables 1.6.2 fails without /run, because it tries to create the /run/xtables.lock file Test output: ================================ Fatal: can't open lock file /run/xtables.lock: No such file or directory 23:29:06.098: 4: ERR: netns-nf.c:21: Can't set input rule (errno = 2 (No such file or directory)) 23:29:06.098: 3: ERR: test.c:315: Test exited unexpectedly with code 255 Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index ac60d3a38..ce8b3b9c5 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -155,7 +155,7 @@ class host_flavor: class ns_flavor: - __root_dirs = ["/bin", "/sbin", "/etc", "/lib", "/lib64", "/dev", "/dev/pts", "/dev/net", "/tmp", "/usr", "/proc"] + __root_dirs = ["/bin", "/sbin", "/etc", "/lib", "/lib64", "/dev", "/dev/pts", "/dev/net", "/tmp", "/usr", "/proc", "/run"] def __init__(self, opts): self.name = "ns" From 2af17257cb28280984b8b87cd2e4be5bed9d15e9 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 9 May 2018 23:53:18 +0300 Subject: [PATCH 1433/4375] net: workaround a problem when iptables can't open /run/xtables.lock Starting with iptables 1.6.2, we have to use the --wait option, but it doesn't work properly with userns, because in this case, we don't have enough rights to open /run/xtables.lock. (00.174703) 1: Running iptables-restore -w for iptables-restore -w Fatal: can't open lock file /run/xtables.lock: Permission denied (00.192058) 1: Error (criu/util.c:842): exited, status=4 (00.192080) 1: Error (criu/net.c:1738): iptables-restore -w failed (00.192088) 1: Error (criu/net.c:2389): Can't create net_ns (00.192131) 1: Error (criu/util.c:1567): Can't wait or bad status: errno=0, status=65280 This patch workarounds this problem by mounting tmpfs into /run. Net namespaces are restored in a separate process, so we can create a new mount namespace and create new mounts. https://github.com/checkpoint-restore/criu/issues/469 Cc: Pavel Tikhomirov Cc: Kirill Tkhai Signed-off-by: Andrei Vagin Signed-off-by: Andrei Vagin --- criu/net.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/criu/net.c b/criu/net.c index cacb69256..2fa6941bb 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1965,6 +1965,48 @@ out: return ret; } +/* + * iptables-restore is executed from a target userns and it may have not enough + * rights to open /run/xtables.lock. Here we try to workaround this problem. + */ +static int prepare_xtable_lock() +{ + int fd; + + fd = open("/run/xtables.lock", O_RDONLY); + if (fd >= 0) { + close(fd); + return 0; + } + + /* + * __prepare_net_namespaces is executed in a separate process, + * so a mount namespace can be changed. + */ + if (unshare(CLONE_NEWNS)) { + pr_perror("Unable to create a mount namespace"); + return -1; + } + + if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL)) { + pr_perror("Unable to conver mounts to slave mounts"); + return -1; + } + /* + * /run/xtables.lock may not exist, so we can't just bind-mount a file + * over it. + * A new mount will not be propagated to the host mount namespace, + * because we are in another userns. + */ + + if (mount("criu-xtable-lock", "/run", "tmpfs", 0, NULL)) { + pr_perror("Unable to mount tmpfs into /run"); + return -1; + } + + return 0; +} + static inline int restore_iptables(int pid) { int ret = -1; @@ -2311,6 +2353,9 @@ static int __prepare_net_namespaces(void *unused) struct ns_id *nsid; int root_ns; + if (prepare_xtable_lock()) + return -1; + root_ns = open_proc(PROC_SELF, "ns/net"); if (root_ns < 0) return -1; From c76849133e6b0346efa6be9de6e102874c3a2570 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 12 May 2018 07:05:59 +0300 Subject: [PATCH 1434/4375] zdtm: mount tmpfs into /run in a test root iptables creates /run/xtables.lock file and we want to have it per-test. (00.332159) 1: Running iptables-restore -w for iptables-restore -w Fatal: can't open lock file /run/xtables.lock: Permission denied Signed-off-by: Andrei Vagin --- test/zdtm/lib/ns.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/zdtm/lib/ns.c b/test/zdtm/lib/ns.c index bf8ca1979..f758061c5 100644 --- a/test/zdtm/lib/ns.c +++ b/test/zdtm/lib/ns.c @@ -98,6 +98,11 @@ static int prepare_mntns(void) return -1; } + if (mount("zdtm_run", "/run", "tmpfs", 0, NULL)) { + fprintf(stderr, "Unable to mount /run: %m\n"); + return -1; + } + if (umount2("./old", MNT_DETACH)) { fprintf(stderr, "umount(./old) failed: %m\n"); return -1; From 17e80025965d0a9c6ee5f66b5a055d628e9f0b9c Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 12 May 2018 09:07:54 +0300 Subject: [PATCH 1435/4375] fs: take into account that cr_system overrides standard descriptors (00.027596) mnt: Dumping mountpoints (00.027600) mnt: 90: 2f:/ @ ./dev/pts (00.027614) mnt: 130: 2e:/ @ ./run tar: /proc/self/fd/1: Cannot open: Not a directory tar: Error is not recoverable: exiting now Signed-off-by: Andrei Vagin --- criu/filesystems.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/criu/filesystems.c b/criu/filesystems.c index fa6d96ecf..59f7c99fe 100644 --- a/criu/filesystems.c +++ b/criu/filesystems.c @@ -384,15 +384,27 @@ static int tmpfs_dump(struct mount_info *pm) int ret = -1, fd = -1, userns_pid = -1; char tmpfs_path[PSFDS]; struct cr_img *img; + int tmp_fds[3], ntmp_fds = 0, i; fd = open_mountpoint(pm); if (fd < 0) return MNT_UNREACHABLE; - /* if fd happens to be 0 here, we need to move it to something - * non-zero, because cr_system_userns closes STDIN_FILENO as we are not - * interested in passing stdin to tar. + /* + * fd should not be one of standard descriptors, because + * cr_system_userns will override them. */ + for (i = 0; i < 3; i++) { + if (fd > 2) + break; + tmp_fds[ntmp_fds++] = fd; + fd = dup(fd); + if (fd < 0) { + pr_perror("Unable to duplicate a file descriptor"); + goto out; + } + } + if (move_fd_from(&fd, STDIN_FILENO) < 0) goto out; @@ -427,6 +439,8 @@ static int tmpfs_dump(struct mount_info *pm) close_image(img); out: + for (i = 0; i < ntmp_fds; i++) + close(tmp_fds[i]); close_safe(&fd); return ret; } From 8338cbc4836f43b7732b2bb9a1480cf9f7399350 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 6 Apr 2018 10:27:19 +0300 Subject: [PATCH 1436/4375] criu: initialize logging for libraries from log_set_loglevel() We have three code paths, where we call log_set_loglevel() and in all these places, we need to initialize libraries logging engines, so it is better to do this from one function. For example, currently we forgot to initialize soccr logging for criu swrk. Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Acked-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/crtools.c | 26 -------------------------- criu/log.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index 42cfd91e9..259580f36 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -57,8 +57,6 @@ #include "setproctitle.h" #include "sysctl.h" -#include "../soccr/soccr.h" - struct cr_options opts; void init_opts(void) @@ -213,28 +211,6 @@ bool deprecated_ok(char *what) return false; } -static void soccr_print_on_level(unsigned int loglevel, const char *format, ...) -{ - va_list args; - int lv; - - switch (loglevel) { - case SOCCR_LOG_DBG: - lv = LOG_DEBUG; - break; - case SOCCR_LOG_ERR: - lv = LOG_ERROR; - break; - default: - lv = LOG_INFO; - break; - } - - va_start(args, format); - vprint_on_level(lv, format, args); - va_end(args); -} - static void rlimit_unlimit_nofile_self(void) { struct rlimit new; @@ -750,8 +726,6 @@ int main(int argc, char *argv[], char *envp[]) if (log_init(opts.output)) return 1; - libsoccr_set_log(log_level, soccr_print_on_level); - compel_log_init(vprint_on_level, log_get_loglevel()); print_versions(); diff --git a/criu/log.c b/criu/log.c index be3e4499e..22c6f2950 100644 --- a/criu/log.c +++ b/criu/log.c @@ -20,6 +20,9 @@ #include "rst-malloc.h" #include "common/lock.h" #include "string.h" +#include "../soccr/soccr.h" +#include "compel/log.h" + #define DEFAULT_LOGFD STDERR_FILENO /* Enable timestamps if verbosity is increased from default */ @@ -199,9 +202,34 @@ void log_fini(void) close_service_fd(LOG_FD_OFF); } +static void soccr_print_on_level(unsigned int loglevel, const char *format, ...) +{ + va_list args; + int lv; + + switch (loglevel) { + case SOCCR_LOG_DBG: + lv = LOG_DEBUG; + break; + case SOCCR_LOG_ERR: + lv = LOG_ERROR; + break; + default: + lv = LOG_INFO; + break; + } + + va_start(args, format); + vprint_on_level(lv, format, args); + va_end(args); +} + void log_set_loglevel(unsigned int level) { current_loglevel = level; + + libsoccr_set_log(level, soccr_print_on_level); + compel_log_init(vprint_on_level, level); } unsigned int log_get_loglevel(void) From 3e86fb12bc37c2fd62365cee595b8a7ebd1ab718 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 6 Apr 2018 10:27:19 +0300 Subject: [PATCH 1437/4375] criu: print criu and kernel versions from log_init() log_init() opens a log file. We want to have criu and kernel versions in each log file, so it looks reasonable to print them from log_init(). Without this patch, versions are not printed, if criu is called in the swrk mode. Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Acked-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-service.c | 2 -- criu/crtools.c | 2 -- criu/include/util.h | 2 -- criu/log.c | 21 +++++++++++++++++++++ criu/util.c | 18 ------------------ 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index d1323dbce..0928df880 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -307,8 +307,6 @@ static int setup_opts_from_req(int sk, CriuOpts *req) goto err; } - print_versions(); - /* checking flags from client */ if (req->has_leave_running && req->leave_running) opts.final_state = TASK_ALIVE; diff --git a/criu/crtools.c b/criu/crtools.c index 259580f36..2c3e0c613 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -727,8 +727,6 @@ int main(int argc, char *argv[], char *envp[]) if (log_init(opts.output)) return 1; - print_versions(); - if (opts.deprecated_ok) pr_debug("DEPRECATED ON\n"); diff --git a/criu/include/util.h b/criu/include/util.h index 757defd55..5c18e69f7 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -377,6 +377,4 @@ static inline void print_stack_trace(pid_t pid) {} ___ret; \ }) -extern void print_versions(void); - #endif /* __CR_UTIL_H__ */ diff --git a/criu/log.c b/criu/log.c index 22c6f2950..6a13266eb 100644 --- a/criu/log.c +++ b/criu/log.c @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -20,6 +21,8 @@ #include "rst-malloc.h" #include "common/lock.h" #include "string.h" +#include "version.h" + #include "../soccr/soccr.h" #include "compel/log.h" @@ -135,6 +138,22 @@ char *log_first_err(void) return first_err->s; } +static void print_versions(void) +{ + struct utsname buf; + + pr_info("Version: %s (gitid %s)\n", CRIU_VERSION, CRIU_GITID); + + if (uname(&buf) < 0) { + pr_perror("Reading kernel version failed!"); + /* This pretty unlikely, just keep on running. */ + return; + } + + pr_info("Running on %s %s %s %s %s\n", buf.nodename, buf.sysname, + buf.release, buf.version, buf.machine); +} + int log_init(const char *output) { int new_logfd, fd; @@ -167,6 +186,8 @@ int log_init(const char *output) if (fd < 0) goto err; + print_versions(); + return 0; err: diff --git a/criu/util.c b/criu/util.c index d6d03a502..cf617bed4 100644 --- a/criu/util.c +++ b/criu/util.c @@ -34,7 +34,6 @@ #include #include #include -#include #include "bitops.h" #include "page.h" @@ -54,7 +53,6 @@ #include "cr-service.h" #include "files.h" #include "pstree.h" -#include "version.h" #include "cr-errno.h" @@ -1517,19 +1515,3 @@ void print_stack_trace(pid_t pid) free(strings); } #endif - -void print_versions(void) -{ - struct utsname buf; - - pr_info("Version: %s (gitid %s)\n", CRIU_VERSION, CRIU_GITID); - - if (uname(&buf) < 0) { - pr_perror("Reading kernel version failed!"); - /* This pretty unlikely, just keep on running. */ - return; - } - - pr_info("Running on %s %s %s %s %s\n", buf.nodename, buf.sysname, - buf.release, buf.version, buf.machine); -} From 9eb9abb62f96164e96a24ef607d22193dbdeb593 Mon Sep 17 00:00:00 2001 From: Andy Tucker Date: Tue, 10 Apr 2018 12:54:11 -0700 Subject: [PATCH 1438/4375] files: Fail dump if dump_one_file() fails When dumping a process with a large number of open files, dump_task_files_seized() processes the fds in batches. If dump_one_file() results in an error, processing of the current batch is stopped but the next batch (if any) will still be fetched and the error value is overwritten. The result is a corrupt dump image (the fdinfo file is missing a bunch of fds) which results in restore failure. Also close all received fds after an error (previously the skipped ones were left open). Signed-off-by: Andy Tucker Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/files.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/criu/files.c b/criu/files.c index ac0d1715e..4585395a6 100644 --- a/criu/files.c +++ b/criu/files.c @@ -606,7 +606,7 @@ int dump_task_files_seized(struct parasite_ctl *ctl, struct pstree_item *item, goto err; ret = 0; /* Don't fail if nr_fds == 0 */ - for (off = 0; off < dfds->nr_fds; off += nr_fds) { + for (off = 0; ret == 0 && off < dfds->nr_fds; off += nr_fds) { if (nr_fds + off > dfds->nr_fds) nr_fds = dfds->nr_fds - off; @@ -620,7 +620,6 @@ int dump_task_files_seized(struct parasite_ctl *ctl, struct pstree_item *item, ret = dump_one_file(item->pid, dfds->fds[i + off], lfds[i], opts + i, ctl, &e); - close(lfds[i]); if (ret) break; @@ -628,6 +627,9 @@ int dump_task_files_seized(struct parasite_ctl *ctl, struct pstree_item *item, if (ret) break; } + + for (i = 0; i < nr_fds; i++) + close(lfds[i]); } pr_info("----------------------------------------\n"); From a66bfa58008f6a2dce74110f6ed35caed367582d Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 20 Apr 2018 13:10:22 +0300 Subject: [PATCH 1439/4375] helper: Move service fds closing code to restore_one_helper() There is no reasons we need this cleanup code in generic restore_one_task(), so let's move it for better readability. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 4aa811270..0bbf4beec 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1164,15 +1164,26 @@ static int wait_exiting_children(void) */ static int restore_one_helper(void) { + int i; + if (prepare_fds(current)) return -1; - return wait_exiting_children(); + if (wait_exiting_children()) + return -1; + + sfds_protected = false; + close_image_dir(); + close_proc(); + for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) + close_service_fd(i); + + return 0; } static int restore_one_task(int pid, CoreEntry *core) { - int i, ret; + int ret; /* No more fork()-s => no more per-pid logs */ @@ -1182,11 +1193,6 @@ static int restore_one_task(int pid, CoreEntry *core) ret = restore_one_zombie(core); else if (current->pid->state == TASK_HELPER) { ret = restore_one_helper(); - sfds_protected = false; - close_image_dir(); - close_proc(); - for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) - close_service_fd(i); } else { pr_err("Unknown state in code %d\n", (int)core->tc->task_state); ret = -1; From fbd8dd889ddd37583f21136648cac6197e44e501 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 28 Apr 2018 09:02:29 +0300 Subject: [PATCH 1440/4375] mem: return -1 from __parasite_dump_pages_seized in error cases Here is one of often mistakes: int funcX() { int ret; ret = funcA() if (ret < 0) goto err; if (smth) goto err; // return 0 !!!! err: return ret; } Signed-off-by: Andrei Vagin --- criu/mem.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/criu/mem.c b/criu/mem.c index 162e98a28..9909ef09d 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -300,7 +300,7 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, struct page_pipe *pp; struct vma_area *vma_area; struct page_xfer xfer = { .parent = NULL }; - int ret = -1; + int ret, exit_code = -1; unsigned cpp_flags = 0; unsigned long pmc_size; @@ -323,7 +323,6 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, pmc_size * PAGE_SIZE)) return -1; - ret = -1; if (!(mdc->pre_dump || mdc->lazy)) /* * Chunk mode pushes pages portion by portion. This mode @@ -416,6 +415,9 @@ again: */ ret = task_reset_dirty_track(item->pid->real); + if (ret) + goto out_xfer; + exit_code = 0; out_xfer: if (!mdc->pre_dump) xfer.close(&xfer); @@ -427,7 +429,7 @@ out_pp: out: pmc_fini(&pmc); pr_info("----------------------------------------\n"); - return ret; + return exit_code; } int parasite_dump_pages_seized(struct pstree_item *item, From 7af751b5696db1a1c4e1796bae9e29cbc303d63d Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 29 Mar 2018 10:02:29 +0300 Subject: [PATCH 1441/4375] test/other: add a test to check the --shell-job option This test creates a pty pair, creates a test process and sets a slave pty as control terminal for it. Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 3 ++ test/Makefile | 2 +- test/others/shell-job/Makefile | 2 ++ test/others/shell-job/run.py | 65 ++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 test/others/shell-job/Makefile create mode 100755 test/others/shell-job/run.py diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 863a31057..17c8c231d 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -107,6 +107,7 @@ bash ./test/jenkins/criu-inhfd.sh make -C test/others/mnt-ext-dev/ run #make -C test/others/exec/ run make -C test/others/make/ run CC="$CC" +make -C test/others/shell-job/ run ./test/zdtm.py run -t zdtm/static/env00 --sibling @@ -127,6 +128,8 @@ ip net add test ./test/zdtm.py run --empty-ns -T zdtm/static/socket-tcp*-local --iter 2 +make -C test/others/shell-job + pip install flake8 make lint diff --git a/test/Makefile b/test/Makefile index 6d7557124..9938015e0 100644 --- a/test/Makefile +++ b/test/Makefile @@ -11,7 +11,7 @@ all: $(MAKE) zdtm-freezer .PHONY: all -TESTS = unix-callback mem-snap rpc libcriu mounts/ext security pipes crit socketpairs overlayfs mnt-ext-dev +TESTS = unix-callback mem-snap rpc libcriu mounts/ext security pipes crit socketpairs overlayfs mnt-ext-dev shell-job other: for t in $(TESTS); do \ diff --git a/test/others/shell-job/Makefile b/test/others/shell-job/Makefile new file mode 100644 index 000000000..d81733ef4 --- /dev/null +++ b/test/others/shell-job/Makefile @@ -0,0 +1,2 @@ +run: + ../../zdtm_ct run.py diff --git a/test/others/shell-job/run.py b/test/others/shell-job/run.py new file mode 100755 index 000000000..9e87d12e4 --- /dev/null +++ b/test/others/shell-job/run.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python2 +import os, pty, sys, subprocess +import termios, fcntl, time, signal + +cr_bin = "../../../criu/criu" + +os.chdir(os.getcwd()) + +def create_pty(): + (fd1, fd2) = pty.openpty() + return (os.fdopen(fd1, "w+"), os.fdopen(fd2, "w+")) + +if not os.access("work", os.X_OK): + os.mkdir("work", 0755) + +open("running", "w").close() +m,s = create_pty() +p = os.pipe() +pr = os.fdopen(p[0], "r") +pw = os.fdopen(p[1], "w") + +pid = os.fork() +if pid == 0: + m.close() + os.setsid() + os.dup2(s.fileno(), 0) + os.dup2(s.fileno(), 1) + os.dup2(s.fileno(), 2) + fcntl.ioctl(s.fileno(), termios.TIOCSCTTY, 1) + pr.close() + pw.close() + while True: + if not os.access("running", os.F_OK): + sys.exit(0) + time.sleep(1) + sys.exit(1) + +pw.close() +pr.read(1) + +cmd = [cr_bin, "dump", "-j", "-t", str(pid), "-D", "work", "-v"] +print("Run: %s" % " ".join(cmd)) +ret = subprocess.Popen(cmd).wait() +if ret != 0: + sys.exit(1) +os.wait() + +os.unlink("running") +m,s = create_pty() +cpid = os.fork() +if cpid == 0: + os.setsid() + fcntl.ioctl(m.fileno(), termios.TIOCSCTTY, 1) + cmd = [cr_bin, "restore", "-j", "-D", "work", "-v"] + print("Run: %s" % " ".join(cmd)) + ret = subprocess.Popen([cr_bin, "restore", "-j", "-D", "work", "-v"]).wait() + if ret != 0: + sys.exit(1) + sys.exit(0) + +pid, status = os.wait() +if status != 0: + print("A child process exited with %d" % status) + sys.exit(1) + From ac713a9b5a9b1901c3fa4f9932986836b1e21856 Mon Sep 17 00:00:00 2001 From: Vitaly Ostrosablin Date: Tue, 3 Apr 2018 19:42:14 +0300 Subject: [PATCH 1442/4375] zdtm: Add a test to check if we can C/R ghost files with no parent dirs. This is test that triggers a bug with ghost files, that was resolved in patch "Don't fail if ghost file has no parent dirs". Signed-off-by: Vitaly Ostrosablin Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/unlink_multiple_largefiles.c | 263 ++++++++++++++++++ .../static/unlink_multiple_largefiles.desc | 1 + 3 files changed, 265 insertions(+) create mode 100644 test/zdtm/static/unlink_multiple_largefiles.c create mode 100644 test/zdtm/static/unlink_multiple_largefiles.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index b01f5bf48..6dfe95905 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -202,6 +202,7 @@ TST_NOFILE := \ pipe03 \ netns_sub \ netns_sub_veth \ + unlink_multiple_largefiles \ # jobctl00 \ include ../Makefile.inc diff --git a/test/zdtm/static/unlink_multiple_largefiles.c b/test/zdtm/static/unlink_multiple_largefiles.c new file mode 100644 index 000000000..c6400b4ff --- /dev/null +++ b/test/zdtm/static/unlink_multiple_largefiles.c @@ -0,0 +1,263 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "zdtmtst.h" + + +#define FSIZE 0x3B600000ULL +#define NFILES 10 +#define BUFSIZE (1<<20) + +const char *test_doc = "C/R of ten big (951MiB) unlinked files in root dir"; +const char *test_author = "Vitaly Ostrosablin "; + +void create_check_pattern(char *buf, size_t count, unsigned char seed) +{ + int i; + + for (i = 0; i < count; i++) + buf[i] = seed++; +} + +struct fiemap *read_fiemap(int fd) +{ + test_msg("Obtaining fiemap for fd %d\n", fd); + struct fiemap *fiemap; + int extents_size; + + fiemap = malloc(sizeof(struct fiemap)); + if (fiemap == NULL) { + pr_perror("Cannot allocate fiemap"); + return NULL; + } + memset(fiemap, 0, sizeof(struct fiemap)); + + fiemap->fm_length = FIEMAP_MAX_OFFSET; + fiemap->fm_start = 0; + fiemap->fm_flags = 0; + fiemap->fm_extent_count = 0; + + if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) { + pr_perror("FIEMAP ioctl failed"); + return NULL; + } + + extents_size = sizeof(struct fiemap_extent) * fiemap->fm_mapped_extents; + + fiemap = realloc(fiemap,sizeof(struct fiemap) + extents_size); + if (fiemap == NULL) { + pr_perror("Cannot resize fiemap"); + return NULL; + } + memset(fiemap->fm_extents, 0, extents_size); + + fiemap->fm_extent_count = fiemap->fm_mapped_extents; + fiemap->fm_mapped_extents = 0; + + if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) { + pr_perror("fiemap ioctl() failed"); + return NULL; + } + test_msg("Debugkillme: %x\n", fiemap->fm_mapped_extents); + + return fiemap; +} + +void check_extent_map(struct fiemap *map) +{ + int i; + unsigned long long datasize = 0; + unsigned long long holesize = 0; + + test_msg("Verifying extent map...\n"); + + for (i = 0; i < map->fm_mapped_extents; i++) { + test_msg("Extent %d, start %llx, length %llx\n", + i, + map->fm_extents[i].fe_logical, + map->fm_extents[i].fe_length); + + if (i == 0) + holesize = map->fm_extents[i].fe_logical; + datasize += map->fm_extents[i].fe_length; + } + if (holesize != FSIZE) { + pr_err("Unexpected hole size %llx != %llx\n", holesize, + (unsigned long long) FSIZE); + exit(1); + } + if (datasize != BUFSIZE) { + pr_err("Unexpected data size %llx != %llx\n", datasize, + (unsigned long long) BUFSIZE); + exit(1); + } +} + +void compare_file_content(int fildes, int seed) +{ + char ebuf[BUFSIZE]; + char rbuf[BUFSIZE]; + char linkpath[PATH_MAX]; + int fd; + struct fiemap *fiemap; + + ssprintf(linkpath, "/proc/self/fd/%d", fildes); + + fd = open(linkpath, O_RDONLY | O_LARGEFILE); + if (fd < 0) { + pr_perror("Cannot open unlinked file %s", linkpath); + exit(1); + } + + memset(ebuf, 0, BUFSIZE); + + fiemap = read_fiemap(fd); + check_extent_map(fiemap); + free(fiemap); + + lseek64(fd, FSIZE, SEEK_SET); + + create_check_pattern(ebuf, BUFSIZE, seed); + + if (read(fd, rbuf, BUFSIZE) != BUFSIZE) { + pr_perror("Cannot read %i bytes from file", BUFSIZE); + goto failed; + } + + if (memcmp(&ebuf, &rbuf, BUFSIZE)) { + pr_err("Control Block: Data mismatch detected\n"); + goto failed; + } + + close(fd); + return; +failed: + close(fd); + exit(1); +} + +void read_proc_fd_link(int fd, char *buf) +{ + ssize_t res; + char linkpath[PATH_MAX]; + + ssprintf(linkpath, "/proc/%d/fd/%d", getpid(), fd); + + res = readlink(linkpath, buf, PATH_MAX - 1); + buf[res] = 0; + if (res < 0) { + pr_perror("Cannot read fd symlink %s", linkpath); + exit(1); + } +} + +int create_unlinked_file(int fileno) +{ + int fd; + char buf[BUFSIZE]; + char fnm[PATH_MAX]; + + ssprintf(fnm, "/unlinked%d", fileno); + fd = open(fnm, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); + if (fd < 0) { + pr_perror("Cannot create file %s", fnm); + exit(1); + } + test_msg("Created file: %s, fd %d\n", fnm, fd); + + if (lseek64(fd, FSIZE, SEEK_SET) < 0) { + pr_perror("Cannot seek to offset %llx", FSIZE); + goto failed; + } + test_msg("File positioning done, offset=%llx\n", FSIZE); + + create_check_pattern(&buf[0], BUFSIZE, fileno); + if (write(fd, buf, BUFSIZE) != BUFSIZE) { + pr_perror("Cannot write %i bytes to file", BUFSIZE); + goto failed; + } + test_msg("%i bytes written to file\n", BUFSIZE); + + if (unlink(fnm) < 0) { + pr_perror("Cannot unlink file %s", fnm); + goto failed; + } + test_msg("File %s is unlinked\n", fnm); + + return fd; +failed: + unlink(fnm); + close(fd); + return -1; +} + +int main(int argc, char **argv) +{ + int fd[NFILES] = {0}; + char links[NFILES][PATH_MAX]; + char link[PATH_MAX]; + int count = 0; + int tempfd; + + test_init(argc, argv); + + /* We need to create 10 unlinked files, each is around 1GB in size */ + for (count = 0; count < NFILES; count++) { + + test_msg("Creating unlinked file %d/%d\n", count + 1, NFILES); + tempfd = create_unlinked_file(count); + + if (tempfd < 0) { + pr_err("Cannot create unlinked file %d/%d\n", + count + 1, NFILES); + return 1; + } + + memset(&links[count][0], 0, PATH_MAX); + read_proc_fd_link(tempfd, &links[count][0]); + + fd[count] = tempfd; + } + test_msg("Created %d unlinked files\n", NFILES); + + test_daemon(); + test_msg("Test daemonized, PID %d\n", getpid()); + test_waitsig(); + + test_msg("PID %d resumed, doing final checks...\n", getpid()); + + for (count = 0; count < NFILES; count++) { + test_msg("Processing fd #%d (%d)\n", count, fd[count]); + + test_msg("Checking symlink consistency...\n"); + memset(&link[0], 0, PATH_MAX); + read_proc_fd_link(fd[count], &link[0]); + + if (strcmp(&links[count][0], &link[0])) { + pr_err("Symlink target %s has changed to %s\n", + links[count], link); + return 1; + } + + test_msg("Checking file contents...\n"); + compare_file_content(fd[count], count); + + test_msg("Closing file descriptor...\n"); + if (close(fd[count]) == -1) { + pr_perror("Close failed"); + return 1; + } + } + + pass(); + return 0; +} diff --git a/test/zdtm/static/unlink_multiple_largefiles.desc b/test/zdtm/static/unlink_multiple_largefiles.desc new file mode 100644 index 000000000..b4ab1a827 --- /dev/null +++ b/test/zdtm/static/unlink_multiple_largefiles.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns', 'opts': '--ghost-limit 1G'} From 2139c955ed1fe4d1f4d2d6d746504bb425d573bc Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 6 Apr 2018 10:21:12 +0300 Subject: [PATCH 1443/4375] zdtm: handle --tcp-established in the rpc mode Signed-off-by: Andrei Vagin --- test/zdtm.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index ce8b3b9c5..850db9d36 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -758,6 +758,9 @@ class criu_rpc: if arg == '--track-mem': criu.opts.track_mem = True continue + if arg == '--tcp-established': + criu.opts.tcp_established = True + continue raise test_fail_exc('RPC for %s required' % arg) From aeeec2165a153b0c4885f5dd3ad26792822a8a9c Mon Sep 17 00:00:00 2001 From: Vitaly Ostrosablin Date: Fri, 6 Apr 2018 17:19:20 +0300 Subject: [PATCH 1444/4375] zdtm: Fix unlink_multiple_largefiles compilation on ppc64 Compiler wants arguments, explicitly casted to (long long) for %llx specifier. Signed-off-by: Vitaly Ostrosablin Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/unlink_multiple_largefiles.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/zdtm/static/unlink_multiple_largefiles.c b/test/zdtm/static/unlink_multiple_largefiles.c index c6400b4ff..a87093439 100644 --- a/test/zdtm/static/unlink_multiple_largefiles.c +++ b/test/zdtm/static/unlink_multiple_largefiles.c @@ -83,21 +83,21 @@ void check_extent_map(struct fiemap *map) for (i = 0; i < map->fm_mapped_extents; i++) { test_msg("Extent %d, start %llx, length %llx\n", i, - map->fm_extents[i].fe_logical, - map->fm_extents[i].fe_length); + (long long) map->fm_extents[i].fe_logical, + (long long) map->fm_extents[i].fe_length); if (i == 0) holesize = map->fm_extents[i].fe_logical; datasize += map->fm_extents[i].fe_length; } if (holesize != FSIZE) { - pr_err("Unexpected hole size %llx != %llx\n", holesize, - (unsigned long long) FSIZE); + pr_err("Unexpected hole size %llx != %llx\n", + (long long) holesize, (unsigned long long) FSIZE); exit(1); } if (datasize != BUFSIZE) { - pr_err("Unexpected data size %llx != %llx\n", datasize, - (unsigned long long) BUFSIZE); + pr_err("Unexpected data size %llx != %llx\n", + (long long) datasize, (unsigned long long) BUFSIZE); exit(1); } } From 53d29d7e2257be7a18364afcd4d80cb203bc6562 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 15 May 2018 22:52:57 +0300 Subject: [PATCH 1445/4375] kdat: fill kdat by zero-s before initializing it kerndat_try_load_cache() fills kdat from /run/criu.kdat, so it will contain some trash, if criu.kdat isn't compatible with the current version of criu. Signed-off-by: Andrei Vagin Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/kerndat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/kerndat.c b/criu/kerndat.c index ba8d93808..8cb569016 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -973,6 +973,9 @@ int kerndat_init(void) if (ret <= 0) return ret; + /* kerndat_try_load_cache can leave some trash in kdat */ + memset(&kdat, 0, sizeof(kdat)); + preload_socket_modules(); preload_netfilter_modules(); From 4b37d0b0063ae2a84fceb96ddbca1d90f0cb8fdb Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Tue, 15 May 2018 23:31:12 +0300 Subject: [PATCH 1446/4375] restore: check a return code of RUN_CLONE_RESTORE_FN Otherwise we can skip an error and then criu will hang on switching to the next stage. Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 86b0c7a3c..d9a7780de 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1554,6 +1554,10 @@ long __export_restore_task(struct task_restore_args *args) */ RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, thread_args, args->clone_restore_fn); + if (ret != thread_args[i].pid - 1) { + pr_err("Unable to create a thread: %ld", ret); + goto core_restore_end; + } } ret = sys_flock(fd, LOCK_UN); From 8d709e67d50c9eaf33cb104cf0fcdc1ea4a91051 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Tue, 15 May 2018 23:29:59 +0300 Subject: [PATCH 1447/4375] zdtm: don't print one line twice (00.566486)pie: 1: seccomp: mode 0 on tid 1 (00.566601)pie: 1: Error (criu/pie/restorer.c:460): seccomp: Unexpected tid -> (00.566601)pie: 1: 1 != 1 (00.566601)pie: 1: 1 != 1 (00.566639)pie: 1: Error (criu/pie/restorer.c:1817): Restorer fail 1 Signed-off-by: Andrei Vagin --- test/zdtm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/zdtm.py b/test/zdtm.py index 850db9d36..f594cd6f5 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1728,6 +1728,7 @@ def grep_errors(fname): else: if print_next: print_next = print_error(l) + before = [] if not first: print_sep("ERROR OVER", "-", 60) From 4daaef027a21b0e193fca4d8dbdc4bba284ff731 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Tue, 15 May 2018 23:29:18 +0300 Subject: [PATCH 1448/4375] compel/log: increase a max line length There are a lot of lines, which are longer than 79: (04.331172)pie: 1: Error (criu/pie/restorer.c:460): seccomp: Unexpected tid -> (04.331172)pie: 1: 1 != 1 Signed-off-by: Andrei Vagin Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/plugins/include/uapi/std/log.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/plugins/include/uapi/std/log.h b/compel/plugins/include/uapi/std/log.h index 3a3d88992..fbd1803bb 100644 --- a/compel/plugins/include/uapi/std/log.h +++ b/compel/plugins/include/uapi/std/log.h @@ -1,7 +1,7 @@ #ifndef COMPEL_PLUGIN_STD_LOG_H__ #define COMPEL_PLUGIN_STD_LOG_H__ -#define STD_LOG_SIMPLE_CHUNK 79 +#define STD_LOG_SIMPLE_CHUNK 256 extern void std_log_set_fd(int fd); extern void std_log_set_loglevel(unsigned int level); From 24c17e5106a343ac796c259c997601b85919961f Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 May 2018 23:42:22 +0300 Subject: [PATCH 1449/4375] lazy-pages: use xfree() instead of free() Although they are the same, xfree() looks more consistent with other code Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index f803f2aa2..e60c782ee 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -150,7 +150,7 @@ static void lpi_fini(struct lazy_pages_info *lpi) { if (!lpi) return; - free(lpi->buf); + xfree(lpi->buf); free_iovs(lpi); if (lpi->lpfd.fd > 0) close(lpi->lpfd.fd); @@ -158,7 +158,7 @@ static void lpi_fini(struct lazy_pages_info *lpi) lpi->parent->num_children--; if (!lpi->parent && !lpi->num_children && lpi->pr.close) lpi->pr.close(&lpi->pr); - free(lpi); + xfree(lpi); } static int prepare_sock_addr(struct sockaddr_un *saddr) From 6cd7b66e645433b1b67578515a0933ea926ce87d Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 May 2018 23:42:23 +0300 Subject: [PATCH 1450/4375] lazy-pages: handle_exit: set uffd to negative value instead of 0 The only use for the userfault file descriptor after the process exited is for debug logs. Using negative value instead of 0 makes logs more readable. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index e60c782ee..3fbc5c404 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -789,7 +789,7 @@ static int handle_exit(struct lazy_pages_info *lpi) return -1; free_iovs(lpi); close(lpi->lpfd.fd); - lpi->lpfd.fd = 0; + lpi->lpfd.fd = -lpi->lpfd.fd; lpi->exited = true; /* keep it for tracking in-flight requests and for the summary */ From 1d85ec97eb69149810294090ba30c8d6cac31b28 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 May 2018 23:42:24 +0300 Subject: [PATCH 1451/4375] lazy-pages: reset poll_timeout to 0 as soon as restore is finished It is possible that notification about restore finish arrives at the same time with a fork event. In such case we return to epoll_run_rfds without resetting the poll_timeout and then we'll keep polling for events indefinitely. To avoid this, we reset the poll_timeout to 0 as soon as we know that restore is finished. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index 3fbc5c404..468c312a4 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1231,6 +1231,8 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) ret = complete_forks(epollfd, &events, &nr_fds); if (ret < 0) goto out; + if (restore_finished) + poll_timeout = 0; if (!restore_finished || !ret) continue; } @@ -1238,7 +1240,6 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) /* make sure we return success if there is nothing to xfer */ ret = 0; - poll_timeout = 0; list_for_each_entry_safe(lpi, n, &lpis, l) { if (!list_empty(&lpi->iovs) && list_empty(&lpi->reqs)) { ret = xfer_pages(lpi); From 780f0e6aa79e3591964d74e763b06ff5396a7dc7 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 15 May 2018 23:42:25 +0300 Subject: [PATCH 1452/4375] lazy-pages: replace crappy num_children with simple reference counting The purpose of the num_children field in 'struct lazy_pages_info' was to prevent closing the page-read while there are still active processes that share it. It did work for the case when handling of the child processes finished before the parent process. However, if the parent lpi is closed first, we've got a dangling pointer at lpi->parent. The obvious solution is to use simple reference counting. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 468c312a4..114118098 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -85,7 +85,7 @@ struct lazy_pages_info { struct list_head reqs; struct lazy_pages_info *parent; - unsigned num_children; + unsigned ref_cnt; struct page_read pr; @@ -127,6 +127,7 @@ static struct lazy_pages_info *lpi_init(void) INIT_LIST_HEAD(&lpi->l); lpi->lpfd.read_event = handle_uffd_event; lpi->xfer_len = DEFAULT_XFER_LEN; + lpi->ref_cnt = 1; return lpi; } @@ -146,6 +147,20 @@ static void free_iovs(struct lazy_pages_info *lpi) } } +static void lpi_fini(struct lazy_pages_info *lpi); + +static inline void lpi_put(struct lazy_pages_info *lpi) +{ + lpi->ref_cnt--; + if (!lpi->ref_cnt) + lpi_fini(lpi); +} + +static inline void lpi_get(struct lazy_pages_info *lpi) +{ + lpi->ref_cnt++; +} + static void lpi_fini(struct lazy_pages_info *lpi) { if (!lpi) @@ -155,12 +170,13 @@ static void lpi_fini(struct lazy_pages_info *lpi) if (lpi->lpfd.fd > 0) close(lpi->lpfd.fd); if (lpi->parent) - lpi->parent->num_children--; - if (!lpi->parent && !lpi->num_children && lpi->pr.close) + lpi_put(lpi->parent); + if (!lpi->parent && lpi->pr.close) lpi->pr.close(&lpi->pr); xfree(lpi); } + static int prepare_sock_addr(struct sockaddr_un *saddr) { int len; @@ -1077,7 +1093,7 @@ static int handle_fork(struct lazy_pages_info *parent_lpi, struct uffd_msg *msg) dup_page_read(&lpi->parent->pr, &lpi->pr); - lpi->parent->num_children++; + lpi_get(lpi->parent); return 1; @@ -1251,7 +1267,7 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds) if (list_empty(&lpi->reqs)) { lazy_pages_summary(lpi); list_del(&lpi->l); - lpi_fini(lpi); + lpi_put(lpi); } } From 7ed045c495581501c996ffe1d60243e40eeaf4bf Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 15 May 2018 23:32:06 +0300 Subject: [PATCH 1453/4375] pie/log: print space after timestamp (00.566486)pie: 1: seccomp: mode 0 on tid 1 Signed-off-by: Andrei Vagin --- compel/plugins/std/log.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compel/plugins/std/log.c b/compel/plugins/std/log.c index 81611d1f1..403ea46f7 100644 --- a/compel/plugins/std/log.c +++ b/compel/plugins/std/log.c @@ -69,8 +69,9 @@ static void sbuf_log_init(struct simple_buf *b) n = std_vprint_num(pbuf, sizeof(pbuf), (unsigned)now.tv_usec, &s); pad_num(&s, &n, 6); memcpy(b->bp, s, n); - b->bp[n] = ')'; - b->bp += n + 1; + b->bp[n++] = ')'; + b->bp[n++] = ' '; + b->bp += n; } n = std_vprint_num(pbuf, sizeof(pbuf), sys_gettid(), &s); From 237260f4206ad4d701f2854645a97ed6928087b8 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 16 May 2018 01:58:15 +0300 Subject: [PATCH 1454/4375] tun: don't leak a file descriptor CID 84654 (#1 of 1): Resource leak (RESOURCE_LEAK) 6. leaked_handle: Handle variable fd going out of scope leaks the handle. Signed-off-by: Andrei Vagin --- criu/tun.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/tun.c b/criu/tun.c index 04bb87df4..8aa61e89a 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -371,7 +371,7 @@ static int tunfile_open(struct file_desc *d, int *new_fd) ns_id = ti->tfe->ns_id; if (set_netns(ns_id)) - return -1; + goto err; if (!ti->tfe->netdev) /* just-opened tun file */ From f381a43524a7f2e18e3002fa2c17ec61ab17f15c Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 16 May 2018 01:55:56 +0300 Subject: [PATCH 1455/4375] action-scripts: check a return code of get_service_fd >>> CID 190177: Integer handling issues (NEGATIVE_RETURNS) >>> rpc_sk is passed to a parameter that cannot be negative. Signed-off-by: Andrei Vagin --- criu/action-scripts.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/criu/action-scripts.c b/criu/action-scripts.c index 3cbe89ee4..7b78a1360 100644 --- a/criu/action-scripts.c +++ b/criu/action-scripts.c @@ -108,6 +108,8 @@ int rpc_send_fd(enum script_actions act, int fd) return -1; rpc_sk = get_service_fd(RPC_SK_OFF); + if (rpc_sk < 0) + return -1; pr_debug("\tRPC\n"); return send_criu_rpc_script(act, (char *)action, rpc_sk, fd); @@ -128,6 +130,10 @@ int run_scripts(enum script_actions act) pr_debug("\tRPC\n"); rpc_sk = get_service_fd(RPC_SK_OFF); + if (rpc_sk < 0) { + ret = -1; + goto out; + } ret = send_criu_rpc_script(act, (char *)action, rpc_sk, -1); goto out; } From 26359e759eef0dc8471bc150b3940bda51eb0342 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 16 May 2018 01:55:57 +0300 Subject: [PATCH 1456/4375] dump: remove dead code CID 190175 (#1 of 1): Logically dead code (DEADCODE) dead_error_line: Execution cannot reach this statement: goto err;. Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 7ceff4c19..93f1ecc45 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1483,9 +1483,6 @@ static int cr_pre_dump_finish(int ret) timing_stop(TIME_FROZEN); - if (ret < 0) - goto err; - pr_info("Pre-dumping tasks' memory\n"); for_each_pstree_item(item) { struct parasite_ctl *ctl = dmpi(item)->parasite_ctl; From 7dc930c9516a06536a480b20f8a1bdd9aebea297 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 16 May 2018 01:55:58 +0300 Subject: [PATCH 1457/4375] sk-unix: don't pass a negative value to close() CID 190174 (#1 of 1): Argument cannot be negative (NEGATIVE_RETURNS) 6. negative_returns: fd is passed to a parameter that cannot be negative. Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index ea8d22d90..891d464ab 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -217,7 +217,7 @@ int kerndat_socket_unix_file(void) return 0; } close(sk); - close(fd); + close_safe(&fd); kdat.sk_unix_file = true; From bf455467cf0b53d2c57148b45c4d1f57faf9537d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 30 Apr 2018 19:41:56 +0100 Subject: [PATCH 1458/4375] Revert "test/make: Include .d files" This reverts commit dcafa78b96084216e32b757be62b7fa8aebbdd87. I've found that we already include deps in Makefile.inc, was to fast on the first attempt and overlooked this. (the include just doesn't work like it should yet..) The origin patch may be just dropped before preparing master's merge. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/lib/Makefile | 1 - test/zdtm/static/Makefile | 2 -- test/zdtm/transition/Makefile | 1 - 3 files changed, 4 deletions(-) diff --git a/test/zdtm/lib/Makefile b/test/zdtm/lib/Makefile index d0a667862..d2d9f1cc3 100644 --- a/test/zdtm/lib/Makefile +++ b/test/zdtm/lib/Makefile @@ -16,7 +16,6 @@ LDLIBS := $(LIB) TARGETS := $(LIB) $(BIN) include ../Makefile.inc -include $(DEP) all: $(TARGETS) .PHONY: all diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 6dfe95905..4f2e97c26 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -365,8 +365,6 @@ OUT = $(TST:%=%.out) STATE = $(TST_STATE:%=%.state) STATE_OUT = $(TST_STATE:%=%.out) -include $(DEP) - all: $(TST) criu-rtc.so install: all .PHONY: all install diff --git a/test/zdtm/transition/Makefile b/test/zdtm/transition/Makefile index c64e4289d..f482a8a09 100644 --- a/test/zdtm/transition/Makefile +++ b/test/zdtm/transition/Makefile @@ -38,7 +38,6 @@ PID = $(TST:%=%.pid) OUT = $(TST:%=%.out) include ../Makefile.inc -include $(DEP) all: $(TST) install: all From 18d4be7cca335931d9c4539444febbbd63a8581a Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 30 Apr 2018 19:41:57 +0100 Subject: [PATCH 1459/4375] zdtm/make: Include Makefile.inc after defining $(DEP) Otherwise, tests dependencies are not considered for build. Add an error in Makefile.inc so this won't happen again. Cc: Cyrill Gorcunov Reported-by: Andrei Vagin Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/Makefile.inc | 3 +++ test/zdtm/static/Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index 12fa86e08..170f31632 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -98,6 +98,9 @@ dep: $(DEP) no-deps-targets := clean cleandep cleanout realclean groups.cleanout +ifeq ($(strip $(DEP)),) +$(error No DEP defined in sub-make) +endif ifeq ($(filter $(no-deps-targets), $(MAKECMDGOALS)),) -include $(wildcard $(DEP)) endif diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 4f2e97c26..fa8a9a237 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -205,8 +205,6 @@ TST_NOFILE := \ unlink_multiple_largefiles \ # jobctl00 \ -include ../Makefile.inc - ifneq ($(SRCARCH),arm) ifneq ($(COMPAT_TEST),y) TST_NOFILE += maps03 @@ -365,6 +363,8 @@ OUT = $(TST:%=%.out) STATE = $(TST_STATE:%=%.state) STATE_OUT = $(TST_STATE:%=%.out) +include ../Makefile.inc + all: $(TST) criu-rtc.so install: all .PHONY: all install From cad611b36091e18de36c916923d9bd76935c73f5 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 30 Apr 2018 19:41:58 +0100 Subject: [PATCH 1460/4375] Documentation/make: Call check before install Let's warn about binary needed for `install` target. Before: [root@localhost criu]# make install GEN crit.1 make[1]: *** [Makefile:49: crit.1] Error 127 make: *** [Makefile.install:32: install-man] Error 2 After: [root@localhost criu]# make install /bin/sh: line 1: xmlto: command not found make[1]: *** [Makefile:32: check] Error 1 make: *** [Makefile.install:32: install-man] Error 2 Fixes: #481 Reported-by: treaki@gmail.com Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Documentation/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index de41b3bb2..fe640b0ee 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -69,7 +69,7 @@ clean: $(call msg-clean, "Documentation") $(Q) rm -f $(XMLS) $(MANS) $(PSS) $(PDFS) $(FOOTER) -install: $(MANS) +install: check $(MANS) $(E) " INSTALL " $(MAN8S) $(Q) mkdir -p $(DESTDIR)$(MAN8DIR) $(Q) install -m 644 $(MAN8S) $(DESTDIR)$(MAN8DIR) From a70b1c797bf237f19c9e05c5078b8a822b60b417 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 18 May 2018 01:41:07 +0300 Subject: [PATCH 1461/4375] restorer: check that close() returns an expected thread pid It is a typo fix which was added on rebase. Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index d9a7780de..012dd25fd 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1554,8 +1554,8 @@ long __export_restore_task(struct task_restore_args *args) */ RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, thread_args, args->clone_restore_fn); - if (ret != thread_args[i].pid - 1) { - pr_err("Unable to create a thread: %ld", ret); + if (ret != thread_args[i].pid) { + pr_err("Unable to create a thread: %ld\n", ret); goto core_restore_end; } } From 202b7745bd0c37a1732ebe2fb009a157d338bf95 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 21 May 2018 15:10:25 +0300 Subject: [PATCH 1462/4375] criu: Version 3.9 Signed-off-by: Pavel Emelyanov --- Makefile.versions | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index facac17b7..996f544d1 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 8 -CRIU_VERSION_SUBLEVEL := 1 +CRIU_VERSION_MINOR := 9 +CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Snow Bunting +CRIU_VERSION_NAME := Sand Martin CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From b78c1e9a5ab96930f02aa69fb9bcd5236972156b Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 10 May 2018 19:14:41 +0100 Subject: [PATCH 1463/4375] criu: Remove PAGE_IMAGE_SIZE It's unused since commit fd3f33f5d23a ("headers: image.h -- Drop unused entries"), so let's remove it completely. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/crtools.c | 1 - criu/include/image.h | 5 ----- 2 files changed, 6 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index 2c3e0c613..238b04a70 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -316,7 +316,6 @@ int main(int argc, char *argv[], char *envp[]) #undef BOOL_OPT - BUILD_BUG_ON(PAGE_SIZE != PAGE_IMAGE_SIZE); BUILD_BUG_ON(CTL_32 != SYSCTL_TYPE__CTL_32); BUILD_BUG_ON(__CTL_STR != SYSCTL_TYPE__CTL_STR); /* We use it for fd overlap handling in clone_service_fd() */ diff --git a/criu/include/image.h b/criu/include/image.h index d60cbadd2..bff3e7afb 100644 --- a/criu/include/image.h +++ b/criu/include/image.h @@ -12,11 +12,6 @@ #include "log.h" #include "common/bug.h" -#ifdef _ARCH_PPC64 -#define PAGE_IMAGE_SIZE 65536 -#else -#define PAGE_IMAGE_SIZE 4096 -#endif /* _ARCH_PPC64 */ #define PAGE_RSS 1 #define PAGE_ANON 2 From 1639e2b213837f299c06a94b119ba917c3b9bef0 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 10 May 2018 19:14:42 +0100 Subject: [PATCH 1464/4375] parasite: Rename misnamed nr_pages It's actually number of bytes spliced, not pages. And I bet (unsigned long) suits the purpose more than (int). Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/parasite.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index 7a48f324e..b9dae3f94 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -67,7 +67,8 @@ static int dump_pages(struct parasite_dump_pages_args *args) { int p, ret, tsock; struct iovec *iovs; - int off, nr_segs, nr_pages; + int off, nr_segs; + unsigned long spliced_bytes = 0; tsock = parasite_get_rpc_sock(); p = recv_fd(tsock); @@ -75,7 +76,6 @@ static int dump_pages(struct parasite_dump_pages_args *args) return -1; iovs = pargs_iovs(args); - nr_pages = 0; off = 0; nr_segs = args->nr_segs; if (nr_segs > UIO_MAXIOV) @@ -89,16 +89,16 @@ static int dump_pages(struct parasite_dump_pages_args *args) ret, nr_segs, args->off + off); return -1; } - nr_pages += ret; + spliced_bytes += ret; off += nr_segs; if (off == args->nr_segs) break; if (off + nr_segs > args->nr_segs) nr_segs = args->nr_segs - off; } - if (nr_pages != args->nr_pages * PAGE_SIZE) { + if (spliced_bytes != args->nr_pages * PAGE_SIZE) { sys_close(p); - pr_err("Can't splice all pages to pipe (%d/%d)\n", nr_pages, args->nr_pages); + pr_err("Can't splice all pages to pipe (%lu/%d)\n", spliced_bytes, args->nr_pages); return -1; } From bc1fbb0f52e14185342f5201356c6737111a34d2 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 10 May 2018 19:14:43 +0100 Subject: [PATCH 1465/4375] aio: Allow expressions in NR_IOEVENTS_IN_PAGES macro The macro is used only in aio_estimate_nr_reqs(): unsigned int k_max_reqs = NR_IOEVENTS_IN_NPAGES(size/PAGE_SIZE); Which compiler may evaluate as (((PAGE_SIZE*size)/PAGE_SIZE) - ...) It works as long as PAGE_SIZE is long. The patches set converts PAGE_SIZE to use sysconf() returning (unsigned), non-long type and making the aio macro overflowing. I do not see any value making PAGE_SIZE (unsigned long) typed. Cc: Kirill Tkhai Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/aio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/aio.c b/criu/aio.c index 27c251df5..45651f2d3 100644 --- a/criu/aio.c +++ b/criu/aio.c @@ -13,7 +13,7 @@ #include "images/mm.pb-c.h" #include -#define NR_IOEVENTS_IN_NPAGES(npages) ((PAGE_SIZE * npages - sizeof(struct aio_ring)) / sizeof(struct io_event)) +#define NR_IOEVENTS_IN_NPAGES(npages) ((PAGE_SIZE * (npages) - sizeof(struct aio_ring)) / sizeof(struct io_event)) int dump_aio_ring(MmEntry *mme, struct vma_area *vma) { From ffa1a03c8f111f3228c5bad4fbbe2e9508822401 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 10 May 2018 19:14:44 +0100 Subject: [PATCH 1466/4375] compel/criu: Add ARCH_HAS_LONG_PAGES to PIE binaries For architectures like aarch64/ppc64 it's needed to propagate the size of page inside PIEs. For the parasite page size will be defined during seizing, and for restorer during early initialization. Afterward we can use PAGE_SIZE in PIEs like we did before. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/include/rpc-pie-priv.h | 3 +++ compel/plugins/std/infect.c | 17 +++++++++++++++++ compel/src/lib/infect.c | 3 +++ criu/cr-restore.c | 3 +++ criu/include/restorer.h | 3 +++ criu/pie/restorer.c | 16 ++++++++++++++++ include/common/arch/aarch64/asm/page.h | 9 +++++++++ include/common/arch/ppc64/asm/page.h | 9 +++++++++ 8 files changed, 63 insertions(+) diff --git a/compel/include/rpc-pie-priv.h b/compel/include/rpc-pie-priv.h index f25ca89eb..15f5b14ca 100644 --- a/compel/include/rpc-pie-priv.h +++ b/compel/include/rpc-pie-priv.h @@ -38,6 +38,9 @@ struct parasite_init_args { uint64_t sigreturn_addr; uint64_t sigframe; /* pointer to sigframe */ futex_t daemon_connected; +#ifdef ARCH_HAS_LONG_PAGES + uint32_t page_size; +#endif }; struct parasite_unmap_args { diff --git a/compel/plugins/std/infect.c b/compel/plugins/std/infect.c index 2d3aa3df8..d5e1b4354 100644 --- a/compel/plugins/std/infect.c +++ b/compel/plugins/std/infect.c @@ -3,6 +3,7 @@ #include "common/scm.h" #include "common/compiler.h" #include "common/lock.h" +#include "common/page.h" #define pr_err(fmt, ...) print_on_level(1, fmt, ##__VA_ARGS__) #define pr_info(fmt, ...) print_on_level(3, fmt, ##__VA_ARGS__) @@ -19,6 +20,19 @@ static int tsock = -1; static struct rt_sigframe *sigframe; +#ifdef ARCH_HAS_LONG_PAGES +/* + * XXX: Make it compel's std plugin global variable. Drop parasite_size(). + * Hint: compel on aarch64 shall learn relocs for that. + */ +static unsigned __page_size; + +unsigned __attribute((weak)) page_size(void) +{ + return __page_size; +} +#endif + int parasite_get_rpc_sock(void) { return tsock; @@ -142,6 +156,9 @@ static noinline __used int parasite_init_daemon(void *data) args->sigreturn_addr = (uint64_t)(uintptr_t)fini_sigreturn; sigframe = (void*)(uintptr_t)args->sigframe; +#ifdef ARCH_HAS_LONG_PAGES + __page_size = args->page_size; +#endif ret = tsock = sys_socket(PF_UNIX, SOCK_SEQPACKET, 0); if (tsock < 0) { diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index ecc6599b1..d51b8aa88 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -613,6 +613,9 @@ static int parasite_init_daemon(struct parasite_ctl *ctl) args->sigframe = (uintptr_t)ctl->rsigframe; args->log_level = compel_log_get_loglevel(); +#ifdef ARCH_HAS_LONG_PAGES + args->page_size = PAGE_SIZE; +#endif futex_set(&args->daemon_connected, 0); diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 0bbf4beec..24e307cf3 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3321,6 +3321,9 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns task_args->premmapped_len = rsti(current)->premmapped_len; task_args->task_size = kdat.task_size; +#ifdef ARCH_HAS_LONG_PAGES + task_args->page_size = PAGE_SIZE; +#endif RST_MEM_FIXUP_PPTR(task_args->vmas); RST_MEM_FIXUP_PPTR(task_args->rings); diff --git a/criu/include/restorer.h b/criu/include/restorer.h index be1b5d7f2..036d736ef 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -200,6 +200,9 @@ struct task_restore_args { void **breakpoint; enum faults fault_strategy; +#ifdef ARCH_HAS_LONG_PAGES + unsigned page_size; +#endif } __aligned(64); /* diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 012dd25fd..1b6e824ae 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -36,6 +36,7 @@ #include "uffd.h" #include "common/lock.h" +#include "common/page.h" #include "restorer.h" #include "aio.h" #include "seccomp.h" @@ -70,6 +71,18 @@ bool fault_injected(enum faults f) return __fault_injected(f, fi_strategy); } +#ifdef ARCH_HAS_LONG_PAGES +/* + * XXX: Make it compel's std plugin global variable. Drop parasite_size(). + * Hint: compel on aarch64 shall learn relocs for that. + */ +static unsigned __page_size; +unsigned page_size(void) +{ + return __page_size; +} +#endif + /* * These are stubs for std compel plugin. */ @@ -1198,6 +1211,9 @@ long __export_restore_task(struct task_restore_args *args) zombies = args->zombies; n_zombies = args->zombies_n; *args->breakpoint = rst_sigreturn; +#ifdef ARCH_HAS_LONG_PAGES + __page_size = args->page_size; +#endif ksigfillset(&act.rt_sa_mask); act.rt_sa_handler = sigchld_handler; diff --git a/include/common/arch/aarch64/asm/page.h b/include/common/arch/aarch64/asm/page.h index de1fe5428..4126c8474 100644 --- a/include/common/arch/aarch64/asm/page.h +++ b/include/common/arch/aarch64/asm/page.h @@ -1,6 +1,9 @@ #ifndef __CR_ASM_PAGE_H__ #define __CR_ASM_PAGE_H__ +#define ARCH_HAS_LONG_PAGES + +#ifndef CR_NOGLIBC #include #ifndef PAGE_SHIFT @@ -18,4 +21,10 @@ #define PAGE_PFN(addr) ((addr) / PAGE_SIZE) #define page_size() sysconf(_SC_PAGESIZE) +#else /* CR_NOGLIBC */ + +extern unsigned page_size(void); +#define PAGE_SIZE page_size() + +#endif /* CR_NOGLIBC */ #endif /* __CR_ASM_PAGE_H__ */ diff --git a/include/common/arch/ppc64/asm/page.h b/include/common/arch/ppc64/asm/page.h index 9d10455f1..a95af55ef 100644 --- a/include/common/arch/ppc64/asm/page.h +++ b/include/common/arch/ppc64/asm/page.h @@ -1,6 +1,9 @@ #ifndef __CR_ASM_PAGE_H__ #define __CR_ASM_PAGE_H__ +#define ARCH_HAS_LONG_PAGES + +#ifndef CR_NOGLIBC #include /* @@ -22,4 +25,10 @@ #define PAGE_PFN(addr) ((addr) / PAGE_SIZE) #define page_size() sysconf(_SC_PAGESIZE) +#else /* CR_NOGLIBC */ + +extern unsigned page_size(void); +#define PAGE_SIZE page_size() + +#endif /* CR_NOGLIBC */ #endif /* __CR_ASM_PAGE_H__ */ From 657b13eaeccb82772aea7ac34f37eab1856b6df3 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 10 May 2018 19:14:45 +0100 Subject: [PATCH 1467/4375] criu/dump: Fix size of personality buffer Personality value is printed in kernel like this: static int proc_pid_personality(/* .. */) { int err = lock_trace(task); if (!err) { seq_printf(m, "%08x\n", task->personality); unlock_trace(task); } return err; } So, we don't need a whole page to read the value. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 93f1ecc45..bb7a6c833 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -97,7 +97,8 @@ int __attribute__((weak)) arch_set_thread_regs(struct pstree_item *item, return 0; } -static char loc_buf[PAGE_SIZE]; +#define PERSONALITY_LENGTH 9 +static char loc_buf[PERSONALITY_LENGTH]; void free_mappings(struct vm_area_list *vma_area_list) { From a58e95aac8bb3b2d009ed51ad53f6396bf96aa04 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 10 May 2018 19:14:46 +0100 Subject: [PATCH 1468/4375] criu/log: Define log buffer length without PAGE_SIZE The same value, but as PAGE_SIZE can be different for the same platform - it's no more static value. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/log.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/log.c b/criu/log.c index 6a13266eb..43dcd106f 100644 --- a/criu/log.c +++ b/criu/log.c @@ -30,10 +30,11 @@ #define DEFAULT_LOGFD STDERR_FILENO /* Enable timestamps if verbosity is increased from default */ #define LOG_TIMESTAMP (DEFAULT_LOGLEVEL + 1) +#define LOG_BUF_LEN (8*1024) static unsigned int current_loglevel = DEFAULT_LOGLEVEL; -static char buffer[PAGE_SIZE * 2]; +static char buffer[LOG_BUF_LEN]; static char buf_off = 0; static struct timeval start; From bbe7721075ab28a03ff48a2c3b5df495816fc4eb Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 10 May 2018 19:14:47 +0100 Subject: [PATCH 1469/4375] criu/proc: Define BUF_SIZE without PAGE_SIZE dependency PAGE_SIZE will be a variable value on platforms where it can be different due to large pages. And looks like (c) there is no reason for BUF_SIZE == PAGE_SIZE, so let's keep it as it was, rather than complicating it with dynamic allocation for the buffer. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/proc_parse.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/proc_parse.c b/criu/proc_parse.c index f2388e631..79af2e36f 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -61,16 +61,16 @@ #define SIGEV_THREAD_ID 4 /* deliver to thread */ #endif +#define BUF_SIZE 4096 /* Good enough value - can be changed */ + struct buffer { - char buf[PAGE_SIZE]; + char buf[BUF_SIZE]; char end; /* '\0' */ }; static struct buffer __buf; static char *buf = __buf.buf; -#define BUF_SIZE sizeof(__buf.buf) - /* * This is how AIO ring buffers look like in proc */ From 2d965008d367455e792e0938dd13656a85dabf14 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 10 May 2018 19:14:48 +0100 Subject: [PATCH 1470/4375] ppc64/aarch64: Dynamically define PAGE_SIZE On ppc64/aarch64 Linux can be set to use Large pages, so the PAGE_SIZE isn't build-time constant anymore. Define it through _SC_PAGESIZE. There are different sizes for a page on ppc64: : #if defined(CONFIG_PPC_256K_PAGES) : #define PAGE_SHIFT 18 : #elif defined(CONFIG_PPC_64K_PAGES) : #define PAGE_SHIFT 16 : #elif defined(CONFIG_PPC_16K_PAGES) : #define PAGE_SHIFT 14 : #else : #define PAGE_SHIFT 12 : #endif And on aarch64 there are default sizes and possibly someone can set his own PAGE_SHIFT: : config ARM64_PAGE_SHIFT : int : default 16 if ARM64_64K_PAGES : default 14 if ARM64_16K_PAGES : default 12 On the downside - each time we need PAGE_SIZE, we're doing libc function call on aarch64/ppc64. Fixes: #415 Tested-by: Adrian Reber Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/crtools.c | 3 ++ criu/arch/ppc64/crtools.c | 3 ++ include/common/arch/aarch64/asm/page.h | 36 ++++++++++++++++------- include/common/arch/ppc64/asm/page.h | 40 ++++++++++++++++---------- 4 files changed, 56 insertions(+), 26 deletions(-) diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index f98743a23..b2ef1c312 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -21,6 +21,9 @@ #include "restorer.h" #include +unsigned __page_size = 0; +unsigned __page_shift = 0; + #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))(src)->e int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd) diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index 5a5966ad4..077c243b2 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -23,6 +23,9 @@ #include "images/core.pb-c.h" #include "images/creds.pb-c.h" +unsigned __page_size = 0; +unsigned __page_shift = 0; + static UserPpc64FpstateEntry *copy_fp_regs(uint64_t *fpregs) { UserPpc64FpstateEntry *fpe; diff --git a/include/common/arch/aarch64/asm/page.h b/include/common/arch/aarch64/asm/page.h index 4126c8474..bd8fe8f71 100644 --- a/include/common/arch/aarch64/asm/page.h +++ b/include/common/arch/aarch64/asm/page.h @@ -4,22 +4,36 @@ #define ARCH_HAS_LONG_PAGES #ifndef CR_NOGLIBC -#include +#include /* ffsl() */ +#include /* _SC_PAGESIZE */ -#ifndef PAGE_SHIFT -# define PAGE_SHIFT 12 -#endif +extern unsigned __page_size; +extern unsigned __page_shift; -#ifndef PAGE_SIZE -# define PAGE_SIZE (1UL << PAGE_SHIFT) -#endif +static inline unsigned page_size(void) +{ + if (!__page_size) + __page_size = sysconf(_SC_PAGESIZE); + return __page_size; +} -#ifndef PAGE_MASK -# define PAGE_MASK (~(PAGE_SIZE - 1)) -#endif +static inline unsigned page_shift(void) +{ + if (!__page_shift) + __page_shift = (ffsl(page_size()) - 1); + return __page_shift; +} + +/* + * Don't add ifdefs for PAGE_SIZE: if any header defines it as a constant + * on aarch64, then we need refrain using PAGE_SIZE in criu and use + * page_size() across sources (as it may differ on aarch64). + */ +#define PAGE_SIZE page_size() +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_SHIFT page_shift() #define PAGE_PFN(addr) ((addr) / PAGE_SIZE) -#define page_size() sysconf(_SC_PAGESIZE) #else /* CR_NOGLIBC */ diff --git a/include/common/arch/ppc64/asm/page.h b/include/common/arch/ppc64/asm/page.h index a95af55ef..5107cb8e0 100644 --- a/include/common/arch/ppc64/asm/page.h +++ b/include/common/arch/ppc64/asm/page.h @@ -4,26 +4,36 @@ #define ARCH_HAS_LONG_PAGES #ifndef CR_NOGLIBC -#include +#include /* ffsl() */ +#include /* _SC_PAGESIZE */ + +extern unsigned __page_size; +extern unsigned __page_shift; + +static inline unsigned page_size(void) +{ + if (!__page_size) + __page_size = sysconf(_SC_PAGESIZE); + return __page_size; +} + +static inline unsigned page_shift(void) +{ + if (!__page_shift) + __page_shift = (ffsl(page_size()) - 1); + return __page_shift; +} /* - * Default config for Pseries is to use 64K pages. - * See kernel file arch/powerpc/configs/pseries_*defconfig + * Don't add ifdefs for PAGE_SIZE: if any header defines it as a constant + * on ppc64, then we need refrain using PAGE_SIZE in criu and use + * page_size() across sources (as it may differ on ppc64). */ -#ifndef PAGE_SHIFT -# define PAGE_SHIFT 16 -#endif - -#ifndef PAGE_SIZE -# define PAGE_SIZE (1UL << PAGE_SHIFT) -#endif - -#ifndef PAGE_MASK -# define PAGE_MASK (~(PAGE_SIZE - 1)) -#endif +#define PAGE_SIZE page_size() +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_SHIFT page_shift() #define PAGE_PFN(addr) ((addr) / PAGE_SIZE) -#define page_size() sysconf(_SC_PAGESIZE) #else /* CR_NOGLIBC */ From 1099cf0639fac0c9f5ed77daa3157dfe1b2bb601 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 10 May 2018 02:54:35 +0300 Subject: [PATCH 1471/4375] travis: build criu and run tests on centos It is one of our target platforms. Cc: Adrian Reber Signed-off-by: Andrei Vagin Acked-by: Adrian Reber Signed-off-by: Andrei Vagin --- .travis.yml | 1 + scripts/build/Dockerfile.centos | 35 +++++++++++++++++++++++++++++++++ scripts/build/Makefile | 2 +- scripts/travis/Makefile | 2 +- 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 scripts/build/Dockerfile.centos diff --git a/.travis.yml b/.travis.yml index 4d239edc2..2d6fc31ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ env: - TR_ARCH=fedora-rawhide - TR_ARCH=fedora-rawhide-aarch64 - TR_ARCH=local GCOV=1 + - TR_ARCH=centos matrix: allow_failures: - env: TR_ARCH=docker-test diff --git a/scripts/build/Dockerfile.centos b/scripts/build/Dockerfile.centos new file mode 100644 index 000000000..e26427d8e --- /dev/null +++ b/scripts/build/Dockerfile.centos @@ -0,0 +1,35 @@ +FROM centos:7 + +ARG CC=gcc +ARG ENV1=FOOBAR + +RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm +RUN yum install -y \ + ccache \ + findutils \ + gcc \ + git \ + iproute \ + iptables \ + libaio-devel \ + libasan \ + libcap-devel \ + libnet-devel \ + libnl3-devel \ + make \ + procps-ng \ + protobuf-c-devel \ + protobuf-devel \ + protobuf-python \ + python \ + python-ipaddr \ + python-yaml \ + tar + +COPY . /criu +WORKDIR /criu + +ENV CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes +RUN mv .ccache /tmp && make mrproper && ccache -sz && \ + date && make -j $(nproc) CC="$CC" && date && ccache -s +RUN make -C test/zdtm -j $(nproc) diff --git a/scripts/build/Makefile b/scripts/build/Makefile index dbf599de3..f333b214a 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -1,5 +1,5 @@ QEMU_ARCHES := armv7hf aarch64 ppc64le s390x fedora-rawhide-aarch64 # require qemu -ARCHES := $(QEMU_ARCHES) x86_64 fedora-asan fedora-rawhide +ARCHES := $(QEMU_ARCHES) x86_64 fedora-asan fedora-rawhide centos TARGETS := $(ARCHES) alpine TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index 4d89610bf..badcb4dd2 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -11,7 +11,7 @@ ifdef CLANG target-suffix = -clang endif -TARGETS := fedora-asan alpine fedora-rawhide +TARGETS := fedora-asan alpine fedora-rawhide centos ZDTM_OPTIONS := alpine: ZDTM_OPTIONS=-x zdtm/static/binfmt_misc -x zdtm/static/netns-nf -x zdtm/static/sched_policy00 -x zdtm/static/seccomp_strict -x zdtm/static/sigaltstack -x zdtm/static/signalfd00 -x zdtm/static/config_inotify_irmap From b912456cad28b637d7371940c93c12336034a1b3 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 10 May 2018 17:57:41 +0300 Subject: [PATCH 1472/4375] arch, ppc64: Add missing atomic_dec_and_test helper Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- include/common/arch/ppc64/asm/atomic.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/common/arch/ppc64/asm/atomic.h b/include/common/arch/ppc64/asm/atomic.h index 354403996..461875c6e 100644 --- a/include/common/arch/ppc64/asm/atomic.h +++ b/include/common/arch/ppc64/asm/atomic.h @@ -125,6 +125,8 @@ static __inline__ int atomic_sub_return(int a, atomic_t *v) return t; } +/* true if the result is 0, or false for all other cases. */ +#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) #define atomic_dec_return(v) (atomic_sub_return(1, v)) #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) From e8d8a364598b929908693b12438ac80b98055dcb Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 10 May 2018 17:57:42 +0300 Subject: [PATCH 1473/4375] unix: Use one word log prefix For grep sake. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 891d464ab..d2185b8bc 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -37,7 +37,7 @@ #include "images/sk-unix.pb-c.h" #undef LOG_PREFIX -#define LOG_PREFIX "sk unix: " +#define LOG_PREFIX "unix: " /* * By-default, when dumping a unix socket, we should dump its peer From b2f3bf1d2d23237a77ad7b1ec283fd4518d7cd91 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 10 May 2018 17:57:44 +0300 Subject: [PATCH 1474/4375] unix: Use uint32_t instead of u32 So the rest of code will match. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index d2185b8bc..ab3d1e635 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -245,7 +245,7 @@ static int get_mnt_id(int lfd, int *mnt_id) return 0; } -static int resolve_rel_name(u32 id, struct unix_sk_desc *sk, const struct fd_parms *p, char **pdir) +static int resolve_rel_name(uint32_t id, struct unix_sk_desc *sk, const struct fd_parms *p, char **pdir) { const char *dirs[] = { "cwd", "root" }; struct pstree_item *task; @@ -315,9 +315,9 @@ err: return -ENOENT; } -static int unix_resolve_name(int lfd, u32 id, struct unix_sk_desc *d, +static int unix_resolve_name(int lfd, uint32_t id, struct unix_sk_desc *d, UnixSkEntry *ue, const struct fd_parms *p); -static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p) +static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) { struct unix_sk_desc *sk, *peer; UnixSkEntry *ue; @@ -545,7 +545,7 @@ const struct fdtype_ops unix_dump_ops = { .dump = dump_one_unix_fd, }; -static int unix_resolve_name(int lfd, u32 id, struct unix_sk_desc *d, +static int unix_resolve_name(int lfd, uint32_t id, struct unix_sk_desc *d, UnixSkEntry *ue, const struct fd_parms *p) { char *name = d->name; @@ -711,7 +711,7 @@ static int unix_collect_one(const struct unix_diag_msg *m, goto err; memcpy(d->icons, nla_data(tb[UNIX_DIAG_ICONS]), len); - d->nr_icons = len / sizeof(u32); + d->nr_icons = len / sizeof(uint32_t); /* * Remember these sockets, we will need them From 41ba3d464f80c085da08d36345e15d011ab838ff Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 10 May 2018 17:57:46 +0300 Subject: [PATCH 1475/4375] unix: Adjust unix_sk_info members For readability sake. And use standart uint8_t types. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index ab3d1e635..918800466 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -880,32 +880,32 @@ err: } struct unix_sk_info { - UnixSkEntry *ue; - struct list_head list; - char *name; - char *name_dir; - unsigned flags; - struct unix_sk_info *peer; - struct pprep_head peer_resolve; /* XXX : union with the above? */ - struct file_desc d; - struct list_head connected; /* List of sockets, connected to me */ - struct list_head node; /* To link in peer's connected list */ - struct list_head scm_fles; + UnixSkEntry *ue; + struct list_head list; + char *name; + char *name_dir; + unsigned flags; + struct unix_sk_info *peer; + struct pprep_head peer_resolve; /* XXX : union with the above? */ + struct file_desc d; + struct list_head connected; /* List of sockets, connected to me */ + struct list_head node; /* To link in peer's connected list */ + struct list_head scm_fles; /* * For DGRAM sockets with queues, we should only restore the queue * once although it may be open by more than one tid. This is the peer * that should do the queueing. */ - struct unix_sk_info *queuer; + struct unix_sk_info *queuer; /* * These bits are set by task-owner of this unix_sk_info. * Another tasks can only read them. */ - u8 bound:1; - u8 listen:1; - u8 is_connected:1; - u8 peer_queue_restored:1; /* Set in 1 after we restore peer's queue */ + uint8_t bound:1; + uint8_t listen:1; + uint8_t is_connected:1; + uint8_t peer_queue_restored:1; /* Set in 1 after we restore peer's queue */ }; struct scm_fle { From 1caa5915f7c2ead8cd60fbd83772d184c2e3fd57 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 10 May 2018 17:57:47 +0300 Subject: [PATCH 1476/4375] unix: Adjust unix_sk_cinfo members For readability sake. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 918800466..ee300b882 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1848,11 +1848,11 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) } struct collect_image_info unix_sk_cinfo = { - .fd_type = CR_FD_UNIXSK, - .pb_type = PB_UNIX_SK, - .priv_size = sizeof(struct unix_sk_info), - .collect = collect_one_unixsk, - .flags = COLLECT_SHARED, + .fd_type = CR_FD_UNIXSK, + .pb_type = PB_UNIX_SK, + .priv_size = sizeof(struct unix_sk_info), + .collect = collect_one_unixsk, + .flags = COLLECT_SHARED, }; static void set_peer(struct unix_sk_info *ui, struct unix_sk_info *peer) From 1e6e548be757e4b5882d3d81be5b2829703eda15 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 10 May 2018 17:57:49 +0300 Subject: [PATCH 1477/4375] unix: Use generic xptr_pull in dump_one_unix_fd To unify style of pointers fetching from memory slab. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index ee300b882..42462c970 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -324,17 +324,18 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) SkOptsEntry *skopts; FilePermsEntry *perms; FownEntry *fown; + void *m; - ue = xmalloc(sizeof(UnixSkEntry) + - sizeof(SkOptsEntry) + - sizeof(FilePermsEntry) + - sizeof(FownEntry)); - if (ue == NULL) - return -1; - - skopts = (void *) ue + sizeof(UnixSkEntry); - perms = (void *) skopts + sizeof(SkOptsEntry); - fown = (void *) perms + sizeof(FilePermsEntry); + m = xmalloc(sizeof(UnixSkEntry) + + sizeof(SkOptsEntry) + + sizeof(FilePermsEntry) + + sizeof(FownEntry)); + if (!m) + return -ENOMEM; + ue = xptr_pull(&m, UnixSkEntry); + skopts = xptr_pull(&m, SkOptsEntry); + perms = xptr_pull(&m, FilePermsEntry); + fown = xptr_pull(&m, FownEntry); unix_sk_entry__init(ue); sk_opts_entry__init(skopts); From 6560320a5b7a1c3b2a6fb72b0b57bd77415aebeb Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 10 May 2018 17:57:50 +0300 Subject: [PATCH 1478/4375] unix: Drop empty line at eof Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 42462c970..b05140fce 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -2038,4 +2038,3 @@ int unix_sk_ids_parse(char *optarg) return 0; } - From 1fa59fa33e8ecef997c766a9f33f41a4eb1d7ba2 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 10 May 2018 17:57:51 +0300 Subject: [PATCH 1479/4375] unix: Don's spam with warning if nothing to unlink Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index b05140fce..81de14301 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1750,7 +1750,7 @@ static void unlink_stale(struct unix_sk_info *ui) return; ret = unlinkat(AT_FDCWD, ui->name, 0) ? -1 : 0; - if (ret < 0) { + if (ret < 0 && errno != ENOENT) { pr_warn("Can't unlink stale socket %#x peer %#x (name %s dir %s)\n", ui->ue->ino, ui->ue->peer, ui->name ? (ui->name[0] ? ui->name : &ui->name[1]) : "-", From 6c064b661f393e26e023e482a8b9abbe2b69dddb Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 10 May 2018 17:57:52 +0300 Subject: [PATCH 1480/4375] unix: Print reverted dir info if only directory provided Otherwise there is an imbalance in logs with number of "Reverted working dir" message | (00.018604) 36: unix: Connected 0x11ceff -> 0x11cf00 (0x11cf00) flags 0 | (00.018644) 36: unix: Reverted working dir | (00.018652) 36: unix: Connected 0x11cefd -> 0x11cefe (0x11cefe) flags 0 | (00.018665) 36: unix: Reverted working dir | (00.018688) 36: unix: Reverted working dir Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 81de14301..c538659fd 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1130,7 +1130,7 @@ static int restore_sk_common(int fd, struct unix_sk_info *ui) return 0; } -static int revert_unix_sk_cwd(int *prev_cwd_fd, int *root_fd, int *ns_fd) +static int revert_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd, int *root_fd, int *ns_fd) { int ret = 0; @@ -1145,7 +1145,7 @@ static int revert_unix_sk_cwd(int *prev_cwd_fd, int *root_fd, int *ns_fd) if (prev_cwd_fd && *prev_cwd_fd >= 0) { if (fchdir(*prev_cwd_fd)) pr_perror("Can't revert working dir"); - else + else if (ui->name_dir) pr_debug("Reverted working dir\n"); close(*prev_cwd_fd); *prev_cwd_fd = -1; @@ -1279,12 +1279,12 @@ static int post_open_standalone(struct file_desc *d, int fd) sizeof(addr.sun_family) + peer->ue->name.len) < 0) { pr_perror("Can't connect %#x socket", ui->ue->ino); - revert_unix_sk_cwd(&cwd_fd, &root_fd, &ns_fd); + revert_unix_sk_cwd(peer, &cwd_fd, &root_fd, &ns_fd); return -1; } ui->is_connected = true; - revert_unix_sk_cwd(&cwd_fd, &root_fd, &ns_fd); + revert_unix_sk_cwd(peer, &cwd_fd, &root_fd, &ns_fd); restore_queue: if (peer->queuer == ui && @@ -1414,7 +1414,7 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) exit_code = 0; done: - revert_unix_sk_cwd(&cwd_fd, &root_fd, &ns_fd); + revert_unix_sk_cwd(ui, &cwd_fd, &root_fd, &ns_fd); return exit_code; } @@ -1756,7 +1756,7 @@ static void unlink_stale(struct unix_sk_info *ui) ui->name ? (ui->name[0] ? ui->name : &ui->name[1]) : "-", ui->name_dir ? ui->name_dir : "-"); } - revert_unix_sk_cwd(&cwd_fd, &root_fd, &ns_fd); + revert_unix_sk_cwd(ui, &cwd_fd, &root_fd, &ns_fd); } static void try_resolve_unix_peer(struct unix_sk_info *ui); From 52973e57cec4074a9baac878eb6f624ef0daa38c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 10 May 2018 17:57:53 +0300 Subject: [PATCH 1481/4375] unix: Unify printings on peer open Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index c538659fd..9bd5506f5 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1445,16 +1445,20 @@ static int post_open_interconnected_master(struct unix_sk_info *ui) return 0; } +static void pr_info_opening(const char *prefix, struct unix_sk_info *ui, struct fdinfo_list_entry *fle) +{ + pr_info("Opening %s (stage %d id %#x ino %#x peer %#x)\n", + prefix, fle->stage, ui->ue->id, ui->ue->ino, ui->ue->peer); +} + static int open_unixsk_pair_master(struct unix_sk_info *ui, int *new_fd) { struct fdinfo_list_entry *fle, *fle_peer; struct unix_sk_info *peer = ui->peer; int sk[2], tmp; - pr_info("Opening pair master (id %#x ino %#x peer %#x)\n", - ui->ue->id, ui->ue->ino, ui->ue->peer); - fle = file_master(&ui->d); + pr_info_opening("master", ui, fle); if (fle->stage == FLE_OPEN) return post_open_interconnected_master(ui); @@ -1505,6 +1509,7 @@ static int open_unixsk_pair_slave(struct unix_sk_info *ui, int *new_fd) struct fdinfo_list_entry *fle_peer; fle_peer = file_master(&ui->peer->d); + pr_info_opening("slave", ui, fle_peer); /* * All the work is made in master. Slave just says it's restored * after it sees the master is restored. @@ -1548,9 +1553,8 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) struct fdinfo_list_entry *fle; int sk; - pr_info("Opening standalone socket (id %#x ino %#x peer %#x)\n", - ui->ue->id, ui->ue->ino, ui->ue->peer); fle = file_master(&ui->d); + pr_info_opening("standalone", ui, fle); if (fle->stage == FLE_OPEN) return post_open_standalone(&ui->d, fle->fe->fd); From e61309a7c67af09470a2c94e56113c4b4039d738 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 10 May 2018 17:57:54 +0300 Subject: [PATCH 1482/4375] unix: Improve init_unix_sk_info This helper must init every member of a structure, not some part of it. Beautify code as well. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 9bd5506f5..b5775159d 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1792,16 +1792,21 @@ static int init_unix_sk_info(struct unix_sk_info *ui, UnixSkEntry *ue) ui->name = NULL; ui->name_dir = (void *)ue->name_dir; - ui->queuer = NULL; - ui->peer = NULL; - ui->bound = 0; - ui->listen = 0; - ui->is_connected = 0; + ui->flags = 0; + ui->peer = NULL; + ui->queuer = NULL; + ui->bound = 0; + ui->listen = 0; + ui->is_connected = 0; ui->peer_queue_restored = 0; + + memzero(&ui->peer_resolve, sizeof(ui->peer_resolve)); + memzero(&ui->d, sizeof(ui->d)); + + INIT_LIST_HEAD(&ui->list); INIT_LIST_HEAD(&ui->connected); INIT_LIST_HEAD(&ui->node); INIT_LIST_HEAD(&ui->scm_fles); - ui->flags = 0; return 0; } From 98cb5c627d2faa87f5ff99274fe2d74a1273e2a0 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 16 May 2018 06:20:22 +0000 Subject: [PATCH 1483/4375] crit: make crit python2/python3 compatible Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- crit/crit | 33 +++++++++++++++++---------------- criu/Makefile.packages | 15 ++++++++++++++- lib/py/__init__.py | 6 +++--- lib/py/criu.py | 2 +- lib/py/images/Makefile | 2 +- lib/py/images/__init__.py | 8 +++++--- lib/py/images/images.py | 8 ++++---- lib/py/images/pb2dict.py | 35 +++++++++++++++++++---------------- scripts/magic-gen.py | 2 +- 9 files changed, 65 insertions(+), 46 deletions(-) diff --git a/crit/crit b/crit/crit index 08e84575d..6adccc9f2 100755 --- a/crit/crit +++ b/crit/crit @@ -1,4 +1,5 @@ #!/usr/bin/env python2 +from __future__ import print_function import argparse import sys import json @@ -8,7 +9,7 @@ import pycriu def inf(opts): if opts['in']: - return open(opts['in'], 'r') + return open(opts['in'], 'rb') else: return sys.stdin @@ -27,9 +28,9 @@ def decode(opts): try: img = pycriu.images.load(inf(opts), opts['pretty'], opts['nopl']) except pycriu.images.MagicException as exc: - print >>sys.stderr, "Unknown magic %#x.\n"\ + print("Unknown magic %#x.\n"\ "Maybe you are feeding me an image with "\ - "raw data(i.e. pages.img)?" % exc.magic + "raw data(i.e. pages.img)?" % exc.magic, file=sys.stderr) sys.exit(1) if opts['pretty']: @@ -47,7 +48,7 @@ def encode(opts): def info(opts): infs = pycriu.images.info(inf(opts)) json.dump(infs, sys.stdout, indent = 4) - print + print() def get_task_id(p, val): return p[val] if val in p else p['ns_' + val][0] @@ -64,8 +65,8 @@ class ps_item: self.kids = [] def show_ps(p, opts, depth = 0): - print "%7d%7d%7d %s%s" % (p.pid, get_task_id(p.p, 'pgid'), get_task_id(p.p, 'sid'), - ' ' * (4 * depth), p.core['tc']['comm']) + print("%7d%7d%7d %s%s" % (p.pid, get_task_id(p.p, 'pgid'), get_task_id(p.p, 'sid'), + ' ' * (4 * depth), p.core['tc']['comm'])) for kid in p.kids: show_ps(kid, opts, depth + 1) @@ -88,7 +89,7 @@ def explore_ps(opts): pp = pss[p.ppid] pp.kids.append(p) - print "%7s%7s%7s %s" % ('PID', 'PGID', 'SID', 'COMM') + print("%7s%7s%7s %s" % ('PID', 'PGID', 'SID', 'COMM')) show_ps(psr, opts) files_img = None @@ -169,13 +170,13 @@ def explore_fds(opts): fdt = idi['entries'][0]['files_id'] fdi = pycriu.images.load(dinf(opts, 'fdinfo-%d.img' % fdt)) - print "%d" % pid + print("%d" % pid) for fd in fdi['entries']: - print "\t%7d: %s" % (fd['fd'], get_file_str(opts, fd)) + print("\t%7d: %s" % (fd['fd'], get_file_str(opts, fd))) fdi = pycriu.images.load(dinf(opts, 'fs-%d.img' % pid))['entries'][0] - print "\t%7s: %s" % ('cwd', get_file_str(opts, {'type': 'REG', 'id': fdi['cwd_id']})) - print "\t%7s: %s" % ('root', get_file_str(opts, {'type': 'REG', 'id': fdi['root_id']})) + print("\t%7s: %s" % ('cwd', get_file_str(opts, {'type': 'REG', 'id': fdi['cwd_id']}))) + print("\t%7s: %s" % ('root', get_file_str(opts, {'type': 'REG', 'id': fdi['root_id']}))) class vma_id: @@ -199,8 +200,8 @@ def explore_mems(opts): pid = get_task_id(p, 'pid') mmi = pycriu.images.load(dinf(opts, 'mm-%d.img' % pid))['entries'][0] - print "%d" % pid - print "\t%-36s %s" % ('exe', get_file_str(opts, {'type': 'REG', 'id': mmi['exe_file_id']})) + print("%d" % pid) + print("\t%-36s %s" % ('exe', get_file_str(opts, {'type': 'REG', 'id': mmi['exe_file_id']}))) for vma in mmi['vmas']: st = vma['status'] @@ -235,7 +236,7 @@ def explore_mems(opts): prot += vma['prot'] & 0x4 and 'x' or '-' astr = '%08lx-%08lx' % (vma['start'], vma['end']) - print "\t%-36s%s%s" % (astr, prot, fn) + print("\t%-36s%s%s" % (astr, prot, fn)) def explore_rss(opts): @@ -245,7 +246,7 @@ def explore_rss(opts): vmas = pycriu.images.load(dinf(opts, 'mm-%d.img' % pid))['entries'][0]['vmas'] pms = pycriu.images.load(dinf(opts, 'pagemap-%d.img' % pid))['entries'] - print "%d" % pid + print("%d" % pid) vmi = 0 pvmi = -1 for pm in pms[1:]: @@ -269,7 +270,7 @@ def explore_rss(opts): vmi -= 1 - print '%-24s%s' % (pstr, vstr) + print('%-24s%s' % (pstr, vstr)) diff --git a/criu/Makefile.packages b/criu/Makefile.packages index 886394fd5..2cea94781 100644 --- a/criu/Makefile.packages +++ b/criu/Makefile.packages @@ -6,6 +6,7 @@ REQ-RPM-PKG-NAMES += protobuf-devel REQ-RPM-PKG-NAMES += protobuf-python REQ-RPM-PKG-NAMES += libnl3-devel REQ-RPM-PKG-NAMES += libcap-devel +REQ-RPM-PKG-NAMES += $(PYTHON)-future REQ-RPM-PKG-TEST-NAMES += libaio-devel @@ -17,7 +18,19 @@ REQ-DEB-PKG-NAMES += python-protobuf REQ-DEB-PKG-NAMES += libnl-3-dev REQ-DEB-PKG-NAMES += libcap-dev -REQ-DEB-PKG-TEST-NAMES += libaio-dev +REQ-DEB-PKG-TEST-NAMES += python-yaml +REQ-DEB-PKG-TEST-NAMES += libaio-dev + +ifeq ($(PYTHON),python3) +REQ-DEB-PKG-NAMES += $(PYTHON)-future +REQ-DEB-PKG-TEST-NAMES += libaio-dev + +REQ-RPM-PKG-TEST-NAMES += $(PYTHON)-PyYAML +else +REQ-DEB-PKG-NAMES += python-future + +REQ-RPM-PKG-TEST-NAMES += $(PYTHON)-pyyaml +endif export LIBS += -lrt -lpthread -lprotobuf-c -ldl -lnl-3 -lsoccr -Lsoccr/ -lnet diff --git a/lib/py/__init__.py b/lib/py/__init__.py index 8e1749961..96b3e9526 100644 --- a/lib/py/__init__.py +++ b/lib/py/__init__.py @@ -1,3 +1,3 @@ -import rpc_pb2 as rpc -import images -from criu import * +from . import rpc_pb2 as rpc +from . import images +from .criu import * diff --git a/lib/py/criu.py b/lib/py/criu.py index e4e46b52b..85c7c07f8 100644 --- a/lib/py/criu.py +++ b/lib/py/criu.py @@ -9,7 +9,7 @@ import signal import sys import struct -import rpc_pb2 as rpc +import pycriu.rpc_pb2 as rpc class _criu_comm: """ diff --git a/lib/py/images/Makefile b/lib/py/images/Makefile index a95f6120b..cb328ec4c 100644 --- a/lib/py/images/Makefile +++ b/lib/py/images/Makefile @@ -17,7 +17,7 @@ magic.py: scripts/magic-gen.py criu/include/magic.h pb.py: images $(Q) echo "# Autogenerated. Do not edit!" > $(obj)/$@ $(Q) for m in $(proto-py-modules); do \ - echo "from $$m import *" >> $(obj)/$@ ;\ + echo "from .$$m import *" >> $(obj)/$@ ;\ done .PHONY: pb.py diff --git a/lib/py/images/__init__.py b/lib/py/images/__init__.py index 379943b97..ea87e4e7b 100644 --- a/lib/py/images/__init__.py +++ b/lib/py/images/__init__.py @@ -1,3 +1,5 @@ -from magic import * -from images import * -from pb import * +import sys, os +sys.path.append(os.path.dirname(os.path.realpath(__file__))) +from .magic import * +from .images import * +from .pb import * diff --git a/lib/py/images/images.py b/lib/py/images/images.py index b706fd3b3..c17b76f0e 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -43,11 +43,11 @@ import struct import os import sys import json -import pb2dict +from . import pb2dict import array -import magic -from pb import * +from . import magic +from .pb import * # # Predefined hardcoded constants @@ -91,7 +91,7 @@ class entry_handler: # Read payload pb = self.payload() buf = f.read(4) - if buf == '': + if buf == b'': break size, = struct.unpack('i', buf) pb.ParseFromString(f.read(size)) diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index fe3dcf175..d99f3e13c 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -1,6 +1,9 @@ from google.protobuf.descriptor import FieldDescriptor as FD import opts_pb2 -import ipaddr +from builtins import str +from past.builtins import long +from ipaddress import IPv4Address +from ipaddress import IPv6Address import socket import collections import os @@ -39,7 +42,7 @@ _basic_cast = { FD.TYPE_BOOL : bool, - FD.TYPE_STRING : unicode + FD.TYPE_STRING : str } def _marked_as_hex(field): @@ -98,11 +101,11 @@ mmap_status_map = [ ]; rfile_flags_map = [ - ('O_WRONLY', 01), - ('O_RDWR', 02), - ('O_APPEND', 02000), - ('O_DIRECT', 040000), - ('O_LARGEFILE', 0100000), + ('O_WRONLY', 0o1), + ('O_RDWR', 0o2), + ('O_APPEND', 0o2000), + ('O_DIRECT', 0o40000), + ('O_LARGEFILE', 0o100000), ]; pmap_flags_map = [ @@ -150,8 +153,8 @@ sk_maps = { 136: 'UDPLITE' }, } -gen_rmaps = { k: {v2:k2 for k2,v2 in v.items()} for k,v in gen_maps.items() } -sk_rmaps = { k: {v2:k2 for k2,v2 in v.items()} for k,v in sk_maps.items() } +gen_rmaps = { k: {v2:k2 for k2,v2 in list(v.items())} for k,v in list(gen_maps.items()) } +sk_rmaps = { k: {v2:k2 for k2,v2 in list(v.items())} for k,v in list(sk_maps.items()) } dict_maps = { 'gen' : ( gen_maps, gen_rmaps ), @@ -159,8 +162,8 @@ dict_maps = { } def map_flags(value, flags_map): - bs = map(lambda x: x[0], filter(lambda x: value & x[1], flags_map)) - value &= ~sum(map(lambda x: x[1], flags_map)) + bs = [x[0] for x in [x for x in flags_map if value & x[1]]] + value &= ~sum([x[1] for x in flags_map]) if value: bs.append("0x%x" % value) return " | ".join(bs) @@ -170,7 +173,7 @@ def unmap_flags(value, flags_map): return 0 bd = dict(flags_map) - return sum(map(lambda x: int(str(bd.get(x, x)), 0), map(lambda x: x.strip(), value.split('|')))) + return sum([int(str(bd.get(x, x)), 0) for x in [x.strip() for x in value.split('|')]]) kern_minorbits = 20 # This is how kernel encodes dev_t in new format @@ -181,7 +184,7 @@ def decode_dev(field, value): return "%d:%d" % (value >> kern_minorbits, value & ((1 << kern_minorbits) - 1)) def encode_dev(field, value): - dev = map(lambda x: int(x), value.split(':')) + dev = [int(x) for x in value.split(':')] if _marked_as_odev(field): return os.makedev(dev[0], dev[1]) else: @@ -215,7 +218,7 @@ def get_bytes_dec(field): return decode_base64 def is_string(value): - return isinstance(value, unicode) or isinstance(value, str) + return isinstance(value, str) def _pb2dict_cast(field, value, pretty = False, is_hex = False): if not is_hex: @@ -267,13 +270,13 @@ def pb2dict(pb, pretty = False, is_hex = False): if pretty and _marked_as_ip(field): if len(value) == 1: v = socket.ntohl(value[0]) - addr = ipaddr.IPv4Address(v) + addr = IPv4Address(v) else: v = 0 + (socket.ntohl(value[0]) << (32 * 3)) + \ (socket.ntohl(value[1]) << (32 * 2)) + \ (socket.ntohl(value[2]) << (32 * 1)) + \ (socket.ntohl(value[3])) - addr = ipaddr.IPv6Address(v) + addr = IPv6Address(v) d_val.append(addr.compressed) else: diff --git a/scripts/magic-gen.py b/scripts/magic-gen.py index 319e99812..14a155a43 100755 --- a/scripts/magic-gen.py +++ b/scripts/magic-gen.py @@ -44,7 +44,7 @@ def main(argv): out.write('#Autogenerated. Do not edit!\n') out.write('by_name = {}\n') out.write('by_val = {}\n') - for k,v in magic.items(): + for k,v in list(magic.items()): # We don't need RAW or V1 magic, because # they can't be used to identify images. if v == '0x0' or v == '1' or k == '0x0' or v == '1': From 1a0ad1ae8748baa2b0db3ef60848bccb1198bb20 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 16 May 2018 06:20:23 +0000 Subject: [PATCH 1484/4375] Makefiles: auto-detect python version - prefer python2 This prepares CRIT for python2/python3 compatibility by auto-detecting the installed python version. python2 is detected first and then the variable PYTHON is set. By setting the variable PYTHON to python2/python3 the user can override the auto-detection. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- lib/Makefile | 3 +-- lib/py/images/Makefile | 4 ++-- scripts/nmk/scripts/tools.mk | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 26b355aa2..94632848e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,6 +1,5 @@ CRIU_SO := libcriu.so UAPI_HEADERS := lib/c/criu.h images/rpc.proto -PYTHON_BIN ?= python2 # # File to keep track of files installed by setup.py @@ -54,7 +53,7 @@ install: lib-c lib-py crit/crit lib/c/criu.pc.in $(Q) sed -e 's,@version@,$(CRIU_VERSION),' -e 's,@libdir@,$(LIBDIR),' -e 's,@includedir@,$(dir $(INCLUDEDIR)/criu/),' lib/c/criu.pc.in > lib/c/criu.pc $(Q) install -m 644 lib/c/criu.pc $(DESTDIR)$(LIBDIR)/pkgconfig $(E) " INSTALL " crit - $(Q) $(PYTHON_BIN) scripts/crit-setup.py install --prefix=$(DESTDIR)$(PREFIX) --record $(CRIT_SETUP_FILES) + $(Q) $(PYTHON) scripts/crit-setup.py install --prefix=$(DESTDIR)$(PREFIX) --record $(CRIT_SETUP_FILES) .PHONY: install uninstall: diff --git a/lib/py/images/Makefile b/lib/py/images/Makefile index cb328ec4c..f7df20f12 100644 --- a/lib/py/images/Makefile +++ b/lib/py/images/Makefile @@ -12,11 +12,11 @@ images: magic.py: scripts/magic-gen.py criu/include/magic.h $(call msg-gen, $@) - $(Q) python $^ $(obj)/$@ + $(Q) $(PYTHON) $^ $(obj)/$@ pb.py: images $(Q) echo "# Autogenerated. Do not edit!" > $(obj)/$@ - $(Q) for m in $(proto-py-modules); do \ + $(Q) for m in $(filter-out opts_pb2, $(proto-py-modules)); do \ echo "from .$$m import *" >> $(obj)/$@ ;\ done .PHONY: pb.py diff --git a/scripts/nmk/scripts/tools.mk b/scripts/nmk/scripts/tools.mk index 56dba8447..485fe9f20 100644 --- a/scripts/nmk/scripts/tools.mk +++ b/scripts/nmk/scripts/tools.mk @@ -18,7 +18,8 @@ MAKE := make MKDIR := mkdir -p AWK := awk PERL := perl -PYTHON := python +FULL_PYTHON := $(shell which python2 2>/dev/null || which python3 2>/dev/null) +PYTHON ?= $(shell basename $(FULL_PYTHON)) FIND := find SH := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ From 4feb07020dedbf845fc00268d8ca02f4645641cd Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 16 May 2018 06:20:24 +0000 Subject: [PATCH 1485/4375] crit: enable python2 or python3 based crit With this last commit of the crit with python3 series it is possible to either use python2 or python3 with CRIU. Now the basic build system functionality (make and make install) are python2/python3 aware. zdtm.py and criu-coredump are still python2, but as they are not part of 'make install' those parts have not yet been ported from python2 to python3. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- .gitignore | 1 + Makefile | 17 +++++++++++++---- crit/Makefile | 13 +++++++++++++ crit/crit-python2 | 6 ++++++ crit/crit-python3 | 6 ++++++ crit/crit => lib/py/cli.py | 1 - 6 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 crit/Makefile create mode 100755 crit/crit-python2 create mode 100755 crit/crit-python3 rename crit/crit => lib/py/cli.py (99%) diff --git a/.gitignore b/.gitignore index 048668905..c231104af 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ images/google/protobuf/*.c images/google/protobuf/*.h .gitid criu/criu +crit/crit criu/arch/*/sys-exec-tbl*.c # x86 syscalls-table is not generated !criu/arch/x86/sys-exec-tbl.c diff --git a/Makefile b/Makefile index 6522d91df..60ad328b4 100644 --- a/Makefile +++ b/Makefile @@ -127,7 +127,7 @@ HOSTCFLAGS += $(WARNINGS) $(DEFINES) -iquote include/ export CFLAGS USERCLFAGS HOSTCFLAGS # Default target -all: criu lib +all: criu lib crit .PHONY: all # @@ -228,14 +228,22 @@ criu: $(criu-deps) $(Q) $(MAKE) $(build)=criu all .PHONY: criu +crit/Makefile: ; +crit/%: criu .FORCE + $(Q) $(MAKE) $(build)=crit $@ +crit: criu + $(Q) $(MAKE) $(build)=crit all +.PHONY: crit + + # -# Libraries next once criu it ready +# Libraries next once crit it ready # (we might generate headers and such # when building criu itself). lib/Makefile: ; -lib/%: criu .FORCE +lib/%: crit .FORCE $(Q) $(MAKE) $(build)=lib $@ -lib: criu +lib: crit $(Q) $(MAKE) $(build)=lib all .PHONY: lib @@ -247,6 +255,7 @@ clean mrproper: $(Q) $(MAKE) $(build)=compel $@ $(Q) $(MAKE) $(build)=compel/plugins $@ $(Q) $(MAKE) $(build)=lib $@ + $(Q) $(MAKE) $(build)=crit $@ .PHONY: clean mrproper clean-top: diff --git a/crit/Makefile b/crit/Makefile new file mode 100644 index 000000000..988b481b6 --- /dev/null +++ b/crit/Makefile @@ -0,0 +1,13 @@ + +all-y += crit + +crit/crit: crit/crit-$(PYTHON) + $(Q) cp $^ $@ +crit: crit/crit +.PHONY: crit + +clean-crit: + $(Q) $(RM) crit/crit +.PHONY: clean-crit +clean: clean-crit +mrproper: clean diff --git a/crit/crit-python2 b/crit/crit-python2 new file mode 100755 index 000000000..b0b7d3c3a --- /dev/null +++ b/crit/crit-python2 @@ -0,0 +1,6 @@ +#!/usr/bin/env python2 + +from pycriu import cli + +if __name__ == '__main__': + cli.main() diff --git a/crit/crit-python3 b/crit/crit-python3 new file mode 100755 index 000000000..80467cba7 --- /dev/null +++ b/crit/crit-python3 @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from pycriu import cli + +if __name__ == '__main__': + cli.main() diff --git a/crit/crit b/lib/py/cli.py similarity index 99% rename from crit/crit rename to lib/py/cli.py index 6adccc9f2..12597dbfb 100755 --- a/crit/crit +++ b/lib/py/cli.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python2 from __future__ import print_function import argparse import sys From 767534f10fcf0485dd58bf37156ace4cc59c35b7 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 16 May 2018 06:20:25 +0000 Subject: [PATCH 1486/4375] Adapt zdtm for python3 compatibility As python3 imports are working a bit differently the structure of the imported files needs to change. Instead of having symlinks to criu.py and rpc_pb2.py which does not match the import structure just create symlink to ../lib/py (like crit) to make zdtm usable again with the python3 compatibility. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/criu.py | 1 - test/pycriu | 1 + test/rpc_pb2.py | 1 - test/zdtm.py | 2 +- 4 files changed, 2 insertions(+), 3 deletions(-) delete mode 120000 test/criu.py create mode 120000 test/pycriu delete mode 120000 test/rpc_pb2.py diff --git a/test/criu.py b/test/criu.py deleted file mode 120000 index 662608498..000000000 --- a/test/criu.py +++ /dev/null @@ -1 +0,0 @@ -../lib/py/criu.py \ No newline at end of file diff --git a/test/pycriu b/test/pycriu new file mode 120000 index 000000000..d13a8790a --- /dev/null +++ b/test/pycriu @@ -0,0 +1 @@ +../lib/py/ \ No newline at end of file diff --git a/test/rpc_pb2.py b/test/rpc_pb2.py deleted file mode 120000 index 49648aef7..000000000 --- a/test/rpc_pb2.py +++ /dev/null @@ -1 +0,0 @@ -../lib/py/rpc_pb2.py \ No newline at end of file diff --git a/test/zdtm.py b/test/zdtm.py index f594cd6f5..8ea6cc8eb 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -20,7 +20,7 @@ import fcntl import errno import datetime import yaml -import criu as crpc +import pycriu as crpc os.chdir(os.path.dirname(os.path.abspath(__file__))) From 553dd546b5a895554d08d9f7cfb46d2cb090c494 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 16 May 2018 06:20:26 +0000 Subject: [PATCH 1487/4375] travis: fix python2 package installation For python2/python3 compatibility install additional (python2-future) and different (python2-ipaddress) packages during test. Also switch Fedora tests to explicitly install versioned python packages (python2-* instead of python-*). Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.alpine | 3 ++- scripts/build/Dockerfile.centos | 6 ++++-- scripts/build/Dockerfile.fedora.tmpl | 12 ++++++++---- scripts/build/Dockerfile.s390x.hdr | 2 +- scripts/build/Dockerfile.tmpl | 3 ++- scripts/travis/travis-tests | 6 ++++-- 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index fa8258187..21647e1e1 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -26,11 +26,12 @@ RUN mv .ccache /tmp && make mrproper && ccache -sz && \ RUN apk add \ py-yaml \ py-pip \ + py2-future \ ip6tables \ iptables \ iproute2 \ tar \ bash -RUN pip install protobuf ipaddr +RUN pip install protobuf ipaddress RUN make -C test/zdtm diff --git a/scripts/build/Dockerfile.centos b/scripts/build/Dockerfile.centos index e26427d8e..75f0ed461 100644 --- a/scripts/build/Dockerfile.centos +++ b/scripts/build/Dockerfile.centos @@ -22,9 +22,11 @@ RUN yum install -y \ protobuf-devel \ protobuf-python \ python \ - python-ipaddr \ + python-ipaddress \ + python2-future \ python-yaml \ - tar + tar \ + which COPY . /criu WORKDIR /criu diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index 039cb1131..f6b374389 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -17,11 +17,15 @@ RUN dnf install -y \ procps-ng \ protobuf-c-devel \ protobuf-devel \ - protobuf-python \ - python \ - python-ipaddr \ + python2-protobuf \ + python2 \ + # Starting with Fedora 28 this is python2-ipaddress + python-ipaddress \ + # Starting with Fedora 28 this is python2-pyyaml python-yaml \ - tar + python2-future \ + tar \ + which # Replace coreutils-single with "traditional" coreutils # to fix the following error on Fedora 28/rawhide while diff --git a/scripts/build/Dockerfile.s390x.hdr b/scripts/build/Dockerfile.s390x.hdr index be75712f4..37ff20832 100644 --- a/scripts/build/Dockerfile.s390x.hdr +++ b/scripts/build/Dockerfile.s390x.hdr @@ -1,4 +1,4 @@ -FROM s390x/debian:jessie +FROM s390x/debian:jessie-backports ENV QEMU_CPU z900 COPY scripts/build/qemu-user-static/usr/bin/qemu-s390x-static /usr/bin/qemu-s390x-static diff --git a/scripts/build/Dockerfile.tmpl b/scripts/build/Dockerfile.tmpl index f1fff3a52..bdfdf713a 100644 --- a/scripts/build/Dockerfile.tmpl +++ b/scripts/build/Dockerfile.tmpl @@ -19,7 +19,8 @@ RUN apt-get update && apt-get install -y \ pkg-config \ protobuf-c-compiler \ protobuf-compiler \ - python-minimal + python-minimal \ + python-future COPY . /criu WORKDIR /criu diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 17c8c231d..c642ae099 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -2,7 +2,7 @@ set -x -e TRAVIS_PKGS="protobuf-c-compiler libprotobuf-c0-dev libaio-dev - libprotobuf-dev protobuf-compiler python-ipaddr libcap-dev + libprotobuf-dev protobuf-compiler libcap-dev libnl-3-dev gcc-multilib gdb bash python-protobuf libnet-dev util-linux asciidoc xmlto libnl-route-3-dev" @@ -45,7 +45,9 @@ travis_prep () { apt-get update -qq apt-get install -qq --no-install-recommends $TRAVIS_PKGS - pip install junit-xml + # travis is based on 14.04 and that does not have python + # packages for future and ipaddress (16.04 has those packages) + pip install junit-xml future ipaddress chmod a+x $HOME } From a674859195ff8e3ffe75d47331a1a570542bd73b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 4 Jun 2018 20:17:57 +0300 Subject: [PATCH 1488/4375] dump: Don't loose dump_namespaces error In case if dump_namespaces failed we may have ret shadowed and erroneously report checkpoint success. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index bb7a6c833..7a9f479c1 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1842,9 +1842,11 @@ int cr_dump_tasks(pid_t pid) if (ret) goto err; - if (root_ns_mask) - if (dump_namespaces(root_item, root_ns_mask) < 0) + if (root_ns_mask) { + ret = dump_namespaces(root_item, root_ns_mask); + if (ret) goto err; + } ret = dump_cgroups(); if (ret) From 00ed1eeb1a5d9ffa9242d6e91aefd919f4eebd53 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:02:51 +0300 Subject: [PATCH 1489/4375] test: make zdtm.py python2/python3 compatible Cc: Adrian Reber Signed-off-by: Andrei Vagin --- test/inhfd/fifo.py | 4 +- test/inhfd/pipe.py | 2 +- test/inhfd/socket.py | 2 +- test/inhfd/tty.py | 2 +- test/zdtm.py | 247 ++++++++++++++++++++++--------------------- 5 files changed, 131 insertions(+), 126 deletions(-) diff --git a/test/inhfd/fifo.py b/test/inhfd/fifo.py index a4b4fc84e..aabc89034 100755 --- a/test/inhfd/fifo.py +++ b/test/inhfd/fifo.py @@ -8,8 +8,8 @@ def create_fds(): raise Exception("Unable to mount tmpfs") tfifo = os.path.join(tdir, "test_fifo") os.mkfifo(tfifo) - fd2 = open(tfifo, "w+") - fd1 = open(tfifo, "r") + fd2 = open(tfifo, "w+b", buffering=0) + fd1 = open(tfifo, "rb") os.system("umount -l %s" % tdir) os.rmdir(tdir) diff --git a/test/inhfd/pipe.py b/test/inhfd/pipe.py index 6e44528bd..0f9115246 100755 --- a/test/inhfd/pipe.py +++ b/test/inhfd/pipe.py @@ -2,7 +2,7 @@ import os def create_fds(): (fd1, fd2) = os.pipe() - return (os.fdopen(fd2, "w"), os.fdopen(fd1, "r")) + return (os.fdopen(fd2, "wb"), os.fdopen(fd1, "rb")) def filename(pipef): return 'pipe:[%d]' % os.fstat(pipef.fileno()).st_ino diff --git a/test/inhfd/socket.py b/test/inhfd/socket.py index 0ac47902e..45ae03367 100755 --- a/test/inhfd/socket.py +++ b/test/inhfd/socket.py @@ -3,7 +3,7 @@ import os def create_fds(): (sk1, sk2) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM) - return (sk1.makefile("w"), sk2.makefile("r")) + return (sk1.makefile("wb"), sk2.makefile("rb")) def __sock_ino(sockf): return os.fstat(sockf.fileno()).st_ino diff --git a/test/inhfd/tty.py b/test/inhfd/tty.py index a158baef4..fbda13948 100755 --- a/test/inhfd/tty.py +++ b/test/inhfd/tty.py @@ -6,7 +6,7 @@ def child_prep(fd): def create_fds(): (fd1, fd2) = pty.openpty() - return (os.fdopen(fd2, "w"), os.fdopen(fd1, "r")) + return (os.fdopen(fd2, "wb"), os.fdopen(fd1, "rb")) def filename(pipef): st = os.fstat(pipef.fileno()) diff --git a/test/zdtm.py b/test/zdtm.py index 8ea6cc8eb..e7daad106 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1,5 +1,8 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python # vim: noet ts=8 sw=8 sts=8 +from __future__ import absolute_import, division, print_function, unicode_literals +from builtins import (str, open, range, zip, int) + import argparse import glob import os @@ -35,10 +38,10 @@ def traceit(f, e, a): global prev_line line = linecache.getline(fil, lineno) if line == prev_line: - print " ..." + print(" ...") else: prev_line = line - print "+%4d: %s" % (lineno, line.rstrip()) + print("+%4d: %s" % (lineno, line.rstrip())) return traceit @@ -120,7 +123,7 @@ def check_core_files(): for i in reports: add_to_report(i, os.path.basename(i)) print_sep(i) - print open(i).read() + print(open(i).read()) print_sep(i) return True @@ -171,7 +174,7 @@ class ns_flavor: # run in parallel try: os.makedirs(self.root + os.path.dirname(fname)) - except OSError, e: + except OSError as e: if e.errno != errno.EEXIST: raise dst = tempfile.mktemp(".tso", "", self.root + os.path.dirname(fname)) @@ -185,10 +188,11 @@ class ns_flavor: # This Mayakovsky-style code gets list of libraries a binary # needs minus vdso and gate .so-s libs = map(lambda x: x[1] == '=>' and x[2] or x[0], - map(lambda x: x.split(), + map(lambda x: str(x).split(), filter(lambda x: not xl.match(x), - map(lambda x: x.strip(), - filter(lambda x: x.startswith('\t'), ldd.stdout.readlines()))))) + map(lambda x: str(x).strip(), + filter(lambda x: str(x).startswith('\t'), ldd.stdout.read().decode('ascii').splitlines()))))) + ldd.wait() for lib in libs: @@ -200,19 +204,19 @@ class ns_flavor: name = "/dev/" + name if not rdev: if not os.access(name, os.F_OK): - print "Skipping %s at root" % name + print("Skipping %s at root" % name) return else: rdev = os.stat(name).st_rdev name = self.root + name os.mknod(name, stat.S_IFCHR, rdev) - os.chmod(name, 0666) + os.chmod(name, 0o666) def __construct_root(self): for dir in self.__root_dirs: os.mkdir(self.root + dir) - os.chmod(self.root + dir, 0777) + os.chmod(self.root + dir, 0o777) for ldir in ["/bin", "/sbin", "/lib", "/lib64"]: os.symlink(".." + ldir, self.root + "/usr" + ldir) @@ -239,9 +243,9 @@ class ns_flavor: with open(os.path.abspath(__file__)) as o: fcntl.flock(o, fcntl.LOCK_EX) if not os.access(self.root + "/.constructed", os.F_OK): - print "Construct root for %s" % l_bins[0] + print("Construct root for %s" % l_bins[0]) self.__construct_root() - os.mknod(self.root + "/.constructed", stat.S_IFREG | 0600) + os.mknod(self.root + "/.constructed", stat.S_IFREG | 0o600) for b in l_bins: self.__copy_libs(b) @@ -257,7 +261,7 @@ class ns_flavor: def clean(): for d in ns_flavor.__root_dirs: p = './' + d - print 'Remove %s' % p + print('Remove %s' % p) if os.access(p, os.F_OK): shutil.rmtree('./' + d) @@ -273,7 +277,7 @@ class userns_flavor(ns_flavor): def init(self, l_bins, x_bins): # To be able to create roots_yard in CRIU - os.chmod(".", os.stat(".").st_mode | 0077) + os.chmod(".", os.stat(".").st_mode | 0o077) ns_flavor.init(self, l_bins, x_bins) @staticmethod @@ -282,7 +286,7 @@ class userns_flavor(ns_flavor): flavors = {'h': host_flavor, 'ns': ns_flavor, 'uns': userns_flavor} -flavors_codes = dict(zip(xrange(len(flavors)), sorted(flavors.keys()))) +flavors_codes = dict(zip(range(len(flavors)), sorted(flavors.keys()))) # # Helpers @@ -302,7 +306,7 @@ def tail(path): stdout = subprocess.PIPE) out = p.stdout.readline() p.wait() - return out + return out.decode() def rpidfile(path): @@ -314,12 +318,12 @@ def wait_pid_die(pid, who, tmo = 30): while stime < tmo: try: os.kill(int(pid), 0) - except OSError, e: + except OSError as e: if e.errno != errno.ESRCH: - print e + print(e) break - print "Wait for %s(%d) to die for %f" % (who, pid, stime) + print("Wait for %s(%d) to die for %f" % (who, pid, stime)) time.sleep(stime) stime *= 2 else: @@ -338,12 +342,12 @@ def test_flag(tdesc, flag): # -class test_fail_exc: +class test_fail_exc(Exception): def __init__(self, step): self.step = step -class test_fail_expected_exc: +class test_fail_expected_exc(Exception): def __init__(self, cr_action): self.cr_action = cr_action @@ -396,12 +400,12 @@ class zdtm_test: # Add write perms for .out and .pid files for b in self._bins: p = os.path.dirname(b) - os.chmod(p, os.stat(p).st_mode | 0222) + os.chmod(p, os.stat(p).st_mode | 0o222) def start(self): self.__flavor.init(self._bins, self._deps) - print "Start test" + print("Start test") env = self._env if not self.__freezer.kernel: @@ -414,7 +418,7 @@ class zdtm_test: env['ZDTM_GROUPS'] = "27495 48244" self.__add_wperms() else: - print "Test is SUID" + print("Test is SUID") if self.__flavor.ns: env['ZDTM_NEWNS'] = "1" @@ -435,7 +439,7 @@ class zdtm_test: try: os.kill(int(self.getpid()), 0) - except Exception, e: + except Exception as e: raise test_fail_exc("start: %s" % e) if not self.static(): @@ -446,7 +450,7 @@ class zdtm_test: def kill(self, sig = signal.SIGKILL): self.__freezer.thaw() if self.__pid: - print "Send the %d signal to %s" % (sig, self.__pid) + print("Send the %d signal to %s" % (sig, self.__pid)) os.kill(int(self.__pid), sig) self.gone(sig == signal.SIGKILL) @@ -458,12 +462,12 @@ class zdtm_test: self.kill(signal.SIGTERM) res = tail(self.__name + '.out') - if 'PASS' not in res.split(): + if 'PASS' not in list(map(lambda s: s.strip(), res.split())): if os.access(self.__name + '.out.inprogress', os.F_OK): print_sep(self.__name + '.out.inprogress') - print open(self.__name + '.out.inprogress').read() + print(open(self.__name + '.out.inprogress').read()) print_sep(self.__name + '.out.inprogress') - raise test_fail_exc("result check") + raise test_fail_exc("result check: %s" % list(map(lambda s: s.strip(), res.split())) + res) def getpid(self): if self.__pid == 0: @@ -505,9 +509,9 @@ class zdtm_test: def print_output(self): if os.access(self.__name + '.out', os.R_OK): - print "Test output: " + "=" * 32 - print open(self.__name + '.out').read() - print " <<< " + "=" * 32 + print("Test output: " + "=" * 32) + print(open(self.__name + '.out').read()) + print(" <<< " + "=" * 32) def static(self): return self.__name.split('/')[1] == 'static' @@ -532,7 +536,7 @@ class zdtm_test: class inhfd_test: def __init__(self, name, desc, flavor, freezer): self.__name = os.path.basename(name) - print "Load %s" % name + print("Load %s" % name) self.__fdtyp = imp.load_source(self.__name, name) self.__my_file = None self.__peer_pid = 0 @@ -565,8 +569,8 @@ class inhfd_test: os.close(start_pipe[1]) try: data = peer_file.read(16) - except Exception, e: - print "Unable to read a peer file: %s" % e + except Exception as e: + print("Unable to read a peer file: %s" % e) sys.exit(1) sys.exit(data == self.__message and 42 or 2) @@ -628,7 +632,7 @@ class groups_test(zdtm_test): if flavor.ns: self.__real_name = name self.__subs = map(lambda x: x.strip(), open(name).readlines()) - print "Subs:\n%s" % '\n'.join(self.__subs) + print("Subs:\n%s" % '\n'.join(self.__subs)) else: self.__real_name = '' self.__subs = [] @@ -688,7 +692,7 @@ class criu_cli: env = dict(os.environ, ASAN_OPTIONS = "log_path=asan.log:disable_coredump=0:detect_leaks=0") if fault: - print "Forcing %s fault" % fault + print("Forcing %s fault" % fault) env['CRIU_FAULT'] = fault cr = subprocess.Popen(strace + [criu_bin, action] + args, env = env, preexec_fn = preexec) @@ -799,8 +803,8 @@ class criu_rpc: p.criu = criu else: raise test_fail_exc('RPC for %s required' % action) - except crpc.CRIUExceptionExternal, e: - print "Fail", e + except crpc.CRIUExceptionExternal as e: + print("Fail", e) ret = -1 else: ret = 0 @@ -847,23 +851,23 @@ class criu: ret = self.__dump_process.wait() if self.__lazy_pages_p: ret = self.__lazy_pages_p.wait() - grep_errors(os.path.join(self.__ddir(), "lazy-pages.log")) + grep_errors(os.path.join(self.__ddir(), "lazy-pages.log")) self.__lazy_pages_p = None if ret: raise test_fail_exc("criu lazy-pages exited with %s" % ret) if self.__page_server_p: ret = self.__page_server_p.wait() - grep_errors(os.path.join(self.__ddir(), "page-server.log")) + grep_errors(os.path.join(self.__ddir(), "page-server.log")) self.__page_server_p = None if ret: raise test_fail_exc("criu page-server exited with %s" % ret) if self.__dump_process: ret = self.__dump_process.wait() - grep_errors(os.path.join(self.__ddir(), "dump.log")) + grep_errors(os.path.join(self.__ddir(), "dump.log")) self.__dump_process = None if ret: raise test_fail_exc("criu dump exited with %s" % ret) - return + return def logs(self): return self.__dump_path @@ -872,7 +876,7 @@ class criu: self.__test = test self.__dump_path = "dump/" + test.getname() + "/" + test.getpid() if os.path.exists(self.__dump_path): - for i in xrange(100): + for i in range(100): newpath = self.__dump_path + "." + str(i) if not os.path.exists(newpath): os.rename(self.__dump_path, newpath) @@ -884,7 +888,7 @@ class criu: def cleanup(self): if self.__dump_path: - print "Removing %s" % self.__dump_path + print("Removing %s" % self.__dump_path) shutil.rmtree(self.__dump_path) def __ddir(self): @@ -903,7 +907,8 @@ class criu: with open(os.path.join(self.__ddir(), action + '.cropt'), 'w') as f: f.write(' '.join(s_args) + '\n') - print "Run criu " + action + + print("Run criu " + action) strace = [] if self.__sat: @@ -949,7 +954,7 @@ class criu: # create a clean directory for images os.rename(__ddir, __ddir + ".fail") os.mkdir(__ddir) - os.chmod(__ddir, 0777) + os.chmod(__ddir, 0o777) else: # on restore we move only a log file, because we need images os.rename(os.path.join(__ddir, log), os.path.join(__ddir, log + ".fail")) @@ -957,7 +962,7 @@ class criu: # PID of one of restored processes. open("/proc/sys/kernel/ns_last_pid", "w+").write(ns_last_pid) # try again without faults - print "Run criu " + action + print("Run criu " + action) ret = self.__criu.run(action, s_args, False, strace, preexec) grep_errors(os.path.join(__ddir, log)) if ret == 0: @@ -979,7 +984,7 @@ class criu: def dump(self, action, opts = []): self.__iter += 1 os.mkdir(self.__ddir()) - os.chmod(self.__ddir(), 0777) + os.chmod(self.__ddir(), 0o777) a_opts = ["-t", self.__test.getpid()] if self.__prev_dump_iter: @@ -987,7 +992,7 @@ class criu: self.__prev_dump_iter = self.__iter if self.__page_server: - print "Adding page server" + print("Adding page server") ps_opts = ["--port", "12345"] if self.__dedup: @@ -1029,7 +1034,7 @@ class criu: if self.__page_server_p: ret = self.__page_server_p.wait() - grep_errors(os.path.join(self.__ddir(), "page-server.log")) + grep_errors(os.path.join(self.__ddir(), "page-server.log")) self.__page_server_p = None if ret: raise test_fail_exc("criu page-server exited with %d" % ret) @@ -1081,31 +1086,31 @@ class criu: @staticmethod def available(): if not os.access(criu_bin, os.X_OK): - print "CRIU binary not built" + print("CRIU binary not built") sys.exit(1) def kill(self): if self.__lazy_pages_p: self.__lazy_pages_p.terminate() - print "criu lazy-pages exited with %s" % self.__lazy_pages_p.wait() - grep_errors(os.path.join(self.__ddir(), "lazy-pages.log")) + print("criu lazy-pages exited with %s" % self.__lazy_pages_p.wait()) + grep_errors(os.path.join(self.__ddir(), "lazy-pages.log")) self.__lazy_pages_p = None if self.__page_server_p: self.__page_server_p.terminate() - print "criu page-server exited with %s" % self.__page_server_p.wait() - grep_errors(os.path.join(self.__ddir(), "page-server.log")) + print("criu page-server exited with %s" % self.__page_server_p.wait()) + grep_errors(os.path.join(self.__ddir(), "page-server.log")) self.__page_server_p = None if self.__dump_process: self.__dump_process.terminate() - print "criu dump exited with %s" % self.__dump_process.wait() - grep_errors(os.path.join(self.__ddir(), "dump.log")) + print("criu dump exited with %s" % self.__dump_process.wait()) + grep_errors(os.path.join(self.__ddir(), "dump.log")) self.__dump_process = None def try_run_hook(test, args): hname = test.getname() + '.hook' if os.access(hname, os.X_OK): - print "Running %s(%s)" % (hname, ', '.join(args)) + print("Running %s(%s)" % (hname, ', '.join(args))) hook = subprocess.Popen([hname] + args) if hook.wait() != 0: raise test_fail_exc("hook " + " ".join(args)) @@ -1123,7 +1128,7 @@ def init_sbs(): global do_sbs do_sbs = True else: - print "Can't do step-by-step in this runtime" + print("Can't do step-by-step in this runtime") def sbs(what): @@ -1136,7 +1141,7 @@ def sbs(what): # def iter_parm(opt, dflt): x = ((opt or str(dflt)) + ":0").split(':') - return (xrange(0, int(x[0])), float(x[1])) + return (range(0, int(x[0])), float(x[1])) def cr(cr_api, test, opts): @@ -1173,7 +1178,7 @@ def cr(cr_api, test, opts): try_run_hook(test, ["--pre-restore"]) cr_api.restore() os.environ["ZDTM_TEST_PID"] = str(test.getpid()) - os.environ["ZDTM_IMG_DIR"] = cr_api.logs() + os.environ["ZDTM_IMG_DIR"] = cr_api.logs() try_run_hook(test, ["--post-restore"]) sbs('post-restore') @@ -1199,7 +1204,7 @@ def get_visible_state(test): cmaps = [[0, 0, ""]] last = 0 for mp in open("/proc/%s/root/proc/%s/maps" % (test.getpid(), pid)): - m = map(lambda x: int('0x' + x, 0), mp.split()[0].split('-')) + m = list(map(lambda x: int('0x' + x, 0), mp.split()[0].split('-'))) m.append(mp.split()[1]) @@ -1221,7 +1226,7 @@ def get_visible_state(test): r = re.compile("^\S+\s\S+\s\S+\s(\S+)\s(\S+)") for m in open("/proc/%s/root/proc/%s/mountinfo" % (test.getpid(), pid)): cmounts.append(r.match(m).groups()) - except IOError, e: + except IOError as e: if e.errno != errno.EINVAL: raise e mounts[pid] = cmounts @@ -1235,8 +1240,8 @@ def check_visible_state(test, state, opts): fnew = new[0][pid] fold = state[0][pid] if fnew != fold: - print "%s: Old files lost: %s" % (pid, fold - fnew) - print "%s: New files appeared: %s" % (pid, fnew - fold) + print("%s: Old files lost: %s" % (pid, fold - fnew)) + print("%s: New files appeared: %s" % (pid, fnew - fold)) raise test_fail_exc("fds compare") old_maps = state[1][pid] @@ -1247,29 +1252,29 @@ def check_visible_state(test, state, opts): if vsyscall in new_maps and vsyscall not in old_maps: new_maps.remove(vsyscall) if old_maps != new_maps: - print "%s: Old maps lost: %s" % (pid, old_maps - new_maps) - print "%s: New maps appeared: %s" % (pid, new_maps - old_maps) + print("%s: Old maps lost: %s" % (pid, old_maps - new_maps)) + print("%s: New maps appeared: %s" % (pid, new_maps - old_maps)) if not opts['fault']: # skip parasite blob raise test_fail_exc("maps compare") old_mounts = state[2][pid] new_mounts = new[2][pid] - for i in xrange(len(old_mounts)): + for i in range(len(old_mounts)): m = old_mounts.pop(0) if m in new_mounts: new_mounts.remove(m) else: old_mounts.append(m) if old_mounts or new_mounts: - print "%s: Old mounts lost: %s" % (pid, old_mounts) - print "%s: New mounts appeared: %s" % (pid, new_mounts) + print("%s: Old mounts lost: %s" % (pid, old_mounts)) + print("%s: New mounts appeared: %s" % (pid, new_mounts)) raise test_fail_exc("mounts compare") if '--link-remap' in test.getdopts(): import glob link_remap_list = glob.glob(os.path.dirname(test.getname()) + '/link_remap*') if link_remap_list: - print "%s: link-remap files left: %s" % (test.getname(), link_remap_list) + print("%s: link-remap files left: %s" % (test.getname(), link_remap_list)) raise test_fail_exc("link remaps left") @@ -1337,7 +1342,7 @@ def cmp_ns(ns1, match, ns2, msg): ns1_ino = os.stat(ns1).st_ino ns2_ino = os.stat(ns2).st_ino if eval("%r %s %r" % (ns1_ino, match, ns2_ino)): - print "%s match (%r %s %r) fail" % (msg, ns1_ino, match, ns2_ino) + print("%s match (%r %s %r) fail" % (msg, ns1_ino, match, ns2_ino)) raise test_fail_exc("%s compare" % msg) @@ -1353,8 +1358,8 @@ def pstree_each_pid(root_pid): pid_line = f_children.readline().strip(" \n") if pid_line: child_pids += pid_line.split(" ") - except Exception, e: - print "Unable to read /proc/*/children: %s" % e + except Exception as e: + print("Unable to read /proc/*/children: %s" % e) return # process is dead yield root_pid @@ -1370,8 +1375,8 @@ def is_proc_stopped(pid): for line in f_status.readlines(): if line.startswith("State:"): return line.split(":", 1)[1].strip().split(" ")[0] - except Exception, e: - print "Unable to read a thread status: %s" % e + except Exception as e: + print("Unable to read a thread status: %s" % e) pass # process is dead return None @@ -1382,8 +1387,8 @@ def is_proc_stopped(pid): thread_dirs = [] try: thread_dirs = os.listdir(tasks_dir) - except Exception, e: - print "Unable to read threads: %s" % e + except Exception as e: + print("Unable to read threads: %s" % e) pass # process is dead for thread_dir in thread_dirs: @@ -1407,8 +1412,8 @@ def pstree_signal(root_pid, signal): for pid in pstree_each_pid(root_pid): try: os.kill(int(pid), signal) - except Exception, e: - print "Unable to kill %d: %s" % (pid, e) + except Exception as e: + print("Unable to kill %d: %s" % (pid, e)) pass # process is dead @@ -1416,7 +1421,7 @@ def do_run_test(tname, tdesc, flavs, opts): tcname = tname.split('/')[0] tclass = test_classes.get(tcname, None) if not tclass: - print "Unknown test class %s" % tcname + print("Unknown test class %s" % tcname) return if opts['report']: @@ -1427,7 +1432,6 @@ def do_run_test(tname, tdesc, flavs, opts): fcg = get_freezer(opts['freezecg']) for f in flavs: - print print_sep("Run %s in %s" % (tname, f)) if opts['dry_run']: continue @@ -1507,23 +1511,23 @@ class Launcher: self.__junit_test_cases = [] self.__file_report = open(reportname, 'a') - print >> self.__file_report, "TAP version 13" - print >> self.__file_report, "# Hardware architecture: " + arch - print >> self.__file_report, "# Timestamp: " + now.strftime("%Y-%m-%d %H:%M") + " (GMT+1)" - print >> self.__file_report, "# " - print >> self.__file_report, "1.." + str(nr_tests) + print(u"TAP version 13", file=self.__file_report) + print(u"# Hardware architecture: " + arch, file=self.__file_report) + print(u"# Timestamp: " + now.strftime("%Y-%m-%d %H:%M") + " (GMT+1)", file=self.__file_report) + print(u"# ", file=self.__file_report) + print(u"1.." + str(nr_tests), file=self.__file_report) self.__taint = open("/proc/sys/kernel/tainted").read() if int(self.__taint, 0) != 0: - print "The kernel is tainted: %r" % self.__taint + print("The kernel is tainted: %r" % self.__taint) if not opts["ignore_taint"]: raise Exception("The kernel is tainted: %r" % self.__taint) def __show_progress(self, msg): - perc = self.__nr * 16 / self.__total - print "=== Run %d/%d %s %s" % (self.__nr, self.__total, '=' * perc + '-' * (16 - perc), msg) + perc = int(self.__nr * 16 / self.__total) + print("=== Run %d/%d %s %s" % (self.__nr, self.__total, '=' * perc + '-' * (16 - perc), msg)) def skip(self, name, reason): - print "Skipping %s (%s)" % (name, reason) + print("Skipping %s (%s)" % (name, reason)) self.__nr += 1 self.__runtest += 1 self.__nr_skip += 1 @@ -1533,8 +1537,8 @@ class Launcher: tc.add_skipped_info(reason) self.__junit_test_cases.append(tc) if self.__file_report: - testline = "ok %d - %s # SKIP %s" % (self.__runtest, name, reason) - print >> self.__file_report, testline + testline = u"ok %d - %s # SKIP %s" % (self.__runtest, name, reason) + print(testline, file=self.__file_report) def run_test(self, name, desc, flavor): @@ -1586,21 +1590,21 @@ class Launcher: failed_flavor = decode_flav(os.WEXITSTATUS(status)) self.__failed.append([sub['name'], failed_flavor]) if self.__file_report: - testline = "not ok %d - %s # flavor %s" % (self.__runtest, sub['name'], failed_flavor) + testline = u"not ok %d - %s # flavor %s" % (self.__runtest, sub['name'], failed_flavor) output = open(sub['log']).read() details = {'output': output} tc.add_error_info(output = output) - print >> self.__file_report, testline - print >> self.__file_report, yaml.dump(details, explicit_start=True, explicit_end=True, default_style='|') + print(testline, file=self.__file_report) + print("%s" % yaml.dump(details, explicit_start=True, explicit_end=True, default_style='|'), file=self.__file_report) if sub['log']: add_to_output(sub['log']) else: if self.__file_report: - testline = "ok %d - %s" % (self.__runtest, sub['name']) - print >> self.__file_report, testline + testline = u"ok %d - %s" % (self.__runtest, sub['name']) + print(testline, file=self.__file_report) if sub['log']: - print open(sub['log']).read() + print(open(sub['log']).read()) os.unlink(sub['log']) return True @@ -1638,7 +1642,7 @@ class Launcher: print_sep("%d TEST(S) FAILED (TOTAL %d/SKIPPED %d)" % (len(self.__failed), self.__total, self.__nr_skip), "#") for failed in self.__failed: - print " * %s(%s)" % (failed[0], failed[1]) + print(" * %s(%s)" % (failed[0], failed[1])) else: print_sep("ALL TEST(S) PASSED (TOTAL %d/SKIPPED %d)" % (self.__total, self.__nr_skip), "#") @@ -1662,7 +1666,7 @@ def all_tests(opts): if stat.S_IFMT(st.st_mode) in [stat.S_IFLNK, stat.S_IFSOCK]: continue files.append(fp) - excl = map(lambda x: os.path.join(desc['dir'], x), desc['exclude']) + excl = list(map(lambda x: os.path.join(desc['dir'], x), desc['exclude'])) tlist = filter(lambda x: not x.endswith('.checkskip') and not x.endswith('.hook') and @@ -1694,16 +1698,16 @@ def self_checkskip(tname): def print_fname(fname, typ): - print "=[%s]=> %s" % (typ, fname) + print("=[%s]=> %s" % (typ, fname)) def print_sep(title, sep = "=", width = 80): - print (" " + title + " ").center(width, sep) + print((" " + title + " ").center(width, sep)) def print_error(line): line = line.rstrip() - print line + print(line) if line.endswith('>'): # combine pie output return True return False @@ -1739,7 +1743,7 @@ def run_tests(opts): if opts['pre'] or opts['snaps']: if not criu.check("mem_dirty_track"): - print "Tracking memory is not available" + print("Tracking memory is not available") return if opts['all']: @@ -1754,29 +1758,30 @@ def run_tests(opts): run_all = False elif opts['from']: if not os.access(opts['from'], os.R_OK): - print "No such file" + print("No such file") return torun = map(lambda x: x.strip(), open(opts['from'])) opts['keep_going'] = False run_all = True else: - print "Specify test with -t or -a" + print("Specify test with -t or -a") return + torun = list(torun) if opts['keep_going'] and len(torun) < 2: - print "[WARNING] Option --keep-going is more useful when running multiple tests" + print("[WARNING] Option --keep-going is more useful when running multiple tests") opts['keep_going'] = False if opts['exclude']: excl = re.compile(".*(" + "|".join(opts['exclude']) + ")") - print "Compiled exclusion list" + print("Compiled exclusion list") if opts['report']: init_report(opts['report']) if opts['parallel'] and opts['freezecg']: - print "Parallel launch with freezer not supported" + print("Parallel launch with freezer not supported") opts['parallel'] = None if opts['join_ns']: @@ -1792,7 +1797,7 @@ def run_tests(opts): raise Exception("UFFD is not supported, cannot run with --lazy-pages") if not uffd_noncoop: # Most tests will work with 4.3 - 4.11 - print "[WARNING] Non-cooperative UFFD is missing, some tests might spuriously fail" + print("[WARNING] Non-cooperative UFFD is missing, some tests might spuriously fail") launcher = Launcher(opts, len(torun)) try: @@ -1819,7 +1824,7 @@ def run_tests(opts): feat_list = tdesc.get('feature', "") for feat in feat_list.split(): if feat not in features: - print "Checking feature %s" % feat + print("Checking feature %s" % feat) features[feat] = criu.check(feat) if not features[feat]: @@ -1896,9 +1901,9 @@ def show_test_info(t): def list_tests(opts): tlist = all_tests(opts) if opts['info']: - print sti_fmt % ('Name', 'Flavors', 'Flags') + print(sti_fmt % ('Name', 'Flavors', 'Flags')) tlist = map(lambda x: show_test_info(x), tlist) - print '\n'.join(tlist) + print('\n'.join(tlist)) class group: @@ -1948,14 +1953,14 @@ class group: f.write("echo 'All %s scripts OK'\n" % ext) f.close() - os.chmod(fname + ext, 0700) + os.chmod(fname + ext, 0o700) def dump(self, fname): f = open(fname, "w") for t in self.__tests: f.write(t + '\n') f.close() - os.chmod(fname, 0700) + os.chmod(fname, 0o700) if len(self.__desc) or len(self.__deps): f = open(fname + '.desc', "w") @@ -1982,7 +1987,7 @@ def group_tests(opts): random.shuffle(tlist) if opts['exclude']: excl = re.compile(".*(" + "|".join(opts['exclude']) + ")") - print "Compiled exclusion list" + print("Compiled exclusion list") for t in tlist: if excl and excl.match(t): @@ -2013,11 +2018,11 @@ def group_tests(opts): g.dump(fn) nr += 1 - print "Generated %d group(s)" % nr + print("Generated %d group(s)" % nr) def clean_stuff(opts): - print "Cleaning %s" % opts['what'] + print("Cleaning %s" % opts['what']) if opts['what'] == 'nsroot': for f in flavors: f = flavors[f] From 0dab224be6b3b15bec32bf4970439652918434eb Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:02:52 +0300 Subject: [PATCH 1490/4375] travis: set python3 as default for fedora containers We need a few jobs to check a compatibility with python3 v2: fix inhfd and rpc tests Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.fedora.tmpl | 11 +++++++++- test/zdtm.py | 32 +++++++++++++++++++++------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index f6b374389..5b618081d 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -23,9 +23,16 @@ RUN dnf install -y \ python-ipaddress \ # Starting with Fedora 28 this is python2-pyyaml python-yaml \ + python3-pip \ python2-future \ + python3-PyYAML \ + python3-future \ + python3-protobuf \ + python3-junit_xml \ tar \ - which + which \ + e2fsprogs \ + asciidoc xmlto # Replace coreutils-single with "traditional" coreutils # to fix the following error on Fedora 28/rawhide while @@ -33,6 +40,8 @@ RUN dnf install -y \ # > sh: /usr/bin/sort: /usr/bin/coreutils: bad interpreter: No such file or directory RUN dnf install -y --allowerasing coreutils +RUN ln -sf python3 /usr/bin/python + COPY . /criu WORKDIR /criu diff --git a/test/zdtm.py b/test/zdtm.py index e7daad106..9bcdc8fc0 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -545,7 +545,7 @@ class inhfd_test: self.__dump_opts = None def start(self): - self.__message = "".join([random.choice(string.ascii_letters) for _ in range(16)]) + self.__message = b"".join([random.choice(string.ascii_letters).encode() for _ in range(16)]) (self.__my_file, peer_file) = self.__fdtyp.create_fds() # Check FDs returned for inter-connection @@ -561,9 +561,14 @@ class inhfd_test: getattr(self.__fdtyp, "child_prep", lambda fd: None)(peer_file) + try: + os.unlink(self.__name + ".out") + except Exception as e: + print(e) + fd = os.open(self.__name + ".out", os.O_WRONLY | os.O_APPEND | os.O_CREAT) + os.dup2(fd, 1) + os.dup2(fd, 2) os.close(0) - os.close(1) - os.close(2) self.__my_file.close() os.close(start_pipe[0]) os.close(start_pipe[1]) @@ -573,6 +578,8 @@ class inhfd_test: print("Unable to read a peer file: %s" % e) sys.exit(1) + if data != self.__message: + print("%r %r" % (data, self.__message)) sys.exit(data == self.__message and 42 or 2) os.close(start_pipe[1]) @@ -586,6 +593,8 @@ class inhfd_test: self.__my_file.write(self.__message) self.__my_file.flush() pid, status = os.waitpid(self.__peer_pid, 0) + print(open(self.__name + ".out").read()) + self.__peer_pid = 0 if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 42: raise test_fail_exc("test failed with %d" % status) @@ -610,7 +619,10 @@ class inhfd_test: def getropts(self): (self.__my_file, self.__peer_file) = self.__fdtyp.create_fds() - return ["--restore-sibling", "--inherit-fd", "fd[%d]:%s" % (self.__peer_file.fileno(), self.__peer_file_name)] + fd = self.__peer_file.fileno() + fdflags = fcntl.fcntl(fd, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC + fcntl.fcntl(fd, fcntl.F_SETFD, fdflags) + return ["--restore-sibling", "--inherit-fd", "fd[%d]:%s" % (fd, self.__peer_file_name)] def print_output(self): pass @@ -695,7 +707,8 @@ class criu_cli: print("Forcing %s fault" % fault) env['CRIU_FAULT'] = fault - cr = subprocess.Popen(strace + [criu_bin, action] + args, env = env, preexec_fn = preexec) + cr = subprocess.Popen(strace + [criu_bin, action] + args, env = env, + close_fds = False, preexec_fn = preexec) if nowait: return cr return cr.wait() @@ -745,7 +758,7 @@ class criu_rpc: continue if arg == '--status-fd': fd = int(args.pop(0)) - os.write(fd, "\0") + os.write(fd, b"\0") fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC) continue if arg == '--port': @@ -932,7 +945,10 @@ class criu: status_fds = None if nowait: status_fds = os.pipe() - s_args += ["--status-fd", str(status_fds[1])] + fd = status_fds[1] + fdflags = fcntl.fcntl(fd, fcntl.F_GETFD) + fcntl.fcntl(fd, fcntl.F_SETFD, fdflags & ~fcntl.FD_CLOEXEC) + s_args += ["--status-fd", str(fd)] ns_last_pid = open("/proc/sys/kernel/ns_last_pid").read() @@ -940,7 +956,7 @@ class criu: if nowait: os.close(status_fds[1]) - if os.read(status_fds[0], 1) != '\0': + if os.read(status_fds[0], 1) != b'\0': ret = ret.wait() raise test_fail_exc("criu %s exited with %s" % (action, ret)) os.close(status_fds[0]) From ece55818e33b75d1a93f6a840fe62838baf6fe78 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:02:53 +0300 Subject: [PATCH 1491/4375] test: import pycriu by its right name Otherwise one library will be imported twice by two different names: py and pycriu, because pycriu is used in the library. https://github.com/checkpoint-restore/criu/issues/495 Signed-off-by: Andrei Vagin --- test/crit-recode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/crit-recode.py b/test/crit-recode.py index 27cc61550..0d4b31777 100755 --- a/test/crit-recode.py +++ b/test/crit-recode.py @@ -1,6 +1,6 @@ #!/bin/env python2 -import py as pycriu +import pycriu import sys import os import subprocess From 841edaf3175557de99bf965055a30a6871260e24 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:02:54 +0300 Subject: [PATCH 1492/4375] lib: a few fixes to be compatible with python3 All these issues was found by running test/crit-recode.py https://github.com/checkpoint-restore/criu/issues/495 v2: drop FD_CLOEXEC for swrk descriptors Signed-off-by: Andrei Vagin --- lib/py/criu.py | 2 ++ lib/py/images/images.py | 41 ++++++++++++++++++--------------- lib/py/images/pb2dict.py | 24 +++++++++---------- scripts/build/Dockerfile.centos | 1 + 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/lib/py/criu.py b/lib/py/criu.py index 85c7c07f8..9465eefa2 100644 --- a/lib/py/criu.py +++ b/lib/py/criu.py @@ -85,6 +85,8 @@ class _criu_comm_bin(_criu_comm): css = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) flags = fcntl.fcntl(css[1], fcntl.F_GETFD) fcntl.fcntl(css[1], fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC) + flags = fcntl.fcntl(css[0], fcntl.F_GETFD) + fcntl.fcntl(css[0], fcntl.F_SETFD, flags & ~fcntl.FD_CLOEXEC) self.daemon = daemon diff --git a/lib/py/images/images.py b/lib/py/images/images.py index c17b76f0e..67ec0b554 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -38,6 +38,7 @@ # } # import io +import base64 import google import struct import os @@ -49,6 +50,10 @@ import array from . import magic from .pb import * +if "encodebytes" not in dir(base64): + base64.encodebytes = base64.encodestring + base64.decodebytes = base64.decodestring + # # Predefined hardcoded constants sizeof_u16 = 2 @@ -185,7 +190,7 @@ class pagemap_handler: pb = pagemap_head() while True: buf = f.read(4) - if buf == '': + if buf == b'': break size, = struct.unpack('i', buf) pb.ParseFromString(f.read(size)) @@ -242,13 +247,13 @@ class ghost_file_handler: if no_payload: f.seek(gc.len, os.SEEK_CUR) else: - entry['extra'] = f.read(gc.len).encode('base64') + entry['extra'] = base64.encodebytes(f.read(gc.len)) entries.append(entry) else: if no_payload: f.seek(0, os.SEEK_END) else: - g_entry['extra'] = f.read().encode('base64') + g_entry['extra'] = base64.encodebytes(f.read()) entries.append(g_entry) return entries @@ -274,9 +279,9 @@ class ghost_file_handler: size = len(pb_str) f.write(struct.pack('i', size)) f.write(pb_str) - f.write(item['extra'].decode('base64')) + f.write(base64.decodebytes(item['extra'])) else: - f.write(item['extra'].decode('base64')) + f.write(base64.decodebytes(item['extra'])) def dumps(self, entries): f = io.BytesIO('') @@ -294,10 +299,10 @@ class pipes_data_extra_handler: def load(self, f, pload): size = pload.bytes data = f.read(size) - return data.encode('base64') + return base64.encodebytes(data) def dump(self, extra, f, pload): - data = extra.decode('base64') + data = base64.decodebytes(extra) f.write(data) def skip(self, f, pload): @@ -308,10 +313,10 @@ class sk_queues_extra_handler: def load(self, f, pload): size = pload.length data = f.read(size) - return data.encode('base64') + return base64.encodebytes(data) def dump(self, extra, f, pb): - data = extra.decode('base64') + data = base64.decodebytes(extra) f.write(data) def skip(self, f, pload): @@ -326,14 +331,14 @@ class tcp_stream_extra_handler: inq = f.read(pb.inq_len) outq = f.read(pb.outq_len) - d['inq'] = inq.encode('base64') - d['outq'] = outq.encode('base64') + d['inq'] = base64.encodebytes(inq) + d['outq'] = base64.encodebytes(outq) return d def dump(self, extra, f, pb): - inq = extra['inq'].decode('base64') - outq = extra['outq'].decode('base64') + inq = base64.decodebytes(extra['inq']) + outq = base64.decodebytes(extra['outq']) f.write(inq) f.write(outq) @@ -388,7 +393,7 @@ class ipc_msg_queue_handler: data = f.read(msg.msize) f.seek(rounded - msg.msize, 1) messages.append(pb2dict.pb2dict(msg)) - messages.append(data.encode('base64')) + base64.encodebytes(messages.append(data)) return messages def dump(self, extra, f, pb): @@ -401,7 +406,7 @@ class ipc_msg_queue_handler: f.write(struct.pack('i', size)) f.write(msg_str) rounded = round_up(msg.msize, sizeof_u64) - data = extra[i + 1].decode('base64') + data = base64.decodebytes(extra[i + 1]) f.write(data[:msg.msize]) f.write('\0' * (rounded - msg.msize)) @@ -428,12 +433,12 @@ class ipc_shm_handler: data = f.read(size) rounded = round_up(size, sizeof_u32) f.seek(rounded - size, 1) - return data.encode('base64') + return base64.encodebytes(data) def dump(self, extra, f, pb): entry = pb2dict.pb2dict(pb) size = entry['size'] - data = extra.decode('base64') + data = base64.decodebytes(extra) rounded = round_up(size, sizeof_u32) f.write(data[:size]) f.write('\0' * (rounded - size)) @@ -588,6 +593,6 @@ def dumps(img): Same as dump(), but takes only an image and returns a string. """ - f = io.BytesIO('') + f = io.BytesIO(b'') dump(img, f) return f.getvalue() diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index d99f3e13c..df0357bdd 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -1,12 +1,10 @@ from google.protobuf.descriptor import FieldDescriptor as FD import opts_pb2 -from builtins import str -from past.builtins import long -from ipaddress import IPv4Address +from ipaddress import IPv4Address, ip_address from ipaddress import IPv6Address import socket import collections -import os +import os, six # pb2dict and dict2pb are methods to convert pb to/from dict. # Inspired by: @@ -27,14 +25,14 @@ import os _basic_cast = { - FD.TYPE_FIXED64 : long, + FD.TYPE_FIXED64 : int, FD.TYPE_FIXED32 : int, - FD.TYPE_SFIXED64 : long, + FD.TYPE_SFIXED64 : int, FD.TYPE_SFIXED32 : int, - FD.TYPE_INT64 : long, - FD.TYPE_UINT64 : long, - FD.TYPE_SINT64 : long, + FD.TYPE_INT64 : int, + FD.TYPE_UINT64 : int, + FD.TYPE_SINT64 : int, FD.TYPE_INT32 : int, FD.TYPE_UINT32 : int, @@ -218,7 +216,7 @@ def get_bytes_dec(field): return decode_base64 def is_string(value): - return isinstance(value, str) + return isinstance(value, six.string_types) def _pb2dict_cast(field, value, pretty = False, is_hex = False): if not is_hex: @@ -232,7 +230,7 @@ def _pb2dict_cast(field, value, pretty = False, is_hex = False): return field.enum_type.values_by_number.get(value, None).name elif field.type in _basic_cast: cast = _basic_cast[field.type] - if pretty and (cast == int or cast == long): + if pretty and (cast == int): if is_hex: # Fields that have (criu).hex = true option set # should be stored in hex string format. @@ -298,7 +296,7 @@ def _dict2pb_cast(field, value): return field.enum_type.values_by_name.get(value, None).number elif field.type in _basic_cast: cast = _basic_cast[field.type] - if (cast == int or cast == long) and is_string(value): + if (cast == int) and is_string(value): if _marked_as_dev(field): return encode_dev(field, value) @@ -338,7 +336,7 @@ def dict2pb(d, pb): if field.label == FD.LABEL_REPEATED: pb_val = getattr(pb, field.name, None) if is_string(value[0]) and _marked_as_ip(field): - val = ipaddr.IPAddress(value[0]) + val = ip_address(value[0]) if val.version == 4: pb_val.append(socket.htonl(int(val))) elif val.version == 6: diff --git a/scripts/build/Dockerfile.centos b/scripts/build/Dockerfile.centos index 75f0ed461..379a84596 100644 --- a/scripts/build/Dockerfile.centos +++ b/scripts/build/Dockerfile.centos @@ -25,6 +25,7 @@ RUN yum install -y \ python-ipaddress \ python2-future \ python-yaml \ + python-six \ tar \ which From 33b6cff41f5e2f922064a255a37f05c2d9190038 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:02:55 +0300 Subject: [PATCH 1493/4375] test: make crit-recode.py python2/python3 compatible Signed-off-by: Andrei Vagin --- test/crit-recode.py | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/test/crit-recode.py b/test/crit-recode.py index 0d4b31777..0cb3341d3 100755 --- a/test/crit-recode.py +++ b/test/crit-recode.py @@ -1,9 +1,11 @@ -#!/bin/env python2 +#!/usr/bin/env python +# vim: noet ts=8 sw=8 sts=8 import pycriu import sys import os import subprocess +import json find = subprocess.Popen(['find', 'test/dump/', '-size', '+0', '-name', '*.img'], stdout = subprocess.PIPE) @@ -14,20 +16,21 @@ def recode_and_check(imgf, o_img, pretty): try: pb = pycriu.images.loads(o_img, pretty) except pycriu.images.MagicException as me: - print "%s magic %x error" % (imgf, me.magic) + print("%s magic %x error" % (imgf, me.magic)) return False - except: - print "%s %sdecode fails" % (imgf, pretty and 'pretty ' or '') + except Exception as e: + print("%s %sdecode fails: %s" % (imgf, pretty and 'pretty ' or '', e)) return False try: r_img = pycriu.images.dumps(pb) - except: - print "%s %sencode fails" % (imgf, pretty and 'pretty ' or '') + except Exception as e: + r_img = pycriu.images.dumps(pb) + print("%s %s encode fails: %s" % (imgf, pretty and 'pretty ' or '', e)) return False if o_img != r_img: - print "%s %srecode mismatch" % (imgf, pretty and 'pretty ' or '') + print("%s %s recode mismatch" % (imgf, pretty and 'pretty ' or '')) return False return True @@ -37,28 +40,28 @@ for imgf in find.stdout.readlines(): imgf = imgf.strip() imgf_b = os.path.basename(imgf) - if imgf_b.startswith('pages-'): + if imgf_b.startswith(b'pages-'): continue - if imgf_b.startswith('iptables-'): + if imgf_b.startswith(b'iptables-'): continue - if imgf_b.startswith('ip6tables-'): + if imgf_b.startswith(b'ip6tables-'): continue - if imgf_b.startswith('route-'): + if imgf_b.startswith(b'route-'): continue - if imgf_b.startswith('route6-'): + if imgf_b.startswith(b'route6-'): continue - if imgf_b.startswith('ifaddr-'): + if imgf_b.startswith(b'ifaddr-'): continue - if imgf_b.startswith('tmpfs-'): + if imgf_b.startswith(b'tmpfs-'): continue - if imgf_b.startswith('netns-ct-'): + if imgf_b.startswith(b'netns-ct-'): continue - if imgf_b.startswith('netns-exp-'): + if imgf_b.startswith(b'netns-exp-'): continue - if imgf_b.startswith('rule-'): + if imgf_b.startswith(b'rule-'): continue - o_img = open(imgf).read() + o_img = open(imgf.decode(), "rb").read() if not recode_and_check(imgf, o_img, False): test_pass = False if not recode_and_check(imgf, o_img, True): @@ -67,7 +70,7 @@ for imgf in find.stdout.readlines(): find.wait() if not test_pass: - print "FAIL" + print("FAIL") sys.exit(1) -print "PASS" +print("PASS") From 0e05bdfe2732685fcc0a39424b80b88368cb86b0 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:02:56 +0300 Subject: [PATCH 1494/4375] travis: run the crit-recode test Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index c642ae099..7b59d5ab9 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -130,6 +130,9 @@ ip net add test ./test/zdtm.py run --empty-ns -T zdtm/static/socket-tcp*-local --iter 2 +./test/zdtm.py run -t zdtm/static/env00 -k always +./test/crit-recode.py + make -C test/others/shell-job pip install flake8 From 8afa426d1864718a42643d71b086825556dd69ea Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:02:57 +0300 Subject: [PATCH 1495/4375] alpine: call write instead of fprintf fprintf in Alpine Linux calls writev, which is prohibited in the SECCOMP_MODE_STRICT mode. ===================== Run zdtm/static/seccomp_strict in h ====================== Start test Test is SUID ./seccomp_strict --pidfile=seccomp_strict.pid --outfile=seccomp_strict.out make: *** [Makefile:385: seccomp_strict.pid] Error 1 Test zdtm/static/seccomp_strict FAIL at start: [Errno 2] No such file or directory: 'zdtm/static/seccomp_strict.pid' Test output: ================================ 22:45:24.661: 38: ERR: seccomp_strict.c:97: read (errno = 2 (No such file or directory)) 22:45:24.662: 37: ERR: test.c:315: Test exited unexpectedly with code 1 Signed-off-by: Andrei Vagin --- test/zdtm/lib/msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/lib/msg.c b/test/zdtm/lib/msg.c index 7b8d74dc4..04cd40167 100644 --- a/test/zdtm/lib/msg.c +++ b/test/zdtm/lib/msg.c @@ -64,6 +64,6 @@ skip: off += vsnprintf(buf + off, sizeof(buf) - off, format, arg); va_end(arg); - fprintf(stderr, "%s", buf); + write(2, buf, off); errno = __errno; } From e57fd31f8b922bf7ae50deba386cfc3a1f1ac28c Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:02:58 +0300 Subject: [PATCH 1496/4375] criu: musl scanf and printf don't support the L modifer for intergers Signed-off-by: Andrei Vagin --- criu/fsnotify.c | 2 +- criu/proc_parse.c | 2 +- criu/signalfd.c | 2 +- criu/uffd.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 73dae3938..001f006bb 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -203,7 +203,7 @@ static int open_handle(unsigned int s_dev, unsigned long i_ino, decode_handle(&handle, f_handle); - pr_debug("Opening fhandle %x:%Lx...\n", + pr_debug("Opening fhandle %x:%llx...\n", s_dev, (unsigned long long)handle.__handle[0]); for (m = mntinfo; m; m = m->next) { diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 79af2e36f..5e1f8529d 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1782,7 +1782,7 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, void *arg) if (type != FD_TYPES__SIGNALFD) goto parse_err; - ret = sscanf(str, "sigmask: %Lx", + ret = sscanf(str, "sigmask: %llx", (unsigned long long *)&sfd->sigmask); if (ret != 1) goto parse_err; diff --git a/criu/signalfd.c b/criu/signalfd.c index bd117a3e0..1bb87d08c 100644 --- a/criu/signalfd.c +++ b/criu/signalfd.c @@ -52,7 +52,7 @@ static void sigset_fill(sigset_t *to, unsigned long long from) { int sig; - pr_info("\tCalculating sigmask for %Lx\n", from); + pr_info("\tCalculating sigmask for %llx\n", from); sigemptyset(to); for (sig = 1; sig < NSIG; sig++) if (from & (1ULL << (sig - 1))) { diff --git a/criu/uffd.c b/criu/uffd.c index 114118098..4a62ab4c1 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1031,7 +1031,7 @@ static int handle_remove(struct lazy_pages_info *lpi, struct uffd_msg *msg) unreg.start = msg->arg.remove.start; unreg.len = msg->arg.remove.end - msg->arg.remove.start; - lp_debug(lpi, "%s: %Lx(%Lx)\n", + lp_debug(lpi, "%s: %llx(%llx)\n", msg->event == UFFD_EVENT_REMOVE ? "REMOVE" : "UNMAP", unreg.start, unreg.len); From 8fc954ab63cb1b48b01020181800d14ea4fd4334 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:02:59 +0300 Subject: [PATCH 1497/4375] alpine: sigaltstack returns EINVAL if SS_ONSTACK is set Actually this flag is ignored by kernel. Signed-off-by: Andrei Vagin --- test/zdtm/static/sigaltstack.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/zdtm/static/sigaltstack.c b/test/zdtm/static/sigaltstack.c index 3ccd18277..d324b0d37 100644 --- a/test/zdtm/static/sigaltstack.c +++ b/test/zdtm/static/sigaltstack.c @@ -64,7 +64,7 @@ static void *thread_func(void *arg) sas_state[SAS_THRD_OLD] = (stack_t) { .ss_size = sizeof(stack_thread) - 8, .ss_sp = stack_thread, - .ss_flags = SS_ONSTACK, + .ss_flags = 0, }; struct sigaction sa = { @@ -106,7 +106,7 @@ int main(int argc, char *argv[]) sas_state[SAS_MAIN_OLD] = (stack_t) { .ss_size = sizeof(stack_main) - 8, .ss_sp = stack_main, - .ss_flags = SS_ONSTACK, + .ss_flags = 0, }; struct sigaction sa = { @@ -151,6 +151,9 @@ int main(int argc, char *argv[]) } task_waiter_fini(&t); + sas_state[SAS_THRD_OLD].ss_flags = SS_ONSTACK; + sas_state[SAS_MAIN_OLD].ss_flags = SS_ONSTACK; + show_ss("main old", &sas_state[SAS_MAIN_OLD]); show_ss("main new", &sas_state[SAS_MAIN_NEW]); show_ss("thrd old", &sas_state[SAS_THRD_OLD]); From 5604ccbe6091e50201ac3a28d83468aa0b01feaa Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:03:00 +0300 Subject: [PATCH 1498/4375] build/docker: install packages to run tests Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.alpine | 7 +++++-- scripts/build/Dockerfile.centos | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index 21647e1e1..c35104c64 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -31,7 +31,10 @@ RUN apk add \ iptables \ iproute2 \ tar \ - bash + bash \ + go \ + e2fsprogs \ + asciidoc xmlto -RUN pip install protobuf ipaddress +RUN pip install protobuf ipaddress junit_xml RUN make -C test/zdtm diff --git a/scripts/build/Dockerfile.centos b/scripts/build/Dockerfile.centos index 379a84596..5f8470773 100644 --- a/scripts/build/Dockerfile.centos +++ b/scripts/build/Dockerfile.centos @@ -24,10 +24,14 @@ RUN yum install -y \ python \ python-ipaddress \ python2-future \ + python2-junit_xml \ python-yaml \ python-six \ tar \ - which + which \ + e2fsprogs \ + python2-pip \ + asciidoc xmlto COPY . /criu WORKDIR /criu From 6c169c5173c9fed20b38830990c4ec0c62beffdb Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:03:01 +0300 Subject: [PATCH 1499/4375] test: don't save content of /sys/kernel/debug/tracing/trace We don't tune tracers, so we don't expect to get anything. In docker containers, debugfs isn't mounted and this command failed. Signed-off-by: Andrei Vagin --- test/jenkins/criu-lib.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jenkins/criu-lib.sh b/test/jenkins/criu-lib.sh index 138066943..72d41b57d 100644 --- a/test/jenkins/criu-lib.sh +++ b/test/jenkins/criu-lib.sh @@ -33,9 +33,9 @@ function mount_tmpfs_to_dump() function fail() { + set +e uname -a - ps axf > ps.log - cat /sys/kernel/debug/tracing/trace > trace.log + ps axf --width 256 > ps.log tar -czf /home/`basename $0`-${BUILD_NUMBER}-${GIT_COMMIT}-$(date +%m%d%H%M).tar.gz . tar -czf report.tar.gz -C test/ report exit 1 From 195ef99187cfef61010dc60e1607b7b82239f767 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:03:02 +0300 Subject: [PATCH 1500/4375] zdtm: fix collecting libraries on Alpine Linux Here is an example of ldd output: /musl # ldd /usr/lib/libxtables.so.12 ldd (0x7fae8e06c000) libc.musl-x86_64.so.1 => ldd (0x7fae8e06c000) We need to skip the "ldd (0x7fae8e06c000)" line. Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 9bcdc8fc0..389ab99ab 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -183,7 +183,7 @@ class ns_flavor: def __copy_libs(self, binary): ldd = subprocess.Popen(["ldd", binary], stdout = subprocess.PIPE) - xl = re.compile('^(linux-gate.so|linux-vdso(64)?.so|not a dynamic)') + xl = re.compile('^(linux-gate.so|linux-vdso(64)?.so|not a dynamic|.*\s*ldd\s)') # This Mayakovsky-style code gets list of libraries a binary # needs minus vdso and gate .so-s From 4f9780946a7dd7fe8331747c16686f18caf722cc Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:03:03 +0300 Subject: [PATCH 1501/4375] test/netns-nf: add one more path for libxt_standard.so On Alpine Linux, libxt_standard.so is installed in /usr/lib/xtables/ Signed-off-by: Andrei Vagin --- test/zdtm/static/netns-nf.desc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/netns-nf.desc b/test/zdtm/static/netns-nf.desc index 618e256e6..496477aa7 100644 --- a/test/zdtm/static/netns-nf.desc +++ b/test/zdtm/static/netns-nf.desc @@ -1,6 +1,6 @@ { 'deps': [ '/bin/sh', '/sbin/iptables', - '/usr/lib64/xtables/libxt_standard.so|/usr/lib/iptables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so|/usr/lib/s390x-linux-gnu/xtables/libxt_standard.so', + '/usr/lib64/xtables/libxt_standard.so|/usr/lib/iptables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so|/usr/lib/s390x-linux-gnu/xtables/libxt_standard.so|/usr/lib/xtables/libxt_standard.so', '/usr/bin/diff'], 'flags': 'suid', 'flavor': 'ns uns'} From d76ddb5e83cab08a58eabd2aca49115da1d6e2df Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:03:04 +0300 Subject: [PATCH 1502/4375] test: run a full set of tests in docker containers Signed-off-by: Andrei Vagin --- scripts/travis/Makefile | 8 +++++++- scripts/travis/docker.env | 4 ++++ scripts/travis/travis-tests | 10 ++++++---- 3 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 scripts/travis/docker.env diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index badcb4dd2..1b2858280 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -11,12 +11,18 @@ ifdef CLANG target-suffix = -clang endif -TARGETS := fedora-asan alpine fedora-rawhide centos +TARGETS := alpine fedora-rawhide centos ZDTM_OPTIONS := alpine: ZDTM_OPTIONS=-x zdtm/static/binfmt_misc -x zdtm/static/netns-nf -x zdtm/static/sched_policy00 -x zdtm/static/seccomp_strict -x zdtm/static/sigaltstack -x zdtm/static/signalfd00 -x zdtm/static/config_inotify_irmap $(TARGETS): + echo 'DOCKER_OPTS="--storage-driver=devicemapper"' > /etc/default/docker + restart docker + $(MAKE) -C ../build $@$(target-suffix) + docker run --env-file docker.env --rm -it --privileged -v /lib/modules:/lib/modules --tmpfs /run criu-$@ scripts/travis/travis-tests + +fedora-asan: echo 'DOCKER_OPTS="--storage-driver=devicemapper"' > /etc/default/docker restart docker $(MAKE) -C ../build $@$(target-suffix) diff --git a/scripts/travis/docker.env b/scripts/travis/docker.env new file mode 100644 index 000000000..36154df0d --- /dev/null +++ b/scripts/travis/docker.env @@ -0,0 +1,4 @@ +SKIP_TRAVIS_PREP=1 +ZDTM_OPTS=-x zdtm/static/binfmt_misc -x zdtm/static/sched_policy00 +CC=gcc +SKIP_EXT_DEV_TEST=1 diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 7b59d5ab9..c8bd5717e 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -84,7 +84,7 @@ chmod 0777 test/ chmod 0777 test/zdtm/static chmod 0777 test/zdtm/transition -./test/zdtm.py run -a -p 2 +./test/zdtm.py run -a -p 2 --keep-going $ZDTM_OPTS KERN_MAJ=`uname -r | cut -d. -f1` KERN_MIN=`uname -r | cut -d. -f2` @@ -99,14 +99,16 @@ LAZY_EXCLUDE="$LAZY_EXCLUDE -x maps04" LAZY_TESTS=.*\(maps0\|uffd-events\|lazy-thp\|futex\|fork\).* -./test/zdtm.py run -p 2 -T $LAZY_TESTS --lazy-pages $LAZY_EXCLUDE -./test/zdtm.py run -p 2 -T $LAZY_TESTS --remote-lazy-pages $LAZY_EXCLUDE +./test/zdtm.py run -p 2 -T $LAZY_TESTS --lazy-pages $LAZY_EXCLUDE $ZDTM_OPTS +./test/zdtm.py run -p 2 -T $LAZY_TESTS --remote-lazy-pages $LAZY_EXCLUDE $ZDTM_OPTS bash ./test/jenkins/criu-fault.sh bash ./test/jenkins/criu-fcg.sh bash ./test/jenkins/criu-inhfd.sh -make -C test/others/mnt-ext-dev/ run +if [ -z "$SKIP_EXT_DEV_TEST" ]; then + make -C test/others/mnt-ext-dev/ run +fi #make -C test/others/exec/ run make -C test/others/make/ run CC="$CC" make -C test/others/shell-job/ run From 7e5e1ff29a99769faf224251d0300fa83944e1ad Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 4 Jun 2018 07:43:21 +0100 Subject: [PATCH 1503/4375] test: Don't leak file descriptor Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- test/inhfd/fifo.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/inhfd/fifo.py b/test/inhfd/fifo.py index aabc89034..11703e1c0 100755 --- a/test/inhfd/fifo.py +++ b/test/inhfd/fifo.py @@ -14,14 +14,14 @@ def create_fds(): os.rmdir(tdir) mnt_id = -1; - f = open("/proc/self/fdinfo/%d" % fd1.fileno()) - for l in f: - l = l.split() - if l[0] == "mnt_id:": - mnt_id = int(l[1]) - break - else: - raise Exception("Unable to find mnt_id") + with open("/proc/self/fdinfo/%d" % fd1.fileno()) as f: + for l in f: + l = l.split() + if l[0] == "mnt_id:": + mnt_id = int(l[1]) + break + else: + raise Exception("Unable to find mnt_id") global id_str id_str = "file[%x:%x]" % (mnt_id, os.fstat(fd1.fileno()).st_ino) From a7cc23c0f55b8bc1cefe3e8f816e0eb6cf29aa91 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 9 Jun 2018 20:30:48 +0300 Subject: [PATCH 1504/4375] zdtm: open notify file descriptors in a binary mode Send pre-dump notify to 36 Traceback (most recent call last): File "zdtm.py", line 2161, in do_run_test(tinfo[0], tinfo[1], tinfo[2], tinfo[3]) File "zdtm.py", line 1549, in do_run_test cr(cr_api, t, opts) File "zdtm.py", line 1264, in cr test.pre_dump_notify() File "zdtm.py", line 490, in pre_dump_notify fdin.write(struct.pack("i", 0)) TypeError: write() argument 1 must be unicode, not str Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 389ab99ab..d67880f7d 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -467,7 +467,7 @@ class zdtm_test: print_sep(self.__name + '.out.inprogress') print(open(self.__name + '.out.inprogress').read()) print_sep(self.__name + '.out.inprogress') - raise test_fail_exc("result check: %s" % list(map(lambda s: s.strip(), res.split())) + res) + raise test_fail_exc("result check") def getpid(self): if self.__pid == 0: From 7e0bef54a516ae74648a5b8fd0753d998a153c16 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 13 Jun 2018 12:12:29 +0000 Subject: [PATCH 1505/4375] zdtm/lib: Check EWOULDBLOCK in errno instead of -EWOULDBLOCK Syscalls do return negative value in case of an error. But errno contains the error code itself. Add uint32_t to sys_futex() definition. sizeof(unsigned int) might be not 4 bytes. Signed-off-by: Dmitry Safonov Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/zdtm/lib/lock.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/zdtm/lib/lock.h b/test/zdtm/lib/lock.h index 972ed5769..9c0831d46 100644 --- a/test/zdtm/lib/lock.h +++ b/test/zdtm/lib/lock.h @@ -23,8 +23,8 @@ typedef struct { #define FUTEX_ABORT_FLAG (0x80000000) #define FUTEX_ABORT_RAW (-1U) -static inline int sys_futex(unsigned int *uaddr, int op, unsigned int val, const struct timespec *timeout, - int *uaddr2, unsigned int val3) +static inline int sys_futex(uint32_t *uaddr, int op, uint32_t val, const struct timespec *timeout, + uint32_t *uaddr2, uint32_t val3) { return syscall(__NR_futex, uaddr, op, val, timeout, uaddr2, val3); } @@ -142,11 +142,11 @@ static void inline mutex_lock(mutex_t *m) uint32_t c; int ret; - while ((c = atomic_inc(&m->raw))) { + while ((c = atomic_inc(&m->raw)) != 0) { ret = sys_futex(&m->raw, FUTEX_WAIT, c + 1, NULL, NULL, 0); if (ret < 0) pr_perror("futex"); - BUG_ON(ret < 0 && errno != -EWOULDBLOCK); + BUG_ON(ret < 0 && errno != EWOULDBLOCK); } } From 19de949023af871846b9b51450b53ad12c40fb1e Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 13 Jun 2018 12:12:30 +0000 Subject: [PATCH 1506/4375] zdtm: fix atomic_{sub, add}_return assembler for aarch64 Running the test suite on aarch64 showed two tests failing (static/fd and transition/maps0007). Debugging showed that the atomic_{sub,add}_return() functions did not return the value but the lower 32bit of the address of that value. Simply dereferencing the input solves the two mentioned test cases. Signed-off-by: Dmitry Safonov Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/zdtm/lib/arch/aarch64/include/asm/atomic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/zdtm/lib/arch/aarch64/include/asm/atomic.h b/test/zdtm/lib/arch/aarch64/include/asm/atomic.h index ccf08e700..ddf4ad9f6 100644 --- a/test/zdtm/lib/arch/aarch64/include/asm/atomic.h +++ b/test/zdtm/lib/arch/aarch64/include/asm/atomic.h @@ -33,7 +33,7 @@ static inline int atomic_add_return(int i, atomic_t *v) " add %w0, %w0, %w3\n" " stlxr %w1, %w0, %2\n" " cbnz %w1, 1b" - : "=&r" (result), "=&r" (tmp), "+Q" (v) + : "=&r" (result), "=&r" (tmp), "+Q" (*v) : "Ir" (i) : "cc", "memory"); @@ -51,7 +51,7 @@ static inline int atomic_sub_return(int i, atomic_t *v) " sub %w0, %w0, %w3\n" " stlxr %w1, %w0, %2\n" " cbnz %w1, 1b" - : "=&r" (result), "=&r" (tmp), "+Q" (v) + : "=&r" (result), "=&r" (tmp), "+Q" (*v) : "Ir" (i) : "cc", "memory"); From 9462f2aed79b4ab64b5dcbf6ee851d9c10d705b1 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 12 Jun 2018 23:50:54 +0300 Subject: [PATCH 1507/4375] crit: typo fix test/dump/zdtm/static/msgque/43/1/ipcns-msg-12.img decode fails: object of type 'NoneType' has no len() Signed-off-by: Andrei Vagin --- lib/py/images/images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/py/images/images.py b/lib/py/images/images.py index 67ec0b554..68f983880 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -393,7 +393,7 @@ class ipc_msg_queue_handler: data = f.read(msg.msize) f.seek(rounded - msg.msize, 1) messages.append(pb2dict.pb2dict(msg)) - base64.encodebytes(messages.append(data)) + messages.append(base64.encodebytes(data)) return messages def dump(self, extra, f, pb): From a58ecb38aa3ccf7853ae1e9a4b710970b8e83750 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 13 Jun 2018 23:57:13 +0100 Subject: [PATCH 1508/4375] tun/kerndat: Keep going with CONFIG_TUN=n check_tun_netns_cr() should return 0 on CONFIG_TUN=n kernels. That is, when we fail to open tun device. Fixes: #496 Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/tun.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/criu/tun.c b/criu/tun.c index 8aa61e89a..1e5cba7c4 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -74,17 +74,18 @@ int check_tun_cr(int no_tun_err) int check_tun_netns_cr(bool *result) { - bool val; + bool val = false; int tun; tun = open(TUN_DEV_GEN_PATH, O_RDONLY); if (tun < 0) { pr_perror("Unable to create tun"); - return -1; + goto out; } check_has_netns_ioc(tun, &val, "tun"); close(tun); +out: if (result) *result = val; From 2899d58fc218493b697ab2139e7d221022758962 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 13 Jun 2018 19:22:28 +0000 Subject: [PATCH 1509/4375] test/zdtm.py: add option to specify external criu for test suite I am regularly running zdtm.py after updating the CRIU rpm to test if the new rpm still works. Until know I usually did: -criu_bin = "../criu/criu" -crit_bin = "../crit/crit" +criu_bin = "/usr/sbin/criu" +crit_bin = "/usr/bin/crit" This commit adds two arguments to zdtm.py: --criu-bin CRIU_BIN Path to criu binary --crit-bin CRIT_BIN Path to crit binary It still defaults to the old values from above, but can now easily be changed to the CRIU binary provided by the packaging system. This change was more complicated than expected which is probably related to the fact that zdtm restarts itself in namespaces. v2: - rebase v3: - fix errors reported by 'make lint' Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/zdtm.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index d67880f7d..fe723c893 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -693,14 +693,12 @@ test_classes = {'zdtm': zdtm_test, 'inhfd': inhfd_test, 'groups': groups_test} # CRIU when launched using CLI # -criu_bin = "../criu/criu" -crit_bin = "../crit/crit" join_ns_file = '/run/netns/zdtm_netns' class criu_cli: @staticmethod - def run(action, args, fault = None, strace = [], preexec = None, nowait = False): + def run(action, args, criu_bin, fault = None, strace = [], preexec = None, nowait = False): env = dict(os.environ, ASAN_OPTIONS = "log_path=asan.log:disable_coredump=0:detect_leaks=0") if fault: @@ -782,7 +780,7 @@ class criu_rpc: raise test_fail_exc('RPC for %s required' % arg) @staticmethod - def run(action, args, fault = None, strace = [], preexec = None, nowait = False): + def run(action, args, criu_bin, fault = None, strace = [], preexec = None, nowait = False): if fault: raise test_fail_exc('RPC and FAULT not supported') if strace: @@ -858,6 +856,8 @@ class criu: self.__lazy_pages_p = None self.__page_server_p = None self.__dump_process = None + self.__criu_bin = opts['criu_bin'] + self.__crit_bin = opts['crit_bin'] def fini(self): if self.__lazy_migrate: @@ -952,7 +952,7 @@ class criu: ns_last_pid = open("/proc/sys/kernel/ns_last_pid").read() - ret = self.__criu.run(action, s_args, self.__fault, strace, preexec, nowait) + ret = self.__criu.run(action, s_args, self.__criu_bin, self.__fault, strace, preexec, nowait) if nowait: os.close(status_fds[1]) @@ -979,7 +979,7 @@ class criu: open("/proc/sys/kernel/ns_last_pid", "w+").write(ns_last_pid) # try again without faults print("Run criu " + action) - ret = self.__criu.run(action, s_args, False, strace, preexec) + ret = self.__criu.run(action, s_args, self.__criu_bin, False, strace, preexec) grep_errors(os.path.join(__ddir, log)) if ret == 0: return @@ -993,7 +993,7 @@ class criu: if not self.__show_stats: return - subprocess.Popen([crit_bin, "show", + subprocess.Popen([self.__crit_bin, "show", os.path.join(self.__dump_path, str(self.__iter), "stats-%s" % action)]).wait() @@ -1097,12 +1097,13 @@ class criu: @staticmethod def check(feature): - return criu_cli.run("check", ["-v0", "--feature", feature]) == 0 + return criu_cli.run("check", ["-v0", "--feature", feature], + opts['criu_bin']) == 0 @staticmethod def available(): - if not os.access(criu_bin, os.X_OK): - print("CRIU binary not built") + if not os.access(opts['criu_bin'], os.X_OK): + print("CRIU binary not found at %s" % opts['criu_bin']) sys.exit(1) def kill(self): @@ -1574,7 +1575,8 @@ class Launcher: nd = ('nocr', 'norst', 'pre', 'iters', 'page_server', 'sibling', 'stop', 'empty_ns', 'fault', 'keep_img', 'report', 'snaps', 'sat', 'script', 'rpc', 'lazy_pages', 'join_ns', 'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup', - 'remote_lazy_pages', 'show_stats', 'lazy_migrate') + 'remote_lazy_pages', 'show_stats', 'lazy_migrate', + 'criu_bin', 'crit_bin') arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd})) if self.__use_log: @@ -2116,6 +2118,8 @@ rp.add_argument("--lazy-migrate", help = "restore pages on demand", action = 'st rp.add_argument("--remote-lazy-pages", help = "simulate lazy migration", action = 'store_true') rp.add_argument("--title", help = "A test suite title", default = "criu") rp.add_argument("--show-stats", help = "Show criu statistics", action = 'store_true') +rp.add_argument("--criu-bin", help = "Path to criu binary", default = '../criu/criu') +rp.add_argument("--crit-bin", help = "Path to crit binary", default = '../crit/crit') lp = sp.add_parser("list", help = "List tests") lp.set_defaults(action = list_tests) From 5686613a6b70097f815098f5c1c8a290769640a4 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 13 Jun 2018 20:46:36 +0300 Subject: [PATCH 1510/4375] zdtm: fix a lint warning about undefined 'raw_input' test/zdtm.py:1238:3: F821 undefined name 'raw_input' v2: ask to press enter, not just any key Signed-off-by: Andrei Vagin --- test/zdtm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index fe723c893..8f396559b 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # vim: noet ts=8 sw=8 sts=8 from __future__ import absolute_import, division, print_function, unicode_literals -from builtins import (str, open, range, zip, int) +from builtins import (str, open, range, zip, int, input) import argparse import glob @@ -1150,7 +1150,7 @@ def init_sbs(): def sbs(what): if do_sbs: - raw_input("Pause at %s. Press any key to continue." % what) + input("Pause at %s. Press Enter to continue." % what) # From e5856d4a7b1eb3625ac660c04290ccc2bf433a45 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 16 May 2018 23:29:49 +0300 Subject: [PATCH 1511/4375] sfd: Don't forget to test sfd_map when closing old fds is_any_service_fd didn't check for service file descriptor being marked in sfd_map in result we may end up leaving some garbage file obtained from the program executing criu. [root@sqvm0910 criu-stable.git]# ll /proc/354877/fd lr-x------ 1 root root 64 May 16 19:03 114 -> / lr-x------ 1 root root 64 May 16 19:03 115 -> / l--------- 1 root root 64 May 16 19:03 117 -> /18311 (deleted) lr-x------ 1 root root 64 May 16 19:03 119 -> /vzt/del/vzctl-rm-me.X1JH4vI (deleted) We are to test if the file descriptor was indeed installed explicitly. https://jira.sw.ru/browse/PSBM-83892 Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/util.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/criu/util.c b/criu/util.c index cf617bed4..837e50626 100644 --- a/criu/util.c +++ b/criu/util.c @@ -636,8 +636,16 @@ int clone_service_fd(struct pstree_item *me) bool is_any_service_fd(int fd) { - return fd > __get_service_fd(SERVICE_FD_MAX, service_fd_id) && - fd < __get_service_fd(SERVICE_FD_MIN, service_fd_id); + int sfd_min_fd = __get_service_fd(SERVICE_FD_MAX, service_fd_id); + int sfd_max_fd = __get_service_fd(SERVICE_FD_MIN, service_fd_id); + + if (fd > sfd_min_fd && fd < sfd_max_fd) { + int type = SERVICE_FD_MAX - (fd - sfd_min_fd); + if (type > SERVICE_FD_MIN && type < SERVICE_FD_MAX) + return !!test_bit(type, sfd_map); + } + + return false; } bool is_service_fd(int fd, enum sfd_type type) From e2143aff7229e62a9d4dcb040bcae1d63294b8ac Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 6 Jun 2018 17:30:58 +0300 Subject: [PATCH 1512/4375] lazy-pages: uffd_{copy, zeropage}: rework error handling Improve code readability and take into account that even if uffdio_{copy,zeropage} has failed, some pages had been updated. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/uffd.c | 60 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 4a62ab4c1..2fe56b3ce 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -814,32 +814,44 @@ static int handle_exit(struct lazy_pages_info *lpi) return 0; } -static int uffd_check_op_error(struct lazy_pages_info *lpi, const char *op, - unsigned long len, unsigned long rc_len, int rc) +static bool uffd_recoverable_error(int mcopy_rc) { - if (rc) { - if (errno == ENOSPC || errno == ESRCH) { - handle_exit(lpi); - return 0; - } - if (rc_len != -EEXIST) { - lp_perror(lpi, "%s: rc:%d copy:%ld, errno:%d", - op, rc, rc_len, errno); - return -1; - } - } else if (rc_len != len) { - lp_err(lpi, "%s unexpected size %ld\n", op, rc_len); + if (errno == EAGAIN || errno == ENOENT || errno == EEXIST) + return true; + + if (mcopy_rc == -ENOENT || mcopy_rc == -EEXIST) + return true; + + return false; +} + +static int uffd_check_op_error(struct lazy_pages_info *lpi, const char *op, + int *nr_pages, long mcopy_rc) +{ + if (errno == ENOSPC || errno == ESRCH) { + handle_exit(lpi); + return 0; + } + + if (!uffd_recoverable_error(mcopy_rc)) { + lp_perror(lpi, "%s: mcopy_rc:%ld", op, mcopy_rc); return -1; } + lp_debug(lpi, "%s: mcopy_rc:%ld, errno:%d\n", op, mcopy_rc, errno); + + if (mcopy_rc <= 0) + *nr_pages = 0; + else + *nr_pages = mcopy_rc / PAGE_SIZE; + return 0; } -static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) +static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int *nr_pages) { struct uffdio_copy uffdio_copy; - unsigned long len = nr_pages * page_size(); - int rc; + unsigned long len = *nr_pages * page_size(); uffdio_copy.dst = address; uffdio_copy.src = (unsigned long)lpi->buf; @@ -848,11 +860,11 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages) uffdio_copy.copy = 0; lp_debug(lpi, "uffd_copy: 0x%llx/%ld\n", uffdio_copy.dst, len); - rc = ioctl(lpi->lpfd.fd, UFFDIO_COPY, &uffdio_copy); - if (uffd_check_op_error(lpi, "copy", len, uffdio_copy.copy, rc)) + if (ioctl(lpi->lpfd.fd, UFFDIO_COPY, &uffdio_copy) && + uffd_check_op_error(lpi, "copy", nr_pages, uffdio_copy.copy)) return -1; - lpi->copied_pages += nr_pages; + lpi->copied_pages += *nr_pages; return 0; } @@ -895,7 +907,7 @@ static int uffd_io_complete(struct page_read *pr, unsigned long img_addr, int nr req_pages = (req->end - req->start) / PAGE_SIZE; nr = min(nr, req_pages); - ret = uffd_copy(lpi, addr, nr); + ret = uffd_copy(lpi, addr, &nr); if (ret < 0) return ret; @@ -916,15 +928,15 @@ static int uffd_zero(struct lazy_pages_info *lpi, __u64 address, int nr_pages) { struct uffdio_zeropage uffdio_zeropage; unsigned long len = page_size() * nr_pages; - int rc; uffdio_zeropage.range.start = address; uffdio_zeropage.range.len = len; uffdio_zeropage.mode = 0; lp_debug(lpi, "zero page at 0x%llx\n", address); - rc = ioctl(lpi->lpfd.fd, UFFDIO_ZEROPAGE, &uffdio_zeropage); - if (uffd_check_op_error(lpi, "zero", len, uffdio_zeropage.zeropage, rc)) + if (ioctl(lpi->lpfd.fd, UFFDIO_ZEROPAGE, &uffdio_zeropage) && + uffd_check_op_error(lpi, "zero", &nr_pages, + uffdio_zeropage.zeropage)) return -1; return 0; From 8a5321d99c7ef5f65bd1357f9c650f2988315bcc Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 17 Jun 2018 06:25:03 +0300 Subject: [PATCH 1513/4375] zdtm.py: exclude a vsyscall vma for x32 tests We alwasy exclude vsyscall vma-s for x32 tests, but this part was broken by python3 patches. 1: Old maps lost: set([]) 1: New maps appeared: set([u"ffffffffff600000-ffffffffff601000 [u'r-xp']"]) Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin --- test/zdtm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 8f396559b..3e25f3369 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1236,7 +1236,7 @@ def get_visible_state(test): cmaps.append(m) last += 1 - maps[pid] = set(map(lambda x: '%x-%x %s' % (x[0], x[1], x[2:]), cmaps)) + maps[pid] = set(map(lambda x: '%x-%x %s' % (x[0], x[1], " ".join(x[2:])), cmaps)) cmounts = [] try: @@ -1265,7 +1265,7 @@ def check_visible_state(test, state, opts): new_maps = new[1][pid] if os.getenv("COMPAT_TEST"): # the vsyscall vma isn't unmapped from x32 processes - vsyscall = "ffffffffff600000-ffffffffff601000 ['r-xp']" + vsyscall = u"ffffffffff600000-ffffffffff601000 r-xp" if vsyscall in new_maps and vsyscall not in old_maps: new_maps.remove(vsyscall) if old_maps != new_maps: From d324645db58f2e5ccfb3edf61e0601bcf22f7964 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 17 Jun 2018 06:44:42 +0300 Subject: [PATCH 1514/4375] bitops: use the UL literal for constants We operate by long variables in out bit arithmetics, so our constants should be marked as long too. Cc: Adrian Reber Reported-by: Adrian Reber Signed-off-by: Andrei Vagin Tested-by: Adrian Reber Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- include/common/asm-generic/bitops.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/common/asm-generic/bitops.h b/include/common/asm-generic/bitops.h index cb449fbf8..fbd25c1b6 100644 --- a/include/common/asm-generic/bitops.h +++ b/include/common/asm-generic/bitops.h @@ -28,25 +28,25 @@ static inline void set_bit(int nr, volatile unsigned long *addr) { addr += nr / BITS_PER_LONG; - *addr |= (1 << (nr % BITS_PER_LONG)); + *addr |= (1UL << (nr % BITS_PER_LONG)); } static inline void change_bit(int nr, volatile unsigned long *addr) { addr += nr / BITS_PER_LONG; - *addr ^= (1 << (nr % BITS_PER_LONG)); + *addr ^= (1UL << (nr % BITS_PER_LONG)); } static inline int test_bit(int nr, volatile const unsigned long *addr) { addr += nr / BITS_PER_LONG; - return (*addr & (1 << (nr % BITS_PER_LONG))) ? -1 : 0; + return (*addr & (1UL << (nr % BITS_PER_LONG))) ? -1 : 0; } static inline void clear_bit(int nr, volatile unsigned long *addr) { addr += nr / BITS_PER_LONG; - *addr &= ~(1 << (nr % BITS_PER_LONG)); + *addr &= ~(1UL << (nr % BITS_PER_LONG)); } /** From 0bb02253e67c75bb3829d993b6622e9742d1fe22 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 5 Jun 2018 19:58:59 +0000 Subject: [PATCH 1515/4375] zdtm/static/maps06: removed hardcoded page-size zdtm/static/maps06 failed on systems with different page-size than 4096. This changes maps06 to use sysconf(_SC_PAGESIZE) instead. Signed-off-by: Adrian Reber Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- test/zdtm/static/maps06.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/test/zdtm/static/maps06.c b/test/zdtm/static/maps06.c index 14dd90f43..7480d6b24 100644 --- a/test/zdtm/static/maps06.c +++ b/test/zdtm/static/maps06.c @@ -10,12 +10,12 @@ const char *test_author = "Andrei Vagin "; char *filename; TEST_OPTION(filename, string, "file name", 1); -#define TEST_SIZE 10240 - int main(int argc, char ** argv) { void *start; int fd, i; + int ps = sysconf(_SC_PAGESIZE); + int test_size; test_init(argc, argv); @@ -23,21 +23,26 @@ int main(int argc, char ** argv) if (fd < 0) return 1; - ftruncate(fd, 4096); + ftruncate(fd, ps); - start = mmap(0, 4096 * TEST_SIZE * 4, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + if (ps == 0x1000) + test_size = 10240; + else + test_size = 512; + + start = mmap(0, ps * test_size * 4, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); if (start == MAP_FAILED) return 1; - for (i = 0; i < TEST_SIZE; i++) { + for (i = 0; i < test_size; i++) { int *addr; - addr = mmap(start + i * 3 * 4096, 4096, + addr = mmap(start + i * 3 * ps, ps, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FILE | MAP_FIXED, fd, 0); if (addr == MAP_FAILED) return 1; addr[0] = i * 2; - addr = mmap(start + (i * 3 + 1) * 4096, 4096, + addr = mmap(start + (i * 3 + 1) * ps, ps, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); if (addr == MAP_FAILED) @@ -49,12 +54,12 @@ int main(int argc, char ** argv) test_waitsig(); - for (i = 0; i < TEST_SIZE; i++) { + for (i = 0; i < test_size; i++) { int *addr; - addr = start + i * 3 * 4096; + addr = start + i * 3 * ps; if (addr[0] != i * 2) fail(); - addr = start + (i * 3 + 1) * 4096; + addr = start + (i * 3 + 1) * ps; if (addr[0] != i) fail(); } From f30f24a17e0ba82d41aee74e410de1f8e830ba6e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 14 Jun 2018 20:27:20 +0300 Subject: [PATCH 1516/4375] x86: Use uint_x types in rt_sigcontext To be close to the kernel code. Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- .../x86/src/lib/include/uapi/asm/sigframe.h | 56 +++++++++---------- compel/arch/x86/src/lib/infect.c | 2 +- criu/arch/x86/sigframe.c | 2 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h index 3260d9c16..0ad45a539 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h @@ -10,34 +10,34 @@ #define SIGFRAME_MAX_OFFSET 8 struct rt_sigcontext { - unsigned long r8; - unsigned long r9; - unsigned long r10; - unsigned long r11; - unsigned long r12; - unsigned long r13; - unsigned long r14; - unsigned long r15; - unsigned long rdi; - unsigned long rsi; - unsigned long rbp; - unsigned long rbx; - unsigned long rdx; - unsigned long rax; - unsigned long rcx; - unsigned long rsp; - unsigned long rip; - unsigned long eflags; - unsigned short cs; - unsigned short gs; - unsigned short fs; - unsigned short ss; - unsigned long err; - unsigned long trapno; - unsigned long oldmask; - unsigned long cr2; - void *fpstate; - unsigned long reserved1[8]; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rdi; + uint64_t rsi; + uint64_t rbp; + uint64_t rbx; + uint64_t rdx; + uint64_t rax; + uint64_t rcx; + uint64_t rsp; + uint64_t rip; + uint64_t eflags; + uint16_t cs; + uint16_t gs; + uint16_t fs; + uint16_t ss; + uint64_t err; + uint64_t trapno; + uint64_t oldmask; + uint64_t cr2; + uint64_t fpstate; + uint64_t reserved1[8]; }; struct rt_sigcontext_32 { diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index 85c93ad8a..9cb5d82eb 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -212,7 +212,7 @@ int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, return -1; } - sigframe->native.uc.uc_mcontext.fpstate = (void *)addr; + sigframe->native.uc.uc_mcontext.fpstate = (uint64_t)addr; } else if (!sigframe->is_native) { sigframe->compat.uc.uc_mcontext.fpstate = (uint32_t)(unsigned long)(void *)&fpu_state->fpu_state_ia32; diff --git a/criu/arch/x86/sigframe.c b/criu/arch/x86/sigframe.c index 89bfa4a0b..11b0d640d 100644 --- a/criu/arch/x86/sigframe.c +++ b/criu/arch/x86/sigframe.c @@ -26,7 +26,7 @@ int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, return -1; } - sigframe->native.uc.uc_mcontext.fpstate = (void *)addr; + sigframe->native.uc.uc_mcontext.fpstate = (uint64_t)addr; } else if (!sigframe->is_native) { sigframe->compat.uc.uc_mcontext.fpstate = (uint32_t)(unsigned long)(void *)&fpu_state->fpu_state_ia32; From 825ac61090afee9b59ca9ca4adb90308aebafc86 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 14 Jun 2018 20:27:21 +0300 Subject: [PATCH 1517/4375] crit: Show cpuinfo image Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- lib/py/images/images.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/py/images/images.py b/lib/py/images/images.py index 68f983880..eec25f5ac 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -510,6 +510,7 @@ handlers = { 'SECCOMP' : entry_handler(seccomp_entry), 'AUTOFS' : entry_handler(autofs_entry), 'FILES' : entry_handler(file_entry), + 'CPUINFO' : entry_handler(cpuinfo_entry), } def __rhandler(f): From 03598ea5aee4824b4ec16301742a165a29dd6f06 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 17 Jun 2018 06:32:53 +0300 Subject: [PATCH 1518/4375] bitops: use a gcc builtin function instead of our __ffs Our __ffs implementation is straightforward and non-optimal, __builtin_ffsl should be faster. Signed-off-by: Andrei Vagin --- include/common/asm-generic/bitops.h | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/include/common/asm-generic/bitops.h b/include/common/asm-generic/bitops.h index fbd25c1b6..0d861bdcc 100644 --- a/include/common/asm-generic/bitops.h +++ b/include/common/asm-generic/bitops.h @@ -57,17 +57,7 @@ static inline void clear_bit(int nr, volatile unsigned long *addr) */ static inline unsigned long __ffs(unsigned long word) { - int p = 0; - - for (; p < 8*sizeof(word); ++p) { - if (word & 1) { - break; - } - - word >>= 1; - } - - return p; + return __builtin_ffsl(word) - 1; } #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) From 0b1e74cb77f9a9be580b1e5a6383177ba1f6e146 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 31 May 2018 09:00:02 +0000 Subject: [PATCH 1519/4375] restore: do not kill restored process on failure While trying to resurrect the test cases in test/other/rpc one test case was checking for returned errors during restore failures. The process was dumping itself and while the process kept on running it tried to restore from that checkpoint. That should fail as the PID is in use of the process doing the test. CRIU, however, killed the test process during restore failure. This is the fix as proposed by Andrei Vagin on the CRIU mailing list. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 24e307cf3..87cc14ec7 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2254,8 +2254,8 @@ out_kill: struct pstree_item *pi; for_each_pstree_item(pi) - if (vpid(pi) > 0) - kill(vpid(pi), SIGKILL); + if (pi->pid->real > 0) + kill(pi->pid->real, SIGKILL); } out: From d611ee03412d572fc2703c285583458a2fc3e25b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 9 Jun 2018 16:06:49 +0300 Subject: [PATCH 1520/4375] sockets: Add sock_type_name and tcp_state_name helpers For readable printings. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/sockets.h | 3 +++ criu/sockets.c | 44 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/criu/include/sockets.h b/criu/include/sockets.h index 0dc92dc35..7e7b88efe 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -95,4 +95,7 @@ extern int set_netns(uint32_t ns_id); extern int kerndat_socket_netns(void); extern int kerndat_socket_unix_file(void); +extern const char *tcp_state_name(unsigned int state); +extern const char *socket_type_name(unsigned int type); + #endif /* __CR_SOCKETS_H__ */ diff --git a/criu/sockets.c b/criu/sockets.c index b7591bf80..bda5e445b 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -39,6 +39,50 @@ #define SO_GET_FILTER SO_ATTACH_FILTER #endif +const char *socket_type_name(unsigned int type) +{ + static const char *types[] = { + [SOCK_STREAM] = __stringify_1(SOCK_STREAM), + [SOCK_DGRAM] = __stringify_1(SOCK_DGRAM), + [SOCK_RAW] = __stringify_1(SOCK_RAW), + [SOCK_SEQPACKET] = __stringify_1(SOCK_SEQPACKET), + [SOCK_PACKET] = __stringify_1(SOCK_PACKET), + }; + size_t i; + + for (i = 0; i < ARRAY_SIZE(types); i++) { + if (type == i) + return types[i]; + } + + return "UNKNOWN"; +} + +const char *tcp_state_name(unsigned int state) +{ + static const char *states[] = { + [TCP_ESTABLISHED] = __stringify_1(TCP_ESTABLISHED), + [TCP_SYN_SENT] = __stringify_1(TCP_SYN_SENT), + [TCP_SYN_RECV] = __stringify_1(TCP_SYN_RECV), + [TCP_FIN_WAIT1] = __stringify_1(TCP_FIN_WAIT1), + [TCP_FIN_WAIT2] = __stringify_1(TCP_FIN_WAIT2), + [TCP_TIME_WAIT] = __stringify_1(TCP_TIME_WAIT), + [TCP_CLOSE] = __stringify_1(TCP_CLOSE), + [TCP_CLOSE_WAIT] = __stringify_1(TCP_CLOSE_WAIT), + [TCP_LAST_ACK] = __stringify_1(TCP_LAST_ACK), + [TCP_LISTEN] = __stringify_1(TCP_LISTEN), + [TCP_CLOSING] = __stringify_1(TCP_CLOSING), + }; + size_t i; + + for (i = 0; i < ARRAY_SIZE(states); i++) { + if (state == i) + return states[i]; + } + + return "UNKNOWN"; +} + struct sock_diag_greq { u8 family; u8 protocol; From 33bbfa9cc60c267650998934a78e2f193d26a929 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 9 Jun 2018 16:06:50 +0300 Subject: [PATCH 1521/4375] unix: Unify id and ino prints Most of them already in hex form, lets do the same for the rest. Also incoming connections are identified by inode number so use hex for them as well for consistency. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index b5775159d..e31f86f36 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -122,7 +122,7 @@ static void show_one_unix(char *act, const struct unix_sk_desc *sk) int i; for (i = 0; i < sk->nr_icons; i++) - pr_debug("\t\ticon: %4d\n", sk->icons[i]); + pr_debug("\t\ticon: %#x\n", sk->icons[i]); } } @@ -142,7 +142,7 @@ static int can_dump_unix_sk(const struct unix_sk_desc *sk) if (sk->type != SOCK_STREAM && sk->type != SOCK_DGRAM && sk->type != SOCK_SEQPACKET) { - pr_err("Unsupported type (%d) on socket %x.\n" + pr_err("Unsupported type (%d) on socket %#x.\n" "Only stream/dgram/seqpacket are supported.\n", sk->type, sk->sd.ino); return 0; @@ -154,7 +154,7 @@ static int can_dump_unix_sk(const struct unix_sk_desc *sk) case TCP_CLOSE: break; default: - pr_err("Unknown state %d for unix socket %x\n", + pr_err("Unknown state %d for unix socket %#x\n", sk->state, sk->sd.ino); return 0; } @@ -270,7 +270,7 @@ static int resolve_rel_name(uint32_t id, struct unix_sk_desc *sk, const struct f return -ENOENT; } - pr_debug("Resolving relative name %s for socket %x\n", + pr_debug("Resolving relative name %s for socket %#x\n", sk->name, sk->sd.ino); for (i = 0; i < ARRAY_SIZE(dirs); i++) { @@ -459,7 +459,7 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) * to check both ends on read()/write(). Thus mismatched sockets behave * the same way as matched. */ - pr_warn("Shutdown mismatch %u:%d -> %u:%d\n", + pr_warn("Shutdown mismatch %#x:%d -> %#x:%d\n", ue->ino, ue->shutdown, peer->sd.ino, peer->shutdown); } } else if (ue->state == TCP_ESTABLISHED) { @@ -494,7 +494,7 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) /* e->sk_desc is _never_ NULL */ if (e->sk_desc->state != TCP_LISTEN) { pr_err("In-flight connection on " - "non-listening socket %d\n", ue->ino); + "non-listening socket %#x\n", ue->ino); goto err; } @@ -731,7 +731,7 @@ static int unix_collect_one(const struct unix_diag_msg *m, e->next = *chain; *chain = e; - pr_debug("\t\tCollected icon %d\n", d->icons[i]); + pr_debug("\t\tCollected icon %#x\n", d->icons[i]); e->peer_ino = n; e->sk_desc = d; @@ -1005,11 +1005,11 @@ int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ids) ui = find_queuer_for(id_for); if (!ui) { - pr_err("Can't find sender for %d\n", id_for); + pr_err("Can't find sender for %#x\n", id_for); return -1; } - pr_info("Found queuer for %d -> %d\n", id_for, ui->ue->id); + pr_info("Found queuer for %#x -> %#x\n", id_for, ui->ue->id); /* * This is the task that will restore this socket */ @@ -1030,7 +1030,7 @@ int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ids) return -1; } - pr_info("scm: add file %d -> %d\n", tgt->id, vpid(owner)); + pr_info("scm: add file %#x -> %d\n", tgt->id, vpid(owner)); sfle = xmalloc(sizeof(*sfle)); if (!sfle) return -1; @@ -1587,13 +1587,13 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) int ret, sks[2]; if (ui->ue->type != SOCK_STREAM) { - pr_err("Non-stream socket %x in established state\n", + pr_err("Non-stream socket %#x in established state\n", ui->ue->ino); return -1; } if (ui->ue->shutdown != SK_SHUTDOWN__BOTH) { - pr_err("Wrong shutdown/peer state for %x\n", + pr_err("Wrong shutdown/peer state for %#x\n", ui->ue->ino); return -1; } From 53e4770065d7e7a9914fb14c352df2b3e17e5b13 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 9 Jun 2018 16:06:51 +0300 Subject: [PATCH 1522/4375] unix: Move unix_resolve_name declaration on top This makes code more accurate. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index e31f86f36..862ade33a 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -92,6 +92,9 @@ struct unix_sk_desc { static LIST_HEAD(unix_sockets); +static int unix_resolve_name(int lfd, uint32_t id, struct unix_sk_desc *d, + UnixSkEntry *ue, const struct fd_parms *p); + struct unix_sk_listen_icon { unsigned int peer_ino; struct unix_sk_desc *sk_desc; @@ -315,8 +318,6 @@ err: return -ENOENT; } -static int unix_resolve_name(int lfd, uint32_t id, struct unix_sk_desc *d, - UnixSkEntry *ue, const struct fd_parms *p); static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) { struct unix_sk_desc *sk, *peer; From 121a31cad4faadf13d3ff59ebcb5ec9182817e70 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 9 Jun 2018 16:06:52 +0300 Subject: [PATCH 1523/4375] unix: Rename unlink_stale to unlink_sk We gonna use it to detele not only stale sockets but ghost sockets as well. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 862ade33a..c3801f73b 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1744,11 +1744,11 @@ static struct file_desc_ops unix_desc_ops = { * Make FS clean from sockets we're about to * restore. See for how we bind them for details */ -static void unlink_stale(struct unix_sk_info *ui) +static void unlink_sk(struct unix_sk_info *ui) { int ret, cwd_fd = -1, root_fd = -1, ns_fd = -1; - if (ui->name[0] == '\0' || (ui->ue->uflags & USK_EXTERN)) + if (!ui->name || ui->name[0] == '\0' || (ui->ue->uflags & USK_EXTERN)) return; if (prep_unix_sk_cwd(ui, &cwd_fd, &root_fd, NULL)) @@ -1756,10 +1756,15 @@ static void unlink_stale(struct unix_sk_info *ui) ret = unlinkat(AT_FDCWD, ui->name, 0) ? -1 : 0; if (ret < 0 && errno != ENOENT) { - pr_warn("Can't unlink stale socket %#x peer %#x (name %s dir %s)\n", + pr_warn("Can't unlink socket %#x peer %#x (name %s dir %s)\n", ui->ue->ino, ui->ue->peer, ui->name ? (ui->name[0] ? ui->name : &ui->name[1]) : "-", ui->name_dir ? ui->name_dir : "-"); + } else if (ret == 0) { + pr_debug("Unlinked socket %#x peer %#x (name %s dir %s)\n", + ui->ue->ino, ui->ue->peer, + ui->name ? (ui->name[0] ? ui->name : &ui->name[1]) : "-", + ui->name_dir ? ui->name_dir : "-"); } revert_unix_sk_cwd(ui, &cwd_fd, &root_fd, &ns_fd); } @@ -1774,8 +1779,7 @@ static int post_prepare_unix_sk(struct pprep_head *ph) ui = container_of(ph, struct unix_sk_info, peer_resolve); if (ui->ue->peer && fixup_unix_peer(ui)) return -1; - if (ui->name) - unlink_stale(ui); + unlink_sk(ui); return 0; } From 787409df9da2292c16d106d0e319b42313a3d147 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 9 Jun 2018 16:06:53 +0300 Subject: [PATCH 1524/4375] unix: Use decimal format for inode printing For debug sake, to unify with helpers tools such as ss, stat and etc. Requested-by: Andrey Vagin Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 56 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index c3801f73b..0dbf8621b 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -118,20 +118,20 @@ static struct unix_sk_listen_icon *lookup_unix_listen_icons(int peer_ino) static void show_one_unix(char *act, const struct unix_sk_desc *sk) { - pr_debug("\t%s: ino %#x peer_ino %#x family %4d type %4d state %2d name %s\n", + pr_debug("\t%s: ino %d peer_ino %d family %4d type %4d state %2d name %s\n", act, sk->sd.ino, sk->peer_ino, sk->sd.family, sk->type, sk->state, sk->name); if (sk->nr_icons) { int i; for (i = 0; i < sk->nr_icons; i++) - pr_debug("\t\ticon: %#x\n", sk->icons[i]); + pr_debug("\t\ticon: %d\n", sk->icons[i]); } } static void show_one_unix_img(const char *act, const UnixSkEntry *e) { - pr_info("\t%s: id %#x ino %#x peer %#x type %d state %d name %d bytes\n", + pr_info("\t%s: id %#x ino %d peer %d type %d state %d name %d bytes\n", act, e->id, e->ino, e->peer, e->type, e->state, (int)e->name.len); } @@ -145,7 +145,7 @@ static int can_dump_unix_sk(const struct unix_sk_desc *sk) if (sk->type != SOCK_STREAM && sk->type != SOCK_DGRAM && sk->type != SOCK_SEQPACKET) { - pr_err("Unsupported type (%d) on socket %#x.\n" + pr_err("Unsupported type (%d) on socket %d.\n" "Only stream/dgram/seqpacket are supported.\n", sk->type, sk->sd.ino); return 0; @@ -157,7 +157,7 @@ static int can_dump_unix_sk(const struct unix_sk_desc *sk) case TCP_CLOSE: break; default: - pr_err("Unknown state %d for unix socket %#x\n", + pr_err("Unknown state %d for unix socket %d\n", sk->state, sk->sd.ino); return 0; } @@ -273,7 +273,7 @@ static int resolve_rel_name(uint32_t id, struct unix_sk_desc *sk, const struct f return -ENOENT; } - pr_debug("Resolving relative name %s for socket %#x\n", + pr_debug("Resolving relative name %s for socket %d\n", sk->name, sk->sd.ino); for (i = 0; i < ARRAY_SIZE(dirs); i++) { @@ -346,7 +346,7 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) sk = (struct unix_sk_desc *)lookup_socket(p->stat.st_ino, PF_UNIX, 0); if (IS_ERR_OR_NULL(sk)) { - pr_err("Unix socket %#x not found\n", (int)p->stat.st_ino); + pr_err("Unix socket %d not found\n", (int)p->stat.st_ino); goto err; } @@ -414,7 +414,7 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) if (ue->peer) { peer = (struct unix_sk_desc *)lookup_socket(ue->peer, PF_UNIX, 0); if (IS_ERR_OR_NULL(peer)) { - pr_err("Unix socket %#x without peer %#x\n", + pr_err("Unix socket %d without peer %d\n", ue->ino, ue->peer); goto err; } @@ -425,7 +425,7 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) */ if (peer->peer_ino != ue->ino) { if (!peer->name) { - pr_err("Unix socket %#x with unreachable peer %#x (%#x/%s)\n", + pr_err("Unix socket %d with unreachable peer %d (%d/%s)\n", ue->ino, ue->peer, peer->peer_ino, peer->name); goto err; } @@ -460,7 +460,7 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) * to check both ends on read()/write(). Thus mismatched sockets behave * the same way as matched. */ - pr_warn("Shutdown mismatch %#x:%d -> %#x:%d\n", + pr_warn("Shutdown mismatch %d:%d -> %d:%d\n", ue->ino, ue->shutdown, peer->sd.ino, peer->shutdown); } } else if (ue->state == TCP_ESTABLISHED) { @@ -479,7 +479,7 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) goto dump; } - pr_err("Dangling connection %#x\n", ue->ino); + pr_err("Dangling connection %d\n", ue->ino); goto err; } @@ -495,13 +495,13 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) /* e->sk_desc is _never_ NULL */ if (e->sk_desc->state != TCP_LISTEN) { pr_err("In-flight connection on " - "non-listening socket %#x\n", ue->ino); + "non-listening socket %d\n", ue->ino); goto err; } ue->peer = e->sk_desc->sd.ino; - pr_debug("\t\tFixed inflight socket %#x peer %#x)\n", + pr_debug("\t\tFixed inflight socket %d peer %d)\n", ue->ino, ue->peer); } dump: @@ -609,7 +609,7 @@ static int unix_resolve_name(int lfd, uint32_t id, struct unix_sk_desc *d, } else if ((st.st_ino != d->vfs_ino) || !phys_stat_dev_match(st.st_dev, d->vfs_dev, ns, name)) { pr_info("unix: Dropping path %s for unlinked bound " - "sk %#x.%#x real %#x.%#x\n", + "sk %#x.%d real %#x.%d\n", name, (int)st.st_dev, (int)st.st_ino, (int)d->vfs_dev, (int)d->vfs_ino); deleted = true; @@ -652,7 +652,7 @@ static int unix_process_name(struct unix_sk_desc *d, const struct unix_diag_msg struct unix_diag_vfs *uv; if (!tb[UNIX_DIAG_VFS]) { - pr_err("Bound socket w/o inode %#x\n", m->udiag_ino); + pr_err("Bound socket w/o inode %d\n", m->udiag_ino); goto skip; } @@ -732,7 +732,7 @@ static int unix_collect_one(const struct unix_diag_msg *m, e->next = *chain; *chain = e; - pr_debug("\t\tCollected icon %#x\n", d->icons[i]); + pr_debug("\t\tCollected icon %d\n", d->icons[i]); e->peer_ino = n; e->sk_desc = d; @@ -1113,7 +1113,7 @@ static int shutdown_unix_sk(int sk, struct unix_sk_info *ui) return -1; } - pr_debug("Socket %#x is shut down %d\n", ue->ino, how); + pr_debug("Socket %d is shut down %d\n", ue->ino, how); return 0; } @@ -1271,7 +1271,7 @@ static int post_open_standalone(struct file_desc *d, int fd) addr.sun_family = AF_UNIX; memcpy(&addr.sun_path, peer->name, peer->ue->name.len); - pr_info("\tConnect %#x to %#x\n", ui->ue->ino, peer->ue->ino); + pr_info("\tConnect %d to %d\n", ui->ue->ino, peer->ue->ino); if (prep_unix_sk_cwd(peer, &cwd_fd, NULL, &ns_fd)) return -1; @@ -1279,7 +1279,7 @@ static int post_open_standalone(struct file_desc *d, int fd) if (connect(fd, (struct sockaddr *)&addr, sizeof(addr.sun_family) + peer->ue->name.len) < 0) { - pr_perror("Can't connect %#x socket", ui->ue->ino); + pr_perror("Can't connect %d socket", ui->ue->ino); revert_unix_sk_cwd(peer, &cwd_fd, &root_fd, &ns_fd); return -1; } @@ -1448,7 +1448,7 @@ static int post_open_interconnected_master(struct unix_sk_info *ui) static void pr_info_opening(const char *prefix, struct unix_sk_info *ui, struct fdinfo_list_entry *fle) { - pr_info("Opening %s (stage %d id %#x ino %#x peer %#x)\n", + pr_info("Opening %s (stage %d id %#x ino %d peer %d)\n", prefix, fle->stage, ui->ue->id, ui->ue->ino, ui->ue->peer); } @@ -1588,13 +1588,13 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) int ret, sks[2]; if (ui->ue->type != SOCK_STREAM) { - pr_err("Non-stream socket %#x in established state\n", + pr_err("Non-stream socket %d in established state\n", ui->ue->ino); return -1; } if (ui->ue->shutdown != SK_SHUTDOWN__BOTH) { - pr_err("Wrong shutdown/peer state for %#x\n", + pr_err("Wrong shutdown/peer state for %d\n", ui->ue->ino); return -1; } @@ -1670,7 +1670,7 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) return -1; if (ui->ue->state == TCP_LISTEN) { - pr_info("\tPutting %#x into listen state\n", ui->ue->ino); + pr_info("\tPutting %d into listen state\n", ui->ue->ino); if (listen(sk, ui->ue->backlog) < 0) { pr_perror("Can't make usk listen"); return -1; @@ -1756,12 +1756,12 @@ static void unlink_sk(struct unix_sk_info *ui) ret = unlinkat(AT_FDCWD, ui->name, 0) ? -1 : 0; if (ret < 0 && errno != ENOENT) { - pr_warn("Can't unlink socket %#x peer %#x (name %s dir %s)\n", + pr_warn("Can't unlink socket %d peer %d (name %s dir %s)\n", ui->ue->ino, ui->ue->peer, ui->name ? (ui->name[0] ? ui->name : &ui->name[1]) : "-", ui->name_dir ? ui->name_dir : "-"); } else if (ret == 0) { - pr_debug("Unlinked socket %#x peer %#x (name %s dir %s)\n", + pr_debug("Unlinked socket %d peer %d (name %s dir %s)\n", ui->ue->ino, ui->ue->peer, ui->name ? (ui->name[0] ? ui->name : &ui->name[1]) : "-", ui->name_dir ? ui->name_dir : "-"); @@ -1845,7 +1845,7 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) uname = "-"; } - pr_info(" `- Got %#x peer %#x (name %s%.*s dir %s)\n", + pr_info(" `- Got %d peer %d (name %s%.*s dir %s)\n", ui->ue->ino, ui->ue->peer, prefix, ulen, uname, ui->name_dir ? ui->name_dir : "-"); @@ -1973,14 +1973,14 @@ static int fixup_unix_peer(struct unix_sk_info *ui) struct unix_sk_info *peer = ui->peer; if (!peer) { - pr_err("FATAL: Peer %#x unresolved for %#x\n", + pr_err("FATAL: Peer %d unresolved for %d\n", ui->ue->peer, ui->ue->ino); return -1; } if (peer != ui && peer->peer == ui && !(ui->flags & (USK_PAIR_MASTER | USK_PAIR_SLAVE))) { - pr_info("Connected %#x -> %#x (%#x) flags %#x\n", + pr_info("Connected %d -> %d (%d) flags %#x\n", ui->ue->ino, ui->ue->peer, peer->ue->ino, ui->flags); /* socketpair or interconnected sockets */ if (interconnected_pair(ui, peer)) From 4691dcf37bdaba1f54e80cc99bc223ce48280ba8 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 9 Jun 2018 16:06:54 +0300 Subject: [PATCH 1525/4375] unix: Add support of ghost sockets Unix sockets may be connected via deleted socket name, moreover the name may be reused (ie same sun_addr but different inodes). To be able to handle them we do a few tricks: - when collecting sockets we figure out if "deleted" mark is present on the socket and if such we order this sockets creation and deletion with mutex, together with adding missing directories, and save this descriptors in fdstore if there are peers connected to - on restore we connect via procfs/fd/X as suggested by Andrew Vagin Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 4 + criu/include/sockets.h | 1 + criu/sk-unix.c | 427 +++++++++++++++++++++++++++++++++-------- 3 files changed, 354 insertions(+), 78 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 87cc14ec7..ea2066eec 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -378,6 +378,10 @@ static int root_prepare_shared(void) if (ret) goto err; + ret = unix_prepare_root_shared(); + if (ret) + goto err; + ret = add_fake_unix_queuers(); if (ret) goto err; diff --git a/criu/include/sockets.h b/criu/include/sockets.h index 7e7b88efe..371d1a509 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -58,6 +58,7 @@ extern int netlink_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, void *arg extern int unix_sk_id_add(unsigned int ino); extern int unix_sk_ids_parse(char *optarg); +extern int unix_prepare_root_shared(void); extern int do_dump_opt(int sk, int level, int name, void *val, int len); #define dump_opt(s, l, n, f) do_dump_opt(s, l, n, f, sizeof(*f)) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 0dbf8621b..fd57205dc 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "libnetlink.h" #include "cr_options.h" @@ -32,6 +33,7 @@ #include "fdstore.h" #include "fdinfo.h" #include "kerndat.h" +#include "rst-malloc.h" #include "protobuf.h" #include "images/sk-unix.pb-c.h" @@ -90,11 +92,21 @@ struct unix_sk_desc { UnixSkEntry *ue; }; +/* + * The mutex_ghost is accessed from different tasks, + * so make sure it is in shared memory. + */ +static mutex_t *mutex_ghost; + static LIST_HEAD(unix_sockets); +static LIST_HEAD(unix_ghost_addr); static int unix_resolve_name(int lfd, uint32_t id, struct unix_sk_desc *d, UnixSkEntry *ue, const struct fd_parms *p); +struct unix_sk_info; +static int unlink_sk(struct unix_sk_info *ui); + struct unix_sk_listen_icon { unsigned int peer_ino; struct unix_sk_desc *sk_desc; @@ -887,12 +899,15 @@ struct unix_sk_info { char *name; char *name_dir; unsigned flags; + int fdstore_id; struct unix_sk_info *peer; struct pprep_head peer_resolve; /* XXX : union with the above? */ struct file_desc d; struct list_head connected; /* List of sockets, connected to me */ struct list_head node; /* To link in peer's connected list */ struct list_head scm_fles; + struct list_head ghost_node; + size_t ghost_dir_pos; /* * For DGRAM sockets with queues, we should only restore the queue @@ -917,6 +932,7 @@ struct scm_fle { #define USK_PAIR_MASTER 0x1 #define USK_PAIR_SLAVE 0x2 +#define USK_GHOST_FDSTORE 0x4 /* bound but removed address */ static struct unix_sk_info *find_unix_sk_by_ino(int ino) { @@ -1241,6 +1257,7 @@ err: static int post_open_standalone(struct file_desc *d, int fd) { + int fdstore_fd = -1, procfs_self_dir = -1, len; struct unix_sk_info *ui; struct unix_sk_info *peer; struct sockaddr_un addr; @@ -1269,22 +1286,49 @@ static int post_open_standalone(struct file_desc *d, int fd) memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; - memcpy(&addr.sun_path, peer->name, peer->ue->name.len); pr_info("\tConnect %d to %d\n", ui->ue->ino, peer->ue->ino); - if (prep_unix_sk_cwd(peer, &cwd_fd, NULL, &ns_fd)) + if (prep_unix_sk_cwd(peer, &cwd_fd, &root_fd, &ns_fd)) return -1; - if (connect(fd, (struct sockaddr *)&addr, - sizeof(addr.sun_family) + - peer->ue->name.len) < 0) { - pr_perror("Can't connect %d socket", ui->ue->ino); - revert_unix_sk_cwd(peer, &cwd_fd, &root_fd, &ns_fd); - return -1; + if (peer->flags & USK_GHOST_FDSTORE) { + procfs_self_dir = open_proc(getpid(), "fd"); + fdstore_fd = fdstore_get(peer->fdstore_id); + + if (fdstore_fd < 0 || procfs_self_dir < 0) + goto err_revert_and_exit; + + /* + * WARNING: After this call we rely on revert_unix_sk_cwd + * to restore the former directories so that connect + * will operate inside proc/$pid/fd/X. + */ + if (fchdir(procfs_self_dir)) { + pr_perror("Can't change to procfs"); + goto err_revert_and_exit; + } + len = snprintf(addr.sun_path, UNIX_PATH_MAX, "%d", fdstore_fd); + } else { + memcpy(&addr.sun_path, peer->name, peer->ue->name.len); + len = peer->ue->name.len; } + + /* + * Make sure the target is not being renamed at the moment + * while we're connecting in sake of ghost sockets. + */ + mutex_lock(mutex_ghost); + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr.sun_family) + len) < 0) { + pr_perror("Can't connect %d socket", ui->ue->ino); + goto err_revert_and_exit; + } + mutex_unlock(mutex_ghost); + ui->is_connected = true; + close_safe(&procfs_self_dir); + close_safe(&fdstore_fd); revert_unix_sk_cwd(peer, &cwd_fd, &root_fd, &ns_fd); restore_queue: @@ -1296,48 +1340,217 @@ restore_sk_common: if (ui->queuer && !ui->queuer->peer_queue_restored) return 1; return restore_sk_common(fd, ui); + +err_revert_and_exit: + close_safe(&procfs_self_dir); + close_safe(&fdstore_fd); + revert_unix_sk_cwd(peer, &cwd_fd, &root_fd, &ns_fd); + return -1; } -static int bind_deleted_unix_sk(int sk, struct unix_sk_info *ui, - struct sockaddr_un *addr) +static int restore_file_perms(struct unix_sk_info *ui) { - char temp[PATH_MAX]; + if (ui->ue->file_perms) { + FilePermsEntry *perms = ui->ue->file_perms; + char fname[PATH_MAX]; + + if (ui->ue->name.len >= sizeof(fname)) { + pr_err("The file name is too long\n"); + return -E2BIG; + } + + memcpy(fname, ui->name, ui->ue->name.len); + fname[ui->ue->name.len] = '\0'; + + if (fchownat(AT_FDCWD, fname, perms->uid, perms->gid, 0) < 0) { + int errno_cpy = errno; + pr_perror("Unable to change file owner and group"); + return -errno_cpy; + } + + if (fchmodat(AT_FDCWD, fname, perms->mode, 0) < 0) { + int errno_cpy = errno; + pr_perror("Unable to change file mode bits"); + return -errno_cpy; + } + } + + return 0; +} + +static int keep_deleted(struct unix_sk_info *ui) +{ + int fd = open(ui->name, O_PATH); + if (fd < 0) { + pr_perror("ghost: Can't open id %#x ino %d addr %s", + ui->ue->id, ui->ue->ino, ui->name); + return -1; + } + ui->fdstore_id = fdstore_add(fd); + pr_debug("ghost: id %#x %d fdstore_id %d %s\n", + ui->ue->id, ui->ue->ino, ui->fdstore_id, ui->name); + close(fd); + return ui->fdstore_id; +} + + +#define UNIX_GHOST_FMT "%s.criu-sk-ghost" + +/* + * When path where socket lives is deleted, we need to reconstruct + * it back up but allow caller to remove it after. + */ +static int bind_on_deleted(int sk, struct unix_sk_info *ui) +{ + char path[PATH_MAX], path_parked[PATH_MAX], *pos; + struct sockaddr_un addr; + bool renamed = false; int ret; - pr_info("found duplicate unix socket bound at %s\n", addr->sun_path); - - ret = snprintf(temp, sizeof(temp), - "%s-%s-%d", addr->sun_path, "criu-temp", getpid()); - /* this shouldn't happen, since sun_addr is only 108 chars long */ - if (ret < 0 || ret >= sizeof(temp)) { - pr_err("snprintf of %s failed?\n", addr->sun_path); - return -1; + if (ui->ue->name.len >= sizeof(path)) { + pr_err("ghost: Too long name for socket id %#x ino %d name %s\n", + ui->ue->id, ui->ue->ino, ui->name); + return -ENOSPC; } - ret = rename(addr->sun_path, temp); + memcpy(path, ui->name, ui->ue->name.len); + path[ui->ue->name.len] = '\0'; + + for (pos = strrchr(path, '/'); pos; + pos = strrchr(path, '/')) { + *pos = '\0'; + + ret = access(path, R_OK | W_OK | X_OK); + if (ret == 0) { + ui->ghost_dir_pos = pos - path; + pr_debug("ghost: socket id %#x ino %d name %s detected F_OK %s\n", + ui->ue->id, ui->ue->ino, ui->name, path); + break; + } + + if (errno != ENOENT) { + ret = -errno; + pr_perror("ghost: Can't access %s for socket id %#x ino %d name %s", + path, ui->ue->id, ui->ue->ino, ui->name); + return ret; + } + } + + memcpy(path, ui->name, ui->ue->name.len); + path[ui->ue->name.len] = '\0'; + + pos = dirname(path); + pr_debug("ghost: socket id %#x ino %d name %s creating %s\n", + ui->ue->id, ui->ue->ino, ui->name, pos); + ret = mkdirpat(AT_FDCWD, pos, 0755); + if (ret) { + errno = -ret; + pr_perror("ghost: Can't create %s", pos); + return ret; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + memcpy(&addr.sun_path, ui->name, ui->ue->name.len); + + ret = bind(sk, (struct sockaddr *)&addr, + sizeof(addr.sun_family) + ui->ue->name.len); if (ret < 0) { - pr_perror("couldn't move socket for binding"); - return -1; + /* + * In case if there some real living socket + * with same name just move it aside for a + * while, we will move it back once ghost + * socket is processed. + */ + if (errno == EADDRINUSE) { + snprintf(path_parked, sizeof(path_parked), UNIX_GHOST_FMT, ui->name); + /* + * Say previous restore get killed in a middle due to + * any reason, be ready the file might already exist, + * clean it up. + */ + if (unlinkat(AT_FDCWD, path_parked, 0) == 0) + pr_debug("ghost: Unlinked stale socket id %#x ino %d name %s\n", + ui->ue->id, ui->ue->ino, path_parked); + if (rename(ui->name, path_parked)) { + ret = -errno; + pr_perror("ghost: Can't rename id %#x ino %d addr %s -> %s", + ui->ue->id, ui->ue->ino, ui->name, path_parked); + return ret; + } + pr_debug("ghost: id %#x ino %d renamed %s -> %s\n", + ui->ue->id, ui->ue->ino, ui->name, path_parked); + renamed = true; + ret = bind(sk, (struct sockaddr *)&addr, + sizeof(addr.sun_family) + ui->ue->name.len); + } + if (ret < 0) { + ret = -errno; + pr_perror("ghost: Can't bind on socket id %#x ino %d addr %s", + ui->ue->id, ui->ue->ino, ui->name); + return ret; + } } - ret = bind(sk, (struct sockaddr *)addr, - sizeof(addr->sun_family) + ui->ue->name.len); + ret = restore_file_perms(ui); + if (ret < 0) + return ret; + + ret = keep_deleted(ui); if (ret < 0) { - pr_perror("Can't bind socket after move"); - return -1; + pr_err("ghost: Can't save socket %#x ino %d addr %s into fdstore\n", + ui->ue->id, ui->ue->ino, ui->name); + return -EIO; } - ret = rename(temp, addr->sun_path); - if (ret < 0) { - pr_perror("couldn't move socket back"); - return -1; - } - - /* we've handled the deleted-ness of this - * socket and we don't want to delete it later - * since it's not /this/ socket. + /* + * Once everything is ready, just remove the socket from the + * filesystem and rename back the original one if it were here. */ - ui->ue->deleted = false; + ret = unlinkat(AT_FDCWD, ui->name, 0); + if (ret < 0) { + ret = -errno; + pr_perror("ghost: Can't unlink socket %#x ino %d addr %s", + ui->ue->id, ui->ue->ino, ui->name); + return ret; + } + + if (renamed) { + if (rename(path_parked, ui->name)) { + ret = -errno; + pr_perror("ghost: Can't rename id %#x ino %d addr %s -> %s", + ui->ue->id, ui->ue->ino, path_parked, ui->name); + return ret; + } + + pr_debug("ghost: id %#x ino %d renamed %s -> %s\n", + ui->ue->id, ui->ue->ino, path_parked, ui->name); + } + + /* + * Finally remove directories we've created. + */ + if (ui->ghost_dir_pos) { + char *pos; + + memcpy(path, ui->name, ui->ue->name.len); + path[ui->ue->name.len] = '\0'; + + for (pos = strrchr(path, '/'); + pos && (pos - path) > ui->ghost_dir_pos; + pos = strrchr(path, '/')) { + *pos = '\0'; + if (rmdir(path)) { + ret = - errno; + pr_perror("ghost: Can't remove directory %s on id %#x ino %d", + path, ui->ue->id, ui->ue->ino); + return -1; + } + pr_debug("ghost: Removed %s on id %#x ino %d\n", + path, ui->ue->id, ui->ue->ino); + } + } + return 0; } @@ -1365,46 +1578,38 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) addr.sun_family = AF_UNIX; memcpy(&addr.sun_path, ui->name, ui->ue->name.len); - if (ui->name[0] && prep_unix_sk_cwd(ui, &cwd_fd, NULL, &ns_fd)) + if (ui->name[0] && prep_unix_sk_cwd(ui, &cwd_fd, &root_fd, &ns_fd)) return -1; - ret = bind(sk, (struct sockaddr *)&addr, - sizeof(addr.sun_family) + ui->ue->name.len); + /* + * Order binding for sake of ghost sockets. We might rename + * existing socket to some temp name, bind ghost, delete it, + * and finally move the former back, thus while we're doing + * this stuff we should not be interruped by connection + * from another sockets. + * + * FIXME: Probably wort make it per address rather for + * optimization sake. + */ + mutex_lock(mutex_ghost); + + if (ui->flags & USK_GHOST_FDSTORE) { + pr_debug("ghost: bind id %#x ino %d addr %s\n", + ui->ue->id, ui->ue->ino, ui->name); + ret = bind_on_deleted(sk, ui); + if (ret) + errno = -ret; + } else { + pr_debug("bind id %#x ino %d addr %s\n", + ui->ue->id, ui->ue->ino, ui->name); + ret = bind(sk, (struct sockaddr *)&addr, + sizeof(addr.sun_family) + ui->ue->name.len); + if (ret == 0 && restore_file_perms(ui)) + goto done; + } if (ret < 0) { - if (ui->ue->has_deleted && ui->ue->deleted && errno == EADDRINUSE) { - if (bind_deleted_unix_sk(sk, ui, &addr)) - goto done; - } else { - pr_perror("Can't bind socket"); - goto done; - } - } - - if (*ui->name && ui->ue->file_perms) { - FilePermsEntry *perms = ui->ue->file_perms; - char fname[PATH_MAX]; - - if (ui->ue->name.len >= sizeof(fname)) { - pr_err("The file name is too long\n"); - goto done; - } - - memcpy(fname, ui->name, ui->ue->name.len); - fname[ui->ue->name.len] = '\0'; - - if (fchownat(AT_FDCWD, fname, perms->uid, perms->gid, 0) == -1) { - pr_perror("Unable to change file owner and group"); - goto done; - } - - if (fchmodat(AT_FDCWD, fname, perms->mode, 0) == -1) { - pr_perror("Unable to change file mode bits"); - goto done; - } - } - - if (ui->ue->deleted && unlink((char *)ui->ue->name.data) < 0) { - pr_perror("failed to unlink %s", ui->ue->name.data); + pr_perror("Can't bind id %#x ino %d addr %s", + ui->ue->id, ui->ue->ino, ui->name); goto done; } @@ -1416,6 +1621,7 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) exit_code = 0; done: revert_unix_sk_cwd(ui, &cwd_fd, &root_fd, &ns_fd); + mutex_unlock(mutex_ghost); return exit_code; } @@ -1551,11 +1757,27 @@ static int setup_second_end(int *sks, struct fdinfo_list_entry *second_end) static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) { struct unix_sk_info *queuer = ui->queuer; - struct fdinfo_list_entry *fle; + struct unix_sk_info *peer = ui->peer; + struct fdinfo_list_entry *fle, *fle_peer; int sk; fle = file_master(&ui->d); pr_info_opening("standalone", ui, fle); + + /* + * If we're about to connect to the peer which + * has been bound to removed address we should + * wait until it is processed and put into fdstore + * engine, later we will use the engine to connect + * into it in a special way. + */ + if (peer && (peer->flags & USK_GHOST_FDSTORE)) { + fle_peer = file_master(&peer->d); + if (fle_peer->stage < FLE_OPEN) { + return 1; + } + } + if (fle->stage == FLE_OPEN) return post_open_standalone(&ui->d, fle->fe->fd); @@ -1744,15 +1966,15 @@ static struct file_desc_ops unix_desc_ops = { * Make FS clean from sockets we're about to * restore. See for how we bind them for details */ -static void unlink_sk(struct unix_sk_info *ui) +static int unlink_sk(struct unix_sk_info *ui) { - int ret, cwd_fd = -1, root_fd = -1, ns_fd = -1; + int ret = 0, cwd_fd = -1, root_fd = -1, ns_fd = -1; if (!ui->name || ui->name[0] == '\0' || (ui->ue->uflags & USK_EXTERN)) - return; + return 0; if (prep_unix_sk_cwd(ui, &cwd_fd, &root_fd, NULL)) - return; + return -1; ret = unlinkat(AT_FDCWD, ui->name, 0) ? -1 : 0; if (ret < 0 && errno != ENOENT) { @@ -1760,13 +1982,17 @@ static void unlink_sk(struct unix_sk_info *ui) ui->ue->ino, ui->ue->peer, ui->name ? (ui->name[0] ? ui->name : &ui->name[1]) : "-", ui->name_dir ? ui->name_dir : "-"); + ret = -errno; + goto out; } else if (ret == 0) { pr_debug("Unlinked socket %d peer %d (name %s dir %s)\n", ui->ue->ino, ui->ue->peer, ui->name ? (ui->name[0] ? ui->name : &ui->name[1]) : "-", ui->name_dir ? ui->name_dir : "-"); } +out: revert_unix_sk_cwd(ui, &cwd_fd, &root_fd, &ns_fd); + return ret; } static void try_resolve_unix_peer(struct unix_sk_info *ui); @@ -1798,6 +2024,8 @@ static int init_unix_sk_info(struct unix_sk_info *ui, UnixSkEntry *ue) ui->name_dir = (void *)ue->name_dir; ui->flags = 0; + ui->fdstore_id = -1; + ui->ghost_dir_pos = 0; ui->peer = NULL; ui->queuer = NULL; ui->bound = 0; @@ -1812,6 +2040,40 @@ static int init_unix_sk_info(struct unix_sk_info *ui, UnixSkEntry *ue) INIT_LIST_HEAD(&ui->connected); INIT_LIST_HEAD(&ui->node); INIT_LIST_HEAD(&ui->scm_fles); + INIT_LIST_HEAD(&ui->ghost_node); + + return 0; +} + +int unix_prepare_root_shared(void) +{ + struct unix_sk_info *ui; + + mutex_ghost = shmalloc(sizeof(*mutex_ghost)); + if (!mutex_ghost) { + pr_err("ghost: Can't allocate mutex\n"); + return -ENOMEM; + } + mutex_init(mutex_ghost); + + pr_debug("ghost: Resolving addresses\n"); + + list_for_each_entry(ui, &unix_ghost_addr, ghost_node) { + pr_debug("ghost: id %#x type %s state %s ino %d peer %d address %s\n", + ui->ue->id, socket_type_name(ui->ue->type), + tcp_state_name(ui->ue->state), + ui->ue->ino, ui->peer ? ui->peer->ue->ino : 0, + ui->name); + + /* + * Drop any existing trash on the FS and mark the + * peer as a ghost one, so we will put it into + * fdstore to be able to connect into it even + * when the address is removed from the FS. + */ + unlink_sk(ui); + ui->flags |= USK_GHOST_FDSTORE; + } return 0; } @@ -1858,6 +2120,15 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) add_post_prepare_cb(&ui->peer_resolve); } + if (ui->ue->deleted) { + if (!ui->name || !ui->ue->name.len || !ui->name[0]) { + pr_err("No name present, ino %d\n", ui->ue->ino); + return -1; + } + + list_add_tail(&ui->ghost_node, &unix_ghost_addr); + } + list_add_tail(&ui->list, &unix_sockets); return file_desc_add(&ui->d, ui->ue->id, &unix_desc_ops); } From 05f9967869f50be79b2f704f3e9fc14a5e4f4b77 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 9 Jun 2018 16:06:55 +0300 Subject: [PATCH 1526/4375] unix: Improve debug message when collecting socket Print its type and state. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index fd57205dc..1e74357e8 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -2107,9 +2107,9 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) uname = "-"; } - pr_info(" `- Got %d peer %d (name %s%.*s dir %s)\n", - ui->ue->ino, ui->ue->peer, - prefix, ulen, uname, + pr_info(" `- Got id %#x ino %d type %s state %s peer %d (name %s%.*s dir %s)\n", + ui->ue->id, ui->ue->ino, socket_type_name(ui->ue->type), + tcp_state_name(ui->ue->state), ui->ue->peer, prefix, ulen, uname, ui->name_dir ? ui->name_dir : "-"); if (ui->ue->peer || ui->name) { From e6d448ca86f97835dbad66ab3789ba308cab5b9a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 9 Jun 2018 16:06:56 +0300 Subject: [PATCH 1527/4375] unix: test -- Add sk-unix01 test To test the case where sockets are removed together with directory they are living in. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/sk-unix01.c | 367 ++++++++++++++++++++++++++++++++ test/zdtm/static/sk-unix01.desc | 1 + 3 files changed, 369 insertions(+) create mode 100644 test/zdtm/static/sk-unix01.c create mode 100644 test/zdtm/static/sk-unix01.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index fa8a9a237..22291ccab 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -332,6 +332,7 @@ TST_DIR = \ autofs \ del_standalone_un \ sk-unix-mntns \ + sk-unix01 \ TST_DIR_FILE = \ chroot \ diff --git a/test/zdtm/static/sk-unix01.c b/test/zdtm/static/sk-unix01.c new file mode 100644 index 000000000..c6c199657 --- /dev/null +++ b/test/zdtm/static/sk-unix01.c @@ -0,0 +1,367 @@ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check that deleted unix sockets with dirs are restored correctly"; +const char *test_author = "Cyrill Gorcunov "; + +char *dirname; +TEST_OPTION(dirname, string, "directory name", 1); + +static int fill_sock_name(struct sockaddr_un *name, const char *filename) +{ + char *cwd; + + cwd = get_current_dir_name(); + if (strlen(filename) + strlen(cwd) + 1 >= sizeof(name->sun_path)) { + pr_err("Name %s/%s is too long for socket\n", + cwd, filename); + return -1; + } + + name->sun_family = AF_LOCAL; + ssprintf(name->sun_path, "%s/%s", cwd, filename); + return 0; +} + +static int sk_alloc_bind(int type, struct sockaddr_un *addr) +{ + int sk; + + sk = socket(PF_UNIX, type, 0); + if (sk < 0) { + pr_perror("socket"); + return -1; + } + + if (addr && bind(sk, (const struct sockaddr *)addr, sizeof(*addr))) { + pr_perror("bind %s", addr->sun_path); + close(sk); + return -1; + } + + return sk; +} + +static int sk_alloc_connect(int type, struct sockaddr_un *addr) +{ + int sk; + + sk = socket(PF_UNIX, type, 0); + if (sk < 0) { + pr_perror("socket"); + return -1; + } + + if (connect(sk, (const struct sockaddr *)addr, sizeof(*addr))) { + pr_perror("connect %s", addr->sun_path); + close(sk); + return -1; + } + + return sk; +} + +int main(int argc, char **argv) +{ + int c1 = 1, c2 = 0, c3 = 3, c4 = 0; + int c5 = 5, c6 = 0, c7 = 7, c8 = 0; + int c9 = 8, c10 = 0; + char filename[PATH_MAX]; + char subdir_dg[PATH_MAX]; + char subdir_st[PATH_MAX]; + struct sockaddr_un addr_from; + struct sockaddr_un addr; + int sk_dgram_pair[2]; + int sk_dgram[9]; + socklen_t len; + int sk_st[5]; + DIR *dir; + + test_init(argc, argv); + + /* + * All sockets are under dir to not clash + * with other tests. + */ + if (mkdir(dirname, 0755) < 0) { + if (errno != EEXIST) { + pr_perror("Can't create %s", dirname); + return 1; + } + } + + /* + * Subdir for dgram sockets. + */ + ssprintf(subdir_dg, "%s/%s", dirname, "dg"); + if (mkdir(subdir_dg, 0755) < 0) { + if (errno != EEXIST) { + pr_perror("Can't create %s", subdir_dg); + return 1; + } + } + + /* + * Subdir for stream sockets. + */ + ssprintf(subdir_st, "%s/%s", dirname, "st"); + if (mkdir(subdir_st, 0755) < 0) { + if (errno != EEXIST) { + pr_perror("Can't create %s", subdir_st); + return 1; + } + } + + /* + * DGRAM sockets + * + * - create 2 sockets + * - bind first to subdired + * - connect second to it + * - delete socket on fs + * - do the same for second pair with same name + * - delete socket on fs + * - create 3 more sockets + * - bind /connect to same name, where one is deleted + */ + + ssprintf(filename, "%s/%s", subdir_dg, "sk-dt"); + if (fill_sock_name(&addr, filename) < 0) { + pr_err("%s is too long for socket\n", filename); + return 1; + } + unlink(addr.sun_path); + + sk_dgram[0] = sk_alloc_bind(SOCK_DGRAM, &addr); + if (sk_dgram[0] < 0) + return 1; + test_msg("sk-dt: alloc/bind %d %s\n", sk_dgram[0], addr.sun_path); + + sk_dgram[1] = sk_alloc_connect(SOCK_DGRAM, &addr); + if (sk_dgram[1] < 0) + return 1; + unlink(addr.sun_path); + test_msg("sk-dt: alloc/connect/unlink %d %s\n", sk_dgram[1], addr.sun_path); + + sk_dgram[2] = sk_alloc_bind(SOCK_DGRAM, &addr); + if (sk_dgram[2] < 0) + return 1; + test_msg("sk-dt: alloc/bind %d %s\n", sk_dgram[2], addr.sun_path); + + sk_dgram[3] = sk_alloc_connect(SOCK_DGRAM, &addr); + if (sk_dgram[3] < 0) + return 1; + unlink(addr.sun_path); + test_msg("sk-dt: alloc/connect/unlink %d %s\n", sk_dgram[3], addr.sun_path); + + ssprintf(filename, "%s/%s", dirname, "sole"); + if (fill_sock_name(&addr, filename) < 0) { + pr_err("%s is too long for socket\n", filename); + return 1; + } + unlink(addr.sun_path); + + sk_dgram[4] = sk_alloc_bind(SOCK_DGRAM, &addr); + if (sk_dgram[4] < 0) + return 1; + test_msg("sk-dt: alloc/bind %d %s\n", sk_dgram[4], addr.sun_path); + + sk_dgram[5] = sk_alloc_connect(SOCK_DGRAM, &addr); + if (sk_dgram[5] < 0) + return 1; + unlink(addr.sun_path); + test_msg("sk-dt: alloc/connect/unlink %d %s\n", sk_dgram[5], addr.sun_path); + + sk_dgram[6] = sk_alloc_bind(SOCK_DGRAM, &addr); + if (sk_dgram[6] < 0) + return 1; + test_msg("sk-dt: alloc/bind %d %s\n", sk_dgram[6], addr.sun_path); + + sk_dgram[7] = sk_alloc_connect(SOCK_DGRAM, &addr); + if (sk_dgram[7] < 0) + return 1; + unlink(addr.sun_path); + test_msg("sk-dt: alloc/connect/unlink %d %s\n", sk_dgram[7], addr.sun_path); + + sk_dgram[8] = sk_alloc_bind(SOCK_DGRAM, &addr); + if (sk_dgram[8] < 0) + return 1; + test_msg("sk-dt: alloc/bind %d %s\n", sk_dgram[8], addr.sun_path); + + if (dup2(sk_dgram[4], 110) < 0 || dup2(sk_dgram[6], 100) < 0) { + pr_perror("Can't move socket"); + return 1; + } + close(sk_dgram[4]); + sk_dgram[4] = 110; + close(sk_dgram[6]); + sk_dgram[6] = 100; + + /* + * DGRAM paired sockets. Just bind both to the same name. + */ + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sk_dgram_pair)) { + pr_perror("Can't create dgram pair"); + return 1; + } + test_msg("sk-dgp: sockpair %d %d\n", + sk_dgram_pair[0], sk_dgram_pair[1]); + ssprintf(filename, "%s/%s", subdir_dg, "sk-dtp"); + + if (fill_sock_name(&addr, filename) < 0) { + pr_err("%s is too long for socket\n", filename); + return 1; + } + + if (bind(sk_dgram_pair[0], (const struct sockaddr *)&addr, sizeof(addr))) { + pr_perror("bind %d to %s", sk_dgram_pair[0], addr.sun_path); + return -1; + } + unlink(addr.sun_path); + if (bind(sk_dgram_pair[1], (const struct sockaddr *)&addr, sizeof(addr))) { + pr_perror("bind %d to %s", sk_dgram_pair[1], addr.sun_path); + return -1; + } + unlink(addr.sun_path); + + /* + * Drop subdirectory. + */ + rmdir(subdir_dg); + + /* + * STREAM sockets + * + * - create server, bind to subdired + * - create client + * - connect to server + * - delete socket on fs + * - bind again to subdired + * - connect to server + * - delete socket on fs + */ + ssprintf(filename, "%s/%s", subdir_st, "sk-st"); + if (fill_sock_name(&addr, filename) < 0) { + pr_err("%s is too long for socket\n", filename); + return 1; + } + unlink(addr.sun_path); + + sk_st[0] = sk_alloc_bind(SOCK_STREAM, &addr); + if (sk_st[0] < 0) + return 1; + test_msg("sk-st: alloc/bind/listen %d\n", sk_st[0]); + + if (listen(sk_st[0], 16)) { + pr_perror("Can't listen on socket"); + return 1; + } + + sk_st[1] = sk_alloc_connect(SOCK_STREAM, &addr); + if (sk_st[1] < 0) + return 1; + test_msg("sk-st: alloc/connect %d\n", sk_st[1]); + + len = sizeof(addr_from); + sk_st[2] = accept(sk_st[0], (struct sockaddr *)&addr_from, &len); + if (sk_st[2] < 0) { + pr_perror("Can't accept on socket"); + return 1; + } + test_msg("sk-st: accept %d\n", sk_st[2]); + + sk_st[3] = sk_alloc_connect(SOCK_STREAM, &addr); + if (sk_st[3] < 0) + return 1; + test_msg("sk-st: alloc/connect %d\n", sk_st[3]); + + len = sizeof(addr_from); + sk_st[4] = accept(sk_st[0], (struct sockaddr *)&addr_from, &len); + if (sk_st[4] < 0) { + pr_perror("Can't accept on socket"); + return 1; + } + test_msg("sk-st: accept %d\n", sk_st[4]); + + unlink(addr.sun_path); + + /* + * Drop subdirectory. + */ + rmdir(subdir_st); + + test_daemon(); + test_waitsig(); + + if (write(sk_dgram[1], &c1, 1) != 1 || + read(sk_dgram[0], &c2, 1) != 1 || + write(sk_dgram[3], &c3, 1) != 1 || + read(sk_dgram[2], &c4, 1) != 1) { + fail("Unable to send/receive a message on dgram"); + return 1; + } + + if (c1 != c2 || c3 != c4) { + fail("Vals mismatch on dgram: c1 %d c2 %d c3 %d c4 %d", + c1, c2, c3, c4); + return 1; + } + + if (write(sk_dgram_pair[1], &c9, 1) != 1 || + read(sk_dgram_pair[0], &c10, 1) != 1) { + fail("Unable to send/receive a message on paired dgram"); + return 1; + } + + if (c9 != c10) { + fail("Vals mismatch on dgram: c9 %d c10 %d", + c9, c10); + return 1; + } + + if (write(sk_st[2], &c5, 1) != 1 || + read(sk_st[1], &c6, 1) != 1 || + write(sk_st[4], &c7, 1) != 1 || + read(sk_st[3], &c8, 1) != 1) { + fail("Unable to send/receive a message on stream"); + return 1; + } + + if (c5 != c6 || c7 != c8) { + fail("Vals mismatch on stream: c5 %d c6 %d c7 %d c8 %d", + c5, c6, c7, c8); + return 1; + } + + dir = opendir(subdir_dg); + if (dir != NULL || errno != ENOENT) { + fail("Directory %s is not deteled", subdir_dg); + return 1; + } + + dir = opendir(subdir_st); + if (dir != NULL || errno != ENOENT) { + fail("Directory %s is not deteled", subdir_st); + return 1; + } + + pass(); + return 0; +} diff --git a/test/zdtm/static/sk-unix01.desc b/test/zdtm/static/sk-unix01.desc new file mode 100644 index 000000000..2651c4d77 --- /dev/null +++ b/test/zdtm/static/sk-unix01.desc @@ -0,0 +1 @@ +{'flavor': 'h ns uns', 'flags': 'suid'} From 70e18b846bdc6657a2726780a1717677ca39a304 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 20 Jun 2018 18:13:21 +0300 Subject: [PATCH 1528/4375] zdtm.py: ignore unicode encode errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have a problem after commit 212e4c771a1b ("test: make zdtm.py python2/python3 compatible") when running tests on python2: https://ci.openvz.org/job/CRIU/job/CRIU-virtuozzo/job/criu-dev/3804/console Traceback (most recent call last): File "./test/zdtm.py", line 2249, in opts['action'](opts) File "./test/zdtm.py", line 2001, in run_tests launcher.run_test(t, tdesc, run_flavs) File "./test/zdtm.py", line 1680, in run_test self.wait() File "./test/zdtm.py", line 1737, in wait self.__wait_one(0) File "./test/zdtm.py", line 1725, in __wait_one print(open(sub['log']).read()) UnicodeEncodeError: 'ascii' codec can't encode character u'\u2018' in position 258: ordinal not in range(128) print does not like "‘" symbol in zdtm_static_cgroup04.log: ... rmdir: failed to remove ‘cgclean.sKFHLm/zdtmtst/special_prop_check’: No such file or directory Small reproducer: [snorch@snorch ~]$ cat test_ascii.py from __future__ import absolute_import, division, print_function, unicode_literals from builtins import (str, open, range, zip, int, input) f = open('./zdtm_static_cgroup04.log') s = f.read() print(s) [snorch@snorch ~]$ python test_ascii.py | grep "" Traceback (most recent call last): File "test_ascii.py", line 6, in print(s) UnicodeEncodeError: 'ascii' codec can't encode character u'\u2018' in position 258: ordinal not in range(128) So just ignore these quote symbol when printing logs. Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 3e25f3369..4bc04a655 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1622,7 +1622,7 @@ class Launcher: print(testline, file=self.__file_report) if sub['log']: - print(open(sub['log']).read()) + print(open(sub['log']).read().encode('ascii', 'ignore')) os.unlink(sub['log']) return True From 55d0f98fc9877161534f8a815b5326f2ec068278 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 6 Jun 2018 08:05:05 +0000 Subject: [PATCH 1529/4375] scripts/systemd-autofs-restart.sh: fix variable name The script checks if $NSENTER is executable and sets $NS_ENTER if not. This seems to be a typo (once with '_' and once without). Untested and not reproducible. It just looks wrong. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- scripts/systemd-autofs-restart.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/systemd-autofs-restart.sh b/scripts/systemd-autofs-restart.sh index 162550299..b22078c36 100755 --- a/scripts/systemd-autofs-restart.sh +++ b/scripts/systemd-autofs-restart.sh @@ -27,7 +27,7 @@ if [ ! -d "/proc/$CRTOOLS_INIT_PID" ]; then fi NS_ENTER=/bin/nsenter -[ ! -x $NSENTER ] || NS_ENTER=/usr/bin/nsenter +[ ! -x $NS_ENTER ] || NS_ENTER=/usr/bin/nsenter if [ ! -x $NS_ENTER ]; then echo "$NS_ENTER binary not found" From 3ec82d4b6aa9badbc8f78da95f7375fd050b2953 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Mon, 18 Jun 2018 10:55:35 +0200 Subject: [PATCH 1530/4375] lib/c: add const qualifier to criu_set_service_binary service_binary is either set to a const char * (CR_DEFAULT_SERVICE_BIN) or to a user provided char *, but there is no reason to give a char *. Users of such function will most likely provide a const char *, that will generate a warning. Thus, we add the const qualifier to better represent the usage of service_binary, and avoid such warnings. Signed-off-by: Ronny Chevalier Signed-off-by: Andrei Vagin --- lib/c/criu.c | 6 +++--- lib/c/criu.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/c/criu.c b/lib/c/criu.c index 832a54d10..ff9c9b87e 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -27,7 +27,7 @@ struct criu_opts { union { char *service_address; int service_fd; - char *service_binary; + const char *service_binary; }; int swrk_pid; }; @@ -68,7 +68,7 @@ void criu_set_service_fd(int fd) criu_local_set_service_fd(global_opts, fd); } -void criu_local_set_service_binary(criu_opts *opts, char *path) +void criu_local_set_service_binary(criu_opts *opts, const char *path) { if (path) opts->service_binary = path; @@ -76,7 +76,7 @@ void criu_local_set_service_binary(criu_opts *opts, char *path) opts->service_binary = CR_DEFAULT_SERVICE_BIN; } -void criu_set_service_binary(char *path) +void criu_set_service_binary(const char *path) { criu_local_set_service_binary(global_opts, path); } diff --git a/lib/c/criu.h b/lib/c/criu.h index 5d0b5b6c0..c531016e2 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -43,7 +43,7 @@ enum criu_cg_mode { void criu_set_service_address(char *path); void criu_set_service_fd(int fd); -void criu_set_service_binary(char *path); +void criu_set_service_binary(const char *path); /* * You can choose if you want libcriu to connect to service socket From d71fc8dc08325a2090acd901746de32c7e739b01 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Mon, 18 Jun 2018 10:55:36 +0200 Subject: [PATCH 1531/4375] lib/c: add missing criu_local_set_service_binary signature Signed-off-by: Ronny Chevalier Signed-off-by: Andrei Vagin --- lib/c/criu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/c/criu.h b/lib/c/criu.h index c531016e2..ae8683bc9 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -168,6 +168,7 @@ void criu_local_set_service_fd(criu_opts *opts, int fd); void criu_local_set_pid(criu_opts *opts, int pid); void criu_local_set_images_dir_fd(criu_opts *opts, int fd); /* must be set for dump/restore */ void criu_local_set_parent_images(criu_opts *opts, char *path); +void criu_local_set_service_binary(criu_opts *opts, const char *path); void criu_local_set_work_dir_fd(criu_opts *opts, int fd); void criu_local_set_leave_running(criu_opts *opts, bool leave_running); void criu_local_set_ext_unix_sk(criu_opts *opts, bool ext_unix_sk); From 7ac24b534810d416df0f118811b76e541fec6aa9 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 21 Jun 2018 11:32:53 +0300 Subject: [PATCH 1532/4375] tests: others,rpc -- Tune up header - string.h is missed for memX helpers - fcntl.h should be included instead of sys With this patch the test-c is compiled on alpine tests, but there is a problem related to the container itself | protoc-c --proto_path=. --c_out=. rpc.proto | gcc -g -Werror -Wall -I. -c -o test-c.o test-c.c | gcc -g -Werror -Wall -I. -c -o rpc.pb-c.o rpc.pb-c.c | gcc test-c.o rpc.pb-c.o -lprotobuf-c -o test-c | protoc --proto_path=. --python_out=. rpc.proto | cp ../../../criu/criu criu | chmod u+s criu | mkdir -p build | chmod a+rwx build | sudo -g '#1000' -u '#1000' ./criu service -v4 -W build -o service.log --address criu_service.socket -d --pidfile pidfile | make: sudo: Command not found Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/others/rpc/test-c.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/others/rpc/test-c.c b/test/others/rpc/test-c.c index 490a07a4f..f210a973a 100644 --- a/test/others/rpc/test-c.c +++ b/test/others/rpc/test-c.c @@ -3,7 +3,8 @@ #include #include #include -#include +#include +#include #include #include #include From 829145e00df21cd93066f307590d5a9737aca50a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 21 Jun 2018 19:35:23 +0300 Subject: [PATCH 1533/4375] net: veth -- Don't force to create master peer index if no nsid In case if master peer of veth device is laying inside node root net-ns we should not request device index but rather allow the kernel to number it automatically. When there is separate net-ns for master peer it should be safe to request an index though. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/net.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/criu/net.c b/criu/net.c index 2fa6941bb..cf3ef5cbf 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1251,7 +1251,17 @@ static int veth_link_info(struct ns_id *ns, struct net_link *link, struct newlin peer_data = NLMSG_TAIL(&req->h); memset(&ifm, 0, sizeof(ifm)); - ifm.ifi_index = nde->peer_ifindex; + /* + * Peer index might lay on the node root net namespace, + * where the device index may be already borrowed by + * some other device, so we should ignore it. + * + * Still if peer is laying in some other net-namespace, + * we should recreate the device index as well as the + * as we do for the master peer end. + */ + if (nde->has_peer_nsid) + ifm.ifi_index = nde->peer_ifindex; addattr_l(&req->h, sizeof(*req), VETH_INFO_PEER, &ifm, sizeof(ifm)); veth_peer_info(link, req, ns, ns_fd); From 69faf90c9b7009f7bf8c260e1a2d6717ccba2f31 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 22 Jun 2018 11:48:30 +0100 Subject: [PATCH 1534/4375] README.md correct travis links Signed-off-by: Andrei Vagin --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 42ff4b5bf..abfec1dca 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![master](https://travis-ci.org/xemul/criu.svg?branch=master)](https://travis-ci.org/xemul/criu) -[![development](https://travis-ci.org/xemul/criu.svg?branch=criu-dev)](https://travis-ci.org/xemul/criu) +[![master](https://travis-ci.org/checkpoint-restore/criu.svg?branch=master)](https://travis-ci.org/checkpoint-restore/criu) +[![development](https://travis-ci.org/checkpoint-restore/criu.svg?branch=criu-dev)](https://travis-ci.org/checkpoint-restore/criu) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/55251ec7db28421da4481fc7c1cb0cee)](https://www.codacy.com/app/xemul/criu?utm_source=github.com&utm_medium=referral&utm_content=xemul/criu&utm_campaign=Badge_Grade)

From 339446a7ccaa2571a9e7de501b8167bd34649d6d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 23 Jun 2018 00:36:13 +0300 Subject: [PATCH 1535/4375] unix: test, sk-unix01 -- Fix data sending for be machines Reported-by: Andrey Vagin Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/sk-unix01.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/test/zdtm/static/sk-unix01.c b/test/zdtm/static/sk-unix01.c index c6c199657..2bceef79a 100644 --- a/test/zdtm/static/sk-unix01.c +++ b/test/zdtm/static/sk-unix01.c @@ -78,6 +78,18 @@ static int sk_alloc_connect(int type, struct sockaddr_un *addr) return sk; } +#define write_int(__f, __p) \ + ({ \ + ssize_t __r = write(__f, __p, sizeof(*(__p))); \ + (__r == sizeof(*(__p))) ? 0 : -1; \ + }) + +#define read_int(__f, __p) \ + ({ \ + ssize_t __r = read(__f, __p, sizeof(*(__p))); \ + (__r == sizeof(*(__p))) ? 0 : -1; \ + }) + int main(int argc, char **argv) { int c1 = 1, c2 = 0, c3 = 3, c4 = 0; @@ -310,10 +322,8 @@ int main(int argc, char **argv) test_daemon(); test_waitsig(); - if (write(sk_dgram[1], &c1, 1) != 1 || - read(sk_dgram[0], &c2, 1) != 1 || - write(sk_dgram[3], &c3, 1) != 1 || - read(sk_dgram[2], &c4, 1) != 1) { + if (write_int(sk_dgram[1], &c1) || read_int(sk_dgram[0], &c2) || + write_int(sk_dgram[3], &c3) || read_int(sk_dgram[2], &c4)) { fail("Unable to send/receive a message on dgram"); return 1; } @@ -324,8 +334,8 @@ int main(int argc, char **argv) return 1; } - if (write(sk_dgram_pair[1], &c9, 1) != 1 || - read(sk_dgram_pair[0], &c10, 1) != 1) { + if (write_int(sk_dgram_pair[1], &c9) || + read_int(sk_dgram_pair[0], &c10)) { fail("Unable to send/receive a message on paired dgram"); return 1; } @@ -336,10 +346,8 @@ int main(int argc, char **argv) return 1; } - if (write(sk_st[2], &c5, 1) != 1 || - read(sk_st[1], &c6, 1) != 1 || - write(sk_st[4], &c7, 1) != 1 || - read(sk_st[3], &c8, 1) != 1) { + if (write_int(sk_st[2], &c5) || read_int(sk_st[1], &c6) || + write_int(sk_st[4], &c7) || read_int(sk_st[3], &c8)) { fail("Unable to send/receive a message on stream"); return 1; } From 2e236dcf10f56f39efd285bf90777097fdf251a1 Mon Sep 17 00:00:00 2001 From: Pawel Stradomski Date: Wed, 13 Jun 2018 12:27:37 +0200 Subject: [PATCH 1536/4375] Allow passing ps-socket file descriptor when launching criu. This makes it possible to have the pageserver communication go over anonymous unix sockets, e.g. created by socketpair(). Such setup makes it easier to secure pageserver connection by wrapping it in an encrypted tunnel. It also helps prevent attacks where a malicious process connects to page server and injects its own stream of pages to either fool criu into restoring wrong pages or to DoS the pageserver by having it exhaust local storage by writing large .img files. Signed-off-by: Pawel Stradomski Signed-off-by: Andrei Vagin --- criu/crtools.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/criu/crtools.c b/criu/crtools.c index 238b04a70..bff53fe15 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -311,6 +311,7 @@ int main(int argc, char *argv[], char *envp[]) { "status-fd", required_argument, 0, 1088 }, BOOL_OPT(SK_CLOSE_PARAM, &opts.tcp_close), { "verbosity", optional_argument, 0, 'v' }, + { "ps-socket", required_argument, 0, 1091}, { }, }; @@ -615,6 +616,9 @@ int main(int argc, char *argv[], char *envp[]) return 1; } break; + case 1091: + opts.ps_socket = atoi(optarg); + break; case 'V': pr_msg("Version: %s\n", CRIU_VERSION); if (strcmp(CRIU_GITID, "0")) From e1a5d71765e28b49a8be91a30faa3402b9e18f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Stradomski?= Date: Thu, 28 Jun 2018 16:10:48 +0200 Subject: [PATCH 1537/4375] Add --ps-socket option to Documentation/criu.txt Signed-off-by: Pawel Stradomski Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index ef0105fdd..09a04d782 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -549,6 +549,12 @@ Launches *criu* in page server mode. *--port* 'number':: Page server port number. +*--ps-socket* 'fd':: + Use provided file descriptor as socket for incoming connection. + In this case --address and --port are ignored. + Useful for intercepting page-server traffic e.g. to add encryption + or authentication. + *--lazy-pages*:: Serve local memory dump to a remote *lazy-pages* daemon. In this mode the *page-server* reads local memory dump and allows the From 57ab74c213b999b7409315e81c9bb6d36d84ddc3 Mon Sep 17 00:00:00 2001 From: Pawel Stradomski Date: Thu, 28 Jun 2018 16:22:13 +0200 Subject: [PATCH 1538/4375] Add information about --ps-socket to usage information in crtools.c Signed-off-by: Pawel Stradomski Signed-off-by: Andrei Vagin --- criu/crtools.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/crtools.c b/criu/crtools.c index bff53fe15..c77f7f3c0 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -968,6 +968,7 @@ usage: "Page/Service server options:\n" " --address ADDR address of server or service\n" " --port PORT port of page server\n" +" --ps-socket FD use specified FD as page server socket\n" " -d|--daemon run in the background after creating socket\n" " --status-fd FD write \\0 to the FD and close it once process is ready\n" " to handle requests\n" From b610f28adada6e3b14183f88c45655d21a926cf4 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 6 Apr 2018 10:31:27 +0300 Subject: [PATCH 1539/4375] parse: add a helper to obtain an uptime will be used in the next patch https://jira.sw.ru/browse/PSBM-67502 note: man for /proc/uptime says that uptime is in seconds and for now the format is "seconds.centiseconds", where ecentiseconds is 2 digits note: now uptime is in csec but I prefer saving it in usec, that allows us to be reuse these image field when/if we have more accurate value. v8: add length specifier to parse only centiseconds v9: put uptime to u_int64_t directly, define CSEC_PER_SEC v10: switch to uint64_t from u_int64_t, comment about usec in image Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/include/proc_parse.h | 1 + criu/proc_parse.c | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h index c787cc86b..4e7b6417d 100644 --- a/criu/include/proc_parse.h +++ b/criu/include/proc_parse.h @@ -107,5 +107,6 @@ int parse_children(pid_t pid, pid_t **_c, int *_n); extern bool is_vma_range_fmt(char *line); extern void parse_vmflags(char *buf, u32 *flags, u64 *madv, int *io_pf); +extern int parse_uptime(uint64_t *upt); #endif /* __CR_PROC_PARSE_H__ */ diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 5e1f8529d..3f3dd36dd 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -2629,3 +2629,28 @@ err: xfree(ch); return -1; } + +#define CSEC_PER_SEC 100 + +__maybe_unused int parse_uptime(uint64_t *upt) +{ + unsigned long sec, csec; + FILE *f; + + f = fopen("/proc/uptime", "r"); + if (!f) { + pr_perror("Failed to fopen /proc/uptime"); + return -1; + } + + if (fscanf(f, "%lu.%2lu", &sec, &csec) != 2) { + pr_perror("Failed to parse /proc/uptime"); + fclose(f); + return -1; + } + + *upt = sec * USEC_PER_SEC + csec * (USEC_PER_SEC / CSEC_PER_SEC); + + fclose(f); + return 0; +} From 5451fc230d852d02a8f48f803b39f834e97e1bc4 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 6 Apr 2018 10:31:28 +0300 Subject: [PATCH 1540/4375] inventory: save uptime to know when dump had happened We want to use a simple fact: If we have an alive process in a pstree we want to dump, and a starttime of that process is less than pre-dump's timestamp (taken while all processes were freezed), then these exact process existed (100% sure) at the time of these pre-dump and the process' memory was dumped in images. So save inventory image on pre-dump and put there an uptime. https://jira.sw.ru/browse/PSBM-67502 v9: improve comment, put uptime to ivnentory image as 1) where is no stats in parent images directory if --work-dir option is set to something different then images directory, 2) stats-dump is not an image and it is a bad practice to put there data required for restoring. v10:s/u_int64_t/uint64_t/ Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 6 ++++++ criu/image.c | 11 +++++++++++ criu/include/crtools.h | 1 + criu/proc_parse.c | 2 +- images/inventory.proto | 1 + 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 7a9f479c1..ac8ef5441 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1472,6 +1472,7 @@ static int setup_alarm_handler() static int cr_pre_dump_finish(int ret) { + InventoryEntry he = INVENTORY_ENTRY__INIT; struct pstree_item *item; /* @@ -1480,6 +1481,8 @@ static int cr_pre_dump_finish(int ret) */ if (arch_set_thread_regs(root_item, false) < 0) goto err; + + prepare_inventory_pre_dump(&he); pstree_switch_state(root_item, TASK_ALIVE); timing_stop(TIME_FROZEN); @@ -1527,6 +1530,9 @@ err: if (bfd_flush_images()) ret = -1; + if (write_img_inventory(&he)) + ret = -1; + if (ret) pr_err("Pre-dumping FAILED.\n"); else { diff --git a/criu/image.c b/criu/image.c index 84e6c8af5..e651c0b02 100644 --- a/criu/image.c +++ b/criu/image.c @@ -16,6 +16,7 @@ #include "xmalloc.h" #include "images/inventory.pb-c.h" #include "images/pagemap.pb-c.h" +#include "proc_parse.h" bool ns_per_id = false; bool img_common_magic = true; @@ -105,6 +106,16 @@ int write_img_inventory(InventoryEntry *he) return 0; } +void prepare_inventory_pre_dump(InventoryEntry *he) +{ + pr_info("Perparing image inventory for pre-dump (version %u)\n", CRTOOLS_IMAGES_V1); + + he->img_version = CRTOOLS_IMAGES_V1_1; + + if (!parse_uptime(&he->dump_uptime)) + he->has_dump_uptime = true; +} + int prepare_inventory(InventoryEntry *he) { struct pid pid; diff --git a/criu/include/crtools.h b/criu/include/crtools.h index a78a577cd..88d2220a4 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -12,6 +12,7 @@ extern int check_img_inventory(void); extern int write_img_inventory(InventoryEntry *he); +extern void prepare_inventory_pre_dump(InventoryEntry *he); extern int prepare_inventory(InventoryEntry *he); struct pprep_head { int (*actor)(struct pprep_head *); diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 3f3dd36dd..3a8013866 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -2632,7 +2632,7 @@ err: #define CSEC_PER_SEC 100 -__maybe_unused int parse_uptime(uint64_t *upt) +int parse_uptime(uint64_t *upt) { unsigned long sec, csec; FILE *f; diff --git a/images/inventory.proto b/images/inventory.proto index f1b01f7e8..7bc2b0c02 100644 --- a/images/inventory.proto +++ b/images/inventory.proto @@ -15,4 +15,5 @@ message inventory_entry { optional bool ns_per_id = 4; optional uint32 root_cg_set = 5; optional lsmtype lsmtype = 6; + optional uint64 dump_uptime = 8; } From 9725b7beeb928c8936fcefdd61cd365ff10f6669 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 6 Apr 2018 10:31:29 +0300 Subject: [PATCH 1541/4375] inventory: add a helper to get entry of parent pre-dump will be used in the next patch https://jira.sw.ru/browse/PSBM-67502 note: actually we need only one value from inventory entry but I still prefer general helper as we still need to read and allocate memory for the whole structure v2: fix get_parent_stats to have static typing v3: simplify get_parent_stats to return a StatsEntry pointer instead of doing it through arguments v8: replace errors with warnings, we should whatch on them only if we have corresponding error in detect_pid_reuse else they are fine v9: change stats to inventory image Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/image.c | 37 +++++++++++++++++++++++++++++++++++++ criu/include/crtools.h | 1 + 2 files changed, 38 insertions(+) diff --git a/criu/image.c b/criu/image.c index e651c0b02..8d44649cb 100644 --- a/criu/image.c +++ b/criu/image.c @@ -116,6 +116,43 @@ void prepare_inventory_pre_dump(InventoryEntry *he) he->has_dump_uptime = true; } +__maybe_unused InventoryEntry *get_parent_inventory(void) +{ + struct cr_img *img; + InventoryEntry *ie; + int dir; + + dir = openat(get_service_fd(IMG_FD_OFF), CR_PARENT_LINK, O_RDONLY); + if (dir == -1) { + pr_warn("Failed to open parent directory"); + return NULL; + } + + img = open_image_at(dir, CR_FD_INVENTORY, O_RSTR); + if (!img) { + pr_warn("Failed to open parent pre-dump inventory image"); + close(dir); + return NULL; + } + + if (pb_read_one(img, &ie, PB_INVENTORY) < 0) { + pr_warn("Failed to read parent pre-dump inventory entry"); + close_image(img); + close(dir); + return NULL; + } + + if (!ie->has_dump_uptime) { + pr_warn("Parent pre-dump inventory has no uptime"); + inventory_entry__free_unpacked(ie, NULL); + ie = NULL; + } + + close_image(img); + close(dir); + return ie; +} + int prepare_inventory(InventoryEntry *he) { struct pid pid; diff --git a/criu/include/crtools.h b/criu/include/crtools.h index 88d2220a4..2c21e822a 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -13,6 +13,7 @@ extern int check_img_inventory(void); extern int write_img_inventory(InventoryEntry *he); extern void prepare_inventory_pre_dump(InventoryEntry *he); +extern InventoryEntry *get_parent_inventory(void); extern int prepare_inventory(InventoryEntry *he); struct pprep_head { int (*actor)(struct pprep_head *); From 6fb00f55305a4743723946e52ad8daad837794cd Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 6 Apr 2018 10:31:30 +0300 Subject: [PATCH 1542/4375] memory: don't use parent memdump if detected possible pid reuse We have a problem when a pid is reused between consequent dumps we can't understand if pagemap and pages from images of parent dump are invalid to restore these pid already. That can lead even to wrong memory restored for these pid, see the test in last patch. So these is a try do separate processes with (likely) invalid previous memory dump from processes with 100% valid previous dump. For that we use the value of /proc//stat's start_time and also the timestamp of each (pre)dump. If the start time is strictly less than the timestamp, that means that the pagemap for these pid from previous dump is valid - was done for exactly the same process. Creation time is in centiseconds by default so if predump is really fast (<1csec) we can have false negative decisions for some processes, but in case of long running processes we are fine. https://jira.sw.ru/browse/PSBM-67502 v2: remove __maybe_unused for get_parent_stats; fix get_parent_stats to have static typing; print warning only if unsure; check has_dump_uptime v3: read parent stats from image only once; reuse stat from previous parse_pid_stat call on dump v4: move code to function; use unsigned long long for ticks; put proc_pid_stat on mem_dump_ctl; print warning on all pid-reuse cases v5: free parent's stats entry properly, pass it in arguments to (pre_)dump_one_task v6: free parent's stats in error path too v7: zero init parent_se v8: improve error message v9: switch to inventory image from stats, if pid-reuse fails - fail current dump Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 36 ++++++++++++++++++++++++++++---- criu/image.c | 2 +- criu/include/mem.h | 9 ++++++-- criu/mem.c | 51 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 90 insertions(+), 8 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index ac8ef5441..7794fd92f 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1138,7 +1138,7 @@ err: return ret; } -static int pre_dump_one_task(struct pstree_item *item) +static int pre_dump_one_task(struct pstree_item *item, InventoryEntry *parent_ie) { pid_t pid = item->pid->real; struct vm_area_list vmas; @@ -1197,6 +1197,8 @@ static int pre_dump_one_task(struct pstree_item *item) mdc.pre_dump = true; mdc.lazy = false; + mdc.stat = NULL; + mdc.parent_ie = parent_ie; ret = parasite_dump_pages_seized(item, &vmas, &mdc, parasite_ctl); if (ret) @@ -1215,7 +1217,7 @@ err_cure: goto err_free; } -static int dump_one_task(struct pstree_item *item) +static int dump_one_task(struct pstree_item *item, InventoryEntry *parent_ie) { pid_t pid = item->pid->real; struct vm_area_list vmas; @@ -1357,6 +1359,8 @@ static int dump_one_task(struct pstree_item *item) mdc.pre_dump = false; mdc.lazy = opts.lazy_pages; + mdc.stat = &pps_buf; + mdc.parent_ie = parent_ie; ret = parasite_dump_pages_seized(item, &vmas, &mdc, parasite_ctl); if (ret) @@ -1544,6 +1548,7 @@ err: int cr_pre_dump_tasks(pid_t pid) { + InventoryEntry *parent_ie = NULL; struct pstree_item *item; int ret = -1; @@ -1595,10 +1600,18 @@ int cr_pre_dump_tasks(pid_t pid) if (collect_namespaces(false) < 0) goto err; + /* Errors handled later in detect_pid_reuse */ + parent_ie = get_parent_inventory(); + for_each_pstree_item(item) - if (pre_dump_one_task(item)) + if (pre_dump_one_task(item, parent_ie)) goto err; + if (parent_ie) { + inventory_entry__free_unpacked(parent_ie, NULL); + parent_ie = NULL; + } + ret = cr_dump_shmem(); if (ret) goto err; @@ -1608,6 +1621,9 @@ int cr_pre_dump_tasks(pid_t pid) ret = 0; err: + if (parent_ie) + inventory_entry__free_unpacked(parent_ie, NULL); + return cr_pre_dump_finish(ret); } @@ -1721,6 +1737,7 @@ static int cr_dump_finish(int ret) int cr_dump_tasks(pid_t pid) { InventoryEntry he = INVENTORY_ENTRY__INIT; + InventoryEntry *parent_ie = NULL; struct pstree_item *item; int pre_dump_ret = 0; int ret = -1; @@ -1808,11 +1825,19 @@ int cr_dump_tasks(pid_t pid) if (collect_seccomp_filters() < 0) goto err; + /* Errors handled later in detect_pid_reuse */ + parent_ie = get_parent_inventory(); + for_each_pstree_item(item) { - if (dump_one_task(item)) + if (dump_one_task(item, parent_ie)) goto err; } + if (parent_ie) { + inventory_entry__free_unpacked(parent_ie, NULL); + parent_ie = NULL; + } + /* * It may happen that a process has completed but its files in * /proc/PID/ are still open by another process. If the PID has been @@ -1870,5 +1895,8 @@ int cr_dump_tasks(pid_t pid) if (ret) goto err; err: + if (parent_ie) + inventory_entry__free_unpacked(parent_ie, NULL); + return cr_dump_finish(ret); } diff --git a/criu/image.c b/criu/image.c index 8d44649cb..243e4a1a2 100644 --- a/criu/image.c +++ b/criu/image.c @@ -116,7 +116,7 @@ void prepare_inventory_pre_dump(InventoryEntry *he) he->has_dump_uptime = true; } -__maybe_unused InventoryEntry *get_parent_inventory(void) +InventoryEntry *get_parent_inventory(void) { struct cr_img *img; InventoryEntry *ie; diff --git a/criu/include/mem.h b/criu/include/mem.h index bb897c599..251cb1a9e 100644 --- a/criu/include/mem.h +++ b/criu/include/mem.h @@ -4,6 +4,9 @@ #include #include "int.h" #include "vma.pb-c.h" +#include "pid.h" +#include "proc_parse.h" +#include "inventory.pb-c.h" struct parasite_ctl; struct vm_area_list; @@ -12,8 +15,10 @@ struct pstree_item; struct vma_area; struct mem_dump_ctl { - bool pre_dump; - bool lazy; + bool pre_dump; + bool lazy; + struct proc_pid_stat *stat; + InventoryEntry *parent_ie; }; extern bool vma_has_guard_gap_hidden(struct vma_area *vma); diff --git a/criu/mem.c b/criu/mem.c index 9909ef09d..c747785f1 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -290,6 +290,46 @@ static int xfer_pages(struct page_pipe *pp, struct page_xfer *xfer) return ret; } +static int detect_pid_reuse(struct pstree_item *item, + struct proc_pid_stat* pps, + InventoryEntry *parent_ie) +{ + unsigned long long dump_ticks; + struct proc_pid_stat pps_buf; + unsigned long long tps; /* ticks per second */ + int ret; + + tps = sysconf(_SC_CLK_TCK); + if (tps == -1) { + pr_perror("Failed to get clock ticks via sysconf"); + return -1; + } + + if (!pps) { + pps = &pps_buf; + ret = parse_pid_stat(item->pid->real, pps); + if (ret < 0) + return -1; + } + + if (!parent_ie) { + pr_err("Pid-reuse detection failed: no parent inventory, " \ + "check warnings in get_parent_stats\n"); + return -1; + } + + dump_ticks = parent_ie->dump_uptime/(USEC_PER_SEC/tps); + + if (pps->start_time >= dump_ticks) { + /* Print "*" if unsure */ + pr_warn("Pid reuse%s detected for pid %d\n", + pps_buf.start_time == dump_ticks ? "*" : "", + item->pid->real); + return 1; + } + return 0; +} + static int __parasite_dump_pages_seized(struct pstree_item *item, struct parasite_dump_pages_args *args, struct vm_area_list *vma_area_list, @@ -303,6 +343,7 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, int ret, exit_code = -1; unsigned cpp_flags = 0; unsigned long pmc_size; + int possible_pid_reuse = 0; pr_info("\n"); pr_info("Dumping pages (type: %d pid: %d)\n", CR_FD_PAGES, item->pid->real); @@ -356,6 +397,14 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, xfer.parent = NULL + 1; } + if (xfer.parent) { + possible_pid_reuse = detect_pid_reuse(item, mdc->stat, + mdc->parent_ie); + if (possible_pid_reuse == -1) + goto out_xfer; + } + + /* * Step 1 -- generate the pagemap */ @@ -382,7 +431,7 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, else { again: ret = generate_iovs(vma_area, pp, map, &off, - has_parent); + has_parent && !possible_pid_reuse); if (ret == -EAGAIN) { BUG_ON(!(pp->flags & PP_CHUNK_MODE)); From e071c2a6102e34644ac7691c7eb6e21126ea578e Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 6 Apr 2018 10:31:31 +0300 Subject: [PATCH 1543/4375] zdtm/lib: add pre-dump-notify test flag If pre-dump-notify flag is set, zdtm sends a notify to the test after pre-dump was finished and waits for the test to send back a reply that test did all it's work and now is ready for a next pre-dump/dump. How it can be used: while (!test_wait_pre_dump()) { /* Do something after predump */ test_wait_pre_dump_ack(); } /* Do something after restore */ Internally we open two pipes for the test one for receiving notify (with two open ends) and one for replying to it (only write end open). Fds of pipes are dupped to predefined numbers and zdtm opens these fds through /proc//fd/{100,101} and communicates with the test. v9: switch to two way interface to remove race then operation we try to run after predump may be yet unfinished at the time of next dump. Suggested-by: Andrei Vagin Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm.py | 27 +++++++++++ test/zdtm/lib/ns.c | 7 +++ test/zdtm/lib/ns.h | 2 + test/zdtm/lib/test.c | 100 ++++++++++++++++++++++++++++++++++++++++ test/zdtm/lib/zdtmtst.h | 4 ++ 5 files changed, 140 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index 4bc04a655..9122ad9c7 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -23,6 +23,7 @@ import fcntl import errno import datetime import yaml +import struct import pycriu as crpc os.chdir(os.path.dirname(os.path.abspath(__file__))) @@ -411,6 +412,10 @@ class zdtm_test: if not self.__freezer.kernel: env['ZDTM_THREAD_BOMB'] = "5" + if test_flag(self.__desc, 'pre-dump-notify'): + env['ZDTM_NOTIFY_FDIN'] = "100" + env['ZDTM_NOTIFY_FDOUT'] = "101" + if not test_flag(self.__desc, 'suid'): # Numbers should match those in criu env['ZDTM_UID'] = "18943" @@ -456,6 +461,27 @@ class zdtm_test: self.__flavor.fini() + def pre_dump_notify(self): + env = self._env + + if 'ZDTM_NOTIFY_FDIN' not in env: + return + + if self.__pid == 0: + self.getpid() + + notify_fdout_path = "/proc/%s/fd/%s" % (self.__pid, env['ZDTM_NOTIFY_FDOUT']) + notify_fdin_path = "/proc/%s/fd/%s" % (self.__pid, env['ZDTM_NOTIFY_FDIN']) + + print "Send pre-dump notify to %s" % (self.__pid) + with open(notify_fdout_path) as fdout: + with open(notify_fdin_path, "w") as fdin: + fdin.write(struct.pack("i", 0)) + fdin.flush() + print "Wait pre-dump notify reply" + ret = struct.unpack('i', fdout.read(4)) + print "Completed pre-dump notify with %d" % (ret) + def stop(self): self.__freezer.thaw() self.getpid() # Read the pid from pidfile back @@ -1176,6 +1202,7 @@ def cr(cr_api, test, opts): else: cr_api.dump("pre-dump") try_run_hook(test, ["--post-pre-dump"]) + test.pre_dump_notify() time.sleep(pres[1]) sbs('pre-dump') diff --git a/test/zdtm/lib/ns.c b/test/zdtm/lib/ns.c index f758061c5..6b4a75399 100644 --- a/test/zdtm/lib/ns.c +++ b/test/zdtm/lib/ns.c @@ -19,6 +19,8 @@ #include "zdtmtst.h" #include "ns.h" +int criu_status_in = -1, criu_status_in_peer = -1, criu_status_out = -1; + extern int pivot_root(const char *new_root, const char *put_old); static int prepare_mntns(void) { @@ -251,6 +253,11 @@ int ns_init(int argc, char **argv) exit(1); } + if (init_notify()) { + fprintf(stderr, "Can't init pre-dump notification: %m"); + exit(1); + } + reap = getenv("ZDTM_NOREAP") == NULL; sigemptyset(&sa.sa_mask); diff --git a/test/zdtm/lib/ns.h b/test/zdtm/lib/ns.h index 23378bc60..40cc1e0c3 100644 --- a/test/zdtm/lib/ns.h +++ b/test/zdtm/lib/ns.h @@ -12,4 +12,6 @@ extern int ns_init(int argc, char **argv); extern void test_waitsig(void); extern void parseargs(int, char **); +extern int init_notify(void); + #endif diff --git a/test/zdtm/lib/test.c b/test/zdtm/lib/test.c index 2c3108850..70e8ad605 100644 --- a/test/zdtm/lib/test.c +++ b/test/zdtm/lib/test.c @@ -33,11 +33,14 @@ enum { static int parent; +extern int criu_status_in, criu_status_in_peer, criu_status_out; + static void sig_hand(int signo) { if (parent) futex_set_and_wake(&test_shared_state->stage, TEST_FAIL_STAGE); futex_set_and_wake(&sig_received, signo); + close(criu_status_in); } static char *outfile; @@ -111,6 +114,63 @@ void test_ext_init(int argc, char **argv) exit(1); } +#define PIPE_RD 0 +#define PIPE_WR 1 + +int init_notify(void) +{ + char *val; + int ret; + int p[2]; + + val = getenv("ZDTM_NOTIFY_FDIN"); + if (!val) + return 0; + criu_status_in = atoi(val); + + val = getenv("ZDTM_NOTIFY_FDOUT"); + if (!val) + return -1; + criu_status_out = atoi(val); + + if (pipe(p)) { + fprintf(stderr, "Unable to create a pipe: %m\n"); + return -1; + } + criu_status_in_peer = p[PIPE_WR]; + + ret = dup2(p[PIPE_RD], criu_status_in); + if (ret < 0) { + fprintf(stderr, "dup2() failed: %m\n"); + close(p[PIPE_RD]); + close(p[PIPE_WR]); + return -1; + } + close(p[PIPE_RD]); + + if (pipe(p)) { + fprintf(stderr, "Unable to create a pipe: %m\n"); + goto err_pipe_in; + } + close(p[PIPE_RD]); + + ret = dup2(p[PIPE_WR], criu_status_out); + if (ret < 0) { + fprintf(stderr, "dup2() failed: %m\n"); + goto err_pipe_out; + } + + close(p[PIPE_WR]); + return 0; +err_pipe_out: + close(p[PIPE_RD]); + close(p[PIPE_WR]); +err_pipe_in: + close(criu_status_in); + close(criu_status_in_peer); + return -1; +} + int write_pidfile(int pid) { int fd = -1; @@ -172,6 +232,9 @@ void test_init(int argc, char **argv) redir_stdfds(); ns_init(argc, argv); } + } else if (init_notify()) { + fprintf(stderr, "Can't init pre-dump notification: %m"); + exit(1); } val = getenv("ZDTM_GROUPS"); @@ -297,6 +360,43 @@ void test_waitsig(void) futex_wait_while(&sig_received, 0); } +int test_wait_pre_dump(void) +{ + int ret; + + if (criu_status_in < 0) { + pr_err("Fd criu_status_in is not initialized\n"); + return -1; + } + + if (read(criu_status_in, &ret, sizeof(ret)) != sizeof(ret)) { + if (errno != EBADF || !futex_get(&sig_received)) + pr_perror("Can't wait pre-dump\n"); + return -1; + } + pr_err("pre-dump\n"); + + return 0; +} + +int test_wait_pre_dump_ack(void) +{ + int ret = 0; + + if (criu_status_out < 0) { + pr_err("Fd criu_status_out is not initialized\n"); + return -1; + } + + pr_err("pre-dump-ack\n"); + if (write(criu_status_out, &ret, sizeof(ret)) != sizeof(ret)) { + pr_perror("Can't reply to pre-dump notify"); + return -1; + } + + return 0; +} + pid_t sys_clone_unified(unsigned long flags, void *child_stack, void *parent_tid, void *child_tid, unsigned long newtls) { diff --git a/test/zdtm/lib/zdtmtst.h b/test/zdtm/lib/zdtmtst.h index dbe825cbc..1fbf795bf 100644 --- a/test/zdtm/lib/zdtmtst.h +++ b/test/zdtm/lib/zdtmtst.h @@ -41,6 +41,10 @@ extern void test_msg(const char *format, ...) extern int test_go(void); /* sleep until SIGTERM is delivered */ extern void test_waitsig(void); +/* sleep until zdtm notifies about predump */ +extern int test_wait_pre_dump(void); +/* notify zdtm that we finished action after predump */ +extern int test_wait_pre_dump_ack(void); #include From f525d4176396965c4a02e3661261d24208648d09 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 7 May 2018 11:42:41 +0300 Subject: [PATCH 1544/4375] seccomp: compel -- Add PTRACE_SECCOMP_GET_METADATA definition We will use it to figure out if filter log target is used. Metadata associated with seccomp filter is relatively new feature which allows userspace to get and set it back. Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/include/uapi/ptrace.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/compel/include/uapi/ptrace.h b/compel/include/uapi/ptrace.h index 7024efef3..fcc2d62b0 100644 --- a/compel/include/uapi/ptrace.h +++ b/compel/include/uapi/ptrace.h @@ -8,6 +8,7 @@ * so there is no way they can be used together. Let's rely on libc one. */ #include +#include #include @@ -49,6 +50,16 @@ #define PTRACE_SECCOMP_GET_FILTER 0x420c #endif +#ifndef PTRACE_SECCOMP_GET_METADATA +# define PTRACE_SECCOMP_GET_METADATA 0x420d + +struct seccomp_metadata { + uint64_t filter_off; /* Input: which filter */ + uint64_t flags; /* Output: filter's flags */ +}; + +#endif /* PTRACE_SECCOMP_GET_METADATA */ + #ifdef PTRACE_EVENT_STOP # if PTRACE_EVENT_STOP == 7 /* Bad value from Linux 3.1-3.3, fixed in 3.4 */ # undef PTRACE_EVENT_STOP From 532d27989a5d09cc07f8bbc05164d7371d4db376 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 7 May 2018 11:42:42 +0300 Subject: [PATCH 1545/4375] seccomp: Define log prefix For grepability sake in logs. Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/seccomp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/seccomp.c b/criu/seccomp.c index 6416e793c..673812b4d 100644 --- a/criu/seccomp.c +++ b/criu/seccomp.c @@ -18,6 +18,9 @@ #include "protobuf.h" #include "images/seccomp.pb-c.h" +#undef LOG_PREFIX +#define LOG_PREFIX "seccomp: " + /* populated on dump during collect_seccomp_filters() */ static int next_filter_id = 0; static struct seccomp_info **filters = NULL; From 2810c2588833596e4f8cf1e910096527e7c79d57 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 7 May 2018 11:42:43 +0300 Subject: [PATCH 1546/4375] seccomp: Move seccomp_info into seccomp.h This header is main place for all seccomp related structures so move seccomp_info here. This will allow to minimize changes area when need to update definitions and such. Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/proc_parse.h | 7 ------- criu/include/seccomp.h | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h index 4e7b6417d..96a097b3d 100644 --- a/criu/include/proc_parse.h +++ b/criu/include/proc_parse.h @@ -4,7 +4,6 @@ #include #include -#include "images/seccomp.pb-c.h" #define PROC_TASK_COMM_LEN 32 #define PROC_TASK_COMM_LEN_FMT "(%31s" @@ -64,12 +63,6 @@ struct proc_pid_stat { int exit_code; }; -struct seccomp_info { - SeccompFilter filter; - int id; - struct seccomp_info *prev; -}; - #define PROC_CAP_SIZE 2 struct proc_status_creds { diff --git a/criu/include/seccomp.h b/criu/include/seccomp.h index 42ab9ab2d..b50ea34e2 100644 --- a/criu/include/seccomp.h +++ b/criu/include/seccomp.h @@ -4,6 +4,7 @@ #include #include +#include "images/seccomp.pb-c.h" #include "images/core.pb-c.h" #ifndef SECCOMP_MODE_DISABLED @@ -26,6 +27,12 @@ #define SECCOMP_FILTER_FLAG_TSYNC 1 #endif +struct seccomp_info { + struct seccomp_info *prev; + int id; + SeccompFilter filter; +}; + extern int collect_seccomp_filters(void); extern int prepare_seccomp_filters(void); struct task_restore_args; From 64073bdee5ec5b2d4a1231c9b17a76aa736b5ba1 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 7 May 2018 11:42:44 +0300 Subject: [PATCH 1547/4375] seccomp: Fetch seccomp flags if kernel provides Note that there is no real usage of this flag on restore, we simply save it in image and will make a real use later. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/seccomp.c | 39 +++++++++++++++++++++++++++++++++++++-- images/seccomp.proto | 1 + 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/criu/seccomp.c b/criu/seccomp.c index 673812b4d..c8cd35f9a 100644 --- a/criu/seccomp.c +++ b/criu/seccomp.c @@ -26,7 +26,8 @@ static int next_filter_id = 0; static struct seccomp_info **filters = NULL; static struct seccomp_info *find_inherited(struct pstree_item *parent, - struct sock_filter *filter, int len) + struct sock_filter *filter, + int len, struct seccomp_metadata *meta) { struct seccomp_info *info; @@ -38,6 +39,12 @@ static struct seccomp_info *find_inherited(struct pstree_item *parent, if (len != info->filter.filter.len) continue; + if (!!meta ^ !!info->filter.has_flags) + continue; + if (info->filter.has_flags && meta) { + if (info->filter.flags != meta->flags) + continue; + } if (!memcmp(filter, info->filter.filter.data, len)) return info; } @@ -47,6 +54,7 @@ static struct seccomp_info *find_inherited(struct pstree_item *parent, static int collect_filter_for_pstree(struct pstree_item *item) { + struct seccomp_metadata meta_buf, *meta = &meta_buf; struct seccomp_info *infos = NULL, *cursor; int info_count, i, ret = -1; struct sock_filter buf[BPF_MAXINSNS]; @@ -75,7 +83,29 @@ static int collect_filter_for_pstree(struct pstree_item *item) } } - inherited = find_inherited(item->parent, buf, len); + if (!meta) + meta = &meta_buf; + + meta->flags = 0; + meta->filter_off = i; + + if (ptrace(PTRACE_SECCOMP_GET_METADATA, item->pid->real, sizeof(meta), meta) < 0) { + if (errno == EIO) { + /* + * No PTRACE_SECCOMP_GET_METADATA support in + * kernel detected, thus simply ignore. Moving + * it into kerndat is preferred but not + * required. + */ + meta = NULL; + } else { + pr_perror("couldn't fetch seccomp metadata: pid %d pos %d", + item->pid->real, i); + goto out; + } + } + + inherited = find_inherited(item->parent, buf, len, meta); if (inherited) { bool found = false; @@ -99,6 +129,11 @@ static int collect_filter_for_pstree(struct pstree_item *item) goto out; seccomp_filter__init(&info->filter); + if (meta) { + info->filter.has_flags = true; + info->filter.flags = meta->flags; + } + info->filter.filter.len = len * sizeof(struct sock_filter); info->filter.filter.data = xmalloc(info->filter.filter.len); if (!info->filter.filter.data) { diff --git a/images/seccomp.proto b/images/seccomp.proto index 565a7cdd4..177e5fd4a 100644 --- a/images/seccomp.proto +++ b/images/seccomp.proto @@ -3,6 +3,7 @@ syntax = "proto2"; message seccomp_filter { required bytes filter = 1; optional uint32 prev = 2; + optional uint32 flags = 3; } message seccomp_entry { From 0f5cce7a4e3d1a2e46691c87986eee1593675ec5 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 7 May 2018 11:42:45 +0300 Subject: [PATCH 1548/4375] seccomp: Add engine to restore per-thread seccomp chains At now we pretend that all threads are sharing seccomp chains and at checkpoint moment we test seccomp modes to make sure if this assumption is valid refusing to dump otherwise. Still the kernel tacks seccomp filter chains per each thread and now we've faced applications (such as java) where per-thread chains are actively used. Thus we need to bring support of handling filters via per-thread basis. In this a bit intrusive patch the restore engine is lifted up to treat each thread separately. Here what is done: - Image core file is modified to keep seccomp filters inside thread_core_entry. For backward compatibility former seccomp_mode and seccomp_filter members in task_core_entry are renamed to have old_ prefix and on restore we test if we're dealing with old images. Since per-thread dump is not yet implemeneted the dumping procedure continue operating with old_ members. - In pie restorer code memory containing filters are addressed from inside thread_restore_args structure which now contains seccomp mode itself and chain attributes (number of filters and etc). Reading of per-thread data is done in seccomp_prepare_threads helper -- we take one pstree_item and walks over every thread inside to allocate pie memory and pin data there. Because of PIE specific, before jumping into pie code we have to relocate this memory into new place and for this seccomp_rst_reloc is served. In restorer itself we check if thread_restore_args provides us enabled seccomp mode (strict or filter passed) and call for restore_seccomp_filter if needed. - To unify names we start using seccomp_ prefix for all related stuff involved into this change (prepare_seccomp_filters renamed to seccomp_read_image because it only reads image and nothing more, image handler is renamed to seccomp_img_entry instead of too short 'se'. With this change we're now allowed to start collecting and dumping seccomp filters per each thread, which will be done in next patch. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 8 +- criu/cr-restore.c | 33 ++++++-- criu/include/restorer.h | 16 +++- criu/include/rst_info.h | 5 ++ criu/include/seccomp.h | 10 ++- criu/pie/restorer.c | 124 +++++++++++++++++----------- criu/seccomp.c | 175 +++++++++++++++++++++++++++------------- images/core.proto | 8 +- 8 files changed, 258 insertions(+), 121 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 7794fd92f..6dc3d9ddc 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -745,12 +745,12 @@ static int dump_task_core_all(struct parasite_ctl *ctl, creds = dmpi(item)->pi_creds; if (creds->s.seccomp_mode != SECCOMP_MODE_DISABLED) { pr_info("got seccomp mode %d for %d\n", creds->s.seccomp_mode, vpid(item)); - core->tc->has_seccomp_mode = true; - core->tc->seccomp_mode = creds->s.seccomp_mode; + core->tc->has_old_seccomp_mode = true; + core->tc->old_seccomp_mode = creds->s.seccomp_mode; if (creds->s.seccomp_mode == SECCOMP_MODE_FILTER) { - core->tc->has_seccomp_filter = true; - core->tc->seccomp_filter = creds->last_filter; + core->tc->has_old_seccomp_filter = true; + core->tc->old_seccomp_filter = creds->last_filter; } } diff --git a/criu/cr-restore.c b/criu/cr-restore.c index ea2066eec..781220ca1 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -330,7 +330,7 @@ static int root_prepare_shared(void) if (prepare_remaps()) return -1; - if (prepare_seccomp_filters()) + if (seccomp_read_image()) return -1; if (collect_images(cinfos, ARRAY_SIZE(cinfos))) @@ -887,7 +887,7 @@ static int restore_one_alive_task(int pid, CoreEntry *core) if (prepare_timerfds(ta)) return -1; - if (seccomp_filters_get_rst_pos(core, ta) < 0) + if (seccomp_prepare_threads(current, ta) < 0) return -1; if (prepare_itimers(pid, ta, core) < 0) @@ -1086,6 +1086,21 @@ static int check_core(CoreEntry *core, struct pstree_item *me) pr_err("Core info data missed for non-zombie\n"); goto out; } + + /* + * Seccomp are moved to per-thread origin, + * so for old images we need to move per-task + * data into proper place. + */ + if (core->tc->has_old_seccomp_mode) { + core->thread_core->has_seccomp_mode = core->tc->has_old_seccomp_mode; + core->thread_core->seccomp_mode = core->tc->old_seccomp_mode; + } + if (core->tc->has_old_seccomp_filter) { + core->thread_core->has_seccomp_filter = core->tc->has_old_seccomp_filter; + core->thread_core->seccomp_filter = core->tc->old_seccomp_filter; + rsti(me)->has_old_seccomp_filter = true; + } } ret = 0; @@ -1273,13 +1288,16 @@ static inline int fork_with_pid(struct pstree_item *item) item->pid->state = ca.core->tc->task_state; rsti(item)->cg_set = ca.core->tc->cg_set; - rsti(item)->has_seccomp = ca.core->tc->seccomp_mode != SECCOMP_MODE_DISABLED; - if (item->pid->state != TASK_DEAD && !task_alive(item)) { pr_err("Unknown task state %d\n", item->pid->state); return -1; } + if (item->pid->state != TASK_DEAD) + rsti(item)->has_seccomp = ca.core->thread_core->seccomp_mode != SECCOMP_MODE_DISABLED; + else + rsti(item)->has_seccomp = false; + if (unlikely(item == root_item)) maybe_clone_parent(item, &ca); } else { @@ -3338,12 +3356,8 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns RST_MEM_FIXUP_PPTR(task_args->rlims); RST_MEM_FIXUP_PPTR(task_args->helpers); RST_MEM_FIXUP_PPTR(task_args->zombies); - RST_MEM_FIXUP_PPTR(task_args->seccomp_filters); RST_MEM_FIXUP_PPTR(task_args->vma_ios); - if (core->tc->has_seccomp_mode) - task_args->seccomp_mode = core->tc->seccomp_mode; - task_args->compatible_mode = core_is_compat(core); /* * Arguments for task restoration. @@ -3417,6 +3431,9 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns if (ret) goto err; + seccomp_rst_reloc(&thread_args[i]); + thread_args[i].seccomp_force_tsync = rsti(current)->has_old_seccomp_filter; + thread_args[i].mz = mz + i; sigframe = (struct rt_sigframe *)&mz[i].rt_sigframe; diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 036d736ef..40b6da0f9 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "common/config.h" #include "types.h" @@ -75,6 +76,11 @@ struct thread_creds_args { unsigned long mem_pos_next; }; +struct thread_seccomp_filter { + struct sock_fprog sock_fprog; + unsigned int flags; +}; + struct thread_restore_args { struct restore_mem_zone *mz; @@ -97,6 +103,13 @@ struct thread_restore_args { int pdeath_sig; struct thread_creds_args *creds_args; + + int seccomp_mode; + unsigned long seccomp_filters_pos; + struct thread_seccomp_filter *seccomp_filters; + void *seccomp_filters_data; + unsigned int seccomp_filters_n; + bool seccomp_force_tsync; } __aligned(64); typedef long (*thread_restore_fcall_t) (struct thread_restore_args *args); @@ -160,9 +173,6 @@ struct task_restore_args { pid_t *zombies; unsigned int zombies_n; - struct sock_fprog *seccomp_filters; - unsigned int seccomp_filters_n; - /* * * * * * * * * * * * * * * * * * * * */ unsigned long task_size; diff --git a/criu/include/rst_info.h b/criu/include/rst_info.h index 336c08b6b..aba05b911 100644 --- a/criu/include/rst_info.h +++ b/criu/include/rst_info.h @@ -60,6 +60,11 @@ struct rst_info { * restorer blob. */ bool has_seccomp; + /* + * To be compatible with old images where filters + * are bound to group leader and we need to use tsync flag. + */ + bool has_old_seccomp_filter; bool has_thp_enabled; diff --git a/criu/include/seccomp.h b/criu/include/seccomp.h index b50ea34e2..0791597fe 100644 --- a/criu/include/seccomp.h +++ b/criu/include/seccomp.h @@ -27,6 +27,9 @@ #define SECCOMP_FILTER_FLAG_TSYNC 1 #endif +struct thread_restore_args; +struct task_restore_args; + struct seccomp_info { struct seccomp_info *prev; int id; @@ -35,6 +38,9 @@ struct seccomp_info { extern int collect_seccomp_filters(void); extern int prepare_seccomp_filters(void); -struct task_restore_args; -extern int seccomp_filters_get_rst_pos(CoreEntry *item, struct task_restore_args *); + +extern int seccomp_read_image(void); +extern int seccomp_prepare_threads(struct pstree_item *item, struct task_restore_args *ta); +extern void seccomp_rst_reloc(struct thread_restore_args *thread_arg); + #endif diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 1b6e824ae..b4d2d6583 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -394,54 +394,82 @@ static int restore_signals(siginfo_t *ptr, int nr, bool group) return 0; } -static int restore_seccomp(struct task_restore_args *args) +static int restore_seccomp_filter(pid_t tid, struct thread_restore_args *args) { + unsigned int flags = args->seccomp_force_tsync ? SECCOMP_FILTER_FLAG_TSYNC : 0; + size_t i; int ret; - switch (args->seccomp_mode) { - case SECCOMP_MODE_DISABLED: - return 0; - case SECCOMP_MODE_STRICT: - ret = sys_prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, 0, 0, 0); + for (i = 0; i < args->seccomp_filters_n; i++) { + struct thread_seccomp_filter *filter = &args->seccomp_filters[i]; + + pr_debug("seccomp: Restoring mode %d flags %x on tid %d filter %d\n", + SECCOMP_SET_MODE_FILTER, (filter->flags | flags), tid, (int)i); + + ret = sys_seccomp(SECCOMP_SET_MODE_FILTER, filter->flags | flags, (void *)&filter->sock_fprog); if (ret < 0) { - pr_err("prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT) returned %d\n", ret); - goto die; - } - return 0; - case SECCOMP_MODE_FILTER: { - int i; - void *filter_data; - - filter_data = &args->seccomp_filters[args->seccomp_filters_n]; - - for (i = 0; i < args->seccomp_filters_n; i++) { - struct sock_fprog *fprog = &args->seccomp_filters[i]; - - fprog->filter = filter_data; - - /* We always TSYNC here, since we require that the - * creds for all threads be the same; this means we - * don't have to restore_seccomp() in threads, and that - * future TSYNC behavior will be correct. - */ - ret = sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, (char *) fprog); - if (ret < 0) { - pr_err("sys_seccomp() returned %d\n", ret); - goto die; + if (ret == -ENOSYS) { + pr_debug("seccomp: sys_seccomp is not supported in kernel, " + "switching to prctl interface\n"); + ret = sys_prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, + (long)(void *)&filter->sock_fprog, 0, 0); + if (ret) { + pr_err("seccomp: PR_SET_SECCOMP returned %d on tid %d\n", + ret, tid); + return -1; + } + } else { + pr_err("seccomp: SECCOMP_SET_MODE_FILTER returned %d on tid %d\n", + ret, tid); + return -1; } - - filter_data += fprog->len * sizeof(struct sock_filter); } - - return 0; - } - default: - goto die; } return 0; -die: - return -1; +} + +static int restore_seccomp(struct thread_restore_args *args) +{ + pid_t tid; + int ret; + + tid = args->pid; + + if (tid != sys_gettid()) { + pr_err("seccomp: Unexpected tid %d != %d\n", + tid, (pid_t)sys_gettid()); + return -1; + } + + switch (args->seccomp_mode) { + case SECCOMP_MODE_DISABLED: + pr_debug("seccomp: mode %d on tid %d\n", SECCOMP_MODE_DISABLED, tid); + return 0; + break; + case SECCOMP_MODE_STRICT: + ret = sys_prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, 0, 0, 0); + if (ret < 0) { + pr_err("seccomp: SECCOMP_MODE_STRICT returned %d on tid %d\n", + ret, tid); + } + break; + case SECCOMP_MODE_FILTER: + ret = restore_seccomp_filter(tid, args); + break; + default: + pr_err("seccomp: Unknown seccomp mode %d on tid %d\n", + args->seccomp_mode, tid); + ret = -1; + break; + } + + if (!ret) { + pr_debug("seccomp: Restored mode %d on tid %d\n", + args->seccomp_mode, tid); + } + + return ret; } static int restore_robust_futex(struct thread_restore_args *args) @@ -525,6 +553,13 @@ long __export_restore_thread(struct thread_restore_args *args) if (restore_thread_common(args)) goto core_restore_end; + /* + * Make sure it's before creds, since it's privileged + * operation bound to uid 0 in current user ns. + */ + if (restore_seccomp(args)) + goto core_restore_end; + ret = restore_creds(args->creds_args, args->ta->proc_fd); if (ret) goto core_restore_end; @@ -543,9 +578,6 @@ long __export_restore_thread(struct thread_restore_args *args) restore_finish_stage(task_entries_local, CR_STATE_RESTORE_SIGCHLD); restore_pdeath_sig(args); - if (args->ta->seccomp_mode != SECCOMP_MODE_DISABLED) - pr_info("Restoring seccomp mode %d for %ld\n", args->ta->seccomp_mode, sys_getpid()); - restore_finish_stage(task_entries_local, CR_STATE_RESTORE_CREDS); futex_dec_and_wake(&thread_inprogress); @@ -1643,11 +1675,11 @@ long __export_restore_task(struct task_restore_args *args) rst_tcp_socks_all(args); - /* The kernel restricts setting seccomp to uid 0 in the current user - * ns, so we must do this before restore_creds. + /* + * Make sure it's before creds, since it's privileged + * operation bound to uid 0 in current user ns. */ - pr_info("restoring seccomp mode %d for %ld\n", args->seccomp_mode, sys_getpid()); - if (restore_seccomp(args)) + if (restore_seccomp(args->t)) goto core_restore_end; /* diff --git a/criu/seccomp.c b/criu/seccomp.c index c8cd35f9a..9b779c80f 100644 --- a/criu/seccomp.c +++ b/criu/seccomp.c @@ -21,6 +21,8 @@ #undef LOG_PREFIX #define LOG_PREFIX "seccomp: " +static SeccompEntry *seccomp_img_entry; + /* populated on dump during collect_seccomp_filters() */ static int next_filter_id = 0; static struct seccomp_info **filters = NULL; @@ -233,10 +235,8 @@ int collect_seccomp_filters(void) return 0; } -/* Populated on restore by prepare_seccomp_filters */ -static SeccompEntry *se; - -int prepare_seccomp_filters(void) +/* The seccomp_img_entry will be shared between all children */ +int seccomp_read_image(void) { struct cr_img *img; int ret; @@ -245,66 +245,129 @@ int prepare_seccomp_filters(void) if (!img) return -1; - ret = pb_read_one_eof(img, &se, PB_SECCOMP); + ret = pb_read_one_eof(img, &seccomp_img_entry, PB_SECCOMP); close_image(img); if (ret <= 0) return 0; /* there were no filters */ - BUG_ON(!se); + BUG_ON(!seccomp_img_entry); return 0; } -int seccomp_filters_get_rst_pos(CoreEntry *core, struct task_restore_args *ta) +/* seccomp_img_entry will be freed per-children after forking */ +static void free_seccomp_filters(void) { - SeccompFilter *sf = NULL; - struct sock_fprog *arr = NULL; - void *filter_data = NULL; - int ret = -1, i, n_filters; - size_t filter_size = 0; - - ta->seccomp_filters_n = 0; - - if (!core->tc->has_seccomp_filter) - return 0; - - ta->seccomp_filters = (struct sock_fprog *)rst_mem_align_cpos(RM_PRIVATE); - - BUG_ON(core->tc->seccomp_filter > se->n_seccomp_filters); - sf = se->seccomp_filters[core->tc->seccomp_filter]; - - while (1) { - ta->seccomp_filters_n++; - filter_size += sf->filter.len; - - if (!sf->has_prev) - break; - - sf = se->seccomp_filters[sf->prev]; + if (seccomp_img_entry) { + seccomp_entry__free_unpacked(seccomp_img_entry, NULL); + seccomp_img_entry = NULL; } - - n_filters = ta->seccomp_filters_n; - arr = rst_mem_alloc(sizeof(struct sock_fprog) * n_filters + filter_size, RM_PRIVATE); - if (!arr) - goto out; - - filter_data = &arr[n_filters]; - sf = se->seccomp_filters[core->tc->seccomp_filter]; - for (i = 0; i < n_filters; i++) { - struct sock_fprog *fprog = &arr[i]; - - BUG_ON(sf->filter.len % sizeof(struct sock_filter)); - fprog->len = sf->filter.len / sizeof(struct sock_filter); - - memcpy(filter_data, sf->filter.data, sf->filter.len); - - filter_data += sf->filter.len; - sf = se->seccomp_filters[sf->prev]; - } - - ret = 0; - -out: - seccomp_entry__free_unpacked(se, NULL); - return ret; +} + +void seccomp_rst_reloc(struct thread_restore_args *args) +{ + size_t j, off; + + if (!args->seccomp_filters_n) + return; + + args->seccomp_filters = rst_mem_remap_ptr(args->seccomp_filters_pos, RM_PRIVATE); + args->seccomp_filters_data = (void *)args->seccomp_filters + + args->seccomp_filters_n * sizeof(struct thread_seccomp_filter); + + for (j = off = 0; j < args->seccomp_filters_n; j++) { + struct thread_seccomp_filter *f = &args->seccomp_filters[j]; + + f->sock_fprog.filter = args->seccomp_filters_data + off; + off += f->sock_fprog.len * sizeof(struct sock_filter); + } +} + +int seccomp_prepare_threads(struct pstree_item *item, struct task_restore_args *ta) +{ + struct thread_restore_args *args_array = (struct thread_restore_args *)(&ta[1]); + size_t i, j, nr_filters, filters_size, rst_size, off; + + for (i = 0; i < item->nr_threads; i++) { + ThreadCoreEntry *thread_core = item->core[i]->thread_core; + struct thread_restore_args *args = &args_array[i]; + SeccompFilter *sf; + + args->seccomp_mode = SECCOMP_MODE_DISABLED; + args->seccomp_filters_pos = 0; + args->seccomp_filters_n = 0; + args->seccomp_filters = NULL; + args->seccomp_filters_data = NULL; + + if (thread_core->has_seccomp_mode) + args->seccomp_mode = thread_core->seccomp_mode; + + if (args->seccomp_mode != SECCOMP_MODE_FILTER) + continue; + + if (thread_core->seccomp_filter >= seccomp_img_entry->n_seccomp_filters) { + pr_err("Corrupted filter index on tid %d (%u > %zu)\n", + item->threads[i].ns[0].virt, thread_core->seccomp_filter, + seccomp_img_entry->n_seccomp_filters); + return -1; + } + + sf = seccomp_img_entry->seccomp_filters[thread_core->seccomp_filter]; + if (sf->filter.len % (sizeof(struct sock_filter))) { + pr_err("Corrupted filter len on tid %d (index %u)\n", + item->threads[i].ns[0].virt, + thread_core->seccomp_filter); + return -1; + } + filters_size = sf->filter.len; + nr_filters = 1; + + while (sf->has_prev) { + if (sf->prev >= seccomp_img_entry->n_seccomp_filters) { + pr_err("Corrupted filter index on tid %d (%u > %zu)\n", + item->threads[i].ns[0].virt, sf->prev, + seccomp_img_entry->n_seccomp_filters); + return -1; + } + + sf = seccomp_img_entry->seccomp_filters[sf->prev]; + if (sf->filter.len % (sizeof(struct sock_filter))) { + pr_err("Corrupted filter len on tid %d (index %u)\n", + item->threads[i].ns[0].virt, sf->prev); + return -1; + } + filters_size += sf->filter.len; + nr_filters++; + } + + args->seccomp_filters_n = nr_filters; + + rst_size = filters_size + nr_filters * sizeof(struct thread_seccomp_filter); + args->seccomp_filters_pos = rst_mem_align_cpos(RM_PRIVATE); + args->seccomp_filters = rst_mem_alloc(rst_size, RM_PRIVATE); + if (!args->seccomp_filters) { + pr_err("Can't allocate %zu bytes for filters on tid %d\n", + rst_size, item->threads[i].ns[0].virt); + return -ENOMEM; + } + args->seccomp_filters_data = (void *)args->seccomp_filters + + nr_filters * sizeof(struct thread_seccomp_filter); + + sf = seccomp_img_entry->seccomp_filters[thread_core->seccomp_filter]; + for (j = off = 0; j < nr_filters; j++) { + struct thread_seccomp_filter *f = &args->seccomp_filters[j]; + + f->sock_fprog.len = sf->filter.len / sizeof(struct sock_filter); + f->sock_fprog.filter = args->seccomp_filters_data + off; + f->flags = sf->flags; + + memcpy(f->sock_fprog.filter, sf->filter.data, sf->filter.len); + + off += sf->filter.len; + sf = seccomp_img_entry->seccomp_filters[sf->prev]; + } + } + + free_seccomp_filters(); + return 0; } diff --git a/images/core.proto b/images/core.proto index 983998392..f9a66b2ae 100644 --- a/images/core.proto +++ b/images/core.proto @@ -40,8 +40,9 @@ message task_core_entry { optional signal_queue_entry signals_s = 10; - optional seccomp_mode seccomp_mode = 11; - optional uint32 seccomp_filter = 12; + /* These two are deprecated, should be per-thread */ + optional seccomp_mode old_seccomp_mode = 11; + optional uint32 old_seccomp_filter = 12; optional uint32 loginuid = 13; @@ -82,6 +83,9 @@ message thread_core_entry { optional signal_queue_entry signals_p = 9; optional creds_entry creds = 10; + + optional seccomp_mode seccomp_mode = 11; + optional uint32 seccomp_filter = 12; } message task_rlimits_entry { From 2f54573029e4157cb6f22bc1a7e2053f00768f93 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 7 May 2018 11:42:46 +0300 Subject: [PATCH 1549/4375] seccomp: Add engine to checkpoint per-thread seccomp chains To checkpoint per-thread seccomp filters we need a significant rework of a dumping code. The general idea is the following: - Each thread is tracked by its tid inside global seccomp rbtree thus we can easily add entries there or lookup on demand. - When we collect threads into pstree entries we fetch its seccomp mode from procfs parsing routine and allocate a new entry inside rbtree to remember the seccomp mode. Note at this moment we're not dumping real filters yet (because filter data image is a single one for all consumers) - Once all tids are collected and our tree is complete we call for seccomp_collect_dump_filters helper which walks every pstree entry and iterate over each tid inside thread group calling seccomp_dump_thread, which in turn uses ptrace engine to fetch filters and keep this data in memory. To optimize data usage we figure out if we can use TSYNC flag on restore calling try_use_tsync helper: for TSYNC flag kernel automatically propagate filter to all threads, thus we need to compare all filters inside thread group for identity since there is no other way to figure out if user passed TSYNC flag when been creating filters. - Finally dump_seccomp_filters is called which does real write of seccomp filter data into an image file. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 19 +- criu/include/pstree.h | 6 +- criu/include/seccomp.h | 40 +++- criu/seccomp.c | 404 +++++++++++++++++++++++++++-------------- criu/seize.c | 77 ++------ 5 files changed, 329 insertions(+), 217 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 6dc3d9ddc..21520c5c2 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -716,6 +716,8 @@ int dump_thread_core(int pid, CoreEntry *core, const struct parasite_dump_thread tc->pdeath_sig = ti->pdeath_sig; } } + if (!ret) + ret = seccomp_dump_thread(pid, tc); return ret; } @@ -729,7 +731,6 @@ static int dump_task_core_all(struct parasite_ctl *ctl, CoreEntry *core = item->core[0]; pid_t pid = item->pid->real; int ret = -1; - struct proc_status_creds *creds; struct parasite_dump_cgroup_args cgroup_args, *info = NULL; BUILD_BUG_ON(sizeof(cgroup_args) < PARASITE_ARG_SIZE_MIN); @@ -742,18 +743,6 @@ static int dump_task_core_all(struct parasite_ctl *ctl, if (ret < 0) goto err; - creds = dmpi(item)->pi_creds; - if (creds->s.seccomp_mode != SECCOMP_MODE_DISABLED) { - pr_info("got seccomp mode %d for %d\n", creds->s.seccomp_mode, vpid(item)); - core->tc->has_old_seccomp_mode = true; - core->tc->old_seccomp_mode = creds->s.seccomp_mode; - - if (creds->s.seccomp_mode == SECCOMP_MODE_FILTER) { - core->tc->has_old_seccomp_filter = true; - core->tc->old_seccomp_filter = creds->last_filter; - } - } - strlcpy((char *)core->tc->comm, stat->comm, TASK_COMM_LEN); core->tc->flags = stat->flags; core->tc->task_state = item->pid->state; @@ -1521,6 +1510,7 @@ static int cr_pre_dump_finish(int ret) } free_pstree(root_item); + seccomp_free_entries(); if (irmap_predump_run()) { ret = -1; @@ -1718,6 +1708,7 @@ static int cr_dump_finish(int ret) TASK_ALIVE : opts.final_state); timing_stop(TIME_FROZEN); free_pstree(root_item); + seccomp_free_entries(); free_file_locks(); free_link_remaps(); free_aufs_branches(); @@ -1822,7 +1813,7 @@ int cr_dump_tasks(pid_t pid) if (!glob_imgset) goto err; - if (collect_seccomp_filters() < 0) + if (seccomp_collect_dump_filters() < 0) goto err; /* Errors handled later in detect_pid_reuse */ diff --git a/criu/include/pstree.h b/criu/include/pstree.h index 34f9bbe6f..508d6df2b 100644 --- a/criu/include/pstree.h +++ b/criu/include/pstree.h @@ -4,6 +4,7 @@ #include "common/list.h" #include "common/lock.h" #include "pid.h" +#include "xmalloc.h" #include "images/core.pb-c.h" /* @@ -53,11 +54,6 @@ static inline struct rst_info *rsti(struct pstree_item *i) struct ns_id; struct dmp_info { struct ns_id *netns; - /* - * We keep the creds here so that we can compare creds while seizing - * threads. Dumping tasks with different creds is not supported. - */ - struct proc_status_creds *pi_creds; struct page_pipe *mem_pp; struct parasite_ctl *parasite_ctl; }; diff --git a/criu/include/seccomp.h b/criu/include/seccomp.h index 0791597fe..8e200124e 100644 --- a/criu/include/seccomp.h +++ b/criu/include/seccomp.h @@ -29,15 +29,43 @@ struct thread_restore_args; struct task_restore_args; +struct pstree_item; +struct rb_node; -struct seccomp_info { - struct seccomp_info *prev; - int id; - SeccompFilter filter; +/* + * seccomp filters are bound to @current->seccomp.filter + * in the kernel, ie they are per thread structures. + * + * If filter is assigned then every subsequent call + * to fork() makes a copy of this @current->seccomp.filter + * pointer into child process. + * + * The thread group can share a filter if the filter + * is assigned with SECCOMP_FILTER_FLAG_TSYNC on group + * which has no filters yet. + */ +struct seccomp_filter_chain { + struct seccomp_filter_chain *prev; + SeccompFilter filter; }; -extern int collect_seccomp_filters(void); -extern int prepare_seccomp_filters(void); +struct seccomp_entry { + struct rb_node node; + struct seccomp_entry *next; + pid_t tid_real; + size_t img_filter_pos; + unsigned int mode; + + struct seccomp_filter_chain *chain; + size_t nr_chains; +}; + +extern struct seccomp_entry *seccomp_lookup(pid_t tid_real, bool create, bool mandatory); +#define seccomp_find_entry(tid_real) seccomp_lookup(tid_real, false, true) +extern int seccomp_collect_entry(pid_t tid_real, unsigned int mode); +extern void seccomp_free_entries(void); +extern int seccomp_dump_thread(pid_t tid_real, ThreadCoreEntry *thread_core); +extern int seccomp_collect_dump_filters(void); extern int seccomp_read_image(void); extern int seccomp_prepare_threads(struct pstree_item *item, struct task_restore_args *ta); diff --git a/criu/seccomp.c b/criu/seccomp.c index 9b779c80f..c5b7c431e 100644 --- a/criu/seccomp.c +++ b/criu/seccomp.c @@ -21,67 +21,133 @@ #undef LOG_PREFIX #define LOG_PREFIX "seccomp: " +static struct rb_root seccomp_tid_rb_root = RB_ROOT; +static struct seccomp_entry *seccomp_tid_entry_root; + static SeccompEntry *seccomp_img_entry; -/* populated on dump during collect_seccomp_filters() */ -static int next_filter_id = 0; -static struct seccomp_info **filters = NULL; - -static struct seccomp_info *find_inherited(struct pstree_item *parent, - struct sock_filter *filter, - int len, struct seccomp_metadata *meta) +struct seccomp_entry *seccomp_lookup(pid_t tid_real, bool create, bool mandatory) { - struct seccomp_info *info; + struct seccomp_entry *entry = NULL; - /* if we have no filters yet, this one has no parent */ - if (!filters) - return NULL; + struct rb_node *node = seccomp_tid_rb_root.rb_node; + struct rb_node **new = &seccomp_tid_rb_root.rb_node; + struct rb_node *parent = NULL; - for (info = filters[dmpi(parent)->pi_creds->last_filter]; info; info = info->prev) { + while (node) { + struct seccomp_entry *this = rb_entry(node, struct seccomp_entry, node); - if (len != info->filter.filter.len) - continue; - if (!!meta ^ !!info->filter.has_flags) - continue; - if (info->filter.has_flags && meta) { - if (info->filter.flags != meta->flags) - continue; - } - if (!memcmp(filter, info->filter.filter.data, len)) - return info; + parent = *new; + if (tid_real < this->tid_real) + node = node->rb_left, new = &((*new)->rb_left); + else if (tid_real > this->tid_real) + node = node->rb_right, new = &((*new)->rb_right); + else + return this; } - return NULL; + if (create) { + entry = xzalloc(sizeof(*entry)); + if (!entry) + return NULL; + rb_init_node(&entry->node); + entry->tid_real = tid_real; + + entry->next = seccomp_tid_entry_root, seccomp_tid_entry_root = entry; + rb_link_and_balance(&seccomp_tid_rb_root, &entry->node, parent, new); + } else { + if (mandatory) + pr_err("Can't find entry on tid_real %d\n", tid_real); + } + + return entry; } -static int collect_filter_for_pstree(struct pstree_item *item) +int seccomp_collect_entry(pid_t tid_real, unsigned int mode) +{ + struct seccomp_entry *entry; + + entry = seccomp_lookup(tid_real, true, false); + if (!entry) { + pr_err("Can't create entry on tid_real %d\n", tid_real); + return -1; + } + entry->mode = mode; + + pr_debug("Collected tid_real %d mode %#x\n", tid_real, mode); + return 0; +} + +static void seccomp_free_chain(struct seccomp_entry *entry) +{ + struct seccomp_filter_chain *chain, *prev; + + for (chain = entry->chain; chain; chain = prev) { + prev = chain->prev; + + xfree(chain->filter.filter.data); + xfree(chain); + } + + entry->nr_chains = 0; + entry->chain = NULL; +} + +void seccomp_free_entries(void) +{ + struct seccomp_entry *entry, *next; + + for (entry = seccomp_tid_entry_root; entry; entry = next) { + next = entry->next; + seccomp_free_chain(entry); + xfree(entry); + } + + seccomp_tid_rb_root = RB_ROOT; + seccomp_tid_entry_root = NULL; +} + +int seccomp_dump_thread(pid_t tid_real, ThreadCoreEntry *thread_core) +{ + struct seccomp_entry *entry = seccomp_find_entry(tid_real); + if (!entry) { + pr_err("Can't dump thread core on tid_real %d\n", tid_real); + return -1; + } + + if (entry->mode != SECCOMP_MODE_DISABLED) { + thread_core->has_seccomp_mode = true; + thread_core->seccomp_mode = entry->mode; + + if (entry->mode == SECCOMP_MODE_FILTER) { + thread_core->has_seccomp_filter = true; + thread_core->seccomp_filter = entry->img_filter_pos; + } + } + + return 0; +} + +static int collect_filter(struct seccomp_entry *entry) { struct seccomp_metadata meta_buf, *meta = &meta_buf; - struct seccomp_info *infos = NULL, *cursor; - int info_count, i, ret = -1; + struct seccomp_filter_chain *chain, *prev; struct sock_filter buf[BPF_MAXINSNS]; - void *m; + size_t i; + int len; - if (item->pid->state == TASK_DEAD || - dmpi(item)->pi_creds->s.seccomp_mode != SECCOMP_MODE_FILTER) + if (entry->mode != SECCOMP_MODE_FILTER) return 0; for (i = 0; true; i++) { - int len; - struct seccomp_info *info, *inherited = NULL; - - len = ptrace(PTRACE_SECCOMP_GET_FILTER, item->pid->real, i, buf); + len = ptrace(PTRACE_SECCOMP_GET_FILTER, entry->tid_real, i, buf); if (len < 0) { if (errno == ENOENT) { - /* end of the search */ - BUG_ON(i == 0); - goto save_infos; - } else if (errno == EINVAL) { - pr_err("dumping seccomp infos not supported\n"); - goto out; + break; } else { - pr_perror("couldn't dump seccomp filter"); - goto out; + pr_perror("Can't fetch filter on tid_real %d i %zu", + entry->tid_real, i); + return -1; } } @@ -91,142 +157,212 @@ static int collect_filter_for_pstree(struct pstree_item *item) meta->flags = 0; meta->filter_off = i; - if (ptrace(PTRACE_SECCOMP_GET_METADATA, item->pid->real, sizeof(meta), meta) < 0) { + if (ptrace(PTRACE_SECCOMP_GET_METADATA, entry->tid_real, sizeof(meta), meta) < 0) { if (errno == EIO) { - /* - * No PTRACE_SECCOMP_GET_METADATA support in - * kernel detected, thus simply ignore. Moving - * it into kerndat is preferred but not - * required. - */ meta = NULL; } else { - pr_perror("couldn't fetch seccomp metadata: pid %d pos %d", - item->pid->real, i); - goto out; + pr_perror("Can't fetch seccomp metadataon tid_real %d pos %zu", + entry->tid_real, i); + return -1; } } - inherited = find_inherited(item->parent, buf, len, meta); - if (inherited) { - bool found = false; + chain = xzalloc(sizeof(*chain)); + if (!chain) + return -1; - /* Small sanity check: if infos is already populated, - * we should have inherited that filter too. */ - for (cursor = infos; cursor; cursor = cursor->prev) { - if (inherited->prev== cursor) { - found = true; - break; - } - } + seccomp_filter__init(&chain->filter); - BUG_ON(!found); + chain->filter.has_flags = true; + chain->filter.flags = 0; - infos = inherited; + chain->filter.filter.len = len * sizeof(struct sock_filter); + chain->filter.filter.data = xmalloc(chain->filter.filter.len); + if (!chain->filter.filter.data) { + xfree(chain); + return -1; + } + + memcpy(chain->filter.filter.data, buf, chain->filter.filter.len); + + if (meta) + chain->filter.flags |= meta->flags; + + prev = entry->chain, entry->chain = chain, chain->prev = prev; + entry->nr_chains++; + } + + return 0; +} + +/* + * When filter is being set up with SECCOMP_FILTER_FLAG_TSYNC then all + * threads share same filters chain. Still without kernel support we + * don't know if the chains are indeed were propagated by the flag above + * or application installed identical chains manually. + * + * Thus we do a trick: if all threads are sharing chains we just drop + * all ones except on a leader and assign SECCOMP_FILTER_FLAG_TSYNC there. + * The rationale is simple: if application is using tsync it always can + * assign new not-tsync filters after, but in reverse if we don't provide + * tsync on restore the further calls with tsync will fail later. + * + * Proper fix needs some support from kernel side (presumably kcmp mode). + */ +static void try_use_tsync(struct seccomp_entry *leader, struct pstree_item *item) +{ + struct seccomp_filter_chain *chain_a, *chain_b; + struct seccomp_entry *entry; + size_t i, j; + + if (leader->mode != SECCOMP_MODE_FILTER) + return; + + for (i = 0; i < item->nr_threads; i++) { + entry = seccomp_find_entry(item->threads[i].real); + BUG_ON(!entry); + + if (entry == leader) continue; + + if (entry->mode != leader->mode || + entry->nr_chains != leader->nr_chains) + return; + + chain_a = leader->chain; + chain_b = entry->chain; + + for (j = 0; j < leader->nr_chains; j++) { + BUG_ON((!chain_a || !chain_b)); + + if (chain_a->filter.filter.len != + chain_b->filter.filter.len) + return; + + if (memcmp(chain_a->filter.filter.data, + chain_b->filter.filter.data, + chain_a->filter.filter.len)) + return; + + chain_a = chain_a->prev; + chain_b = chain_b->prev; } - - info = xmalloc(sizeof(*info)); - if (!info) - goto out; - seccomp_filter__init(&info->filter); - - if (meta) { - info->filter.has_flags = true; - info->filter.flags = meta->flags; - } - - info->filter.filter.len = len * sizeof(struct sock_filter); - info->filter.filter.data = xmalloc(info->filter.filter.len); - if (!info->filter.filter.data) { - xfree(info); - goto out; - } - - memcpy(info->filter.filter.data, buf, info->filter.filter.len); - - info->prev = infos; - infos = info; } -save_infos: - info_count = i; + /* OK, so threads can be restored with tsync */ + pr_debug("Use SECCOMP_FILTER_FLAG_TSYNC for tid_real %d\n", + leader->tid_real); - m = xrealloc(filters, sizeof(*filters) * (next_filter_id + info_count)); - if (!m) - goto out; - filters = m; + for (chain_a = leader->chain; chain_a; chain_a = chain_a->prev) + chain_a->filter.flags |= SECCOMP_FILTER_FLAG_TSYNC; - for (cursor = infos, i = info_count + next_filter_id - 1; - i >= next_filter_id; i--) { - BUG_ON(!cursor); - cursor->id = i; - filters[i] = cursor; - cursor = cursor->prev; + for (i = 0; i < item->nr_threads; i++) { + entry = seccomp_find_entry(item->threads[i].real); + BUG_ON(!entry); + + if (entry == leader) + continue; + + pr_debug("\t Disable filter on tid_rea %d, will be propagated\n", + entry->tid_real); + + entry->mode = SECCOMP_MODE_DISABLED; + seccomp_free_chain(entry); + } +} + +static int collect_filters(struct pstree_item *item) +{ + struct seccomp_entry *leader, *entry; + size_t i; + + if (item->pid->state == TASK_DEAD) + return 0; + + leader = seccomp_find_entry(item->pid->real); + if (!leader) { + pr_err("Can't collect filter on leader tid_real %d\n", + item->pid->real); + return -1; } - next_filter_id += info_count; + for (i = 0; i < item->nr_threads; i++) { + entry = seccomp_find_entry(item->threads[i].real); + if (!leader) { + pr_err("Can't collect filter on tid_real %d\n", + item->pid->real); + return -1; + } - dmpi(item)->pi_creds->last_filter = infos->id; - - /* Don't free the part of the tree we just successfully acquired */ - infos = NULL; - ret = 0; -out: - while (infos) { - struct seccomp_info *freeme = infos; - infos = infos->prev; - xfree(freeme->filter.filter.data); - xfree(freeme); + if (collect_filter(entry)) + return -1; } - return ret; + try_use_tsync(leader, item); + return 0; } static int dump_seccomp_filters(void) { SeccompEntry se = SECCOMP_ENTRY__INIT; - int ret = -1, i; + struct seccomp_filter_chain *chain; + struct seccomp_entry *entry; + size_t img_filter_pos = 0, nr_chains = 0; + struct rb_node *node; + int ret; - /* If we didn't collect any filters, don't create a seccomp image at all. */ - if (next_filter_id == 0) - return 0; + for (node = rb_first(&seccomp_tid_rb_root); node; node = rb_next(node)) { + entry = rb_entry(node, struct seccomp_entry, node); + nr_chains += entry->nr_chains; + } - se.seccomp_filters = xzalloc(sizeof(*se.seccomp_filters) * next_filter_id); - if (!se.seccomp_filters) - return -1; + se.n_seccomp_filters = nr_chains; + if (nr_chains) { + se.seccomp_filters = xmalloc(sizeof(*se.seccomp_filters) * nr_chains); + if (!se.seccomp_filters) + return -1; + } - se.n_seccomp_filters = next_filter_id; + for (node = rb_first(&seccomp_tid_rb_root); node; node = rb_next(node)) { + entry = rb_entry(node, struct seccomp_entry, node); - for (i = 0; i < next_filter_id; i++) { - SeccompFilter *sf; - struct seccomp_info *cur = filters[i]; + if (!entry->nr_chains) + continue; - sf = se.seccomp_filters[cur->id] = &cur->filter; - if (cur->prev) { - sf->has_prev = true; - sf->prev = cur->prev->id; + for (chain = entry->chain; chain; chain = chain->prev) { + if (img_filter_pos >= nr_chains) { + pr_err("Unexpected position %zu > %zu\n", + img_filter_pos, nr_chains); + xfree(se.seccomp_filters); + return -1; + } + + se.seccomp_filters[img_filter_pos] = &chain->filter; + if (chain != entry->chain) { + chain->filter.has_prev = true; + chain->filter.prev = img_filter_pos - 1; + } + img_filter_pos++; } + + entry->img_filter_pos = img_filter_pos - 1; } ret = pb_write_one(img_from_set(glob_imgset, CR_FD_SECCOMP), &se, PB_SECCOMP); xfree(se.seccomp_filters); - for (i = 0; i < next_filter_id; i++) { - struct seccomp_info *freeme = filters[i]; - - xfree(freeme->filter.filter.data); - xfree(freeme); + for (node = rb_first(&seccomp_tid_rb_root); node; node = rb_next(node)) { + entry = rb_entry(node, struct seccomp_entry, node); + seccomp_free_chain(entry); } - xfree(filters); return ret; } -int collect_seccomp_filters(void) +int seccomp_collect_dump_filters(void) { - if (preorder_pstree_traversal(root_item, collect_filter_for_pstree) < 0) + if (preorder_pstree_traversal(root_item, collect_filters) < 0) return -1; if (dump_seccomp_filters()) diff --git a/criu/seize.c b/criu/seize.c index bc689d265..d47d4bfc1 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -17,6 +17,7 @@ #include "criu-log.h" #include #include "proc_parse.h" +#include "seccomp.h" #include "seize.h" #include "stats.h" #include "xmalloc.h" @@ -458,7 +459,7 @@ static int collect_children(struct pstree_item *item) nr_inprogress = 0; for (i = 0; i < nr_children; i++) { struct pstree_item *c; - struct proc_status_creds *creds; + struct proc_status_creds creds; pid_t pid = ch[i]; /* Is it already frozen? */ @@ -484,13 +485,7 @@ static int collect_children(struct pstree_item *item) /* fails when meets a zombie */ compel_interrupt_task(pid); - creds = xzalloc(sizeof(*creds)); - if (!creds) { - ret = -1; - goto free; - } - - ret = compel_wait_task(pid, item->pid->real, parse_pid_status, NULL, &creds->s, NULL); + ret = compel_wait_task(pid, item->pid->real, parse_pid_status, NULL, &creds.s, NULL); if (ret < 0) { /* * Here is a race window between parse_children() and seize(), @@ -501,7 +496,6 @@ static int collect_children(struct pstree_item *item) */ ret = 0; xfree(c); - xfree(creds); continue; } @@ -510,12 +504,15 @@ static int collect_children(struct pstree_item *item) else processes_to_wait--; - dmpi(c)->pi_creds = creds; c->pid->real = pid; c->parent = item; c->pid->state = ret; list_add_tail(&c->sibling, &item->children); + ret = seccomp_collect_entry(pid, creds.s.seccomp_mode); + if (ret < 0) + goto free; + /* Here is a recursive call (Depth-first search) */ ret = collect_task(c); if (ret < 0) @@ -626,51 +623,16 @@ static inline bool thread_collected(struct pstree_item *i, pid_t tid) return false; } -static bool creds_dumpable(struct proc_status_creds *parent, - struct proc_status_creds *child) -{ - /* - * - seccomp filters should be passed via - * semantic comparison (FIXME) but for - * now we require them to be exactly - * identical - */ - if (parent->s.seccomp_mode != child->s.seccomp_mode || - parent->last_filter != child->last_filter) { - if (!pr_quelled(LOG_DEBUG)) { - pr_debug("Creds undumpable (parent:child)\n" - " uids: %d:%d %d:%d %d:%d %d:%d\n" - " gids: %d:%d %d:%d %d:%d %d:%d\n" - " state: %d:%d" - " ppid: %d:%d\n" - " shdpnd: %llu:%llu\n" - " seccomp_mode: %d:%d\n" - " last_filter: %u:%u\n", - parent->uids[0], child->uids[0], - parent->uids[1], child->uids[1], - parent->uids[2], child->uids[2], - parent->uids[3], child->uids[3], - parent->gids[0], child->gids[0], - parent->gids[1], child->gids[1], - parent->gids[2], child->gids[2], - parent->gids[3], child->gids[3], - parent->s.state, child->s.state, - parent->s.ppid, child->s.ppid, - parent->s.shdpnd, child->s.shdpnd, - parent->s.seccomp_mode, child->s.seccomp_mode, - parent->last_filter, child->last_filter); - } - return false; - } - - return true; -} - static int collect_threads(struct pstree_item *item) { + struct seccomp_entry *task_seccomp_entry; struct pid *threads = NULL; int nr_threads = 0, i = 0, ret, nr_inprogress, nr_stopped = 0; + task_seccomp_entry = seccomp_find_entry(item->pid->real); + if (!task_seccomp_entry) + goto err; + ret = parse_threads(item->pid->real, &threads, &nr_threads); if (ret < 0) goto err; @@ -734,7 +696,7 @@ static int collect_threads(struct pstree_item *item) goto err; } - if (!creds_dumpable(dmpi(item)->pi_creds, &t_creds)) + if (seccomp_collect_entry(pid, t_creds.s.seccomp_mode)) goto err; if (ret == TASK_STOPPED) { @@ -823,7 +785,7 @@ int collect_pstree(void) { pid_t pid = root_item->pid->real; int ret = -1; - struct proc_status_creds *creds; + struct proc_status_creds creds; timing_start(TIME_FREEZING); @@ -842,11 +804,7 @@ int collect_pstree(void) goto err; } - creds = xzalloc(sizeof(*creds)); - if (!creds) - goto err; - - ret = compel_wait_task(pid, -1, parse_pid_status, NULL, &creds->s, NULL); + ret = compel_wait_task(pid, -1, parse_pid_status, NULL, &creds.s, NULL); if (ret < 0) goto err; @@ -857,7 +815,10 @@ int collect_pstree(void) pr_info("Seized task %d, state %d\n", pid, ret); root_item->pid->state = ret; - dmpi(root_item)->pi_creds = creds; + + ret = seccomp_collect_entry(pid, creds.s.seccomp_mode); + if (ret < 0) + goto err; ret = collect_task(root_item); if (ret < 0) From 96a30f068c3c8bd19c2377666a367bd030b83dde Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 7 May 2018 11:42:47 +0300 Subject: [PATCH 1550/4375] seccomp: test -- Add seccomp_filter_threads Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 2 + test/zdtm/static/seccomp_filter_threads.c | 161 +++++++++++++++++++ test/zdtm/static/seccomp_filter_threads.desc | 1 + 3 files changed, 164 insertions(+) create mode 100644 test/zdtm/static/seccomp_filter_threads.c create mode 100644 test/zdtm/static/seccomp_filter_threads.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 22291ccab..e0ca4d625 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -182,6 +182,7 @@ TST_NOFILE := \ seccomp_strict \ seccomp_filter \ seccomp_filter_tsync \ + seccomp_filter_threads \ seccomp_filter_inheritance \ different_creds \ vsx \ @@ -458,6 +459,7 @@ different_creds: LDLIBS += -pthread sigpending: LDLIBS += -pthread sigaltstack: LDLIBS += -pthread seccomp_filter_tsync: LDLIBS += -pthread +seccomp_filter_threads: LDLIBS += -pthread shm: CFLAGS += -DNEW_IPC_NS msgque: CFLAGS += -DNEW_IPC_NS sem: CFLAGS += -DNEW_IPC_NS diff --git a/test/zdtm/static/seccomp_filter_threads.c b/test/zdtm/static/seccomp_filter_threads.c new file mode 100644 index 000000000..a0e0b6472 --- /dev/null +++ b/test/zdtm/static/seccomp_filter_threads.c @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __NR_seccomp +# include +# include +# include +# include +#endif + +#include "zdtmtst.h" + +#ifndef SECCOMP_SET_MODE_FILTER +#define SECCOMP_SET_MODE_FILTER 1 +#endif + +#ifndef SECCOMP_FILTER_FLAG_TSYNC +#define SECCOMP_FILTER_FLAG_TSYNC 1 +#endif + +const char *test_doc = "Check threads to carry different seccomps"; +const char *test_author = "Cyrill Gorcunov "; + +#ifdef __NR_seccomp + +static task_waiter_t tw; + +int get_seccomp_mode(pid_t pid) +{ + FILE *f; + char buf[PATH_MAX]; + + sprintf(buf, "/proc/%d/status", pid); + f = fopen(buf, "r+"); + if (!f) { + pr_perror("fopen failed"); + return -1; + } + + while (NULL != fgets(buf, sizeof(buf), f)) { + int mode; + + if (sscanf(buf, "Seccomp:\t%d", &mode) != 1) + continue; + + fclose(f); + return mode; + } + fclose(f); + + return -1; +} + +int filter_syscall(int syscall_nr, unsigned int flags) +{ + struct sock_filter filter[] = { + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), + }; + + struct sock_fprog bpf_prog = { + .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), + .filter = filter, + }; + + if (syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, flags, &bpf_prog) < 0) { + pr_perror("seccomp failed"); + return -1; + } + + return 0; +} + +void *thread_main(void *arg) +{ + if (filter_syscall(__NR_ptrace, 0) < 0) + pthread_exit((void *)1); + + test_msg("__NR_ptrace filtered inside a sole thread\n"); + + task_waiter_complete(&tw, 1); + task_waiter_wait4(&tw, 2); + + ptrace(PTRACE_TRACEME); + pthread_exit((void *)1); +} + +int main(int argc, char ** argv) +{ + int ret, mode, status; + pid_t pid; + + test_init(argc, argv); + task_waiter_init(&tw); + + pid = fork(); + if (pid < 0) { + pr_perror("fork"); + return -1; + } + + if (pid == 0) { + pthread_t thread; + void *p = NULL; + + zdtm_seccomp = 1; + + pthread_create(&thread, NULL, thread_main, NULL); + if (pthread_join(thread, &p) != 0) { + pr_perror("pthread_join"); + exit(1); + } + + syscall(__NR_exit, p); + } + + task_waiter_wait4(&tw, 1); + + test_daemon(); + test_waitsig(); + + task_waiter_complete(&tw, 2); + mode = get_seccomp_mode(pid); + + if (mode != SECCOMP_MODE_DISABLED) { + fail("seccomp mode mismatch %d\n", mode); + return 1; + } + + ret = waitpid(pid, &status, 0); + if (ret != pid) { + fail("waitpid: %d != %d", ret, pid); + exit(1); + } + + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + fail("expected 0 exit, got %d\n", WEXITSTATUS(status)); + exit(1); + } + + pass(); + return 0; +} + +#else /* __NR_seccomp */ + +#define TEST_SKIP_REASON "incompatible kernel (no seccomp)" +#include "skip-me.c" + +#endif /* __NR_seccomp */ diff --git a/test/zdtm/static/seccomp_filter_threads.desc b/test/zdtm/static/seccomp_filter_threads.desc new file mode 100644 index 000000000..14dd96184 --- /dev/null +++ b/test/zdtm/static/seccomp_filter_threads.desc @@ -0,0 +1 @@ +{'flags': 'suid', 'feature': 'seccomp_filters'} From 64ec202356aab0f3ebd58d0150e2a57e3ce27976 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 7 May 2018 11:42:48 +0300 Subject: [PATCH 1551/4375] seccomp: Dont forget to suspend filtering on threads When considering if we to call PTRACE_O_SUSPEND_SECCOMP on the tid we should take into account if there at least one thread which has seccomp mode enabled, otherwise we might miss filter suspension and restore procedure might break due to own criu syscall get filtered out. Same time we should move seccomp restore for threads to take place after CR_STATE_RESTORE_SIGCHLD state so that main criu code will attach to threads and setup seccomp suspension flag before we start restoring the filters. Reported-by: Andrei Vagin Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 29 +++++++++++++++++++++++++---- criu/pie/restorer.c | 21 ++++++++++----------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 781220ca1..39a6d9949 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -770,6 +770,23 @@ static int open_cores(int pid, CoreEntry *leader_core) current->core = cores; + /* + * Walk over all threads and if one them is having + * active seccomp mode we will suspend filtering + * on the whole group until restore complete. + * + * Otherwise any criu code which might use same syscall + * if present inside a filter chain would take filter + * action and might break restore procedure. + */ + for (i = 0; i < current->nr_threads; i++) { + ThreadCoreEntry *thread_core = cores[i]->thread_core; + if (thread_core->seccomp_mode != SECCOMP_MODE_DISABLED) { + rsti(current)->has_seccomp = true; + break; + } + } + return 0; err: xfree(cores); @@ -1293,10 +1310,14 @@ static inline int fork_with_pid(struct pstree_item *item) return -1; } - if (item->pid->state != TASK_DEAD) - rsti(item)->has_seccomp = ca.core->thread_core->seccomp_mode != SECCOMP_MODE_DISABLED; - else - rsti(item)->has_seccomp = false; + /* + * By default we assume that seccomp is not + * used at all (especially on dead task). Later + * we will walk over all threads and check in + * details if filter is present setting up + * this flag as appropriate. + */ + rsti(item)->has_seccomp = false; if (unlikely(item == root_item)) maybe_clone_parent(item, &ca); diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index b4d2d6583..040a6c583 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -553,17 +553,6 @@ long __export_restore_thread(struct thread_restore_args *args) if (restore_thread_common(args)) goto core_restore_end; - /* - * Make sure it's before creds, since it's privileged - * operation bound to uid 0 in current user ns. - */ - if (restore_seccomp(args)) - goto core_restore_end; - - ret = restore_creds(args->creds_args, args->ta->proc_fd); - if (ret) - goto core_restore_end; - ret = restore_dumpable_flag(&args->ta->mm); if (ret) goto core_restore_end; @@ -578,6 +567,16 @@ long __export_restore_thread(struct thread_restore_args *args) restore_finish_stage(task_entries_local, CR_STATE_RESTORE_SIGCHLD); restore_pdeath_sig(args); + /* + * Make sure it's before creds, since it's privileged + * operation bound to uid 0 in current user ns. + */ + if (restore_seccomp(args)) + goto core_restore_end; + + ret = restore_creds(args->creds_args, args->ta->proc_fd); + if (ret) + goto core_restore_end; restore_finish_stage(task_entries_local, CR_STATE_RESTORE_CREDS); futex_dec_and_wake(&thread_inprogress); From b4451351a5317662a6763f0f5f68026a23ddcc8e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 7 May 2018 11:42:49 +0300 Subject: [PATCH 1552/4375] seccomp: test, seccomp_filter_threads -- Use multiple threads Andrew proposed the test which actually triggered the issue in current seccomp series, put it into a regular basis. Suggested-by: Andrey Vagin Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/seccomp_filter_threads.c | 96 +++++++++++++++++++---- 1 file changed, 80 insertions(+), 16 deletions(-) diff --git a/test/zdtm/static/seccomp_filter_threads.c b/test/zdtm/static/seccomp_filter_threads.c index a0e0b6472..b3fa6089d 100644 --- a/test/zdtm/static/seccomp_filter_threads.c +++ b/test/zdtm/static/seccomp_filter_threads.c @@ -9,6 +9,7 @@ #include #include #include +#include #ifdef __NR_seccomp # include @@ -18,6 +19,7 @@ #endif #include "zdtmtst.h" +#include "lock.h" #ifndef SECCOMP_SET_MODE_FILTER #define SECCOMP_SET_MODE_FILTER 1 @@ -32,7 +34,10 @@ const char *test_author = "Cyrill Gorcunov "; #ifdef __NR_seccomp -static task_waiter_t tw; +static long sys_gettid(void) { return syscall(__NR_gettid); } + +static futex_t *wait_rdy; +static futex_t *wait_run; int get_seccomp_mode(pid_t pid) { @@ -40,7 +45,7 @@ int get_seccomp_mode(pid_t pid) char buf[PATH_MAX]; sprintf(buf, "/proc/%d/status", pid); - f = fopen(buf, "r+"); + f = fopen(buf, "r"); if (!f) { pr_perror("fopen failed"); return -1; @@ -82,27 +87,76 @@ int filter_syscall(int syscall_nr, unsigned int flags) return 0; } +void tigger_ptrace(void) { ptrace(PTRACE_TRACEME); } +void trigger_prctl(void) { prctl(PR_SET_PDEATHSIG, 9, 0, 0, 0); } +void trigger_mincore(void) { mincore(NULL, 0, NULL); } + +#define gen_param(__syscall_nr, __trigger) \ +{ \ + .syscall_name = # __syscall_nr, \ + .syscall_nr = __syscall_nr, \ + .trigger = __trigger, \ +} + +struct { + char *syscall_name; + unsigned int syscall_nr; + void (*trigger)(void); +} pthread_seccomp_params[] = { + gen_param(__NR_ptrace, tigger_ptrace), + gen_param(__NR_prctl, trigger_prctl), + gen_param(__NR_mincore, trigger_mincore), +}; + +#define WAITER_VALS_OFFSET (ARRAY_SIZE(pthread_seccomp_params) * 2) + void *thread_main(void *arg) { - if (filter_syscall(__NR_ptrace, 0) < 0) + size_t nr = (long) arg; + + if (filter_syscall(pthread_seccomp_params[nr].syscall_nr, 0) < 0) pthread_exit((void *)1); - test_msg("__NR_ptrace filtered inside a sole thread\n"); + test_msg("%s filtered inside a sole thread %lu\n", + pthread_seccomp_params[nr].syscall_name, + sys_gettid()); - task_waiter_complete(&tw, 1); - task_waiter_wait4(&tw, 2); + futex_inc_and_wake(wait_rdy); + futex_wait_while_lt(wait_run, 1); - ptrace(PTRACE_TRACEME); + test_msg("Triggering %zu %s thread %lu\n", + nr, pthread_seccomp_params[nr].syscall_name, + sys_gettid()); + + pthread_seccomp_params[nr].trigger(); + + test_msg("Abnormal exit %zu thread %lu\n", nr, sys_gettid()); pthread_exit((void *)1); } int main(int argc, char ** argv) { int ret, mode, status; + size_t i; pid_t pid; test_init(argc, argv); - task_waiter_init(&tw); + + wait_rdy = mmap(NULL, sizeof(*wait_rdy), PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED, -1, 0); + wait_run = mmap(NULL, sizeof(*wait_rdy), PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED, -1, 0); + + if (wait_rdy == MAP_FAILED || wait_run == MAP_FAILED) { + pr_perror("mmap failed\n"); + exit(1); + } + + futex_init(wait_rdy); + futex_init(wait_run); + + futex_set(wait_rdy, 0); + futex_set(wait_run, 0); pid = fork(); if (pid < 0) { @@ -110,27 +164,37 @@ int main(int argc, char ** argv) return -1; } + if (pid == 0) { - pthread_t thread; + pthread_t thread[ARRAY_SIZE(pthread_seccomp_params)]; void *p = NULL; zdtm_seccomp = 1; - pthread_create(&thread, NULL, thread_main, NULL); - if (pthread_join(thread, &p) != 0) { - pr_perror("pthread_join"); - exit(1); + for (i = 0; i < ARRAY_SIZE(pthread_seccomp_params); i++) { + if (pthread_create(&thread[i], NULL, thread_main, (void *)i)) { + pr_perror("pthread_create"); + exit(1); + } } - syscall(__NR_exit, p); + for (i = 0; i < ARRAY_SIZE(pthread_seccomp_params); i++) { + test_msg("Waiting thread %zu\n", i); + if (pthread_join(thread[i], &p) != 0) { + pr_perror("pthread_join"); + exit(1); + } + } + + syscall(__NR_exit, 0); } - task_waiter_wait4(&tw, 1); + futex_wait_until(wait_rdy, ARRAY_SIZE(pthread_seccomp_params)); test_daemon(); test_waitsig(); - task_waiter_complete(&tw, 2); + futex_inc_and_wake(wait_run); mode = get_seccomp_mode(pid); if (mode != SECCOMP_MODE_DISABLED) { From 673d1c77118f0f4dd76b18f06e2310519f34b88e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 7 May 2018 11:42:50 +0300 Subject: [PATCH 1553/4375] seccomp: Fix nits in collect_filter - Fix typo in sizeof() operand - Eliminate redundant prctl calls if no PTRACE_SECCOMP_GET_METADATA detected Reported-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/seccomp.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/criu/seccomp.c b/criu/seccomp.c index c5b7c431e..583860379 100644 --- a/criu/seccomp.c +++ b/criu/seccomp.c @@ -151,19 +151,18 @@ static int collect_filter(struct seccomp_entry *entry) } } - if (!meta) - meta = &meta_buf; + if (meta) { + meta->filter_off = i; - meta->flags = 0; - meta->filter_off = i; - - if (ptrace(PTRACE_SECCOMP_GET_METADATA, entry->tid_real, sizeof(meta), meta) < 0) { - if (errno == EIO) { - meta = NULL; - } else { - pr_perror("Can't fetch seccomp metadataon tid_real %d pos %zu", - entry->tid_real, i); - return -1; + if (ptrace(PTRACE_SECCOMP_GET_METADATA, entry->tid_real, sizeof(*meta), meta) < 0) { + if (errno == EIO) { + /* Old kernel, no METADATA support */ + meta = NULL; + } else { + pr_perror("Can't fetch seccomp metadata on tid_real %d pos %zu", + entry->tid_real, i); + return -1; + } } } From d5a3d807afa23868fec43537e4c75ea29e468ccb Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 15 May 2018 11:12:40 +0300 Subject: [PATCH 1554/4375] seccomp: Don't lookup for pidns in restore_seccomp Looking up for pid in nesting pidns supposed to be done for non group leaders only, thus __export_restore_thread do this check on its own and we don't have to make a similar lookup especially on group leader where pids in args never were valid. Reported-by: Andrei Vagin Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 040a6c583..7e298aeaa 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -431,17 +431,9 @@ static int restore_seccomp_filter(pid_t tid, struct thread_restore_args *args) static int restore_seccomp(struct thread_restore_args *args) { - pid_t tid; + pid_t tid = sys_gettid(); int ret; - tid = args->pid; - - if (tid != sys_gettid()) { - pr_err("seccomp: Unexpected tid %d != %d\n", - tid, (pid_t)sys_gettid()); - return -1; - } - switch (args->seccomp_mode) { case SECCOMP_MODE_DISABLED: pr_debug("seccomp: mode %d on tid %d\n", SECCOMP_MODE_DISABLED, tid); From d92366efe58ed03aea0c8faa4e26b39f3ef38f36 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 15 May 2018 11:12:39 +0300 Subject: [PATCH 1555/4375] seccomp: Move changed ptrace flags setup after creds Credential commitment affects dumpable and pdeath signals so we have to move their restore after the restore_creds, just like we have in __export_restore_task (ie for group leader). https://jira.sw.ru/browse/PSBM-84198 Acked-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/restorer.h | 4 +++- criu/pie/restorer.c | 8 +++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 40b6da0f9..af1718cb9 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -273,7 +273,7 @@ enum { * almost ready and what's left is: * pick up zombies and helpers * restore sigchild handlers used to detect restore errors - * restore credentials + * restore credentials, seccomp, dumpable and pdeath_sig */ CR_STATE_RESTORE, /* @@ -288,6 +288,8 @@ enum { * credentials are restored. Otherwise someone can attach to a * process, which are not restored credentials yet and execute * some code. + * Seccomp needs to be restored after creds. + * Dumpable and pdeath signal are restored after seccomp. */ CR_STATE_RESTORE_CREDS, CR_STATE_COMPLETE diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 7e298aeaa..f472d05b3 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -545,10 +545,6 @@ long __export_restore_thread(struct thread_restore_args *args) if (restore_thread_common(args)) goto core_restore_end; - ret = restore_dumpable_flag(&args->ta->mm); - if (ret) - goto core_restore_end; - pr_info("%ld: Restored\n", sys_gettid()); restore_finish_stage(task_entries_local, CR_STATE_RESTORE); @@ -557,7 +553,6 @@ long __export_restore_thread(struct thread_restore_args *args) goto core_restore_end; restore_finish_stage(task_entries_local, CR_STATE_RESTORE_SIGCHLD); - restore_pdeath_sig(args); /* * Make sure it's before creds, since it's privileged @@ -567,8 +562,11 @@ long __export_restore_thread(struct thread_restore_args *args) goto core_restore_end; ret = restore_creds(args->creds_args, args->ta->proc_fd); + ret = ret || restore_dumpable_flag(&args->ta->mm); + ret = ret || restore_pdeath_sig(args); if (ret) goto core_restore_end; + restore_finish_stage(task_entries_local, CR_STATE_RESTORE_CREDS); futex_dec_and_wake(&thread_inprogress); From e58f5daa9838189b26dedf1d0f5f97b15f3daaa2 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 16 May 2018 11:36:33 +0300 Subject: [PATCH 1556/4375] seccomp: Fix typo in collect_filters *** CID 190178: Null pointer dereferences (NULL_RETURNS) /criu/seccomp.c: 296 in collect_filters() Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/seccomp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/seccomp.c b/criu/seccomp.c index 583860379..bbcbc9841 100644 --- a/criu/seccomp.c +++ b/criu/seccomp.c @@ -287,7 +287,7 @@ static int collect_filters(struct pstree_item *item) for (i = 0; i < item->nr_threads; i++) { entry = seccomp_find_entry(item->threads[i].real); - if (!leader) { + if (!entry) { pr_err("Can't collect filter on tid_real %d\n", item->pid->real); return -1; From b9c5028e38b1822a70ecad763b2ce4ac6094bf3c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 16 May 2018 11:36:37 +0300 Subject: [PATCH 1557/4375] seccomp: Fix building issue on recent kernels The seccomp_metadata may be already defined in system ptrace.h header on recent kernels so include it. https://github.com/checkpoint-restore/criu/issues/486#event-1628406918 Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/seccomp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/seccomp.c b/criu/seccomp.c index bbcbc9841..df7cadff3 100644 --- a/criu/seccomp.c +++ b/criu/seccomp.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "common/config.h" #include "imgset.h" From 2a63e3983b36a139056d5f42011560567a8680c1 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 16 May 2018 11:46:59 +0300 Subject: [PATCH 1558/4375] seccomp: Don't exit from __export_restore_thread After CR_STATE_RESTORE_SIGCHLD stage triggered we are not allowed to exit, just yield the BUG instead. Reported-by: Andrei Vagin Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index f472d05b3..53b14e576 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -559,13 +559,13 @@ long __export_restore_thread(struct thread_restore_args *args) * operation bound to uid 0 in current user ns. */ if (restore_seccomp(args)) - goto core_restore_end; + BUG(); ret = restore_creds(args->creds_args, args->ta->proc_fd); ret = ret || restore_dumpable_flag(&args->ta->mm); ret = ret || restore_pdeath_sig(args); if (ret) - goto core_restore_end; + BUG(); restore_finish_stage(task_entries_local, CR_STATE_RESTORE_CREDS); From 39cf3060a36ed514cc305fdd94b553f5ef4ccf79 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 22 May 2018 23:21:01 +0300 Subject: [PATCH 1559/4375] seccomp: Use own seccomp_metadata_t type On fedora rawhide seccomp_metadata for some reason is not defined (while in kernel it introduced together with PTRACE_SECCOMP_GET_METADATA). So lets do a trick for a while -- define own alias. Once system headers get settled down we might find more suitable solution. Because it's a part of kernel API we're on the safe side. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/include/uapi/ptrace.h | 12 ++++++++---- criu/seccomp.c | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/compel/include/uapi/ptrace.h b/compel/include/uapi/ptrace.h index fcc2d62b0..4df00b6e1 100644 --- a/compel/include/uapi/ptrace.h +++ b/compel/include/uapi/ptrace.h @@ -52,13 +52,17 @@ #ifndef PTRACE_SECCOMP_GET_METADATA # define PTRACE_SECCOMP_GET_METADATA 0x420d +#endif /* PTRACE_SECCOMP_GET_METADATA */ -struct seccomp_metadata { +/* + * struct seccomp_metadata is not yet + * settled down well in headers so use + * own identical definition for a while. + */ +typedef struct { uint64_t filter_off; /* Input: which filter */ uint64_t flags; /* Output: filter's flags */ -}; - -#endif /* PTRACE_SECCOMP_GET_METADATA */ +} seccomp_metadata_t; #ifdef PTRACE_EVENT_STOP # if PTRACE_EVENT_STOP == 7 /* Bad value from Linux 3.1-3.3, fixed in 3.4 */ diff --git a/criu/seccomp.c b/criu/seccomp.c index df7cadff3..94e663d40 100644 --- a/criu/seccomp.c +++ b/criu/seccomp.c @@ -131,7 +131,7 @@ int seccomp_dump_thread(pid_t tid_real, ThreadCoreEntry *thread_core) static int collect_filter(struct seccomp_entry *entry) { - struct seccomp_metadata meta_buf, *meta = &meta_buf; + seccomp_metadata_t meta_buf, *meta = &meta_buf; struct seccomp_filter_chain *chain, *prev; struct sock_filter buf[BPF_MAXINSNS]; size_t i; From 7e50b256b2490fbec453ed12257d5bda5bd7cf84 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 1 Feb 2018 19:04:09 +0300 Subject: [PATCH 1560/4375] criu: fix leaks detected by coverity scan 1) fix sfle memory leak on get_fle_for_scm error 2) fix gfd open descriptor leak on get_fle_for_scm error 3-6) fix buf memory leak on read and pwrite errors Signed-off-by: Pavel Tikhomirov --- criu/files-reg.c | 3 +-- criu/sk-unix.c | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 5da7a8ea8..6583d4df5 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -166,7 +166,6 @@ static int copy_chunk_from_file(int fd, int img, off_t off, size_t len) } xfree(buf); - return 0; } @@ -231,7 +230,6 @@ static int copy_chunk_to_file(int img, int fd, off_t off, size_t len) } xfree(buf); - return 0; } @@ -268,6 +266,7 @@ static int mkreg_ghost(char *path, GhostFileEntry *gfe, struct cr_img *img) if (gfe->chunks) { if (!gfe->has_size) { pr_err("Corrupted ghost image -> no size\n"); + close(gfd); return -1; } diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 1e74357e8..cfe0fa18b 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1055,6 +1055,7 @@ int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ids) sfle->fle = get_fle_for_task(tgt, owner, false); if (!sfle->fle) { pr_err("Can't request new fle for scm\n"); + xfree(sfle); return -1; } From 40ab3c18c8cfb93dc350862eafe0fc318c8090fa Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 21 Mar 2017 02:30:23 +0300 Subject: [PATCH 1561/4375] zdtm: show a process tree if a test doesn't show signs of life Call "ps axf" if waitpid() is running more than 10 seconds Signed-off-by: Andrei Vagin --- test/zdtm.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 9122ad9c7..94d5958b3 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -31,6 +31,13 @@ os.chdir(os.path.dirname(os.path.abspath(__file__))) prev_line = None +def alarm(*args): + print "==== ALARM ====" + + +signal.signal(signal.SIGALRM, alarm) + + def traceit(f, e, a): if e == "line": lineno = f.f_lineno @@ -1622,7 +1629,22 @@ class Launcher: self.wait() def __wait_one(self, flags): - pid, status = os.waitpid(0, flags) + pid = -1 + status = -1 + signal.alarm(10) + while True: + try: + pid, status = os.waitpid(0, flags) + except OSError, e: + if e.errno == errno.EINTR: + subprocess.Popen(["ps", "axf"]).wait() + continue + signal.alarm(0) + raise e + else: + break + signal.alarm(0) + self.__runtest += 1 if pid != 0: sub = self.__subs.pop(pid) From 061c21e6b896c3f1d54a2eb12c952541d248a40e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 16 Aug 2017 10:32:25 +0300 Subject: [PATCH 1562/4375] check/servise: use cached kdat values for features check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The kerndat_init() is now called before the jump to action handler. This allows us to directly use kdat without calling to the corresponding kerndat_*() methods. ✓ travis-ci: success for lazy-pages: update checks for availability of userfaultfd (rev3) Signed-off-by: Mike Rapoport Signed-off-by: Pavel Emelyanov --- criu/cr-check.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index 3e920c12e..d36875eb0 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1064,9 +1064,6 @@ static int check_can_map_vdso(void) static int check_sk_netns(void) { - if (kerndat_socket_netns() < 0) - return -1; - if (!kdat.sk_ns) return -1; @@ -1226,9 +1223,6 @@ static int check_tun_netns(void) static int check_nsid(void) { - if (kerndat_nsid() < 0) - return -1; - if (!kdat.has_nsid) { pr_warn("NSID isn't supported\n"); return -1; @@ -1239,9 +1233,6 @@ static int check_nsid(void) static int check_link_nsid(void) { - if (kerndat_link_nsid() < 0) - return -1; - if (!kdat.has_link_nsid) { pr_warn("NSID isn't supported\n"); return -1; From c971d7a97b7a798182a8df0f9d51823b4eaf1c16 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 10 May 2018 17:17:36 -0700 Subject: [PATCH 1563/4375] zdtm/socket-ext: clean up test files Reported-by: Dmitry Safonov Cc: Dmitry Safonov Signed-off-by: Andrei Vagin Reviewed-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/socket-ext.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/test/zdtm/static/socket-ext.c b/test/zdtm/static/socket-ext.c index c33960dbf..333fb8ce2 100644 --- a/test/zdtm/static/socket-ext.c +++ b/test/zdtm/static/socket-ext.c @@ -29,11 +29,26 @@ int main(int argc, char *argv[]) char *path; pid_t pid; int ret, sk; + char *val; + + unsetenv("ZDTM_GROUPS"); + val = getenv("ZDTM_GID"); + if (val && (setgid(atoi(val)) == -1)) { + fprintf(stderr, "Can't set gid: %m"); + exit(1); + } + + val = getenv("ZDTM_UID"); + if (val && (setuid(atoi(val)) == -1)) { + fprintf(stderr, "Can't set uid: %m"); + exit(1); + } if (mkdtemp(dir) < 0) { pr_perror("mkdtemp(%s) failed", dir); return 1; } + chmod(dir, 0777); addr.sun_family = AF_UNIX; snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", dir, "sock"); @@ -92,8 +107,14 @@ int main(int argc, char *argv[]) test_daemon(); test_waitsig(); - unlink(path); - unlink(dir); + if (unlink(path)) { + pr_perror("Unable to remove %s\n", path); + return 1; + } + if (rmdir(dir)) { + pr_perror("Unable to remove %s", dir); + return 1; + } ret = send(sk, "H", 1, 0); if (ret != 1) { From b4afa08060218148ae1ae0f7a1bdcbc25d62562d Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 2 Jun 2018 00:02:51 +0300 Subject: [PATCH 1564/4375] test: make zdtm.py python2/python3 compatible Cc: Adrian Reber Signed-off-by: Andrei Vagin --- test/zdtm.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 94d5958b3..fa91f01ba 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -32,7 +32,7 @@ prev_line = None def alarm(*args): - print "==== ALARM ====" + print("==== ALARM ====") signal.signal(signal.SIGALRM, alarm) @@ -480,14 +480,14 @@ class zdtm_test: notify_fdout_path = "/proc/%s/fd/%s" % (self.__pid, env['ZDTM_NOTIFY_FDOUT']) notify_fdin_path = "/proc/%s/fd/%s" % (self.__pid, env['ZDTM_NOTIFY_FDIN']) - print "Send pre-dump notify to %s" % (self.__pid) + print("Send pre-dump notify to %s" % (self.__pid)) with open(notify_fdout_path) as fdout: with open(notify_fdin_path, "w") as fdin: fdin.write(struct.pack("i", 0)) fdin.flush() - print "Wait pre-dump notify reply" + print("Wait pre-dump notify reply") ret = struct.unpack('i', fdout.read(4)) - print "Completed pre-dump notify with %d" % (ret) + print("Completed pre-dump notify with %d" % (ret)) def stop(self): self.__freezer.thaw() @@ -500,7 +500,7 @@ class zdtm_test: print_sep(self.__name + '.out.inprogress') print(open(self.__name + '.out.inprogress').read()) print_sep(self.__name + '.out.inprogress') - raise test_fail_exc("result check") + raise test_fail_exc("result check: %s" % list(map(lambda s: s.strip(), res.split())) + res) def getpid(self): if self.__pid == 0: @@ -1635,7 +1635,7 @@ class Launcher: while True: try: pid, status = os.waitpid(0, flags) - except OSError, e: + except OSError as e: if e.errno == errno.EINTR: subprocess.Popen(["ps", "axf"]).wait() continue From d6d9d7f7acd4a7544c9b739fe1266d7b70fe1a85 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 6 Jun 2018 17:30:57 +0300 Subject: [PATCH 1565/4375] zdtm/lib: don't close bad criu_status_in file descriptor in signal handler The criu_status_in is not always used and it may be -1 when the signal handler closes it. With lazy-pages we hit a corner case which clobbers the errno value. This happens when we resume the process inside glibc syscall wrapper and get the signal before the page containing errno is copied. In this case, signal handler is invoked before the syscall return value is written to errno and the actual value of errno seen by the process becomes -EBADF because of close(-1) in the signal handler. Let's ensure that close() in signal handler does not fail to make Jenkins happier while the proper solution for the lazy-pages issue is found. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm/lib/test.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/zdtm/lib/test.c b/test/zdtm/lib/test.c index 70e8ad605..a1bdfc1b4 100644 --- a/test/zdtm/lib/test.c +++ b/test/zdtm/lib/test.c @@ -40,7 +40,8 @@ static void sig_hand(int signo) if (parent) futex_set_and_wake(&test_shared_state->stage, TEST_FAIL_STAGE); futex_set_and_wake(&sig_received, signo); - close(criu_status_in); + if (criu_status_in >= 0) + close(criu_status_in); } static char *outfile; From 81a37d059741497ed86561cc954f0d3d5cdf205d Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 31 Jan 2018 10:24:44 +0000 Subject: [PATCH 1566/4375] remote: Fix incorrect handling of `port` option The `port` option is converted from unsigned short integer to network byte order twice. Unfortunately the 2nd conversion reverses the 1st one. Example: #include #include #include int main() { printf("%d\n", htons(atoi("1234"))); /* 53764 */ printf("%d\n", htons(htons(atoi("1234")))); /* 1234 */ return 0; } Signed-off-by: Radostin Stoyanov --- criu/cr-service.c | 2 +- criu/crtools.c | 2 +- criu/page-xfer.c | 2 +- criu/util.c | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 0928df880..274ff218b 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -377,7 +377,7 @@ static int setup_opts_from_req(int sk, CriuOpts *req) } if (req->ps) { - opts.port = htons((short)req->ps->port); + opts.port = (short)req->ps->port; if (!opts.lazy_pages) { opts.use_page_server = true; diff --git a/criu/crtools.c b/criu/crtools.c index c77f7f3c0..0bb5d2803 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -475,7 +475,7 @@ int main(int argc, char *argv[], char *envp[]) opts.addr = optarg; break; case 1052: - opts.port = htons(atoi(optarg)); + opts.port = atoi(optarg); if (!opts.port) goto bad_arg; break; diff --git a/criu/page-xfer.c b/criu/page-xfer.c index c70aec5fb..e653de5b3 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -1055,7 +1055,7 @@ int disconnect_from_page_server(void) return 0; pr_info("Disconnect from the page server %s:%u\n", - opts.addr, (int)ntohs(opts.port)); + opts.addr, opts.port); if (opts.ps_socket != -1) /* diff --git a/criu/util.c b/criu/util.c index 837e50626..4687b5dd8 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1249,7 +1249,7 @@ static int get_sockaddr_in(struct sockaddr_in *addr, char *host) return -1; } - addr->sin_port = opts.port; + addr->sin_port = htons(opts.port); return 0; } @@ -1259,7 +1259,7 @@ int setup_tcp_server(char *type) struct sockaddr_in saddr; socklen_t slen = sizeof(saddr); - pr_info("Starting %s server on port %u\n", type, (int)ntohs(opts.port)); + pr_info("Starting %s server on port %u\n", type, opts.port); sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sk < 0) { @@ -1349,7 +1349,7 @@ int setup_tcp_client(char *addr) struct sockaddr_in saddr; int sk; - pr_info("Connecting to server %s:%u\n", addr, (int)ntohs(opts.port)); + pr_info("Connecting to server %s:%u\n", addr, opts.port); if (get_sockaddr_in(&saddr, addr)) return -1; From 4001a324cee0e1f48bbb65be46d4c85f9337ab84 Mon Sep 17 00:00:00 2001 From: Pawel Stradomski Date: Wed, 6 Jun 2018 21:09:13 +0200 Subject: [PATCH 1567/4375] Allow criu page-server to work over ipv6. Signed-off-by: Pawel Stradomski Signed-off-by: Andrei Vagin --- criu/util.c | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/criu/util.c b/criu/util.c index 4687b5dd8..16b1c7511 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1237,39 +1237,50 @@ void print_data(unsigned long addr, unsigned char *data, size_t size) } } -static int get_sockaddr_in(struct sockaddr_in *addr, char *host) +static int get_sockaddr_in(struct sockaddr_storage *addr, char *host) { memset(addr, 0, sizeof(*addr)); - addr->sin_family = AF_INET; - if (!host) - addr->sin_addr.s_addr = INADDR_ANY; - else if (!inet_aton(host, &addr->sin_addr)) { + if (!host) { + ((struct sockaddr_in *)addr)->sin_addr.s_addr = INADDR_ANY; + addr->ss_family = AF_INET; + } else if (inet_pton(AF_INET, host, &((struct sockaddr_in *)addr)->sin_addr)) { + addr->ss_family = AF_INET; + } else if (inet_pton(AF_INET6, host, &((struct sockaddr_in6 *)addr)->sin6_addr)) { + addr->ss_family = AF_INET6; + } else { pr_perror("Bad server address"); return -1; } - addr->sin_port = htons(opts.port); + if (addr->ss_family == AF_INET6) { + ((struct sockaddr_in6 *)addr)->sin6_port = htons(opts.port); + } else if (addr->ss_family == AF_INET) { + ((struct sockaddr_in *)addr)->sin_port = htons(opts.port); + } + return 0; } int setup_tcp_server(char *type) { int sk = -1; - struct sockaddr_in saddr; + struct sockaddr_storage saddr; socklen_t slen = sizeof(saddr); + if (get_sockaddr_in(&saddr, opts.addr)) { + return -1; + } + pr_info("Starting %s server on port %u\n", type, opts.port); - sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + sk = socket(saddr.ss_family, SOCK_STREAM, IPPROTO_TCP); + if (sk < 0) { pr_perror("Can't init %s server", type); return -1; } - if (get_sockaddr_in(&saddr, opts.addr)) - goto out; - if (bind(sk, (struct sockaddr *)&saddr, slen)) { pr_perror("Can't bind %s server", type); goto out; @@ -1287,7 +1298,12 @@ int setup_tcp_server(char *type) goto out; } - opts.port = ntohs(saddr.sin_port); + if (saddr.ss_family == AF_INET6) { + opts.port = ntohs(((struct sockaddr_in *)&saddr)->sin_port); + } else if (saddr.ss_family == AF_INET) { + opts.port = ntohs(((struct sockaddr_in6 *)&saddr)->sin6_port); + } + pr_info("Using %u port\n", opts.port); } @@ -1346,7 +1362,7 @@ out: int setup_tcp_client(char *addr) { - struct sockaddr_in saddr; + struct sockaddr_storage saddr; int sk; pr_info("Connecting to server %s:%u\n", addr, opts.port); @@ -1354,7 +1370,7 @@ int setup_tcp_client(char *addr) if (get_sockaddr_in(&saddr, addr)) return -1; - sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + sk = socket(saddr.ss_family, SOCK_STREAM, IPPROTO_TCP); if (sk < 0) { pr_perror("Can't create socket"); return -1; From 54858b1360b2c7a3dad812c0dda2a11d15259c93 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 27 Jun 2017 14:21:44 +0300 Subject: [PATCH 1568/4375] compel, x86_64: Fix sys_clone() definition Commit 37e4c7bfc264 fixed arm, ppc, x86 (32bit), while it made wrong definition of x86_64. Fix that. Also, add commentary to raw fork() implementation. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- compel/arch/x86/plugins/std/syscalls/syscall_64.tbl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl index 0200111c7..726fa7970 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl @@ -37,7 +37,7 @@ __NR_shutdown 48 sys_shutdown (int sockfd, int how) __NR_bind 49 sys_bind (int sockfd, const struct sockaddr *addr, int addrlen) __NR_setsockopt 54 sys_setsockopt (int sockfd, int level, int optname, const void *optval, socklen_t optlen) __NR_getsockopt 55 sys_getsockopt (int sockfd, int level, int optname, const void *optval, socklen_t *optlen) -__NR_clone 56 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, unsigned long newtls, void *child_tid) +__NR_clone 56 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, void *child_tid, unsigned long new_tls) __NR_exit 60 sys_exit (unsigned long error_code) __NR_wait4 61 sys_wait4 (int pid, int *status, int options, struct rusage *ru) __NR_kill 62 sys_kill (long pid, int sig) From 3b33e16f3e7e38f987d7546c5f01967b2011b38b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 16 May 2018 11:36:36 +0300 Subject: [PATCH 1569/4375] mem: Fix typo in detect_pid_reuse *** CID 190172: Uninitialized variables (UNINIT) /criu/mem.c: 325 in detect_pid_reuse() Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/mem.c b/criu/mem.c index c747785f1..d28bc39bf 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -323,7 +323,7 @@ static int detect_pid_reuse(struct pstree_item *item, if (pps->start_time >= dump_ticks) { /* Print "*" if unsure */ pr_warn("Pid reuse%s detected for pid %d\n", - pps_buf.start_time == dump_ticks ? "*" : "", + pps->start_time == dump_ticks ? "*" : "", item->pid->real); return 1; } From 4d9bf608b59b6e323f346b0beb956b02ecbef294 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 6 Apr 2018 10:31:32 +0300 Subject: [PATCH 1570/4375] zdtm: check that pid-reuse does not break iterative memory dump The idea of the test is: 1) mmap separate page and put variable there, so that other usage does not dirty these region. Initialize the variable with VALUE_A. 2) fork a child with special pid == CHILD_NS_PID. Only if it is a first child overwrite the variable with VALUE_B. 3) wait for the end of the next predump or end of restore with test_wait_pre_dump_ack/test_wait_pre_dump pair and kill our child. Note: The memory region is "clean" in parent. 4) goto (2) unles end of cr is reported by test_waitpre So on first iteration child with pid CHILD_NS_PID was dumped with VALUE_B, on all other iterations and on final dump other child with the same pid exists but with VALUE_A. But on all iterations after the first one we have these memory region "clean". So criu before the fix would have restored the VALUE_B taking it from first child's image, but should restore VALUE_A. Note: Child in its turn waits termination and performs a check that variable value doesn't change after c/r. We should run the test with at least one predump to trigger the problem: [root@snorch criu]# ./test/zdtm.py run --pre 1 -k always -t zdtm/transition/pid_reuse Checking feature ns_pid Checking feature ns_get_userns Checking feature ns_get_parent === Run 1/1 ================ zdtm/transition/pid_reuse ===================== Run zdtm/transition/pid_reuse in ns ====================== DEP pid_reuse.d CC pid_reuse.o LINK pid_reuse Start test Test is SUID ./pid_reuse --pidfile=pid_reuse.pid --outfile=pid_reuse.out Run criu pre-dump Send the 10 signal to 52 Run criu dump Run criu restore Send the 15 signal to 73 Wait for zdtm/transition/pid_reuse(73) to die for 0.100000 Test output: ================================ 14:47:57.717: 11235: ERR: pid_reuse.c:76: Wrong value in a variable after restore 14:47:57.717: 4: FAIL: pid_reuse.c:110: Task 11235 exited with wrong code 1 (errno = 11 (Resource temporarily unavailable)) <<< ================================ https://jira.sw.ru/browse/PSBM-67502 v3: simplify waitpid's status check v9: switch to test_wait_pre_dump(_ack) Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm/transition/Makefile | 1 + test/zdtm/transition/pid_reuse.c | 116 ++++++++++++++++++++++++++++ test/zdtm/transition/pid_reuse.desc | 1 + 3 files changed, 118 insertions(+) create mode 100644 test/zdtm/transition/pid_reuse.c create mode 100644 test/zdtm/transition/pid_reuse.desc diff --git a/test/zdtm/transition/Makefile b/test/zdtm/transition/Makefile index f482a8a09..35301ac85 100644 --- a/test/zdtm/transition/Makefile +++ b/test/zdtm/transition/Makefile @@ -21,6 +21,7 @@ TST_NOFILE = \ socket-tcp6 \ shmem \ lazy-thp \ + pid_reuse \ TST_FILE = \ diff --git a/test/zdtm/transition/pid_reuse.c b/test/zdtm/transition/pid_reuse.c new file mode 100644 index 000000000..f8f923069 --- /dev/null +++ b/test/zdtm/transition/pid_reuse.c @@ -0,0 +1,116 @@ +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Tests that forking tasks with same pid does not break iterative dump"; +const char *test_author = "Pavel Tikhomirov "; + +enum { + VALUE_A = 1, + VALUE_B = 2, +}; + +#define CHILD_NS_PID 11235 + +static int set_ns_next_pid(pid_t pid) +{ + char buf[32]; + int len, fd; + + fd = open("/proc/sys/kernel/ns_last_pid", O_WRONLY); + if (fd < 0) { + pr_perror("Failed to open ns_last_pid"); + return -1; + } + + len = snprintf(buf, sizeof(buf), "%d", pid - 1); + len -= write(fd, buf, len); + if (len) + pr_perror("Can't set ns_last_pid"); + close(fd); + + return len ? -1 : 0; +} + +int main(int argc, char **argv) +{ + int pid, wpid, status; + bool overwrite = true; + bool wait = true; + int *variable; + void *mem; + + test_init(argc, argv); + + mem = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (mem == MAP_FAILED) { + pr_perror("Can't mmap memory region"); + return 1; + } + + variable = (int *)mem; + *variable = VALUE_A; + + test_daemon(); + + while (wait) { + if (set_ns_next_pid(CHILD_NS_PID)) + return 1; + + pid = fork(); + if (pid == -1) { + pr_perror("fork"); + return 1; + } else if (pid == 0) { + if (overwrite) + *variable = VALUE_B; + + /* Reuse test_waitsig to wait SIGTERM from parent */ + test_waitsig(); + + if (*variable != (overwrite ? VALUE_B : VALUE_A)) { + pr_err("Wrong value in a variable after restore\n"); + exit(1); + } + exit(0); + } + + if (pid != CHILD_NS_PID) { + pr_err("Child started with wrong pid %d (expected %d)\n", pid, CHILD_NS_PID); + kill(pid, SIGKILL); + waitpid(pid, NULL, 0); + return 1; + } + + /* Notify we are ready for a next pre-dump/dump */ + if (!overwrite) + test_wait_pre_dump_ack(); + + /* Wait for next pre-dump/dump finish */ + if (test_wait_pre_dump()) + wait = false; + + if (kill(pid, SIGTERM)) { + pr_perror("kill"); + return 1; + } + + wpid = waitpid(pid, &status, 0); + if (wpid <= 0) { + pr_perror("waitpid"); + return 1; + } + + if (status) { + fail("Task %d died with exit status %x", wpid, status); + return 1; + } + + overwrite = false; + } + + pass(); + return 0; +} diff --git a/test/zdtm/transition/pid_reuse.desc b/test/zdtm/transition/pid_reuse.desc new file mode 100644 index 000000000..474f44ebf --- /dev/null +++ b/test/zdtm/transition/pid_reuse.desc @@ -0,0 +1 @@ +{'flags': 'suid pre-dump-notify'} From b988fae54436cf110a3d3c15e3cff68e44def60f Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 5 Oct 2017 23:17:05 +0300 Subject: [PATCH 1571/4375] travis/docker-test: use make to install criu Signed-off-by: Andrei Vagin --- scripts/travis/docker-test.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/travis/docker-test.sh b/scripts/travis/docker-test.sh index 8ed02863b..0f034cfa6 100755 --- a/scripts/travis/docker-test.sh +++ b/scripts/travis/docker-test.sh @@ -33,8 +33,7 @@ export SKIP_TRAVIS_TEST=1 cd ../../ -touch /usr/sbin/criu -mount --bind criu/criu /usr/sbin/criu +make install docker info From a9e29bc5961a327e451102be24af93e99ec8bb3f Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 9 May 2018 17:08:27 +0000 Subject: [PATCH 1572/4375] Fix building unlink_fstat00 unlink test case Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/zdtm/static/unlink_fstat00.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/zdtm/static/unlink_fstat00.c b/test/zdtm/static/unlink_fstat00.c index faafb1b7f..79ea90274 100644 --- a/test/zdtm/static/unlink_fstat00.c +++ b/test/zdtm/static/unlink_fstat00.c @@ -9,6 +9,14 @@ #include "zdtmtst.h" +#ifndef __O_TMPFILE +#define __O_TMPFILE 020000000 +#endif + +#ifndef O_TMPFILE +#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) +#endif + const char *test_doc = "Open, unlink, change size, seek, migrate, check size"; #ifdef UNLINK_FSTAT04 From 5c76d061866ea5d62e3faec19caf56bd6dcc3eca Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 9 Jun 2018 20:30:48 +0300 Subject: [PATCH 1573/4375] zdtm: open notify file descriptors in a binary mode Send pre-dump notify to 36 Traceback (most recent call last): File "zdtm.py", line 2161, in do_run_test(tinfo[0], tinfo[1], tinfo[2], tinfo[3]) File "zdtm.py", line 1549, in do_run_test cr(cr_api, t, opts) File "zdtm.py", line 1264, in cr test.pre_dump_notify() File "zdtm.py", line 490, in pre_dump_notify fdin.write(struct.pack("i", 0)) TypeError: write() argument 1 must be unicode, not str Signed-off-by: Andrei Vagin --- test/zdtm.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index fa91f01ba..b99db2478 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -481,8 +481,8 @@ class zdtm_test: notify_fdin_path = "/proc/%s/fd/%s" % (self.__pid, env['ZDTM_NOTIFY_FDIN']) print("Send pre-dump notify to %s" % (self.__pid)) - with open(notify_fdout_path) as fdout: - with open(notify_fdin_path, "w") as fdin: + with open(notify_fdout_path, "rb") as fdout: + with open(notify_fdin_path, "wb") as fdin: fdin.write(struct.pack("i", 0)) fdin.flush() print("Wait pre-dump notify reply") @@ -500,7 +500,7 @@ class zdtm_test: print_sep(self.__name + '.out.inprogress') print(open(self.__name + '.out.inprogress').read()) print_sep(self.__name + '.out.inprogress') - raise test_fail_exc("result check: %s" % list(map(lambda s: s.strip(), res.split())) + res) + raise test_fail_exc("result check") def getpid(self): if self.__pid == 0: From fc11d59db11c8f3b7e43e93f6a0cbfee153f077a Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 28 Jun 2018 09:46:45 +0000 Subject: [PATCH 1574/4375] travis: fix building on s390x The travis build for s390x started to fail with: Failed to fetch http://security.debian.org/debian-security/dists/jessie/updates/InRelease Unable to find expected entry 'main/binary-s390x/Packages' in Release file (Wrong sources.list entry or malformed file) This changes the repository definition just like it is done for ppc64le. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.s390x.hdr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/build/Dockerfile.s390x.hdr b/scripts/build/Dockerfile.s390x.hdr index 37ff20832..7c92fe093 100644 --- a/scripts/build/Dockerfile.s390x.hdr +++ b/scripts/build/Dockerfile.s390x.hdr @@ -2,3 +2,5 @@ FROM s390x/debian:jessie-backports ENV QEMU_CPU z900 COPY scripts/build/qemu-user-static/usr/bin/qemu-s390x-static /usr/bin/qemu-s390x-static +# The security repository does not seem to exist anymore +RUN sed -i '/security/ d' /etc/apt/sources.list From c49eab368a68682475c4e693258246e04232e6d2 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 10 Jul 2018 07:04:49 +0300 Subject: [PATCH 1575/4375] criu: Version 3.10 Signed-off-by: Andrei Vagin --- Makefile.versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index 996f544d1..2e149de83 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 9 +CRIU_VERSION_MINOR := 10 CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Sand Martin +CRIU_VERSION_NAME := Granite Eagle CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From 380df8a605ea8c0d88e1c6f7a5ed205547928600 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 28 Apr 2018 10:59:17 +0300 Subject: [PATCH 1576/4375] inventory: save dump_uptime for criu dump if track_mem is set A set of images from criu dump can be used as a previous point, when we are doing snapshots. In this case, each point contains a full set of images. https://github.com/checkpoint-restore/criu/issues/479 v2: return -1 if invertory_save_uptime failed Cc: Pavel Tikhomirov Signed-off-by: Andrei Vagin Reviewed-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 12 ++++++++++-- criu/image.c | 16 +++++++++++----- criu/include/crtools.h | 2 +- criu/mem.c | 12 ++++++------ 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 21520c5c2..8cf20177e 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1472,10 +1472,14 @@ static int cr_pre_dump_finish(int ret) * Restore registers for tasks only. The threads have not been * infected. Therefore, the thread register sets have not been changed. */ - if (arch_set_thread_regs(root_item, false) < 0) + ret = arch_set_thread_regs(root_item, false); + if (ret) + goto err; + + ret = invertory_save_uptime(&he); + if (ret) goto err; - prepare_inventory_pre_dump(&he); pstree_switch_state(root_item, TASK_ALIVE); timing_stop(TIME_FROZEN); @@ -1882,6 +1886,10 @@ int cr_dump_tasks(pid_t pid) if (ret) goto err; + ret = invertory_save_uptime(&he); + if (ret) + goto err; + ret = write_img_inventory(&he); if (ret) goto err; diff --git a/criu/image.c b/criu/image.c index 243e4a1a2..60112398c 100644 --- a/criu/image.c +++ b/criu/image.c @@ -106,14 +106,20 @@ int write_img_inventory(InventoryEntry *he) return 0; } -void prepare_inventory_pre_dump(InventoryEntry *he) +int invertory_save_uptime(InventoryEntry *he) { - pr_info("Perparing image inventory for pre-dump (version %u)\n", CRTOOLS_IMAGES_V1); + if (!opts.track_mem) + return 0; - he->img_version = CRTOOLS_IMAGES_V1_1; + /* + * dump_uptime is used to detect whether a process was handled + * before or it is a new process with the same pid. + */ + if (parse_uptime(&he->dump_uptime)) + return -1; - if (!parse_uptime(&he->dump_uptime)) - he->has_dump_uptime = true; + he->has_dump_uptime = true; + return 0; } InventoryEntry *get_parent_inventory(void) diff --git a/criu/include/crtools.h b/criu/include/crtools.h index 2c21e822a..7b2dc4523 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -12,7 +12,7 @@ extern int check_img_inventory(void); extern int write_img_inventory(InventoryEntry *he); -extern void prepare_inventory_pre_dump(InventoryEntry *he); +extern int invertory_save_uptime(InventoryEntry *he); extern InventoryEntry *get_parent_inventory(void); extern int prepare_inventory(InventoryEntry *he); struct pprep_head { diff --git a/criu/mem.c b/criu/mem.c index d28bc39bf..d020b7fd4 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -299,6 +299,12 @@ static int detect_pid_reuse(struct pstree_item *item, unsigned long long tps; /* ticks per second */ int ret; + if (!parent_ie) { + pr_err("Pid-reuse detection failed: no parent inventory, " \ + "check warnings in get_parent_stats\n"); + return -1; + } + tps = sysconf(_SC_CLK_TCK); if (tps == -1) { pr_perror("Failed to get clock ticks via sysconf"); @@ -312,12 +318,6 @@ static int detect_pid_reuse(struct pstree_item *item, return -1; } - if (!parent_ie) { - pr_err("Pid-reuse detection failed: no parent inventory, " \ - "check warnings in get_parent_stats\n"); - return -1; - } - dump_ticks = parent_ie->dump_uptime/(USEC_PER_SEC/tps); if (pps->start_time >= dump_ticks) { From 3d30627082c413e1020d8719784910d9225d6262 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 14 Jun 2018 20:27:22 +0300 Subject: [PATCH 1577/4375] x86: cpu -- Sync bits with kernel Tracking cpuid features is easier when sync'ed with kernel source code. Note though that while in kernel feature bits are not part of ABI, we're saving bits into an image so as result make sure they are posted in proper place together with keeping in mind the backward compatibility issue. Here we also start using v2 of cpuinfo image with more feature bits. Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/cpu.c | 85 +++-- compel/arch/x86/src/lib/include/cpu.h | 8 + .../arch/x86/src/lib/include/uapi/asm/cpu.h | 298 ++++++++++++++---- criu/arch/x86/cpu.c | 264 ++++++++++------ 4 files changed, 478 insertions(+), 177 deletions(-) diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c index dbd3136f0..f8d5e1ba3 100644 --- a/compel/arch/x86/src/lib/cpu.c +++ b/compel/arch/x86/src/lib/cpu.c @@ -34,6 +34,8 @@ int compel_test_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) int compel_cpuid(compel_cpuinfo_t *c) { + uint32_t eax, ebx, ecx, edx; + /* * See cpu_detect() in the kernel, also * read cpuid specs not only from general @@ -62,8 +64,6 @@ int compel_cpuid(compel_cpuinfo_t *c) /* Intel-defined flags: level 0x00000001 */ if (c->cpuid_level >= 0x00000001) { - uint32_t eax, ebx, ecx, edx; - cpuid(0x00000001, &eax, &ebx, &ecx, &edx); c->x86_family = (eax >> 8) & 0xf; c->x86_model = (eax >> 4) & 0xf; @@ -74,34 +74,51 @@ int compel_cpuid(compel_cpuinfo_t *c) if (c->x86_family >= 0x6) c->x86_model += ((eax >> 16) & 0xf) << 4; - c->x86_capability[0] = edx; - c->x86_capability[4] = ecx; + c->x86_capability[CPUID_1_EDX] = edx; + c->x86_capability[CPUID_1_ECX] = ecx; } + /* Thermal and Power Management Leaf: level 0x00000006 (eax) */ + if (c->cpuid_level >= 0x00000006) + c->x86_capability[CPUID_6_EAX] = cpuid_eax(0x00000006); + /* Additional Intel-defined flags: level 0x00000007 */ if (c->cpuid_level >= 0x00000007) { - uint32_t eax, ebx, ecx, edx; - cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx); - c->x86_capability[9] = ebx; - c->x86_capability[11] = ecx; + c->x86_capability[CPUID_7_0_EBX] = ebx; + c->x86_capability[CPUID_7_0_ECX] = ecx; + c->x86_capability[CPUID_7_0_EDX] = edx; } /* Extended state features: level 0x0000000d */ if (c->cpuid_level >= 0x0000000d) { - uint32_t eax, ebx, ecx, edx; - cpuid_count(0x0000000d, 1, &eax, &ebx, &ecx, &edx); - c->x86_capability[10] = eax; + c->x86_capability[CPUID_D_1_EAX] = eax; + } + + /* Additional Intel-defined flags: level 0x0000000F */ + if (c->cpuid_level >= 0x0000000F) { + /* QoS sub-leaf, EAX=0Fh, ECX=0 */ + cpuid_count(0x0000000F, 0, &eax, &ebx, &ecx, &edx); + c->x86_capability[CPUID_F_0_EDX] = edx; + + if (compel_test_cpu_cap(c, X86_FEATURE_CQM_LLC)) { + /* QoS sub-leaf, EAX=0Fh, ECX=1 */ + cpuid_count(0x0000000F, 1, &eax, &ebx, &ecx, &edx); + c->x86_capability[CPUID_F_1_EDX] = edx; + } } /* AMD-defined flags: level 0x80000001 */ - c->extended_cpuid_level = cpuid_eax(0x80000000); + eax = cpuid_eax(0x80000000); + c->extended_cpuid_level = eax; - if ((c->extended_cpuid_level & 0xffff0000) == 0x80000000) { - if (c->extended_cpuid_level >= 0x80000001) { - c->x86_capability[1] = cpuid_edx(0x80000001); - c->x86_capability[6] = cpuid_ecx(0x80000001); + if ((eax & 0xffff0000) == 0x80000000) { + if (eax >= 0x80000001) { + cpuid(0x80000001, &eax, &ebx, &ecx, &edx); + + c->x86_capability[CPUID_8000_0001_ECX] = ecx; + c->x86_capability[CPUID_8000_0001_EDX] = edx; } } @@ -109,6 +126,9 @@ int compel_cpuid(compel_cpuinfo_t *c) * We're don't care about scattered features for now, * otherwise look into init_scattered_cpuid_features() * in kernel. + * + * Same applies to speculation control. Look into + * init_speculation_control() otherwise. */ if (c->extended_cpuid_level >= 0x80000004) { @@ -135,9 +155,39 @@ int compel_cpuid(compel_cpuinfo_t *c) } } + if (c->extended_cpuid_level >= 0x80000007) { + cpuid(0x80000007, &eax, &ebx, &ecx, &edx); + + c->x86_capability[CPUID_8000_0007_EBX] = ebx; + c->x86_power = edx; + } + + if (c->extended_cpuid_level >= 0x8000000a) + c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a); + + if (c->extended_cpuid_level >= 0x80000008) + c->x86_capability[CPUID_8000_0008_EBX] = cpuid_ebx(0x80000008); + + /* On x86-64 CPUID is always present */ + compel_set_cpu_cap(c, X86_FEATURE_CPUID); + /* On x86-64 NOP is always present */ compel_set_cpu_cap(c, X86_FEATURE_NOPL); + /* + * On x86-64 syscalls32 are enabled but we don't + * set it yet for backward compatibility reason + */ + //compel_set_cpu_cap(c, X86_FEATURE_SYSCALL32); + + /* See filter_cpuid_features in kernel */ + if ((int32_t)c->cpuid_level < (int32_t)0x0000000d) + compel_clear_cpu_cap(c, X86_FEATURE_XSAVE); + + /* + * We only care about small subset from c_early_init: + * early_init_amd and early_init_intel + */ switch (c->x86_vendor) { case X86_VENDOR_INTEL: /* @@ -152,9 +202,6 @@ int compel_cpuid(compel_cpuinfo_t *c) compel_set_cpu_cap(c, X86_FEATURE_REP_GOOD); } - /* See filter_cpuid_features in kernel */ - if ((int32_t)c->cpuid_level < (int32_t)0x0000000d) - compel_clear_cpu_cap(c, X86_FEATURE_XSAVE); break; case X86_VENDOR_AMD: /* diff --git a/compel/arch/x86/src/lib/include/cpu.h b/compel/arch/x86/src/lib/include/cpu.h index 396fcfdbe..60b7d24d4 100644 --- a/compel/arch/x86/src/lib/include/cpu.h +++ b/compel/arch/x86/src/lib/include/cpu.h @@ -40,6 +40,14 @@ static inline unsigned int cpuid_eax(unsigned int op) return eax; } +static inline unsigned int cpuid_ebx(unsigned int op) +{ + unsigned int eax, ebx, ecx, edx; + + cpuid(op, &eax, &ebx, &ecx, &edx); + return ebx; +} + static inline unsigned int cpuid_ecx(unsigned int op) { unsigned int eax, ebx, ecx, edx; diff --git a/compel/arch/x86/src/lib/include/uapi/asm/cpu.h b/compel/arch/x86/src/lib/include/uapi/asm/cpu.h index 90d777080..65f0576f2 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/cpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/cpu.h @@ -5,121 +5,310 @@ /* * Adopted from linux kernel and enhanced from Intel/AMD manuals. + * Note these bits are not ABI for linux kernel but they _are_ + * for us, so make sure they are at proper position between + * versions. + * + * In particular since we aready used leaf 11 we have + * to keep it here, since it's an ABI now. */ +enum cpuid_leafs { + CPUID_1_EDX = 0, + CPUID_8000_0001_EDX = 1, + CPUID_8086_0001_EDX = 2, + CPUID_LNX_1 = 3, + CPUID_1_ECX = 4, + CPUID_C000_0001_EDX = 5, + CPUID_8000_0001_ECX = 6, + CPUID_LNX_2 = 7, + CPUID_LNX_3 = 8, + CPUID_7_0_EBX = 9, + CPUID_D_1_EAX = 10, + CPUID_7_0_ECX = 11, + CPUID_F_1_EDX = 12, + CPUID_8000_0008_EBX = 13, + CPUID_6_EAX = 14, + CPUID_8000_000A_EDX = 15, + CPUID_F_0_EDX = 16, + CPUID_8000_0007_EBX = 17, + CPUID_7_0_EDX = 18, +}; -#define NCAPINTS (12) /* N 32-bit words worth of info */ +#define NCAPINTS_V1 12 +#define NCAPINTS_V2 19 + +#define NCAPINTS (NCAPINTS_V2) /* N 32-bit words worth of info */ #define NCAPINTS_BITS (NCAPINTS * 32) +/* Intel-defined CPU features, CPUID level 0x00000001 (EDX), word 0 */ #define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */ -#define X86_FEATURE_VME (0*32+ 1) /* Virtual 8086 Mode Enhancements */ +#define X86_FEATURE_VME (0*32+ 1) /* Virtual Mode Extensions */ #define X86_FEATURE_DE (0*32+ 2) /* Debugging Extensions */ -#define X86_FEATURE_PSE (0*32+ 3) /* Page Size Extension */ +#define X86_FEATURE_PSE (0*32+ 3) /* Page Size Extensions */ #define X86_FEATURE_TSC (0*32+ 4) /* Time Stamp Counter */ -#define X86_FEATURE_MSR (0*32+ 5) /* Model Specific Registers RDMSR and WRMSR Instructions */ -#define X86_FEATURE_PAE (0*32+ 6) /* Physical Address Extension */ +#define X86_FEATURE_MSR (0*32+ 5) /* Model-Specific Registers */ +#define X86_FEATURE_PAE (0*32+ 6) /* Physical Address Extensions */ #define X86_FEATURE_MCE (0*32+ 7) /* Machine Check Exception */ #define X86_FEATURE_CX8 (0*32+ 8) /* CMPXCHG8 instruction */ -#define X86_FEATURE_APIC (0*32+ 9) /* APIC On-Chip */ -#define X86_FEATURE_SEP (0*32+11) /* SYSENTER and SYSEXIT Instructions */ +#define X86_FEATURE_APIC (0*32+ 9) /* Onboard APIC */ +#define X86_FEATURE_SEP (0*32+11) /* SYSENTER/SYSEXIT */ #define X86_FEATURE_MTRR (0*32+12) /* Memory Type Range Registers */ -#define X86_FEATURE_PGE (0*32+13) /* PTE Global Bit */ +#define X86_FEATURE_PGE (0*32+13) /* Page Global Enable */ #define X86_FEATURE_MCA (0*32+14) /* Machine Check Architecture */ #define X86_FEATURE_CMOV (0*32+15) /* CMOV instructions (plus FCMOVcc, FCOMI with FPU) */ #define X86_FEATURE_PAT (0*32+16) /* Page Attribute Table */ -#define X86_FEATURE_PSE36 (0*32+17) /* 36-Bit Page Size Extension */ -#define X86_FEATURE_PSN (0*32+18) /* Processor Serial Number */ -#define X86_FEATURE_DS (0*32+21) /* Debug Store */ +#define X86_FEATURE_PSE36 (0*32+17) /* 36-bit PSEs */ +#define X86_FEATURE_PN (0*32+18) /* Processor serial number */ #define X86_FEATURE_CLFLUSH (0*32+19) /* CLFLUSH instruction */ -#define X86_FEATURE_ACPI (0*32+22) /* Thermal Monitor and Software Controlled Clock Facilities */ +#define X86_FEATURE_DS (0*32+21) /* "dts" Debug Store */ +#define X86_FEATURE_ACPI (0*32+22) /* ACPI via MSR */ #define X86_FEATURE_MMX (0*32+23) /* Multimedia Extensions */ #define X86_FEATURE_FXSR (0*32+24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */ #define X86_FEATURE_XMM (0*32+25) /* "sse" */ #define X86_FEATURE_XMM2 (0*32+26) /* "sse2" */ -#define X86_FEATURE_SS (0*32+27) /* Self Snoop */ -#define X86_FEATURE_HTT (0*32+28) /* Multi-Threading */ -#define X86_FEATURE_TM (0*32+29) /* Thermal Monitor */ +#define X86_FEATURE_SELFSNOOP (0*32+27) /* "ss" CPU self snoop */ +#define X86_FEATURE_HT (0*32+28) /* Hyper-Threading */ +#define X86_FEATURE_ACC (0*32+29) /* "tm" Automatic clock control */ +#define X86_FEATURE_IA64 (0*32+30) /* IA-64 processor */ #define X86_FEATURE_PBE (0*32+31) /* Pending Break Enable */ +/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */ +/* Don't duplicate feature flags which are redundant with Intel! */ #define X86_FEATURE_SYSCALL (1*32+11) /* SYSCALL/SYSRET */ +#define X86_FEATURE_MP (1*32+19) /* MP Capable */ +#define X86_FEATURE_NX (1*32+20) /* Execute Disable */ #define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */ +#define X86_FEATURE_FXSR_OPT (1*32+25) /* FXSAVE/FXRSTOR optimizations */ +#define X86_FEATURE_GBPAGES (1*32+26) /* "pdpe1gb" GB pages */ #define X86_FEATURE_RDTSCP (1*32+27) /* RDTSCP */ -#define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */ -#define X86_FEATURE_3DNOW (1*32+31) /* 3DNow! */ +#define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64, 64-bit support) */ +#define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow extensions */ +#define X86_FEATURE_3DNOW (1*32+31) /* 3DNow */ -#define X86_FEATURE_REP_GOOD (3*32+16) /* rep microcode works well */ +/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */ +#define X86_FEATURE_RECOVERY (2*32+ 0) /* CPU in recovery mode */ +#define X86_FEATURE_LONGRUN (2*32+ 1) /* Longrun power control */ +#define X86_FEATURE_LRTI (2*32+ 3) /* LongRun table interface */ + +/* Other features, Linux-defined mapping, word 3 */ +/* This range is used for feature bits which conflict or are synthesized */ +#define X86_FEATURE_CXMMX (3*32+ 0) /* Cyrix MMX extensions */ +#define X86_FEATURE_K6_MTRR (3*32+ 1) /* AMD K6 nonstandard MTRRs */ +#define X86_FEATURE_CYRIX_ARR (3*32+ 2) /* Cyrix ARRs (= MTRRs) */ +#define X86_FEATURE_CENTAUR_MCR (3*32+ 3) /* Centaur MCRs (= MTRRs) */ + +/* CPU types for specific tunings: */ +#define X86_FEATURE_K8 (3*32+ 4) /* "" Opteron, Athlon64 */ +#define X86_FEATURE_K7 (3*32+ 5) /* "" Athlon */ +#define X86_FEATURE_P3 (3*32+ 6) /* "" P3 */ +#define X86_FEATURE_P4 (3*32+ 7) /* "" P4 */ +#define X86_FEATURE_CONSTANT_TSC (3*32+ 8) /* TSC ticks at a constant rate */ +#define X86_FEATURE_UP (3*32+ 9) /* SMP kernel running on UP */ +#define X86_FEATURE_ART (3*32+10) /* Always running timer (ART) */ +#define X86_FEATURE_ARCH_PERFMON (3*32+11) /* Intel Architectural PerfMon */ +#define X86_FEATURE_PEBS (3*32+12) /* Precise-Event Based Sampling */ +#define X86_FEATURE_BTS (3*32+13) /* Branch Trace Store */ +#define X86_FEATURE_SYSCALL32 (3*32+14) /* "" syscall in IA32 userspace */ +#define X86_FEATURE_SYSENTER32 (3*32+15) /* "" sysenter in IA32 userspace */ +#define X86_FEATURE_REP_GOOD (3*32+16) /* REP microcode works well */ +#define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* "" MFENCE synchronizes RDTSC */ +#define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* "" LFENCE synchronizes RDTSC */ +#define X86_FEATURE_ACC_POWER (3*32+19) /* AMD Accumulated Power Mechanism */ #define X86_FEATURE_NOPL (3*32+20) /* The NOPL (0F 1F) instructions */ +#define X86_FEATURE_ALWAYS (3*32+21) /* "" Always-present feature */ +#define X86_FEATURE_XTOPOLOGY (3*32+22) /* CPU topology enum extensions */ +#define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */ +#define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */ +#define X86_FEATURE_CPUID (3*32+25) /* CPU has CPUID instruction itself */ +#define X86_FEATURE_EXTD_APICID (3*32+26) /* Extended APICID (8 bits) */ +#define X86_FEATURE_AMD_DCM (3*32+27) /* AMD multi-node processor */ +#define X86_FEATURE_APERFMPERF (3*32+28) /* P-State hardware coordination feedback capability (APERF/MPERF MSRs) */ +#define X86_FEATURE_NONSTOP_TSC_S3 (3*32+30) /* TSC doesn't stop in S3 state */ +#define X86_FEATURE_TSC_KNOWN_FREQ (3*32+31) /* TSC has known frequency */ +/* Intel-defined CPU features, CPUID level 0x00000001 (ECX), word 4 */ #define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */ #define X86_FEATURE_PCLMULQDQ (4*32+ 1) /* PCLMULQDQ instruction */ -#define X86_FEATURE_DTES64 (4*32+ 2) /* 64-bit DS Area */ -#define X86_FEATURE_MWAIT (4*32+ 3) /* "monitor" Monitor/Mwait support */ -#define X86_FEATURE_DSCPL (4*32+ 4) /* CPL Qualified Debug Store */ -#define X86_FEATURE_VMX (4*32+ 5) /* Virtual Machine Extensions */ -#define X86_FEATURE_SMX (4*32+ 6) /* Safer Mode Extensions */ -#define X86_FEATURE_EST (4*32+ 7) /* Enhanced Intel SpeedStep technology */ +#define X86_FEATURE_DTES64 (4*32+ 2) /* 64-bit Debug Store */ +#define X86_FEATURE_MWAIT (4*32+ 3) /* "monitor" MONITOR/MWAIT support */ +#define X86_FEATURE_DSCPL (4*32+ 4) /* "ds_cpl" CPL-qualified (filtered) Debug Store */ +#define X86_FEATURE_VMX (4*32+ 5) /* Hardware virtualization */ +#define X86_FEATURE_SMX (4*32+ 6) /* Safer Mode eXtensions */ +#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */ #define X86_FEATURE_TM2 (4*32+ 8) /* Thermal Monitor 2 */ #define X86_FEATURE_SSSE3 (4*32+ 9) /* Supplemental SSE-3 */ -#define X86_FEATURE_CNXTID (4*32+10) /* L1 Context ID */ +#define X86_FEATURE_CID (4*32+10) /* Context ID */ +#define X86_FEATURE_SDBG (4*32+11) /* Silicon Debug */ #define X86_FEATURE_FMA (4*32+12) /* Fused multiply-add */ -#define X86_FEATURE_CX16 (4*32+13) /* CMPXCHG16B */ -#define X86_FEATURE_XTPR_UCTL (4*32+14) /* xTPR Update Control */ -#define X86_FEATURE_PDCM (4*32+15) /* Perfmon and Debug Capability */ -#define X86_FEATURE_PCID (4*32+17) /* Process-context identifiers */ -#define X86_FEATURE_DCA (4*32+18) /* Ability to prefetch data from a memory mapped device */ +#define X86_FEATURE_CX16 (4*32+13) /* CMPXCHG16B instruction */ +#define X86_FEATURE_XTPR (4*32+14) /* Send Task Priority Messages */ +#define X86_FEATURE_PDCM (4*32+15) /* Perf/Debug Capabilities MSR */ +#define X86_FEATURE_PCID (4*32+17) /* Process Context Identifiers */ +#define X86_FEATURE_DCA (4*32+18) /* Direct Cache Access */ #define X86_FEATURE_XMM4_1 (4*32+19) /* "sse4_1" SSE-4.1 */ #define X86_FEATURE_XMM4_2 (4*32+20) /* "sse4_2" SSE-4.2 */ -#define X86_FEATURE_X2APIC (4*32+21) /* x2APIC */ +#define X86_FEATURE_X2APIC (4*32+21) /* X2APIC */ #define X86_FEATURE_MOVBE (4*32+22) /* MOVBE instruction */ #define X86_FEATURE_POPCNT (4*32+23) /* POPCNT instruction */ -#define X86_FEATURE_TSCDL (4*32+24) /* Local APIC timer supports one-shot operation using a TSC deadline value */ +#define X86_FEATURE_TSC_DEADLINE_TIMER (4*32+24) /* TSC deadline timer */ #define X86_FEATURE_AES (4*32+25) /* AES instructions */ -#define X86_FEATURE_XSAVE (4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */ -#define X86_FEATURE_OSXSAVE (4*32+27) /* "" XSAVE enabled in the OS */ +#define X86_FEATURE_XSAVE (4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV instructions */ +#define X86_FEATURE_OSXSAVE (4*32+27) /* "" XSAVE instruction enabled in the OS */ #define X86_FEATURE_AVX (4*32+28) /* Advanced Vector Extensions */ -#define X86_FEATURE_F16C (4*32+29) /* 16-bit fp conversions */ -#define X86_FEATURE_RDRAND (4*32+30) /* The RDRAND instruction */ +#define X86_FEATURE_F16C (4*32+29) /* 16-bit FP conversions */ +#define X86_FEATURE_RDRAND (4*32+30) /* RDRAND instruction */ +#define X86_FEATURE_HYPERVISOR (4*32+31) /* Running on a hypervisor */ +/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ +#define X86_FEATURE_XSTORE (5*32+ 2) /* "rng" RNG present (xstore) */ +#define X86_FEATURE_XSTORE_EN (5*32+ 3) /* "rng_en" RNG enabled */ +#define X86_FEATURE_XCRYPT (5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */ +#define X86_FEATURE_XCRYPT_EN (5*32+ 7) /* "ace_en" on-CPU crypto enabled */ +#define X86_FEATURE_ACE2 (5*32+ 8) /* Advanced Cryptography Engine v2 */ +#define X86_FEATURE_ACE2_EN (5*32+ 9) /* ACE v2 enabled */ +#define X86_FEATURE_PHE (5*32+10) /* PadLock Hash Engine */ +#define X86_FEATURE_PHE_EN (5*32+11) /* PHE enabled */ +#define X86_FEATURE_PMM (5*32+12) /* PadLock Montgomery Multiplier */ +#define X86_FEATURE_PMM_EN (5*32+13) /* PMM enabled */ + +/* More extended AMD flags: CPUID level 0x80000001, ECX, word 6 */ +#define X86_FEATURE_LAHF_LM (6*32+ 0) /* LAHF/SAHF in long mode */ +#define X86_FEATURE_CMP_LEGACY (6*32+ 1) /* If yes HyperThreading not valid */ +#define X86_FEATURE_SVM (6*32+ 2) /* Secure Virtual Machine */ +#define X86_FEATURE_EXTAPIC (6*32+ 3) /* Extended APIC space */ +#define X86_FEATURE_CR8_LEGACY (6*32+ 4) /* CR8 in 32-bit mode */ #define X86_FEATURE_ABM (6*32+ 5) /* Advanced bit manipulation */ #define X86_FEATURE_SSE4A (6*32+ 6) /* SSE-4A */ #define X86_FEATURE_MISALIGNSSE (6*32+ 7) /* Misaligned SSE mode */ #define X86_FEATURE_3DNOWPREFETCH (6*32+ 8) /* 3DNow prefetch instructions */ +#define X86_FEATURE_OSVW (6*32+ 9) /* OS Visible Workaround */ +#define X86_FEATURE_IBS (6*32+10) /* Instruction Based Sampling */ #define X86_FEATURE_XOP (6*32+11) /* extended AVX instructions */ +#define X86_FEATURE_SKINIT (6*32+12) /* SKINIT/STGI instructions */ +#define X86_FEATURE_WDT (6*32+13) /* Watchdog timer */ +#define X86_FEATURE_LWP (6*32+15) /* Light Weight Profiling */ #define X86_FEATURE_FMA4 (6*32+16) /* 4 operands MAC instructions */ -#define X86_FEATURE_TBM (6*32+21) /* trailing bit manipulations */ +#define X86_FEATURE_TCE (6*32+17) /* Translation Cache Extension */ +#define X86_FEATURE_NODEID_MSR (6*32+19) /* NodeId MSR */ +#define X86_FEATURE_TBM (6*32+21) /* Trailing Bit Manipulations */ +#define X86_FEATURE_TOPOEXT (6*32+22) /* Topology extensions CPUID leafs */ +#define X86_FEATURE_PERFCTR_CORE (6*32+23) /* Core performance counter extensions */ +#define X86_FEATURE_PERFCTR_NB (6*32+24) /* NB performance counter extensions */ +#define X86_FEATURE_BPEXT (6*32+26) /* Data breakpoint extension */ +#define X86_FEATURE_PTSC (6*32+27) /* Performance time-stamp counter */ +#define X86_FEATURE_PERFCTR_LLC (6*32+28) /* Last Level Cache performance counter extensions */ +#define X86_FEATURE_MWAITX (6*32+29) /* MWAIT extension (MONITORX/MWAITX instructions) */ -#define X86_FEATURE_FSGSBASE (9*32+ 0) /* Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE */ +/* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */ +#define X86_FEATURE_FSGSBASE (9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/ +#define X86_FEATURE_TSC_ADJUST (9*32+ 1) /* TSC adjustment MSR 0x3B */ #define X86_FEATURE_BMI1 (9*32+ 3) /* 1st group bit manipulation extensions */ #define X86_FEATURE_HLE (9*32+ 4) /* Hardware Lock Elision */ #define X86_FEATURE_AVX2 (9*32+ 5) /* AVX2 instructions */ #define X86_FEATURE_SMEP (9*32+ 7) /* Supervisor Mode Execution Protection */ #define X86_FEATURE_BMI2 (9*32+ 8) /* 2nd group bit manipulation extensions */ -#define X86_FEATURE_ERMS (9*32+ 9) /* Enhanced REP MOVSB/STOSB */ +#define X86_FEATURE_ERMS (9*32+ 9) /* Enhanced REP MOVSB/STOSB instructions */ #define X86_FEATURE_INVPCID (9*32+10) /* Invalidate Processor Context ID */ #define X86_FEATURE_RTM (9*32+11) /* Restricted Transactional Memory */ +#define X86_FEATURE_CQM (9*32+12) /* Cache QoS Monitoring */ #define X86_FEATURE_MPX (9*32+14) /* Memory Protection Extension */ +#define X86_FEATURE_RDT_A (9*32+15) /* Resource Director Technology Allocation */ #define X86_FEATURE_AVX512F (9*32+16) /* AVX-512 Foundation */ -#define X86_FEATURE_AVX512DQ (9*32+17) /* AVX-512 Foundation */ -#define X86_FEATURE_RDSEED (9*32+18) /* The RDSEED instruction */ -#define X86_FEATURE_ADX (9*32+19) /* The ADCX and ADOX instructions */ +#define X86_FEATURE_AVX512DQ (9*32+17) /* AVX-512 DQ (Double/Quad granular) Instructions */ +#define X86_FEATURE_RDSEED (9*32+18) /* RDSEED instruction */ +#define X86_FEATURE_ADX (9*32+19) /* ADCX and ADOX instructions */ #define X86_FEATURE_SMAP (9*32+20) /* Supervisor Mode Access Prevention */ +#define X86_FEATURE_AVX512IFMA (9*32+21) /* AVX-512 Integer Fused Multiply-Add instructions */ #define X86_FEATURE_CLFLUSHOPT (9*32+23) /* CLFLUSHOPT instruction */ -#define X86_FEATURE_IPT (9*32+25) /* Intel Processor Trace */ +#define X86_FEATURE_CLWB (9*32+24) /* CLWB instruction */ +#define X86_FEATURE_INTEL_PT (9*32+25) /* Intel Processor Trace */ #define X86_FEATURE_AVX512PF (9*32+26) /* AVX-512 Prefetch */ #define X86_FEATURE_AVX512ER (9*32+27) /* AVX-512 Exponential and Reciprocal */ #define X86_FEATURE_AVX512CD (9*32+28) /* AVX-512 Conflict Detection */ -#define X86_FEATURE_SHA (9*32+29) /* Intel SHA extensions */ -#define X86_FEATURE_AVX512BW (9*32+30) /* AVX-512 */ -#define X86_FEATURE_AVXVL (9*32+31) /* AVX-512 */ +#define X86_FEATURE_SHA_NI (9*32+29) /* SHA1/SHA256 Instruction Extensions */ +#define X86_FEATURE_AVX512BW (9*32+30) /* AVX-512 BW (Byte/Word granular) Instructions */ +#define X86_FEATURE_AVX512VL (9*32+31) /* AVX-512 VL (128/256 Vector Length) Extensions */ -#define X86_FEATURE_XSAVEOPT (10*32+0) /* XSAVEOPT */ -#define X86_FEATURE_XSAVEC (10*32+1) /* XSAVEC */ -#define X86_FEATURE_XGETBV1 (10*32+2) /* XGETBV with ECX = 1 */ -#define X86_FEATURE_XSAVES (10*32+3) /* XSAVES/XRSTORS */ +/* Extended state features, CPUID level 0x0000000d:1 (EAX), word 10 */ +#define X86_FEATURE_XSAVEOPT (10*32+ 0) /* XSAVEOPT instruction */ +#define X86_FEATURE_XSAVEC (10*32+ 1) /* XSAVEC instruction */ +#define X86_FEATURE_XGETBV1 (10*32+ 2) /* XGETBV with ECX = 1 instruction */ +#define X86_FEATURE_XSAVES (10*32+ 3) /* XSAVES/XRSTORS instructions */ -/* - * Node 11 is our own, kernel has not such entry. - */ -#define X86_FEATURE_PREFETCHWT1 (11*32+0) /* The PREFETCHWT1 instruction */ +/* Intel-defined CPU features, CPUID level 0x00000007:0 (ECX), word 11 */ +#define X86_FEATURE_PREFETCHWT1 (11*32+ 0) /* PREFETCHWT1 Intel® Xeon PhiTM only */ +#define X86_FEATURE_AVX512VBMI (11*32+ 1) /* AVX512 Vector Bit Manipulation instructions*/ +#define X86_FEATURE_UMIP (11*32+ 2) /* User Mode Instruction Protection */ +#define X86_FEATURE_PKU (11*32+ 3) /* Protection Keys for Userspace */ +#define X86_FEATURE_OSPKE (11*32+ 4) /* OS Protection Keys Enable */ +#define X86_FEATURE_AVX512_VBMI2 (11*32+ 6) /* Additional AVX512 Vector Bit Manipulation Instructions */ +#define X86_FEATURE_GFNI (11*32+ 8) /* Galois Field New Instructions */ +#define X86_FEATURE_VAES (11*32+ 9) /* Vector AES */ +#define X86_FEATURE_VPCLMULQDQ (11*32+10) /* Carry-Less Multiplication Double Quadword */ +#define X86_FEATURE_AVX512_VNNI (11*32+11) /* Vector Neural Network Instructions */ +#define X86_FEATURE_AVX512_BITALG (11*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */ +#define X86_FEATURE_TME (11*32+13) /* Intel Total Memory Encryption */ +#define X86_FEATURE_AVX512_VPOPCNTDQ (11*32+14) /* POPCNT for vectors of DW/QW */ +#define X86_FEATURE_LA57 (11*32+16) /* 5-level page tables */ +#define X86_FEATURE_RDPID (11*32+22) /* RDPID instruction */ +#define X86_FEATURE_CLDEMOTE (11*32+25) /* CLDEMOTE instruction */ + +/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:1 (EDX), word 12 */ +#define X86_FEATURE_CQM_OCCUP_LLC (12*32+ 0) /* LLC occupancy monitoring */ +#define X86_FEATURE_CQM_MBM_TOTAL (12*32+ 1) /* LLC Total MBM monitoring */ +#define X86_FEATURE_CQM_MBM_LOCAL (12*32+ 2) /* LLC Local MBM monitoring */ + +/* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */ +#define X86_FEATURE_CLZERO (13*32+ 0) /* CLZERO instruction */ +#define X86_FEATURE_IRPERF (13*32+ 1) /* Instructions Retired Count */ +#define X86_FEATURE_XSAVEERPTR (13*32+ 2) /* Always save/restore FP error pointers */ +#define X86_FEATURE_IBPB (13*32+12) /* Indirect Branch Prediction Barrier */ +#define X86_FEATURE_IBRS (13*32+14) /* Indirect Branch Restricted Speculation */ +#define X86_FEATURE_STIBP (13*32+15) /* Single Thread Indirect Branch Predictors */ + +/* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */ +#define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ +#define X86_FEATURE_IDA (14*32+ 1) /* Intel Dynamic Acceleration */ +#define X86_FEATURE_ARAT (14*32+ 2) /* Always Running APIC Timer */ +#define X86_FEATURE_PLN (14*32+ 4) /* Intel Power Limit Notification */ +#define X86_FEATURE_PTS (14*32+ 6) /* Intel Package Thermal Status */ +#define X86_FEATURE_HWP (14*32+ 7) /* Intel Hardware P-states */ +#define X86_FEATURE_HWP_NOTIFY (14*32+ 8) /* HWP Notification */ +#define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* HWP Activity Window */ +#define X86_FEATURE_HWP_EPP (14*32+10) /* HWP Energy Perf. Preference */ +#define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* HWP Package Level Request */ + +/* AMD SVM Feature Identification, CPUID level 0x8000000a (EDX), word 15 */ +#define X86_FEATURE_NPT (15*32+ 0) /* Nested Page Table support */ +#define X86_FEATURE_LBRV (15*32+ 1) /* LBR Virtualization support */ +#define X86_FEATURE_SVML (15*32+ 2) /* "svm_lock" SVM locking MSR */ +#define X86_FEATURE_NRIPS (15*32+ 3) /* "nrip_save" SVM next_rip save */ +#define X86_FEATURE_TSCRATEMSR (15*32+ 4) /* "tsc_scale" TSC scaling support */ +#define X86_FEATURE_VMCBCLEAN (15*32+ 5) /* "vmcb_clean" VMCB clean bits support */ +#define X86_FEATURE_FLUSHBYASID (15*32+ 6) /* flush-by-ASID support */ +#define X86_FEATURE_DECODEASSISTS (15*32+ 7) /* Decode Assists support */ +#define X86_FEATURE_PAUSEFILTER (15*32+10) /* filtered pause intercept */ +#define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */ +#define X86_FEATURE_AVIC (15*32+13) /* Virtual Interrupt Controller */ +#define X86_FEATURE_V_VMSAVE_VMLOAD (15*32+15) /* Virtual VMSAVE VMLOAD */ +#define X86_FEATURE_VGIF (15*32+16) /* Virtual GIF */ + +/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:0 (EDX), word 16 */ +#define X86_FEATURE_CQM_LLC (16*32+ 1) /* LLC QoS if 1 */ + +/* AMD-defined CPU features, CPUID level 0x80000007 (EBX), word 17 */ +#define X86_FEATURE_OVERFLOW_RECOV (17*32+ 0) /* MCA overflow recovery support */ +#define X86_FEATURE_SUCCOR (17*32+ 1) /* Uncorrectable error containment and recovery */ +#define X86_FEATURE_SMCA (17*32+ 3) /* Scalable MCA */ + +/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ +#define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ +#define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ +#define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */ +#define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ +#define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ +#define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ +#define X86_FEATURE_SPEC_CTRL_SSBD (18*32+31) /* "" Speculative Store Bypass Disable */ enum { X86_VENDOR_INTEL = 0, @@ -134,6 +323,7 @@ struct cpuinfo_x86 { uint8_t x86_model; uint8_t x86_mask; uint32_t x86_capability[NCAPINTS]; + uint32_t x86_power; uint32_t extended_cpuid_level; int cpuid_level; char x86_vendor_id[16]; diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index 5e95d25d8..bcf80778a 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -76,7 +76,7 @@ int cpu_dump_cpuinfo(void) cpu_x86_info.cpu_family = rt_cpu_info.x86_family; cpu_x86_info.model = rt_cpu_info.x86_model; cpu_x86_info.stepping = rt_cpu_info.x86_mask; - cpu_x86_info.capability_ver = 1; + cpu_x86_info.capability_ver = 2; cpu_x86_info.n_capability = ARRAY_SIZE(rt_cpu_info.x86_capability); cpu_x86_info.capability = (void *)rt_cpu_info.x86_capability; @@ -95,94 +95,91 @@ int cpu_dump_cpuinfo(void) #define __ins_bit(__l, __v) (1u << ((__v) - 32u * (__l))) static u32 x86_ins_capability_mask[NCAPINTS] = { - [0] = - __ins_bit(0, X86_FEATURE_FPU) | - __ins_bit(0, X86_FEATURE_TSC) | - __ins_bit(0, X86_FEATURE_CX8) | - __ins_bit(0, X86_FEATURE_SEP) | - __ins_bit(0, X86_FEATURE_CMOV) | - __ins_bit(0, X86_FEATURE_CLFLUSH) | - __ins_bit(0, X86_FEATURE_MMX) | - __ins_bit(0, X86_FEATURE_FXSR) | - __ins_bit(0, X86_FEATURE_XMM) | - __ins_bit(0, X86_FEATURE_XMM2), + [CPUID_1_EDX] = + __ins_bit(CPUID_1_EDX, X86_FEATURE_FPU) | + __ins_bit(CPUID_1_EDX, X86_FEATURE_TSC) | + __ins_bit(CPUID_1_EDX, X86_FEATURE_CX8) | + __ins_bit(CPUID_1_EDX, X86_FEATURE_SEP) | + __ins_bit(CPUID_1_EDX, X86_FEATURE_CMOV) | + __ins_bit(CPUID_1_EDX, X86_FEATURE_CLFLUSH) | + __ins_bit(CPUID_1_EDX, X86_FEATURE_MMX) | + __ins_bit(CPUID_1_EDX, X86_FEATURE_FXSR) | + __ins_bit(CPUID_1_EDX, X86_FEATURE_XMM) | + __ins_bit(CPUID_1_EDX, X86_FEATURE_XMM2), - [1] = - __ins_bit(1, X86_FEATURE_SYSCALL) | - __ins_bit(1, X86_FEATURE_MMXEXT) | - __ins_bit(1, X86_FEATURE_RDTSCP) | - __ins_bit(1, X86_FEATURE_3DNOWEXT) | - __ins_bit(1, X86_FEATURE_3DNOW), + [CPUID_8000_0001_EDX] = + __ins_bit(CPUID_8000_0001_EDX, X86_FEATURE_SYSCALL) | + __ins_bit(CPUID_8000_0001_EDX, X86_FEATURE_MMXEXT) | + __ins_bit(CPUID_8000_0001_EDX, X86_FEATURE_RDTSCP) | + __ins_bit(CPUID_8000_0001_EDX, X86_FEATURE_3DNOWEXT) | + __ins_bit(CPUID_8000_0001_EDX, X86_FEATURE_3DNOW), - [3] = - __ins_bit(3, X86_FEATURE_REP_GOOD) | - __ins_bit(3, X86_FEATURE_NOPL), + [CPUID_LNX_1] = + __ins_bit(CPUID_LNX_1, X86_FEATURE_REP_GOOD) | + __ins_bit(CPUID_LNX_1, X86_FEATURE_NOPL), - [4] = - __ins_bit(4, X86_FEATURE_XMM3) | - __ins_bit(4, X86_FEATURE_PCLMULQDQ) | - __ins_bit(4, X86_FEATURE_MWAIT) | - __ins_bit(4, X86_FEATURE_SSSE3) | - __ins_bit(4, X86_FEATURE_CX16) | - __ins_bit(4, X86_FEATURE_XMM4_1) | - __ins_bit(4, X86_FEATURE_XMM4_2) | - __ins_bit(4, X86_FEATURE_MOVBE) | - __ins_bit(4, X86_FEATURE_POPCNT) | - __ins_bit(4, X86_FEATURE_AES) | - __ins_bit(4, X86_FEATURE_XSAVE) | - __ins_bit(4, X86_FEATURE_OSXSAVE) | - __ins_bit(4, X86_FEATURE_AVX) | - __ins_bit(4, X86_FEATURE_F16C) | - __ins_bit(4, X86_FEATURE_RDRAND), + [CPUID_1_ECX] = + __ins_bit(CPUID_1_ECX, X86_FEATURE_XMM3) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_PCLMULQDQ) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_MWAIT) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_SSSE3) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_CX16) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_XMM4_1) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_XMM4_2) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_MOVBE) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_POPCNT) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_AES) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_XSAVE) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_OSXSAVE) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_AVX) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_F16C) | + __ins_bit(CPUID_1_ECX, X86_FEATURE_RDRAND), - [6] = - __ins_bit(6, X86_FEATURE_ABM) | - __ins_bit(6, X86_FEATURE_SSE4A) | - __ins_bit(6, X86_FEATURE_MISALIGNSSE) | - __ins_bit(6, X86_FEATURE_3DNOWPREFETCH) | - __ins_bit(6, X86_FEATURE_XOP) | - __ins_bit(6, X86_FEATURE_FMA4) | - __ins_bit(6, X86_FEATURE_TBM), + [CPUID_8000_0001_ECX] = + __ins_bit(CPUID_8000_0001_ECX, X86_FEATURE_ABM) | + __ins_bit(CPUID_8000_0001_ECX, X86_FEATURE_SSE4A) | + __ins_bit(CPUID_8000_0001_ECX, X86_FEATURE_MISALIGNSSE) | + __ins_bit(CPUID_8000_0001_ECX, X86_FEATURE_3DNOWPREFETCH) | + __ins_bit(CPUID_8000_0001_ECX, X86_FEATURE_XOP) | + __ins_bit(CPUID_8000_0001_ECX, X86_FEATURE_FMA4) | + __ins_bit(CPUID_8000_0001_ECX, X86_FEATURE_TBM), - [9] = - __ins_bit(9, X86_FEATURE_FSGSBASE) | - __ins_bit(9, X86_FEATURE_BMI1) | - __ins_bit(9, X86_FEATURE_HLE) | - __ins_bit(9, X86_FEATURE_AVX2) | - __ins_bit(9, X86_FEATURE_BMI2) | - __ins_bit(9, X86_FEATURE_ERMS) | - __ins_bit(9, X86_FEATURE_RTM) | - __ins_bit(9, X86_FEATURE_MPX) | - __ins_bit(9, X86_FEATURE_AVX512F) | - __ins_bit(9, X86_FEATURE_AVX512DQ) | - __ins_bit(9, X86_FEATURE_RDSEED) | - __ins_bit(9, X86_FEATURE_ADX) | - __ins_bit(9, X86_FEATURE_CLFLUSHOPT) | - __ins_bit(9, X86_FEATURE_AVX512PF) | - __ins_bit(9, X86_FEATURE_AVX512ER) | - __ins_bit(9, X86_FEATURE_AVX512CD) | - __ins_bit(9, X86_FEATURE_SHA) | - __ins_bit(9, X86_FEATURE_AVX512BW) | - __ins_bit(9, X86_FEATURE_AVXVL), + [CPUID_7_0_EBX] = + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_FSGSBASE) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_BMI1) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_HLE) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_AVX2) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_BMI2) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_ERMS) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_RTM) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_MPX) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_AVX512F) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_AVX512DQ) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_RDSEED) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_ADX) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_CLFLUSHOPT) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_AVX512PF) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_AVX512ER) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_AVX512CD) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_SHA_NI) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_AVX512BW) | + __ins_bit(CPUID_7_0_EBX, X86_FEATURE_AVX512VL), - [10] = - __ins_bit(10, X86_FEATURE_XSAVEOPT) | - __ins_bit(10, X86_FEATURE_XSAVEC) | - __ins_bit(10, X86_FEATURE_XGETBV1) | - __ins_bit(10, X86_FEATURE_XSAVES), - - [11] = - __ins_bit(11, X86_FEATURE_PREFETCHWT1), + [CPUID_D_1_EAX] = + __ins_bit(CPUID_D_1_EAX, X86_FEATURE_XSAVEOPT) | + __ins_bit(CPUID_D_1_EAX, X86_FEATURE_XSAVEC) | + __ins_bit(CPUID_D_1_EAX, X86_FEATURE_XGETBV1) | + __ins_bit(CPUID_D_1_EAX, X86_FEATURE_XSAVES), }; #undef __ins_bit -static int cpu_validate_ins_features(CpuinfoX86Entry *img_x86_entry) +static int cpu_validate_ins_features(compel_cpuinfo_t *cpu_info) { size_t i; - for (i = 0; i < ARRAY_SIZE(rt_cpu_info.x86_capability); i++) { - u32 s = img_x86_entry->capability[i] & x86_ins_capability_mask[i]; + for (i = 0; i < ARRAY_SIZE(cpu_info->x86_capability); i++) { + u32 s = cpu_info->x86_capability[i] & x86_ins_capability_mask[i]; u32 d = rt_cpu_info.x86_capability[i] & x86_ins_capability_mask[i]; /* @@ -198,21 +195,8 @@ static int cpu_validate_ins_features(CpuinfoX86Entry *img_x86_entry) return 0; } -static int cpu_validate_features(CpuinfoX86Entry *img_x86_entry) +static int cpu_validate_features(compel_cpuinfo_t *cpu_info) { - if (img_x86_entry->n_capability != ARRAY_SIZE(rt_cpu_info.x86_capability)) { - /* - * Image carries different number of bits. - * Simply reject, we can't guarantee anything - * in such case. - */ - pr_err("Size of features in image mismatch " - "one provided by run time CPU (%d:%d)\n", - (unsigned)img_x86_entry->n_capability, - (unsigned)ARRAY_SIZE(rt_cpu_info.x86_capability)); - return -1; - } - if (opts.cpu_cap == CPU_CAP_FPU) { /* * If we're requested to check FPU only ignore @@ -221,7 +205,7 @@ static int cpu_validate_features(CpuinfoX86Entry *img_x86_entry) */ #define __mismatch_fpu_bit(__bit) \ - (test_bit(__bit, (void *)img_x86_entry->capability) && \ + (test_bit(__bit, (void *)cpu_info->x86_capability) && \ !compel_cpu_has_feature(__bit)) if (__mismatch_fpu_bit(X86_FEATURE_FPU) || __mismatch_fpu_bit(X86_FEATURE_FXSR) || @@ -238,22 +222,98 @@ static int cpu_validate_features(CpuinfoX86Entry *img_x86_entry) * Capability on instructions level only. */ if (opts.cpu_cap == CPU_CAP_INS) - return cpu_validate_ins_features(img_x86_entry); + return cpu_validate_ins_features(cpu_info); /* * Strict capability mode. Everything must match. */ - if (memcmp(img_x86_entry->capability, rt_cpu_info.x86_capability, - sizeof(rt_cpu_info.x86_capability))) { - pr_err("CPU capabilites do not match run time\n"); - return -1; + if (memcmp(cpu_info->x86_capability, rt_cpu_info.x86_capability, + sizeof(cpu_info->x86_capability))) { + pr_err("CPU capabilites do not match run time\n"); + return -1; } return 0; } +static const struct { + const uint32_t capability_ver; + const uint32_t ncapints; +} ncapints[] = { + { .capability_ver = 1, .ncapints = NCAPINTS_V1 }, + { .capability_ver = 2, .ncapints = NCAPINTS_V2 }, +}; + +static compel_cpuinfo_t *img_to_cpuinfo(CpuinfoX86Entry *img_x86_entry) +{ + compel_cpuinfo_t *cpu_info; + size_t size, i; + + BUILD_BUG_ON(sizeof(img_x86_entry->capability[0]) != + sizeof(cpu_info->x86_capability[0])); + BUILD_BUG_ON(ARRAY_SIZE(rt_cpu_info.x86_capability) != NCAPINTS); + + if (img_x86_entry->vendor_id != CPUINFO_X86_ENTRY__VENDOR__INTEL && + img_x86_entry->vendor_id != CPUINFO_X86_ENTRY__VENDOR__AMD) { + pr_err("Image carries unknown vendor %u\n", + (unsigned)img_x86_entry->vendor_id); + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(ncapints); i++) { + if (img_x86_entry->capability_ver == ncapints[i].capability_ver) { + if (img_x86_entry->n_capability != ncapints[i].ncapints) { + pr_err("Image carries %u words while %u expected\n", + (unsigned)img_x86_entry->n_capability, + (unsigned)ncapints[i].ncapints); + return NULL; + } + break; + } + } + + if (i >= ARRAY_SIZE(ncapints)) { + pr_err("Image carries unknown capability version %d\n", + (unsigned)img_x86_entry->capability_ver); + return NULL; + } + + cpu_info = xzalloc(sizeof(*cpu_info)); + if (!cpu_info) + return NULL; + + /* + * Copy caps from image and fill the left ones from + * run-time infomation for easier compatibility testing. + */ + size = sizeof(img_x86_entry->capability[0]) * img_x86_entry->n_capability; + memcpy(cpu_info->x86_capability, img_x86_entry->capability, size); + if (img_x86_entry->capability_ver == 1) { + memcpy(&cpu_info->x86_capability[NCAPINTS_V1], + &rt_cpu_info.x86_capability[NCAPINTS_V1], + (NCAPINTS_V2 - NCAPINTS_V1) * sizeof(rt_cpu_info.x86_capability[0])); + } + + if (img_x86_entry->vendor_id == CPUINFO_X86_ENTRY__VENDOR__INTEL) + cpu_info->x86_vendor = X86_VENDOR_INTEL; + else + cpu_info->x86_vendor = X86_VENDOR_AMD; + cpu_info->x86_family = img_x86_entry->cpu_family; + cpu_info->x86_model = img_x86_entry->model; + cpu_info->x86_mask = img_x86_entry->stepping; + cpu_info->extended_cpuid_level = rt_cpu_info.extended_cpuid_level; + cpu_info->cpuid_level = rt_cpu_info.cpuid_level; + cpu_info->x86_power = rt_cpu_info.x86_power; + + memcpy(cpu_info->x86_vendor_id, rt_cpu_info.x86_model_id, sizeof(cpu_info->x86_vendor_id)); + strncpy(cpu_info->x86_model_id, img_x86_entry->model_id, sizeof(cpu_info->x86_model_id) - 1); + + return cpu_info; +} + int cpu_validate_cpuinfo(void) { + compel_cpuinfo_t *cpu_info = NULL; CpuinfoX86Entry *img_x86_entry; CpuinfoEntry *img_cpu_info; struct cr_img *img; @@ -280,15 +340,11 @@ int cpu_validate_cpuinfo(void) goto err; } - if (img_x86_entry->n_capability != ARRAY_SIZE(rt_cpu_info.x86_capability)) { - pr_err("Image carries %u words while %u expected\n", - (unsigned)img_x86_entry->n_capability, - (unsigned)ARRAY_SIZE(rt_cpu_info.x86_capability)); - goto err; - } - - ret = cpu_validate_features(img_x86_entry); + cpu_info = img_to_cpuinfo(img_x86_entry); + if (cpu_info) + ret = cpu_validate_features(cpu_info); err: + xfree(cpu_info); close_image(img); return ret; } From 6d6840075e7231f8da0920ff1f6d2c79ed3b845f Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 14 Jun 2018 20:27:23 +0300 Subject: [PATCH 1578/4375] x86: cpu -- Add new instruction bits to check Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index bcf80778a..b065a1f92 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -168,8 +168,26 @@ static u32 x86_ins_capability_mask[NCAPINTS] = { [CPUID_D_1_EAX] = __ins_bit(CPUID_D_1_EAX, X86_FEATURE_XSAVEOPT) | __ins_bit(CPUID_D_1_EAX, X86_FEATURE_XSAVEC) | - __ins_bit(CPUID_D_1_EAX, X86_FEATURE_XGETBV1) | - __ins_bit(CPUID_D_1_EAX, X86_FEATURE_XSAVES), + __ins_bit(CPUID_D_1_EAX, X86_FEATURE_XGETBV1), + + [CPUID_7_0_ECX] = + __ins_bit(CPUID_7_0_ECX, X86_FEATURE_AVX512VBMI) | + __ins_bit(CPUID_7_0_ECX, X86_FEATURE_AVX512_VBMI2) | + __ins_bit(CPUID_7_0_ECX, X86_FEATURE_GFNI) | + __ins_bit(CPUID_7_0_ECX, X86_FEATURE_VAES) | + __ins_bit(CPUID_7_0_ECX, X86_FEATURE_VPCLMULQDQ) | + __ins_bit(CPUID_7_0_ECX, X86_FEATURE_AVX512_VNNI) | + __ins_bit(CPUID_7_0_ECX, X86_FEATURE_AVX512_BITALG) | + __ins_bit(CPUID_7_0_ECX, X86_FEATURE_TME) | + __ins_bit(CPUID_7_0_ECX, X86_FEATURE_AVX512_VPOPCNTDQ) | + __ins_bit(CPUID_7_0_ECX, X86_FEATURE_RDPID), + + [CPUID_8000_0008_EBX] = + __ins_bit(CPUID_8000_0008_EBX, X86_FEATURE_CLZERO), + + [CPUID_7_0_EDX] = + __ins_bit(CPUID_7_0_EDX, X86_FEATURE_AVX512_4VNNIW) | + __ins_bit(CPUID_7_0_EDX, X86_FEATURE_AVX512_4FMAPS), }; #undef __ins_bit From c2905da5814493135c7c3c9ecb4ea7314c01d95d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 14 Jun 2018 20:27:24 +0300 Subject: [PATCH 1579/4375] x86: cpu -- Show additional xsave info on init For debug sake. Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index b065a1f92..b32b8824f 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -48,10 +48,14 @@ int cpu_init(void) } } - pr_debug("fpu:%d fxsr:%d xsave:%d\n", + pr_debug("fpu:%d fxsr:%d xsave:%d xsaveopt:%d xsavec:%d xgetbv1:%d xsaves:%d\n", !!compel_cpu_has_feature(X86_FEATURE_FPU), !!compel_cpu_has_feature(X86_FEATURE_FXSR), - !!compel_cpu_has_feature(X86_FEATURE_OSXSAVE)); + !!compel_cpu_has_feature(X86_FEATURE_OSXSAVE), + !!compel_cpu_has_feature(X86_FEATURE_XSAVEOPT), + !!compel_cpu_has_feature(X86_FEATURE_XSAVEC), + !!compel_cpu_has_feature(X86_FEATURE_XGETBV1), + !!compel_cpu_has_feature(X86_FEATURE_XSAVES)); return 0; } From bb760d88292d970201e1c28f776343c151cda3cf Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 14 Jun 2018 20:27:25 +0300 Subject: [PATCH 1580/4375] x86: cpu -- Check for xsaves bit on cpu validation Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index b32b8824f..375a77550 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -231,7 +231,8 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) !compel_cpu_has_feature(__bit)) if (__mismatch_fpu_bit(X86_FEATURE_FPU) || __mismatch_fpu_bit(X86_FEATURE_FXSR) || - __mismatch_fpu_bit(X86_FEATURE_OSXSAVE)) { + __mismatch_fpu_bit(X86_FEATURE_OSXSAVE) || + __mismatch_fpu_bit(X86_FEATURE_XSAVES)) { pr_err("FPU feature required by image " "is not supported on host.\n"); return -1; From f25f91e5e8e99f7657eef77eff3a305d5f0f4680 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 14 Jun 2018 20:27:26 +0300 Subject: [PATCH 1581/4375] x86: cpu -- Report when unsupported compact xsave frame detected We don't have yet support of compacted xsave frames so report error on cpu-check, checkpoint, restore actions. Basically it is done in cpu_init routine which is called in the sites we're interested in. Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index 375a77550..c7def8883 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -29,6 +29,20 @@ static compel_cpuinfo_t rt_cpu_info; +static int cpu_has_unsupported_features(void) +{ + /* + * We don't support yet compacted xsave format so + * exit early if present. + */ + if (compel_cpu_has_feature(X86_FEATURE_XSAVES)) { + pr_err("Unsupported compact xsave frame on runtime cpu present\n"); + return 1; + } + + return 0; +} + int cpu_init(void) { if (compel_cpuid(&rt_cpu_info)) @@ -57,7 +71,7 @@ int cpu_init(void) !!compel_cpu_has_feature(X86_FEATURE_XGETBV1), !!compel_cpu_has_feature(X86_FEATURE_XSAVES)); - return 0; + return cpu_has_unsupported_features() ? -1 : 0; } int cpu_dump_cpuinfo(void) @@ -219,6 +233,9 @@ static int cpu_validate_ins_features(compel_cpuinfo_t *cpu_info) static int cpu_validate_features(compel_cpuinfo_t *cpu_info) { + if (cpu_has_unsupported_features()) + return -1; + if (opts.cpu_cap == CPU_CAP_FPU) { /* * If we're requested to check FPU only ignore From 18be1a83a94b372b79c8057204fc7d738ab849d5 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 14 Jun 2018 20:27:27 +0300 Subject: [PATCH 1582/4375] compel: cpu -- Add ability to clear features Will need them to mask some of the features from command line options. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/cpu.c | 18 ++++++++++++++++++ compel/arch/arm/src/lib/cpu.c | 18 ++++++++++++++++++ compel/arch/ppc64/src/lib/cpu.c | 18 ++++++++++++++++++ compel/arch/s390/src/lib/cpu.c | 18 ++++++++++++++++++ compel/arch/x86/src/lib/cpu.c | 18 ++++++++++++++++++ compel/include/uapi/cpu.h | 2 ++ 6 files changed, 92 insertions(+) diff --git a/compel/arch/aarch64/src/lib/cpu.c b/compel/arch/aarch64/src/lib/cpu.c index 30263b377..fca699403 100644 --- a/compel/arch/aarch64/src/lib/cpu.c +++ b/compel/arch/aarch64/src/lib/cpu.c @@ -26,3 +26,21 @@ bool compel_cpu_has_feature(unsigned int feature) } return compel_test_cpu_cap(&rt_info, feature); } + +void compel_cpu_clear_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_clear_cpu_cap(&rt_info, feature); +} + +void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + memcpy(c, &rt_info, sizeof(rt_info)); +} diff --git a/compel/arch/arm/src/lib/cpu.c b/compel/arch/arm/src/lib/cpu.c index 30263b377..fca699403 100644 --- a/compel/arch/arm/src/lib/cpu.c +++ b/compel/arch/arm/src/lib/cpu.c @@ -26,3 +26,21 @@ bool compel_cpu_has_feature(unsigned int feature) } return compel_test_cpu_cap(&rt_info, feature); } + +void compel_cpu_clear_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_clear_cpu_cap(&rt_info, feature); +} + +void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + memcpy(c, &rt_info, sizeof(rt_info)); +} diff --git a/compel/arch/ppc64/src/lib/cpu.c b/compel/arch/ppc64/src/lib/cpu.c index 24c3c0cc6..0a7adcb0b 100644 --- a/compel/arch/ppc64/src/lib/cpu.c +++ b/compel/arch/ppc64/src/lib/cpu.c @@ -40,3 +40,21 @@ bool compel_cpu_has_feature(unsigned int feature) } return compel_test_cpu_cap(&rt_info, feature); } + +void compel_cpu_clear_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_clear_cpu_cap(&rt_info, feature); +} + +void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + memcpy(c, &rt_info, sizeof(rt_info)); +} diff --git a/compel/arch/s390/src/lib/cpu.c b/compel/arch/s390/src/lib/cpu.c index b5c066c90..3f38f118d 100644 --- a/compel/arch/s390/src/lib/cpu.c +++ b/compel/arch/s390/src/lib/cpu.c @@ -40,3 +40,21 @@ bool cpu_has_feature(unsigned int feature) } return compel_test_cpu_cap(&rt_info, feature); } + +void compel_cpu_clear_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_clear_cpu_cap(&rt_info, feature); +} + +void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + memcpy(c, &rt_info, sizeof(rt_info)); +} diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c index f8d5e1ba3..93e430fac 100644 --- a/compel/arch/x86/src/lib/cpu.c +++ b/compel/arch/x86/src/lib/cpu.c @@ -233,3 +233,21 @@ bool compel_cpu_has_feature(unsigned int feature) } return compel_test_cpu_cap(&rt_info, feature); } + +void compel_cpu_clear_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_clear_cpu_cap(&rt_info, feature); +} + +void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + memcpy(c, &rt_info, sizeof(rt_info)); +} diff --git a/compel/include/uapi/cpu.h b/compel/include/uapi/cpu.h index 4268b6c4f..379959585 100644 --- a/compel/include/uapi/cpu.h +++ b/compel/include/uapi/cpu.h @@ -7,5 +7,7 @@ extern int compel_cpuid(compel_cpuinfo_t *info); extern bool compel_cpu_has_feature(unsigned int feature); +extern void compel_cpu_clear_feature(unsigned int feature); +extern void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c); #endif /* UAPI_COMPEL_CPU_H__ */ From 7680c27b0d33284f540d4c8db911856978b1915e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 14 Jun 2018 20:27:28 +0300 Subject: [PATCH 1583/4375] x86: cpu -- Add ability to ignore xsaves Currently even if kernel supports compact xsave frame a user can disable it by passing noxsaves argument as a boot option. Thus cpuid instruction will report its presence but in real it gonna be masked from kernel pov. Lets do the same and allow a user to mask it via --cpu-cap=noxsaves option (valid for x86 only). Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/cpu.c | 5 +++++ criu/arch/arm/cpu.c | 5 +++++ criu/arch/ppc64/cpu.c | 5 +++++ criu/arch/s390/cpu.c | 5 +++++ criu/arch/x86/cpu.c | 24 ++++++++++++++++++++++++ criu/crtools.c | 5 +++++ criu/include/cpu.h | 1 + 7 files changed, 50 insertions(+) diff --git a/criu/arch/aarch64/cpu.c b/criu/arch/aarch64/cpu.c index 34313fb15..ef339f2f1 100644 --- a/criu/arch/aarch64/cpu.c +++ b/criu/arch/aarch64/cpu.c @@ -38,3 +38,8 @@ int cpuinfo_check(void) { return -ENOTSUP; } + +int cpu_parse_option(const char *opt) +{ + return -ENOTSUP; +} diff --git a/criu/arch/arm/cpu.c b/criu/arch/arm/cpu.c index 34313fb15..ef339f2f1 100644 --- a/criu/arch/arm/cpu.c +++ b/criu/arch/arm/cpu.c @@ -38,3 +38,8 @@ int cpuinfo_check(void) { return -ENOTSUP; } + +int cpu_parse_option(const char *opt) +{ + return -ENOTSUP; +} diff --git a/criu/arch/ppc64/cpu.c b/criu/arch/ppc64/cpu.c index 4fcfb065a..cdee8c72f 100644 --- a/criu/arch/ppc64/cpu.c +++ b/criu/arch/ppc64/cpu.c @@ -140,3 +140,8 @@ int cpuinfo_check(void) return 0; } + +int cpu_parse_option(const char *opt) +{ + return -1; +} diff --git a/criu/arch/s390/cpu.c b/criu/arch/s390/cpu.c index f93666ed6..5f6b83f70 100644 --- a/criu/arch/s390/cpu.c +++ b/criu/arch/s390/cpu.c @@ -156,3 +156,8 @@ int cpuinfo_check(void) return 1; return 0; } + +int cpu_parse_option(const char *opt) +{ + return -1; +} diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index c7def8883..e424fa0f6 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -416,3 +416,27 @@ int cpuinfo_check(void) return 0; } + +int cpu_parse_option(const char *opt) +{ + static struct { + const char *name; + unsigned int feature; + } filters[] = { + { + .name = "noxsaves", + .feature = X86_FEATURE_XSAVES, + }, + }; + + size_t i; + + for (i = 0; i < ARRAY_SIZE(filters); i++) { + if (strncmp(opt, filters[i].name, strlen(filters[i].name))) + continue; + compel_cpu_clear_feature(filters[i].feature); + return strlen(filters[i].name); + } + + return -1; +} diff --git a/criu/crtools.c b/criu/crtools.c index 0bb5d2803..650c7679a 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -150,6 +150,11 @@ static int parse_cpu_cap(struct cr_options *opts, const char *optarg) } else if (!strncmp(optarg, "ins", 3)) { ____cpu_set_cap(opts, CPU_CAP_INS, inverse); optarg += 3; + } else if (!strncmp(optarg, "op=", 3)) { + int pos = cpu_parse_option(&optarg[3]); + if (pos <= 0) + goto Esyntax; + optarg += pos + 3; } else goto Esyntax; } diff --git a/criu/include/cpu.h b/criu/include/cpu.h index e30696790..09b3c7899 100644 --- a/criu/include/cpu.h +++ b/criu/include/cpu.h @@ -8,5 +8,6 @@ extern int cpu_dump_cpuinfo(void); extern int cpu_validate_cpuinfo(void); extern int cpuinfo_dump(void); extern int cpuinfo_check(void); +extern int cpu_parse_option(const char *opt); #endif /* __CR_CPU_H__ */ From d8ff54e6925db54e348d037306ad197a67b264c6 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 14 Jun 2018 20:27:29 +0300 Subject: [PATCH 1584/4375] x86: cpu -- Use rt information since it might we filtered With new cpu-cap='op=noxsaves' mode on x86 we should use compel's instance of rt info since only it carries features masked. Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index e424fa0f6..d7d432b54 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -45,8 +45,7 @@ static int cpu_has_unsupported_features(void) int cpu_init(void) { - if (compel_cpuid(&rt_cpu_info)) - return -1; + compel_cpu_copy_cpuinfo(&rt_cpu_info); BUILD_BUG_ON(sizeof(struct xsave_struct) != XSAVE_SIZE); BUILD_BUG_ON(sizeof(struct i387_fxsave_struct) != FXSAVE_SIZE); From bda258766f5c423ab3dfc84ec48289cdfa870a1e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 14 Jun 2018 20:27:30 +0300 Subject: [PATCH 1585/4375] x86: cpu -- Show which exactly features are failing in fpu capability mode For easier understanding what is failed. Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index d7d432b54..11a81863f 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -250,7 +250,12 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) __mismatch_fpu_bit(X86_FEATURE_OSXSAVE) || __mismatch_fpu_bit(X86_FEATURE_XSAVES)) { pr_err("FPU feature required by image " - "is not supported on host.\n"); + "is not supported on host " + "(fpu:%d fxsr:%d osxsave:%d xsaves:%d)\n", + __mismatch_fpu_bit(X86_FEATURE_FPU), + __mismatch_fpu_bit(X86_FEATURE_FXSR), + __mismatch_fpu_bit(X86_FEATURE_OSXSAVE), + __mismatch_fpu_bit(X86_FEATURE_XSAVES)); return -1; } else return 0; From 39a2602f3e0279d435eb1668febf438ee188cf5f Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 19 Jun 2018 22:52:21 +0300 Subject: [PATCH 1586/4375] x86: cpu -- Proceed even if xsavec detected for dev reason Andrew reported that previously he been able to c/r even on the machine with xsavec enabled, so allow to process for now. P.S.I'm investigating the problem and to not block testing process lets permit passing with xsaves bit present. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index 11a81863f..d5d879e79 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -36,8 +36,9 @@ static int cpu_has_unsupported_features(void) * exit early if present. */ if (compel_cpu_has_feature(X86_FEATURE_XSAVES)) { - pr_err("Unsupported compact xsave frame on runtime cpu present\n"); - return 1; + pr_warn("Unsupported compact xsave frame on runtime cpu present\n"); + pr_warn("FIXME: Dazen and confused, but proceed for development reason\n"); + return 0; } return 0; From e098b119f3480418c43431beb04f700d1e87f19f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 7 Dec 2016 17:19:00 +0300 Subject: [PATCH 1587/4375] test, unix: Exhaustive testing of states (v2) By exhaustive testing I understand a test suite that generates as much states to try to C/R as possible by trying all the possible sequences of system calls. Since such a generation, if done on all the Linux API we support in CRIU, would produce bazillions of process, I propose to start with something simple. As a starting point -- unix stream sockets with abstract names that can be created and used by a single process :) The script generates situations in which unix sockets can get into by using a pre-defined set of system calls. In this patch the syscalls are socket, listen, bind, accept, connect and send. Also the nummber of system calls to use (i.e. -- the depth of the tree) is limited by the --depth option. There are three things that can be done with a generated 'state': I) Generate :) and show Generation is done by recursively doing everything that is possible (and makes sence) in a given state. To reduce the size of the tree some meaningless branches are cut, e.g. creating a socket and closing it right after that, creating two similar sockets one-by-one and some more. Shown on the screen is a cryptic string, e.g. 'SA-CX-MX_SBL one, describing the sockets in the state. This is how it can be decoded: - sockets are delimited with _ - first goes type (S -- stream, D --datagram) - next goes name state (A -- no name, B with name, X socket is not in FD table, i.e. closed or not yet accepted) - next may go letter L meaning that the socket is listening - -Cx -- socket is connected and x is the peer's name state - -Ixyz -- socket has incoming connections queue and xyz are the connect()-ors name states - -Mxyz -- socket has messages and xyz is senders' name states The example above means, that we have two sockets: - SA-CX-MX: stream, with no name, connected to a dead one and with a message from a dead one - SBL: stream, with name, listening Next printed is the sequence of system calls to get into it, e.g. this is how to get into the state above: socket(S) = 1 bind(1, $name-1) listen(1) socket(S) = 2 connect(2, $name-1) accept(1) = 3 send(2, $message-0) send(3, $message-0) close(3) Program has created a stream socket, bound it, listened it, then created another stream socket, connected to the 1st one, then accepted the connection sent two messages vice-versa and closed the accepted end, so the 1st socket left connected to the dead socket with a message from it. II) Run the state This is when test actually creates a process that does the syscalls required to get into the generated state (and hopefully gets into it). III) Check C/R of the state This is the trickiest part when it comes to the R step -- it's not clear how to validate that the state restored is correct. But if only trying to dump the state -- it's just calling criu dump. As images dir the state string description is used. One may choose only to generate the states with --gen option. One may choose only to run the states with --run option. The latter is useful to verify that the states generator is actually producing valid states. If no options given, the state is also dump-ed (restore is to come later). For now the usage experience is like this: - Going --depth 10 --gen (i.e. just generating all possibles states that are acheivable with 10 syscalls) produces 44 unique states for 0.01 seconds. The generated result covers some static tests we have in zdtm :) More generation stats is like this: --depth 15 : 1.1 sec / 72 states --depth 18 : 13.2 sec / 89 states --depth 20 : 1 m 8 sec / 101 state - Running and trying with criu is checked with --depth 9. Criu fails to dump the state SA-CX-MX_SBL (shown above) with the error Error (criu/sk-queue.c:151): recvmsg fail: error: Connection reset by peer Nearest plans: 1. Add generators for on-disk sockets names (now oly abstract). Here an interesting case is when names overlap and one socket gets a name of another, but isn't accessible by it 2. Add datagram sockets. Here it'd be fun to look at how many-to-one connections are generated and checked. 3. Add socketpair()-s. Farther plans: 1. Cut the tree better to allow for deeper tree scan. 2. Add restore. 3. Add SCM-s 4. Have the exhaustive testing for other resources. Changes since v1: * Added DGRAM sockets :) Dgram sockets are trickier that STREAM, as they can reconnect from one peer to another. Thus just limiting the tree depth results in wierd states when socket just changes peer. In the v1 of this patch new sockets were added to the state only when old ones reported that there's nothing that can be done with them. This limited the amount of stupid branches, but this strategy doesn't work with dgram due to reconnect. Due to this, change #2: * Added the --sockets NR option to limit the amount of sockets. This allowed to throw new sockets into the state on each step, which made a lot of interesting states for DGRAM ones. * Added the 'restore' stage and checks after it. After the process is restore the script performs as much checks as possible having the expected state description in memory. The checks verify that the values below get from real sockets match the expectations in generated state: - socket itself - name - listen state - pending connections - messages in queue (sender is not checked) - connectivity The latter is checked last, after all queues should be empty, by sending control messages with socket.recv() method. * Added --keep option to run all tests even if one of them fails. And print nice summary at the end. So far the test found several issues: - Dump doesn't work for half-closed connection with unread messages - Pending half-closed connection is not restored - Socket name is not restored - Message is not restored New TODO: - Check listen state is still possible to accept connections (?) - Add socketpair()s - Add on-disk names - Add SCM-s - Exhaustive script for other resources Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/exhaustive/unix.py | 756 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 756 insertions(+) create mode 100755 test/exhaustive/unix.py diff --git a/test/exhaustive/unix.py b/test/exhaustive/unix.py new file mode 100755 index 000000000..727aa0a7a --- /dev/null +++ b/test/exhaustive/unix.py @@ -0,0 +1,756 @@ +#!/usr/bin/env python + +import sys +import os +import socket +import argparse +import time +import subprocess +import signal +import fcntl +import stat + +criu_bin='../../criu/criu' + +sk_type_s = { + socket.SOCK_STREAM: "S", + socket.SOCK_DGRAM: "D", +} + +# Actions that can be done by test. Actions are not only syscall +# names to call, but also arguments with which to do it +# +# Each action consists of +# - arguments, e.g. type of socket, or socket id to work on +# - act() method which just generates an record +# - do() method, that actually does what's required +# - show() method to return the string description of what's done + +def mk_socket(st, typ): + st.sk_id += 1 + sk = sock(st.sk_id, typ) + st.add_socket(sk) + return sk + +class act_socket: + def __init__(self, typ): + self.typ = typ + + def act(self, st): + sk = mk_socket(st, self.typ) + self.sk_id = sk.sk_id + + def do(self, st): + sk = socket.socket(socket.AF_UNIX, self.typ, 0) + st.real_sockets[self.sk_id] = sk + + def show(self): + return 'socket(%s) = %d' % (sk_type_s[self.typ], self.sk_id) + + +class act_close: + def __init__(self, sk_id): + self.sk_id = sk_id + + def act(self, st): + sk = st.get_socket(self.sk_id) + st.del_socket(sk) + for ic in sk.icons: + sk = st.get_socket(ic) + st.del_socket(sk) + + def do(self, st): + sk = st.real_sockets.pop(self.sk_id) + sk.close() + + def show(self): + return 'close(%d)' % self.sk_id + + +class act_listen: + def __init__(self, sk_id): + self.sk_id = sk_id + + def act(self, st): + sk = st.get_socket(self.sk_id) + sk.listen = True + + def do(self, st): + sk = st.real_sockets[self.sk_id] + sk.listen(10) + + def show(self): + return 'listen(%d)' % self.sk_id + + +class act_bind: + def __init__(self, sk_id, name_id): + self.sk_id = sk_id + self.name_id = name_id + + def act(self, st): + sk = st.get_socket(self.sk_id) + sk.name = self.name_id + + def do(self, st): + sk = st.real_sockets[self.sk_id] + sk.bind(sock.real_name_for(self.name_id)) + + def show(self): + return 'bind(%d, $name-%d)' % (self.sk_id, self.name_id) + + +class act_connect: + def __init__(self, sk_id, listen_sk_id): + self.sk_id = sk_id + self.lsk_id = listen_sk_id + + def act(self, st): + sk = st.get_socket(self.sk_id) + if st.sk_type == socket.SOCK_STREAM: + lsk = st.get_socket(self.lsk_id) + psk = mk_socket(st, socket.SOCK_STREAM) + psk.visible = False + sk.peer = psk.sk_id + psk.peer = sk.sk_id + psk.name = lsk.name + lsk.icons.append(psk.sk_id) + lsk.icons_seq += 1 + else: + sk.peer = self.lsk_id + psk = st.get_socket(self.lsk_id) + psk.icons_seq += 1 + + def do(self, st): + sk = st.real_sockets[self.sk_id] + sk.connect(sock.real_name_for(self.lsk_id)) + + def show(self): + return 'connect(%d, $name-%d)' % (self.sk_id, self.lsk_id) + + +class act_accept: + def __init__(self, sk_id): + self.sk_id = sk_id + + def act(self, st): + lsk = st.get_socket(self.sk_id) + iid = lsk.icons.pop(0) + nsk = st.get_socket(iid) + nsk.visible = True + self.nsk_id = nsk.sk_id + + def do(self, st): + sk = st.real_sockets[self.sk_id] + nsk, ai = sk.accept() + if self.nsk_id in st.real_sockets: + raise Exception("SK ID conflict") + st.real_sockets[self.nsk_id] = nsk + + def show(self): + return 'accept(%d) = %d' % (self.sk_id, self.nsk_id) + + +class act_sendmsg: + def __init__(self, sk_id, to_id): + self.sk_id = sk_id + self.to_id = to_id + self.direct_send = None + + def act(self, st): + sk = st.get_socket(self.sk_id) + msg = (sk.sk_id, sk.outseq) + self.msg_id = sk.outseq + sk.outseq += 1 + psk = st.get_socket(self.to_id) + psk.inqueue.append(msg) + self.direct_send = (sk.peer == psk.sk_id) + + def do(self, st): + sk = st.real_sockets[self.sk_id] + msgv = act_sendmsg.msgval(self.msg_id) + if self.direct_send: + sk.send(msgv) + else: + sk.sendto(msgv, sock.real_name_for(self.to_id)) + + def show(self): + return 'send(%d, %d, $message-%d)' % (self.sk_id, self.to_id, self.msg_id) + + @staticmethod + def msgval(msgid, pref = ''): + return '%sMSG%d' % (pref, msgid) + +# +# Description of a socket +# +class sock: + def __init__(self, sk_id, sock_type): + # ID of a socket. Since states and sockets are cloned + # while we scan the tree of states the only valid way + # to address a socket is to find one by ID. + self.sk_id = sk_id + # The socket.SOCK_FOO value + self.sk_type = sock_type + # Sockets that haven't yet been accept()-ed are in the + # state, but user cannot operate on them. Also this + # invisibility contributes to state descriptionm since + # connection to not accepted socket is not the same + # as connection to accepted one. + self.visible = True + # The listen() was called. + self.listen = False + # The bind() was called. Also set by accept(), the name + # inherits from listener. + self.name = None + # The connect() was called. Set on two sockets when the + # connect() is called. + self.peer = None + # Progress on accepting connections. Used to check when + # it's OK to close the socket (see comment below). + self.icons_seq = 0 + # List of IDs of sockets that can be accept()-ed + self.icons = [] + # Number to generate message contents. + self.outseq = 0 + # Incoming queue of messages. + self.inqueue = [] + + def clone(self): + sk = sock(self.sk_id, self.sk_type) + sk.visible = self.visible + sk.listen = self.listen + sk.name = self.name + sk.peer = self.peer + sk.icons_seq = self.icons_seq + sk.icons = list(self.icons) + sk.outseq = self.outseq + sk.inqueue = list(self.inqueue) + return sk + + def get_actions(self, st): + if not self.visible: + return [] + + if st.sk_type == socket.SOCK_STREAM: + return self.get_stream_actions(st) + else: + return self.get_dgram_actions(st) + + def get_send_action(self, to, st): + # However, if peer has a message from us at + # the queue tail, sending a new one doesn't + # really make sence + want_msg = True + if len(to.inqueue) != 0: + lmsg = to.inqueue[-1] + if lmsg[0] == self.sk_id: + want_msg = False + if want_msg: + return [ act_sendmsg(self.sk_id, to.sk_id) ] + else: + return [ ] + + def get_stream_actions(self, st): + act_list = [] + + # Any socket can be closed, but closing a socket + # that hasn't contributed to some new states is + # just waste of time, so we close only connected + # sockets or listeners that has at least one + # incoming connection pendig or served + + if self.listen: + if self.icons: + act_list.append(act_accept(self.sk_id)) + if self.icons_seq: + act_list.append(act_close(self.sk_id)) + elif self.peer: + act_list.append(act_close(self.sk_id)) + # Connected sockets can send and receive messages + # But receiving seem not to produce any new states, + # so only sending + # Also sending to a closed socket doesn't work + psk = st.get_socket(self.peer, True) + if psk: + act_list += self.get_send_action(psk, st) + else: + for psk in st.sockets: + if psk.listen and psk.name: + act_list.append(act_connect(self.sk_id, psk.sk_id)) + + # Listen on not-bound socket is prohibited as + # well as binding a listening socket + if not self.name: + # TODO: support for file paths (see real_name_for) + # TODO: these names can overlap each other + act_list.append(act_bind(self.sk_id, self.sk_id)) + else: + act_list.append(act_listen(self.sk_id)) + + return act_list + + def get_dgram_actions(self, st): + act_list = [] + + # Dgram socket can bind at any time + if not self.name: + act_list.append(act_bind(self.sk_id, self.sk_id)) + + # Can connect to peer-less sockets + for psk in st.sockets: + if psk == self: + continue + if psk.peer != None and psk.peer != self.sk_id: + # Peer by someone else, can do nothing + continue + + # Peer-less psk or having us as peer + # We can connect to or send messages + if psk.name and self.peer != psk.sk_id: + act_list.append(act_connect(self.sk_id, psk.sk_id)) + + if psk.name or self.peer == psk.sk_id: + act_list += self.get_send_action(psk, st) + + if self.outseq != 0 or self.icons_seq != 0: + act_list.append(act_close(self.sk_id)) + + return act_list + + @staticmethod + def name_of(sk): + if not sk: + return 'X' + elif not sk.visible: + return 'H' + elif sk.name: + return 'B' + else: + return 'A' + + @staticmethod + def real_name_for(sk_id): + return "\0" + "CRSK%d" % sk_id + + # The describe() generates a string that represents + # a state of a socket. Called by state.describe(), see + # comment there about what description is. + def describe(self, st): + dsc = '%s' % sk_type_s[self.sk_type] + dsc += sock.name_of(self) + + if self.listen: + dsc += 'L' + if self.peer: + psk = st.get_socket(self.peer, True) + dsc += '-C%s' % sock.name_of(psk) + if self.icons: + i_dsc = '' + for c in self.icons: + psk = st.get_socket(c) + psk = st.get_socket(psk.peer, True) + i_dsc += sock.name_of(psk) + dsc += '-I%s' % i_dsc + if self.inqueue: + froms = set() + for m in self.inqueue: + froms.add(m[0]) + q_dsc = '' + for f in froms: + fsk = st.get_socket(f, True) + q_dsc += sock.name_of(fsk) + dsc += '-M%s' % q_dsc + return dsc + + +class state: + def __init__(self, max_sockets, sk_type): + self.sockets = [] + self.sk_id = 0 + self.steps = [] + self.real_sockets = {} + self.sockets_left = max_sockets + self.sk_type = sk_type + + def add_socket(self, sk): + self.sockets.append(sk) + + def del_socket(self, sk): + self.sockets.remove(sk) + + def get_socket(self, sk_id, can_be_null = False): + for sk in self.sockets: + if sk.sk_id == sk_id: + return sk + + if not can_be_null: + raise Exception("%d socket not in list" % sk_id) + + return None + + def get_actions(self): + act_list = [] + + # Any socket in the state we can change it + for sk in self.sockets: + act_list += sk.get_actions(self) + + if self.sockets_left > 0: + act_list.append(act_socket(self.sk_type)) + self.sockets_left -= 1 + + return act_list + + def clone(self): + nst = state(self.sockets_left, self.sk_type) + for sk in self.sockets: + nst.sockets.append(sk.clone()) + nst.sk_id = self.sk_id + nst.steps = list(self.steps) + return nst + + # Generates textual description of a state. Different states + # may have same descriptions, e.g. if we have two sockets and + # only one of them is in listen state, we don't care which + # one in which. At the same time really different states + # shouldn't map to the same string. + def describe(self): + sks = map(lambda x: x.describe(self), self.sockets) + sks = sorted(sks) + return '_'.join(sks) + + +def set_nonblock(sk): + fd = sk.fileno() + flags = fcntl.fcntl(fd, fcntl.F_GETFL) + fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) + +CHK_FAIL_UNKNOWN = 10 +CHK_FAIL_SOCKET = 11 +CHK_FAIL_STAT = 12 +CHK_FAIL_LISTEN = 13 +CHK_FAIL_NAME = 14 +CHK_FAIL_ACCEPT = 15 +CHK_FAIL_RECV_0 = 16 +CHK_FAIL_RECV_MIX = 17 +CHK_FAIL_CONNECT = 18 +CHK_FAIL_CONNECT2 = 19 +CHK_FAIL_KILLED = 20 +CHK_FAIL_DUMP = 21 +CHK_FAIL_RESTORE = 22 + +CHK_PASS = 42 + +fail_desc = { + CHK_FAIL_UNKNOWN: 'Aliens invaded the test', + CHK_FAIL_LISTEN: 'Listen state lost on restore', + CHK_FAIL_NAME: 'Name lost on restore', + CHK_FAIL_ACCEPT: 'Incoming connection lost on restore', + CHK_FAIL_RECV_0: 'Message lost on restore', + CHK_FAIL_RECV_MIX: 'Message misorder on restore', + CHK_FAIL_CONNECT: 'Connectivity broken on restore', + CHK_FAIL_CONNECT2: 'Connectivity broken the hard way on restore', + CHK_FAIL_KILLED: 'Test process died unexpectedly', + CHK_FAIL_DUMP: 'Cannot dump', + CHK_FAIL_RESTORE: 'Cannot restore', +} + +def chk_real_state(st): + # Befor enything else -- check that we still have + # all the sockets at hands + for sk in st.sockets: + if not sk.visible: + continue + + # In theory we can have key-not-found exception here, + # but this has nothing to do with sockets restore, + # since it's just bytes in memory, so ... we assume + # that we have object here and just check for it in + # the fdtable + rsk = st.real_sockets[sk.sk_id] + try: + s_st = os.fstat(rsk.fileno()) + except: + print 'FAIL: Socket %d lost' % sk.sk_id + return CHK_FAIL_SOCKET + if not stat.S_ISSOCK(s_st.st_mode): + print 'FAIL: Not a socket %d at %d' % (sk.sk_id, rsk.fileno()) + return CHK_FAIL_STAT + + # First -- check the listen states and names + for sk in st.sockets: + if not sk.visible: + continue + + rsk = st.real_sockets[sk.sk_id] + r_listen = rsk.getsockopt(socket.SOL_SOCKET, socket.SO_ACCEPTCONN) + if (sk.listen and r_listen == 0) or (not sk.listen and r_listen == 1): + print "FAIL: Socket %d listen %d, expected %d" % \ + (sk.sk_id, r_listen, sk.listen and 1 or 0) + return CHK_FAIL_LISTEN + + if sk.name: + r_name = rsk.getsockname() + w_name = sock.real_name_for(sk.name) + if r_name != w_name: + print 'FAIL: Socket %d name mismatch [%s], want [%s]' % \ + (sk.sk_id, r_name, w_name) + return CHK_FAIL_NAME + + # Second -- check (accept) pending connections + for sk in st.sockets: + if not sk.listen: + continue + + rsk = st.real_sockets[sk.sk_id] + set_nonblock(rsk) + + while sk.icons: + # Do act_accept to change the state properly + # and not write the code twice + acc = act_accept(sk.sk_id) + acc.act(st) + try: + acc.do(st) + except: + print 'FAIL: Cannot accept pending connection for %d' % sk.sk_id + return CHK_FAIL_ACCEPT + + print ' `- did %s' % acc.show() + + # Third -- check inqueues + for sk in st.sockets: + if not sk.inqueue: + continue + + rsk = st.real_sockets[sk.sk_id] + set_nonblock(rsk) + + while sk.inqueue: + msg = sk.inqueue.pop(0) + try: + r_msg, m_from = rsk.recvfrom(128) + except: + print 'FAIL: No message in queue for %d' % sk.sk_id + return CHK_FAIL_RECV_0 + + w_msg = act_sendmsg.msgval(msg[1]) + if r_msg != w_msg: + print 'FAIL: Message misorder: %s want %s (from %d)' % \ + (r_msg, w_msg, msg[0]) + return CHK_FAIL_RECV_MIX + + # TODO -- check sender + print ' `- recvd %d.%d msg %s -> %d' % \ + (msg[0], msg[1], m_from, sk.sk_id) + + # Finally, after all sockets are visible and all inqueues are + # drained -- check the sockets connectivity + for sk in st.sockets: + if not sk.peer: + continue + + # Closed connection with one peer alive. Cannot check. + if not sk.peer in st.real_sockets: + continue + + rsk = st.real_sockets[sk.sk_id] + psk = st.real_sockets[sk.peer] + set_nonblock(psk) + msgv = act_sendmsg.msgval(3 * sk.sk_id + 5 * sk.peer, 'C') # just random + + try: + rsk.send(msgv) + rmsg = psk.recv(128) + except: + print 'FAIL: Connectivity %d -> %d lost' % \ + (sk.sk_id, sk.peer) + return CHK_FAIL_CONNECT + + # If sockets are not connected the recv above + # would generate exception and the check would + # fail. But just in case we've screwed the queues + # the hard way -- also check for the message being + # delivered for real + if rmsg != msgv: + print 'FAIL: Connectivity %d -> %d not verified' % \ + (sk.sk_id, sk.peer) + return CHK_FAIL_CONNECT2 + + print ' `- checked %d -> %d with %s' % (sk.sk_id, sk.peer, msgv) + + return CHK_PASS + + +def chk_state(st, opts): + print "Will check state" + + sigsk_name = "\0" + "CRSIGSKC" + signal_sk = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) + signal_sk.bind(sigsk_name) + + # FIXME Ideally call to criu should be performed by the run_state's + # pid!=0 branch, but for simplicity we fork the kid which has the + # same set of sockets we do, then dump it. Then restore and notify + # via dgram socket to check its state. Current task still has all + # the same sockets :) so we close them not to produce bind() name + # conflicts on restore + + pid = os.fork() + if pid == 0: + msg = signal_sk.recv(64) + ret = chk_real_state(st) + sys.exit(ret) + + signal_sk.close() + for rsk in st.real_sockets.values(): + rsk.close() + + print "`- dump" + img_path = "sti_" + st.describe() + try: + os.mkdir(img_path) + subprocess.check_call([criu_bin, "dump", "-t", "%d" % pid, "-D", img_path, "-v4", "-o", "dump.log", "-j"]) + except: + print "Dump failed" + os.kill(pid, signal.SIGKILL) + return CHK_FAIL_DUMP + + print "`- restore" + try: + os.waitpid(pid, 0) + subprocess.check_call([criu_bin, "restore", "-D", img_path, "-v4", "-o", "rst.log", "-j", "-d", "-S"]) + except: + print "Restore failed" + return CHK_FAIL_RESTORE + + print "`- check" + signal_sk = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) + try: + signal_sk.sendto('check', sigsk_name) + except: + # Probably the peer has died before us or smth else went wrong + os.kill(pid, signal.SIGKILL) + + wp, status = os.waitpid(pid, 0) + if os.WIFEXITED(status): + status = os.WEXITSTATUS(status) + if status != CHK_PASS: + print "`- exited with %d" % status + return status + elif os.WIFSIGNALED(status): + status = os.WTERMSIG(status) + print "`- killed with %d" % status + return CHK_FAIL_KILLED + else: + return CHK_FAIL_UNKNOWN + + return CHK_PASS + + +def run_state(st, opts): + print "Will run state" + pid = os.fork() + if pid != 0: + wpid, status = os.wait() + if os.WIFEXITED(status): + status = os.WEXITSTATUS(status) + elif os.WIFSIGNALED(status): + status = CHK_FAIL_KILLED + else: + status = CHK_FAIL_UNKNOWN + return status + + # Try the states in subprocess so that once + # it exits the created sockets are removed + for step in st.steps: + step.do(st) + + if not opts.run: + ret = chk_state(st, opts) + else: + ret = chk_real_state(st) + + sys.exit(ret) + + +def proceed(st, seen, failed, opts, depth = 0): + desc = st.describe() + if not desc: + pass + elif not desc in seen: + # When scanning the tree we run and try only states that + # differ, but don't stop tree traversal on them. This is + # because sometimes we can get into the already seen state + # using less steps and it's better to proceed as we have + # depth to move forward and generate more states. + seen[desc] = len(st.steps) + print '%s' % desc + for s in st.steps: + print '\t%s' % s.show() + + if not opts.gen: + ret = run_state(st, opts) + if ret != CHK_PASS: + failed.add((desc, ret)) + if not opts.keep: + return False + else: + # Don't even proceed with this state if we've already + # seen one but get there with less steps + seen_score = seen[desc] + if len(st.steps) > seen_score: + return True + else: + seen[desc] = len(st.steps) + + if depth >= opts.depth: + return True + + actions = st.get_actions() + for act in actions: + nst = st.clone() + act.act(nst) + nst.steps.append(act) + if not proceed(nst, seen, failed, opts, depth + 1): + return False + + return True + + +p = argparse.ArgumentParser("CRIU test suite") +p.add_argument("--depth", help = "Depth of generated tree", default = '8') +p.add_argument("--sockets", help = "Maximum number of sockets", default = '1') +p.add_argument("--dgram", help = "Use SOCK_DGRAM sockets", action = 'store_true') +p.add_argument("--stream", help = "Use SOCK_STREAM sockets", action = 'store_true') +p.add_argument("--gen", help = "Only generate and show states", action = 'store_true') +p.add_argument("--run", help = "Run the states, but don't C/R", action = 'store_true') +p.add_argument("--keep", help = "Don't stop on error", action = 'store_true') +opts = p.parse_args() +opts.depth = int(opts.depth) + +# XXX: does it make any sence to mix two types in one go? +if opts.stream and opts.dgram: + print 'Choose only one type' + sys.exit(1) + +if opts.stream: + sk_type = socket.SOCK_STREAM +elif opts.dgram: + sk_type = socket.SOCK_DGRAM +else: + print 'Choose some type' + sys.exit(1) + +st = state(int(opts.sockets), sk_type) +seen = {} +failed = set() +proceed(st, seen, failed, opts) + +if len(failed) == 0: + print 'PASS (%d states)' % len(seen) +else: + print 'FAIL %d/%d' % (len(failed), len(seen)) + for f in failed: + print "\t%-50s: %s" % (f[0], fail_desc.get(f[1], 'unknown reason %d' % f[1])) From e51960ea3e5345d5b24446ca86584f9ed5439392 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 9 Dec 2016 16:59:00 +0300 Subject: [PATCH 1588/4375] test, pipes: Exhaustive test of shared pipes So, here's the next test that just enumerates all possible states and checks that CRIU C/R-s it well. This time -- pipes. The goal of the test is to load the fd-sharing engine, so pipes are chosen, as they not only generate shared struct files, but also produce 2 descriptors in CRIU's fdesc->open callback which is handled separately. It's implemented slightly differently from the unix test, since we don't want to check sequences of syscalls on objects, we need to check the task to pipe relations in all possible ways. The 'state' is several tasks, several pipes and each generated test includes pipe ends sitting in all possible combinations in the tasks' FDTs. Also note, that states, that seem to be equal to each other, e.g. pipe between tasks A->B and pipe B->A, are really different as CRIU picks the pipe-restorer based in task PIDs. So whether the picked task has read end or write end at his FDT makes a difference on restore. Number of tasks is limited with --tasks option, number of pipes with the --pipes one. Test just runs all -- generates states, makes them and C/R-s them. To check the restored result the /proc/pid/fd/ and /proc/pid/fdinfo/ for all restored tasks is analyzed. Right now CRIU works OK for --tasks 2 --pipes 2 (for more -- didn't check). Kirill, please, check that your patches pass this test. TODO: - Randomize FDs under which tasks see the pipes. Now all tasks if they have some pipe, all see it under the same set of FDs. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- test/exhaustive/pipe.py | 270 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100755 test/exhaustive/pipe.py diff --git a/test/exhaustive/pipe.py b/test/exhaustive/pipe.py new file mode 100755 index 000000000..4e94cab93 --- /dev/null +++ b/test/exhaustive/pipe.py @@ -0,0 +1,270 @@ +#!/usr/bin/env python + +import argparse +import os +import signal +import socket +import time +import sys +import subprocess + +criu_bin='../../criu/criu' + +def mix(nr_tasks, nr_pipes): + # Returned is the list of combinations. + # Each combination is the lists of pipe descriptors. + # Each pipe descriptor is a 2-elemtn tuple, that contains values + # for R and W ends of pipes, each being a bit-field denoting in + # which tasks the respective end should be opened or not. + + # First -- make a full set of combinations for a single pipe. + max_idx = 1 << nr_tasks + pipe_mix = [[(r, w)] for r in xrange(0, max_idx) for w in xrange(0, max_idx)] + + # Now, for every pipe throw another one into the game making + # all possible combinations of what was seen before with the + # newbie. + pipes_mix = pipe_mix + for t in xrange(1, nr_pipes): + pipes_mix = [ o + n for o in pipes_mix for n in pipe_mix ] + + return pipes_mix + + +# Called by a test sub-process. It just closes the not needed ends +# of pipes and sleeps waiting for death. +def make_pipes(task_nr, nr_pipes, pipes, comb, status_pipe): + print '\t\tMake pipes for %d' % task_nr + # We need to make sure that pipes have their + # ends according to comb for task_nr + + for i in xrange(0, nr_pipes): + # Read end + if not (comb[i][0] & (1 << task_nr)): + os.close(pipes[i][0]) + # Write end + if not (comb[i][1] & (1 << task_nr)): + os.close(pipes[i][1]) + + os.write(status_pipe, '0') + os.close(status_pipe) + while True: + time.sleep(100) + + +def get_pipe_ino(pid, fd): + try: + return os.stat('/proc/%d/fd/%d' % (pid, fd)).st_ino + except: + return None + + +def get_pipe_rw(pid, fd): + for l in open('/proc/%d/fdinfo/%d' % (pid, fd)): + if l.startswith('flags:'): + f = l.split(None, 1)[1][-2] + if f == '0': + return 0 # Read + elif f == '1': + return 1 # Write + break + + raise Exception('Unexpected fdinfo contents') + + +def check_pipe_y(pid, fd, rw, inos): + ino = get_pipe_ino(pid, fd) + if ino == None: + return 'missing ' + if not inos.has_key(fd): + inos[fd] = ino + elif inos[fd] != ino: + return 'wrong ' + mod = get_pipe_rw(pid, fd) + if mod != rw: + return 'badmode ' + return None + + +def check_pipe_n(pid, fd): + ino = get_pipe_ino(pid, fd) + if ino == None: + return None + else: + return 'present ' + + +def check_pipe_end(kids, fd, comb, rw, inos): + t_nr = 0 + for t_pid in kids: + if comb & (1 << t_nr): + res = check_pipe_y(t_pid, fd, rw, inos) + else: + res = check_pipe_n(t_pid, fd) + if res != None: + return res + 'kid(%d)' % t_nr + t_nr += 1 + return None + + +def check_pipe(kids, fds, comb, inos): + for e in (0, 1): # 0 == R, 1 == W, see get_pipe_rw() + res = check_pipe_end(kids, fds[e], comb[e], e, inos) + if res != None: + return res + 'end(%d)' % e + return None + +def check_pipes(kids, pipes, comb): + # Kids contain pids + # Pipes contain pipe FDs + # Comb contain list of pairs of bits for RW ends + p_nr = 0 + p_inos = {} + for p_fds in pipes: + res = check_pipe(kids, p_fds, comb[p_nr], p_inos) + if res != None: + return res + 'pipe(%d)' % p_nr + p_nr += 1 + + return None + + +# Run by test main process. It opens pipes, then forks kids that +# will contain needed pipe ends, then report back that it's ready +# and waits for a signal (unix socket message) to start checking +# the kids' FD tables. +def make_comb(comb, opts, status_pipe): + print '\tMake pipes' + # 1st -- make needed pipes + pipes = [] + for p in xrange(0, opts.pipes): + pipes.append(os.pipe()) + + # Fork the kids that'll make pipes + kc_pipe = os.pipe() + kids = [] + for t in xrange(0, opts.tasks): + pid = os.fork() + if pid == 0: + os.close(status_pipe) + os.close(kc_pipe[0]) + make_pipes(t, opts.pipes, pipes, comb, kc_pipe[1]) + sys.exit(1) + kids.append(pid) + + os.close(kc_pipe[1]) + for p in pipes: + os.close(p[0]) + os.close(p[1]) + + # Wait for kids to get ready + k_res = '' + while True: + v = os.read(kc_pipe[0], 16) + if v == '': + break + k_res += v + os.close(kc_pipe[0]) + + ex_code = 1 + if k_res == '0' * opts.tasks: + print '\tWait for C/R' + cmd_sk = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) + cmd_sk.bind('\0CRIUPCSK') + + # Kids are ready, so is socket for kicking us. Notify the + # parent task that we are good to go. + os.write(status_pipe, '0') + os.close(status_pipe) + v = cmd_sk.recv(16) + if v == '0': + print '\tCheck pipes' + res = check_pipes(kids, pipes, comb) + if res == None: + ex_code = 0 + else: + print '\tFAIL %s' % res + + # Just kill kids, all checks are done by us, we don't need'em any more + for t in kids: + os.kill(t, signal.SIGKILL) + os.waitpid(t, 0) + + return ex_code + + +def cr_test(pid): + print 'C/R test' + img_dir = 'pimg_%d' % pid + try: + os.mkdir(img_dir) + subprocess.check_call([criu_bin, 'dump', '-t', '%d' % pid, '-D', img_dir, '-o', 'dump.log', '-v4', '-j']) + except: + print '`- dump fail' + return False + + try: + os.waitpid(pid, 0) + subprocess.check_call([criu_bin, 'restore', '-D', img_dir, '-o', 'rst.log', '-v4', '-j', '-d', '-S']) + except: + print '`- restore fail' + return False + + return True + + +def run(comb, opts): + print 'Checking %r' % comb + cpipe = os.pipe() + pid = os.fork() + if pid == 0: + os.close(cpipe[0]) + ret = make_comb(comb, opts, cpipe[1]) + sys.exit(ret) + + # Wait for the main process to get ready + os.close(cpipe[1]) + res = os.read(cpipe[0], 16) + os.close(cpipe[0]) + + if res == '0': + res = cr_test(pid) + + print 'Wake up test' + s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) + if res: + res = '0' + else: + res = 'X' + try: + # Kick the test to check its state + s.sendto(res, '\0CRIUPCSK') + except: + # Restore might have failed or smth else happenned + os.kill(pid, signal.SIGKILL) + s.close() + + # Wait for the guy to exit and get the result (PASS/FAIL) + p, st = os.waitpid(pid, 0) + if os.WIFEXITED(st): + st = os.WEXITSTATUS(st) + + print 'Done (%d, pid == %d)' % (st, pid) + return st == 0 + + +p = argparse.ArgumentParser("CRIU test suite") +p.add_argument("--tasks", help = "Number of tasks", default = '2') +p.add_argument("--pipes", help = "Number of pipes", default = '2') +opts = p.parse_args() +opts.tasks = int(opts.tasks) +opts.pipes = int(opts.pipes) + +pipe_combs = mix(opts.tasks, opts.pipes) + +for comb in pipe_combs: + if not run(comb, opts): + print 'FAIL' + break +else: + print 'PASS' From 3f994bcfc3adc51780c2b67f76286dd5535d0a86 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 25 Jan 2017 19:19:00 +0300 Subject: [PATCH 1589/4375] lib: Add simple Go wrappers for swrk mode We'll need some docs :) bu the API is criu := MakeCriu() criu.Dump(opts, notify) criu.Restore(opts, notify) criu.PreDump(opts, notify) criu.StartPageServer(opts) where opts is the object from rpc.proto, Go has almost native support for those, so caller should - compile .proto file - export it and golang/protobuf/proto - create and initialize the CriuOpts struct and notify is an interface with callbacks that correspond to criu notification messages. A stupid dump/restore tool in src/test/main.go demonstrates the above. Changes since v1: * Added keep_open mode for pre-dumps. Do use it one needs to call criu.Prepare() right after creation and criu.Cleanup() right after .Dump() * Report resp.cr_errmsg string on request error. Further TODO: - docs - code comments travis-ci: success for libphaul (rev2) Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- lib/go/.gitignore | 1 + lib/go/Makefile | 8 ++ lib/go/src/criu/main.go | 177 ++++++++++++++++++++++++++++++++++++++ lib/go/src/criu/notify.go | 52 +++++++++++ lib/go/src/test/main.go | 114 ++++++++++++++++++++++++ 5 files changed, 352 insertions(+) create mode 100644 lib/go/.gitignore create mode 100644 lib/go/Makefile create mode 100644 lib/go/src/criu/main.go create mode 100644 lib/go/src/criu/notify.go create mode 100644 lib/go/src/test/main.go diff --git a/lib/go/.gitignore b/lib/go/.gitignore new file mode 100644 index 000000000..8cab5691e --- /dev/null +++ b/lib/go/.gitignore @@ -0,0 +1 @@ +src/rpc/rpc.pb.go diff --git a/lib/go/Makefile b/lib/go/Makefile new file mode 100644 index 000000000..c8551d609 --- /dev/null +++ b/lib/go/Makefile @@ -0,0 +1,8 @@ +all: test + +test: rpc + GOPATH=$(shell pwd):/usr/share/gocode go build -o test test + +rpc: + mkdir -p src/rpc/ + protoc --go_out=src/rpc/ --proto_path=../../images/ ../../images/rpc.proto diff --git a/lib/go/src/criu/main.go b/lib/go/src/criu/main.go new file mode 100644 index 000000000..90866ea18 --- /dev/null +++ b/lib/go/src/criu/main.go @@ -0,0 +1,177 @@ +package criu + +import ( + "errors" + "fmt" + "github.com/golang/protobuf/proto" + "os" + "os/exec" + "rpc" + "strconv" + "syscall" +) + +type Criu struct { + swrk_cmd *exec.Cmd + swrk_sk *os.File +} + +func MakeCriu() *Criu { + return &Criu{} +} + +func (c *Criu) Prepare() error { + fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_SEQPACKET, 0) + if err != nil { + return err + } + + cln := os.NewFile(uintptr(fds[0]), "criu-xprt-cln") + syscall.CloseOnExec(fds[0]) + srv := os.NewFile(uintptr(fds[1]), "criu-xprt-srv") + defer srv.Close() + + args := []string{"swrk", strconv.Itoa(fds[1])} + cmd := exec.Command("criu", args...) + + err = cmd.Start() + if err != nil { + cln.Close() + return err + } + + c.swrk_cmd = cmd + c.swrk_sk = cln + + return nil +} + +func (c *Criu) Cleanup() { + if c.swrk_cmd != nil { + c.swrk_sk.Close() + c.swrk_sk = nil + c.swrk_cmd.Wait() + c.swrk_cmd = nil + } +} + +func (c *Criu) sendAndRecv(req_b []byte) ([]byte, int, error) { + cln := c.swrk_sk + _, err := cln.Write(req_b) + if err != nil { + return nil, 0, err + } + + resp_b := make([]byte, 2*4096) + n, err := cln.Read(resp_b) + if err != nil { + return nil, 0, err + } + + return resp_b, n, nil +} + +func (c *Criu) doSwrk(req_type rpc.CriuReqType, opts *rpc.CriuOpts, nfy CriuNotify) error { + req := rpc.CriuReq{ + Type: &req_type, + Opts: opts, + } + + if nfy != nil { + opts.NotifyScripts = proto.Bool(true) + } + + if c.swrk_cmd == nil { + err := c.Prepare() + if err != nil { + return err + } + + defer c.Cleanup() + } + + for { + req_b, err := proto.Marshal(&req) + if err != nil { + return err + } + + resp_b, resp_s, err := c.sendAndRecv(req_b) + if err != nil { + return err + } + + resp := &rpc.CriuResp{} + err = proto.Unmarshal(resp_b[:resp_s], resp) + if err != nil { + return err + } + + if !resp.GetSuccess() { + return fmt.Errorf("operation failed (msg:%s err:%d)", + resp.GetCrErrmsg(), resp.GetCrErrno()) + } + + resp_type := resp.GetType() + if resp_type == req_type { + break + } + if resp_type != rpc.CriuReqType_NOTIFY { + return errors.New("unexpected responce") + } + if nfy == nil { + return errors.New("unexpected notify") + } + + notify := resp.GetNotify() + switch notify.GetScript() { + case "pre-dump": + err = nfy.PreDump() + case "post-dump": + err = nfy.PostDump() + case "pre-restore": + err = nfy.PreRestore() + case "post-restore": + err = nfy.PostRestore(notify.GetPid()) + case "network-lock": + err = nfy.NetworkLock() + case "network-unlock": + err = nfy.NetworkUnlock() + case "setup-namespaces": + err = nfy.SetupNamespaces(notify.GetPid()) + case "post-setup-namespaces": + err = nfy.PostSetupNamespaces() + case "post-resume": + err = nfy.PostResume() + default: + err = nil + } + + if err != nil { + return err + } + + req = rpc.CriuReq{ + Type: &resp_type, + NotifySuccess: proto.Bool(true), + } + } + + return nil +} + +func (c *Criu) Dump(opts rpc.CriuOpts, nfy CriuNotify) error { + return c.doSwrk(rpc.CriuReqType_DUMP, &opts, nfy) +} + +func (c *Criu) Restore(opts rpc.CriuOpts, nfy CriuNotify) error { + return c.doSwrk(rpc.CriuReqType_RESTORE, &opts, nfy) +} + +func (c *Criu) PreDump(opts rpc.CriuOpts, nfy CriuNotify) error { + return c.doSwrk(rpc.CriuReqType_PRE_DUMP, &opts, nfy) +} + +func (c *Criu) StartPageServer(opts rpc.CriuOpts) error { + return c.doSwrk(rpc.CriuReqType_PAGE_SERVER, &opts, nil) +} diff --git a/lib/go/src/criu/notify.go b/lib/go/src/criu/notify.go new file mode 100644 index 000000000..8ce16b7f7 --- /dev/null +++ b/lib/go/src/criu/notify.go @@ -0,0 +1,52 @@ +package criu + +type CriuNotify interface { + PreDump() error + PostDump() error + PreRestore() error + PostRestore(pid int32) error + NetworkLock() error + NetworkUnlock() error + SetupNamespaces(pid int32) error + PostSetupNamespaces() error + PostResume() error +} + +type CriuNoNotify struct { +} + +func (c CriuNoNotify) PreDump() error { + return nil +} + +func (c CriuNoNotify) PostDump() error { + return nil +} + +func (c CriuNoNotify) PreRestore() error { + return nil +} + +func (c CriuNoNotify) PostRestore(pid int32) error { + return nil +} + +func (c CriuNoNotify) NetworkLock() error { + return nil +} + +func (c CriuNoNotify) NetworkUnlock() error { + return nil +} + +func (c CriuNoNotify) SetupNamespaces(pid int32) error { + return nil +} + +func (c CriuNoNotify) PostSetupNamespaces() error { + return nil +} + +func (c CriuNoNotify) PostResume() error { + return nil +} diff --git a/lib/go/src/test/main.go b/lib/go/src/test/main.go new file mode 100644 index 000000000..ae38befdf --- /dev/null +++ b/lib/go/src/test/main.go @@ -0,0 +1,114 @@ +package main + +import ( + "criu" + "fmt" + "github.com/golang/protobuf/proto" + "os" + "rpc" + "strconv" +) + +type TestNfy struct { + criu.CriuNoNotify +} + +func (c TestNfy) PreDump() error { + fmt.Printf("TEST PRE DUMP\n") + return nil +} + +func doDump(c *criu.Criu, pid_s string, img_dir string, pre bool, prev_img string) error { + fmt.Printf("Dumping\n") + pid, _ := strconv.Atoi(pid_s) + img, err := os.Open(img_dir) + if err != nil { + return fmt.Errorf("can't open image dir (%s)", err) + } + defer img.Close() + + opts := rpc.CriuOpts{ + Pid: proto.Int32(int32(pid)), + ImagesDirFd: proto.Int32(int32(img.Fd())), + LogLevel: proto.Int32(4), + LogFile: proto.String("dump.log"), + } + + if prev_img != "" { + opts.ParentImg = proto.String(prev_img) + opts.TrackMem = proto.Bool(true) + } + + if pre { + err = c.PreDump(opts, TestNfy{}) + } else { + err = c.Dump(opts, TestNfy{}) + } + if err != nil { + return fmt.Errorf("dump fail (%s)", err) + } + + return nil +} + +// Usage: test $act $pid $images_dir +func main() { + c := criu.MakeCriu() + act := os.Args[1] + switch act { + case "dump": + err := doDump(c, os.Args[2], os.Args[3], false, "") + if err != nil { + fmt.Print(err) + os.Exit(1) + } + case "dump2": + err := c.Prepare() + if err != nil { + fmt.Print(err) + os.Exit(1) + } + + err = doDump(c, os.Args[2], os.Args[3]+"/pre", true, "") + if err != nil { + fmt.Printf("pre-dump failed") + fmt.Print(err) + os.Exit(1) + } + err = doDump(c, os.Args[2], os.Args[3], false, "./pre") + if err != nil { + fmt.Printf("dump failed") + fmt.Print(err) + os.Exit(1) + } + + c.Cleanup() + case "restore": + fmt.Printf("Restoring\n") + img, err := os.Open(os.Args[2]) + if err != nil { + fmt.Printf("can't open image dir") + os.Exit(1) + } + defer img.Close() + + opts := rpc.CriuOpts{ + ImagesDirFd: proto.Int32(int32(img.Fd())), + LogLevel: proto.Int32(4), + LogFile: proto.String("restore.log"), + } + + err = c.Restore(opts, nil) + if err != nil { + fmt.Printf("Error:") + fmt.Print(err) + fmt.Printf("\n") + os.Exit(1) + } + default: + fmt.Printf("unknown action\n") + os.Exit(1) + } + + fmt.Printf("Success\n") +} From d3ecc80ea05cd7598d5a4f603d8dd6a6e055ff4b Mon Sep 17 00:00:00 2001 From: Rodrigo Bruno Date: Sat, 11 Feb 2017 04:34:39 +0100 Subject: [PATCH 1590/4375] img: Introduce O_FORCE_LOCAL flag for images criu/image-desc.c | 4 ++-- criu/image.c | 4 ++-- criu/include/image.h | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) In order to prepare for remote snapshots (possible with Image Proxy and Image Cache) the O_FORCE_LOCAL flag is added to force some images not to be remote and stay as local files in the file system. Signed-off-by: Rodrigo Bruno Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/image-desc.c | 4 ++-- criu/image.c | 4 ++-- criu/include/image.h | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/criu/image-desc.c b/criu/image-desc.c index b96eb3e5f..053e7af21 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -104,13 +104,13 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { [CR_FD_STATS] = { .fmt = "stats-%s", .magic = STATS_MAGIC, - .oflags = O_SERVICE, + .oflags = O_SERVICE | O_FORCE_LOCAL, }, [CR_FD_IRMAP_CACHE] = { .fmt = "irmap-cache", .magic = IRMAP_CACHE_MAGIC, - .oflags = O_SERVICE, + .oflags = O_SERVICE | O_FORCE_LOCAL, }, [CR_FD_FILE_LOCKS_PID] = { diff --git a/criu/image.c b/criu/image.c index 60112398c..16ac0e35f 100644 --- a/criu/image.c +++ b/criu/image.c @@ -371,11 +371,11 @@ static int do_open_image(struct cr_img *img, int dfd, int type, unsigned long of { int ret, flags; - flags = oflags & ~(O_NOBUF | O_SERVICE); + flags = oflags & ~(O_NOBUF | O_SERVICE | O_FORCE_LOCAL); ret = openat(dfd, path, flags, CR_FD_PERM); if (ret < 0) { - if (!(flags & O_CREAT) && (errno == ENOENT)) { + if (!(flags & O_CREAT) && (errno == ENOENT || ret == -ENOENT)) { pr_info("No %s image\n", path); img->_x.fd = EMPTY_IMG_FD; goto skip_magic; diff --git a/criu/include/image.h b/criu/include/image.h index bff3e7afb..d576f5a13 100644 --- a/criu/include/image.h +++ b/criu/include/image.h @@ -103,6 +103,7 @@ extern bool img_common_magic; #define O_DUMP (O_WRONLY | O_CREAT | O_TRUNC) #define O_SHOW (O_RDONLY | O_NOBUF) #define O_RSTR (O_RDONLY) +#define O_FORCE_LOCAL (O_SYNC) struct cr_img { union { From 98415541a09441162c76aac77254cd4741a8fdf9 Mon Sep 17 00:00:00 2001 From: Veronika Kabatova Date: Tue, 20 Jun 2017 15:14:10 +0200 Subject: [PATCH 1591/4375] Add support for configuration files Implementation changes for usage of simple configuration files. Before parsing the command line options, either default configuration files (/etc/criu/default.conf, $HOME/.criu/default.conf; in this order) are parsed, or a specific config file passed by the user. Two new options are introduced: "--config FILEPATH" option allows users to specify a single configuration file they want to use; and "--no-default-config" option to forbid the parsing of default configuration files. Both options are to be passed only via the command line. Usage of configuration files is not mandatory to keep backwards compatibility. The implementation of this feature tries to be compatible with command line usage -- the user should get the same results whether he passes the options (in the right order of parsing) on command line or writes them in config files. This allows the user to: 1) Override boolean options if needed 2) Specify partial configuration for options that are possible to pass several times (e.g. "--external"), and pass the rest of the options based on process runtime by command line Configuration file syntax allows comments marked with '#' sign, the rest of the line after '#' is ignored. The user can use one option per line (with argument supplied on the same line if needed, divided with whitespace characters), the options are the same as long options (without the "--" prefix used on command line). Configuration file example (syntax purposes only, doesn't make sense): $ cat ~/.criu/default.conf tcp-established work-dir /home//criu/work_directory extra # inline comment no-restore-sibling tree 111111 Signed-off-by: Veronika Kabatova Signed-off-by: Andrei Vagin --- criu/Makefile | 7 ++ criu/crtools.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 226 insertions(+), 8 deletions(-) diff --git a/criu/Makefile b/criu/Makefile index b3b09ce7a..bcfb71622 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -12,6 +12,12 @@ ifeq ($(filter clean mrproper,$(MAKECMDGOALS)),) COMPEL_LIBS := $(shell $(COMPEL_BIN) --static libs) endif +# +# Configuration file paths +CONFIG-DEFINES += -DGLOBAL_CONFIG_DIR='"/etc/criu/"' +CONFIG-DEFINES += -DDEFAULT_CONFIG_FILENAME='"default.conf"' +CONFIG-DEFINES += -DUSER_CONFIG_DIR='".criu/"' + # # General flags. ccflags-y += -fno-strict-aliasing @@ -22,6 +28,7 @@ ccflags-y += -iquote $(ARCH_DIR)/include ccflags-y += -iquote . ccflags-y += -I/usr/include/libnl3 ccflags-y += $(COMPEL_UAPI_INCLUDES) +ccflags-y += $(CONFIG-DEFINES) export ccflags-y diff --git a/criu/crtools.c b/criu/crtools.c index 650c7679a..825823aa6 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -58,6 +58,8 @@ #include "sysctl.h" struct cr_options opts; +char **global_conf = NULL; +char **user_conf = NULL; void init_opts(void) { @@ -230,21 +232,198 @@ static void rlimit_unlimit_nofile_self(void) pr_debug("rlimit: RLIMIT_NOFILE unlimited for self\n"); } +#define HELP_PASSED 1 +#define DEFAULT_CONFIGS_FORBIDDEN 2 +int passed_help_or_defaults_forbidden(int argc, char *argv[]) +{ + /* + * Check for --help / -h on commandline before parsing, otherwise + * the help message won't be displayed if there is an error in + * configuration file syntax. Checks are kept in parser in case of + * option being put in the configuration file itself. + * + * Check also whether default configfiles are forbidden to lower + * number of argv iterations, but checks for help have higher priority. + */ + int i, ret = 0; + for (i = 0; i < argc; i++) { + if ((!strcmp(argv[i], "--help")) || (!strcmp(argv[i], "-h"))) + return HELP_PASSED; + if (!strcmp(argv[i], "--no-default-config")) + ret = DEFAULT_CONFIGS_FORBIDDEN; + } + return ret; +} + +char * specific_config_passed(char *args[], int argc) +{ + int i; + for (i = 0; i < argc; i++) { + if (!strcmp(args[i], "--config")) { + /* getopt takes next string as required argument automatically */ + return args[i + 1]; + } else if (strstr(args[i], "--config=") != NULL) { + return args[i] + strlen("--config="); + } + } + return NULL; +} + +static int count_elements(char **to_count) +{ + int count = 0; + if (to_count != NULL) + while (to_count[count] != NULL) + count++; + return count; +} + +char ** parse_config(char *filepath) +{ +#define DEFAULT_CONFIG_SIZE 10 + FILE* configfile = fopen(filepath, "r"); + int config_size = DEFAULT_CONFIG_SIZE; + int i = 1, len = 0, offset; + size_t limit = 0; + bool was_newline; + char *tmp_string, *line = NULL, *quoted, *quotedptr; + char **configuration, **tmp_conf; + + if (!configfile) { + return NULL; + } + configuration = xmalloc(config_size * sizeof(char *)); + if (configuration == NULL) { + fclose(configfile); + exit(1); + } + /* + * Initialize first element, getopt ignores it. + */ + configuration[0] = "criu"; + + while ((len = getline(&line, &limit, configfile)) != -1) { + offset = 0; + was_newline = true; + if (i >= config_size - 1) { + config_size *= 2; + tmp_conf = xrealloc(configuration, config_size * sizeof(char *)); + if (tmp_conf == NULL) { + fclose(configfile); + exit(1); + } + configuration = tmp_conf; + } + while (sscanf(line + offset, "%m[^ \t\n]s", &configuration[i]) == 1) { + if (configuration[i][0] == '#') { + if (sscanf(line, "%*[^\n]") != 0) { + pr_err("Error while reading configuration file %s\n", filepath); + fclose(configfile); + exit(1); + } + configuration[i] = NULL; + break; + } + if ((configuration[i][0] == '\"') && (strchr(line + offset + 1, '"'))) { + /* + * Handle empty strings which strtok ignores + */ + if (!strcmp(configuration[i], "\"\"")) { + configuration[i] = ""; + offset += strlen("\"\""); + } else if ((configuration[i] = strtok_r(line + offset, "\"", "edptr))) { + /* + * Handle escaping of quotes in quoted string + */ + while (configuration[i][strlen(configuration[i]) - 1] == '\\') { + offset++; + len = strlen(configuration[i]); + configuration[i][len - 1] = '"'; + if (*quotedptr == '"') { + quotedptr++; + break; + } + quoted = strtok_r(NULL, "\"", "edptr); + tmp_string = xmalloc(len + strlen(quoted) + 1); + if (tmp_string == NULL) { + fclose(configfile); + exit(1); + } + memmove(tmp_string, configuration[i], len); + memmove(tmp_string + len, quoted, strlen(quoted) + 1); + configuration[i] = tmp_string; + } + offset += 2; + } + } + offset += strlen(configuration[i]); + if (was_newline) { + was_newline = false; + len = strlen(configuration[i]); + tmp_string = xrealloc(configuration[i], len + strlen("--") + 1); + if (tmp_string == NULL) { + fclose(configfile); + exit(1); + } + memmove(tmp_string + strlen("--"), tmp_string, len + 1); + memmove(tmp_string, "--", strlen("--")); + configuration[i] = tmp_string; + } + i++; + while ((isspace(*(line + offset)) && (*(line + offset) != '\n'))) offset++; + } + line = NULL; + } + + fclose(configfile); + return configuration; +} + +static void init_configuration(int argc, char *argv[], int defaults_forbidden) +{ + char *specific_conf = specific_config_passed(argv, argc); + char local_filepath[PATH_MAX + 1]; + char *home_dir = getenv("HOME"); + + if ((specific_conf == NULL) && (!defaults_forbidden)) { + global_conf = parse_config(GLOBAL_CONFIG_DIR DEFAULT_CONFIG_FILENAME); + if (!home_dir) { + pr_info("Unable to get $HOME directory, local configuration file will not be used."); + } else { + snprintf(local_filepath, PATH_MAX, "%s/%s%s", + home_dir, USER_CONFIG_DIR, DEFAULT_CONFIG_FILENAME); + user_conf = parse_config(local_filepath); + } + } else if (specific_conf != NULL) { + global_conf = parse_config(specific_conf); + if (global_conf == NULL) { + pr_err("Can't access configuration file %s.\n", specific_conf); + exit(1); + } + } +} + int main(int argc, char *argv[], char *envp[]) { - -#define BOOL_OPT(OPT_NAME, SAVE_TO) \ - {OPT_NAME, no_argument, SAVE_TO, true},\ - {"no-" OPT_NAME, no_argument, SAVE_TO, false} +#define PARSING_GLOBAL_CONF 1 +#define PARSING_USER_CONF 2 +#define PARSING_ARGV 3 pid_t pid = 0, tree_id = 0; int ret = -1; bool usage_error = true; bool has_exec_cmd = false; bool has_sub_command; - int opt, idx; + int opt = 0, idx, help_or_configs; + int first_count = 1, second_count = 1; + int state = PARSING_GLOBAL_CONF; int log_level = DEFAULT_LOGLEVEL; char *imgs_dir = "."; + +#define BOOL_OPT(OPT_NAME, SAVE_TO) \ + {OPT_NAME, no_argument, SAVE_TO, true},\ + {"no-" OPT_NAME, no_argument, SAVE_TO, false} + static const char short_opts[] = "dSsRf:F:t:p:hcD:o:v::x::Vr:jJ:lW:L:M:"; static struct option long_opts[] = { { "tree", required_argument, 0, 't' }, @@ -317,6 +496,8 @@ int main(int argc, char *argv[], char *envp[]) BOOL_OPT(SK_CLOSE_PARAM, &opts.tcp_close), { "verbosity", optional_argument, 0, 'v' }, { "ps-socket", required_argument, 0, 1091}, + { "config", required_argument, 0, 1089}, + { "no-default-config", no_argument, 0, 1090}, { }, }; @@ -376,11 +557,38 @@ int main(int argc, char *argv[], char *envp[]) return cr_service_work(atoi(argv[2])); } + help_or_configs = passed_help_or_defaults_forbidden(argc, argv); + if (help_or_configs == 1) { + usage_error = false; + goto usage; + } + init_configuration(argc, argv, (help_or_configs == DEFAULT_CONFIGS_FORBIDDEN)); + if (global_conf != NULL) first_count = count_elements(global_conf); + if (user_conf != NULL) second_count = count_elements(user_conf); + while (1) { idx = -1; - opt = getopt_long(argc, argv, short_opts, long_opts, &idx); - if (opt == -1) + + switch (state) { + case PARSING_GLOBAL_CONF: + opt = getopt_long(first_count, global_conf, short_opts, long_opts, &idx); break; + case PARSING_USER_CONF: + opt = getopt_long(second_count, user_conf, short_opts, long_opts, &idx); + break; + case PARSING_ARGV: + opt = getopt_long(argc, argv, short_opts, long_opts, &idx); + break; + } + if (opt == -1) { + if (state < PARSING_ARGV) { + state++; + optind = 0; + continue; + } else { + break; + } + } if (!opt) continue; @@ -474,7 +682,6 @@ int main(int argc, char *argv[], char *envp[]) case 1049: if (add_script(optarg)) return 1; - break; case 1051: opts.addr = optarg; @@ -621,6 +828,10 @@ int main(int argc, char *argv[], char *envp[]) return 1; } break; + case 1089: + break; + case 1090: + break; case 1091: opts.ps_socket = atoi(optarg); break; From 5f3853e035d17d902968955c460b4a2d3d1c6647 Mon Sep 17 00:00:00 2001 From: Veronika Kabatova Date: Tue, 20 Jun 2017 15:14:11 +0200 Subject: [PATCH 1592/4375] Add documentation for configuration files Signed-off-by: Veronika Kabatova Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 37 +++++++++++++++++++++++++++++++++++++ criu/crtools.c | 4 ++++ 2 files changed, 41 insertions(+) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 09a04d782..609234bca 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -53,6 +53,12 @@ The following levels are available: * *-v4* above plus lots of debug. +*--config* 'file':: + Pass a specific configuration file to criu. + +*--no-default-config*:: + Forbid parsing of default configuration files. + *--pidfile* 'file':: Write root task, service or page-server pid into a 'file'. @@ -601,6 +607,37 @@ Fetches current CPU features (i.e. CPU the *criu* is running on) and test if they are compatible with the ones present in an image file. +CONFIGURATION FILES +------------------- +Criu supports usage of configuration files to avoid the need of writing every +option on command line, which is useful especially with repeated usage of +same options. A specific configuration file can be passed with +"*--config* 'file'" option. If no file is passed, default configuration files +'/etc/criu/default.conf' and '$HOME/.criu/default.conf' are parsed (if +present on the system). Default configuration file parsing can be forbidden +with "*--no-default-config*" if needed. Parsed configuration files are merged +with command line options, which allows overriding boolean options. + +Configuration file syntax +~~~~~~~~~~~~~~~~~~~~~~~~~ +Comments are supported using \'#' sign. The rest of the line is ignored. +Options are the same as command line options without the \'--' prefix, use +one option per line (with corresponding argument if applicable, divided by +whitespaces). If needed, the argument can be provided in double quotes (this +should be needed only if the argument contains whitespaces). In case this type +of argument contains a literal double quote as well, it can be escaped using +the \'\' sign. Usage of commands is disallowed and all other escape sequences +are interpreted literally. + +Example of configuration file to illustrate syntax: +--------------- +$ cat ~/.criu/default.conf +tcp-established +work-dir "/home/USERNAME/criu/my \"work\" directory" +#this is a comment +no-restore-sibling # this is another comment +--------------- + EXAMPLES -------- To checkpoint a program with pid of *1234* and write all image files into diff --git a/criu/crtools.c b/criu/crtools.c index 825823aa6..9d4f337e8 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -1189,6 +1189,10 @@ usage: " --status-fd FD write \\0 to the FD and close it once process is ready\n" " to handle requests\n" "\n" +"Configuration file options:\n" +" --config FILEPATH pass a specific configuration file\n" +" --no-default-config forbid usage of default configuration files\n" +"\n" "Other options:\n" " -h|--help show this text\n" " -V|--version show version\n" From 7c9e7cfc3e8690d350876bda1c8fda9763d395cf Mon Sep 17 00:00:00 2001 From: Veronika Kabatova Date: Tue, 20 Jun 2017 15:14:12 +0200 Subject: [PATCH 1593/4375] Modify and add test for configuration file functionality Creating a test for verifying configuration parsing feature. The test is created by reusing already present inotify_irmap test. Because of addition of default configuration files, --no-default-config option is added to zdtm.py to not break the test suite on systems with these files present. Signed-off-by: Veronika Kabatova Signed-off-by: Andrei Vagin --- test/Makefile | 2 +- test/zdtm.py | 8 +- test/zdtm/static/Makefile | 1 + test/zdtm/static/config_inotify_irmap.c | 91 ++++++++++++++++++++++ test/zdtm/static/config_inotify_irmap.desc | 3 + 5 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 test/zdtm/static/config_inotify_irmap.c create mode 100644 test/zdtm/static/config_inotify_irmap.desc diff --git a/test/Makefile b/test/Makefile index 9938015e0..cf7dacac4 100644 --- a/test/Makefile +++ b/test/Makefile @@ -51,7 +51,7 @@ clean_root: .PHONY: clean_root clean: clean_root - $(RM) zdtm_ct zdtm-tst-list umount2 + $(RM) zdtm_ct zdtm-tst-list umount2 zdtm_test_config.conf $(Q) $(RM) *.log $(Q) $(RM) -r ./dump/ $(Q) $(MAKE) -C zdtm cleandep clean cleanout diff --git a/test/zdtm.py b/test/zdtm.py index b99db2478..4508ebb24 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -738,8 +738,8 @@ class criu_cli: print("Forcing %s fault" % fault) env['CRIU_FAULT'] = fault - cr = subprocess.Popen(strace + [criu_bin, action] + args, env = env, - close_fds = False, preexec_fn = preexec) + cr = subprocess.Popen(strace + [criu_bin, action, "--no-default-config"] + args, + env = env, close_fds = False, preexec_fn = preexec) if nowait: return cr return cr.wait() @@ -1130,8 +1130,8 @@ class criu: @staticmethod def check(feature): - return criu_cli.run("check", ["-v0", "--feature", feature], - opts['criu_bin']) == 0 + return criu_cli.run("check", ["--no-default-config", "-v0", + "--feature", feature], opts['criu_bin']) == 0 @staticmethod def available(): diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index e0ca4d625..28c6a1aa0 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -204,6 +204,7 @@ TST_NOFILE := \ netns_sub \ netns_sub_veth \ unlink_multiple_largefiles \ + config_inotify_irmap \ # jobctl00 \ ifneq ($(SRCARCH),arm) diff --git a/test/zdtm/static/config_inotify_irmap.c b/test/zdtm/static/config_inotify_irmap.c new file mode 100644 index 000000000..831dc1974 --- /dev/null +++ b/test/zdtm/static/config_inotify_irmap.c @@ -0,0 +1,91 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +/* + * This test reuses inotify_irmap test for testing configuration files + * functionality. For parts not related to configuration files, please + * refer to the original test case and it's author. + */ + +const char *test_doc = "Default configuration files usage"; +const char *test_author = "Veronika Kabatova "; + +#define TDIR "/etc" +char test_files[2][128] = {TDIR"/zdtm-test", TDIR"/zdtm-test1",}; +#define CONFIG_PATH "../../zdtm_test_config.conf" + +#define BUFF_SIZE ((sizeof(struct inotify_event) + PATH_MAX)) + +int main (int argc, char *argv[]) +{ + char buf[BUFF_SIZE]; + int fd, wd, i; + + test_init(argc, argv); + + for (i = 0; i < 2; i++) { + unlink(test_files[i]); + if (creat(test_files[i], 0600) < 0) { + pr_perror("Can't make test file"); + exit(1); + } + } + fd = inotify_init1(IN_NONBLOCK); + if (fd < 0) { + pr_perror("inotify_init failed"); + goto err; + } + for (i = 0; i < 2; i++) { + wd = inotify_add_watch(fd, test_files[i], IN_OPEN); + if (wd < 0) { + pr_perror("inotify_add_watch failed"); + goto err; + } + } + + FILE *configfile = fopen(CONFIG_PATH, "w"); + if (configfile == NULL) { + pr_perror("Unable to create configuration file %s", CONFIG_PATH); + goto err; + } + fprintf(configfile, "force-irmap\t\nirmap-scan-path /zdtm/static\n"); + fclose(configfile); + + test_daemon(); + test_waitsig(); + + for (i = 0; i < 2; i++) { + memset(buf, 0, sizeof(buf)); + wd = open(test_files[i], O_RDONLY); + if (read(fd, buf, sizeof(buf)) <= 0) { + fail("No events in queue"); + unlink(CONFIG_PATH); + goto err; + } + } + + close(wd); + close(fd); + for (i = 0; i < 2; i++) + unlink(test_files[i]); + unlink(CONFIG_PATH); + pass(); + return 0; +err: + for (i = 0; i < 2; i++) + unlink(test_files[i]); + return 1; +} diff --git a/test/zdtm/static/config_inotify_irmap.desc b/test/zdtm/static/config_inotify_irmap.desc new file mode 100644 index 000000000..591ae7191 --- /dev/null +++ b/test/zdtm/static/config_inotify_irmap.desc @@ -0,0 +1,3 @@ +(lambda confpath: +{'flags': 'suid', 'opts': '--config %s' % (confpath) +}) (os.path.abspath('./zdtm_test_config.conf')) From 32833597c7dfab4a5b1450c7127719b7eeda897d Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 26 Apr 2018 18:52:17 +0300 Subject: [PATCH 1594/4375] criu: split configuration parsing into separate file Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/Makefile.crtools | 1 + criu/config.c | 204 +++++++++++++++++++++++++++++++++++++++++ criu/crtools.c | 182 +----------------------------------- criu/include/crtools.h | 2 + 4 files changed, 209 insertions(+), 180 deletions(-) create mode 100644 criu/config.c diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 0d28dee3e..b8f24850f 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -83,6 +83,7 @@ obj-y += path.o obj-y += autofs.o obj-y += fdstore.o obj-y += uffd.o +obj-y += config.o ifeq ($(VDSO),y) obj-y += pie-util-vdso.o diff --git a/criu/config.c b/criu/config.c new file mode 100644 index 000000000..10630c661 --- /dev/null +++ b/criu/config.c @@ -0,0 +1,204 @@ +#include +#include +#include +#include +#include + +#include "log.h" +#include "crtools.h" + +#include "common/xmalloc.h" + +extern char **global_conf; +extern char **user_conf; + +#define HELP_PASSED 1 +#define DEFAULT_CONFIGS_FORBIDDEN 2 + +static int passed_help_or_defaults_forbidden(int argc, char *argv[]) +{ + /* + * Check for --help / -h on commandline before parsing, otherwise + * the help message won't be displayed if there is an error in + * configuration file syntax. Checks are kept in parser in case of + * option being put in the configuration file itself. + * + * Check also whether default configfiles are forbidden to lower + * number of argv iterations, but checks for help have higher priority. + */ + int i, ret = 0; + for (i = 0; i < argc; i++) { + if ((!strcmp(argv[i], "--help")) || (!strcmp(argv[i], "-h"))) + return HELP_PASSED; + if (!strcmp(argv[i], "--no-default-config")) + ret = DEFAULT_CONFIGS_FORBIDDEN; + } + return ret; +} + +static char * specific_config_passed(char *args[], int argc) +{ + int i; + for (i = 0; i < argc; i++) { + if (!strcmp(args[i], "--config")) { + /* getopt takes next string as required argument automatically */ + return args[i + 1]; + } else if (strstr(args[i], "--config=") != NULL) { + return args[i] + strlen("--config="); + } + } + return NULL; +} + +static int count_elements(char **to_count) +{ + int count = 0; + if (to_count != NULL) + while (to_count[count] != NULL) + count++; + return count; +} + +static char ** parse_config(char *filepath) +{ +#define DEFAULT_CONFIG_SIZE 10 + FILE* configfile = fopen(filepath, "r"); + int config_size = DEFAULT_CONFIG_SIZE; + int i = 1, len = 0, offset; + size_t limit = 0; + bool was_newline; + char *tmp_string, *line = NULL, *quoted, *quotedptr; + char **configuration, **tmp_conf; + + if (!configfile) { + return NULL; + } + configuration = xmalloc(config_size * sizeof(char *)); + if (configuration == NULL) { + fclose(configfile); + exit(1); + } + /* + * Initialize first element, getopt ignores it. + */ + configuration[0] = "criu"; + + while ((len = getline(&line, &limit, configfile)) != -1) { + offset = 0; + was_newline = true; + if (i >= config_size - 1) { + config_size *= 2; + tmp_conf = xrealloc(configuration, config_size * sizeof(char *)); + if (tmp_conf == NULL) { + fclose(configfile); + exit(1); + } + configuration = tmp_conf; + } + while (sscanf(line + offset, "%m[^ \t\n]s", &configuration[i]) == 1) { + if (configuration[i][0] == '#') { + if (sscanf(line, "%*[^\n]") != 0) { + pr_err("Error while reading configuration file %s\n", filepath); + fclose(configfile); + exit(1); + } + configuration[i] = NULL; + break; + } + if ((configuration[i][0] == '\"') && (strchr(line + offset + 1, '"'))) { + /* + * Handle empty strings which strtok ignores + */ + if (!strcmp(configuration[i], "\"\"")) { + configuration[i] = ""; + offset += strlen("\"\""); + } else if ((configuration[i] = strtok_r(line + offset, "\"", "edptr))) { + /* + * Handle escaping of quotes in quoted string + */ + while (configuration[i][strlen(configuration[i]) - 1] == '\\') { + offset++; + len = strlen(configuration[i]); + configuration[i][len - 1] = '"'; + if (*quotedptr == '"') { + quotedptr++; + break; + } + quoted = strtok_r(NULL, "\"", "edptr); + tmp_string = xmalloc(len + strlen(quoted) + 1); + if (tmp_string == NULL) { + fclose(configfile); + exit(1); + } + memmove(tmp_string, configuration[i], len); + memmove(tmp_string + len, quoted, strlen(quoted) + 1); + configuration[i] = tmp_string; + } + offset += 2; + } + } + offset += strlen(configuration[i]); + if (was_newline) { + was_newline = false; + len = strlen(configuration[i]); + tmp_string = xrealloc(configuration[i], len + strlen("--") + 1); + if (tmp_string == NULL) { + fclose(configfile); + exit(1); + } + memmove(tmp_string + strlen("--"), tmp_string, len + 1); + memmove(tmp_string, "--", strlen("--")); + configuration[i] = tmp_string; + } + i++; + while ((isspace(*(line + offset)) && (*(line + offset) != '\n'))) offset++; + } + line = NULL; + } + + fclose(configfile); + return configuration; +} + +static void init_configuration(int argc, char *argv[], int defaults_forbidden) +{ + char *specific_conf = specific_config_passed(argv, argc); + char local_filepath[PATH_MAX + 1]; + char *home_dir = getenv("HOME"); + + if ((specific_conf == NULL) && (!defaults_forbidden)) { + global_conf = parse_config(GLOBAL_CONFIG_DIR DEFAULT_CONFIG_FILENAME); + if (!home_dir) { + pr_info("Unable to get $HOME directory, local configuration file will not be used."); + } else { + snprintf(local_filepath, PATH_MAX, "%s/%s%s", + home_dir, USER_CONFIG_DIR, DEFAULT_CONFIG_FILENAME); + user_conf = parse_config(local_filepath); + } + } else if (specific_conf != NULL) { + global_conf = parse_config(specific_conf); + if (global_conf == NULL) { + pr_err("Can't access configuration file %s.\n", specific_conf); + exit(1); + } + } +} + +void init_config(int argc, char **argv, int *first_count, int *second_count) +{ + int help_or_configs; + bool usage_error; + + help_or_configs = passed_help_or_defaults_forbidden(argc, argv); + if (help_or_configs == 1) { + usage_error = false; + printf("goto usage: %d\n", usage_error); + return; + } + + init_configuration(argc, argv, (help_or_configs == DEFAULT_CONFIGS_FORBIDDEN)); + if (global_conf != NULL) + *first_count = count_elements(global_conf); + if (user_conf != NULL) + *second_count = count_elements(user_conf); +} diff --git a/criu/crtools.c b/criu/crtools.c index 9d4f337e8..5c6f7d850 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -232,177 +232,6 @@ static void rlimit_unlimit_nofile_self(void) pr_debug("rlimit: RLIMIT_NOFILE unlimited for self\n"); } -#define HELP_PASSED 1 -#define DEFAULT_CONFIGS_FORBIDDEN 2 -int passed_help_or_defaults_forbidden(int argc, char *argv[]) -{ - /* - * Check for --help / -h on commandline before parsing, otherwise - * the help message won't be displayed if there is an error in - * configuration file syntax. Checks are kept in parser in case of - * option being put in the configuration file itself. - * - * Check also whether default configfiles are forbidden to lower - * number of argv iterations, but checks for help have higher priority. - */ - int i, ret = 0; - for (i = 0; i < argc; i++) { - if ((!strcmp(argv[i], "--help")) || (!strcmp(argv[i], "-h"))) - return HELP_PASSED; - if (!strcmp(argv[i], "--no-default-config")) - ret = DEFAULT_CONFIGS_FORBIDDEN; - } - return ret; -} - -char * specific_config_passed(char *args[], int argc) -{ - int i; - for (i = 0; i < argc; i++) { - if (!strcmp(args[i], "--config")) { - /* getopt takes next string as required argument automatically */ - return args[i + 1]; - } else if (strstr(args[i], "--config=") != NULL) { - return args[i] + strlen("--config="); - } - } - return NULL; -} - -static int count_elements(char **to_count) -{ - int count = 0; - if (to_count != NULL) - while (to_count[count] != NULL) - count++; - return count; -} - -char ** parse_config(char *filepath) -{ -#define DEFAULT_CONFIG_SIZE 10 - FILE* configfile = fopen(filepath, "r"); - int config_size = DEFAULT_CONFIG_SIZE; - int i = 1, len = 0, offset; - size_t limit = 0; - bool was_newline; - char *tmp_string, *line = NULL, *quoted, *quotedptr; - char **configuration, **tmp_conf; - - if (!configfile) { - return NULL; - } - configuration = xmalloc(config_size * sizeof(char *)); - if (configuration == NULL) { - fclose(configfile); - exit(1); - } - /* - * Initialize first element, getopt ignores it. - */ - configuration[0] = "criu"; - - while ((len = getline(&line, &limit, configfile)) != -1) { - offset = 0; - was_newline = true; - if (i >= config_size - 1) { - config_size *= 2; - tmp_conf = xrealloc(configuration, config_size * sizeof(char *)); - if (tmp_conf == NULL) { - fclose(configfile); - exit(1); - } - configuration = tmp_conf; - } - while (sscanf(line + offset, "%m[^ \t\n]s", &configuration[i]) == 1) { - if (configuration[i][0] == '#') { - if (sscanf(line, "%*[^\n]") != 0) { - pr_err("Error while reading configuration file %s\n", filepath); - fclose(configfile); - exit(1); - } - configuration[i] = NULL; - break; - } - if ((configuration[i][0] == '\"') && (strchr(line + offset + 1, '"'))) { - /* - * Handle empty strings which strtok ignores - */ - if (!strcmp(configuration[i], "\"\"")) { - configuration[i] = ""; - offset += strlen("\"\""); - } else if ((configuration[i] = strtok_r(line + offset, "\"", "edptr))) { - /* - * Handle escaping of quotes in quoted string - */ - while (configuration[i][strlen(configuration[i]) - 1] == '\\') { - offset++; - len = strlen(configuration[i]); - configuration[i][len - 1] = '"'; - if (*quotedptr == '"') { - quotedptr++; - break; - } - quoted = strtok_r(NULL, "\"", "edptr); - tmp_string = xmalloc(len + strlen(quoted) + 1); - if (tmp_string == NULL) { - fclose(configfile); - exit(1); - } - memmove(tmp_string, configuration[i], len); - memmove(tmp_string + len, quoted, strlen(quoted) + 1); - configuration[i] = tmp_string; - } - offset += 2; - } - } - offset += strlen(configuration[i]); - if (was_newline) { - was_newline = false; - len = strlen(configuration[i]); - tmp_string = xrealloc(configuration[i], len + strlen("--") + 1); - if (tmp_string == NULL) { - fclose(configfile); - exit(1); - } - memmove(tmp_string + strlen("--"), tmp_string, len + 1); - memmove(tmp_string, "--", strlen("--")); - configuration[i] = tmp_string; - } - i++; - while ((isspace(*(line + offset)) && (*(line + offset) != '\n'))) offset++; - } - line = NULL; - } - - fclose(configfile); - return configuration; -} - -static void init_configuration(int argc, char *argv[], int defaults_forbidden) -{ - char *specific_conf = specific_config_passed(argv, argc); - char local_filepath[PATH_MAX + 1]; - char *home_dir = getenv("HOME"); - - if ((specific_conf == NULL) && (!defaults_forbidden)) { - global_conf = parse_config(GLOBAL_CONFIG_DIR DEFAULT_CONFIG_FILENAME); - if (!home_dir) { - pr_info("Unable to get $HOME directory, local configuration file will not be used."); - } else { - snprintf(local_filepath, PATH_MAX, "%s/%s%s", - home_dir, USER_CONFIG_DIR, DEFAULT_CONFIG_FILENAME); - user_conf = parse_config(local_filepath); - } - } else if (specific_conf != NULL) { - global_conf = parse_config(specific_conf); - if (global_conf == NULL) { - pr_err("Can't access configuration file %s.\n", specific_conf); - exit(1); - } - } -} - int main(int argc, char *argv[], char *envp[]) { #define PARSING_GLOBAL_CONF 1 @@ -414,7 +243,7 @@ int main(int argc, char *argv[], char *envp[]) bool usage_error = true; bool has_exec_cmd = false; bool has_sub_command; - int opt = 0, idx, help_or_configs; + int opt = 0, idx; int first_count = 1, second_count = 1; int state = PARSING_GLOBAL_CONF; int log_level = DEFAULT_LOGLEVEL; @@ -557,14 +386,7 @@ int main(int argc, char *argv[], char *envp[]) return cr_service_work(atoi(argv[2])); } - help_or_configs = passed_help_or_defaults_forbidden(argc, argv); - if (help_or_configs == 1) { - usage_error = false; - goto usage; - } - init_configuration(argc, argv, (help_or_configs == DEFAULT_CONFIGS_FORBIDDEN)); - if (global_conf != NULL) first_count = count_elements(global_conf); - if (user_conf != NULL) second_count = count_elements(user_conf); + init_config(argc, argv, &first_count, &second_count); while (1) { idx = -1; diff --git a/criu/include/crtools.h b/criu/include/crtools.h index 7b2dc4523..75038f8e9 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -32,6 +32,8 @@ extern int cr_lazy_pages(bool daemon); extern int check_add_feature(char *arg); extern void pr_check_features(const char *offset, const char *sep, int width); +extern void init_config(int argc, char **argv, int *first_cnt, int *second_cnt); + #define PPREP_HEAD_INACTIVE ((struct pprep_head *)-1) #define add_post_prepare_cb_once(phead) do { \ From b65c79194d5fd69eba915fb6a1c0b941f230768a Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 26 Apr 2018 18:52:18 +0300 Subject: [PATCH 1595/4375] criu: fix 'criu --version' Currently kerndat_init() runs before command line parsing and running simple 'criu --version' command may produce something like: Warn (criu/kerndat.c:847): Can't load /run/criu.kdat Error (criu/util.c:842): exited, status=3 Error (criu/util.c:842): exited, status=3 Write 4294967295 to /proc/self/loginuid failed: Operation not permittedWarn (criu/net.c:2732): Unable to get socket network namespace Warn (criu/net.c:2732): Unable to get tun network namespace Warn (criu/sk-unix.c:213): sk unix: Unable to open a socket file: Operation not permitted Error (criu/net.c:3023): Unable create a network namespace: Operation not permitted Warn (criu/net.c:3069): NSID isn't reported for network links Version: 3.6 GitID: v3.6-611-g0b27d0a Group early calls to kerndat_* and init_service_fd calls into a function and call this function after the command line parsing is finished. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/crtools.c | 60 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index 5c6f7d850..aaac84531 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -232,6 +232,35 @@ static void rlimit_unlimit_nofile_self(void) pr_debug("rlimit: RLIMIT_NOFILE unlimited for self\n"); } +static int early_init(void) +{ + /* + * Service fd engine implies that file descritprs + * used won't be borrowed by the rest of the code + * and default 1024 limit is not enough for high + * loaded test/containers. Thus use kdat engine + * to fetch current system level limit for numbers + * of files allowed to open up and lift up own + * limits. + * + * Note we have to do it before the service fd + * get inited and we dont exit with errors here + * because in worst scenario where clash of fd + * happen we simply exit with explicit error + * during real action stage. + */ + if (!kerndat_files_stat(true)) + rlimit_unlimit_nofile_self(); + + if (init_service_fd()) + return 1; + + if (kerndat_init()) + return 1; + + return 0; +} + int main(int argc, char *argv[], char *envp[]) { #define PARSING_GLOBAL_CONF 1 @@ -349,33 +378,13 @@ int main(int argc, char *argv[], char *envp[]) init_opts(); - /* - * Service fd engine implies that file descritprs - * used won't be borrowed by the rest of the code - * and default 1024 limit is not enough for high - * loaded test/containers. Thus use kdat engine - * to fetch current system level limit for numbers - * of files allowed to open up and lift up own - * limits. - * - * Note we have to do it before the service fd - * get inited and we dont exit with errors here - * because in worst scenario where clash of fd - * happen we simply exit with explicit error - * during real action stage. - */ - if (!kerndat_files_stat(true)) - rlimit_unlimit_nofile_self(); - - if (init_service_fd()) - return 1; - - if (kerndat_init()) - return 1; - if (!strcmp(argv[1], "swrk")) { if (argc < 3) goto usage; + + if (early_init()) + return -1; + /* * This is to start criu service worker from libcriu calls. * The usage is "criu swrk " and is not for CLI/scripts. @@ -670,6 +679,9 @@ int main(int argc, char *argv[], char *envp[]) } } + if (early_init()) + return -1; + if (opts.deprecated_ok) pr_msg("Turn deprecated stuff ON\n"); if (opts.tcp_skip_in_flight) From 0322077dbb777a28e7f43b3e47d08d922568f23d Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 9 May 2018 17:17:50 +0300 Subject: [PATCH 1596/4375] criu/config: rename variables counting options in config files s/first_count/global_cfg_argc s/second_count/user_cfg_argc Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/config.c | 6 +++--- criu/crtools.c | 8 ++++---- criu/include/crtools.h | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/criu/config.c b/criu/config.c index 10630c661..5ff433cb5 100644 --- a/criu/config.c +++ b/criu/config.c @@ -184,7 +184,7 @@ static void init_configuration(int argc, char *argv[], int defaults_forbidden) } } -void init_config(int argc, char **argv, int *first_count, int *second_count) +void init_config(int argc, char **argv, int *global_cfg_argc, int *user_cfg_argc) { int help_or_configs; bool usage_error; @@ -198,7 +198,7 @@ void init_config(int argc, char **argv, int *first_count, int *second_count) init_configuration(argc, argv, (help_or_configs == DEFAULT_CONFIGS_FORBIDDEN)); if (global_conf != NULL) - *first_count = count_elements(global_conf); + *global_cfg_argc = count_elements(global_conf); if (user_conf != NULL) - *second_count = count_elements(user_conf); + *user_cfg_argc = count_elements(user_conf); } diff --git a/criu/crtools.c b/criu/crtools.c index aaac84531..58e12e8f8 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -273,7 +273,7 @@ int main(int argc, char *argv[], char *envp[]) bool has_exec_cmd = false; bool has_sub_command; int opt = 0, idx; - int first_count = 1, second_count = 1; + int global_cfg_argc = 0, user_cfg_argc = 0; int state = PARSING_GLOBAL_CONF; int log_level = DEFAULT_LOGLEVEL; char *imgs_dir = "."; @@ -395,17 +395,17 @@ int main(int argc, char *argv[], char *envp[]) return cr_service_work(atoi(argv[2])); } - init_config(argc, argv, &first_count, &second_count); + init_config(argc, argv, &global_cfg_argc, &user_cfg_argc); while (1) { idx = -1; switch (state) { case PARSING_GLOBAL_CONF: - opt = getopt_long(first_count, global_conf, short_opts, long_opts, &idx); + opt = getopt_long(global_cfg_argc, global_conf, short_opts, long_opts, &idx); break; case PARSING_USER_CONF: - opt = getopt_long(second_count, user_conf, short_opts, long_opts, &idx); + opt = getopt_long(user_cfg_argc, user_conf, short_opts, long_opts, &idx); break; case PARSING_ARGV: opt = getopt_long(argc, argv, short_opts, long_opts, &idx); diff --git a/criu/include/crtools.h b/criu/include/crtools.h index 75038f8e9..234894f48 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -32,7 +32,8 @@ extern int cr_lazy_pages(bool daemon); extern int check_add_feature(char *arg); extern void pr_check_features(const char *offset, const char *sep, int width); -extern void init_config(int argc, char **argv, int *first_cnt, int *second_cnt); +extern void init_config(int argc, char **argv, + int *global_cfg_argc, int *user_cfg_argc); #define PPREP_HEAD_INACTIVE ((struct pprep_head *)-1) From 30cbb11190d5cf4a8c78a7bf20c0b7d64813eb8f Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 9 May 2018 17:17:51 +0300 Subject: [PATCH 1597/4375] criu/config: allow init_config properly handle -h/--help When config parsing was split into a separate part the handling of -h/--help option during init_config was broken. Fix it. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/config.c | 11 ++++++----- criu/crtools.c | 5 ++++- criu/include/crtools.h | 5 +++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/criu/config.c b/criu/config.c index 5ff433cb5..bfaa05793 100644 --- a/criu/config.c +++ b/criu/config.c @@ -184,16 +184,15 @@ static void init_configuration(int argc, char *argv[], int defaults_forbidden) } } -void init_config(int argc, char **argv, int *global_cfg_argc, int *user_cfg_argc) +int init_config(int argc, char **argv, int *global_cfg_argc, int *user_cfg_argc, + bool *usage_error) { int help_or_configs; - bool usage_error; help_or_configs = passed_help_or_defaults_forbidden(argc, argv); if (help_or_configs == 1) { - usage_error = false; - printf("goto usage: %d\n", usage_error); - return; + *usage_error = false; + return 1; } init_configuration(argc, argv, (help_or_configs == DEFAULT_CONFIGS_FORBIDDEN)); @@ -201,4 +200,6 @@ void init_config(int argc, char **argv, int *global_cfg_argc, int *user_cfg_argc *global_cfg_argc = count_elements(global_conf); if (user_conf != NULL) *user_cfg_argc = count_elements(user_conf); + + return 0; } diff --git a/criu/crtools.c b/criu/crtools.c index 58e12e8f8..8006b2070 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -395,7 +395,10 @@ int main(int argc, char *argv[], char *envp[]) return cr_service_work(atoi(argv[2])); } - init_config(argc, argv, &global_cfg_argc, &user_cfg_argc); + ret = init_config(argc, argv, &global_cfg_argc, &user_cfg_argc, + &usage_error); + if (ret) + goto usage; while (1) { idx = -1; diff --git a/criu/include/crtools.h b/criu/include/crtools.h index 234894f48..5ffacb697 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -32,8 +32,9 @@ extern int cr_lazy_pages(bool daemon); extern int check_add_feature(char *arg); extern void pr_check_features(const char *offset, const char *sep, int width); -extern void init_config(int argc, char **argv, - int *global_cfg_argc, int *user_cfg_argc); +extern int init_config(int argc, char **argv, + int *global_cfg_argc, int *user_cfg_argc, + bool *usage_error); #define PPREP_HEAD_INACTIVE ((struct pprep_head *)-1) From c1a4545a850f222c97c313b50e4a388c2e2fc383 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 9 May 2018 17:17:52 +0300 Subject: [PATCH 1598/4375] criu/config: reduce the number of argv traversals Instead of pre-parsing command line twice, one time to detect -h/--help and another time to find config file parameter, check for both in one pass. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/config.c | 87 ++++++++++++++++++++++----------------------------- 1 file changed, 37 insertions(+), 50 deletions(-) diff --git a/criu/config.c b/criu/config.c index bfaa05793..3d91ef1c3 100644 --- a/criu/config.c +++ b/criu/config.c @@ -12,44 +12,6 @@ extern char **global_conf; extern char **user_conf; -#define HELP_PASSED 1 -#define DEFAULT_CONFIGS_FORBIDDEN 2 - -static int passed_help_or_defaults_forbidden(int argc, char *argv[]) -{ - /* - * Check for --help / -h on commandline before parsing, otherwise - * the help message won't be displayed if there is an error in - * configuration file syntax. Checks are kept in parser in case of - * option being put in the configuration file itself. - * - * Check also whether default configfiles are forbidden to lower - * number of argv iterations, but checks for help have higher priority. - */ - int i, ret = 0; - for (i = 0; i < argc; i++) { - if ((!strcmp(argv[i], "--help")) || (!strcmp(argv[i], "-h"))) - return HELP_PASSED; - if (!strcmp(argv[i], "--no-default-config")) - ret = DEFAULT_CONFIGS_FORBIDDEN; - } - return ret; -} - -static char * specific_config_passed(char *args[], int argc) -{ - int i; - for (i = 0; i < argc; i++) { - if (!strcmp(args[i], "--config")) { - /* getopt takes next string as required argument automatically */ - return args[i + 1]; - } else if (strstr(args[i], "--config=") != NULL) { - return args[i] + strlen("--config="); - } - } - return NULL; -} - static int count_elements(char **to_count) { int count = 0; @@ -160,13 +122,13 @@ static char ** parse_config(char *filepath) return configuration; } -static void init_configuration(int argc, char *argv[], int defaults_forbidden) +static void init_configuration(int argc, char *argv[], bool no_default_config, + char *cfg_file) { - char *specific_conf = specific_config_passed(argv, argc); char local_filepath[PATH_MAX + 1]; char *home_dir = getenv("HOME"); - if ((specific_conf == NULL) && (!defaults_forbidden)) { + if ((cfg_file == NULL) && (!no_default_config)) { global_conf = parse_config(GLOBAL_CONFIG_DIR DEFAULT_CONFIG_FILENAME); if (!home_dir) { pr_info("Unable to get $HOME directory, local configuration file will not be used."); @@ -175,10 +137,10 @@ static void init_configuration(int argc, char *argv[], int defaults_forbidden) home_dir, USER_CONFIG_DIR, DEFAULT_CONFIG_FILENAME); user_conf = parse_config(local_filepath); } - } else if (specific_conf != NULL) { - global_conf = parse_config(specific_conf); + } else if (cfg_file != NULL) { + global_conf = parse_config(cfg_file); if (global_conf == NULL) { - pr_err("Can't access configuration file %s.\n", specific_conf); + pr_err("Can't access configuration file %s.\n", cfg_file); exit(1); } } @@ -187,15 +149,40 @@ static void init_configuration(int argc, char *argv[], int defaults_forbidden) int init_config(int argc, char **argv, int *global_cfg_argc, int *user_cfg_argc, bool *usage_error) { - int help_or_configs; + bool no_default_config = false; + char *cfg_file = NULL; + int i; - help_or_configs = passed_help_or_defaults_forbidden(argc, argv); - if (help_or_configs == 1) { - *usage_error = false; - return 1; + /* + * We are runnning before getopt(), so we need to pre-parse + * the command line. + * + * Check for --help / -h on commandline before parsing, otherwise + * the help message won't be displayed if there is an error in + * configuration file syntax. Checks are kept in parser in case of + * option being put in the configuration file itself. + * + * Check also whether default configfiles are forbidden to lower + * number of argv iterations, but checks for help have higher priority. + */ + for (i = 0; i < argc; i++) { + if ((!strcmp(argv[i], "--help")) || (!strcmp(argv[i], "-h"))) { + *usage_error = false; + return 1; + } else if (!strcmp(argv[i], "--no-default-config")) { + no_default_config = true; + } else if (!strcmp(argv[i], "--config")) { + /* + * getopt takes next string as required + * argument automatically, we do the same + */ + cfg_file = argv[i + 1]; + } else if (strstr(argv[i], "--config=") != NULL) { + cfg_file = argv[i] + strlen("--config="); + } } - init_configuration(argc, argv, (help_or_configs == DEFAULT_CONFIGS_FORBIDDEN)); + init_configuration(argc, argv, no_default_config, cfg_file); if (global_conf != NULL) *global_cfg_argc = count_elements(global_conf); if (user_conf != NULL) From a21d8f1ca175e6dfa739deab6059143d8dc4fbf0 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 9 May 2018 09:28:27 +0300 Subject: [PATCH 1599/4375] config: skip spaces at a beginning of lines Otherwise lines started with spaces are ignored. Cc: Veronika Kabatova Signed-off-by: Andrei Vagin --- criu/config.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/criu/config.c b/criu/config.c index 3d91ef1c3..e3519ebe5 100644 --- a/criu/config.c +++ b/criu/config.c @@ -57,7 +57,12 @@ static char ** parse_config(char *filepath) } configuration = tmp_conf; } - while (sscanf(line + offset, "%m[^ \t\n]s", &configuration[i]) == 1) { + while (1) { + while ((isspace(*(line + offset)) && (*(line + offset) != '\n'))) offset++; + + if (sscanf(line + offset, "%m[^ \t\n]s", &configuration[i]) != 1) + break; + if (configuration[i][0] == '#') { if (sscanf(line, "%*[^\n]") != 0) { pr_err("Error while reading configuration file %s\n", filepath); @@ -113,7 +118,6 @@ static char ** parse_config(char *filepath) configuration[i] = tmp_string; } i++; - while ((isspace(*(line + offset)) && (*(line + offset) != '\n'))) offset++; } line = NULL; } From ba98bae9022476e4e00eeb81b9454efad1befe0d Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 9 May 2018 09:28:28 +0300 Subject: [PATCH 1600/4375] config: initialize the last element of a config argv as NULL Now we rely on scanf, that it will initializes a pointer to NULL, when it fails to parse a string, but I can't find in a man page, that it has to do this. Signed-off-by: Andrei Vagin --- criu/config.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/criu/config.c b/criu/config.c index e3519ebe5..f3bf35b5f 100644 --- a/criu/config.c +++ b/criu/config.c @@ -60,8 +60,10 @@ static char ** parse_config(char *filepath) while (1) { while ((isspace(*(line + offset)) && (*(line + offset) != '\n'))) offset++; - if (sscanf(line + offset, "%m[^ \t\n]s", &configuration[i]) != 1) + if (sscanf(line + offset, "%m[^ \t\n]s", &configuration[i]) != 1) { + configuration[i] = NULL; break; + } if (configuration[i][0] == '#') { if (sscanf(line, "%*[^\n]") != 0) { From 2280a6eecf67065210432f4c9172f736f0bacb58 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 10 May 2018 06:36:58 +0300 Subject: [PATCH 1601/4375] config: check that there are not unhandled parameters in a config Return an error if we meet unexpected parameters in a config file Cc: Veronika Kabatova Signed-off-by: Andrei Vagin --- criu/crtools.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index 8006b2070..829e5d796 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -401,20 +401,38 @@ int main(int argc, char *argv[], char *envp[]) goto usage; while (1) { + char **_argv = NULL; + int _argc = 0; + idx = -1; switch (state) { case PARSING_GLOBAL_CONF: - opt = getopt_long(global_cfg_argc, global_conf, short_opts, long_opts, &idx); + _argc = global_cfg_argc; + _argv = global_conf; break; case PARSING_USER_CONF: - opt = getopt_long(user_cfg_argc, user_conf, short_opts, long_opts, &idx); + _argc = user_cfg_argc; + _argv = user_conf; break; case PARSING_ARGV: - opt = getopt_long(argc, argv, short_opts, long_opts, &idx); + _argc = argc; + _argv = argv; break; + default: + BUG(); } + opt = getopt_long(_argc, _argv, short_opts, long_opts, &idx); if (opt == -1) { + switch (state) { + case PARSING_GLOBAL_CONF: + case PARSING_USER_CONF: + if (optind < _argc) { + pr_err("Unknown config parameter: %s\n", _argv[optind]); + return -1; + } + break; + } if (state < PARSING_ARGV) { state++; optind = 0; From 03d636afedfd366d3fe9daa8b312fd42b99765fa Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 31 May 2018 09:00:03 +0000 Subject: [PATCH 1602/4375] test/other/rpc: resurrect the RPC test cases In this directory there are various test cases using CRIU in RPC mode (or SWRK mode). This fixes the broken tests by moving the start of 'criu service' from run.sh to the Makefile as the test cases is running using "sudo -g '#1000' -u '#1000'" and the PID file created by CRIU can only be read by the root user. If starting the 'criu service' before run.sh the PID file still can be changed to 0666 and fixing the test script. This also adds version.py to the test cases that are executed. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/others/rpc/Makefile | 4 ++++ test/others/rpc/run.sh | 7 ------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/test/others/rpc/Makefile b/test/others/rpc/Makefile index bf2a2d262..5b383cfb8 100644 --- a/test/others/rpc/Makefile +++ b/test/others/rpc/Makefile @@ -7,7 +7,11 @@ LDLIBS += -lprotobuf-c run: all mkdir -p build chmod a+rwx build + @# need to start the criu daemon here to access the pidfile + sudo -g '#1000' -u '#1000' ./criu service -v4 -W build -o service.log --address criu_service.socket -d --pidfile pidfile + chmod a+rw build/pidfile sudo -g '#1000' -u '#1000' ./run.sh + sudo -g '#1000' -u '#1000' ./version.py criu: ../../../criu/criu cp ../../../criu/criu $@ diff --git a/test/others/rpc/run.sh b/test/others/rpc/run.sh index ed99addb2..aaf48f4ad 100755 --- a/test/others/rpc/run.sh +++ b/test/others/rpc/run.sh @@ -15,11 +15,6 @@ function title_print { } -function start_server { - title_print "Start service server" - ${CRIU} service -v4 -W build -o service.log --address criu_service.socket -d --pidfile pidfile -} - function stop_server { title_print "Shutdown service server" kill -SIGTERM $(cat build/pidfile) @@ -78,8 +73,6 @@ function test_errno { trap 'echo "FAIL"; stop_server' EXIT -start_server - test_c test_py test_restore_loop From 46b35b2c2f92f7760e51ab4674e3f00b9262ea30 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 31 May 2018 09:00:04 +0000 Subject: [PATCH 1603/4375] test/others/rpc: also run RPC version command via service This extends the test.py to also run the RPC command VERSION via 'criu service'. It was already running using 'criu swrk'. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/others/rpc/test.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/others/rpc/test.py b/test/others/rpc/test.py index 601a34fe4..63eef378e 100755 --- a/test/others/rpc/test.py +++ b/test/others/rpc/test.py @@ -42,3 +42,40 @@ else: if resp.dump.restored: print 'Restored' + +# Connect to service socket +s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) +s.connect(args['socket']) + +# Create criu msg, set it's type to dump request +# and set dump options. Checkout more options in protobuf/rpc.proto +req = rpc.criu_req() +req.type = rpc.VERSION + +# Send request +s.send(req.SerializeToString()) + +# Recv response +resp = rpc.criu_resp() +MAX_MSG_SIZE = 1024 +resp.ParseFromString(s.recv(MAX_MSG_SIZE)) + +if resp.type != rpc.VERSION: + print('RPC: Unexpected msg type') + sys.exit(-1) +else: + if resp.success: + print('RPC: Success') + print('CRIU major %d' % resp.version.major) + print('CRIU minor %d' % resp.version.minor) + if resp.version.HasField('gitid'): + print('CRIU gitid %s' % resp.version.gitid) + if resp.version.HasField('sublevel'): + print('CRIU sublevel %s' % resp.version.sublevel) + if resp.version.HasField('extra'): + print('CRIU extra %s' % resp.version.extra) + if resp.version.HasField('name'): + print('CRIU name %s' % resp.version.name) + else: + print 'Fail' + sys.exit(-1) From 6a49d037aa309f53579c5637d9f0d067ea75ff21 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 31 May 2018 09:00:05 +0000 Subject: [PATCH 1604/4375] travis: run test/other/rpc tests Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index c8bd5717e..f46c99ff8 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -112,6 +112,7 @@ fi #make -C test/others/exec/ run make -C test/others/make/ run CC="$CC" make -C test/others/shell-job/ run +make -C test/others/rpc/ run ./test/zdtm.py run -t zdtm/static/env00 --sibling From 2c5b2785edd04397ca9da480938c25d59f1cbcca Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 21 Jun 2018 21:10:38 +0000 Subject: [PATCH 1605/4375] tests: fix builds on alpine and centos Install sudo, create test user with ID 1000, install bash, fix pidfile creation and pidfile chmod. v2: * use sleep to give the criu daemon some time to start up Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.alpine | 7 ++++++- scripts/build/Dockerfile.centos | 1 + test/others/rpc/Makefile | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index c35104c64..aab6184d7 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -4,6 +4,7 @@ ARG ENV1=FOOBAR RUN apk update && apk add \ $CC \ + bash \ build-base \ ccache \ coreutils \ @@ -15,7 +16,8 @@ RUN apk update && apk add \ pkgconfig \ protobuf-c-dev \ protobuf-dev \ - python + python \ + sudo COPY . /criu WORKDIR /criu @@ -36,5 +38,8 @@ RUN apk add \ e2fsprogs \ asciidoc xmlto +# The rpc test cases are running as user #1000, let's add the user +RUN adduser -u 1000 -D test + RUN pip install protobuf ipaddress junit_xml RUN make -C test/zdtm diff --git a/scripts/build/Dockerfile.centos b/scripts/build/Dockerfile.centos index 5f8470773..0160b7594 100644 --- a/scripts/build/Dockerfile.centos +++ b/scripts/build/Dockerfile.centos @@ -27,6 +27,7 @@ RUN yum install -y \ python2-junit_xml \ python-yaml \ python-six \ + sudo \ tar \ which \ e2fsprogs \ diff --git a/test/others/rpc/Makefile b/test/others/rpc/Makefile index 5b383cfb8..2b15873fd 100644 --- a/test/others/rpc/Makefile +++ b/test/others/rpc/Makefile @@ -9,6 +9,8 @@ run: all chmod a+rwx build @# need to start the criu daemon here to access the pidfile sudo -g '#1000' -u '#1000' ./criu service -v4 -W build -o service.log --address criu_service.socket -d --pidfile pidfile + # Give the criu daemon some time to start up + sleep 0.5 chmod a+rw build/pidfile sudo -g '#1000' -u '#1000' ./run.sh sudo -g '#1000' -u '#1000' ./version.py From 7ae8d6e3348abd1374a851ec0b2b5b0cafb626b9 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 28 Jun 2018 12:43:27 +0000 Subject: [PATCH 1606/4375] criu service: support status-fd Make the --status-fd option also work in 'criu service' mode to avoid race conditions during testing. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-service.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/cr-service.c b/criu/cr-service.c index 274ff218b..3a07d5b76 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -1206,6 +1206,9 @@ int cr_service(bool daemon_mode) if (setup_sigchld_handler()) goto err; + if (close_status_fd()) + return -1; + while (1) { int sk; From ae55a6ccd5fc9a1de6894a4d39e96e4b2c7e99b0 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 28 Jun 2018 12:43:28 +0000 Subject: [PATCH 1607/4375] tests: fix builds on alpine and centos Install sudo, create test user with ID 1000, install bash, fix pidfile creation and pidfile chmod. v2: * use sleep to give the criu daemon some time to start up v3: * Andrei is of course right and sleep is not good solution. After adding --status-fd support to criu service, this is how we now detect that criu is ready. v4: * This was much more complicated than expected which is related to the different versions of the tools on the different travis test targets. There seems to be a bug in bash on Ubuntu https://lists.gnu.org/archive/html/bug-bash/2017-07/msg00039.html which prevents using 'read -n1' on Ubuntu. As a workaround the result from CRIU's status FD is now read via python. Another problem was discovered on alpine with the loop restore test. CRIU says to use setsid even if the process is already using setsid. As a workaround, still with setsid, this process is now using shell-job true for checkpoint and restore. Parts of v2 have been committed before. So the changes from this commit are partially already in another commit. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.centos | 4 ++++ test/others/rpc/Makefile | 17 +++++++++++++---- test/others/rpc/read.py | 18 ++++++++++++++++++ test/others/rpc/restore-loop.py | 5 +++++ test/others/rpc/run.sh | 4 +++- 5 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 test/others/rpc/read.py diff --git a/scripts/build/Dockerfile.centos b/scripts/build/Dockerfile.centos index 0160b7594..d8e70ac47 100644 --- a/scripts/build/Dockerfile.centos +++ b/scripts/build/Dockerfile.centos @@ -40,4 +40,8 @@ WORKDIR /criu ENV CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes RUN mv .ccache /tmp && make mrproper && ccache -sz && \ date && make -j $(nproc) CC="$CC" && date && ccache -s + +# The rpc test cases are running as user #1000, let's add the user +RUN adduser -u 1000 test + RUN make -C test/zdtm -j $(nproc) diff --git a/test/others/rpc/Makefile b/test/others/rpc/Makefile index 2b15873fd..50cd063d0 100644 --- a/test/others/rpc/Makefile +++ b/test/others/rpc/Makefile @@ -4,13 +4,22 @@ all: test-c rpc_pb2.py criu CFLAGS += -g -Werror -Wall -I. LDLIBS += -lprotobuf-c +PYTHON ?= python + run: all mkdir -p build chmod a+rwx build - @# need to start the criu daemon here to access the pidfile - sudo -g '#1000' -u '#1000' ./criu service -v4 -W build -o service.log --address criu_service.socket -d --pidfile pidfile - # Give the criu daemon some time to start up - sleep 0.5 + rm -f build/status + sudo -g '#1000' -u '#1000' mkfifo build/status + @# Need to start the criu daemon here to access the pidfile. + @# The script read.py is used to wait until 'criu service' + @# is ready. As 'read -n 1' in some releases has a bug and does + @# not read correctly a \0, using python is a workaround. + sudo -g '#1000' -u '#1000' -- bash -c "exec 200<>build/status; \ + ./criu service -v4 -W build --address criu_service.socket \ + -d --pidfile pidfile -o service.log --status-fd 200; \ + $(PYTHON) read.py build/status" + rm -f build/status chmod a+rw build/pidfile sudo -g '#1000' -u '#1000' ./run.sh sudo -g '#1000' -u '#1000' ./version.py diff --git a/test/others/rpc/read.py b/test/others/rpc/read.py new file mode 100644 index 000000000..680069b76 --- /dev/null +++ b/test/others/rpc/read.py @@ -0,0 +1,18 @@ +# This script is used to read a single character from CRIU's status FD. +# That way we know when the CRIU service is ready. CRIU writes a \0 to +# the status FD. +# In theory this could be easily done using 'read -n 1' from bash, but +# but the bash version on Ubuntu has probably the following bug: +# https://lists.gnu.org/archive/html/bug-bash/2017-07/msg00039.html + +import os +import sys + + +f=open(sys.argv[1]) +r = f.read(1) + +if r == '\0': + sys.exit(0) + +sys.exit(-1) diff --git a/test/others/rpc/restore-loop.py b/test/others/rpc/restore-loop.py index 21e93b96e..1ea9bf320 100755 --- a/test/others/rpc/restore-loop.py +++ b/test/others/rpc/restore-loop.py @@ -19,6 +19,11 @@ s.connect(args['socket']) req = rpc.criu_req() req.type = rpc.RESTORE req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY) +# As the dumped process is running with setsid this should not +# be necessary. There seems to be a problem for this testcase +# in combination with alpine's setsid. +# The dump is now done with -j and the restore also. +req.opts.shell_job = True # Send request s.send(req.SerializeToString()) diff --git a/test/others/rpc/run.sh b/test/others/rpc/run.sh index aaf48f4ad..d1facd82f 100755 --- a/test/others/rpc/run.sh +++ b/test/others/rpc/run.sh @@ -50,7 +50,9 @@ function test_restore_loop { echo "pid ${P}" title_print "Dump loop.sh" - ${CRIU} dump -v4 -o dump-loop.log -D build/imgs_loop -t ${P} + # So theoretically '-j' (--shell-job) should not be necessary, but on alpine + # this test fails without it. + ${CRIU} dump -j -v4 -o dump-loop.log -D build/imgs_loop -t ${P} title_print "Run restore-loop" ./restore-loop.py build/criu_service.socket build/imgs_loop From 4d164327b871ac876069f826393a136693154859 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 11 Jul 2018 00:36:11 +0300 Subject: [PATCH 1608/4375] restore: set uid and git onto zero otherwise PR_SET_MM_EXE_FILE can fail When a non-root user runs "criu restore" and criu has the suid bit, a process will run with non-zero uid and gid. Before the 4.13 kernel (4d28df6152aa "prctl: Allow local CAP_SYS_ADMIN changing exe_file"), PR_SET_MM_EXE_FILE fails if uid or gid isn't zero. Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 39a6d9949..387822226 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1286,7 +1286,11 @@ static void maybe_clone_parent(struct pstree_item *item, static bool needs_prep_creds(struct pstree_item *item) { - return (!item->parent && (root_ns_mask & CLONE_NEWUSER)); + /* + * Before the 4.13 kernel, it was impossible to set + * an exe_file if uid or gid isn't zero. + */ + return (!item->parent && ((root_ns_mask & CLONE_NEWUSER) || getuid())); } static inline int fork_with_pid(struct pstree_item *item) From 33fb955ef4c9198d96caf3d04ce04ce4589610c3 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 21 Oct 2017 00:01:13 +0300 Subject: [PATCH 1609/4375] restore: don't call free_mappings for an uninitialized list vma_area_list@entry=0x818) at criu/cr-dump.c:107 107 list_for_each_entry_safe(vma_area, p, &vma_area_list->h, list) Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 387822226..a788198e4 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3232,7 +3232,8 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns if (current->parent == NULL) { /* Wait when all tasks restored all files */ - restore_wait_other_tasks(); + if (restore_wait_other_tasks()) + goto err_nv; } /* From dc1e3b59ff7da8dd264dc28693a913e313d39fee Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 25 Jul 2017 15:35:47 +0300 Subject: [PATCH 1610/4375] cr-check: Make compat_cr warning arch-independent I think, we should warn a user when we can't C/R compatible applications. That's valid for different than x86 archs. Let's correct the message the way it'll suit non-x86. Reported-by: Adrian Reber Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cr-check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index d36875eb0..0b9e3c37f 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1026,7 +1026,7 @@ static int check_compat_cr(void) return 0; pr_warn("compat_cr is not supported. Requires kernel >= v4.12\n"); #else - pr_warn("CRIU built without CONFIG_COMPAT - can't C/R ia32\n"); + pr_warn("CRIU built without CONFIG_COMPAT - can't C/R compatible tasks\n"); #endif return -1; } From 9a64e0032a468222234723c599841f7a2ccd9e9f Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 16 May 2017 19:26:59 +0300 Subject: [PATCH 1611/4375] forking: Introduce last_pid_mutex and helpers Introduce mutex for synchronization ns_last_pid file on restore. Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 1 + criu/include/rst_info.h | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index a788198e4..c951b3c9f 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2328,6 +2328,7 @@ int prepare_task_entries(void) task_entries->nr_helpers = 0; futex_set(&task_entries->start, CR_STATE_FAIL); mutex_init(&task_entries->userns_sync_lock); + mutex_init(&task_entries->last_pid_mutex); return 0; } diff --git a/criu/include/rst_info.h b/criu/include/rst_info.h index aba05b911..07c634f4a 100644 --- a/criu/include/rst_info.h +++ b/criu/include/rst_info.h @@ -11,6 +11,7 @@ struct task_entries { futex_t start; atomic_t cr_err; mutex_t userns_sync_lock; + mutex_t last_pid_mutex; }; struct fdt { @@ -71,4 +72,16 @@ struct rst_info { void *breakpoint; }; +extern struct task_entries *task_entries; + +static inline void lock_last_pid(void) +{ + mutex_lock(&task_entries->last_pid_mutex); +} + +static inline void unlock_last_pid(void) +{ + mutex_unlock(&task_entries->last_pid_mutex); +} + #endif /* __CR_RST_INFO_H__ */ From 53a11dfc5c45a132459249fd6d37feac25247d98 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 16 May 2017 19:27:07 +0300 Subject: [PATCH 1612/4375] forking: Use last_pid_mutex for synchronization during clone() Before this patch we used flock to order task creation, but this way is not good. It took 5 syscalls to synchronize a creation of a single child: 1)open() 2)flock(LOCK_EX) 3)flock(LOCK_UN) 4)close() in parent 5)close() in child The patch introduces more effective way for synchronization, which executes 2 syscalls only. We use last_pid_mutex, and the syscalls number sounds definitely better. v2: Don't use flock() at all Signed-off-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 28 +++++++++------------------- criu/pie/restorer.c | 21 +++++++-------------- 2 files changed, 16 insertions(+), 33 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index c951b3c9f..ad28bbceb 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1243,7 +1243,6 @@ static int restore_one_task(int pid, CoreEntry *core) struct cr_clone_arg { struct pstree_item *item; unsigned long clone_flags; - int fd; CoreEntry *core; }; @@ -1346,24 +1345,22 @@ static inline int fork_with_pid(struct pstree_item *item) if (!(ca.clone_flags & CLONE_NEWPID)) { char buf[32]; int len; + int fd; - ca.fd = open_proc_rw(PROC_GEN, LAST_PID_PATH); - if (ca.fd < 0) + fd = open_proc_rw(PROC_GEN, LAST_PID_PATH); + if (fd < 0) goto err; - if (flock(ca.fd, LOCK_EX)) { - close(ca.fd); - pr_perror("%d: Can't lock %s", pid, LAST_PID_PATH); - goto err; - } + lock_last_pid(); len = snprintf(buf, sizeof(buf), "%d", pid - 1); - if (write(ca.fd, buf, len) != len) { + if (write(fd, buf, len) != len) { pr_perror("%d: Write %s to %s", pid, buf, LAST_PID_PATH); + close(fd); goto err_unlock; } + close(fd); } else { - ca.fd = -1; BUG_ON(pid != INIT_PID); } @@ -1395,12 +1392,8 @@ static inline int fork_with_pid(struct pstree_item *item) } err_unlock: - if (ca.fd >= 0) { - if (flock(ca.fd, LOCK_UN)) - pr_perror("%d: Can't unlock %s", pid, LAST_PID_PATH); - - close(ca.fd); - } + if (!(ca.clone_flags & CLONE_NEWPID)) + unlock_last_pid(); err: if (ca.core) core_entry__free_unpacked(ca.core, NULL); @@ -1664,9 +1657,6 @@ static int restore_task_with_children(void *_arg) current->pid->real, vpid(current)); } - if ( !(ca->clone_flags & CLONE_FILES)) - close_safe(&ca->fd); - pid = getpid(); if (vpid(current) != pid) { pr_err("Pid %d do not match expected %d\n", pid, vpid(current)); diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 53b14e576..fe52d444d 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1551,20 +1551,16 @@ long __export_restore_task(struct task_restore_args *args) CLONE_THREAD | CLONE_SYSVSEM | CLONE_FS; long last_pid_len; long parent_tid; - int i, fd; + int i, fd = -1; + /* One level pid ns hierarhy */ fd = sys_openat(args->proc_fd, LAST_PID_PATH, O_RDWR, 0); if (fd < 0) { pr_err("can't open last pid fd %d\n", fd); goto core_restore_end; } - ret = sys_flock(fd, LOCK_EX); - if (ret) { - pr_err("Can't lock last_pid %d\n", fd); - sys_close(fd); - goto core_restore_end; - } + mutex_lock(&task_entries_local->last_pid_mutex); for (i = 0; i < args->nr_threads; i++) { char last_pid_buf[16], *s; @@ -1580,6 +1576,7 @@ long __export_restore_task(struct task_restore_args *args) if (ret < 0) { pr_err("Can't set last_pid %ld/%s\n", ret, last_pid_buf); sys_close(fd); + mutex_unlock(&task_entries_local->last_pid_mutex); goto core_restore_end; } @@ -1593,18 +1590,14 @@ long __export_restore_task(struct task_restore_args *args) RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, thread_args, args->clone_restore_fn); if (ret != thread_args[i].pid) { pr_err("Unable to create a thread: %ld\n", ret); + mutex_unlock(&task_entries_local->last_pid_mutex); goto core_restore_end; } } - ret = sys_flock(fd, LOCK_UN); - if (ret) { - pr_err("Can't unlock last_pid %ld\n", ret); + mutex_unlock(&task_entries_local->last_pid_mutex); + if (fd >= 0) sys_close(fd); - goto core_restore_end; - } - - sys_close(fd); } restore_rlims(args); From 26aadb5acbef327441d7cc10b9675fa907ef0664 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 17 Mar 2017 17:55:04 +0300 Subject: [PATCH 1613/4375] images: remap-file-path -- Reserve entries for spfs manager Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- images/remap-file-path.proto | 3 +++ 1 file changed, 3 insertions(+) diff --git a/images/remap-file-path.proto b/images/remap-file-path.proto index 2221800c7..3cc78a25e 100644 --- a/images/remap-file-path.proto +++ b/images/remap-file-path.proto @@ -4,6 +4,9 @@ enum remap_type { LINKED = 0; GHOST = 1; PROCFS = 2; + // Reserved for spfs manager + // SPFS = 3; + // SPFS_LINKED = 4; }; message remap_file_path_entry { From 7a680d7ba025b49219bb92b7cf5a82e65b6ff013 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 17 Mar 2017 17:55:05 +0300 Subject: [PATCH 1614/4375] images: sk-inet -- Reserve entries for IP raw sockets Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- images/sk-inet.proto | 3 +++ 1 file changed, 3 insertions(+) diff --git a/images/sk-inet.proto b/images/sk-inet.proto index 4be88adba..cb8245c2c 100644 --- a/images/sk-inet.proto +++ b/images/sk-inet.proto @@ -6,6 +6,9 @@ import "sk-opts.proto"; message ip_opts_entry { optional bool freebind = 1; + // For raw sockets support + // optional bool hdrincl = 2; + // optional bool nodefrag = 3; } message inet_sk_entry { From c983d5f9fdb91dd8f3a2e26c779f3375b649666b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 17 Mar 2017 17:55:06 +0300 Subject: [PATCH 1615/4375] images: sk-netlink -- Reserve entries for netlink queued messages Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- images/sk-netlink.proto | 2 ++ 1 file changed, 2 insertions(+) diff --git a/images/sk-netlink.proto b/images/sk-netlink.proto index 402281dd9..97fa44586 100644 --- a/images/sk-netlink.proto +++ b/images/sk-netlink.proto @@ -17,4 +17,6 @@ message netlink_sk_entry { required fown_entry fown = 11; required sk_opts_entry opts = 12; optional uint32 ns_id = 13; + // For netlink queued messages + // optional nl_sk_opts_entry nl_opts = 14; } From b58eed2a6d652902e26fe22ef6e75726f3e57059 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 17 Mar 2017 17:55:08 +0300 Subject: [PATCH 1616/4375] images: tty -- Reserve entries for multiple devpts support Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- images/tty.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/images/tty.proto b/images/tty.proto index c282cc2ef..ed664ef51 100644 --- a/images/tty.proto +++ b/images/tty.proto @@ -39,6 +39,8 @@ enum TtyType { message tty_data_entry { required uint32 tty_id = 1; required bytes data = 2; + + // optional sint32 mnt_id = 3 [default = 0]; } message tty_info_entry { @@ -73,6 +75,8 @@ message tty_info_entry { optional uint32 uid = 14; optional uint32 gid = 15; + + // optional sint32 mnt_id = 16 [default = 0]; }; message tty_file_entry { @@ -81,5 +85,6 @@ message tty_file_entry { required uint32 flags = 3 [(criu).hex = true]; required fown_entry fown = 4; + // optional sint32 mnt_id = 5 [default = 0]; optional uint32 regf_id = 6; } From d6ec8347570a4e361dc29614844f4b7484b33796 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 3 Jul 2018 02:52:14 +0300 Subject: [PATCH 1617/4375] zdtm: handle errors of make Signed-off-by: Andrei Vagin --- test/zdtm.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 4508ebb24..17306341a 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -354,6 +354,9 @@ class test_fail_exc(Exception): def __init__(self, step): self.step = step + def __str__(self): + return str(self.step) + class test_fail_expected_exc(Exception): def __init__(self, cr_action): @@ -393,7 +396,8 @@ class zdtm_test: preexec_fn = self.__freezer and self.__freezer.attach or None) if act == "pid": try_run_hook(self, ["--post-start"]) - s.wait() + if s.wait(): + raise test_fail_exc(str(s_args)) if self.__freezer: self.__freezer.freeze() From 6cb36a1e08c22e9f4256eb219d90a5d12cc4ec28 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:29 +0300 Subject: [PATCH 1618/4375] kcmp: Cleanup sources - switch to use uintX type (just to drop uX finally, it doesn't worth to carry this type) - instead of including huge util.h rather include the files which are really needed: log, xmalloc, compiler and bug Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/kcmp-ids.h | 6 ++++-- criu/kcmp-ids.c | 13 +++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/criu/include/kcmp-ids.h b/criu/include/kcmp-ids.h index afe68d6d3..ac6d84a2b 100644 --- a/criu/include/kcmp-ids.h +++ b/criu/include/kcmp-ids.h @@ -1,6 +1,8 @@ #ifndef __CR_KCMP_IDS_H__ #define __CR_KCMP_IDS_H__ +#include + #include "kcmp.h" struct kid_tree { @@ -23,7 +25,7 @@ struct kid_elem { unsigned idx; }; -extern u32 kid_generate_gen(struct kid_tree *tree, - struct kid_elem *elem, int *new_id); +extern uint32_t kid_generate_gen(struct kid_tree *tree, + struct kid_elem *elem, int *new_id); #endif /* __CR_KCMP_IDS_H__ */ diff --git a/criu/kcmp-ids.c b/criu/kcmp-ids.c index 2a7685397..c87e245d0 100644 --- a/criu/kcmp-ids.c +++ b/criu/kcmp-ids.c @@ -2,8 +2,13 @@ #include #include +#include "log.h" +#include "xmalloc.h" + +#include "common/compiler.h" +#include "common/bug.h" + #include "rbtree.h" -#include "util.h" #include "kcmp-ids.h" /* @@ -52,7 +57,7 @@ struct kid_entry { struct rb_root subtree_root; struct rb_node subtree_node; - u32 subid; /* subid is always unique */ + uint32_t subid; /* subid is always unique */ struct kid_elem elem; } __aligned(sizeof(long)); @@ -79,7 +84,7 @@ err: return e; } -static u32 kid_generate_sub(struct kid_tree *tree, struct kid_entry *e, +static uint32_t kid_generate_sub(struct kid_tree *tree, struct kid_entry *e, struct kid_elem *elem, int *new_id) { struct rb_node *node = e->subtree_root.rb_node; @@ -119,7 +124,7 @@ static u32 kid_generate_sub(struct kid_tree *tree, struct kid_entry *e, return sub->subid; } -u32 kid_generate_gen(struct kid_tree *tree, +uint32_t kid_generate_gen(struct kid_tree *tree, struct kid_elem *elem, int *new_id) { struct rb_node *node = tree->root.rb_node; From 77a6fcb98a47e761b94dbc750fb2f6bdc49c2b6d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:30 +0300 Subject: [PATCH 1619/4375] kcmp: Beautify kcmp-ids.h - aling memebers - use pid_t type for PIDs Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/kcmp-ids.h | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/criu/include/kcmp-ids.h b/criu/include/kcmp-ids.h index ac6d84a2b..37e2398db 100644 --- a/criu/include/kcmp-ids.h +++ b/criu/include/kcmp-ids.h @@ -2,27 +2,28 @@ #define __CR_KCMP_IDS_H__ #include +#include #include "kcmp.h" struct kid_tree { - struct rb_root root; - unsigned kcmp_type; - unsigned long subid; + struct rb_root root; + unsigned int kcmp_type; + unsigned long subid; }; -#define DECLARE_KCMP_TREE(name, type) \ - struct kid_tree name = { \ - .root = RB_ROOT, \ - .kcmp_type = type, \ - .subid = 1, \ +#define DECLARE_KCMP_TREE(name, type) \ + struct kid_tree name = { \ + .root = RB_ROOT, \ + .kcmp_type = type, \ + .subid = 1, \ } struct kid_elem { - int pid; - unsigned genid; - unsigned idx; + pid_t pid; + unsigned int genid; + unsigned int idx; }; extern uint32_t kid_generate_gen(struct kid_tree *tree, From 40c986ca3e1aadde068416ff8248a4de888acc07 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:31 +0300 Subject: [PATCH 1620/4375] kcmp: Drop empty line at EOF Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/kcmp-ids.c | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/kcmp-ids.c b/criu/kcmp-ids.c index c87e245d0..5b91fb66b 100644 --- a/criu/kcmp-ids.c +++ b/criu/kcmp-ids.c @@ -154,4 +154,3 @@ uint32_t kid_generate_gen(struct kid_tree *tree, return e->subid; } - From 7c72478f979af7e305025d93dcb7054a145083b7 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:32 +0300 Subject: [PATCH 1621/4375] kcmp: Add epoll definitions Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/kcmp.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/criu/include/kcmp.h b/criu/include/kcmp.h index 76f557bff..f1c898d71 100644 --- a/criu/include/kcmp.h +++ b/criu/include/kcmp.h @@ -1,6 +1,8 @@ #ifndef __CR_KCMP_H__ #define __CR_KCMP_H__ +#include + enum kcmp_type { KCMP_FILE, KCMP_VM, @@ -9,8 +11,16 @@ enum kcmp_type { KCMP_SIGHAND, KCMP_IO, KCMP_SYSVSEM, + KCMP_EPOLL_TFD, KCMP_TYPES, }; +/* Slot for KCMP_EPOLL_TFD */ +typedef struct { + uint32_t efd; /* epoll file descriptor */ + uint32_t tfd; /* target file number */ + uint32_t toff; /* target offset within same numbered sequence */ +} kcmp_epoll_slot_t; + #endif /* __CR_KCMP_H__ */ From 08603fa6ab0737915e82d721b31853752d43ed94 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:33 +0300 Subject: [PATCH 1622/4375] epoll: kdat -- Check if we have KCMP_EPOLL_TFD support We will need it to make sure the target files in epolls are present in current process. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/kerndat.h | 1 + criu/kerndat.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 10e56f187..2740dd3b1 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -73,6 +73,7 @@ struct kerndat_s { unsigned long files_stat_max_files; bool x86_has_ptrace_fpu_xsave_bug; bool has_inotify_setnextwd; + bool has_kcmp_epoll_tfd; }; extern struct kerndat_s kdat; diff --git a/criu/kerndat.c b/criu/kerndat.c index 8cb569016..3cb407c91 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -40,6 +40,7 @@ #include "prctl.h" #include "uffd.h" #include "vdso.h" +#include "kcmp.h" struct kerndat_s kdat = { }; @@ -764,6 +765,51 @@ int kerndat_has_inotify_setnextwd(void) return ret; } +int has_kcmp_epoll_tfd(void) +{ + kcmp_epoll_slot_t slot = { }; + int ret = -1, efd, tfd; + pid_t pid = getpid(); + struct epoll_event ev; + int pipefd[2]; + + efd = epoll_create(1); + if (efd < 0) { + pr_perror("Can't create epoll"); + return -1; + } + + memset(&ev, 0xff, sizeof(ev)); + ev.events = EPOLLIN | EPOLLOUT; + + if (pipe(pipefd)) { + pr_perror("Can't create pipe"); + close(efd); + return -1; + } + + tfd = pipefd[0]; + if (epoll_ctl(efd, EPOLL_CTL_ADD, tfd, &ev)) { + pr_perror("Can't add event"); + goto out; + } + + slot.efd = efd; + slot.tfd = tfd; + + if (syscall(SYS_kcmp, pid, pid, KCMP_EPOLL_TFD, tfd, &slot) == 0) + kdat.has_kcmp_epoll_tfd = true; + else + kdat.has_kcmp_epoll_tfd = false; + ret = 0; + +out: + close(pipefd[0]); + close(pipefd[1]); + close(efd); + return ret; +} + int __attribute__((weak)) kdat_x86_has_ptrace_fpu_xsave_bug(void) { return 0; @@ -1034,6 +1080,8 @@ int kerndat_init(void) ret = kerndat_x86_has_ptrace_fpu_xsave_bug(); if (!ret) ret = kerndat_has_inotify_setnextwd(); + if (!ret) + ret = has_kcmp_epoll_tfd(); kerndat_lsm(); kerndat_mmap_min_addr(); From 070720d44beafbfa193955c41f93fe4516e601e3 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:34 +0300 Subject: [PATCH 1623/4375] epoll: Pass drained fds to dump_one_file In epoll dumping we will need the whole set of fds to investigate the targets, so pass this parameter down to epoll code. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/files.c | 8 +++++--- criu/include/files.h | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/criu/files.c b/criu/files.c index 4585395a6..6b8bca2dd 100644 --- a/criu/files.c +++ b/criu/files.c @@ -475,7 +475,8 @@ static int dump_chrdev(struct fd_parms *p, int lfd, FdinfoEntry *e) } static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, - struct parasite_ctl *ctl, FdinfoEntry *e) + struct parasite_ctl *ctl, FdinfoEntry *e, + struct parasite_drain_fd *dfds) { struct fd_parms p = FD_PARMS_INIT; const struct fdtype_ops *ops; @@ -498,6 +499,7 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, } p.fd_ctl = ctl; /* Some dump_opts require this to talk to parasite */ + p.dfds = dfds; /* epoll needs to verify if target fd exist */ if (S_ISSOCK(p.stat.st_mode)) return dump_socket(&p, lfd, e); @@ -572,7 +574,7 @@ int dump_my_file(int lfd, u32 *id, int *type) me.real = getpid(); me.ns[0].virt = -1; /* FIXME */ - if (dump_one_file(&me, lfd, lfd, &fo, NULL, &e)) + if (dump_one_file(&me, lfd, lfd, &fo, NULL, &e, NULL)) return -1; *id = e.id; @@ -619,7 +621,7 @@ int dump_task_files_seized(struct parasite_ctl *ctl, struct pstree_item *item, FdinfoEntry e = FDINFO_ENTRY__INIT; ret = dump_one_file(item->pid, dfds->fds[i + off], - lfds[i], opts + i, ctl, &e); + lfds[i], opts + i, ctl, &e, dfds); if (ret) break; diff --git a/criu/include/files.h b/criu/include/files.h index 945c7b4fb..a3beaf315 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -15,6 +15,7 @@ #include "images/fown.pb-c.h" #include "images/vma.pb-c.h" +struct parasite_drain_fd; struct pstree_item; struct file_desc; struct cr_imgset; @@ -50,6 +51,7 @@ struct fd_parms { int mnt_id; struct parasite_ctl *fd_ctl; + struct parasite_drain_fd *dfds; }; #define FD_PARMS_INIT \ From 1804d6f3bc09ab2d7f56ceb98cad6ff19bab0ce4 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:35 +0300 Subject: [PATCH 1624/4375] epoll: Use real file transferred for target fds check When we are checkpoiting epoll targets we assuming that this target file is belonging to the process we are on. This is of course not true. Without kernel support the only thing we can do is compare fd numbers with ones present in epoll fdinfo. When fd numer match we assume that it indeed the file which has been added into epoll. This won't cover the case when file has been moved to some other number and new one is reopened instead of it. Such scenario will trigger false positive and we can't do anything about. In next patches with kernel help we will make precise check for files identity. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/eventpoll.c | 51 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/criu/eventpoll.c b/criu/eventpoll.c index f0265ced2..c7e5e8881 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -12,6 +12,7 @@ #include #include +#include "types.h" #include "crtools.h" #include "common/compiler.h" #include "imgset.h" @@ -22,6 +23,7 @@ #include "util.h" #include "log.h" #include "pstree.h" +#include "parasite.h" #include "protobuf.h" #include "images/eventpoll.pb-c.h" @@ -55,7 +57,9 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) { FileEntry fe = FILE_ENTRY__INIT; EventpollFileEntry e = EVENTPOLL_FILE_ENTRY__INIT; - int i, ret = -1; + EventpollTfdEntry **tfd_cpy = NULL; + size_t i, j, k, n_tfd_cpy; + int ret = -1; e.id = id; e.flags = p->flags; @@ -68,14 +72,51 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) fe.id = e.id; fe.epfd = &e; + n_tfd_cpy = e.n_tfd; + tfd_cpy = xmemdup(e.tfd, sizeof(e.tfd[0]) * e.n_tfd); + if (!tfd_cpy) + goto out; + + /* + * Handling dup'ed or transferred target + * files is tricky: we need to use kcmp + * to find out where file came from. Until + * it's implemented lets use simplier approach + * just check the targets are blonging to the + * pid's file set. + */ + if (p->dfds) { + for (i = j = 0; i < e.n_tfd; i++) { + for (k = 0; k < p->dfds->nr_fds; k++) { + if (p->dfds->fds[k] == e.tfd[i]->tfd) + break; + } + + if (k >= p->dfds->nr_fds) { + pr_warn("Escaped/closed fd descriptor %d on pid %d, ignoring\n", + e.tfd[i]->tfd, p->pid); + continue; + } + + e.tfd[j++] = e.tfd[i]; + } + e.n_tfd = j; /* New amount of "semi-valid" fds */ + } + pr_info_eventpoll("Dumping ", &e); ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); -out: - for (i = 0; i < e.n_tfd; i++) { - if (!ret) + if (!ret) { + for (i = 0; i < e.n_tfd; i++) pr_info_eventpoll_tfd("Dumping: ", e.tfd[i]); - eventpoll_tfd_entry__free_unpacked(e.tfd[i], NULL); } + + /* Restore former values to free resources */ + memcpy(e.tfd, tfd_cpy, sizeof(e.tfd[0]) * n_tfd_cpy); + e.n_tfd = n_tfd_cpy; +out: + for (i = 0; i < e.n_tfd; i++) + eventpoll_tfd_entry__free_unpacked(e.tfd[i], NULL); + xfree(tfd_cpy); xfree(e.tfd); return ret; From cfa3f405d522334076fc4d687bd077bee3186ccf Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:36 +0300 Subject: [PATCH 1625/4375] epoll: Use kcmp to find proper target file When target file obtained from epoll fdinfo (internally the kernel keeps only file _number_ inside) we have to check its identity to make sure it is exactly one which has been added into epoll engine. The only proper way is to use kcmp syscall. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/eventpoll.c | 90 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 11 deletions(-) diff --git a/criu/eventpoll.c b/criu/eventpoll.c index c7e5e8881..90fac9948 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -24,6 +24,8 @@ #include "log.h" #include "pstree.h" #include "parasite.h" +#include "kerndat.h" +#include "kcmp.h" #include "protobuf.h" #include "images/eventpoll.pb-c.h" @@ -53,12 +55,81 @@ static void pr_info_eventpoll(char *action, EventpollFileEntry *e) pr_info("%seventpoll: id %#08x flags %#04x\n", action, e->id, e->flags); } +static int tfd_cmp(const void *a, const void *b) +{ + if (((int *)a)[0] > ((int *)b)[0]) + return 1; + if (((int *)a)[0] < ((int *)b)[0]) + return -1; + return 0; +} + +/* + * fds in fd_parms are sorted so we can use binary search + * for better performance. + */ +static int find_tfd(pid_t pid, int efd, int fds[], size_t nr_fds, int tfd) +{ + kcmp_epoll_slot_t slot = { + .efd = efd, + .tfd = tfd, + .toff = 0, + }; + int *tfd_found; + size_t i; + + pr_debug("find_tfd: pid %d efd %d tfd %d\n", pid, efd, tfd); + + /* + * Optimistic case: the target fd belongs to us + * and wasn't dup'ed. + */ + tfd_found = bsearch(&tfd, fds, nr_fds, sizeof(int), tfd_cmp); + if (tfd_found) { + if (kdat.has_kcmp_epoll_tfd) { + if (syscall(SYS_kcmp, pid, pid, KCMP_EPOLL_TFD, tfd, &slot) == 0) { + pr_debug("find_tfd (kcmp-yes): bsearch match pid %d efd %d tfd %d\n", + pid, efd, tfd); + return tfd; + } + } else { + pr_debug("find_tfd (kcmp-no): bsearch match pid %d efd %d tfd %d\n", + pid, efd, tfd); + return tfd; + } + } + + /* + * Pessimistic case: the file has been dup'ed, we have to walk + * over all files and find one which is suitable via series of + * the kcmp syscalls. + */ + + if (!kdat.has_kcmp_epoll_tfd) { + pr_debug("find_tfd (kcmp-no): no match pid %d efd %d tfd %d\n", + pid, efd, tfd); + return -1; + } + + for (i = 0; i < nr_fds; i++) { + if (syscall(SYS_kcmp, pid, pid, KCMP_EPOLL_TFD, fds[i], &slot) == 0) { + pr_debug("find_tfd (kcmp-yes): nsearch match pid %d efd %d tfd %d -> %d\n", + pid, efd, tfd, fds[i]); + return fds[i]; + } + } + + pr_debug("find_tfd (kcmp-yes): no match pid %d efd %d tfd %d\n", + pid, efd, tfd); + return -1; +} + static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) { FileEntry fe = FILE_ENTRY__INIT; EventpollFileEntry e = EVENTPOLL_FILE_ENTRY__INIT; EventpollTfdEntry **tfd_cpy = NULL; - size_t i, j, k, n_tfd_cpy; + size_t i, j, n_tfd_cpy; int ret = -1; e.id = id; @@ -87,21 +158,18 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) */ if (p->dfds) { for (i = j = 0; i < e.n_tfd; i++) { - for (k = 0; k < p->dfds->nr_fds; k++) { - if (p->dfds->fds[k] == e.tfd[i]->tfd) - break; - } - - if (k >= p->dfds->nr_fds) { + int tfd = find_tfd(p->pid, p->fd, p->dfds->fds, + p->dfds->nr_fds, e.tfd[i]->tfd); + if (tfd == -1) { pr_warn("Escaped/closed fd descriptor %d on pid %d, ignoring\n", e.tfd[i]->tfd, p->pid); continue; } - - e.tfd[j++] = e.tfd[i]; + e.tfd[j++]->tfd = tfd; } - e.n_tfd = j; /* New amount of "semi-valid" fds */ - } + e.n_tfd = j; /* New amount of "valid" fds */ + } else + pr_warn_once("Unix SCM files are not verified\n"); pr_info_eventpoll("Dumping ", &e); ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); From 50e1be4514fd342d57720825b4206badafa237c8 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:37 +0300 Subject: [PATCH 1626/4375] epoll: Add support for multiple duped fds Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/eventpoll.c | 52 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/criu/eventpoll.c b/criu/eventpoll.c index 90fac9948..1ac6d5d9a 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -68,17 +68,18 @@ static int tfd_cmp(const void *a, const void *b) * fds in fd_parms are sorted so we can use binary search * for better performance. */ -static int find_tfd(pid_t pid, int efd, int fds[], size_t nr_fds, int tfd) +static int find_tfd(pid_t pid, int efd, int fds[], size_t nr_fds, int tfd, + unsigned int toff) { kcmp_epoll_slot_t slot = { .efd = efd, .tfd = tfd, - .toff = 0, + .toff = toff, }; int *tfd_found; size_t i; - pr_debug("find_tfd: pid %d efd %d tfd %d\n", pid, efd, tfd); + pr_debug("find_tfd: pid %d efd %d tfd %d toff %u\n", pid, efd, tfd, toff); /* * Optimistic case: the target fd belongs to us @@ -88,13 +89,13 @@ static int find_tfd(pid_t pid, int efd, int fds[], size_t nr_fds, int tfd) if (tfd_found) { if (kdat.has_kcmp_epoll_tfd) { if (syscall(SYS_kcmp, pid, pid, KCMP_EPOLL_TFD, tfd, &slot) == 0) { - pr_debug("find_tfd (kcmp-yes): bsearch match pid %d efd %d tfd %d\n", - pid, efd, tfd); + pr_debug("find_tfd (kcmp-yes): bsearch match pid %d efd %d tfd %d toff %u\n", + pid, efd, tfd, toff); return tfd; } } else { - pr_debug("find_tfd (kcmp-no): bsearch match pid %d efd %d tfd %d\n", - pid, efd, tfd); + pr_debug("find_tfd (kcmp-no): bsearch match pid %d efd %d tfd %d toff %u\n", + pid, efd, tfd, toff); return tfd; } } @@ -106,21 +107,21 @@ static int find_tfd(pid_t pid, int efd, int fds[], size_t nr_fds, int tfd) */ if (!kdat.has_kcmp_epoll_tfd) { - pr_debug("find_tfd (kcmp-no): no match pid %d efd %d tfd %d\n", - pid, efd, tfd); + pr_debug("find_tfd (kcmp-no): no match pid %d efd %d tfd %d toff %u\n", + pid, efd, tfd, toff); return -1; } for (i = 0; i < nr_fds; i++) { if (syscall(SYS_kcmp, pid, pid, KCMP_EPOLL_TFD, fds[i], &slot) == 0) { - pr_debug("find_tfd (kcmp-yes): nsearch match pid %d efd %d tfd %d -> %d\n", - pid, efd, tfd, fds[i]); + pr_debug("find_tfd (kcmp-yes): nsearch match pid %d efd %d tfd %d toff %u -> %d\n", + pid, efd, tfd, toff, fds[i]); return fds[i]; } } - pr_debug("find_tfd (kcmp-yes): no match pid %d efd %d tfd %d\n", - pid, efd, tfd); + pr_debug("find_tfd (kcmp-yes): no match pid %d efd %d tfd %d toff %u\n", + pid, efd, tfd, toff); return -1; } @@ -129,7 +130,8 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) FileEntry fe = FILE_ENTRY__INIT; EventpollFileEntry e = EVENTPOLL_FILE_ENTRY__INIT; EventpollTfdEntry **tfd_cpy = NULL; - size_t i, j, n_tfd_cpy; + ssize_t i, j, n_tfd_cpy; + uint32_t *toff = NULL; int ret = -1; e.id = id; @@ -148,6 +150,25 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) if (!tfd_cpy) goto out; + /* + * In regular case there is no so many dup'ed + * descriptors so instead of complex mappings + * lets rather walk over members with O(n^2) + */ + if (p->dfds) { + toff = xzalloc(sizeof(*toff) * e.n_tfd); + if (!toff) + goto out; + for (i = 1; i < e.n_tfd; i++) { + for (j = i - 1; j < e.n_tfd && j >= 0; j--) { + if (e.tfd[i]->tfd == e.tfd[j]->tfd) { + toff[i] = toff[j] + 1; + break; + } + } + } + } + /* * Handling dup'ed or transferred target * files is tricky: we need to use kcmp @@ -159,7 +180,7 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) if (p->dfds) { for (i = j = 0; i < e.n_tfd; i++) { int tfd = find_tfd(p->pid, p->fd, p->dfds->fds, - p->dfds->nr_fds, e.tfd[i]->tfd); + p->dfds->nr_fds, e.tfd[i]->tfd, toff[i]); if (tfd == -1) { pr_warn("Escaped/closed fd descriptor %d on pid %d, ignoring\n", e.tfd[i]->tfd, p->pid); @@ -186,6 +207,7 @@ out: eventpoll_tfd_entry__free_unpacked(e.tfd[i], NULL); xfree(tfd_cpy); xfree(e.tfd); + xfree(toff); return ret; } From f15fe7cfb3ac4913e3329c20e46ee94a9406fa0c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:38 +0300 Subject: [PATCH 1627/4375] epoll: Show tfd in decimal form For easier fd match when reading logs Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/eventpoll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/eventpoll.c b/criu/eventpoll.c index 1ac6d5d9a..3779ebeeb 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -46,8 +46,8 @@ int is_eventpoll_link(char *link) static void pr_info_eventpoll_tfd(char *action, EventpollTfdEntry *e) { - pr_info("%seventpoll-tfd: id %#08x tfd %#08x events %#08x data %#016"PRIx64"\n", - action, e->id, e->tfd, e->events, e->data); + pr_info("%seventpoll-tfd: tfd %8d events %#08x data %#016"PRIx64"\n", + action, e->tfd, e->events, e->data); } static void pr_info_eventpoll(char *action, EventpollFileEntry *e) From 3d280e02835ca3e2e4cf070b757a778da1302699 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:39 +0300 Subject: [PATCH 1628/4375] epoll: Print efd id when showing targets To figure out efd:tfd mapping easier by reading the logs. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/eventpoll.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/criu/eventpoll.c b/criu/eventpoll.c index 3779ebeeb..a32bdd07d 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -44,10 +44,10 @@ int is_eventpoll_link(char *link) return is_anon_link_type(link, "[eventpoll]"); } -static void pr_info_eventpoll_tfd(char *action, EventpollTfdEntry *e) +static void pr_info_eventpoll_tfd(char *action, uint32_t id, EventpollTfdEntry *e) { - pr_info("%seventpoll-tfd: tfd %8d events %#08x data %#016"PRIx64"\n", - action, e->tfd, e->events, e->data); + pr_info("%seventpoll-tfd: id %#08x tfd %8d events %#08x data %#016"PRIx64"\n", + action, id, e->tfd, e->events, e->data); } static void pr_info_eventpoll(char *action, EventpollFileEntry *e) @@ -196,7 +196,7 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); if (!ret) { for (i = 0; i < e.n_tfd; i++) - pr_info_eventpoll_tfd("Dumping: ", e.tfd[i]); + pr_info_eventpoll_tfd("Dumping: ", e.id, e.tfd[i]); } /* Restore former values to free resources */ @@ -277,7 +277,7 @@ static int eventpoll_retore_tfd(int fd, int id, EventpollTfdEntry *tdefe) { struct epoll_event event; - pr_info_eventpoll_tfd("Restore ", tdefe); + pr_info_eventpoll_tfd("Restore ", id, tdefe); event.events = tdefe->events; event.data.u64 = tdefe->data; From 071cc1e1fab68025595482678e34aace1f5bb22d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:40 +0300 Subject: [PATCH 1629/4375] epoll: Align members in assignments For readability sake Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/eventpoll.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/criu/eventpoll.c b/criu/eventpoll.c index a32bdd07d..6247b955e 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -309,8 +309,8 @@ static int eventpoll_post_open(struct file_desc *d, int fd) } static struct file_desc_ops desc_ops = { - .type = FD_TYPES__EVENTPOLL, - .open = eventpoll_open, + .type = FD_TYPES__EVENTPOLL, + .open = eventpoll_open, }; static int collect_one_epoll_tfd(void *o, ProtobufCMessage *msg, struct cr_img *i) @@ -345,10 +345,10 @@ static int collect_one_epoll_tfd(void *o, ProtobufCMessage *msg, struct cr_img * } struct collect_image_info epoll_tfd_cinfo = { - .fd_type = CR_FD_EVENTPOLL_TFD, - .pb_type = PB_EVENTPOLL_TFD, - .collect = collect_one_epoll_tfd, - .flags = COLLECT_NOFREE, + .fd_type = CR_FD_EVENTPOLL_TFD, + .pb_type = PB_EVENTPOLL_TFD, + .collect = collect_one_epoll_tfd, + .flags = COLLECT_NOFREE, }; static int collect_one_epoll(void *o, ProtobufCMessage *msg, struct cr_img *i) @@ -361,8 +361,8 @@ static int collect_one_epoll(void *o, ProtobufCMessage *msg, struct cr_img *i) } struct collect_image_info epoll_cinfo = { - .fd_type = CR_FD_EVENTPOLL_FILE, - .pb_type = PB_EVENTPOLL_FILE, - .priv_size = sizeof(struct eventpoll_file_info), - .collect = collect_one_epoll, + .fd_type = CR_FD_EVENTPOLL_FILE, + .pb_type = PB_EVENTPOLL_FILE, + .priv_size = sizeof(struct eventpoll_file_info), + .collect = collect_one_epoll, }; From ca8144b7f765303f961aeeb35347257f548e2424 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:41 +0300 Subject: [PATCH 1630/4375] epoll: Add kcmp_epoll check To run epoll tests only where it is supported. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-check.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/criu/cr-check.c b/criu/cr-check.c index 0b9e3c37f..f496d25ad 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1078,6 +1078,14 @@ static int check_sk_unix_file(void) return 0; } +static int check_kcmp_epoll(void) +{ + if (!kdat.has_kcmp_epoll_tfd) + return -1; + + return 0; +} + static int (*chk_feature)(void); /* @@ -1185,6 +1193,7 @@ int cr_check(void) ret |= check_uffd(); ret |= check_uffd_noncoop(); ret |= check_sk_netns(); + ret |= check_kcmp_epoll(); } /* @@ -1269,6 +1278,7 @@ static struct feature_list feature_list[] = { { "sk_unix_file", check_sk_unix_file }, { "nsid", check_nsid }, { "link_nsid", check_link_nsid}, + { "kcmp_epoll", check_kcmp_epoll}, { NULL, NULL }, }; From fa989970ec79c3d7478895c349c74a507252b545 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:42 +0300 Subject: [PATCH 1631/4375] epoll: Save fields of target files in eventpoll_tfd_entry We will use them to fast lookup of targets files. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/proc_parse.c | 20 +++++++++++++++++--- images/eventpoll.proto | 5 +++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 3a8013866..1a5722eaf 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1762,9 +1762,23 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, void *arg) eventpoll_tfd_entry__init(e); - ret = sscanf(str, "tfd: %d events: %x data: %"PRIx64, - &e->tfd, &e->events, &e->data); - if (ret != 3) { + ret = sscanf(str, "tfd: %d events: %x data: %llx" + " pos:%lli ino:%lx sdev:%x", + &e->tfd, &e->events, (long long *)&e->data, + (long long *)&e->pos, (long *)&e->inode, + &e->dev); + if (ret < 3 || ret > 6) { + eventpoll_tfd_entry__free_unpacked(e, NULL); + goto parse_err; + } else if (ret == 3) { + e->has_dev = false; + e->has_inode = false; + e->has_pos = false; + } else if (ret == 6) { + e->has_dev = true; + e->has_inode = true; + e->has_pos = true; + } else if (ret < 6) { eventpoll_tfd_entry__free_unpacked(e, NULL); goto parse_err; } diff --git a/images/eventpoll.proto b/images/eventpoll.proto index 8901d807a..4a8d1b834 100644 --- a/images/eventpoll.proto +++ b/images/eventpoll.proto @@ -7,6 +7,11 @@ message eventpoll_tfd_entry { required uint32 tfd = 2; required uint32 events = 3; required uint64 data = 4; + + /* to find dup'ed target files */ + optional uint32 dev = 5; + optional uint64 inode = 6; + optional uint64 pos = 7; } message eventpoll_file_entry { From d026ba1cdd16b72066a784d89eab00921c490d78 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:43 +0300 Subject: [PATCH 1632/4375] epoll: Exit with error if tfd is missing If we can't find target file descriptor we should exit on dump with error instead of skipping it. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/eventpoll.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/criu/eventpoll.c b/criu/eventpoll.c index 6247b955e..3dcc731ba 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -129,9 +129,8 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) { FileEntry fe = FILE_ENTRY__INIT; EventpollFileEntry e = EVENTPOLL_FILE_ENTRY__INIT; - EventpollTfdEntry **tfd_cpy = NULL; - ssize_t i, j, n_tfd_cpy; uint32_t *toff = NULL; + ssize_t i, j; int ret = -1; e.id = id; @@ -145,11 +144,6 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) fe.id = e.id; fe.epfd = &e; - n_tfd_cpy = e.n_tfd; - tfd_cpy = xmemdup(e.tfd, sizeof(e.tfd[0]) * e.n_tfd); - if (!tfd_cpy) - goto out; - /* * In regular case there is no so many dup'ed * descriptors so instead of complex mappings @@ -178,17 +172,16 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) * pid's file set. */ if (p->dfds) { - for (i = j = 0; i < e.n_tfd; i++) { + for (i = 0; i < e.n_tfd; i++) { int tfd = find_tfd(p->pid, p->fd, p->dfds->fds, p->dfds->nr_fds, e.tfd[i]->tfd, toff[i]); if (tfd == -1) { - pr_warn("Escaped/closed fd descriptor %d on pid %d, ignoring\n", + pr_err("Escaped/closed fd descriptor %d on pid %d\n", e.tfd[i]->tfd, p->pid); - continue; + goto out; } - e.tfd[j++]->tfd = tfd; + e.tfd[i]->tfd = tfd; } - e.n_tfd = j; /* New amount of "valid" fds */ } else pr_warn_once("Unix SCM files are not verified\n"); @@ -199,13 +192,9 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) pr_info_eventpoll_tfd("Dumping: ", e.id, e.tfd[i]); } - /* Restore former values to free resources */ - memcpy(e.tfd, tfd_cpy, sizeof(e.tfd[0]) * n_tfd_cpy); - e.n_tfd = n_tfd_cpy; out: for (i = 0; i < e.n_tfd; i++) eventpoll_tfd_entry__free_unpacked(e.tfd[i], NULL); - xfree(tfd_cpy); xfree(e.tfd); xfree(toff); From 67bd254a0dd76fbb97c4a6d1f12c4c324f9b3ba3 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:44 +0300 Subject: [PATCH 1633/4375] epoll: Add kid_lookup_epoll_tfd helper To find target files with help of our collected rbtree. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/file-ids.c | 2 +- criu/include/file-ids.h | 2 ++ criu/include/kcmp-ids.h | 4 +++ criu/kcmp-ids.c | 54 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/criu/file-ids.c b/criu/file-ids.c index 36973cbdd..006e47d64 100644 --- a/criu/file-ids.c +++ b/criu/file-ids.c @@ -19,7 +19,7 @@ #include "irmap.h" #include "files.h" -static DECLARE_KCMP_TREE(fd_tree, KCMP_FILE); +DECLARE_KCMP_TREE(fd_tree, KCMP_FILE); #define FDID_BITS 5 #define FDID_SIZE (1 << FDID_BITS) diff --git a/criu/include/file-ids.h b/criu/include/file-ids.h index 845cfaa9f..9a39f0d2d 100644 --- a/criu/include/file-ids.h +++ b/criu/include/file-ids.h @@ -16,4 +16,6 @@ struct fd_parms; extern int fd_id_generate(pid_t pid, FdinfoEntry *fe, struct fd_parms *p); extern int fd_id_generate_special(struct fd_parms *p, u32 *id); +extern struct kid_tree fd_tree; + #endif /* __CR_FILE_IDS_H__ */ diff --git a/criu/include/kcmp-ids.h b/criu/include/kcmp-ids.h index 37e2398db..a37622c50 100644 --- a/criu/include/kcmp-ids.h +++ b/criu/include/kcmp-ids.h @@ -29,4 +29,8 @@ struct kid_elem { extern uint32_t kid_generate_gen(struct kid_tree *tree, struct kid_elem *elem, int *new_id); +extern struct kid_elem *kid_lookup_epoll_tfd(struct kid_tree *tree, + struct kid_elem *elem, + kcmp_epoll_slot_t *slot); + #endif /* __CR_KCMP_IDS_H__ */ diff --git a/criu/kcmp-ids.c b/criu/kcmp-ids.c index 5b91fb66b..4fde10e67 100644 --- a/criu/kcmp-ids.c +++ b/criu/kcmp-ids.c @@ -152,5 +152,57 @@ uint32_t kid_generate_gen(struct kid_tree *tree, rb_link_and_balance(&tree->root, &e->node, parent, new); *new_id = 1; return e->subid; - +} + +static struct kid_elem *kid_lookup_epoll_tfd_sub(struct kid_tree *tree, + struct kid_entry *e, + struct kid_elem *elem, + kcmp_epoll_slot_t *slot) +{ + struct rb_node *node = e->subtree_root.rb_node; + struct rb_node **new = &e->subtree_root.rb_node; + + BUG_ON(!node); + + while (node) { + struct kid_entry *this = rb_entry(node, struct kid_entry, subtree_node); + int ret = syscall(SYS_kcmp, this->elem.pid, elem->pid, KCMP_EPOLL_TFD, + this->elem.idx, slot); + + if (ret == 1) + node = node->rb_left, new = &((*new)->rb_left); + else if (ret == 2) + node = node->rb_right, new = &((*new)->rb_right); + else if (ret == 0) + return &this->elem; + else { + pr_perror("kcmp-epoll failed: pid (%d %d) type %u idx (%u %u)", + this->elem.pid, elem->pid, KCMP_EPOLL_TFD, + this->elem.idx, elem->idx); + return NULL; + } + } + + return NULL; +} + +struct kid_elem *kid_lookup_epoll_tfd(struct kid_tree *tree, + struct kid_elem *elem, + kcmp_epoll_slot_t *slot) +{ + struct rb_node *node = tree->root.rb_node; + struct rb_node **new = &tree->root.rb_node; + + while (node) { + struct kid_entry *this = rb_entry(node, struct kid_entry, node); + + if (elem->genid < this->elem.genid) + node = node->rb_left, new = &((*new)->rb_left); + else if (elem->genid > this->elem.genid) + node = node->rb_right, new = &((*new)->rb_right); + else + return kid_lookup_epoll_tfd_sub(tree, this, elem, slot); + } + + return NULL; } From 605b9be8156809cda5db82e794340c0a5e8caebe Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:45 +0300 Subject: [PATCH 1634/4375] files: make_gen_id -- Promote to be general helper It is used in files tree generation so we will need reuse for epoll sake. Also use the whole 64 bit offset to shuffle bits more. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/files.c | 11 ++++++++--- criu/include/files.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/criu/files.c b/criu/files.c index 6b8bca2dd..4ed84305e 100644 --- a/criu/files.c +++ b/criu/files.c @@ -303,9 +303,12 @@ static int fixup_overlayfs(struct fd_parms *p, struct fd_link *link) * The kcmp-ids.c engine does this trick, see comments in it for more info. */ -static u32 make_gen_id(const struct fd_parms *p) +uint32_t make_gen_id(uint32_t st_dev, uint32_t st_ino, uint64_t pos) { - return ((u32)p->stat.st_dev) ^ ((u32)p->stat.st_ino) ^ ((u32)p->pos); + uint32_t pos_hi = pos >> 32; + uint32_t pos_low = pos & 0xffffffff; + + return st_dev ^ st_ino ^ pos_hi ^ pos_low; } int do_dump_gen_file(struct fd_parms *p, int lfd, @@ -314,7 +317,9 @@ int do_dump_gen_file(struct fd_parms *p, int lfd, int ret = -1; e->type = ops->type; - e->id = make_gen_id(p); + e->id = make_gen_id((uint32_t)p->stat.st_dev, + (uint32_t)p->stat.st_ino, + (uint64_t)p->pos); e->fd = p->fd; e->flags = p->fd_flags; diff --git a/criu/include/files.h b/criu/include/files.h index a3beaf315..75757bd1d 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -63,6 +63,7 @@ struct fd_parms { } extern int fill_fdlink(int lfd, const struct fd_parms *p, struct fd_link *link); +extern uint32_t make_gen_id(uint32_t st_dev, uint32_t st_ino, uint64_t pos); struct file_desc; From 4e8ca613d3d59c3e3a300768c8278cc308f0c7ef Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 4 Jul 2018 18:51:46 +0300 Subject: [PATCH 1635/4375] epoll: Use epoll queues to speedup multiple duped fds When we are dumping epoll and one of target fd is been duped we can reuse already collected fds rbtree to find proper target. We handle it in a lazy way: - try use plain regular bsearch first, in case of all targets are not duped we checkpoint epoll immediately - if bsearch failed we put this epoll entry into a queue and run its dumping later when all other files in the process are already dumped. At this moment fds tree should already has all target files in rbtree thus we can simply lookup for it Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 6 + criu/eventpoll.c | 266 ++++++++++++++++++++++++++++++--------- criu/include/eventpoll.h | 2 + 3 files changed, 214 insertions(+), 60 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 8cf20177e..b6c3883e3 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -82,6 +82,7 @@ #include "seize.h" #include "fault-injection.h" #include "dump.h" +#include "eventpoll.h" /* * Architectures can overwrite this function to restore register sets that @@ -1344,6 +1345,11 @@ static int dump_one_task(struct pstree_item *item, InventoryEntry *parent_ie) pr_err("Dump files (pid: %d) failed with %d\n", pid, ret); goto err_cure; } + ret = flush_eventpoll_dinfo_queue(); + if (ret) { + pr_err("Dump eventpoll (pid: %d) failed with %d\n", pid, ret); + goto err_cure; + } } mdc.pre_dump = false; diff --git a/criu/eventpoll.c b/criu/eventpoll.c index 3dcc731ba..a47cf015a 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -25,7 +25,8 @@ #include "pstree.h" #include "parasite.h" #include "kerndat.h" -#include "kcmp.h" +#include "file-ids.h" +#include "kcmp-ids.h" #include "protobuf.h" #include "images/eventpoll.pb-c.h" @@ -33,6 +34,27 @@ #undef LOG_PREFIX #define LOG_PREFIX "epoll: " +static LIST_HEAD(dinfo_list); + +typedef struct { + uint32_t tfd; + uint32_t off; + uint32_t idx; +} toff_t; + +struct eventpoll_dinfo { + struct list_head list; + + FileEntry *fe; + EventpollFileEntry *e; + + toff_t *toff; + FownEntry fown; + + pid_t pid; + int efd; +}; + struct eventpoll_file_info { EventpollFileEntry *efe; struct file_desc d; @@ -55,6 +77,113 @@ static void pr_info_eventpoll(char *action, EventpollFileEntry *e) pr_info("%seventpoll: id %#08x flags %#04x\n", action, e->id, e->flags); } +static int queue_dinfo(FileEntry **fe, EventpollFileEntry **e, toff_t **toff, const struct fd_parms *p) +{ + struct eventpoll_dinfo *dinfo; + + pr_info_eventpoll("Queueing ", *e); + + dinfo = xmalloc(sizeof(*dinfo)); + if (!dinfo) + return -ENOMEM; + + memcpy(&dinfo->fown, &p->fown, sizeof(dinfo->fown)); + + INIT_LIST_HEAD(&dinfo->list); + + dinfo->fe = *fe; + dinfo->e = *e; + dinfo->toff = *toff; + dinfo->e->fown = &dinfo->fown; + dinfo->pid = p->pid; + dinfo->efd = p->fd; + + *fe = NULL; + *e = NULL; + *toff = NULL; + + list_add_tail(&dinfo->list, &dinfo_list); + return 0; +} + +static void dequeue_dinfo(struct eventpoll_dinfo *dinfo) +{ + ssize_t i; + + for (i = 0; i < dinfo->e->n_tfd; i++) + eventpoll_tfd_entry__free_unpacked(dinfo->e->tfd[i], NULL); + + xfree(dinfo->fe); + xfree(dinfo->e->tfd); + xfree(dinfo->e); + xfree(dinfo->toff); + + list_del(&dinfo->list); + + xfree(dinfo); +} + +int flush_eventpoll_dinfo_queue(void) +{ + struct eventpoll_dinfo *dinfo, *t; + ssize_t i; + + list_for_each_entry_safe(dinfo, t, &dinfo_list, list) { + EventpollFileEntry *e = dinfo->e; + + for (i = 0; i < e->n_tfd; i++) { + EventpollTfdEntry *tfde = e->tfd[i]; + struct kid_elem ke = { + .pid = dinfo->pid, + .genid = make_gen_id(tfde->dev, + tfde->inode, + tfde->pos), + .idx = tfde->tfd, + }; + kcmp_epoll_slot_t slot = { + .efd = dinfo->efd, + .tfd = tfde->tfd, + .toff = dinfo->toff[i].off, + }; + struct kid_elem *t = kid_lookup_epoll_tfd(&fd_tree, &ke, &slot); + if (!t) { + pr_debug("kid_lookup_epoll: no match pid %d efd %d tfd %d toff %u\n", + dinfo->pid, dinfo->efd, tfde->tfd, dinfo->toff[i].off); + goto err; + } + + pr_debug("kid_lookup_epoll: rbsearch match pid %d efd %d tfd %d toff %u -> %d\n", + dinfo->pid, dinfo->efd, tfde->tfd, dinfo->toff[i].off, t->idx); + + /* Make sure the pid matches */ + if (t->pid != dinfo->pid) { + pr_debug("kid_lookup_epoll: pid mismatch %d %d efd %d tfd %d toff %u\n", + dinfo->pid, t->pid, dinfo->efd, tfde->tfd, dinfo->toff[i].off); + goto err; + } + + tfde->tfd = t->idx; + } + + pr_info_eventpoll("Dumping ", e); + if (pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), dinfo->fe, PB_FILE)) + goto err; + + for (i = 0; i < e->n_tfd; i++) + pr_info_eventpoll_tfd("Dumping: ", e->id, e->tfd[i]); + + dequeue_dinfo(dinfo); + } + + return 0; + +err: + list_for_each_entry_safe(dinfo, t, &dinfo_list, list) + dequeue_dinfo(dinfo); + + return -1; +} + static int tfd_cmp(const void *a, const void *b) { if (((int *)a)[0] > ((int *)b)[0]) @@ -64,12 +193,25 @@ static int tfd_cmp(const void *a, const void *b) return 0; } +static int toff_cmp(const void *a, const void *b) +{ + if (((toff_t *)a)[0].tfd > ((toff_t *)b)[0].tfd) + return 1; + if (((toff_t *)a)[0].tfd < ((toff_t *)b)[0].tfd) + return -1; + if (((toff_t *)a)[0].idx > ((toff_t *)b)[0].idx) + return 1; + if (((toff_t *)a)[0].idx < ((toff_t *)b)[0].idx) + return -1; + return 0; +} + /* * fds in fd_parms are sorted so we can use binary search * for better performance. */ -static int find_tfd(pid_t pid, int efd, int fds[], size_t nr_fds, int tfd, - unsigned int toff) +static int find_tfd_bsearch(pid_t pid, int efd, int fds[], size_t nr_fds, + int tfd, unsigned int toff) { kcmp_epoll_slot_t slot = { .efd = efd, @@ -77,9 +219,8 @@ static int find_tfd(pid_t pid, int efd, int fds[], size_t nr_fds, int tfd, .toff = toff, }; int *tfd_found; - size_t i; - pr_debug("find_tfd: pid %d efd %d tfd %d toff %u\n", pid, efd, tfd, toff); + pr_debug("find_tfd_bsearch: pid %d efd %d tfd %d toff %u\n", pid, efd, tfd, toff); /* * Optimistic case: the target fd belongs to us @@ -89,60 +230,50 @@ static int find_tfd(pid_t pid, int efd, int fds[], size_t nr_fds, int tfd, if (tfd_found) { if (kdat.has_kcmp_epoll_tfd) { if (syscall(SYS_kcmp, pid, pid, KCMP_EPOLL_TFD, tfd, &slot) == 0) { - pr_debug("find_tfd (kcmp-yes): bsearch match pid %d efd %d tfd %d toff %u\n", + pr_debug("find_tfd_bsearch (kcmp-yes): bsearch match pid %d efd %d tfd %d toff %u\n", pid, efd, tfd, toff); return tfd; } } else { - pr_debug("find_tfd (kcmp-no): bsearch match pid %d efd %d tfd %d toff %u\n", + pr_debug("find_tfd_bsearch (kcmp-no): bsearch match pid %d efd %d tfd %d toff %u\n", pid, efd, tfd, toff); return tfd; } } - /* - * Pessimistic case: the file has been dup'ed, we have to walk - * over all files and find one which is suitable via series of - * the kcmp syscalls. - */ - - if (!kdat.has_kcmp_epoll_tfd) { - pr_debug("find_tfd (kcmp-no): no match pid %d efd %d tfd %d toff %u\n", - pid, efd, tfd, toff); - return -1; - } - - for (i = 0; i < nr_fds; i++) { - if (syscall(SYS_kcmp, pid, pid, KCMP_EPOLL_TFD, fds[i], &slot) == 0) { - pr_debug("find_tfd (kcmp-yes): nsearch match pid %d efd %d tfd %d toff %u -> %d\n", - pid, efd, tfd, toff, fds[i]); - return fds[i]; - } - } - - pr_debug("find_tfd (kcmp-yes): no match pid %d efd %d tfd %d toff %u\n", + pr_debug("find_tfd_bsearch: no match pid %d efd %d tfd %d toff %u\n", pid, efd, tfd, toff); return -1; } static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) { - FileEntry fe = FILE_ENTRY__INIT; - EventpollFileEntry e = EVENTPOLL_FILE_ENTRY__INIT; - uint32_t *toff = NULL; - ssize_t i, j; + toff_t *toff_base, *toff = NULL; + EventpollFileEntry *e = NULL; + FileEntry *fe = NULL; int ret = -1; + ssize_t i; - e.id = id; - e.flags = p->flags; - e.fown = (FownEntry *)&p->fown; + e = xmalloc(sizeof(*e)); + if (!e) + goto out; + eventpoll_file_entry__init(e); - if (parse_fdinfo(lfd, FD_TYPES__EVENTPOLL, &e)) + fe = xmalloc(sizeof(*fe)); + if (!fe) + goto out; + file_entry__init(fe); + + e->id = id; + e->flags = p->flags; + e->fown = (FownEntry *)&p->fown; + + if (parse_fdinfo(lfd, FD_TYPES__EVENTPOLL, e)) goto out; - fe.type = FD_TYPES__EVENTPOLL; - fe.id = e.id; - fe.epfd = &e; + fe->type = FD_TYPES__EVENTPOLL; + fe->id = e->id; + fe->epfd = e; /* * In regular case there is no so many dup'ed @@ -150,16 +281,25 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) * lets rather walk over members with O(n^2) */ if (p->dfds) { - toff = xzalloc(sizeof(*toff) * e.n_tfd); + toff = xmalloc(sizeof(*toff) * e->n_tfd); if (!toff) goto out; - for (i = 1; i < e.n_tfd; i++) { - for (j = i - 1; j < e.n_tfd && j >= 0; j--) { - if (e.tfd[i]->tfd == e.tfd[j]->tfd) { - toff[i] = toff[j] + 1; - break; - } - } + for (i = 0; i < e->n_tfd; i++) { + toff[i].idx = i; + toff[i].tfd = e->tfd[i]->tfd; + toff[i].off = 0; + } + + qsort(toff, e->n_tfd, sizeof(*toff), toff_cmp); + + toff_base = NULL; + for (i = 1; i < e->n_tfd; i++) { + if (toff[i].tfd == toff[i - 1].tfd) { + if (!toff_base) + toff_base = &toff[i - 1]; + toff[i].off = toff[i].idx - toff_base->idx; + } else + toff_base = NULL; } } @@ -172,30 +312,36 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) * pid's file set. */ if (p->dfds) { - for (i = 0; i < e.n_tfd; i++) { - int tfd = find_tfd(p->pid, p->fd, p->dfds->fds, - p->dfds->nr_fds, e.tfd[i]->tfd, toff[i]); + for (i = 0; i < e->n_tfd; i++) { + int tfd = find_tfd_bsearch(p->pid, p->fd, p->dfds->fds, + p->dfds->nr_fds, e->tfd[i]->tfd, toff[i].off); if (tfd == -1) { - pr_err("Escaped/closed fd descriptor %d on pid %d\n", - e.tfd[i]->tfd, p->pid); + if (kdat.has_kcmp_epoll_tfd) { + ret = queue_dinfo(&fe, &e, &toff, p); + } else { + pr_err("Escaped/closed fd descriptor %d on pid %d\n", + e->tfd[i]->tfd, p->pid); + } goto out; } - e.tfd[i]->tfd = tfd; } } else pr_warn_once("Unix SCM files are not verified\n"); - pr_info_eventpoll("Dumping ", &e); - ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); + pr_info_eventpoll("Dumping ", e); + ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), fe, PB_FILE); if (!ret) { - for (i = 0; i < e.n_tfd; i++) - pr_info_eventpoll_tfd("Dumping: ", e.id, e.tfd[i]); + for (i = 0; i < e->n_tfd; i++) + pr_info_eventpoll_tfd("Dumping: ", e->id, e->tfd[i]); } out: - for (i = 0; i < e.n_tfd; i++) - eventpoll_tfd_entry__free_unpacked(e.tfd[i], NULL); - xfree(e.tfd); + for (i = 0; e && i < e->n_tfd; i++) + eventpoll_tfd_entry__free_unpacked(e->tfd[i], NULL); + xfree(fe); + if (e) + xfree(e->tfd); + xfree(e); xfree(toff); return ret; diff --git a/criu/include/eventpoll.h b/criu/include/eventpoll.h index 96a77bc98..411c5c93f 100644 --- a/criu/include/eventpoll.h +++ b/criu/include/eventpoll.h @@ -4,6 +4,8 @@ #include "files.h" extern int is_eventpoll_link(char *link); +extern int flush_eventpoll_dinfo_queue(void); + extern const struct fdtype_ops eventpoll_dump_ops; extern struct collect_image_info epoll_tfd_cinfo; extern struct collect_image_info epoll_cinfo; From bdbd7c8f14ddebd4fbc5e1bc77f9dcb17831c966 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 4 Jul 2018 18:51:47 +0300 Subject: [PATCH 1636/4375] zdtm/static: add a test to check epoll file descriptors Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/epoll.c | 137 ++++++++++++++++++++++++++++++++++++ test/zdtm/static/epoll.desc | 1 + 3 files changed, 139 insertions(+) create mode 100644 test/zdtm/static/epoll.c create mode 100644 test/zdtm/static/epoll.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 28c6a1aa0..980d8c437 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -120,6 +120,7 @@ TST_NOFILE := \ file_fown \ proc-self \ eventfs00 \ + epoll \ signalfd00 \ inotify_irmap \ fanotify00 \ diff --git a/test/zdtm/static/epoll.c b/test/zdtm/static/epoll.c new file mode 100644 index 000000000..ce3b176d3 --- /dev/null +++ b/test/zdtm/static/epoll.c @@ -0,0 +1,137 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check for epoll"; +const char *test_author = "Andrei Vagin "; + +#define DUPFDNO 999 + +int main(int argc, char *argv[]) +{ + int epollfd1, epollfd2, fd; + struct epoll_event ev; + int i, ret; + + struct { + int pipefd[2]; + } pipes[250]; + + test_init(argc, argv); + + epollfd1 = epoll_create(1); + if (epollfd1 < 0) { + pr_perror("epoll_create failed"); + exit(1); + } + epollfd2 = epoll_create(1); + if (epollfd2 < 0) { + pr_perror("epoll_create failed"); + exit(1); + } + + memset(&ev, 0, sizeof(ev)); + ev.events = EPOLLIN | EPOLLOUT; + + for (i = 0; i < ARRAY_SIZE(pipes); i++) { + if (pipe(pipes[i].pipefd)) { + pr_err("Can't create pipe %d\n", i); + exit(1); + } + + if (i % 2) { + int nfd; + + nfd = dup2(pipes[i].pipefd[0], i + 700); + if (nfd < 0) { + pr_err("dup2"); + exit(1); + } + close(pipes[i].pipefd[0]); + pipes[i].pipefd[0] = nfd; + } + + ev.data.u64 = i; + fd = dup2(pipes[i].pipefd[0], DUPFDNO); + if (fd < 0) { + pr_perror("Can't dup %d to %d", pipes[i].pipefd[0], DUPFDNO); + exit(1); + } + + test_msg("epoll %d add %d native\n", epollfd1, pipes[i].pipefd[0]); + if (epoll_ctl(epollfd1, EPOLL_CTL_ADD, pipes[i].pipefd[0], &ev)) { + pr_perror("Can't add pipe %d", pipes[i].pipefd[0]); + exit(1); + } + + test_msg("epoll %d add %d dup'ed from %d\n", epollfd1, fd, pipes[i].pipefd[0]); + if (epoll_ctl(epollfd2, EPOLL_CTL_ADD, fd, &ev)) { + pr_perror("Can't add pipe %d", fd); + exit(1); + } + + close(fd); + test_msg("epoll source %d closed\n", fd); + } + + test_daemon(); + test_waitsig(); + + ret = 0; + for (i = 0; i < ARRAY_SIZE(pipes); i++) { + uint8_t cw = 1, cr; + + if (write(pipes[i].pipefd[1], &cw, sizeof(cw)) != sizeof(cw)) { + pr_perror("Unable to write into a pipe\n"); + return 1; + } + + if (epoll_wait(epollfd1, &ev, 1, -1) != 1) { + pr_perror("Unable to wain events"); + return 1; + } + if (ev.data.u64 != i) { + pr_err("ev.fd=%d ev.data.u64=%#llx (%d expected)\n", + ev.data.fd, (long long)ev.data.u64, i); + ret |= 1; + } + + if (epoll_wait(epollfd2, &ev, 1, -1) != 1) { + pr_perror("Unable to wain events"); + return 1; + } + if (ev.data.u64 != i) { + pr_err("ev.fd=%d ev.data.u64=%#llx (%d expected)\n", + ev.data.fd, (long long)ev.data.u64, i); + ret |= 1; + } + + if (read(pipes[i].pipefd[0], &cr, sizeof(cr)) != sizeof(cr)) { + pr_perror("read"); + return 1; + } + } + + if (ret) + return 1; + + pass(); + return 0; +} diff --git a/test/zdtm/static/epoll.desc b/test/zdtm/static/epoll.desc new file mode 100644 index 000000000..72cc898d5 --- /dev/null +++ b/test/zdtm/static/epoll.desc @@ -0,0 +1 @@ +{ 'feature' : 'kcmp_epoll' } From 077409c19705fe7a1fb36ad9d7caf66eeb241ce1 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 9 Jul 2018 06:28:27 +0000 Subject: [PATCH 1637/4375] travis: fix rawhide test by also installing sudo Signed-off-by: Adrian Reber Acked-by: Radostin Stoyanov Acked-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.fedora.tmpl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index 5b618081d..de45fd8cb 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -29,6 +29,7 @@ RUN dnf install -y \ python3-future \ python3-protobuf \ python3-junit_xml \ + sudo \ tar \ which \ e2fsprogs \ @@ -48,5 +49,9 @@ WORKDIR /criu ENV CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes RUN mv .ccache /tmp && make mrproper && ccache -sz && \ date && make -j $(nproc) CC="$CC" && date && ccache -s + +# The rpc test cases are running as user #1000, let's add the user +RUN adduser -u 1000 test + RUN make -C test/zdtm -j $(nproc) From 0a859275ef93de89e144a79f26f1cf081bd35f4f Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 27 Jun 2018 14:55:10 +0300 Subject: [PATCH 1638/4375] fdstore: Unlimit fdstore queue on start We use fdstore intensively for example when handling bindmounted sockets and ghost dgram sockets. The system limit for per-socket queue may not be enough if someone generate lots of ghost sockets (150 and more as been detected on default fedora 27). To make it operatable lets unlimit fdstore queue size on startup. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/fdstore.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/criu/fdstore.c b/criu/fdstore.c index 8d3a6c89b..88a5a9a15 100644 --- a/criu/fdstore.c +++ b/criu/fdstore.c @@ -20,6 +20,8 @@ static struct fdstore_desc { int fdstore_init(void) { + /* In kernel a bufsize has type int and a value is doubled. */ + uint32_t buf[2] = { INT_MAX / 2, INT_MAX / 2 }; struct sockaddr_un addr; unsigned int addrlen; struct stat st; @@ -44,6 +46,13 @@ int fdstore_init(void) return -1; } + if (setsockopt(sk, SOL_SOCKET, SO_SNDBUFFORCE, &buf[0], sizeof(buf[0])) < 0 || + setsockopt(sk, SOL_SOCKET, SO_RCVBUFFORCE, &buf[1], sizeof(buf[1])) < 0) { + pr_perror("Unable to set SO_SNDBUFFORCE/SO_RCVBUFFORCE"); + close(sk); + return -1; + } + addr.sun_family = AF_UNIX; addrlen = snprintf(addr.sun_path, sizeof(addr.sun_path), "X/criu-fdstore-%"PRIx64, st.st_ino); addrlen += sizeof(addr.sun_family); @@ -79,11 +88,13 @@ int fdstore_init(void) int fdstore_add(int fd) { int sk = get_service_fd(FDSTORE_SK_OFF); - int id; + int id, ret; mutex_lock(&desc->lock); - if (send_fd(sk, NULL, 0, fd)) { + ret = send_fd(sk, NULL, 0, fd); + if (ret) { + pr_perror("Can't send fd %d into store\n", fd); mutex_unlock(&desc->lock); return -1; } From 35fbc373a95d9077dd0dcc4737b3a9de486ebf48 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Fri, 29 Jun 2018 12:50:07 +0000 Subject: [PATCH 1639/4375] test rpc: remove unnecessary import, close fd Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/others/rpc/read.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/others/rpc/read.py b/test/others/rpc/read.py index 680069b76..bbf69b6cb 100644 --- a/test/others/rpc/read.py +++ b/test/others/rpc/read.py @@ -5,12 +5,11 @@ # but the bash version on Ubuntu has probably the following bug: # https://lists.gnu.org/archive/html/bug-bash/2017-07/msg00039.html -import os import sys - -f=open(sys.argv[1]) +f = open(sys.argv[1]) r = f.read(1) +f.close() if r == '\0': sys.exit(0) From f167a1dd344e6f5c163414ea9489f74dcd912cf1 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 10 Jul 2018 19:02:23 +0300 Subject: [PATCH 1640/4375] mount: add helper to check unsupported children collision See more detailed explanation inside in-code comment. note: Actually before we remove validate_mounts (later in these patchset) we likely won't get to these check and fail earlier, as having children collision implies shared mounts with different sets of children. note: from v4.11 and ms kernel commit 1064f874abc0 ("mnt: Tuck mounts under others instead of creating shadow/side mounts.") there will be no more mount collision. Signed-off-by: Pavel Tikhomirov --- criu/mount.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/criu/mount.c b/criu/mount.c index 0a8406c80..7b642e0b2 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -685,6 +685,34 @@ static bool mnt_is_external(struct mount_info *m) return 0; } +/* + * Having two children whith same mountpoint is unsupported. That can happen in + * case of mount propagation inside of shared mounts, in that case it is hard + * to find out mount propagation siblings and which of these mounts is above + * (visible) and which is beneath (hidden). It would've broken mount restore + * order in can_mount_now and also visibility assumptions in open_mountpoint. + * + * Anyway after kernel v4.11 such mounts will be impossible. + */ +static int validate_children_collision(struct mount_info *mnt) +{ + struct mount_info *chi, *chj; + + list_for_each_entry(chi, &mnt->children, siblings) { + list_for_each_entry(chj, &mnt->children, siblings) { + if (chj == chi) + break; + if (!strcmp(chj->mountpoint, chi->mountpoint)) { + pr_err("Mount %d has two children with same " + "mountpoint: %d %d\n", + mnt->mnt_id, chj->mnt_id, chi->mnt_id); + return -1; + } + } + } + return 0; +} + static int validate_mounts(struct mount_info *info, bool for_dump) { struct mount_info *m, *t; @@ -697,6 +725,9 @@ static int validate_mounts(struct mount_info *info, bool for_dump) if (m->shared_id && validate_shared(m)) return -1; + if (validate_children_collision(m)) + return -1; + if (mnt_is_external(m)) continue; From fc01e18b4773da04f12ab3ddaa401f46eba09490 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 10 Jul 2018 19:02:24 +0300 Subject: [PATCH 1641/4375] zdtm: add a test for unsupported children collision These test is not automatic as after kernel v4.11 behaviour changes, on older kernel we get children collision: 817 188 0:48 / /zdtm/static/unsupported_children_collision.test/share1 rw,relatime shared:942 - tmpfs share rw > 818 817 0:124 / /zdtm/static/unsupported_children_collision.test/share1/child rw,relatime shared:943 - tmpfs child1 rw 819 188 0:48 / /zdtm/static/unsupported_children_collision.test/share2 rw,relatime shared:942 - tmpfs share rw 820 819 0:125 / /zdtm/static/unsupported_children_collision.test/share2/child rw,relatime shared:944 - tmpfs child2 rw > 821 817 0:125 / /zdtm/static/unsupported_children_collision.test/share1/child rw,relatime shared:944 - tmpfs child2 rw Signed-off-by: Pavel Tikhomirov --- test/zdtm/static/Makefile | 1 + .../static/unsupported_children_collision.c | 110 ++++++++++++++++++ .../unsupported_children_collision.desc | 1 + 3 files changed, 112 insertions(+) create mode 100644 test/zdtm/static/unsupported_children_collision.c create mode 100644 test/zdtm/static/unsupported_children_collision.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 980d8c437..b7d984d49 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -336,6 +336,7 @@ TST_DIR = \ del_standalone_un \ sk-unix-mntns \ sk-unix01 \ + unsupported_children_collision \ TST_DIR_FILE = \ chroot \ diff --git a/test/zdtm/static/unsupported_children_collision.c b/test/zdtm/static/unsupported_children_collision.c new file mode 100644 index 000000000..15e8f3ba0 --- /dev/null +++ b/test/zdtm/static/unsupported_children_collision.c @@ -0,0 +1,110 @@ +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check unsupported children collision for mounts"; +const char *test_author = "Pavel Tikhomirov "; + +char *dirname; +TEST_OPTION(dirname, string, "directory name", 1); + +int main(int argc, char **argv) +{ + char share1[PATH_MAX], share2[PATH_MAX]; + char child1[PATH_MAX], child2[PATH_MAX]; + + test_init(argc, argv); + + if (mkdir(dirname, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("zdtm_fs", dirname, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, dirname, NULL, MS_PRIVATE, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(share1, sizeof(share1), "%s/share1", dirname); + if (mkdir(share1, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("share", share1, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, share1, NULL, MS_SHARED, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(child1, sizeof(child1), "%s/share1/child", dirname); + if (mkdir(child1, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("child1", child1, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(share2, sizeof(share2), "%s/share2", dirname); + if (mkdir(share2, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount(share1, share2, NULL, MS_BIND, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(child2, sizeof(child2), "%s/share2/child", dirname); + if (mount("child2", child2, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (umount(child2)) { + pr_perror("Unable to umount %s", share1); + return 1; + } + + if (umount(share2)) { + pr_perror("Unable to umount %s", share2); + return 1; + } + + if (umount(child1)) { + pr_perror("Unable to umount %s", child1); + return 1; + } + + if (umount(share1)) { + pr_perror("Unable to umount %s", share1); + return 1; + } + + if (umount(dirname)) { + pr_perror("Unable to umount %s", dirname); + return 1; + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/unsupported_children_collision.desc b/test/zdtm/static/unsupported_children_collision.desc new file mode 100644 index 000000000..6da6e749f --- /dev/null +++ b/test/zdtm/static/unsupported_children_collision.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns', 'flags': 'suid noauto crfail'} From 64586567aeff18a500983162c28cc17a6288f9c3 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 10 Jul 2018 19:02:25 +0300 Subject: [PATCH 1642/4375] mount: fix can_mount_now to wait children of master's share properly We should not use ->bind link for checking master's children. As if we have two slaves shared between each other, the one mounted first will replace ->bind link for the other - that will break restore. Also while on it, if we do not want doubled mounts and want to prohibit propagation to slaves on restore we likely want all children of the whole master's share mounted before slave. JFYI: Actually these restriction is very strict and some cases will fail to restore, for instance (hope nobody does so): mkdir /test mount -t tmpfs test /test mount --make-private /test mkdir /test/{share,slave} mount -t tmpfs share /test/share --make-shared mount --bind /test/share/ /test/slave/ mount --make-slave /test/slave mount --make-shared /test/slave mkdir /test/share/slave mount --bind /test/slave/ /test/share/slave/ cat /proc/self/mountinfo | grep test 524 612 0:69 / /test rw,relatime - tmpfs test rw 570 524 0:73 / /test/share rw,relatime shared:879 - tmpfs share rw 571 524 0:73 / /test/slave rw,relatime shared:942 master:879 - tmpfs share rw 602 570 0:73 / /test/share/slave rw,relatime shared:942 master:879 - tmpfs share rw 603 571 0:73 / /test/slave/slave rw,relatime shared:943 master:942 - tmpfs share rw Here 603 is a propagation of 602 from master 570 to slave 571, and it is the only way to get such a mount as 571 and 602 are in one shared group now and all later mounts to them will propagate between them and create dublicated mounts. So to create real 603 without dups we need to have /test/slave mounted before /test/share/slave, which contradicts with current assumption. Signed-off-by: Pavel Tikhomirov --- criu/mount.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 7b642e0b2..d33a3cb86 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2365,19 +2365,23 @@ static bool can_mount_now(struct mount_info *mi) /* * We're the slave peer: * - Make sure the master peer is already mounted - * - Make sure all children are mounted as well to - * eliminate mounts duplications + * - Make sure all children of master's share are + * mounted as well to eliminate mounts duplications */ if (mi->master_id > 0) { - struct mount_info *c; + struct mount_info *c, *s; if (mi->bind == NULL) return false; - list_for_each_entry(c, &mi->bind->children, siblings) { + list_for_each_entry(c, &mi->mnt_master->children, siblings) if (!c->mounted) return false; - } + + list_for_each_entry(s, &mi->mnt_master->mnt_share, mnt_share) + list_for_each_entry(c, &s->children, siblings) + if (!c->mounted) + return false; } if (!fsroot_mounted(mi) && (mi->bind == NULL && !mi->need_plugin)) From 24bd5fcfff4ffc5c3cc648691a53ab288f0ce69e Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 10 Jul 2018 19:02:26 +0300 Subject: [PATCH 1643/4375] zdtm: check children of shared slaves restore 495 494 0:62 / /zdtm/static/shared_slave_mount_children.test/share rw,relatime shared:235 - tmpfs share rw 496 494 0:62 / /zdtm/static/shared_slave_mount_children.test/slave1 rw,relatime shared:236 master:235 - tmpfs share rw 497 494 0:62 / /zdtm/static/shared_slave_mount_children.test/slave2 rw,relatime shared:236 master:235 - tmpfs share rw 498 496 0:63 / /zdtm/static/shared_slave_mount_children.test/slave1/child rw,relatime shared:237 - tmpfs child rw 499 497 0:63 / /zdtm/static/shared_slave_mount_children.test/slave2/child rw,relatime shared:237 - tmpfs child rw Before the fix we had: (00.167574) 1: Error (criu/mount.c:1769): mnt: A few mount points can't be mounted (00.167577) 1: Error (criu/mount.c:1773): mnt: 498:496 / /tmp/.criu.mntns.o2Op5j/9-0000000000/zdtm/static/shared_slave_mount_children.test/slave1/child child (00.167580) 1: Error (criu/mount.c:1773): mnt: 497:494 / /tmp/.criu.mntns.o2Op5j/9-0000000000/zdtm/static/shared_slave_mount_children.test/slave2 share Signed-off-by: Pavel Tikhomirov --- test/zdtm/static/Makefile | 1 + .../zdtm/static/shared_slave_mount_children.c | 125 ++++++++++++++++++ .../static/shared_slave_mount_children.desc | 1 + 3 files changed, 127 insertions(+) create mode 100644 test/zdtm/static/shared_slave_mount_children.c create mode 100644 test/zdtm/static/shared_slave_mount_children.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index b7d984d49..6022b8045 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -337,6 +337,7 @@ TST_DIR = \ sk-unix-mntns \ sk-unix01 \ unsupported_children_collision \ + shared_slave_mount_children \ TST_DIR_FILE = \ chroot \ diff --git a/test/zdtm/static/shared_slave_mount_children.c b/test/zdtm/static/shared_slave_mount_children.c new file mode 100644 index 000000000..75c2513c6 --- /dev/null +++ b/test/zdtm/static/shared_slave_mount_children.c @@ -0,0 +1,125 @@ +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check non-uniform shares restore fine"; +const char *test_author = "Pavel Tikhomirov "; + +char *dirname; +TEST_OPTION(dirname, string, "directory name", 1); + +int main(int argc, char **argv) +{ + char share[PATH_MAX], slave1[PATH_MAX], slave2[PATH_MAX]; + char child[PATH_MAX]; + + test_init(argc, argv); + + if (mkdir(dirname, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("zdtm_fs", dirname, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, dirname, NULL, MS_PRIVATE, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(share, sizeof(share), "%s/share", dirname); + if (mkdir(share, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("share", share, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, share, NULL, MS_SHARED, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(slave1, sizeof(slave1), "%s/slave1", dirname); + if (mkdir(slave1, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount(share, slave1, NULL, MS_BIND, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, slave1, NULL, MS_SLAVE, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, slave1, NULL, MS_SHARED, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(slave2, sizeof(slave2), "%s/slave2", dirname); + if (mkdir(slave2, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount(slave1, slave2, NULL, MS_BIND, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(child, sizeof(child), "%s/slave1/child", dirname); + if (mkdir(child, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("child", child, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (umount(child)) { + pr_perror("Unable to umount %s", child); + return 1; + } + + if (umount(slave2)) { + pr_perror("Unable to umount %s", slave2); + return 1; + } + + if (umount(slave1)) { + pr_perror("Unable to umount %s", slave1); + return 1; + } + + if (umount(share)) { + pr_perror("Unable to umount %s", share); + return 1; + } + + if (umount(dirname)) { + pr_perror("Unable to umount %s", dirname); + return 1; + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/shared_slave_mount_children.desc b/test/zdtm/static/shared_slave_mount_children.desc new file mode 100644 index 000000000..7657ba45c --- /dev/null +++ b/test/zdtm/static/shared_slave_mount_children.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns', 'flags': 'suid'} From bc930d120e70e9c219cb1dfc8e23c08ad5e06b6a Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 10 Jul 2018 19:02:27 +0300 Subject: [PATCH 1644/4375] mount: put all mounts which propagate from each other to a list These information will help improving the restore of tricky mounts configurations. Function same_propagation_group checks if two mounts were created simultaneousely through shared mount propagation, and the main part of these - they should be in exaclty the same place inside the share of their parents. Function root_path_from_parent prints the mountpoint path relative to the root of the parent's share, by first substracting parent's mountpoint from our mountpoint and second prepending parents root path (relative to the root of it's file system), e.g: id parent_id root mountpoint 1 0 / / 2 1 / /parent_a 3 1 /dir /parent_b 4 2 / /parent_a/dir/a 5 3 / /parent_b/a (Let 2 and 3 be a shared group) For mount 4 root_path_from_parent gives: "/parent_a/dir/a" - "/parent_a" == "/dir/a" "/" + "/dir/a" == "/dir/a" For mount 5: "/parent_b/a" - "/parent_b" == "/a" "/dir" + "/a" == "/dir/a" So mounts 4 and 5 are a propagation group. Signed-off-by: Pavel Tikhomirov --- criu/include/mount.h | 1 + criu/mount.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/criu/include/mount.h b/criu/include/mount.h index ed771ffac..84c62c8d0 100644 --- a/criu/include/mount.h +++ b/criu/include/mount.h @@ -65,6 +65,7 @@ struct mount_info { struct list_head mnt_slave_list; /* list of slave mounts */ struct list_head mnt_slave; /* slave list entry */ struct mount_info *mnt_master; /* slave is on master->mnt_slave_list */ + struct list_head mnt_propagate; /* circular list of mounts which propagate from each other */ struct list_head postpone; diff --git a/criu/mount.c b/criu/mount.c index d33a3cb86..1447e086a 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -931,6 +931,74 @@ static int resolve_external_mounts(struct mount_info *info) return 0; } +static int root_path_from_parent(struct mount_info *m, char *buf, int size) +{ + bool head_slash = false, tail_slash = false; + int p_len = strlen(m->parent->mountpoint), + m_len = strlen(m->mountpoint), + len; + + if (!m->parent) + return -1; + + len = snprintf(buf, size, "%s", m->parent->root); + if (len >= size) + return -1; + + BUG_ON(len <= 0); + if (buf[len-1] == '/') + tail_slash = true; + + size -= len; + buf += len; + + len = m_len - p_len; + BUG_ON(len < 0); + if (len) { + if (m->mountpoint[p_len] == '/') + head_slash = true; + + len = snprintf(buf, size, "%s%s", + (!tail_slash && !head_slash) ? "/" : "", + m->mountpoint + p_len + (tail_slash && head_slash)); + if (len >= size) + return -1; + } + + return 0; +} + +static int same_propagation_group(struct mount_info *a, struct mount_info *b) { + char root_path_a[PATH_MAX], root_path_b[PATH_MAX]; + + /* + * If mounts are in same propagation group: + * 1) Their parents should be different + * 2) Their parents should be together in same shared group + */ + if (!a->parent || !b->parent || a->parent == b->parent || + a->parent->shared_id != b->parent->shared_id) + return 0; + + if (root_path_from_parent(a, root_path_a, PATH_MAX)) { + pr_err("Failed to get root path for mount %d\n", a->mnt_id); + return -1; + } + + if (root_path_from_parent(b, root_path_b, PATH_MAX)) { + pr_err("Failed to get root path for mount %d\n", b->mnt_id); + return -1; + } + + /* + * 3) Their mountpoints relative to the root of the superblock of their + * parent's share should be equal + */ + if (!strcmp(root_path_a, root_path_b)) + return 1; + return 0; +} + static int resolve_shared_mounts(struct mount_info *info, int root_master_id) { struct mount_info *m, *t; @@ -1003,6 +1071,35 @@ static int resolve_shared_mounts(struct mount_info *info, int root_master_id) } } + /* Search propagation groups */ + for (m = info; m; m = m->next) { + struct mount_info *sparent; + + if (!list_empty(&m->mnt_propagate)) + continue; + + if (!m->parent || !m->parent->shared_id) + continue; + + list_for_each_entry(sparent, &m->parent->mnt_share, mnt_share) { + struct mount_info *schild; + + list_for_each_entry(schild, &sparent->children, siblings) { + int ret; + + ret = same_propagation_group(m, schild); + if (ret < 0) + return -1; + else if (ret) { + BUG_ON(!mounts_equal(m, schild)); + pr_debug("\tMount %3d is in same propagation group with %3d (@%s ~ @%s)\n", + m->mnt_id, schild->mnt_id, m->mountpoint, schild->mountpoint); + list_add(&schild->mnt_propagate, &m->mnt_propagate); + } + } + } + } + return 0; } @@ -2700,6 +2797,7 @@ struct mount_info *mnt_entry_alloc() INIT_LIST_HEAD(&new->mnt_slave_list); INIT_LIST_HEAD(&new->mnt_share); INIT_LIST_HEAD(&new->mnt_bind); + INIT_LIST_HEAD(&new->mnt_propagate); INIT_LIST_HEAD(&new->postpone); } return new; From 545b07368cb9f494c78fedc9c028f6bf242158ee Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 10 Jul 2018 19:02:28 +0300 Subject: [PATCH 1645/4375] mount: improve can_mount_now using propagation groups 1) redo waiting for parents of propagation group to be mounted using pre-found propagation groups 2) for shared mount wait for children of that shared group which has no propagation in our shared mount (2) - effectively is a support of non-uniform shares, that means two mounts of shared group can have different sets of children now - we will mount them in the right order, but propagate_mount and validate_shared are still preventing c/r-ing such shares, will fix the former and remove the latter in separate(next) patches. Signed-off-by: Pavel Tikhomirov --- criu/include/mount.h | 1 + criu/mount.c | 77 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/criu/include/mount.h b/criu/include/mount.h index 84c62c8d0..ca17b059a 100644 --- a/criu/include/mount.h +++ b/criu/include/mount.h @@ -66,6 +66,7 @@ struct mount_info { struct list_head mnt_slave; /* slave list entry */ struct mount_info *mnt_master; /* slave is on master->mnt_slave_list */ struct list_head mnt_propagate; /* circular list of mounts which propagate from each other */ + struct list_head mnt_notprop; /* temporary list used in can_mount_now */ struct list_head postpone; diff --git a/criu/mount.c b/criu/mount.c index 1447e086a..3a4b68910 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2456,6 +2456,9 @@ static bool can_mount_now(struct mount_info *mi) if (rst_mnt_is_root(mi)) return true; + /* Parent should be mounted already, that's how mnt_tree_for_each works */ + BUG_ON(mi->parent && !mi->parent->mounted); + if (mi->external) goto shared; @@ -2485,28 +2488,67 @@ static bool can_mount_now(struct mount_info *mi) return false; shared: - if (mi->parent->shared_id) { - struct mount_info *n; + /* Mount only after all parents of our propagation group mounted */ + if (!list_empty(&mi->mnt_propagate)) { + struct mount_info *p; - list_for_each_entry(n, &mi->parent->mnt_share, mnt_share) - /* - * All mounts from mi's parent shared group which - * have mi's 'sibling' should receive it through - * mount propagation, so all such mounts in parent - * shared group should be mounted beforehand. - */ - if (!n->mounted) { - char path[PATH_MAX], *mp; - struct mount_info *c; + list_for_each_entry(p, &mi->mnt_propagate, mnt_propagate) { + BUG_ON(!p->parent); + if (!p->parent->mounted) + return false; + } + } - mp = mnt_get_sibling_path(mi, n, path, sizeof(path)); - if (mp == NULL) + /* + * Mount only after all children of share, which shouldn't + * (but can if wrong order) propagate to us, are mounted + */ + if (mi->shared_id) { + struct mount_info *s, *c, *p, *t; + LIST_HEAD(mi_notprop); + bool can = true; + + /* Add all children of the shared group */ + list_for_each_entry(s, &mi->mnt_share, mnt_share) { + list_for_each_entry(c, &s->children, siblings) { + char root_path[PATH_MAX]; + int ret; + + ret = root_path_from_parent(c, root_path, PATH_MAX); + BUG_ON(ret); + + /* Mount is out of our root */ + if (!issubpath(root_path, mi->root)) continue; - list_for_each_entry(c, &n->children, siblings) - if (mounts_equal(mi, c) && !strcmp(mp, c->mountpoint)) - return false; + list_add(&c->mnt_notprop, &mi_notprop); } + } + + /* Delete all members of our children's propagation groups */ + list_for_each_entry(c, &mi->children, siblings) { + list_for_each_entry(p, &c->mnt_propagate, mnt_propagate) { + list_del_init(&p->mnt_notprop); + } + } + + /* Delete all members of our propagation group */ + list_for_each_entry(p, &mi->mnt_propagate, mnt_propagate) { + list_del_init(&p->mnt_notprop); + } + + /* Delete self */ + list_del_init(&mi->mnt_notprop); + + /* Check not propagated mounts mounted and cleanup list */ + list_for_each_entry_safe(p, t, &mi_notprop, mnt_notprop) { + if (!p->mounted) + can = false; + list_del_init(&p->mnt_notprop); + } + + if (!can) + return false; } return true; @@ -2798,6 +2840,7 @@ struct mount_info *mnt_entry_alloc() INIT_LIST_HEAD(&new->mnt_share); INIT_LIST_HEAD(&new->mnt_bind); INIT_LIST_HEAD(&new->mnt_propagate); + INIT_LIST_HEAD(&new->mnt_notprop); INIT_LIST_HEAD(&new->postpone); } return new; From 69535342cb9a02d922e15cf55e96eda14a8aa19a Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 10 Jul 2018 19:02:29 +0300 Subject: [PATCH 1646/4375] mount: use propagation groups in propagate_mount replacing excess search These also fixes false-propagation problem of the mount to itself if it is in parent's share. Signed-off-by: Pavel Tikhomirov --- criu/mount.c | 54 +++++++++++++++------------------------------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 3a4b68910..91b5a47f3 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2010,7 +2010,7 @@ static int propagate_siblings(struct mount_info *mi) static int propagate_mount(struct mount_info *mi) { - struct mount_info *t; + struct mount_info *p; propagate_siblings(mi); @@ -2019,47 +2019,21 @@ static int propagate_mount(struct mount_info *mi) umount_from_slaves(mi); - /* Propagate this mount to everyone from a parent group */ - - list_for_each_entry(t, &mi->parent->mnt_share, mnt_share) { - struct mount_info *c; - char path[PATH_MAX], *mp; - bool found = false; + /* Mark mounts in propagation group mounted */ + list_for_each_entry(p, &mi->mnt_propagate, mnt_propagate) { + /* Should not propagate the same mount twice */ + BUG_ON(p->mounted); + pr_debug("\t\tPropagate %s\n", p->mountpoint); /* - * If a mount from parent's shared group is not yet mounted - * it shouldn't have 'sibling' in it - see can_mount_now() + * When a mount is propagated, the result mount + * is always shared. If we want to get a private + * mount, we need to convert it. */ - if (!t->mounted) - continue; - - mp = mnt_get_sibling_path(mi, t, path, sizeof(path)); - if (mp == NULL) - continue; - - list_for_each_entry(c, &t->children, siblings) { - if (mounts_equal(mi, c) && !strcmp(mp, c->mountpoint)) { - /* Should not propagate the same mount twice */ - BUG_ON(c->mounted); - pr_debug("\t\tPropagate %s\n", c->mountpoint); - - /* - * When a mount is propagated, the result mount - * is always shared. If we want to get a private - * mount, we need to convert it. - */ - restore_shared_options(c, !c->shared_id, 0, 0); - - c->mounted = true; - propagate_siblings(c); - umount_from_slaves(c); - found = true; - } - } - if (!found) { - pr_err("Unable to find %s\n", mp); - return -1; - } + restore_shared_options(p, !p->shared_id, 0, 0); + p->mounted = true; + propagate_siblings(p); + umount_from_slaves(p); } skip_parent: @@ -2068,6 +2042,8 @@ skip_parent: * only if a proper root mount exists */ if (fsroot_mounted(mi) || mi->parent == root_yard_mp || mi->external) { + struct mount_info *t; + list_for_each_entry(t, &mi->mnt_bind, mnt_bind) { if (t->mounted) continue; From c9cf0b4a08b3fbe9e47a461b8886b197344d099b Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 10 Jul 2018 19:02:30 +0300 Subject: [PATCH 1647/4375] mount: remove validate_shared as now we allow non-uniform sharings Signed-off-by: Pavel Tikhomirov --- criu/mount.c | 104 +-------------------------------------------------- 1 file changed, 1 insertion(+), 103 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 91b5a47f3..b56164e95 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -512,104 +512,6 @@ static int try_resolve_ext_mount(struct mount_info *info) return 0; } -static struct mount_info *find_wider_shared(struct mount_info *m) -{ - struct mount_info *p; - - /* - * Try to find a mount, which is wider or equal. - * A is wider than B, if A->root is a subpath of B->root. - */ - list_for_each_entry(p, &m->mnt_share, mnt_share) - if (issubpath(m->root, p->root)) - return p; - - return NULL; -} - -static struct mount_info *find_shared_peer(struct mount_info *m, - struct mount_info *ct, char *ct_mountpoint) -{ - struct mount_info *cm; - - list_for_each_entry(cm, &m->children, siblings) { - if (strcmp(ct_mountpoint, cm->mountpoint)) - continue; - - if (!mounts_equal(cm, ct)) - break; - - return cm; - } - - return NULL; -} - -static int validate_shared(struct mount_info *m) -{ - struct mount_info *t, *ct; - char buf[PATH_MAX], *sibling_path; - LIST_HEAD(children); - - /* - * Check that all mounts in one shared group has the same set of - * children. Only visible children are accounted. A non-root bind-mount - * doesn't see children out of its root and it's expected case. - * - * Here is a few conditions: - * 1. t is wider than m - * 2. We search a wider mount in the same direction, so when we - * enumerate all mounts, we can't be sure that all of them - * has the same set of children. - */ - - t = find_wider_shared(m); - if (!t) - /* - * The current mount is the widest one in its shared group, - * all others will be compared to it or with some other, - * which will be compared to it. - */ - return 0; - - /* Search a child, which is visible in both mounts. */ - list_for_each_entry(ct, &t->children, siblings) { - struct mount_info *cm; - - if (ct->is_ns_root || ct->mnt_id == CRTIME_MNT_ID) - continue; - - sibling_path = mnt_get_sibling_path(ct, m, buf, sizeof(buf)); - if (sibling_path == NULL) - continue; - - cm = find_shared_peer(m, ct, sibling_path); - if (!cm) - goto err; - - /* - * Keep this one aside. At the end of t's children scan we should - * move _all_ m's children here (the list_empty check below). - */ - list_move(&cm->siblings, &children); - } - - /* Now all real mounts should be moved */ - list_for_each_entry(ct, &m->children, siblings) { - if (ct->mnt_id != CRTIME_MNT_ID) - goto err; - } - - list_splice(&children, &m->children); - return 0; - -err: - list_splice(&children, &m->children); - pr_err("%d:%s and %d:%s have different set of mounts\n", - m->mnt_id, m->mountpoint, t->mnt_id, t->mountpoint); - return -1; -} - /* * Find the mount_info from which the respective bind-mount * can be created. It can be either an FS-root mount, or the @@ -722,9 +624,6 @@ static int validate_mounts(struct mount_info *info, bool for_dump) /* root mount can be any */ continue; - if (m->shared_id && validate_shared(m)) - return -1; - if (validate_children_collision(m)) return -1; @@ -2880,8 +2779,7 @@ static int get_mp_root(MntEntry *me, struct mount_info *mi) * to ->root can confuse mnt_is_external and other functions * which expect to see the path in the file system to the root * of these mount (mounts_equal, mnt_build_ids_tree, - * find_wider_shared, find_fsroot_mount_for, - * find_best_external_match, etc.) + * find_fsroot_mount_for, find_best_external_match, etc.) */ me->root = NO_ROOT_MOUNT; } From 382756a4f5d63e8d87e0f6d857d7ce2482dbb755 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 10 Jul 2018 19:02:31 +0300 Subject: [PATCH 1648/4375] zdtm: add a test for non-uniform shares Create a tree of shared mounts where shared mounts have different sets of children (while having the same root): First share1 is mounted shared tmpfs and second share1/child1 is mounted inside, third share1 is bind-mounted to share2 (now share1 and share2 have the same shared id, but share2 has no child), fourth share1/child2 is bind-mounted from share1, and also propagated to share2/child2 (now all except share1/child1 have the same shared id), fifth share1/child3 is mounted and propagates inside the share. Finally we have four mounts shared between each other with different sets of children mounts, and even more two of them are children of another two: 495 494 0:62 / /zdtm/static/non_uniform_share_propagation.test/share1 rw,relatime shared:235 - tmpfs share rw 496 495 0:63 / /zdtm/static/non_uniform_share_propagation.test/share1/child1 rw,relatime shared:236 - tmpfs child1 rw 497 494 0:62 / /zdtm/static/non_uniform_share_propagation.test/share2 rw,relatime shared:235 - tmpfs share rw 498 495 0:62 / /zdtm/static/non_uniform_share_propagation.test/share1/child2 rw,relatime shared:235 - tmpfs share rw 499 497 0:62 / /zdtm/static/non_uniform_share_propagation.test/share2/child2 rw,relatime shared:235 - tmpfs share rw 500 495 0:64 / /zdtm/static/non_uniform_share_propagation.test/share1/child3 rw,relatime shared:237 - tmpfs child3 rw 503 497 0:64 / /zdtm/static/non_uniform_share_propagation.test/share2/child3 rw,relatime shared:237 - tmpfs child3 rw 502 499 0:64 / /zdtm/static/non_uniform_share_propagation.test/share2/child2/child3 rw,relatime shared:237 - tmpfs child3 rw 501 498 0:64 / /zdtm/static/non_uniform_share_propagation.test/share1/child2/child3 rw,relatime shared:237 - tmpfs child3 rw Signed-off-by: Pavel Tikhomirov --- test/zdtm/static/Makefile | 1 + .../static/non_uniform_share_propagation.c | 131 ++++++++++++++++++ .../static/non_uniform_share_propagation.desc | 1 + 3 files changed, 133 insertions(+) create mode 100644 test/zdtm/static/non_uniform_share_propagation.c create mode 100644 test/zdtm/static/non_uniform_share_propagation.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 6022b8045..d2577e86e 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -338,6 +338,7 @@ TST_DIR = \ sk-unix01 \ unsupported_children_collision \ shared_slave_mount_children \ + non_uniform_share_propagation \ TST_DIR_FILE = \ chroot \ diff --git a/test/zdtm/static/non_uniform_share_propagation.c b/test/zdtm/static/non_uniform_share_propagation.c new file mode 100644 index 000000000..7a18247ab --- /dev/null +++ b/test/zdtm/static/non_uniform_share_propagation.c @@ -0,0 +1,131 @@ +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check non-uniform shares restore fine"; +const char *test_author = "Pavel Tikhomirov "; + +char *dirname; +TEST_OPTION(dirname, string, "directory name", 1); + +int main(int argc, char **argv) +{ + char share1[PATH_MAX], share2[PATH_MAX]; + char child1[PATH_MAX], child2[PATH_MAX], child3[PATH_MAX]; + + test_init(argc, argv); + + if (mkdir(dirname, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("zdtm_fs", dirname, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, dirname, NULL, MS_PRIVATE, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(share1, sizeof(share1), "%s/share1", dirname); + if (mkdir(share1, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("share", share1, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, share1, NULL, MS_SHARED, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(child1, sizeof(child1), "%s/share1/child1", dirname); + if (mkdir(child1, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("child1", child1, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(share2, sizeof(share2), "%s/share2", dirname); + if (mkdir(share2, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount(share1, share2, NULL, MS_BIND, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(child2, sizeof(child2), "%s/share1/child2", dirname); + if (mkdir(child2, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount(share1, child2, NULL, MS_BIND, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(child3, sizeof(child3), "%s/share1/child3", dirname); + if (mkdir(child3, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("child3", child3, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (umount(child3)) { + pr_perror("Unable to umount %s", child1); + return 1; + } + + if (umount(child2)) { + pr_perror("Unable to umount %s", share1); + return 1; + } + + if (umount(share2)) { + pr_perror("Unable to umount %s", share2); + return 1; + } + + if (umount(child1)) { + pr_perror("Unable to umount %s", child1); + return 1; + } + + if (umount(share1)) { + pr_perror("Unable to umount %s", share1); + return 1; + } + + if (umount(dirname)) { + pr_perror("Unable to umount %s", dirname); + return 1; + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/non_uniform_share_propagation.desc b/test/zdtm/static/non_uniform_share_propagation.desc new file mode 100644 index 000000000..7657ba45c --- /dev/null +++ b/test/zdtm/static/non_uniform_share_propagation.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns', 'flags': 'suid'} From e54d0d26ba634328fca71d6b4fe017ee0f76e2c5 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 11 Jul 2018 13:43:33 +0300 Subject: [PATCH 1649/4375] mount: fix regression where open_mountpoint failed on readonly fs If we fail to create temporary directory for doing a clean mount we can make mount clean reusing the code which enters new mountns to umount overmounts. As when last process exits mntns all mounts are implicitly cleaned from children, see in kernel source - sys_exit->do_exit ->exit_task_namespaces->switch_task_namespaces->free_nsproxy ->put_mnt_ns->umount_tree->drop_collected_mounts->umount_tree: /* Hide the mounts from mnt_mounts */ list_for_each_entry(p, &tmp_list, mnt_list) { list_del_init(&p->mnt_child); } Fixes commit b6cfb1ce2948 ("mount: make open_mountpoint handle overmouts properly") https://github.com/checkpoint-restore/criu/issues/520 Signed-off-by: Pavel Tikhomirov Acked-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/mount.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index b56164e95..9cc8f6e94 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1325,10 +1325,18 @@ int ns_open_mountpoint(void *arg) if (umount_overmounts(mi)) goto err; - /* Save fd which we opened for parent due to CLONE_FILES flag */ - *fd = get_clean_fd(mi); - if (*fd < 0) + /* + * Save fd which we opened for parent due to CLONE_FILES flag + * + * Mount can still have children in it, but we don't need to clean it + * explicitly as when last process exits mntns all mounts in it are + * cleaned from their children, and we are exactly the last process. + */ + *fd = open(mi->mountpoint, O_DIRECTORY|O_RDONLY); + if (*fd < 0) { + pr_perror("Unable to open %s", mi->mountpoint); goto err; + } return 0; err: @@ -1367,18 +1375,22 @@ int open_mountpoint(struct mount_info *pm) if (!mnt_is_overmounted(pm)) { pr_info("\tmount has children %s\n", pm->mountpoint); - fd = get_clean_fd(pm); - if (fd < 0) - goto err; - } else { + } + + /* + * Mount is overmounted or probably we can't create a temporary + * direcotry for a cleaned mount + */ + if (fd < 0) { int pid, status; struct clone_arg ca = { .mi = pm, .fd = &fd }; - pr_info("\tmount is overmounted %s\n", pm->mountpoint); + pr_info("\tmount is overmounted or has children %s\n", + pm->mountpoint); /* * We are overmounted - not accessible in a regular way. We From 868de91a099c00f099d8a41557d660d173f72521 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 2 Jul 2018 21:43:45 +0100 Subject: [PATCH 1650/4375] kdat: Don't open /run/criu.kdat if doesn't exists When CRIU is called for a first time and the /run/criu.kdat file does not exists, the following warning is shown: Warn (criu/kerndat.c:847): Can't load /run/criu.kdat This patch is replacing this warning with a more appropriate debug message. File /run/criu.kdat does not exist Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/kerndat.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/criu/kerndat.c b/criu/kerndat.c index 3cb407c91..b884f6d15 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -835,7 +835,10 @@ static int kerndat_try_load_cache(void) fd = open(KERNDAT_CACHE_FILE, O_RDONLY); if (fd < 0) { - pr_warn("Can't load %s\n", KERNDAT_CACHE_FILE); + if(ENOENT == errno) + pr_debug("File %s does not exist\n", KERNDAT_CACHE_FILE); + else + pr_warn("Can't load %s\n", KERNDAT_CACHE_FILE); return 1; } From 6c81e8773e61f9789aebfddd546e5be6bae3ac9f Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 25 Jun 2018 15:53:36 +0300 Subject: [PATCH 1651/4375] zdtm.py: also check that sharing options are restored for mounts We already check (root, mountpoint) pairs preserve, do the same for (root, mountpoint, shared, slave) fours. Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 17306341a..99ec6aaac 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1278,7 +1278,7 @@ def get_visible_state(test): cmounts = [] try: - r = re.compile("^\S+\s\S+\s\S+\s(\S+)\s(\S+)") + r = re.compile("^\S+\s\S+\s\S+\s(\S+)\s(\S+)\s\S+\s[^-]*?(shared)?[^-]*?(master)?[^-]*?-") for m in open("/proc/%s/root/proc/%s/mountinfo" % (test.getpid(), pid)): cmounts.append(r.match(m).groups()) except IOError as e: From 3a66660e3ea0d0833563d13ba0921502de55aff1 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 25 Jun 2018 15:53:37 +0300 Subject: [PATCH 1652/4375] zdtm: shared options should not be lost for bind mounts 1150 1371 0:169 / /zdtm/static/private_bind_propagation.test rw,relatime shared:920 - tmpfs zdtm_fs rw 1151 1150 0:170 / /zdtm/static/private_bind_propagation.test/share1 rw,relatime shared:921 - tmpfs share rw 1152 1150 0:170 / /zdtm/static/private_bind_propagation.test/share2 rw,relatime shared:921 - tmpfs share rw 1153 1151 0:169 /source /zdtm/static/private_bind_propagation.test/share1/child rw,relatime - tmpfs zdtm_fs rw 1154 1152 0:169 /source /zdtm/static/private_bind_propagation.test/share2/child rw,relatime - tmpfs zdtm_fs rw Signed-off-by: Pavel Tikhomirov --- test/zdtm/static/Makefile | 1 + test/zdtm/static/private_bind_propagation.c | 116 ++++++++++++++++++ .../zdtm/static/private_bind_propagation.desc | 1 + 3 files changed, 118 insertions(+) create mode 100644 test/zdtm/static/private_bind_propagation.c create mode 100644 test/zdtm/static/private_bind_propagation.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index d2577e86e..fe67747db 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -339,6 +339,7 @@ TST_DIR = \ unsupported_children_collision \ shared_slave_mount_children \ non_uniform_share_propagation \ + private_bind_propagation \ TST_DIR_FILE = \ chroot \ diff --git a/test/zdtm/static/private_bind_propagation.c b/test/zdtm/static/private_bind_propagation.c new file mode 100644 index 000000000..ee4adbd2d --- /dev/null +++ b/test/zdtm/static/private_bind_propagation.c @@ -0,0 +1,116 @@ +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check sharing options are restored for bindmounted shared group children"; +const char *test_author = "Pavel Tikhomirov "; + +char *dirname; +TEST_OPTION(dirname, string, "directory name", 1); + +int main(int argc, char **argv) +{ + char share1[PATH_MAX], share2[PATH_MAX], source[PATH_MAX]; + char child1[PATH_MAX], child2[PATH_MAX]; + + test_init(argc, argv); + + if (mkdir(dirname, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("zdtm_fs", dirname, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, dirname, NULL, MS_SHARED, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(share1, sizeof(share1), "%s/share1", dirname); + if (mkdir(share1, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("share", share1, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, share1, NULL, MS_SHARED, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(share2, sizeof(share2), "%s/share2", dirname); + if (mkdir(share2, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount(share1, share2, NULL, MS_BIND, NULL)) { + pr_perror("mount"); + return 1; + } + + snprintf(source, sizeof(source), "%s/source", dirname); + if (mkdir(source, 0700)) { + pr_perror("mkdir"); + return 1; + } + + snprintf(child1, sizeof(child1), "%s/share1/child", dirname); + snprintf(child2, sizeof(child2), "%s/share1/child", dirname); + if (mkdir(child1, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount(source, child1, NULL, MS_BIND, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, child1, NULL, MS_PRIVATE, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, child2, NULL, MS_PRIVATE, NULL)) { + pr_perror("mount"); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (umount(child1)) { + pr_perror("Unable to umount %s", child1); + return 1; + } + + if (umount(share1)) { + pr_perror("Unable to umount %s", share1); + return 1; + } + + if (umount(share2)) { + pr_perror("Unable to umount %s", share2); + return 1; + } + + if (umount(dirname)) { + pr_perror("Unable to umount %s", dirname); + return 1; + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/private_bind_propagation.desc b/test/zdtm/static/private_bind_propagation.desc new file mode 100644 index 000000000..7657ba45c --- /dev/null +++ b/test/zdtm/static/private_bind_propagation.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns', 'flags': 'suid'} From 3e4cecb996ad75bba7543883aa24a55da1457c24 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 23 Jul 2018 19:11:31 +0300 Subject: [PATCH 1653/4375] net: read network namespace images before forking tasks We need to know which namespaces are external to restore them properly. Acked-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/include/net.h | 1 + criu/namespaces.c | 3 +++ criu/net.c | 48 ++++++++++++++++++++++++++++++++-------------- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/criu/include/net.h b/criu/include/net.h index 1f6be068d..38b33a727 100644 --- a/criu/include/net.h +++ b/criu/include/net.h @@ -50,5 +50,6 @@ extern int net_get_nsid(int rtsk, int fd, int *nsid); extern struct ns_id *net_get_root_ns(); extern int kerndat_nsid(void); extern void check_has_netns_ioc(int fd, bool *kdat_val, const char *name); +extern int read_net_ns_img(); #endif /* __CR_NET_H__ */ diff --git a/criu/namespaces.c b/criu/namespaces.c index 87a8dadb2..f58f310ad 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -1739,6 +1739,9 @@ int prepare_namespace_before_tasks(void) if (read_mnt_ns_img()) goto err_img; + if (read_net_ns_img()) + goto err_img; + return 0; err_img: diff --git a/criu/net.c b/criu/net.c index cf3ef5cbf..e0e537a7c 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2048,26 +2048,47 @@ out: return ret; } +int read_net_ns_img(void) +{ + struct ns_id *ns; + + for (ns = ns_ids; ns != NULL; ns = ns->next) { + struct cr_img *img; + int ret; + + if (ns->nd != &net_ns_desc) + continue; + + img = open_image(CR_FD_NETNS, O_RSTR, ns->id); + if (!img) + return -1; + + if (empty_image(img)) { + /* Backward compatibility */ + close_image(img); + continue; + } + + ret = pb_read_one(img, &ns->net.netns, PB_NETNS); + close_image(img); + if (ret < 0) { + pr_err("Can not read netns object\n"); + return -1; + } + } + + return 0; +} + static int restore_netns_conf(struct ns_id *ns) { - NetnsEntry *netns; + NetnsEntry *netns = ns->net.netns; int ret = 0; - struct cr_img *img; - img = open_image(CR_FD_NETNS, O_RSTR, ns->id); - if (!img) - return -1; - - if (empty_image(img)) + if (ns->net.netns == NULL) /* Backward compatibility */ goto out; - ret = pb_read_one(img, &netns, PB_NETNS); - if (ret < 0) { - pr_err("Can not read netns object\n"); - return -1; - } - if ((netns)->def_conf4) { ret = ipv4_conf_op("all", (netns)->all_conf4, (netns)->n_all_conf4, CTL_WRITE, NULL); if (ret) @@ -2094,7 +2115,6 @@ static int restore_netns_conf(struct ns_id *ns) ns->net.netns = netns; out: - close_image(img); return ret; } From c2b21fbf4baa5b134e90d9daf863b770b7518c73 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 24 Jul 2018 06:14:02 +0300 Subject: [PATCH 1654/4375] criu: add support for external net namespaces It works like other external resources. A user specify which namespaces are external and have not to be dumped. On restore, the user gives file descriptors to preconfigured namespaces. How to use: dump: --external net[INO]:KEY restore: --inherit-fd fd[NSFD]:KEY The test script contains more details how to use this: test/others/netns_ext/run.sh Acked-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 6 ++++- criu/include/namespaces.h | 1 + criu/include/net.h | 2 ++ criu/net.c | 49 +++++++++++++++++++++++++++++++++++---- images/netdev.proto | 1 + 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index ad28bbceb..833b44e82 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1673,7 +1673,11 @@ static int restore_task_with_children(void *_arg) * ACT_SETUP_NS scripts, so the root netns has to be created here */ if (root_ns_mask & CLONE_NEWNET) { - ret = unshare(CLONE_NEWNET); + struct ns_id *ns = net_get_root_ns(); + if (ns->ext_key) + ret = net_set_ext(ns); + else + ret = unshare(CLONE_NEWNET); if (ret) { pr_perror("Can't unshare net-namespace"); goto err; diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index c0ad0f419..5fe8038bf 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -91,6 +91,7 @@ struct ns_id { struct ns_desc *nd; struct ns_id *next; enum ns_type type; + char *ext_key; /* * For mount namespaces on restore -- indicates that diff --git a/criu/include/net.h b/criu/include/net.h index 38b33a727..9976f6eb0 100644 --- a/criu/include/net.h +++ b/criu/include/net.h @@ -50,6 +50,8 @@ extern int net_get_nsid(int rtsk, int fd, int *nsid); extern struct ns_id *net_get_root_ns(); extern int kerndat_nsid(void); extern void check_has_netns_ioc(int fd, bool *kdat_val, const char *name); +extern int net_set_ext(struct ns_id *ns); +extern struct ns_id *get_root_netns(); extern int read_net_ns_img(); #endif /* __CR_NET_H__ */ diff --git a/criu/net.c b/criu/net.c index e0e537a7c..cbd03dd0a 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2075,6 +2075,7 @@ int read_net_ns_img(void) pr_err("Can not read netns object\n"); return -1; } + ns->ext_key = ns->net.netns->ext_key; } return 0; @@ -2198,6 +2199,22 @@ static int dump_netns_ids(int rtsk, struct ns_id *ns) (void *)&arg); } +int net_set_ext(struct ns_id *ns) +{ + int fd, ret; + + fd = inherit_fd_lookup_id(ns->ext_key); + if (fd < 0) { + pr_err("Unable to find an external netns: %s\n", ns->ext_key); + return -1; + } + + ret = switch_ns_by_fd(fd, &net_ns_desc, NULL); + close(fd); + + return ret; +} + int dump_net_ns(struct ns_id *ns) { struct cr_imgset *fds; @@ -2208,7 +2225,14 @@ int dump_net_ns(struct ns_id *ns) return -1; ret = mount_ns_sysfs(); - if (!(opts.empty_ns & CLONE_NEWNET)) { + if (ns->ext_key) { + NetnsEntry netns = NETNS_ENTRY__INIT; + + netns.ext_key = ns->ext_key; + ret = pb_write_one(img_from_set(fds, CR_FD_NETNS), &netns, PB_NETNS); + if (ret) + goto out; + } else if (!(opts.empty_ns & CLONE_NEWNET)) { int sk; sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); @@ -2252,6 +2276,7 @@ int dump_net_ns(struct ns_id *ns) if (!ret) ret = dump_nf_ct(fds, CR_FD_NETNF_EXP); +out: close(ns_sysfs_fd); ns_sysfs_fd = -1; @@ -2305,7 +2330,7 @@ static int prepare_net_ns_first_stage(struct ns_id *ns) { int ret = 0; - if (opts.empty_ns & CLONE_NEWNET) + if (ns->ext_key || (opts.empty_ns & CLONE_NEWNET)) return 0; ret = restore_netns_conf(ns); @@ -2321,7 +2346,7 @@ static int prepare_net_ns_second_stage(struct ns_id *ns) { int ret = 0, nsid = ns->id; - if (!(opts.empty_ns & CLONE_NEWNET)) { + if (!(opts.empty_ns & CLONE_NEWNET) && !ns->ext_key) { if (ns->net.netns) netns_entry__free_unpacked(ns->net.netns, NULL); @@ -2369,7 +2394,14 @@ static int open_net_ns(struct ns_id *nsid) static int do_create_net_ns(struct ns_id *ns) { - if (unshare(CLONE_NEWNET)) { + int ret; + + if (ns->ext_key) + ret = net_set_ext(ns); + else + ret = unshare(CLONE_NEWNET); + + if (ret) { pr_perror("Unable to create a new netns"); return -1; } @@ -2716,9 +2748,18 @@ static int netns_nr; static int collect_net_ns(struct ns_id *ns, void *oarg) { bool for_dump = (oarg == (void *)1); + char id[64], *val; int ret; pr_info("Collecting netns %d/%d\n", ns->id, ns->ns_pid); + + snprintf(id, sizeof(id), "net[%u]", ns->kid); + val = external_lookup_by_key(id); + if (!IS_ERR_OR_NULL(val)) { + pr_debug("The %s netns is external\n", id); + ns->ext_key = val; + } + ret = prep_ns_sockets(ns, for_dump); if (ret) return ret; diff --git a/images/netdev.proto b/images/netdev.proto index b4b64d2cc..476a92ced 100644 --- a/images/netdev.proto +++ b/images/netdev.proto @@ -70,4 +70,5 @@ message netns_entry { repeated sysctl_entry all_conf6 = 6; repeated netns_id nsids = 7; + optional string ext_key = 8; } From 15b4d9205ba2d5bd196a6e295c0f090cc53c843a Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 23 Jul 2018 19:08:54 +0300 Subject: [PATCH 1655/4375] test/others: check external network namespaces Acked-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/others/netns_ext/Makefile | 2 ++ test/others/netns_ext/_run.sh | 4 ++++ test/others/netns_ext/run.sh | 40 ++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 test/others/netns_ext/Makefile create mode 100644 test/others/netns_ext/_run.sh create mode 100755 test/others/netns_ext/run.sh diff --git a/test/others/netns_ext/Makefile b/test/others/netns_ext/Makefile new file mode 100644 index 000000000..7779a9903 --- /dev/null +++ b/test/others/netns_ext/Makefile @@ -0,0 +1,2 @@ +run: + ./run.sh diff --git a/test/others/netns_ext/_run.sh b/test/others/netns_ext/_run.sh new file mode 100644 index 000000000..59070fb1b --- /dev/null +++ b/test/others/netns_ext/_run.sh @@ -0,0 +1,4 @@ +echo $$ > $1 +while :; do + sleep 1 +done diff --git a/test/others/netns_ext/run.sh b/test/others/netns_ext/run.sh new file mode 100755 index 000000000..6de6c5ad8 --- /dev/null +++ b/test/others/netns_ext/run.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +set -e + +CRIU=../../../criu/criu +setsid unshare -n bash -c 'unshare -n sh _run.sh pidfile2 & unshare -n sh _run.sh pidfile3 & ip link add xxx type veth && ip link add mymacvlan1 link xxx type macvlan mode bridge && . _run.sh pidfile' < /dev/zero &> output & +sleep 1 +while :; do + test -f pidfile && test -f pidfile2 && break; + sleep 0.1 +done + +pid=$(cat pidfile) +pid2=$(cat pidfile2) + +touch test_netns +mount --bind /proc/$pid/ns/net test_netns +touch test_netns2 +mount --bind /proc/$pid2/ns/net test_netns2 +mkdir -p images +ino=$(ls -iL test_netns | awk '{ print $1 }') +ino2=$(ls -iL test_netns2 | awk '{ print $1 }') +exec 33< test_netns +exec 34< test_netns2 +$CRIU dump -t $pid -o dump.log -D images --external net[$ino]:test_netns --external net[$ino2]:test_netns2 +cat images/dump.log | grep -B 5 Error || echo ok +$CRIU restore -o restore.log -D images --inherit-fd fd[33]:test_netns --inherit-fd fd[34]:test_netns2 -d +cat images/restore.log | grep -B 5 Error || echo ok +new_ino=$(ls -iL /proc/$pid/ns/net | awk '{ print $1 }') +new_ino2=$(ls -iL /proc/$pid2/ns/net | awk '{ print $1 }') +[ "$ino" -ne "$new_ino" ] && { + echo FAIL + exit 1 +} +[ "$ino2" -ne "$new_ino2" ] && { + echo FAIL + exit 1 +} +echo PASS +exit 0 From bab6c7b74b32bd15e0741310c876ceb6cfbca063 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 24 Jul 2018 18:18:29 +0200 Subject: [PATCH 1656/4375] config: fix valgrind leak Running 'criu dump -t ' with a configuration file under valgrind where does not exist, gives: ==14336== 600 bytes in 5 blocks are definitely lost in loss record 5 of 5 ==14336== at 0x4C29BC3: malloc (vg_replace_malloc.c:299) ==14336== by 0x5D387A4: getdelim (in /usr/lib64/libc-2.17.so) ==14336== by 0x439829: getline (stdio.h:117) ==14336== by 0x439829: parse_config (config.c:69) ==14336== by 0x439CB2: init_configuration.isra.1 (config.c:159) ==14336== by 0x439F75: init_config (config.c:212) ==14336== by 0x439F75: parse_options (config.c:487) ==14336== by 0x42499F: main (crtools.c:140) ==14336== LEAK SUMMARY: ==14336== definitely lost: 600 bytes in 5 blocks With this patch: ==17892== LEAK SUMMARY: ==17892== definitely lost: 0 bytes in 0 blocks Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/config.c b/criu/config.c index f3bf35b5f..a39696dc3 100644 --- a/criu/config.c +++ b/criu/config.c @@ -121,9 +121,11 @@ static char ** parse_config(char *filepath) } i++; } + free(line); line = NULL; } + free(line); fclose(configfile); return configuration; } From 69663091336e7f318ea4b0608d90a810ff81e89e Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 24 Jul 2018 12:55:02 +0300 Subject: [PATCH 1657/4375] mount: fix segmentation fault in can_mount_now on no mnt_master In resolve_shared_mounts there are cases when we have m->master_id > 0 but m->mnt_master is not set, it happens for cases where we have no access to master mount, for instance CT root m->parent==NULL or when mount is external. In can_mount_now for such master mounts we don't need to check mounted state also, so just use "if(mi->mnt_master)" condition instead of "if(mi->master_id > 0)" to fix segfault. https://jira.sw.ru/browse/PSBM-86978 Program terminated with signal 11, Segmentation fault. 0x000000000046328b in can_mount_now (mi=0x2155970) at criu/mount.c:2699 2699 list_for_each_entry(c, &mi->mnt_master->children, siblings) (gdb) p mi->mnt_master $2 = (struct mount_info *) 0x0 Fixes commit 3a02362c5be1 ("mount: fix can_mount_now to wait children of master's share properly") Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/mount.c b/criu/mount.c index 9cc8f6e94..d2292cd8e 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2355,7 +2355,7 @@ static bool can_mount_now(struct mount_info *mi) * - Make sure all children of master's share are * mounted as well to eliminate mounts duplications */ - if (mi->master_id > 0) { + if (mi->mnt_master) { struct mount_info *c, *s; if (mi->bind == NULL) From 9bb44e6f11fc1c3a099ea77cc2795164d4f5ccfd Mon Sep 17 00:00:00 2001 From: Pawel Stradomski Date: Tue, 24 Jul 2018 12:12:27 +0200 Subject: [PATCH 1658/4375] Punch holes in input files when restoring anonymous non-shared memory if --auto-dedup is enabled. This reduces memory usage if image files are stored on tmpfs. Signed-off-by: Pawel Stradomski Signed-off-by: Andrei Vagin --- .../arch/arm/plugins/std/syscalls/syscall.def | 1 + .../plugins/std/syscalls/syscall-ppc64.tbl | 1 + .../plugins/std/syscalls/syscall-s390.tbl | 1 + .../x86/plugins/std/syscalls/syscall_32.tbl | 1 + .../x86/plugins/std/syscalls/syscall_64.tbl | 1 + criu/cr-restore.c | 2 ++ criu/include/restorer.h | 1 + criu/mem.c | 6 ++++- criu/pie/restorer.c | 26 +++++++++++++++++++ 9 files changed, 39 insertions(+), 1 deletion(-) diff --git a/compel/arch/arm/plugins/std/syscalls/syscall.def b/compel/arch/arm/plugins/std/syscalls/syscall.def index b68f9f2f2..bcd61d4a1 100644 --- a/compel/arch/arm/plugins/std/syscalls/syscall.def +++ b/compel/arch/arm/plugins/std/syscalls/syscall.def @@ -109,3 +109,4 @@ seccomp 277 383 (unsigned int op, unsigned int flags, const char *uargs) gettimeofday 169 78 (struct timeval *tv, struct timezone *tz) preadv_raw 69 361 (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) userfaultfd 282 388 (int flags) +fallocate 47 352 (int fd, int mode, loff_t offset, loff_t len) diff --git a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl index fa0b034ee..62e0bc1a0 100644 --- a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl +++ b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl @@ -89,6 +89,7 @@ __NR_set_robust_list 300 sys_set_robust_list (struct robust_list_head *head, si __NR_get_robust_list 299 sys_get_robust_list (int pid, struct robust_list_head **head_ptr, size_t *len_ptr) __NR_vmsplice 285 sys_vmsplice (int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags) __NR_openat 286 sys_openat (int dfd, const char *filename, int flags, int mode) +__NR_fallocate 309 sys_fallocate (int fd, int mode, loff_t offset, loff_t len) __NR_timerfd_settime 311 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) __NR_signalfd4 313 sys_signalfd (int fd, k_rtsigset_t *mask, size_t sizemask, int flags) __NR_rt_tgsigqueueinfo 322 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *info) diff --git a/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl b/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl index bc77ae970..3521e9150 100644 --- a/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl +++ b/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl @@ -89,6 +89,7 @@ __NR_set_robust_list 304 sys_set_robust_list (struct robust_list_head *head, si __NR_get_robust_list 305 sys_get_robust_list (int pid, struct robust_list_head **head_ptr, size_t *len_ptr) __NR_vmsplice 309 sys_vmsplice (int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags) __NR_openat 288 sys_openat (int dfd, const char *filename, int flags, int mode) +__NR_fallocate 314 sys_fallocate (int fd, int mode, loff_t offset, loff_t len) __NR_timerfd_settime 320 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) __NR_signalfd4 322 sys_signalfd (int fd, k_rtsigset_t *mask, size_t sizemask, int flags) __NR_rt_tgsigqueueinfo 330 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *info) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl index 9e1de2815..a6c55b83c 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl @@ -83,6 +83,7 @@ __NR_set_robust_list 311 sys_set_robust_list (struct robust_list_head *head, si __NR_get_robust_list 312 sys_get_robust_list (int pid, struct robust_list_head **head_ptr, size_t *len_ptr) __NR_vmsplice 316 sys_vmsplice (int fd, const struct iovec *iov, unsigned int nr_segs, unsigned int flags) __NR_signalfd 321 sys_signalfd (int ufd, const k_rtsigset_t *sigmask, size_t sigsetsize) +__NR_fallocate 324 sys_fallocate (int fd, int mode, loff_t offset, loff_t len) __NR_timerfd_settime 325 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) __NR_preadv 333 sys_preadv_raw (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) __NR_rt_tgsigqueueinfo 335 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *uinfo) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl index 726fa7970..642715147 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl @@ -94,6 +94,7 @@ __NR_set_robust_list 273 sys_set_robust_list (struct robust_list_head *head, s __NR_get_robust_list 274 sys_get_robust_list (int pid, struct robust_list_head **head_ptr, size_t *len_ptr) __NR_seccomp 317 sys_seccomp (unsigned int op, unsigned int flags, const char *uargs) __NR_vmsplice 278 sys_vmsplice (int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags) +__NR_fallocate 285 sys_fallocate (int fd, int mode, loff_t offset, loff_t len) __NR_timerfd_settime 286 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) __NR_signalfd4 289 sys_signalfd (int fd, k_rtsigset_t *mask, size_t sizemask, int flags) __NR_preadv 295 sys_preadv_raw (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 833b44e82..edbce5d1f 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3495,6 +3495,8 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns task_args->nr_threads = current->nr_threads; task_args->thread_args = thread_args; + task_args->auto_dedup = opts.auto_dedup; + /* * Make root and cwd restore _that_ late not to break any * attempts to open files by paths above (e.g. /proc). diff --git a/criu/include/restorer.h b/criu/include/restorer.h index af1718cb9..fd94de6ca 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -202,6 +202,7 @@ struct task_restore_args { bool compatible_mode; bool can_map_vdso; + bool auto_dedup; #ifdef CONFIG_VDSO unsigned long vdso_rt_size; struct vdso_maps vdso_maps_rt; /* runtime vdso symbols */ diff --git a/criu/mem.c b/criu/mem.c index d020b7fd4..44d0e2585 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -1271,7 +1271,11 @@ static int prepare_vma_ios(struct pstree_item *t, struct task_restore_args *ta) { struct cr_img *pages; - pages = open_image(CR_FD_PAGES, O_RSTR, rsti(t)->pages_img_id); + /* if auto-dedup is on we need RDWR mode to be able to punch holes + * in the input files (in restorer.c) + */ + pages = open_image(CR_FD_PAGES, opts.auto_dedup ? O_RDWR : O_RSTR, + rsti(t)->pages_img_id); if (!pages) return -1; diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index fe52d444d..e5a40a977 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -51,6 +51,15 @@ #define PR_SET_PDEATHSIG 1 #endif +#ifndef FALLOC_FL_KEEP_SIZE +#define FALLOC_FL_KEEP_SIZE 0x01 +#endif + +#ifndef FALLOC_FL_PUNCH_HOLE +#define FALLOC_FL_PUNCH_HOLE 0x02 +#endif + + #define sys_prctl_safe(opcode, val1, val2, val3) \ ({ \ long __ret = sys_prctl(opcode, val1, val2, val3, 0); \ @@ -647,6 +656,14 @@ static unsigned long restore_mapping(VmaEntry *vma_entry) !(vma_entry->status & VMA_NO_PROT_WRITE)) prot |= PROT_WRITE; + /* TODO: Drop MAP_LOCKED bit and restore it after reading memory. + * + * Code below tries to limit memory usage by running fallocate() + * after each preadv() to avoid doubling memory usage (once in + * image files, once in process). Unfortunately, MAP_LOCKED defeats + * that mechanism as it causes the process to be charged for memory + * immediately upon mmap, not later upon preadv(). + */ pr_debug("\tmmap(%"PRIx64" -> %"PRIx64", %x %x %d)\n", vma_entry->start, vma_entry->end, prot, flags, (int)vma_entry->fd); @@ -1368,6 +1385,15 @@ long __export_restore_task(struct task_restore_args *args) } pr_debug("`- returned %ld\n", (long)r); + /* If the file is open for writing, then it means we should punch holes + * in it. */ + if (r > 0 && args->auto_dedup) { + int fr = sys_fallocate(args->vma_ios_fd, FALLOC_FL_KEEP_SIZE|FALLOC_FL_PUNCH_HOLE, + rio->off, r); + if (fr < 0) { + pr_debug("Failed to punch holes with fallocate: %d\n", fr); + } + } rio->off += r; /* Advance the iovecs */ do { From 6ef193b0a0fe7a3341f71c43a955a5ea4be6f068 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 25 Jul 2018 22:40:27 +0300 Subject: [PATCH 1659/4375] test: check criu restore with --auto-dedup Signed-off-by: Andrei Vagin --- test/zdtm.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index 99ec6aaac..2a3742f8f 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1105,6 +1105,9 @@ class criu: r_opts += ['--empty-ns', 'net'] r_opts += ['--action-script', os.getcwd() + '/empty-netns-prep.sh'] + if self.__dedup: + r_opts += ["--auto-dedup"] + self.__prev_dump_iter = None criu_dir = os.path.dirname(os.getcwd()) if os.getenv("GCOV"): From bc7d57ebadc00bff01e8e90ccc2600687eb6d025 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:29 +0300 Subject: [PATCH 1660/4375] log: Setup loglevel early We're printing messages before the log file is set up, so instead of keeping silence lets print data in default outputs. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/crtools.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/crtools.c b/criu/crtools.c index 829e5d796..2f89b69cf 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -700,6 +700,8 @@ int main(int argc, char *argv[], char *envp[]) } } + log_set_loglevel(log_level); + if (early_init()) return -1; @@ -796,7 +798,6 @@ int main(int argc, char *argv[], char *envp[]) return 1; } - log_set_loglevel(log_level); if (log_init(opts.output)) return 1; From e319aaa0cf489488d7796b6abea7f88a21d6e07f Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:30 +0300 Subject: [PATCH 1661/4375] compiler: Add FIELD_SIZEOF helper Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- include/common/compiler.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/common/compiler.h b/include/common/compiler.h index ada79f293..eaf545b26 100644 --- a/include/common/compiler.h +++ b/include/common/compiler.h @@ -57,6 +57,10 @@ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) +#ifndef FIELD_SIZEOF +# define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) +#endif + #define __round_mask(x, y) ((__typeof__(x))((y) - 1)) #define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1) #define round_down(x, y) ((x) & ~__round_mask(x, y)) From f0fb0bc964f70bc4c890e294f0034d9609b466da Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:31 +0300 Subject: [PATCH 1662/4375] x86: cpu -- Add image definitions for fpu frames Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- images/core-x86.proto | 21 +++++++++++++++++++++ images/cpuinfo.proto | 2 ++ 2 files changed, 23 insertions(+) diff --git a/images/core-x86.proto b/images/core-x86.proto index d4b791dbc..2ed2ad35d 100644 --- a/images/core-x86.proto +++ b/images/core-x86.proto @@ -40,8 +40,29 @@ message user_x86_regs_entry { } message user_x86_xsave_entry { + /* standart xsave features */ required uint64 xstate_bv = 1; + + /* AVX components: 16x 256-bit ymm registers, hi 128 bits */ repeated uint32 ymmh_space = 2; + + /* MPX components */ + repeated uint64 bndreg_state = 3; + repeated uint64 bndcsr_state = 4; + + /* AVX512 components: k0-k7, ZMM_Hi256, Hi16_ZMM */ + repeated uint64 opmask_reg = 5; + repeated uint64 zmm_upper = 6; + repeated uint64 hi16_zmm = 7; + + /* Protected keys */ + repeated uint32 pkru = 8; + + /* + * Processor trace (PT) and hardware duty cycling (HDC) + * are supervisor state components and only managed by + * xsaves/xrstors on cpl=0, so ignore them. + */ } message user_x86_fpregs_entry { diff --git a/images/cpuinfo.proto b/images/cpuinfo.proto index a8cb8de34..b399503bd 100644 --- a/images/cpuinfo.proto +++ b/images/cpuinfo.proto @@ -15,6 +15,8 @@ message cpuinfo_x86_entry { repeated uint32 capability = 6; optional string model_id = 7; + + optional uint64 xfeatures_mask = 8; } message cpuinfo_ppc64_entry { From 3c4dfb6ef413ca40c9614b25d2fb931c72a669e2 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:32 +0300 Subject: [PATCH 1663/4375] x86: cpu -- Detect and save fpu status in info - externd compel_cpuinfo_t to keep all fpu information neded for xsaves mode - fetch xsaves data in compel_cpuid All this will allow us to extend criu to support avx-512 intructions. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/cpu.c | 206 +++++++++++++++++- .../arch/x86/src/lib/include/uapi/asm/cpu.h | 15 ++ .../arch/x86/src/lib/include/uapi/asm/fpu.h | 185 +++++++++++++++- 3 files changed, 399 insertions(+), 7 deletions(-) diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c index 93e430fac..4657f9723 100644 --- a/compel/arch/x86/src/lib/cpu.c +++ b/compel/arch/x86/src/lib/cpu.c @@ -6,6 +6,7 @@ #include "common/compiler.h" #include "log.h" +#include "common/bug.h" #undef LOG_PREFIX #define LOG_PREFIX "cpu: " @@ -13,6 +14,40 @@ static compel_cpuinfo_t rt_info; static bool rt_info_done = false; +/* + * Although we spell it out in here, the Processor Trace + * xfeature is completely unused. We use other mechanisms + * to save/restore PT state in Linux. + */ + +static const char * const xfeature_names[] = { + "x87 floating point registers" , + "SSE registers" , + "AVX registers" , + "MPX bounds registers" , + "MPX CSR" , + "AVX-512 opmask" , + "AVX-512 Hi256" , + "AVX-512 ZMM_Hi256" , + "Processor Trace" , + "Protection Keys User registers", + "Hardware Duty Cycling" , +}; + +static short xsave_cpuid_features[] = { + X86_FEATURE_FPU, + X86_FEATURE_XMM, + X86_FEATURE_AVX, + X86_FEATURE_MPX, + X86_FEATURE_MPX, + X86_FEATURE_AVX512F, + X86_FEATURE_AVX512F, + X86_FEATURE_AVX512F, + X86_FEATURE_INTEL_PT, + X86_FEATURE_PKU, + X86_FEATURE_HDC, +}; + void compel_set_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) { if (likely(feature < NCAPINTS_BITS)) @@ -32,6 +67,172 @@ int compel_test_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) return 0; } +static int compel_fpuid(compel_cpuinfo_t *c) +{ + unsigned int last_good_offset; + uint32_t eax, ebx, ecx, edx; + size_t i; + + BUILD_BUG_ON(ARRAY_SIZE(xsave_cpuid_features) != + ARRAY_SIZE(xfeature_names)); + + if (!compel_test_cpu_cap(c, X86_FEATURE_FPU)) { + pr_err("fpu: No FPU detected\n"); + return -1; + } + + if (!compel_test_cpu_cap(c, X86_FEATURE_XSAVE)) { + pr_info("fpu: x87 FPU will use %s\n", + compel_test_cpu_cap(c, X86_FEATURE_FXSR) ? + "FXSAVE" : "FSAVE"); + return 0; + } + + cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx); + c->xfeatures_mask = eax + ((uint64_t)edx << 32); + + if ((c->xfeatures_mask & XFEATURE_MASK_FPSSE) != XFEATURE_MASK_FPSSE) { + /* + * This indicates that something really unexpected happened + * with the enumeration. + */ + pr_err("fpu: FP/SSE not present amongst the CPU's xstate features: 0x%llx\n", + (unsigned long long)c->xfeatures_mask); + return -1; + } + + /* + * Clear XSAVE features that are disabled in the normal CPUID. + */ + for (i = 0; i < ARRAY_SIZE(xsave_cpuid_features); i++) { + if (!compel_test_cpu_cap(c, xsave_cpuid_features[i])) + c->xfeatures_mask &= ~(1 << i); + } + + c->xfeatures_mask &= XCNTXT_MASK; + c->xfeatures_mask &= ~XFEATURE_MASK_SUPERVISOR; + + /* + * xsaves is not enabled in userspace, so + * xsaves is mostly for debug purpose. + */ + cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx); + c->xsave_size = ebx; + c->xsave_size_max = ecx; + + cpuid_count(XSTATE_CPUID, 1, &eax, &ebx, &ecx, &edx); + c->xsaves_size = ebx; + + pr_debug("fpu: xfeatures_mask 0x%llx xsave_size %u xsave_size_max %u xsaves_size %u\n", + (unsigned long long)c->xfeatures_mask, + c->xsave_size, c->xsave_size_max, c->xsaves_size); + + if (c->xsave_size_max > sizeof(struct xsave_struct)) + pr_warn_once("fpu: max xsave frame exceed xsave_struct (%u %u)\n", + c->xsave_size_max, (unsigned)sizeof(struct xsave_struct)); + + memset(c->xstate_offsets, 0xff, sizeof(c->xstate_offsets)); + memset(c->xstate_sizes, 0xff, sizeof(c->xstate_sizes)); + memset(c->xstate_comp_offsets, 0xff, sizeof(c->xstate_comp_offsets)); + memset(c->xstate_comp_sizes, 0xff, sizeof(c->xstate_comp_sizes)); + + /* start at the beginnning of the "extended state" */ + last_good_offset = offsetof(struct xsave_struct, extended_state_area); + + /* + * The FP xstates and SSE xstates are legacy states. They are always + * in the fixed offsets in the xsave area in either compacted form + * or standard form. + */ + c->xstate_offsets[0] = 0; + c->xstate_sizes[0] = offsetof(struct i387_fxsave_struct, xmm_space); + c->xstate_offsets[1] = c->xstate_sizes[0]; + c->xstate_sizes[1] = FIELD_SIZEOF(struct i387_fxsave_struct, xmm_space); + + for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) { + if (!(c->xfeatures_mask & (1UL << i))) + continue; + + /* + * If an xfeature is supervisor state, the offset + * in EBX is invalid. We leave it to -1. + * + * SDM says: If state component 'i' is a user state component, + * ECX[0] return 0; if state component i is a supervisor + * state component, ECX[0] returns 1. + */ + cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx); + if (!(ecx & 1)) + c->xstate_offsets[i] = ebx; + + c->xstate_sizes[i] = eax; + + /* + * In our xstate size checks, we assume that the + * highest-numbered xstate feature has the + * highest offset in the buffer. Ensure it does. + */ + if (last_good_offset > c->xstate_offsets[i]) + pr_warn_once("fpu: misordered xstate %d %d\n", + last_good_offset, c->xstate_offsets[i]); + + last_good_offset = c->xstate_offsets[i]; + } + + BUILD_BUG_ON(sizeof(c->xstate_offsets) != sizeof(c->xstate_sizes)); + BUILD_BUG_ON(sizeof(c->xstate_comp_offsets) != sizeof(c->xstate_comp_sizes)); + + c->xstate_comp_offsets[0] = 0; + c->xstate_comp_sizes[0] = offsetof(struct i387_fxsave_struct, xmm_space); + c->xstate_comp_offsets[1] = c->xstate_comp_sizes[0]; + c->xstate_comp_sizes[1] = FIELD_SIZEOF(struct i387_fxsave_struct, xmm_space); + + if (!compel_test_cpu_cap(c, X86_FEATURE_XSAVES)) { + for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) { + if ((c->xfeatures_mask & (1UL << i))) { + c->xstate_comp_offsets[i] = c->xstate_offsets[i]; + c->xstate_comp_sizes[i] = c->xstate_sizes[i]; + } + } + } else { + c->xstate_comp_offsets[FIRST_EXTENDED_XFEATURE] = + FXSAVE_SIZE + XSAVE_HDR_SIZE; + + for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) { + if ((c->xfeatures_mask & (1UL << i))) + c->xstate_comp_sizes[i] = c->xstate_sizes[i]; + else + c->xstate_comp_sizes[i] = 0; + + if (i > FIRST_EXTENDED_XFEATURE) { + c->xstate_comp_offsets[i] = c->xstate_comp_offsets[i-1] + + c->xstate_comp_sizes[i-1]; + + /* + * The value returned by ECX[1] indicates the alignment + * of state component 'i' when the compacted format + * of the extended region of an XSAVE area is used: + */ + cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx); + if (ecx & 2) + c->xstate_comp_offsets[i] = ALIGN(c->xstate_comp_offsets[i], 64); + } + } + } + + if (!pr_quelled(COMPEL_LOG_DEBUG)) { + for (i = 0; i < ARRAY_SIZE(c->xstate_offsets); i++) { + if (!(c->xfeatures_mask & (1UL << i))) + continue; + pr_debug("fpu: %-32s xstate_offsets %6d / %-6d xstate_sizes %6d / %-6d\n", + xfeature_names[i], c->xstate_offsets[i], c->xstate_comp_offsets[i], + c->xstate_sizes[i], c->xstate_comp_sizes[i]); + } + } + + return 0; +} + int compel_cpuid(compel_cpuinfo_t *c) { uint32_t eax, ebx, ecx, edx; @@ -222,7 +423,10 @@ int compel_cpuid(compel_cpuinfo_t *c) break; } - return 0; + pr_debug("x86_family %u x86_vendor_id %s x86_model_id %s\n", + c->x86_family, c->x86_vendor_id, c->x86_model_id); + + return compel_fpuid(c); } bool compel_cpu_has_feature(unsigned int feature) diff --git a/compel/arch/x86/src/lib/include/uapi/asm/cpu.h b/compel/arch/x86/src/lib/include/uapi/asm/cpu.h index 65f0576f2..6a0c91af4 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/cpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/cpu.h @@ -3,6 +3,8 @@ #include +#include + /* * Adopted from linux kernel and enhanced from Intel/AMD manuals. * Note these bits are not ABI for linux kernel but they _are_ @@ -277,6 +279,7 @@ enum cpuid_leafs { #define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* HWP Activity Window */ #define X86_FEATURE_HWP_EPP (14*32+10) /* HWP Energy Perf. Preference */ #define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* HWP Package Level Request */ +#define X86_FEATURE_HDC (14*32+13) /* HDC base registers present */ /* AMD SVM Feature Identification, CPUID level 0x8000000a (EDX), word 15 */ #define X86_FEATURE_NPT (15*32+ 0) /* Nested Page Table support */ @@ -318,6 +321,7 @@ enum { }; struct cpuinfo_x86 { + /* cpu context */ uint8_t x86_family; uint8_t x86_vendor; uint8_t x86_model; @@ -328,6 +332,17 @@ struct cpuinfo_x86 { int cpuid_level; char x86_vendor_id[16]; char x86_model_id[64]; + + /* fpu context */ + uint64_t xfeatures_mask; + uint32_t xsave_size_max; + uint32_t xsave_size; + uint32_t xstate_offsets[XFEATURE_MAX]; + uint32_t xstate_sizes[XFEATURE_MAX]; + + uint32_t xsaves_size; + uint32_t xstate_comp_offsets[XFEATURE_MAX]; + uint32_t xstate_comp_sizes[XFEATURE_MAX]; }; typedef struct cpuinfo_x86 compel_cpuinfo_t; diff --git a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h index dca280bdb..b18c91757 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h @@ -19,7 +19,66 @@ #define XSTATE_YMM 0x4 #define FXSAVE_SIZE 512 -#define XSAVE_SIZE 832 +#define XSAVE_SIZE 4096 + +#define XSAVE_HDR_SIZE 64 +#define XSAVE_HDR_OFFSET FXSAVE_SIZE + +#define XSAVE_YMM_SIZE 256 +#define XSAVE_YMM_OFFSET (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET) + +/* + * List of XSAVE features Linux knows about: + */ +enum xfeature { + XFEATURE_FP, + XFEATURE_SSE, + /* + * Values above here are "legacy states". + * Those below are "extended states". + */ + XFEATURE_YMM, + XFEATURE_BNDREGS, + XFEATURE_BNDCSR, + XFEATURE_OPMASK, + XFEATURE_ZMM_Hi256, + XFEATURE_Hi16_ZMM, + XFEATURE_PT, + XFEATURE_PKRU, + XFEATURE_HDC, + + XFEATURE_MAX, +}; + +#define XSTATE_CPUID 0x0000000d + +#define XFEATURE_MASK_FP (1 << XFEATURE_FP) +#define XFEATURE_MASK_SSE (1 << XFEATURE_SSE) +#define XFEATURE_MASK_YMM (1 << XFEATURE_YMM) +#define XFEATURE_MASK_BNDREGS (1 << XFEATURE_BNDREGS) +#define XFEATURE_MASK_BNDCSR (1 << XFEATURE_BNDCSR) +#define XFEATURE_MASK_OPMASK (1 << XFEATURE_OPMASK) +#define XFEATURE_MASK_ZMM_Hi256 (1 << XFEATURE_ZMM_Hi256) +#define XFEATURE_MASK_Hi16_ZMM (1 << XFEATURE_Hi16_ZMM) +#define XFEATURE_MASK_PT (1 << XFEATURE_PT) +#define XFEATURE_MASK_PKRU (1 << XFEATURE_PKRU) +#define XFEATURE_MASK_HDC (1 << XFEATURE_HDC) + +#define XFEATURE_MASK_FPSSE (XFEATURE_MASK_FP | XFEATURE_MASK_SSE) +#define XFEATURE_MASK_AVX512 (XFEATURE_MASK_OPMASK | XFEATURE_MASK_ZMM_Hi256 | XFEATURE_MASK_Hi16_ZMM) + +#define FIRST_EXTENDED_XFEATURE XFEATURE_YMM + +/* Supervisor features */ +#define XFEATURE_MASK_SUPERVISOR (XFEATURE_MASK_PT | XFEATURE_HDC) + +/* All currently supported features */ +#define XCNTXT_MASK \ + (XFEATURE_MASK_FP | XFEATURE_MASK_SSE | \ + XFEATURE_MASK_YMM | XFEATURE_MASK_OPMASK | \ + XFEATURE_MASK_ZMM_Hi256 | XFEATURE_MASK_Hi16_ZMM | \ + XFEATURE_MASK_PKRU | XFEATURE_MASK_BNDREGS | \ + XFEATURE_MASK_BNDCSR) struct fpx_sw_bytes { uint32_t magic1; @@ -66,27 +125,141 @@ struct i387_fxsave_struct { struct xsave_hdr_struct { uint64_t xstate_bv; - uint64_t reserved1[2]; - uint64_t reserved2[5]; + uint64_t xcomp_bv; + uint64_t reserved[6]; } __packed; +/* + * xstate_header.xcomp_bv[63] indicates that the extended_state_area + * is in compacted format. + */ +#define XCOMP_BV_COMPACTED_FORMAT ((uint64_t)1 << 63) + +/* + * State component 2: + * + * There are 16x 256-bit AVX registers named YMM0-YMM15. + * The low 128 bits are aliased to the 16 SSE registers (XMM0-XMM15) + * and are stored in 'struct fxregs_state::xmm_space[]' in the + * "legacy" area. + * + * The high 128 bits are stored here. + */ struct ymmh_struct { - uint32_t ymmh_space[64]; + uint32_t ymmh_space[64]; } __packed; +/* Intel MPX support: */ + +struct mpx_bndreg { + uint64_t lower_bound; + uint64_t upper_bound; +} __packed; + +/* + * State component 3 is used for the 4 128-bit bounds registers + */ +struct mpx_bndreg_state { + struct mpx_bndreg bndreg[4]; +} __packed; + +/* + * State component 4 is used for the 64-bit user-mode MPX + * configuration register BNDCFGU and the 64-bit MPX status + * register BNDSTATUS. We call the pair "BNDCSR". + */ +struct mpx_bndcsr { + uint64_t bndcfgu; + uint64_t bndstatus; +} __packed; + +/* + * The BNDCSR state is padded out to be 64-bytes in size. + */ +struct mpx_bndcsr_state { + union { + struct mpx_bndcsr bndcsr; + uint8_t pad_to_64_bytes[64]; + }; +} __packed; + +/* AVX-512 Components: */ + +/* + * State component 5 is used for the 8 64-bit opmask registers + * k0-k7 (opmask state). + */ +struct avx_512_opmask_state { + uint64_t opmask_reg[8]; +} __packed; + +/* + * State component 6 is used for the upper 256 bits of the + * registers ZMM0-ZMM15. These 16 256-bit values are denoted + * ZMM0_H-ZMM15_H (ZMM_Hi256 state). + */ +struct avx_512_zmm_uppers_state { + uint64_t zmm_upper[16 * 4]; +} __packed; + +/* + * State component 7 is used for the 16 512-bit registers + * ZMM16-ZMM31 (Hi16_ZMM state). + */ +struct avx_512_hi16_state { + uint64_t hi16_zmm[16 * 8]; +} __packed; + +/* + * State component 9: 32-bit PKRU register. The state is + * 8 bytes long but only 4 bytes is used currently. + */ +struct pkru_state { + uint32_t pkru; + uint32_t pad; +} __packed; + +/* + * This is our most modern FPU state format, as saved by the XSAVE + * and restored by the XRSTOR instructions. + * + * It consists of a legacy fxregs portion, an xstate header and + * subsequent areas as defined by the xstate header. Not all CPUs + * support all the extensions, so the size of the extended area + * can vary quite a bit between CPUs. + * + * + * One page should be enough for the whole xsave state. + */ +#define EXTENDED_STATE_AREA_SIZE (4096 - sizeof(struct i387_fxsave_struct) - sizeof(struct xsave_hdr_struct)) + /* * cpu requires it to be 64 byte aligned */ struct xsave_struct { struct i387_fxsave_struct i387; struct xsave_hdr_struct xsave_hdr; - struct ymmh_struct ymmh; + union { + /* + * This ymmh is unndeed, for + * backward compatibility. + */ + struct ymmh_struct ymmh; + uint8_t extended_state_area[EXTENDED_STATE_AREA_SIZE]; + }; } __aligned(FP_MIN_ALIGN_BYTES) __packed; struct xsave_struct_ia32 { struct i387_fxsave_struct i387; struct xsave_hdr_struct xsave_hdr; - struct ymmh_struct ymmh; + union { + /* + * This ymmh is unndeed, for + * backward compatibility. + */ + struct ymmh_struct ymmh; + uint8_t extended_state_area[EXTENDED_STATE_AREA_SIZE]; + }; } __aligned(FXSAVE_ALIGN_BYTES) __packed; typedef struct { From c926e2a7184c6ca4661321c0084c792005a5d7de Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:33 +0300 Subject: [PATCH 1664/4375] x86: cpu -- Save xfeature on dump This feature will allow to catch incapability early if present in image. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index d5d879e79..e9c24af84 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -97,6 +97,8 @@ int cpu_dump_cpuinfo(void) cpu_x86_info.capability_ver = 2; cpu_x86_info.n_capability = ARRAY_SIZE(rt_cpu_info.x86_capability); cpu_x86_info.capability = (void *)rt_cpu_info.x86_capability; + cpu_x86_info.has_xfeatures_mask = true; + cpu_x86_info.xfeatures_mask = rt_cpu_info.xfeatures_mask; if (rt_cpu_info.x86_model_id[0]) cpu_x86_info.model_id = rt_cpu_info.x86_model_id; @@ -263,6 +265,17 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) #undef __mismatch_fpu_bit } + /* + * Make sure the xsave features are at least not less + * than current cpu supports. + */ + if (cpu_info->xfeatures_mask > rt_cpu_info.xfeatures_mask) { + uint64_t m = cpu_info->xfeatures_mask & ~rt_cpu_info.xfeatures_mask; + pr_err("CPU xfeatures has unsupported bits (%#llx)\n", + (unsigned long long)m); + return -1; + } + /* * Capability on instructions level only. */ @@ -353,6 +366,17 @@ static compel_cpuinfo_t *img_to_cpuinfo(CpuinfoX86Entry *img_x86_entry) memcpy(cpu_info->x86_vendor_id, rt_cpu_info.x86_model_id, sizeof(cpu_info->x86_vendor_id)); strncpy(cpu_info->x86_model_id, img_x86_entry->model_id, sizeof(cpu_info->x86_model_id) - 1); + /* + * For old images where no xfeatures_mask present we + * simply fetch runtime cpu mask because later we will + * do either instruction capability check, either strict + * check for capabilities. + */ + if (!img_x86_entry->has_xfeatures_mask) { + cpu_info->xfeatures_mask = rt_cpu_info.xfeatures_mask; + } else + cpu_info->xfeatures_mask = img_x86_entry->xfeatures_mask; + return cpu_info; } From 888514aee0478b758aacc36eb0f7c509366a757c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:34 +0300 Subject: [PATCH 1665/4375] compel: fpu -- Add compel_test_fpu_cap helper Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/cpu.c | 1 + compel/arch/arm/src/lib/cpu.c | 1 + compel/arch/ppc64/src/lib/cpu.c | 1 + compel/arch/s390/src/lib/cpu.c | 1 + compel/arch/x86/src/lib/cpu.c | 7 +++++++ compel/arch/x86/src/lib/include/uapi/asm/fpu.h | 1 + compel/include/compel-cpu.h | 1 + 7 files changed, 13 insertions(+) diff --git a/compel/arch/aarch64/src/lib/cpu.c b/compel/arch/aarch64/src/lib/cpu.c index fca699403..c7573f6ad 100644 --- a/compel/arch/aarch64/src/lib/cpu.c +++ b/compel/arch/aarch64/src/lib/cpu.c @@ -16,6 +16,7 @@ static bool rt_info_done = false; void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } +int compel_test_fpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } int compel_cpuid(compel_cpuinfo_t *info) { return 0; } bool compel_cpu_has_feature(unsigned int feature) diff --git a/compel/arch/arm/src/lib/cpu.c b/compel/arch/arm/src/lib/cpu.c index fca699403..c7573f6ad 100644 --- a/compel/arch/arm/src/lib/cpu.c +++ b/compel/arch/arm/src/lib/cpu.c @@ -16,6 +16,7 @@ static bool rt_info_done = false; void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } +int compel_test_fpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } int compel_cpuid(compel_cpuinfo_t *info) { return 0; } bool compel_cpu_has_feature(unsigned int feature) diff --git a/compel/arch/ppc64/src/lib/cpu.c b/compel/arch/ppc64/src/lib/cpu.c index 0a7adcb0b..f6d163b89 100644 --- a/compel/arch/ppc64/src/lib/cpu.c +++ b/compel/arch/ppc64/src/lib/cpu.c @@ -17,6 +17,7 @@ static bool rt_info_done = false; void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } +int compel_test_fpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } int compel_cpuid(compel_cpuinfo_t *info) diff --git a/compel/arch/s390/src/lib/cpu.c b/compel/arch/s390/src/lib/cpu.c index 3f38f118d..85a074a3b 100644 --- a/compel/arch/s390/src/lib/cpu.c +++ b/compel/arch/s390/src/lib/cpu.c @@ -17,6 +17,7 @@ static bool rt_info_done = false; void compel_set_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) { } void compel_clear_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) { } +int compel_test_fpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } int compel_test_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) { return 0; } int compel_cpuid(compel_cpuinfo_t *info) diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c index 4657f9723..722c729e2 100644 --- a/compel/arch/x86/src/lib/cpu.c +++ b/compel/arch/x86/src/lib/cpu.c @@ -67,6 +67,13 @@ int compel_test_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) return 0; } +int compel_test_fpu_cap(compel_cpuinfo_t *c, unsigned int feature) +{ + if (likely(feature < XFEATURE_MAX)) + return (c->xfeatures_mask & (1UL << feature)); + return 0; +} + static int compel_fpuid(compel_cpuinfo_t *c) { unsigned int last_good_offset; diff --git a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h index b18c91757..a32a00e9c 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h @@ -63,6 +63,7 @@ enum xfeature { #define XFEATURE_MASK_PT (1 << XFEATURE_PT) #define XFEATURE_MASK_PKRU (1 << XFEATURE_PKRU) #define XFEATURE_MASK_HDC (1 << XFEATURE_HDC) +#define XFEATURE_MASK_MAX (1 << XFEATURE_MAX) #define XFEATURE_MASK_FPSSE (XFEATURE_MASK_FP | XFEATURE_MASK_SSE) #define XFEATURE_MASK_AVX512 (XFEATURE_MASK_OPMASK | XFEATURE_MASK_ZMM_Hi256 | XFEATURE_MASK_Hi16_ZMM) diff --git a/compel/include/compel-cpu.h b/compel/include/compel-cpu.h index a06b2de2e..f30afa0f9 100644 --- a/compel/include/compel-cpu.h +++ b/compel/include/compel-cpu.h @@ -7,5 +7,6 @@ extern void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); extern void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); extern int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); +extern int compel_test_fpu_cap(compel_cpuinfo_t *c, unsigned int feature); #endif From 5014812df983ca0eae98ad045664f8fc8e7c2fc9 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:35 +0300 Subject: [PATCH 1666/4375] compel: fpu -- Add compel_fpu_has_feature helper Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/cpu.c | 9 +++++++++ compel/arch/arm/src/lib/cpu.c | 9 +++++++++ compel/arch/ppc64/src/lib/cpu.c | 9 +++++++++ compel/arch/s390/src/lib/cpu.c | 11 ++++++++++- compel/arch/x86/src/lib/cpu.c | 9 +++++++++ compel/include/uapi/cpu.h | 1 + 6 files changed, 47 insertions(+), 1 deletion(-) diff --git a/compel/arch/aarch64/src/lib/cpu.c b/compel/arch/aarch64/src/lib/cpu.c index c7573f6ad..38d9cbf4e 100644 --- a/compel/arch/aarch64/src/lib/cpu.c +++ b/compel/arch/aarch64/src/lib/cpu.c @@ -28,6 +28,15 @@ bool compel_cpu_has_feature(unsigned int feature) return compel_test_cpu_cap(&rt_info, feature); } +bool compel_fpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_fpu_cap(&rt_info, feature); +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/arch/arm/src/lib/cpu.c b/compel/arch/arm/src/lib/cpu.c index c7573f6ad..38d9cbf4e 100644 --- a/compel/arch/arm/src/lib/cpu.c +++ b/compel/arch/arm/src/lib/cpu.c @@ -28,6 +28,15 @@ bool compel_cpu_has_feature(unsigned int feature) return compel_test_cpu_cap(&rt_info, feature); } +bool compel_fpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_fpu_cap(&rt_info, feature); +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/arch/ppc64/src/lib/cpu.c b/compel/arch/ppc64/src/lib/cpu.c index f6d163b89..27a21a53a 100644 --- a/compel/arch/ppc64/src/lib/cpu.c +++ b/compel/arch/ppc64/src/lib/cpu.c @@ -42,6 +42,15 @@ bool compel_cpu_has_feature(unsigned int feature) return compel_test_cpu_cap(&rt_info, feature); } +bool compel_fpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_fpu_cap(&rt_info, feature); +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/arch/s390/src/lib/cpu.c b/compel/arch/s390/src/lib/cpu.c index 85a074a3b..97ab809b8 100644 --- a/compel/arch/s390/src/lib/cpu.c +++ b/compel/arch/s390/src/lib/cpu.c @@ -33,7 +33,7 @@ int compel_cpuid(compel_cpuinfo_t *info) return 0; } -bool cpu_has_feature(unsigned int feature) +bool compel_cpu_has_feature(unsigned int feature) { if (!rt_info_done) { compel_cpuid(&rt_info); @@ -42,6 +42,15 @@ bool cpu_has_feature(unsigned int feature) return compel_test_cpu_cap(&rt_info, feature); } +bool compel_fpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_fpu_cap(&rt_info, feature); +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c index 722c729e2..85a936299 100644 --- a/compel/arch/x86/src/lib/cpu.c +++ b/compel/arch/x86/src/lib/cpu.c @@ -445,6 +445,15 @@ bool compel_cpu_has_feature(unsigned int feature) return compel_test_cpu_cap(&rt_info, feature); } +bool compel_fpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_fpu_cap(&rt_info, feature); +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/include/uapi/cpu.h b/compel/include/uapi/cpu.h index 379959585..d858a0b46 100644 --- a/compel/include/uapi/cpu.h +++ b/compel/include/uapi/cpu.h @@ -7,6 +7,7 @@ extern int compel_cpuid(compel_cpuinfo_t *info); extern bool compel_cpu_has_feature(unsigned int feature); +extern bool compel_fpu_has_feature(unsigned int feature); extern void compel_cpu_clear_feature(unsigned int feature); extern void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c); From d25af82cc05b9f98d6be7ce4623aaa1381a156ab Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:36 +0300 Subject: [PATCH 1667/4375] compel: fpu -- Add compel_fpu_feature_size Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/cpu.c | 9 +++++++++ compel/arch/arm/src/lib/cpu.c | 9 +++++++++ compel/arch/ppc64/src/lib/cpu.c | 9 +++++++++ compel/arch/s390/src/lib/cpu.c | 9 +++++++++ compel/arch/x86/src/lib/cpu.c | 12 ++++++++++++ compel/include/uapi/cpu.h | 2 ++ 6 files changed, 50 insertions(+) diff --git a/compel/arch/aarch64/src/lib/cpu.c b/compel/arch/aarch64/src/lib/cpu.c index 38d9cbf4e..e82988879 100644 --- a/compel/arch/aarch64/src/lib/cpu.c +++ b/compel/arch/aarch64/src/lib/cpu.c @@ -37,6 +37,15 @@ bool compel_fpu_has_feature(unsigned int feature) return compel_test_fpu_cap(&rt_info, feature); } +uint32_t compel_fpu_feature_size(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return 0; +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/arch/arm/src/lib/cpu.c b/compel/arch/arm/src/lib/cpu.c index 38d9cbf4e..e82988879 100644 --- a/compel/arch/arm/src/lib/cpu.c +++ b/compel/arch/arm/src/lib/cpu.c @@ -37,6 +37,15 @@ bool compel_fpu_has_feature(unsigned int feature) return compel_test_fpu_cap(&rt_info, feature); } +uint32_t compel_fpu_feature_size(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return 0; +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/arch/ppc64/src/lib/cpu.c b/compel/arch/ppc64/src/lib/cpu.c index 27a21a53a..a9be1fd6b 100644 --- a/compel/arch/ppc64/src/lib/cpu.c +++ b/compel/arch/ppc64/src/lib/cpu.c @@ -51,6 +51,15 @@ bool compel_fpu_has_feature(unsigned int feature) return compel_test_fpu_cap(&rt_info, feature); } +uint32_t compel_fpu_feature_size(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return 0; +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/arch/s390/src/lib/cpu.c b/compel/arch/s390/src/lib/cpu.c index 97ab809b8..bb32affe8 100644 --- a/compel/arch/s390/src/lib/cpu.c +++ b/compel/arch/s390/src/lib/cpu.c @@ -51,6 +51,15 @@ bool compel_fpu_has_feature(unsigned int feature) return compel_test_fpu_cap(&rt_info, feature); } +uint32_t compel_fpu_feature_size(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return 0; +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c index 85a936299..dd5524d81 100644 --- a/compel/arch/x86/src/lib/cpu.c +++ b/compel/arch/x86/src/lib/cpu.c @@ -454,6 +454,18 @@ bool compel_fpu_has_feature(unsigned int feature) return compel_test_fpu_cap(&rt_info, feature); } +uint32_t compel_fpu_feature_size(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + if (feature >= FIRST_EXTENDED_XFEATURE && + feature < XFEATURE_MAX) + return rt_info.xstate_sizes[feature]; + return 0; +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/include/uapi/cpu.h b/compel/include/uapi/cpu.h index d858a0b46..c82f8abb6 100644 --- a/compel/include/uapi/cpu.h +++ b/compel/include/uapi/cpu.h @@ -2,12 +2,14 @@ #define UAPI_COMPEL_CPU_H__ #include +#include #include extern int compel_cpuid(compel_cpuinfo_t *info); extern bool compel_cpu_has_feature(unsigned int feature); extern bool compel_fpu_has_feature(unsigned int feature); +extern uint32_t compel_fpu_feature_size(unsigned int feature); extern void compel_cpu_clear_feature(unsigned int feature); extern void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c); From dd4c0c6b22d3e3ede23cff9ac43786f5f00948ec Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:37 +0300 Subject: [PATCH 1668/4375] compel: fpu -- Add compel_fpu_feature_offset helper Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/cpu.c | 9 +++++++++ compel/arch/arm/src/lib/cpu.c | 9 +++++++++ compel/arch/ppc64/src/lib/cpu.c | 9 +++++++++ compel/arch/s390/src/lib/cpu.c | 9 +++++++++ compel/arch/x86/src/lib/cpu.c | 12 ++++++++++++ compel/include/uapi/cpu.h | 1 + 6 files changed, 49 insertions(+) diff --git a/compel/arch/aarch64/src/lib/cpu.c b/compel/arch/aarch64/src/lib/cpu.c index e82988879..15a49c420 100644 --- a/compel/arch/aarch64/src/lib/cpu.c +++ b/compel/arch/aarch64/src/lib/cpu.c @@ -46,6 +46,15 @@ uint32_t compel_fpu_feature_size(unsigned int feature) return 0; } +uint32_t compel_fpu_feature_offset(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return 0; +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/arch/arm/src/lib/cpu.c b/compel/arch/arm/src/lib/cpu.c index e82988879..15a49c420 100644 --- a/compel/arch/arm/src/lib/cpu.c +++ b/compel/arch/arm/src/lib/cpu.c @@ -46,6 +46,15 @@ uint32_t compel_fpu_feature_size(unsigned int feature) return 0; } +uint32_t compel_fpu_feature_offset(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return 0; +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/arch/ppc64/src/lib/cpu.c b/compel/arch/ppc64/src/lib/cpu.c index a9be1fd6b..d0e366e71 100644 --- a/compel/arch/ppc64/src/lib/cpu.c +++ b/compel/arch/ppc64/src/lib/cpu.c @@ -60,6 +60,15 @@ uint32_t compel_fpu_feature_size(unsigned int feature) return 0; } +uint32_t compel_fpu_feature_offset(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return 0; +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/arch/s390/src/lib/cpu.c b/compel/arch/s390/src/lib/cpu.c index bb32affe8..98503b191 100644 --- a/compel/arch/s390/src/lib/cpu.c +++ b/compel/arch/s390/src/lib/cpu.c @@ -51,6 +51,15 @@ bool compel_fpu_has_feature(unsigned int feature) return compel_test_fpu_cap(&rt_info, feature); } +uint32_t compel_fpu_feature_offset(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return 0; +} + uint32_t compel_fpu_feature_size(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c index dd5524d81..d422f91fd 100644 --- a/compel/arch/x86/src/lib/cpu.c +++ b/compel/arch/x86/src/lib/cpu.c @@ -466,6 +466,18 @@ uint32_t compel_fpu_feature_size(unsigned int feature) return 0; } +uint32_t compel_fpu_feature_offset(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + if (feature >= FIRST_EXTENDED_XFEATURE && + feature < XFEATURE_MAX) + return rt_info.xstate_offsets[feature]; + return 0; +} + void compel_cpu_clear_feature(unsigned int feature) { if (!rt_info_done) { diff --git a/compel/include/uapi/cpu.h b/compel/include/uapi/cpu.h index c82f8abb6..6f827d447 100644 --- a/compel/include/uapi/cpu.h +++ b/compel/include/uapi/cpu.h @@ -10,6 +10,7 @@ extern int compel_cpuid(compel_cpuinfo_t *info); extern bool compel_cpu_has_feature(unsigned int feature); extern bool compel_fpu_has_feature(unsigned int feature); extern uint32_t compel_fpu_feature_size(unsigned int feature); +extern uint32_t compel_fpu_feature_offset(unsigned int feature); extern void compel_cpu_clear_feature(unsigned int feature); extern void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c); From b99be2741a94174f4823e5d84cd24e750ba4f5dc Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:38 +0300 Subject: [PATCH 1669/4375] x86: cpu -- Add support for extended xsave area cpu extensions (such as avx-512) require bigger xsave area to keep fpu registers set, so we allocate a page per process to keep them all. On checkpoint we parse runtime fpu features and dump them into an image and do reverse on restore procedure. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 153 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 138 insertions(+), 15 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 0b5a0acd6..bb25916f3 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -17,6 +17,21 @@ int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpre #define assign_reg(dst, src, e) do { dst->e = (__typeof__(dst->e))src.e; } while (0) #define assign_array(dst, src, e) memcpy(dst->e, &src.e, sizeof(src.e)) +#define assign_xsave(feature, xsave, member, area) \ + do { \ + if (compel_fpu_has_feature(feature)) { \ + uint32_t off = compel_fpu_feature_offset(feature); \ + void *from = &area[off]; \ + size_t size = pb_repeated_size(xsave, member); \ + size_t xsize = (size_t)compel_fpu_feature_size(feature); \ + if (xsize != size) { \ + pr_err("%s reported %zu bytes (expecting %zu)\n", \ + # feature, xsize, size); \ + return -1; \ + } \ + memcpy(xsave->member, from, size); \ + } \ + } while (0) if (user_regs_native(regs)) { assign_reg(gpregs, regs->native, r15); @@ -89,14 +104,27 @@ int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpre assign_array(core->thread_info->fpregs, fpregs->i387, xmm_space); if (compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) { - BUG_ON(core->thread_info->fpregs->xsave->n_ymmh_space != ARRAY_SIZE(fpregs->ymmh.ymmh_space)); + UserX86XsaveEntry *xsave = core->thread_info->fpregs->xsave; + uint8_t *extended_state_area = (void *)fpregs; - assign_reg(core->thread_info->fpregs->xsave, fpregs->xsave_hdr, xstate_bv); - assign_array(core->thread_info->fpregs->xsave, fpregs->ymmh, ymmh_space); + /* + * xcomp_bv is designated for compacted format but user + * space never use it, thus we can simply ignore. + */ + assign_reg(xsave, fpregs->xsave_hdr, xstate_bv); + + assign_xsave(XFEATURE_YMM, xsave, ymmh_space, extended_state_area); + assign_xsave(XFEATURE_BNDREGS, xsave, bndreg_state, extended_state_area); + assign_xsave(XFEATURE_BNDCSR, xsave, bndcsr_state, extended_state_area); + assign_xsave(XFEATURE_OPMASK, xsave, opmask_reg, extended_state_area); + assign_xsave(XFEATURE_ZMM_Hi256,xsave, zmm_upper, extended_state_area); + assign_xsave(XFEATURE_Hi16_ZMM, xsave, hi16_zmm, extended_state_area); + assign_xsave(XFEATURE_PKRU, xsave, pkru, extended_state_area); } #undef assign_reg #undef assign_array +#undef assign_xsave return 0; } @@ -113,6 +141,62 @@ static void alloc_tls(ThreadInfoX86 *ti, void **mempool) } } +static int alloc_xsave_extends(UserX86XsaveEntry *xsave) +{ + if (compel_fpu_has_feature(XFEATURE_YMM)) { + xsave->n_ymmh_space = 64; + xsave->ymmh_space = xzalloc(pb_repeated_size(xsave, ymmh_space)); + if (!xsave->ymmh_space) + goto err; + } + + if (compel_fpu_has_feature(XFEATURE_BNDREGS)) { + xsave->n_bndreg_state = 4 * 2; + xsave->bndreg_state = xzalloc(pb_repeated_size(xsave, bndreg_state)); + if (!xsave->bndreg_state) + goto err; + } + + if (compel_fpu_has_feature(XFEATURE_BNDCSR)) { + xsave->n_bndcsr_state = 2; + xsave->bndcsr_state = xzalloc(pb_repeated_size(xsave, bndcsr_state)); + if (!xsave->bndcsr_state) + goto err; + } + + if (compel_fpu_has_feature(XFEATURE_OPMASK)) { + xsave->n_opmask_reg = 8; + xsave->opmask_reg = xzalloc(pb_repeated_size(xsave, opmask_reg)); + if (!xsave->opmask_reg) + goto err; + } + + if (compel_fpu_has_feature(XFEATURE_ZMM_Hi256)) { + xsave->n_zmm_upper = 16 * 4; + xsave->zmm_upper = xzalloc(pb_repeated_size(xsave, zmm_upper)); + if (!xsave->zmm_upper) + goto err; + } + + if (compel_fpu_has_feature(XFEATURE_Hi16_ZMM)) { + xsave->n_hi16_zmm = 16 * 8; + xsave->hi16_zmm = xzalloc(pb_repeated_size(xsave, hi16_zmm)); + if (!xsave->hi16_zmm) + goto err; + } + + if (compel_fpu_has_feature(XFEATURE_PKRU)) { + xsave->n_pkru = 2; + xsave->pkru = xzalloc(pb_repeated_size(xsave, pkru)); + if (!xsave->pkru) + goto err; + } + + return 0; +err: + return -1; +} + int arch_alloc_thread_info(CoreEntry *core) { size_t sz; @@ -165,9 +249,7 @@ int arch_alloc_thread_info(CoreEntry *core) xsave = fpregs->xsave = xptr_pull(&m, UserX86XsaveEntry); user_x86_xsave_entry__init(xsave); - xsave->n_ymmh_space = 64; - xsave->ymmh_space = xzalloc(pb_repeated_size(xsave, ymmh_space)); - if (!xsave->ymmh_space) + if (alloc_xsave_extends(xsave)) goto err; } } @@ -182,8 +264,16 @@ void arch_free_thread_info(CoreEntry *core) if (!core->thread_info) return; - if (core->thread_info->fpregs->xsave) + if (core->thread_info->fpregs->xsave) { xfree(core->thread_info->fpregs->xsave->ymmh_space); + xfree(core->thread_info->fpregs->xsave->pkru); + xfree(core->thread_info->fpregs->xsave->hi16_zmm); + xfree(core->thread_info->fpregs->xsave->zmm_upper); + xfree(core->thread_info->fpregs->xsave->opmask_reg); + xfree(core->thread_info->fpregs->xsave->bndcsr_state); + xfree(core->thread_info->fpregs->xsave->bndreg_state); + } + xfree(core->thread_info->fpregs->st_space); xfree(core->thread_info->fpregs->xmm_space); xfree(core->thread_info); @@ -284,6 +374,24 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) #define assign_reg(dst, src, e) do { dst.e = (__typeof__(dst.e))src->e; } while (0) #define assign_array(dst, src, e) memcpy(dst.e, (src)->e, sizeof(dst.e)) +#define assign_xsave(feature, xsave, member, area) \ + do { \ + if (compel_fpu_has_feature(feature)) { \ + uint32_t off = compel_fpu_feature_offset(feature); \ + void *to = &area[off]; \ + void *from = xsave->member; \ + size_t size = pb_repeated_size(xsave, member); \ + size_t xsize = (size_t)compel_fpu_feature_size(feature); \ + if (xsize != size) { \ + pr_err("%s reported %zu bytes (expecting %zu)\n", \ + # feature, xsize, size); \ + return -1; \ + } \ + xstate_bv |= (1UL << feature); \ + xstate_size += xsize; \ + memcpy(to, from, size); \ + } \ + } while (0) assign_reg(x->i387, core->thread_info->fpregs, cwd); assign_reg(x->i387, core->thread_info->fpregs, swd); @@ -303,26 +411,40 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) if (compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) { struct fpx_sw_bytes *fpx_sw = (void *)&x->i387.sw_reserved; + size_t xstate_size = XSAVE_YMM_OFFSET; + uint32_t xstate_bv = 0; void *magic2; - x->xsave_hdr.xstate_bv = XSTATE_FP | XSTATE_SSE | XSTATE_YMM; + xstate_bv = XFEATURE_MASK_FP | XFEATURE_MASK_SSE; /* * fpregs->xsave pointer might not present on image so we - * simply clear out all ymm registers. + * simply clear out everything. */ - if (core->thread_info->fpregs->xsave) - assign_array(x->ymmh, core->thread_info->fpregs->xsave, ymmh_space); + if (core->thread_info->fpregs->xsave) { + UserX86XsaveEntry *xsave = core->thread_info->fpregs->xsave; + uint8_t *extended_state_area = (void *)x; + + assign_xsave(XFEATURE_YMM, xsave, ymmh_space, extended_state_area); + assign_xsave(XFEATURE_BNDREGS, xsave, bndreg_state, extended_state_area); + assign_xsave(XFEATURE_BNDCSR, xsave, bndcsr_state, extended_state_area); + assign_xsave(XFEATURE_OPMASK, xsave, opmask_reg, extended_state_area); + assign_xsave(XFEATURE_ZMM_Hi256,xsave, zmm_upper, extended_state_area); + assign_xsave(XFEATURE_Hi16_ZMM, xsave, hi16_zmm, extended_state_area); + assign_xsave(XFEATURE_PKRU, xsave, pkru, extended_state_area); + } + + x->xsave_hdr.xstate_bv = xstate_bv; fpx_sw->magic1 = FP_XSTATE_MAGIC1; - fpx_sw->xstate_bv = XSTATE_FP | XSTATE_SSE | XSTATE_YMM; - fpx_sw->xstate_size = sizeof(struct xsave_struct); - fpx_sw->extended_size = sizeof(struct xsave_struct) + FP_XSTATE_MAGIC2_SIZE; + fpx_sw->xstate_bv = xstate_bv; + fpx_sw->xstate_size = xstate_size; + fpx_sw->extended_size = xstate_size + FP_XSTATE_MAGIC2_SIZE; /* * This should be at the end of xsave frame. */ - magic2 = (void *)x + sizeof(struct xsave_struct); + magic2 = (void *)x + xstate_size; *(u32 *)magic2 = FP_XSTATE_MAGIC2; } @@ -330,6 +452,7 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) #undef assign_reg #undef assign_array +#undef assign_xsave return 0; } From 373361723a9e85d4f17a9a724c48574d717cf058 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:39 +0300 Subject: [PATCH 1670/4375] x86: cpu -- Improve show_rt_xsave_frame For debug sake Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index bb25916f3..385e7cfee 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -336,14 +336,13 @@ static void show_rt_xsave_frame(struct xsave_struct *x) pr_debug("xsave runtime structure\n"); pr_debug("-----------------------\n"); - pr_debug("cwd:%x swd:%x twd:%x fop:%x mxcsr:%x mxcsr_mask:%x\n", + pr_debug("cwd:%#x swd:%#x twd:%#x fop:%#x mxcsr:%#x mxcsr_mask:%#x\n", (int)i387->cwd, (int)i387->swd, (int)i387->twd, (int)i387->fop, (int)i387->mxcsr, (int)i387->mxcsr_mask); - pr_debug("magic1:%x extended_size:%x xstate_bv:%lx xstate_size:%x\n", + pr_debug("magic1:%#x extended_size:%u xstate_bv:%#lx xstate_size:%u\n", fpx->magic1, fpx->extended_size, (long)fpx->xstate_bv, fpx->xstate_size); - - pr_debug("xstate_bv: %lx\n", (long)xsave_hdr->xstate_bv); + pr_debug("xstate_bv: %#lx\n", (long)xsave_hdr->xstate_bv); pr_debug("-----------------------\n"); } From af967683018c6d12ad8b8e955f4645faa88e85a1 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:40 +0300 Subject: [PATCH 1671/4375] x86: Add prefix for logs Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 385e7cfee..f451c6f4a 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -10,6 +10,9 @@ #include "asm/compat.h" +#undef LOG_PREFIX +#define LOG_PREFIX "x86: " + int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) { CoreEntry *core = x; From d98a1eee6ee9f47a439224f836ddf540975ae949 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:41 +0300 Subject: [PATCH 1672/4375] compel: Shrink cpuinfo fetching Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/cpu.c | 41 ++++++++++++------------------- compel/arch/arm/src/lib/cpu.c | 41 ++++++++++++------------------- compel/arch/ppc64/src/lib/cpu.c | 41 ++++++++++++------------------- compel/arch/s390/src/lib/cpu.c | 38 +++++++++++----------------- compel/arch/x86/src/lib/cpu.c | 41 ++++++++++++------------------- 5 files changed, 78 insertions(+), 124 deletions(-) diff --git a/compel/arch/aarch64/src/lib/cpu.c b/compel/arch/aarch64/src/lib/cpu.c index 15a49c420..cfaab1e65 100644 --- a/compel/arch/aarch64/src/lib/cpu.c +++ b/compel/arch/aarch64/src/lib/cpu.c @@ -11,7 +11,16 @@ #define LOG_PREFIX "cpu: " static compel_cpuinfo_t rt_info; -static bool rt_info_done = false; + +static void fetch_rt_cpuinfo(void) +{ + static bool rt_info_done = false; + + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } +} void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } @@ -21,54 +30,36 @@ int compel_cpuid(compel_cpuinfo_t *info) { return 0; } bool compel_cpu_has_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_test_cpu_cap(&rt_info, feature); } bool compel_fpu_has_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_test_fpu_cap(&rt_info, feature); } uint32_t compel_fpu_feature_size(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return 0; } uint32_t compel_fpu_feature_offset(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return 0; } void compel_cpu_clear_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_clear_cpu_cap(&rt_info, feature); } void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); memcpy(c, &rt_info, sizeof(rt_info)); } diff --git a/compel/arch/arm/src/lib/cpu.c b/compel/arch/arm/src/lib/cpu.c index 15a49c420..cfaab1e65 100644 --- a/compel/arch/arm/src/lib/cpu.c +++ b/compel/arch/arm/src/lib/cpu.c @@ -11,7 +11,16 @@ #define LOG_PREFIX "cpu: " static compel_cpuinfo_t rt_info; -static bool rt_info_done = false; + +static void fetch_rt_cpuinfo(void) +{ + static bool rt_info_done = false; + + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } +} void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } @@ -21,54 +30,36 @@ int compel_cpuid(compel_cpuinfo_t *info) { return 0; } bool compel_cpu_has_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_test_cpu_cap(&rt_info, feature); } bool compel_fpu_has_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_test_fpu_cap(&rt_info, feature); } uint32_t compel_fpu_feature_size(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return 0; } uint32_t compel_fpu_feature_offset(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return 0; } void compel_cpu_clear_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_clear_cpu_cap(&rt_info, feature); } void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); memcpy(c, &rt_info, sizeof(rt_info)); } diff --git a/compel/arch/ppc64/src/lib/cpu.c b/compel/arch/ppc64/src/lib/cpu.c index d0e366e71..338ab4891 100644 --- a/compel/arch/ppc64/src/lib/cpu.c +++ b/compel/arch/ppc64/src/lib/cpu.c @@ -13,7 +13,16 @@ #define LOG_PREFIX "cpu: " static compel_cpuinfo_t rt_info; -static bool rt_info_done = false; + +static void fetch_rt_cpuinfo(void) +{ + static bool rt_info_done = false; + + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } +} void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } @@ -35,54 +44,36 @@ int compel_cpuid(compel_cpuinfo_t *info) bool compel_cpu_has_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_test_cpu_cap(&rt_info, feature); } bool compel_fpu_has_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_test_fpu_cap(&rt_info, feature); } uint32_t compel_fpu_feature_size(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return 0; } uint32_t compel_fpu_feature_offset(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return 0; } void compel_cpu_clear_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_clear_cpu_cap(&rt_info, feature); } void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); memcpy(c, &rt_info, sizeof(rt_info)); } diff --git a/compel/arch/s390/src/lib/cpu.c b/compel/arch/s390/src/lib/cpu.c index 98503b191..5d86bf239 100644 --- a/compel/arch/s390/src/lib/cpu.c +++ b/compel/arch/s390/src/lib/cpu.c @@ -15,6 +15,14 @@ static compel_cpuinfo_t rt_info; static bool rt_info_done = false; +static void fetch_rt_cpuinfo(void) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } +} + void compel_set_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) { } void compel_clear_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) { } int compel_test_fpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } @@ -35,54 +43,36 @@ int compel_cpuid(compel_cpuinfo_t *info) bool compel_cpu_has_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_test_cpu_cap(&rt_info, feature); } bool compel_fpu_has_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_test_fpu_cap(&rt_info, feature); } uint32_t compel_fpu_feature_offset(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return 0; } uint32_t compel_fpu_feature_size(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return 0; } void compel_cpu_clear_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_clear_cpu_cap(&rt_info, feature); } void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); memcpy(c, &rt_info, sizeof(rt_info)); } diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c index d422f91fd..9152765bf 100644 --- a/compel/arch/x86/src/lib/cpu.c +++ b/compel/arch/x86/src/lib/cpu.c @@ -12,7 +12,16 @@ #define LOG_PREFIX "cpu: " static compel_cpuinfo_t rt_info; -static bool rt_info_done = false; + +static void fetch_rt_cpuinfo(void) +{ + static bool rt_info_done = false; + + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } +} /* * Although we spell it out in here, the Processor Trace @@ -438,28 +447,19 @@ int compel_cpuid(compel_cpuinfo_t *c) bool compel_cpu_has_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_test_cpu_cap(&rt_info, feature); } bool compel_fpu_has_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_test_fpu_cap(&rt_info, feature); } uint32_t compel_fpu_feature_size(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); if (feature >= FIRST_EXTENDED_XFEATURE && feature < XFEATURE_MAX) return rt_info.xstate_sizes[feature]; @@ -468,10 +468,7 @@ uint32_t compel_fpu_feature_size(unsigned int feature) uint32_t compel_fpu_feature_offset(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); if (feature >= FIRST_EXTENDED_XFEATURE && feature < XFEATURE_MAX) return rt_info.xstate_offsets[feature]; @@ -480,18 +477,12 @@ uint32_t compel_fpu_feature_offset(unsigned int feature) void compel_cpu_clear_feature(unsigned int feature) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); return compel_clear_cpu_cap(&rt_info, feature); } void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c) { - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } + fetch_rt_cpuinfo(); memcpy(c, &rt_info, sizeof(rt_info)); } From 7b367a11987d9184df17258a085c23b49db116e8 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:42 +0300 Subject: [PATCH 1673/4375] compel: arm -- Remove code duplication arm's cpu code is the same as aarch64, so use the symlink. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/arch/arm/src/lib/cpu.c | 66 +---------------------------------- 1 file changed, 1 insertion(+), 65 deletions(-) mode change 100644 => 120000 compel/arch/arm/src/lib/cpu.c diff --git a/compel/arch/arm/src/lib/cpu.c b/compel/arch/arm/src/lib/cpu.c deleted file mode 100644 index cfaab1e65..000000000 --- a/compel/arch/arm/src/lib/cpu.c +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include - -#include "compel-cpu.h" - -#include "common/bitops.h" - -#include "log.h" - -#undef LOG_PREFIX -#define LOG_PREFIX "cpu: " - -static compel_cpuinfo_t rt_info; - -static void fetch_rt_cpuinfo(void) -{ - static bool rt_info_done = false; - - if (!rt_info_done) { - compel_cpuid(&rt_info); - rt_info_done = true; - } -} - -void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } -void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } -int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } -int compel_test_fpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } -int compel_cpuid(compel_cpuinfo_t *info) { return 0; } - -bool compel_cpu_has_feature(unsigned int feature) -{ - fetch_rt_cpuinfo(); - return compel_test_cpu_cap(&rt_info, feature); -} - -bool compel_fpu_has_feature(unsigned int feature) -{ - fetch_rt_cpuinfo(); - return compel_test_fpu_cap(&rt_info, feature); -} - -uint32_t compel_fpu_feature_size(unsigned int feature) -{ - fetch_rt_cpuinfo(); - return 0; -} - -uint32_t compel_fpu_feature_offset(unsigned int feature) -{ - fetch_rt_cpuinfo(); - return 0; -} - -void compel_cpu_clear_feature(unsigned int feature) -{ - fetch_rt_cpuinfo(); - return compel_clear_cpu_cap(&rt_info, feature); -} - -void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c) -{ - fetch_rt_cpuinfo(); - memcpy(c, &rt_info, sizeof(rt_info)); -} diff --git a/compel/arch/arm/src/lib/cpu.c b/compel/arch/arm/src/lib/cpu.c new file mode 120000 index 000000000..ceb924b73 --- /dev/null +++ b/compel/arch/arm/src/lib/cpu.c @@ -0,0 +1 @@ +../../../aarch64/src/lib/cpu.c \ No newline at end of file From 9166f90e5813b06d96296416215de5f3beeb67b7 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:43 +0300 Subject: [PATCH 1674/4375] x86: cpu -- Calculate number of image elems runtime Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index f451c6f4a..66c5476bb 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -13,6 +13,9 @@ #undef LOG_PREFIX #define LOG_PREFIX "x86: " +#define XSAVE_PB_NELEMS(__s, __obj, __member) \ + (sizeof(__s) / sizeof(*(__obj)->__member)) + int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) { CoreEntry *core = x; @@ -147,49 +150,49 @@ static void alloc_tls(ThreadInfoX86 *ti, void **mempool) static int alloc_xsave_extends(UserX86XsaveEntry *xsave) { if (compel_fpu_has_feature(XFEATURE_YMM)) { - xsave->n_ymmh_space = 64; + xsave->n_ymmh_space = XSAVE_PB_NELEMS(struct ymmh_struct, xsave, ymmh_space); xsave->ymmh_space = xzalloc(pb_repeated_size(xsave, ymmh_space)); if (!xsave->ymmh_space) goto err; } if (compel_fpu_has_feature(XFEATURE_BNDREGS)) { - xsave->n_bndreg_state = 4 * 2; + xsave->n_bndreg_state = XSAVE_PB_NELEMS(struct mpx_bndreg_state, xsave, bndreg_state); xsave->bndreg_state = xzalloc(pb_repeated_size(xsave, bndreg_state)); if (!xsave->bndreg_state) goto err; } if (compel_fpu_has_feature(XFEATURE_BNDCSR)) { - xsave->n_bndcsr_state = 2; + xsave->n_bndcsr_state = XSAVE_PB_NELEMS(struct mpx_bndcsr_state, xsave, bndcsr_state); xsave->bndcsr_state = xzalloc(pb_repeated_size(xsave, bndcsr_state)); if (!xsave->bndcsr_state) goto err; } if (compel_fpu_has_feature(XFEATURE_OPMASK)) { - xsave->n_opmask_reg = 8; + xsave->n_opmask_reg = XSAVE_PB_NELEMS(struct avx_512_opmask_state, xsave, opmask_reg); xsave->opmask_reg = xzalloc(pb_repeated_size(xsave, opmask_reg)); if (!xsave->opmask_reg) goto err; } if (compel_fpu_has_feature(XFEATURE_ZMM_Hi256)) { - xsave->n_zmm_upper = 16 * 4; + xsave->n_zmm_upper = XSAVE_PB_NELEMS(struct avx_512_zmm_uppers_state, xsave, zmm_upper); xsave->zmm_upper = xzalloc(pb_repeated_size(xsave, zmm_upper)); if (!xsave->zmm_upper) goto err; } if (compel_fpu_has_feature(XFEATURE_Hi16_ZMM)) { - xsave->n_hi16_zmm = 16 * 8; + xsave->n_hi16_zmm = XSAVE_PB_NELEMS(struct avx_512_hi16_state, xsave, hi16_zmm); xsave->hi16_zmm = xzalloc(pb_repeated_size(xsave, hi16_zmm)); if (!xsave->hi16_zmm) goto err; } if (compel_fpu_has_feature(XFEATURE_PKRU)) { - xsave->n_pkru = 2; + xsave->n_pkru = XSAVE_PB_NELEMS(struct pkru_state, xsave, pkru); xsave->pkru = xzalloc(pb_repeated_size(xsave, pkru)); if (!xsave->pkru) goto err; From 7f112e608454fe5fc93d5bd0677387af11ab39aa Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:44 +0300 Subject: [PATCH 1675/4375] x86: cpu -- Make detailed verification of xsave elements in image Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 68 +++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 66c5476bb..185ade407 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -287,6 +287,7 @@ void arch_free_thread_info(CoreEntry *core) static bool valid_xsave_frame(CoreEntry *core) { + UserX86XsaveEntry *xsave = core->thread_info->fpregs->xsave; struct xsave_struct *x = NULL; if (core->thread_info->fpregs->n_st_space < ARRAY_SIZE(x->i387.st_space)) { @@ -306,13 +307,62 @@ static bool valid_xsave_frame(CoreEntry *core) } if (compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) { - if (core->thread_info->fpregs->xsave && - core->thread_info->fpregs->xsave->n_ymmh_space < ARRAY_SIZE(x->ymmh.ymmh_space)) { - pr_err("Corruption in FPU ymmh_space area " - "(got %li but %li expected)\n", - (long)core->thread_info->fpregs->xsave->n_ymmh_space, - (long)ARRAY_SIZE(x->ymmh.ymmh_space)); - return false; + if (xsave) { + size_t i; + struct { + const char *name; + size_t expected; + size_t obtained; + void *ptr; + } features[] = { + { + .name = __stringify_1(XFEATURE_YMM), + .expected = XSAVE_PB_NELEMS(struct ymmh_struct, xsave, ymmh_space), + .obtained = xsave->n_ymmh_space, + .ptr = xsave->ymmh_space, + }, { + .name = __stringify_1(XFEATURE_BNDREGS), + .expected = XSAVE_PB_NELEMS(struct mpx_bndreg_state, xsave, bndreg_state), + .obtained = xsave->n_bndreg_state, + .ptr = xsave->bndreg_state, + }, { + .name = __stringify_1(XFEATURE_BNDCSR), + .expected = XSAVE_PB_NELEMS(struct mpx_bndcsr_state, xsave, bndcsr_state), + .obtained = xsave->n_bndcsr_state, + .ptr = xsave->bndcsr_state, + }, { + .name = __stringify_1(XFEATURE_OPMASK), + .expected = XSAVE_PB_NELEMS(struct avx_512_opmask_state, xsave, opmask_reg), + .obtained = xsave->n_opmask_reg, + .ptr = xsave->opmask_reg, + }, { + .name = __stringify_1(XFEATURE_ZMM_Hi256), + .expected = XSAVE_PB_NELEMS(struct avx_512_zmm_uppers_state, xsave, zmm_upper), + .obtained = xsave->n_zmm_upper, + .ptr = xsave->zmm_upper, + }, { + .name = __stringify_1(XFEATURE_Hi16_ZMM), + .expected = XSAVE_PB_NELEMS(struct avx_512_hi16_state, xsave, hi16_zmm), + .obtained = xsave->n_hi16_zmm, + .ptr = xsave->hi16_zmm, + }, { + .name = __stringify_1(XFEATURE_PKRU), + .expected = XSAVE_PB_NELEMS(struct pkru_state, xsave, pkru), + .obtained = xsave->n_pkru, + .ptr = xsave->pkru, + }, + }; + + for (i = 0; i < ARRAY_SIZE(features); i++) { + if (!features[i].ptr && i > 0) + continue; + + if (features[i].expected > features[i].obtained) { + pr_err("Corruption in %s area (expected %zu but %zu obtained)\n", + features[i].name, features[i].expected, features[i].obtained); + return false; + } + } } } else { /* @@ -320,13 +370,13 @@ static bool valid_xsave_frame(CoreEntry *core) * on must have X86_FEATURE_OSXSAVE feature until explicitly * stated in options. */ - if (core->thread_info->fpregs->xsave) { + if (xsave) { if (opts.cpu_cap & CPU_CAP_FPU) { pr_err("FPU xsave area present, " "but host cpu doesn't support it\n"); return false; } else - pr_warn_once("FPU is about to restore ignoring ymm state!\n"); + pr_warn_once("FPU is about to restore ignoring xsave state!\n"); } } From bcdbe22ab9c673ccdbeb2132eb47f4aefea1e853 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:45 +0300 Subject: [PATCH 1676/4375] x86: cpu -- Allow to proceed xsaves silently We fully support xsaves now, so no need for warning or any other message. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index e9c24af84..6ce2e88f3 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -32,15 +32,8 @@ static compel_cpuinfo_t rt_cpu_info; static int cpu_has_unsupported_features(void) { /* - * We don't support yet compacted xsave format so - * exit early if present. + * Put any unsupported features here. */ - if (compel_cpu_has_feature(X86_FEATURE_XSAVES)) { - pr_warn("Unsupported compact xsave frame on runtime cpu present\n"); - pr_warn("FIXME: Dazen and confused, but proceed for development reason\n"); - return 0; - } - return 0; } From 314801b9f005bd0d3a6083ae8b3b4295fa0196fe Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 19 Jul 2018 15:47:46 +0300 Subject: [PATCH 1677/4375] x86: cpu -- Drop feature bypassing We fully support xsaves, so no need for noxsaves temporary option anymore. This reverts commit ba93feb5f0f017f2ee498f6ee2db58bcaf817501. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/arch/aarch64/cpu.c | 5 ----- criu/arch/arm/cpu.c | 5 ----- criu/arch/ppc64/cpu.c | 5 ----- criu/arch/s390/cpu.c | 5 ----- criu/arch/x86/cpu.c | 24 ------------------------ criu/crtools.c | 5 ----- criu/include/cpu.h | 1 - 7 files changed, 50 deletions(-) diff --git a/criu/arch/aarch64/cpu.c b/criu/arch/aarch64/cpu.c index ef339f2f1..34313fb15 100644 --- a/criu/arch/aarch64/cpu.c +++ b/criu/arch/aarch64/cpu.c @@ -38,8 +38,3 @@ int cpuinfo_check(void) { return -ENOTSUP; } - -int cpu_parse_option(const char *opt) -{ - return -ENOTSUP; -} diff --git a/criu/arch/arm/cpu.c b/criu/arch/arm/cpu.c index ef339f2f1..34313fb15 100644 --- a/criu/arch/arm/cpu.c +++ b/criu/arch/arm/cpu.c @@ -38,8 +38,3 @@ int cpuinfo_check(void) { return -ENOTSUP; } - -int cpu_parse_option(const char *opt) -{ - return -ENOTSUP; -} diff --git a/criu/arch/ppc64/cpu.c b/criu/arch/ppc64/cpu.c index cdee8c72f..4fcfb065a 100644 --- a/criu/arch/ppc64/cpu.c +++ b/criu/arch/ppc64/cpu.c @@ -140,8 +140,3 @@ int cpuinfo_check(void) return 0; } - -int cpu_parse_option(const char *opt) -{ - return -1; -} diff --git a/criu/arch/s390/cpu.c b/criu/arch/s390/cpu.c index 5f6b83f70..f93666ed6 100644 --- a/criu/arch/s390/cpu.c +++ b/criu/arch/s390/cpu.c @@ -156,8 +156,3 @@ int cpuinfo_check(void) return 1; return 0; } - -int cpu_parse_option(const char *opt) -{ - return -1; -} diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index 6ce2e88f3..35660929d 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -438,27 +438,3 @@ int cpuinfo_check(void) return 0; } - -int cpu_parse_option(const char *opt) -{ - static struct { - const char *name; - unsigned int feature; - } filters[] = { - { - .name = "noxsaves", - .feature = X86_FEATURE_XSAVES, - }, - }; - - size_t i; - - for (i = 0; i < ARRAY_SIZE(filters); i++) { - if (strncmp(opt, filters[i].name, strlen(filters[i].name))) - continue; - compel_cpu_clear_feature(filters[i].feature); - return strlen(filters[i].name); - } - - return -1; -} diff --git a/criu/crtools.c b/criu/crtools.c index 2f89b69cf..66391be22 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -152,11 +152,6 @@ static int parse_cpu_cap(struct cr_options *opts, const char *optarg) } else if (!strncmp(optarg, "ins", 3)) { ____cpu_set_cap(opts, CPU_CAP_INS, inverse); optarg += 3; - } else if (!strncmp(optarg, "op=", 3)) { - int pos = cpu_parse_option(&optarg[3]); - if (pos <= 0) - goto Esyntax; - optarg += pos + 3; } else goto Esyntax; } diff --git a/criu/include/cpu.h b/criu/include/cpu.h index 09b3c7899..e30696790 100644 --- a/criu/include/cpu.h +++ b/criu/include/cpu.h @@ -8,6 +8,5 @@ extern int cpu_dump_cpuinfo(void); extern int cpu_validate_cpuinfo(void); extern int cpuinfo_dump(void); extern int cpuinfo_check(void); -extern int cpu_parse_option(const char *opt); #endif /* __CR_CPU_H__ */ From faa8bae6f214d504bd08324a4d684734a88001f2 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 12 Jul 2018 15:51:32 +0300 Subject: [PATCH 1678/4375] nmk: Don't include deps on mrproper mrproper doesn't require inclusion of deps similar as clean target. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/build.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nmk/scripts/build.mk b/scripts/nmk/scripts/build.mk index a6bd47d52..890a912d0 100644 --- a/scripts/nmk/scripts/build.mk +++ b/scripts/nmk/scripts/build.mk @@ -270,7 +270,7 @@ define collect-deps endef ifneq ($(MAKECMDGOALS),) - ifneq ($(MAKECMDGOALS),clean) + ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) $(foreach goal,$(MAKECMDGOALS),$(eval $(call collect-deps,$(goal)))) deps-y := $(call uniq,$(deps-y)) ifneq ($(deps-y),) From 6ed2532b362c7cdd521922e98247146da167b6cd Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 12 Jul 2018 15:51:33 +0300 Subject: [PATCH 1679/4375] nmk: Filter out already seen targets from collect-deps Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/build.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nmk/scripts/build.mk b/scripts/nmk/scripts/build.mk index 890a912d0..f16af03f2 100644 --- a/scripts/nmk/scripts/build.mk +++ b/scripts/nmk/scripts/build.mk @@ -261,7 +261,7 @@ define collect-deps ifeq ($(lib-target),$(1)) deps-y += $(lib-y:.o=.d) endif - ifneq ($(filter all $(all-y) $(hostprogs-y),$(1)),) + ifneq ($(filter all $(filter-out $(builtin-target) $(lib-target), $(all-y)) $(hostprogs-y),$(1)),) deps-y += $(obj-y:.o=.d) deps-y += $(lib-y:.o=.d) deps-y += $(foreach t,$(target),$(call objectify,$($(t)-lib-y:.o=.d)) $(call objectify,$($(t)-obj-y:.o=.d))) From d3b4fbc2ac8f7f01be6f90c22a55d8820fcce5cc Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 12 Jul 2018 15:51:34 +0300 Subject: [PATCH 1680/4375] nmk: Gather reserved vars on top of build Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/build.mk | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/scripts/nmk/scripts/build.mk b/scripts/nmk/scripts/build.mk index f16af03f2..25c563d25 100644 --- a/scripts/nmk/scripts/build.mk +++ b/scripts/nmk/scripts/build.mk @@ -6,17 +6,25 @@ ifndef ____nmk_defined__build src := $(obj) src-makefile := $(call objectify,$(makefile)) obj-y := +obj-e := +builtin-name := +builtin-target := lib-y := +lib-e := +lib-name := +lib-target := +hostprogs-y := +libso-y := +ld_flags := +ldflags-so := +arflags-y := target := deps-y := all-y := -builtin-name := -lib-name := -ld_flags := cleanup-y := mrproper-y := +target := objdirs := -libso-y := MAKECMDGOALS := $(call uniq,$(MAKECMDGOALS)) @@ -112,7 +120,6 @@ $(eval $(call gen-cc-rules,$(obj)/%,$(obj)/%)) # # Prepare targets. ifneq ($(lib-y),) - lib-target := ifneq ($(lib-name),) lib-target := $(obj)/$(lib-name) else @@ -125,7 +132,6 @@ ifneq ($(lib-y),) endif ifneq ($(obj-y),) - builtin-target := ifneq ($(builtin-name),) builtin-target := $(obj)/$(builtin-name) else From edbac23ffb5810b6092af4d2b8455966dc155d17 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 12 Jul 2018 15:51:35 +0300 Subject: [PATCH 1681/4375] nmk: Drop unneeded ld_flags Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/build.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/nmk/scripts/build.mk b/scripts/nmk/scripts/build.mk index 25c563d25..cdbe4c625 100644 --- a/scripts/nmk/scripts/build.mk +++ b/scripts/nmk/scripts/build.mk @@ -111,7 +111,7 @@ builtin-name := $(strip $(builtin-name)) # # Link flags. -ld_flags := $(strip $(LDFLAGS) $(ldflags-y)) +ldflags-y := $(strip $(LDFLAGS) $(ldflags-y)) # # $(obj) related rules. @@ -162,7 +162,7 @@ endef ifdef builtin-target $(eval $(call gen-ld-target-rule, \ $(builtin-target), \ - $(ld_flags), \ + $(ldflags-y), \ $(obj-y) $(__nmk-makefile-deps), \ $(obj-y) $(call objectify,$(obj-e)))) endif @@ -181,7 +181,7 @@ define gen-custom-target-rule ifneq ($($(1)-obj-y),) $(eval $(call gen-ld-target-rule, \ $(obj)/$(1).built-in.o, \ - $(ld_flags) $(LDFLAGS_$(1)), \ + $(ldflags-y) $(LDFLAGS_$(1)), \ $(call objectify,$($(1)-obj-y)) \ $(__nmk-makefile-deps), \ $(call objectify,$($(1)-obj-y)) \ From 733c5b0b6fd5de1fc44fae1360963fb050eaf1b5 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 12 Jul 2018 15:51:36 +0300 Subject: [PATCH 1682/4375] nmk: Align continuations Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/build.mk | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/nmk/scripts/build.mk b/scripts/nmk/scripts/build.mk index cdbe4c625..dbf2bbf0a 100644 --- a/scripts/nmk/scripts/build.mk +++ b/scripts/nmk/scripts/build.mk @@ -162,8 +162,8 @@ endef ifdef builtin-target $(eval $(call gen-ld-target-rule, \ $(builtin-target), \ - $(ldflags-y), \ - $(obj-y) $(__nmk-makefile-deps), \ + $(ldflags-y), \ + $(obj-y) $(__nmk-makefile-deps), \ $(obj-y) $(call objectify,$(obj-e)))) endif @@ -171,7 +171,7 @@ ifdef lib-target $(eval $(call gen-ar-target-rule, \ $(lib-target), \ $(ARFLAGS) $(arflags-y), \ - $(lib-y) $(__nmk-makefile-deps), \ + $(lib-y) $(__nmk-makefile-deps), \ $(lib-y) $(call objectify,$(lib-e)))) endif @@ -181,9 +181,9 @@ define gen-custom-target-rule ifneq ($($(1)-obj-y),) $(eval $(call gen-ld-target-rule, \ $(obj)/$(1).built-in.o, \ - $(ldflags-y) $(LDFLAGS_$(1)), \ + $(ldflags-y) $(LDFLAGS_$(1)), \ $(call objectify,$($(1)-obj-y)) \ - $(__nmk-makefile-deps), \ + $(__nmk-makefile-deps), \ $(call objectify,$($(1)-obj-y)) \ $(call objectify,$($(1)-obj-e)))) all-y += $(obj)/$(1).built-in.o @@ -196,7 +196,7 @@ define gen-custom-target-rule $(obj)/$(1).lib.a, \ $(ARFLAGS) $($(1)-arflags-y), \ $(call objectify,$($(1)-lib-y)) \ - $(__nmk-makefile-deps), \ + $(__nmk-makefile-deps), \ $(call objectify,$($(1)-lib-y))) \ $(call objectify,$($(1)-lib-e))) all-y += $(obj)/$(1).lib.a From e4f62b929c56c02e1d844137dd644812bc9d288f Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 12 Jul 2018 15:51:37 +0300 Subject: [PATCH 1683/4375] nmk: Add collect-hostprogs-deps helper Thus will include hostprogs deps only if requested. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/build.mk | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/nmk/scripts/build.mk b/scripts/nmk/scripts/build.mk index dbf2bbf0a..82b2876dc 100644 --- a/scripts/nmk/scripts/build.mk +++ b/scripts/nmk/scripts/build.mk @@ -255,6 +255,11 @@ $(foreach t,$(libso-y),$(eval $(call gen-so-link-rules,$(t)))) # # Figure out if the target we're building needs deps to include. +define collect-hostprogs-deps + ifeq ($(1),$(2)) + deps-y += $(addprefix $(obj)/,$($(1)-objs:.o=.d)) + endif +endef define collect-deps ifneq ($(filter-out %.d,$(1)),) ifneq ($(filter %.o %.i %.s,$(1)),) @@ -267,11 +272,12 @@ define collect-deps ifeq ($(lib-target),$(1)) deps-y += $(lib-y:.o=.d) endif + $(foreach t,$(hostprogs-y),$(eval $(call collect-hostprogs-deps,$(t),$(1)))) ifneq ($(filter all $(filter-out $(builtin-target) $(lib-target), $(all-y)) $(hostprogs-y),$(1)),) deps-y += $(obj-y:.o=.d) deps-y += $(lib-y:.o=.d) deps-y += $(foreach t,$(target),$(call objectify,$($(t)-lib-y:.o=.d)) $(call objectify,$($(t)-obj-y:.o=.d))) - deps-y += $(foreach t,$(hostprogs-y),$(addprefix $(obj)/,$($(t)-objs:.o=.d))) + $(foreach t,$(hostprogs-y),$(eval $(call collect-hostprogs-deps,$(t),$(t)))) endif endef From dfaf0868b480ea8c7265ea8c407ed2502b8dcd5c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 12 Jul 2018 15:51:38 +0300 Subject: [PATCH 1684/4375] nmk: Add collect-target-deps helper Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/build.mk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/nmk/scripts/build.mk b/scripts/nmk/scripts/build.mk index 82b2876dc..e55fd5726 100644 --- a/scripts/nmk/scripts/build.mk +++ b/scripts/nmk/scripts/build.mk @@ -260,6 +260,12 @@ define collect-hostprogs-deps deps-y += $(addprefix $(obj)/,$($(1)-objs:.o=.d)) endif endef +define collect-target-deps + ifeq ($(1),$(2)) + deps-y += $(call objectify,$($(t)-lib-y:.o=.d)) + deps-y += $(call objectify,$($(t)-obj-y:.o=.d)) + endif +endef define collect-deps ifneq ($(filter-out %.d,$(1)),) ifneq ($(filter %.o %.i %.s,$(1)),) @@ -273,11 +279,12 @@ define collect-deps deps-y += $(lib-y:.o=.d) endif $(foreach t,$(hostprogs-y),$(eval $(call collect-hostprogs-deps,$(t),$(1)))) + $(foreach t,$(target),$(eval $(call collect-target-deps,$(t),$(1)))) ifneq ($(filter all $(filter-out $(builtin-target) $(lib-target), $(all-y)) $(hostprogs-y),$(1)),) deps-y += $(obj-y:.o=.d) deps-y += $(lib-y:.o=.d) - deps-y += $(foreach t,$(target),$(call objectify,$($(t)-lib-y:.o=.d)) $(call objectify,$($(t)-obj-y:.o=.d))) $(foreach t,$(hostprogs-y),$(eval $(call collect-hostprogs-deps,$(t),$(t)))) + $(foreach t,$(target),$(eval $(call collect-target-deps,$(t),$(t)))) endif endef From 44b670532451e550414c487a0ad2516a82596715 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 12 Jul 2018 15:51:39 +0300 Subject: [PATCH 1685/4375] nmk: Add obj and lib deps gathering via helpers Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/build.mk | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/scripts/nmk/scripts/build.mk b/scripts/nmk/scripts/build.mk index e55fd5726..bf5048fca 100644 --- a/scripts/nmk/scripts/build.mk +++ b/scripts/nmk/scripts/build.mk @@ -255,6 +255,16 @@ $(foreach t,$(libso-y),$(eval $(call gen-so-link-rules,$(t)))) # # Figure out if the target we're building needs deps to include. +define collect-builtin-deps + ifeq ($(1),$(2)) + deps-y += $(obj-y:.o=.d) + endif +endef +define collect-lib-deps + ifeq ($(1),$(2)) + deps-y += $(lib-y:.o=.d) + endif +endef define collect-hostprogs-deps ifeq ($(1),$(2)) deps-y += $(addprefix $(obj)/,$($(1)-objs:.o=.d)) @@ -272,12 +282,8 @@ define collect-deps deps-y += $(addsuffix .d,$(basename $(1))) endif endif - ifeq ($(builtin-target),$(1)) - deps-y += $(obj-y:.o=.d) - endif - ifeq ($(lib-target),$(1)) - deps-y += $(lib-y:.o=.d) - endif + $(eval $(call collect-builtin-deps,$(builtin-target),$(1))) + $(eval $(call collect-lib-deps,$(lib-target),$(1))) $(foreach t,$(hostprogs-y),$(eval $(call collect-hostprogs-deps,$(t),$(1)))) $(foreach t,$(target),$(eval $(call collect-target-deps,$(t),$(1)))) ifneq ($(filter all $(filter-out $(builtin-target) $(lib-target), $(all-y)) $(hostprogs-y),$(1)),) From 9ca150867f8889b667cb63033f41fd6fc2c2713a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 12 Jul 2018 15:51:40 +0300 Subject: [PATCH 1686/4375] nmk: Make collect-deps to be more precise about targets Thus to choose which deps to include, for example if only particular file is being build there is no need to include any other deps. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/build.mk | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/scripts/nmk/scripts/build.mk b/scripts/nmk/scripts/build.mk index bf5048fca..d01d2b72c 100644 --- a/scripts/nmk/scripts/build.mk +++ b/scripts/nmk/scripts/build.mk @@ -277,20 +277,22 @@ define collect-target-deps endif endef define collect-deps - ifneq ($(filter-out %.d,$(1)),) - ifneq ($(filter %.o %.i %.s,$(1)),) - deps-y += $(addsuffix .d,$(basename $(1))) - endif - endif - $(eval $(call collect-builtin-deps,$(builtin-target),$(1))) - $(eval $(call collect-lib-deps,$(lib-target),$(1))) - $(foreach t,$(hostprogs-y),$(eval $(call collect-hostprogs-deps,$(t),$(1)))) - $(foreach t,$(target),$(eval $(call collect-target-deps,$(t),$(1)))) - ifneq ($(filter all $(filter-out $(builtin-target) $(lib-target), $(all-y)) $(hostprogs-y),$(1)),) - deps-y += $(obj-y:.o=.d) - deps-y += $(lib-y:.o=.d) + ifneq ($(filter all,$(1)),) + $(eval $(call collect-builtin-deps,$(builtin-target),$(builtin-target))) + $(eval $(call collect-lib-deps,$(lib-target),$(lib-target))) $(foreach t,$(hostprogs-y),$(eval $(call collect-hostprogs-deps,$(t),$(t)))) $(foreach t,$(target),$(eval $(call collect-target-deps,$(t),$(t)))) + else + ifneq ($(filter-out %.d $(builtin-target) $(lib-target) $(hostprogs-y) $(target),$(1)),) + ifneq ($(filter %.o %.i %.s,$(1)),) + deps-y += $(addsuffix .d,$(basename $(1))) + endif + else + $(eval $(call collect-builtin-deps,$(builtin-target),$(1))) + $(eval $(call collect-lib-deps,$(lib-target),$(1))) + $(foreach t,$(hostprogs-y),$(eval $(call collect-hostprogs-deps,$(t),$(1)))) + $(foreach t,$(target),$(eval $(call collect-target-deps,$(t),$(1)))) + endif endif endef From 3c044783afb6201219796720da4d3c6e51044f61 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 12 Jul 2018 15:51:41 +0300 Subject: [PATCH 1687/4375] compel: Move lib files into lib-y They were occasionally kept in obj-y. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index 7ef01aa01..f751d6a74 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -24,6 +24,10 @@ host-lib-y += src/lib/log.o lib-y += arch/$(ARCH)/src/lib/cpu.o lib-y += arch/$(ARCH)/src/lib/infect.o +lib-y += arch/$(ARCH)/src/lib/handle-elf.o +host-lib-y += arch/$(ARCH)/src/lib/handle-elf.o +lib-y += src/lib/handle-elf.o +host-lib-y += src/lib/handle-elf.o lib-y += src/lib/infect-rpc.o lib-y += src/lib/infect-util.o lib-y += src/lib/infect.o @@ -36,8 +40,6 @@ HOSTCFLAGS += -DNO_RELOCS endif obj-y += src/main.o -obj-y += arch/$(ARCH)/src/lib/handle-elf.o -obj-y += src/lib/handle-elf.o host-ccflags-y += $(ccflags-y) From f5c427116d361a226a8a8d8c28cda275dac0e7ea Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 12 Jul 2018 15:51:42 +0300 Subject: [PATCH 1688/4375] compel: Make sure the hostprog is built early The host compel-host-bin must be built before criu, same time the criu itself should not depend on libcompel or plugins because they are the part of the compel package. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- Makefile.compel | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile.compel b/Makefile.compel index 8768c795d..764afadc8 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -27,8 +27,6 @@ compel-plugins += compel/plugins/std.lib.a compel/plugins/fds.lib.a LIBCOMPEL_SO := libcompel.so LIBCOMPEL_A := libcompel.a export LIBCOMPEL_SO LIBCOMPEL_A -criu-deps += compel/$(LIBCOMPEL_A) -criu-deps += $(compel-plugins) # # Compel itself. @@ -38,6 +36,12 @@ compel/%: $(compel-deps) $(compel-plugins) .FORCE criu-deps += compel/compel-host-bin +# +# Make sure the host program is ready after the +# library and plugins are built. +compel/compel-host-bin: | compel/$(LIBCOMPEL_A) $(compel-plugins) +$(COMPEL_BIN): compel/compel-host-bin + # # Plugins compel/plugins/Makefile: ; From 79fdf2081042a787521110b1f7906ce63a05a94d Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 26 Jul 2018 11:18:06 +0200 Subject: [PATCH 1689/4375] image: add a few missing newlines in pr_warn() Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/image.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/criu/image.c b/criu/image.c index 16ac0e35f..3564a8a41 100644 --- a/criu/image.c +++ b/criu/image.c @@ -130,26 +130,26 @@ InventoryEntry *get_parent_inventory(void) dir = openat(get_service_fd(IMG_FD_OFF), CR_PARENT_LINK, O_RDONLY); if (dir == -1) { - pr_warn("Failed to open parent directory"); + pr_warn("Failed to open parent directory\n"); return NULL; } img = open_image_at(dir, CR_FD_INVENTORY, O_RSTR); if (!img) { - pr_warn("Failed to open parent pre-dump inventory image"); + pr_warn("Failed to open parent pre-dump inventory image\n"); close(dir); return NULL; } if (pb_read_one(img, &ie, PB_INVENTORY) < 0) { - pr_warn("Failed to read parent pre-dump inventory entry"); + pr_warn("Failed to read parent pre-dump inventory entry\n"); close_image(img); close(dir); return NULL; } if (!ie->has_dump_uptime) { - pr_warn("Parent pre-dump inventory has no uptime"); + pr_warn("Parent pre-dump inventory has no uptime\n"); inventory_entry__free_unpacked(ie, NULL); ie = NULL; } From 8c817b2b0a6973958847ccaed5bae50e7b33d52e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 12 Jul 2018 23:41:43 +0300 Subject: [PATCH 1690/4375] service: don't leak a file descriptor CID 190777 (#1 of 1): Resource leak (RESOURCE_LEAK) 15. leaked_handle: Handle variable server_fd going out of scope leaks the handle. Signed-off-by: Andrei Vagin --- criu/cr-service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 3a07d5b76..e9401be3a 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -1207,7 +1207,7 @@ int cr_service(bool daemon_mode) goto err; if (close_status_fd()) - return -1; + goto err; while (1) { int sk; From 80d2c2153537b517bdddeaa0e7583be8c51cdf0c Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 12 Jul 2018 23:41:44 +0300 Subject: [PATCH 1691/4375] mount: don't dereference pointer before null check CID 190775 (#1 of 1): Dereference before null check (REVERSE_INULL) check_after_deref: Null-checking m->parent suggests that it may be null, but it has already been dereferenced on all paths leading to the check. Signed-off-by: Andrei Vagin --- criu/mount.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index d2292cd8e..62e012ec5 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -833,13 +833,14 @@ static int resolve_external_mounts(struct mount_info *info) static int root_path_from_parent(struct mount_info *m, char *buf, int size) { bool head_slash = false, tail_slash = false; - int p_len = strlen(m->parent->mountpoint), - m_len = strlen(m->mountpoint), - len; + int p_len, m_len, len; if (!m->parent) return -1; + p_len = strlen(m->parent->mountpoint), + m_len = strlen(m->mountpoint), + len = snprintf(buf, size, "%s", m->parent->root); if (len >= size) return -1; From 682610a9fa095d10e80039c7a3025f7793a542b9 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 12 Jul 2018 23:41:45 +0300 Subject: [PATCH 1692/4375] unix: check that a length of a socket is less than UNIX_PATH_MAX CID 190774 (#1 of 1): Out-of-bounds access (OVERRUN) 5. overrun-buffer-arg: Overrunning array addr.sun_path of 108 bytes by passing it to a function which accesses it at byte offset 4094 using argument ui->ue->name.len (which evaluates to 4095). Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index cfe0fa18b..cedbd2f88 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1408,7 +1408,7 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) bool renamed = false; int ret; - if (ui->ue->name.len >= sizeof(path)) { + if (ui->ue->name.len >= sizeof(UNIX_PATH_MAX)) { pr_err("ghost: Too long name for socket id %#x ino %d name %s\n", ui->ue->id, ui->ue->ino, ui->name); return -ENOSPC; From 7842fa1df27dc07f42e686a86b545f508296b75c Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 1 Feb 2018 22:29:06 +0300 Subject: [PATCH 1693/4375] criu: dump and restore a thread name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: 志平 林 Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 3 +++ criu/cr-restore.c | 5 +++++ criu/include/parasite.h | 1 + criu/include/restorer.h | 2 ++ criu/pie/parasite.c | 18 +++++++++++++++--- criu/pie/restorer.c | 6 ++++++ images/core.proto | 2 ++ 7 files changed, 34 insertions(+), 3 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index b6c3883e3..f7d9b2b09 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -716,6 +716,9 @@ int dump_thread_core(int pid, CoreEntry *core, const struct parasite_dump_thread tc->has_pdeath_sig = true; tc->pdeath_sig = ti->pdeath_sig; } + tc->comm = xstrdup(ti->comm); + if (tc->comm == NULL) + return -1; } if (!ret) ret = seccomp_dump_thread(pid, tc); diff --git a/criu/cr-restore.c b/criu/cr-restore.c index edbce5d1f..60e095695 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3461,6 +3461,11 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns if (construct_sigframe(sigframe, sigframe, blkset, tcore)) goto err; + if (thread_args[i].comm) + strncpy(thread_args[i].comm, tcore->thread_core->comm, TASK_COMM_LEN); + else + strncpy(thread_args[i].comm, core->tc->comm, TASK_COMM_LEN); + if (thread_args[i].pid != pid) core_entry__free_unpacked(tcore, NULL); diff --git a/criu/include/parasite.h b/criu/include/parasite.h index 9de0d2e9a..9e2e1498e 100644 --- a/criu/include/parasite.h +++ b/criu/include/parasite.h @@ -170,6 +170,7 @@ struct parasite_dump_thread { tls_t tls; stack_t sas; int pdeath_sig; + char comm[TASK_COMM_LEN]; struct parasite_dump_creds creds[0]; }; diff --git a/criu/include/restorer.h b/criu/include/restorer.h index fd94de6ca..de14eff95 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -110,6 +110,8 @@ struct thread_restore_args { void *seccomp_filters_data; unsigned int seccomp_filters_n; bool seccomp_force_tsync; + + char comm[TASK_COMM_LEN]; } __aligned(64); typedef long (*thread_restore_fcall_t) (struct thread_restore_args *args); diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index b9dae3f94..1567ed7a5 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -172,16 +172,28 @@ static int dump_thread_common(struct parasite_dump_thread *ti) arch_get_tls(&ti->tls); ret = sys_prctl(PR_GET_TID_ADDRESS, (unsigned long) &ti->tid_addr, 0, 0, 0); - if (ret) + if (ret) { + pr_err("Unable to get the clear_child_tid address: %d\n", ret); goto out; + } ret = sys_sigaltstack(NULL, &ti->sas); - if (ret) + if (ret) { + pr_err("Unable to get signal stack context: %d\n", ret); goto out; + } ret = sys_prctl(PR_GET_PDEATHSIG, (unsigned long)&ti->pdeath_sig, 0, 0, 0); - if (ret) + if (ret) { + pr_err("Unable to get the parent death signal: %d\n", ret); goto out; + } + + ret = sys_prctl(PR_GET_NAME, (unsigned long) &ti->comm, 0, 0, 0); + if (ret) { + pr_err("Unable to get the thread name: %d\n", ret); + goto out; + } ret = dump_creds(ti->creds); out: diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index e5a40a977..5f442e4a2 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -554,6 +554,12 @@ long __export_restore_thread(struct thread_restore_args *args) if (restore_thread_common(args)) goto core_restore_end; + ret = sys_prctl(PR_SET_NAME, (unsigned long) &args->comm, 0, 0, 0); + if (ret) { + pr_err("Unable to set a thread name: %d\n", ret); + goto core_restore_end; + } + pr_info("%ld: Restored\n", sys_gettid()); restore_finish_stage(task_entries_local, CR_STATE_RESTORE); diff --git a/images/core.proto b/images/core.proto index f9a66b2ae..ce25b0971 100644 --- a/images/core.proto +++ b/images/core.proto @@ -86,6 +86,8 @@ message thread_core_entry { optional seccomp_mode seccomp_mode = 11; optional uint32 seccomp_filter = 12; + + optional string comm = 13; } message task_rlimits_entry { From d9ea1ca1a70b35fda5b50a7c2bd83f4280ff2383 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 27 Jul 2018 21:50:49 +0300 Subject: [PATCH 1694/4375] unix: typo fix Fixes: e8f913fbfd9d ("unix: check that a length of a socket is less than UNIX_PATH_MAX") Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index cedbd2f88..d7086bbc6 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1408,7 +1408,7 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) bool renamed = false; int ret; - if (ui->ue->name.len >= sizeof(UNIX_PATH_MAX)) { + if (ui->ue->name.len >= UNIX_PATH_MAX) { pr_err("ghost: Too long name for socket id %#x ino %d name %s\n", ui->ue->id, ui->ue->ino, ui->name); return -ENOSPC; From 75d049c5a75fe1f11852273fea8b2f66dc97f1a5 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 27 Jul 2018 22:22:15 +0300 Subject: [PATCH 1695/4375] Revert "test: check criu restore with --auto-dedup" This reverts commit 8f1ba5892dd2b137a24e144febed2464f245ed1a. This test doesn't work right now: =[log]=> dump/zdtm/transition/maps007/174/3/restore.log ------------------------ grep Error ------------------------ (00.237564) 1: `- FD 2 pid 6 (00.237566) 1: `- type 1 ID 0xa (00.237567) 1: `- FD 3 pid 5 (00.237568) 1: `- FD 3 pid 6 (00.240025) 1: Error (criu/image.c:432): Unable to open pages-3.img: Permission denied (00.270600) uns: calling exit_usernsd (-1, 1) (00.270640) uns: daemon calls 0x469f80 (199, -1, 1) (00.270648) uns: `- daemon exits w/ 0 (00.271193) uns: daemon stopped (00.271199) Error (criu/cr-restore.c:2308): Restoring FAILED. ------------------------ ERROR OVER ------------------------ Signed-off-by: Andrei Vagin --- test/zdtm.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 2a3742f8f..99ec6aaac 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1105,9 +1105,6 @@ class criu: r_opts += ['--empty-ns', 'net'] r_opts += ['--action-script', os.getcwd() + '/empty-netns-prep.sh'] - if self.__dedup: - r_opts += ["--auto-dedup"] - self.__prev_dump_iter = None criu_dir = os.path.dirname(os.getcwd()) if os.getenv("GCOV"): From 5ef034862bfb747b8f96173d2d7940abd24ef082 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 28 Jul 2018 00:44:33 +0300 Subject: [PATCH 1696/4375] restore: check whether a thread core contains comm or not CC criu/cr-restore.o criu/cr-restore.c:3470:22: error: address of array 'thread_args[i].comm' will always evaluate to 'true' [-Werror,-Wpointer-bool-conversion] if (thread_args[i].comm) ~~ ~~~~~~~~~~~~~~~^~~~ 1 error generated. Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 60e095695..192c3a2be 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3461,7 +3461,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns if (construct_sigframe(sigframe, sigframe, blkset, tcore)) goto err; - if (thread_args[i].comm) + if (tcore->thread_core->comm) strncpy(thread_args[i].comm, tcore->thread_core->comm, TASK_COMM_LEN); else strncpy(thread_args[i].comm, core->tc->comm, TASK_COMM_LEN); From 139d2dbf0b5098c560819c411e3b1f8f47e07d17 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 1 Aug 2018 16:31:13 +0000 Subject: [PATCH 1697/4375] config: move getopt out of main() This moves the whole getopt setup and analysis out of main() into its own function in config.c. The main motivation for this change is to be able to call getopt parsing and configuration file parsing also from the RPC code path. In one of the discussion emails about configuration files in CLI and RPC mode the following architecture was proposed: apply_config(global_conf) apply_config(user_conf) apply_config(pre_conf) parse_command_line() apply_rpc_options() apply_config(post_conf) And especially for the last step the getopt parsing needs to be out of main() and callable from the RPC code path. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/config.c | 576 +++++++++++++++++++++++++++++++++++++- criu/crtools.c | 559 ++---------------------------------- criu/include/cr_options.h | 7 +- criu/include/crtools.h | 4 - 4 files changed, 594 insertions(+), 552 deletions(-) diff --git a/criu/config.c b/criu/config.c index a39696dc3..df802e6a9 100644 --- a/criu/config.c +++ b/criu/config.c @@ -1,16 +1,36 @@ -#include -#include -#include #include +#include #include +#include +#include +#include +#include #include "log.h" +#include "common/list.h" + +#include "action-scripts.h" +#include "cgroup.h" +#include "cgroup-props.h" +#include "common/bug.h" +#include "cpu.h" #include "crtools.h" +#include "cr_options.h" +#include "filesystems.h" +#include "file-lock.h" +#include "irmap.h" +#include "mount.h" +#include "namespaces.h" +#include "net.h" +#include "sk-inet.h" +#include "sockets.h" +#include "tty.h" +#include "version.h" #include "common/xmalloc.h" -extern char **global_conf; -extern char **user_conf; +char **global_conf = NULL; +char **user_conf = NULL; static int count_elements(char **to_count) { @@ -154,7 +174,7 @@ static void init_configuration(int argc, char *argv[], bool no_default_config, } } -int init_config(int argc, char **argv, int *global_cfg_argc, int *user_cfg_argc, +static int init_config(int argc, char **argv, int *global_cfg_argc, int *user_cfg_argc, bool *usage_error) { bool no_default_config = false; @@ -198,3 +218,547 @@ int init_config(int argc, char **argv, int *global_cfg_argc, int *user_cfg_argc, return 0; } + +static int parse_cpu_cap(struct cr_options *opts, const char *optarg) +{ + bool inverse = false; + +#define ____cpu_set_cap(__opts, __cap, __inverse) \ + do { \ + if ((__inverse)) \ + (__opts)->cpu_cap &= ~(__cap); \ + else \ + (__opts)->cpu_cap |= (__cap); \ + } while (0) + + if (!optarg) { + ____cpu_set_cap(opts, CPU_CAP_ALL, false); + return 0; + } + + while (*optarg) { + if (optarg[0] == '^') { + inverse = !inverse; + optarg++; + continue; + } else if (optarg[0] == ',') { + inverse = false; + optarg++; + continue; + } + + if (!strncmp(optarg, "fpu", 3)) { + ____cpu_set_cap(opts, CPU_CAP_FPU, inverse); + optarg += 3; + } else if (!strncmp(optarg, "all", 3)) { + ____cpu_set_cap(opts, CPU_CAP_ALL, inverse); + optarg += 3; + } else if (!strncmp(optarg, "none", 4)) { + if (inverse) + opts->cpu_cap = CPU_CAP_ALL; + else + opts->cpu_cap = CPU_CAP_NONE; + optarg += 4; + } else if (!strncmp(optarg, "cpu", 3)) { + ____cpu_set_cap(opts, CPU_CAP_CPU, inverse); + optarg += 3; + } else if (!strncmp(optarg, "ins", 3)) { + ____cpu_set_cap(opts, CPU_CAP_INS, inverse); + optarg += 3; + } else + goto Esyntax; + } +#undef ____cpu_set_cap + + return 0; + +Esyntax: + pr_err("Unknown FPU mode `%s' selected\n", optarg); + return -1; +} + +static int parse_manage_cgroups(struct cr_options *opts, const char *optarg) +{ + if (!optarg) { + opts->manage_cgroups = CG_MODE_SOFT; + return 0; + } + + if (!strcmp(optarg, "none")) { + opts->manage_cgroups = CG_MODE_NONE; + } else if (!strcmp(optarg, "props")) { + opts->manage_cgroups = CG_MODE_PROPS; + } else if (!strcmp(optarg, "soft")) { + opts->manage_cgroups = CG_MODE_SOFT; + } else if (!strcmp(optarg, "full")) { + opts->manage_cgroups = CG_MODE_FULL; + } else if (!strcmp(optarg, "strict")) { + opts->manage_cgroups = CG_MODE_STRICT; + } else + goto Esyntax; + + return 0; + +Esyntax: + pr_err("Unknown cgroups mode `%s' selected\n", optarg); + return -1; +} + +static size_t parse_size(char *optarg) +{ + if (index(optarg, 'K')) + return (size_t)KILO(atol(optarg)); + else if (index(optarg, 'M')) + return (size_t)MEGA(atol(optarg)); + else if (index(optarg, 'G')) + return (size_t)GIGA(atol(optarg)); + return (size_t)atol(optarg); +} + +static int parse_join_ns(const char *ptr) +{ + char *aux, *ns_file, *extra_opts = NULL; + + aux = strchr(ptr, ':'); + if (aux == NULL) + return -1; + *aux = '\0'; + + ns_file = aux + 1; + aux = strchr(ns_file, ','); + if (aux != NULL) { + *aux = '\0'; + extra_opts = aux + 1; + } else { + extra_opts = NULL; + } + if (join_ns_add(ptr, ns_file, extra_opts)) + return -1; + + return 0; +} + +#define PARSING_GLOBAL_CONF 1 +#define PARSING_USER_CONF 2 +#define PARSING_ARGV 3 + +/* + * parse_options() is the point where the getopt parsing happens. The CLI + * parsing as well as the configuration file parsing happens here. + * This used to be all part of main() and to integrate the new code flow + * in main() this function (parse_options()) returns '0' if everything is + * correct, '1' if something failed and '2' if the CRIU help text should + * be displayed. + */ +int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) +{ + int state = PARSING_GLOBAL_CONF; + int global_cfg_argc = 0, user_cfg_argc = 0; + /* remove pid, unused */ + pid_t pid = 0; + int ret; + int opt; + int idx; + + +#define BOOL_OPT(OPT_NAME, SAVE_TO) \ + {OPT_NAME, no_argument, SAVE_TO, true},\ + {"no-" OPT_NAME, no_argument, SAVE_TO, false} + + static const char short_opts[] = "dSsRf:F:t:p:hcD:o:v::x::Vr:jJ:lW:L:M:"; + static struct option long_opts[] = { + { "tree", required_argument, 0, 't' }, + { "pid", required_argument, 0, 'p' }, + { "leave-stopped", no_argument, 0, 's' }, + { "leave-running", no_argument, 0, 'R' }, + BOOL_OPT("restore-detached", &opts.restore_detach), + BOOL_OPT("restore-sibling", &opts.restore_sibling), + BOOL_OPT("daemon", &opts.restore_detach), + { "contents", no_argument, 0, 'c' }, + { "file", required_argument, 0, 'f' }, + { "fields", required_argument, 0, 'F' }, + { "images-dir", required_argument, 0, 'D' }, + { "work-dir", required_argument, 0, 'W' }, + { "log-file", required_argument, 0, 'o' }, + { "join-ns", required_argument, 0, 'J' }, + { "root", required_argument, 0, 'r' }, + { USK_EXT_PARAM, optional_argument, 0, 'x' }, + { "help", no_argument, 0, 'h' }, + BOOL_OPT(SK_EST_PARAM, &opts.tcp_established_ok), + { "close", required_argument, 0, 1043 }, + BOOL_OPT("log-pid", &opts.log_file_per_pid), + { "version", no_argument, 0, 'V' }, + BOOL_OPT("evasive-devices", &opts.evasive_devices), + { "pidfile", required_argument, 0, 1046 }, + { "veth-pair", required_argument, 0, 1047 }, + { "action-script", required_argument, 0, 1049 }, + BOOL_OPT(LREMAP_PARAM, &opts.link_remap_ok), + BOOL_OPT(OPT_SHELL_JOB, &opts.shell_job), + BOOL_OPT(OPT_FILE_LOCKS, &opts.handle_file_locks), + BOOL_OPT("page-server", &opts.use_page_server), + { "address", required_argument, 0, 1051 }, + { "port", required_argument, 0, 1052 }, + { "prev-images-dir", required_argument, 0, 1053 }, + { "ms", no_argument, 0, 1054 }, + BOOL_OPT("track-mem", &opts.track_mem), + BOOL_OPT("auto-dedup", &opts.auto_dedup), + { "libdir", required_argument, 0, 'L' }, + { "cpu-cap", optional_argument, 0, 1057 }, + BOOL_OPT("force-irmap", &opts.force_irmap), + { "ext-mount-map", required_argument, 0, 'M' }, + { "exec-cmd", no_argument, 0, 1059 }, + { "manage-cgroups", optional_argument, 0, 1060 }, + { "cgroup-root", required_argument, 0, 1061 }, + { "inherit-fd", required_argument, 0, 1062 }, + { "feature", required_argument, 0, 1063 }, + { "skip-mnt", required_argument, 0, 1064 }, + { "enable-fs", required_argument, 0, 1065 }, + { "enable-external-sharing", no_argument, &opts.enable_external_sharing, true }, + { "enable-external-masters", no_argument, &opts.enable_external_masters, true }, + { "freeze-cgroup", required_argument, 0, 1068 }, + { "ghost-limit", required_argument, 0, 1069 }, + { "irmap-scan-path", required_argument, 0, 1070 }, + { "lsm-profile", required_argument, 0, 1071 }, + { "timeout", required_argument, 0, 1072 }, + { "external", required_argument, 0, 1073 }, + { "empty-ns", required_argument, 0, 1074 }, + { "lazy-pages", no_argument, 0, 1076 }, + BOOL_OPT("extra", &opts.check_extra_features), + BOOL_OPT("experimental", &opts.check_experimental_features), + { "all", no_argument, 0, 1079 }, + { "cgroup-props", required_argument, 0, 1080 }, + { "cgroup-props-file", required_argument, 0, 1081 }, + { "cgroup-dump-controller", required_argument, 0, 1082 }, + BOOL_OPT(SK_INFLIGHT_PARAM, &opts.tcp_skip_in_flight), + BOOL_OPT("deprecated", &opts.deprecated_ok), + BOOL_OPT("display-stats", &opts.display_stats), + BOOL_OPT("weak-sysctls", &opts.weak_sysctls), + { "status-fd", required_argument, 0, 1088 }, + BOOL_OPT(SK_CLOSE_PARAM, &opts.tcp_close), + { "verbosity", optional_argument, 0, 'v' }, + { "ps-socket", required_argument, 0, 1091}, + { "config", required_argument, 0, 1089}, + { "no-default-config", no_argument, 0, 1090}, + { }, + }; + +#undef BOOL_OPT + + + + ret = init_config(argc, argv, &global_cfg_argc, &user_cfg_argc, + usage_error); + if (ret) + return 2; + + while (1) { + char **_argv = NULL; + int _argc = 0; + + idx = -1; + + switch (state) { + case PARSING_GLOBAL_CONF: + _argc = global_cfg_argc; + _argv = global_conf; + break; + case PARSING_USER_CONF: + _argc = user_cfg_argc; + _argv = user_conf; + break; + case PARSING_ARGV: + _argc = argc; + _argv = argv; + break; + default: + BUG(); + } + opt = getopt_long(_argc, _argv, short_opts, long_opts, &idx); + if (opt == -1) { + switch (state) { + case PARSING_GLOBAL_CONF: + case PARSING_USER_CONF: + if (optind < _argc) { + pr_err("Unknown config parameter: %s\n", _argv[optind]); + return -1; + } + break; + } + if (state < PARSING_ARGV) { + state++; + optind = 0; + continue; + } else { + break; + } + } + if (!opt) + continue; + + switch (opt) { + case 's': + opts.final_state = TASK_STOPPED; + break; + case 'R': + opts.final_state = TASK_ALIVE; + break; + case 'x': + if (optarg && unix_sk_ids_parse(optarg) < 0) + return 1; + opts.ext_unix_sk = true; + break; + case 'p': + pid = atoi(optarg); + if (pid <= 0) + goto bad_arg; + break; + case 't': + opts.tree_id = atoi(optarg); + if (opts.tree_id <= 0) + goto bad_arg; + break; + case 'c': + opts.show_pages_content = true; + break; + case 'f': + opts.show_dump_file = optarg; + break; + case 'F': + opts.show_fmt = optarg; + break; + case 'r': + opts.root = optarg; + break; + case 'd': + opts.restore_detach = true; + break; + case 'S': + opts.restore_sibling = true; + break; + case 'D': + opts.imgs_dir = optarg; + break; + case 'W': + opts.work_dir = optarg; + break; + case 'o': + opts.output = optarg; + break; + case 'J': + if (parse_join_ns(optarg)) + goto bad_arg; + break; + case 'v': + if (optarg) { + if (optarg[0] == 'v') + /* handle -vvvvv */ + opts.log_level += strlen(optarg) + 1; + else + opts.log_level = atoi(optarg); + } else + opts.log_level++; + break; + case 1043: { + int fd; + + fd = atoi(optarg); + pr_info("Closing fd %d\n", fd); + close(fd); + break; + } + case 1046: + opts.pidfile = optarg; + break; + case 1047: + { + char *aux; + + aux = strchr(optarg, '='); + if (aux == NULL) + goto bad_arg; + + *aux = '\0'; + if (veth_pair_add(optarg, aux + 1)) + return 1; + } + break; + case 1049: + if (add_script(optarg)) + return 1; + break; + case 1051: + opts.addr = optarg; + break; + case 1052: + opts.port = atoi(optarg); + if (!opts.port) + goto bad_arg; + break; + case 'j': + opts.shell_job = true; + break; + case 'l': + opts.handle_file_locks = true; + break; + case 1053: + opts.img_parent = optarg; + break; + case 1057: + if (parse_cpu_cap(&opts, optarg)) + return 2; + break; + case 1058: + opts.force_irmap = true; + break; + case 1054: + pr_err("--ms is deprecated; see \"Check options\" of criu --help\n"); + return 1; + case 'L': + opts.libdir = optarg; + break; + case 1059: + *has_exec_cmd = true; + break; + case 1060: + if (parse_manage_cgroups(&opts, optarg)) + return 2; + break; + case 1061: + { + char *path, *ctl; + + path = strchr(optarg, ':'); + if (path) { + *path = '\0'; + path++; + ctl = optarg; + } else { + path = optarg; + ctl = NULL; + } + + if (new_cg_root_add(ctl, path)) + return -1; + } + break; + case 1062: + if (inherit_fd_parse(optarg) < 0) + return 1; + break; + case 1063: + 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)) + return 1; + break; + case 1065: + if (!add_fsname_auto(optarg)) + return 1; + break; + case 1068: + opts.freeze_cgroup = optarg; + break; + case 1069: + opts.ghost_limit = parse_size(optarg); + break; + case 1070: + if (irmap_scan_path_add(optarg)) + return -1; + break; + case 1071: + opts.lsm_profile = optarg; + opts.lsm_supplied = true; + break; + case 1072: + opts.timeout = atoi(optarg); + break; + case 1076: + opts.lazy_pages = true; + break; + case 'M': + { + char *aux; + + if (strcmp(optarg, "auto") == 0) { + opts.autodetect_ext_mounts = true; + break; + } + + aux = strchr(optarg, ':'); + if (aux == NULL) + goto bad_arg; + + *aux = '\0'; + if (ext_mount_add(optarg, aux + 1)) + return 1; + } + break; + case 1073: + if (add_external(optarg)) + return 1; + break; + case 1074: + if (!strcmp("net", optarg)) + opts.empty_ns |= CLONE_NEWNET; + else { + pr_err("Unsupported empty namespace: %s\n", + optarg); + return 1; + } + break; + case 1079: + opts.check_extra_features = true; + opts.check_experimental_features = true; + break; + case 1080: + opts.cgroup_props = optarg; + break; + case 1081: + opts.cgroup_props_file = optarg; + break; + case 1082: + if (!cgp_add_dump_controller(optarg)) + return 1; + break; + case 1088: + if (sscanf(optarg, "%d", &opts.status_fd) != 1) { + pr_err("Unable to parse a value of --status-fd\n"); + return 1; + } + break; + case 1089: + break; + case 1090: + break; + case 1091: + opts.ps_socket = atoi(optarg); + break; + case 'V': + pr_msg("Version: %s\n", CRIU_VERSION); + if (strcmp(CRIU_GITID, "0")) + pr_msg("GitID: %s\n", CRIU_GITID); + exit(0); + case 'h': + *usage_error = false; + return 2; + default: + return 2; + } + } + + return 0; + +bad_arg: + if (idx < 0) /* short option */ + pr_msg("Error: invalid argument for -%c: %s\n", + opt, optarg); + else /* long option */ + pr_msg("Error: invalid argument for --%s: %s\n", + long_opts[idx].name, optarg); + return 1; +} diff --git a/criu/crtools.c b/criu/crtools.c index 66391be22..9fe0dccb2 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -33,7 +33,6 @@ #include "files.h" #include "sk-inet.h" #include "net.h" -#include "version.h" #include "page-xfer.h" #include "tty.h" #include "file-lock.h" @@ -41,14 +40,10 @@ #include "plugin.h" #include "criu-log.h" #include "util.h" -#include "mount.h" -#include "filesystems.h" +#include "protobuf-desc.h" #include "namespaces.h" #include "cgroup.h" -#include "cgroup-props.h" #include "cpu.h" -#include "action-scripts.h" -#include "irmap.h" #include "fault-injection.h" #include "lsm.h" #include "proc_parse.h" @@ -58,8 +53,6 @@ #include "sysctl.h" struct cr_options opts; -char **global_conf = NULL; -char **user_conf = NULL; void init_opts(void) { @@ -81,125 +74,7 @@ void init_opts(void) opts.timeout = DEFAULT_TIMEOUT; opts.empty_ns = 0; opts.status_fd = -1; -} - -static int parse_join_ns(const char *ptr) -{ - char *aux, *ns_file, *extra_opts = NULL; - - aux = strchr(ptr, ':'); - if (aux == NULL) - return -1; - *aux = '\0'; - - ns_file = aux + 1; - aux = strchr(ns_file, ','); - if (aux != NULL) { - *aux = '\0'; - extra_opts = aux + 1; - } else { - extra_opts = NULL; - } - if (join_ns_add(ptr, ns_file, extra_opts)) - return -1; - - return 0; -} - -static int parse_cpu_cap(struct cr_options *opts, const char *optarg) -{ - bool inverse = false; - -#define ____cpu_set_cap(__opts, __cap, __inverse) \ - do { \ - if ((__inverse)) \ - (__opts)->cpu_cap &= ~(__cap); \ - else \ - (__opts)->cpu_cap |= (__cap); \ - } while (0) - - if (!optarg) { - ____cpu_set_cap(opts, CPU_CAP_ALL, false); - return 0; - } - - while (*optarg) { - if (optarg[0] == '^') { - inverse = !inverse; - optarg++; - continue; - } else if (optarg[0] == ',') { - inverse = false; - optarg++; - continue; - } - - if (!strncmp(optarg, "fpu", 3)) { - ____cpu_set_cap(opts, CPU_CAP_FPU, inverse); - optarg += 3; - } else if (!strncmp(optarg, "all", 3)) { - ____cpu_set_cap(opts, CPU_CAP_ALL, inverse); - optarg += 3; - } else if (!strncmp(optarg, "none", 4)) { - if (inverse) - opts->cpu_cap = CPU_CAP_ALL; - else - opts->cpu_cap = CPU_CAP_NONE; - optarg += 4; - } else if (!strncmp(optarg, "cpu", 3)) { - ____cpu_set_cap(opts, CPU_CAP_CPU, inverse); - optarg += 3; - } else if (!strncmp(optarg, "ins", 3)) { - ____cpu_set_cap(opts, CPU_CAP_INS, inverse); - optarg += 3; - } else - goto Esyntax; - } -#undef ____cpu_set_cap - - return 0; - -Esyntax: - pr_err("Unknown FPU mode `%s' selected\n", optarg); - return -1; -} - -static int parse_manage_cgroups(struct cr_options *opts, const char *optarg) -{ - if (!optarg) { - opts->manage_cgroups = CG_MODE_SOFT; - return 0; - } - - if (!strcmp(optarg, "none")) { - opts->manage_cgroups = CG_MODE_NONE; - } else if (!strcmp(optarg, "props")) { - opts->manage_cgroups = CG_MODE_PROPS; - } else if (!strcmp(optarg, "soft")) { - opts->manage_cgroups = CG_MODE_SOFT; - } else if (!strcmp(optarg, "full")) { - opts->manage_cgroups = CG_MODE_FULL; - } else if (!strcmp(optarg, "strict")) { - opts->manage_cgroups = CG_MODE_STRICT; - } else - goto Esyntax; - - return 0; - -Esyntax: - pr_err("Unknown cgroups mode `%s' selected\n", optarg); - return -1; -} - -static size_t parse_size(char *optarg) -{ - if (index(optarg, 'K')) - return (size_t)KILO(atol(optarg)); - else if (index(optarg, 'M')) - return (size_t)MEGA(atol(optarg)); - else if (index(optarg, 'G')) - return (size_t)GIGA(atol(optarg)); - return (size_t)atol(optarg); + opts.log_level = DEFAULT_LOGLEVEL; } bool deprecated_ok(char *what) @@ -258,103 +133,10 @@ static int early_init(void) int main(int argc, char *argv[], char *envp[]) { -#define PARSING_GLOBAL_CONF 1 -#define PARSING_USER_CONF 2 -#define PARSING_ARGV 3 - - pid_t pid = 0, tree_id = 0; int ret = -1; bool usage_error = true; bool has_exec_cmd = false; bool has_sub_command; - int opt = 0, idx; - int global_cfg_argc = 0, user_cfg_argc = 0; - int state = PARSING_GLOBAL_CONF; - int log_level = DEFAULT_LOGLEVEL; - char *imgs_dir = "."; - -#define BOOL_OPT(OPT_NAME, SAVE_TO) \ - {OPT_NAME, no_argument, SAVE_TO, true},\ - {"no-" OPT_NAME, no_argument, SAVE_TO, false} - - static const char short_opts[] = "dSsRf:F:t:p:hcD:o:v::x::Vr:jJ:lW:L:M:"; - static struct option long_opts[] = { - { "tree", required_argument, 0, 't' }, - { "pid", required_argument, 0, 'p' }, - { "leave-stopped", no_argument, 0, 's' }, - { "leave-running", no_argument, 0, 'R' }, - BOOL_OPT("restore-detached", &opts.restore_detach), - BOOL_OPT("restore-sibling", &opts.restore_sibling), - BOOL_OPT("daemon", &opts.restore_detach), - { "contents", no_argument, 0, 'c' }, - { "file", required_argument, 0, 'f' }, - { "fields", required_argument, 0, 'F' }, - { "images-dir", required_argument, 0, 'D' }, - { "work-dir", required_argument, 0, 'W' }, - { "log-file", required_argument, 0, 'o' }, - { "join-ns", required_argument, 0, 'J' }, - { "root", required_argument, 0, 'r' }, - { USK_EXT_PARAM, optional_argument, 0, 'x' }, - { "help", no_argument, 0, 'h' }, - BOOL_OPT(SK_EST_PARAM, &opts.tcp_established_ok), - { "close", required_argument, 0, 1043 }, - BOOL_OPT("log-pid", &opts.log_file_per_pid), - { "version", no_argument, 0, 'V' }, - BOOL_OPT("evasive-devices", &opts.evasive_devices), - { "pidfile", required_argument, 0, 1046 }, - { "veth-pair", required_argument, 0, 1047 }, - { "action-script", required_argument, 0, 1049 }, - BOOL_OPT(LREMAP_PARAM, &opts.link_remap_ok), - BOOL_OPT(OPT_SHELL_JOB, &opts.shell_job), - BOOL_OPT(OPT_FILE_LOCKS, &opts.handle_file_locks), - BOOL_OPT("page-server", &opts.use_page_server), - { "address", required_argument, 0, 1051 }, - { "port", required_argument, 0, 1052 }, - { "prev-images-dir", required_argument, 0, 1053 }, - { "ms", no_argument, 0, 1054 }, - BOOL_OPT("track-mem", &opts.track_mem), - BOOL_OPT("auto-dedup", &opts.auto_dedup), - { "libdir", required_argument, 0, 'L' }, - { "cpu-cap", optional_argument, 0, 1057 }, - BOOL_OPT("force-irmap", &opts.force_irmap), - { "ext-mount-map", required_argument, 0, 'M' }, - { "exec-cmd", no_argument, 0, 1059 }, - { "manage-cgroups", optional_argument, 0, 1060 }, - { "cgroup-root", required_argument, 0, 1061 }, - { "inherit-fd", required_argument, 0, 1062 }, - { "feature", required_argument, 0, 1063 }, - { "skip-mnt", required_argument, 0, 1064 }, - { "enable-fs", required_argument, 0, 1065 }, - { "enable-external-sharing", no_argument, &opts.enable_external_sharing, true }, - { "enable-external-masters", no_argument, &opts.enable_external_masters, true }, - { "freeze-cgroup", required_argument, 0, 1068 }, - { "ghost-limit", required_argument, 0, 1069 }, - { "irmap-scan-path", required_argument, 0, 1070 }, - { "lsm-profile", required_argument, 0, 1071 }, - { "timeout", required_argument, 0, 1072 }, - { "external", required_argument, 0, 1073 }, - { "empty-ns", required_argument, 0, 1074 }, - { "lazy-pages", no_argument, 0, 1076 }, - BOOL_OPT("extra", &opts.check_extra_features), - BOOL_OPT("experimental", &opts.check_experimental_features), - { "all", no_argument, 0, 1079 }, - { "cgroup-props", required_argument, 0, 1080 }, - { "cgroup-props-file", required_argument, 0, 1081 }, - { "cgroup-dump-controller", required_argument, 0, 1082 }, - BOOL_OPT(SK_INFLIGHT_PARAM, &opts.tcp_skip_in_flight), - BOOL_OPT("deprecated", &opts.deprecated_ok), - BOOL_OPT("display-stats", &opts.display_stats), - BOOL_OPT("weak-sysctls", &opts.weak_sysctls), - { "status-fd", required_argument, 0, 1088 }, - BOOL_OPT(SK_CLOSE_PARAM, &opts.tcp_close), - { "verbosity", optional_argument, 0, 'v' }, - { "ps-socket", required_argument, 0, 1091}, - { "config", required_argument, 0, 1089}, - { "no-default-config", no_argument, 0, 1090}, - { }, - }; - -#undef BOOL_OPT BUILD_BUG_ON(CTL_32 != SYSCTL_TYPE__CTL_32); BUILD_BUG_ON(__CTL_STR != SYSCTL_TYPE__CTL_STR); @@ -390,312 +172,14 @@ int main(int argc, char *argv[], char *envp[]) return cr_service_work(atoi(argv[2])); } - ret = init_config(argc, argv, &global_cfg_argc, &user_cfg_argc, - &usage_error); - if (ret) + ret = parse_options(argc, argv, &usage_error, &has_exec_cmd); + + if (ret == 1) + return 1; + if (ret == 2) goto usage; - while (1) { - char **_argv = NULL; - int _argc = 0; - - idx = -1; - - switch (state) { - case PARSING_GLOBAL_CONF: - _argc = global_cfg_argc; - _argv = global_conf; - break; - case PARSING_USER_CONF: - _argc = user_cfg_argc; - _argv = user_conf; - break; - case PARSING_ARGV: - _argc = argc; - _argv = argv; - break; - default: - BUG(); - } - opt = getopt_long(_argc, _argv, short_opts, long_opts, &idx); - if (opt == -1) { - switch (state) { - case PARSING_GLOBAL_CONF: - case PARSING_USER_CONF: - if (optind < _argc) { - pr_err("Unknown config parameter: %s\n", _argv[optind]); - return -1; - } - break; - } - if (state < PARSING_ARGV) { - state++; - optind = 0; - continue; - } else { - break; - } - } - if (!opt) - continue; - - switch (opt) { - case 's': - opts.final_state = TASK_STOPPED; - break; - case 'R': - opts.final_state = TASK_ALIVE; - break; - case 'x': - if (optarg && unix_sk_ids_parse(optarg) < 0) - return 1; - opts.ext_unix_sk = true; - break; - case 'p': - pid = atoi(optarg); - if (pid <= 0) - goto bad_arg; - break; - case 't': - tree_id = atoi(optarg); - if (tree_id <= 0) - goto bad_arg; - break; - case 'c': - opts.show_pages_content = true; - break; - case 'f': - opts.show_dump_file = optarg; - break; - case 'F': - opts.show_fmt = optarg; - break; - case 'r': - opts.root = optarg; - break; - case 'd': - opts.restore_detach = true; - break; - case 'S': - opts.restore_sibling = true; - break; - case 'D': - imgs_dir = optarg; - break; - case 'W': - opts.work_dir = optarg; - break; - case 'o': - opts.output = optarg; - break; - case 'J': - if (parse_join_ns(optarg)) - goto bad_arg; - break; - case 'v': - if (optarg) { - if (optarg[0] == 'v') - /* handle -vvvvv */ - log_level += strlen(optarg) + 1; - else - log_level = atoi(optarg); - } else - log_level++; - break; - case 1043: { - int fd; - - fd = atoi(optarg); - pr_info("Closing fd %d\n", fd); - close(fd); - break; - } - case 1046: - opts.pidfile = optarg; - break; - case 1047: - { - char *aux; - - aux = strchr(optarg, '='); - if (aux == NULL) - goto bad_arg; - - *aux = '\0'; - if (veth_pair_add(optarg, aux + 1)) - return 1; - } - break; - case 1049: - if (add_script(optarg)) - return 1; - break; - case 1051: - opts.addr = optarg; - break; - case 1052: - opts.port = atoi(optarg); - if (!opts.port) - goto bad_arg; - break; - case 'j': - opts.shell_job = true; - break; - case 'l': - opts.handle_file_locks = true; - break; - case 1053: - opts.img_parent = optarg; - break; - case 1057: - if (parse_cpu_cap(&opts, optarg)) - goto usage; - break; - case 1058: - opts.force_irmap = true; - break; - case 1054: - pr_err("--ms is deprecated; see \"Check options\" of criu --help\n"); - return 1; - case 'L': - opts.libdir = optarg; - break; - case 1059: - has_exec_cmd = true; - break; - case 1060: - if (parse_manage_cgroups(&opts, optarg)) - goto usage; - break; - case 1061: - { - char *path, *ctl; - - path = strchr(optarg, ':'); - if (path) { - *path = '\0'; - path++; - ctl = optarg; - } else { - path = optarg; - ctl = NULL; - } - - if (new_cg_root_add(ctl, path)) - return -1; - } - break; - case 1062: - if (inherit_fd_parse(optarg) < 0) - return 1; - break; - case 1063: - 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)) - return 1; - break; - case 1065: - if (!add_fsname_auto(optarg)) - return 1; - break; - case 1068: - opts.freeze_cgroup = optarg; - break; - case 1069: - opts.ghost_limit = parse_size(optarg); - break; - case 1070: - if (irmap_scan_path_add(optarg)) - return -1; - break; - case 1071: - opts.lsm_profile = optarg; - opts.lsm_supplied = true; - break; - case 1072: - opts.timeout = atoi(optarg); - break; - case 1076: - opts.lazy_pages = true; - break; - case 'M': - { - char *aux; - - if (strcmp(optarg, "auto") == 0) { - opts.autodetect_ext_mounts = true; - break; - } - - aux = strchr(optarg, ':'); - if (aux == NULL) - goto bad_arg; - - *aux = '\0'; - if (ext_mount_add(optarg, aux + 1)) - return 1; - } - break; - case 1073: - if (add_external(optarg)) - return 1; - break; - case 1074: - if (!strcmp("net", optarg)) - opts.empty_ns |= CLONE_NEWNET; - else { - pr_err("Unsupported empty namespace: %s\n", - optarg); - return 1; - } - break; - case 1079: - opts.check_extra_features = true; - opts.check_experimental_features = true; - break; - case 1080: - opts.cgroup_props = optarg; - break; - case 1081: - opts.cgroup_props_file = optarg; - break; - case 1082: - if (!cgp_add_dump_controller(optarg)) - return 1; - break; - case 1088: - if (sscanf(optarg, "%d", &opts.status_fd) != 1) { - pr_err("Unable to parse a value of --status-fd\n"); - return 1; - } - break; - case 1089: - break; - case 1090: - break; - case 1091: - opts.ps_socket = atoi(optarg); - break; - case 'V': - pr_msg("Version: %s\n", CRIU_VERSION); - if (strcmp(CRIU_GITID, "0")) - pr_msg("GitID: %s\n", CRIU_GITID); - return 0; - case 'h': - usage_error = false; - goto usage; - default: - goto usage; - } - } - - log_set_loglevel(log_level); + log_set_loglevel(opts.log_level); if (early_init()) return -1; @@ -726,8 +210,11 @@ int main(int argc, char *argv[], char *envp[]) return 1; } + if (opts.imgs_dir == NULL) + opts.imgs_dir = "."; + if (opts.work_dir == NULL) - opts.work_dir = imgs_dir; + opts.work_dir = opts.imgs_dir; if (optind >= argc) { pr_msg("Error: command is required\n"); @@ -773,7 +260,7 @@ int main(int argc, char *argv[], char *envp[]) /* We must not open imgs dir, if service is called */ if (strcmp(argv[optind], "service")) { - ret = open_image_dir(imgs_dir); + ret = open_image_dir(opts.imgs_dir); if (ret < 0) return 1; } @@ -793,7 +280,6 @@ int main(int argc, char *argv[], char *envp[]) return 1; } - if (log_init(opts.output)) return 1; @@ -813,20 +299,20 @@ int main(int argc, char *argv[], char *envp[]) pr_info("Will do snapshot from %s\n", opts.img_parent); if (!strcmp(argv[optind], "dump")) { - if (!tree_id) + if (!opts.tree_id) goto opt_pid_missing; - return cr_dump_tasks(tree_id); + return cr_dump_tasks(opts.tree_id); } if (!strcmp(argv[optind], "pre-dump")) { - if (!tree_id) + if (!opts.tree_id) goto opt_pid_missing; - return cr_pre_dump_tasks(tree_id) != 0; + return cr_pre_dump_tasks(opts.tree_id) != 0; } if (!strcmp(argv[optind], "restore")) { - if (tree_id) + if (opts.tree_id) pr_warn("Using -t with criu restore is obsoleted\n"); ret = cr_restore_tasks(); @@ -1054,13 +540,4 @@ usage: opt_pid_missing: pr_msg("Error: pid not specified\n"); return 1; - -bad_arg: - if (idx < 0) /* short option */ - pr_msg("Error: invalid argument for -%c: %s\n", - opt, optarg); - else /* long option */ - pr_msg("Error: invalid argument for --%s: %s\n", - long_opts[idx].name, optarg); - return 1; } diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index 5b17130ad..f6c500475 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -1,6 +1,7 @@ #ifndef __CR_OPTIONS_H__ #define __CR_OPTIONS_H__ +#include #include #include "common/config.h" #include "common/list.h" @@ -121,10 +122,14 @@ struct cr_options { int weak_sysctls; int status_fd; bool orphan_pts_master; + pid_t tree_id; + int log_level; + char *imgs_dir; }; extern struct cr_options opts; -extern void init_opts(void); +extern int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd); +extern void init_opts(); #endif /* __CR_OPTIONS_H__ */ diff --git a/criu/include/crtools.h b/criu/include/crtools.h index 5ffacb697..7b2dc4523 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -32,10 +32,6 @@ extern int cr_lazy_pages(bool daemon); extern int check_add_feature(char *arg); extern void pr_check_features(const char *offset, const char *sep, int width); -extern int init_config(int argc, char **argv, - int *global_cfg_argc, int *user_cfg_argc, - bool *usage_error); - #define PPREP_HEAD_INACTIVE ((struct pprep_head *)-1) #define add_post_prepare_cb_once(phead) do { \ From 1bc4b8b56092ea2d5988f080fc16fdbcb9507fe2 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 1 Aug 2018 16:31:14 +0000 Subject: [PATCH 1698/4375] config: remove unused pid option This removes the code around '--pid, -p' which is not used at all. The command-line option is still available to not break CRIU users, but as the result has not been used, just remove the code assigning it. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/config.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/criu/config.c b/criu/config.c index df802e6a9..de977d551 100644 --- a/criu/config.c +++ b/criu/config.c @@ -354,8 +354,6 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) { int state = PARSING_GLOBAL_CONF; int global_cfg_argc = 0, user_cfg_argc = 0; - /* remove pid, unused */ - pid_t pid = 0; int ret; int opt; int idx; @@ -368,6 +366,7 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) static const char short_opts[] = "dSsRf:F:t:p:hcD:o:v::x::Vr:jJ:lW:L:M:"; static struct option long_opts[] = { { "tree", required_argument, 0, 't' }, + /* The pid option is unused and never evaluated. */ { "pid", required_argument, 0, 'p' }, { "leave-stopped", no_argument, 0, 's' }, { "leave-running", no_argument, 0, 'R' }, @@ -507,11 +506,6 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) return 1; opts.ext_unix_sk = true; break; - case 'p': - pid = atoi(optarg); - if (pid <= 0) - goto bad_arg; - break; case 't': opts.tree_id = atoi(optarg); if (opts.tree_id <= 0) From f3f6edb4bf3511b30317c49d9ebedf95562e9ae2 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 1 Aug 2018 16:31:15 +0000 Subject: [PATCH 1699/4375] config: remove more unused option handling The variable show_dump_file and show_fmt are assigned but never used, this remove the assignment. The CLI option still exists to not break the user interface. It exists, but it is unused. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/config.c | 6 ------ criu/include/cr_options.h | 2 -- 2 files changed, 8 deletions(-) diff --git a/criu/config.c b/criu/config.c index de977d551..19d93c95c 100644 --- a/criu/config.c +++ b/criu/config.c @@ -514,12 +514,6 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) case 'c': opts.show_pages_content = true; break; - case 'f': - opts.show_dump_file = optarg; - break; - case 'F': - opts.show_fmt = optarg; - break; case 'r': opts.root = optarg; break; diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index f6c500475..b937d5ac7 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -50,8 +50,6 @@ struct irmap_path_opt { struct cr_options { int final_state; - char *show_dump_file; - char *show_fmt; int check_extra_features; int check_experimental_features; bool show_pages_content; From 4bd4b5fc0908ac7725b5dbf2b463f8c347210361 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 1 Aug 2018 16:31:16 +0000 Subject: [PATCH 1700/4375] config: move init_opts() to config.c This just moves the functions init_opts() and deprecated_ok() also to config.c as that is where most of the option and configuration setup and handling is done today. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/config.c | 36 ++++++++++++++++++++++++++++++++++++ criu/crtools.c | 36 ------------------------------------ 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/criu/config.c b/criu/config.c index 19d93c95c..73ff7bc9d 100644 --- a/criu/config.c +++ b/criu/config.c @@ -29,6 +29,8 @@ #include "common/xmalloc.h" +struct cr_options opts; + char **global_conf = NULL; char **user_conf = NULL; @@ -219,6 +221,40 @@ static int init_config(int argc, char **argv, int *global_cfg_argc, int *user_cf return 0; } +void init_opts(void) +{ + memset(&opts, 0, sizeof(opts)); + + /* Default options */ + opts.final_state = TASK_DEAD; + INIT_LIST_HEAD(&opts.ext_mounts); + INIT_LIST_HEAD(&opts.inherit_fds); + INIT_LIST_HEAD(&opts.external); + INIT_LIST_HEAD(&opts.join_ns); + INIT_LIST_HEAD(&opts.new_cgroup_roots); + INIT_LIST_HEAD(&opts.irmap_scan_paths); + + opts.cpu_cap = CPU_CAP_DEFAULT; + opts.manage_cgroups = CG_MODE_DEFAULT; + opts.ps_socket = -1; + opts.ghost_limit = DEFAULT_GHOST_LIMIT; + opts.timeout = DEFAULT_TIMEOUT; + opts.empty_ns = 0; + opts.status_fd = -1; + opts.log_level = DEFAULT_LOGLEVEL; +} + +bool deprecated_ok(char *what) +{ + if (opts.deprecated_ok) + return true; + + pr_err("Deprecated functionality (%s) rejected.\n", what); + pr_err("Use the --deprecated option or set CRIU_DEPRECATED environment.\n"); + pr_err("For details visit https://criu.org/Deprecation\n"); + return false; +} + static int parse_cpu_cap(struct cr_options *opts, const char *optarg) { bool inverse = false; diff --git a/criu/crtools.c b/criu/crtools.c index 9fe0dccb2..8156bb971 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -52,42 +52,6 @@ #include "setproctitle.h" #include "sysctl.h" -struct cr_options opts; - -void init_opts(void) -{ - memset(&opts, 0, sizeof(opts)); - - /* Default options */ - opts.final_state = TASK_DEAD; - INIT_LIST_HEAD(&opts.ext_mounts); - INIT_LIST_HEAD(&opts.inherit_fds); - INIT_LIST_HEAD(&opts.external); - INIT_LIST_HEAD(&opts.join_ns); - INIT_LIST_HEAD(&opts.new_cgroup_roots); - INIT_LIST_HEAD(&opts.irmap_scan_paths); - - opts.cpu_cap = CPU_CAP_DEFAULT; - opts.manage_cgroups = CG_MODE_DEFAULT; - opts.ps_socket = -1; - opts.ghost_limit = DEFAULT_GHOST_LIMIT; - opts.timeout = DEFAULT_TIMEOUT; - opts.empty_ns = 0; - opts.status_fd = -1; - opts.log_level = DEFAULT_LOGLEVEL; -} - -bool deprecated_ok(char *what) -{ - if (opts.deprecated_ok) - return true; - - pr_err("Deprecated functionality (%s) rejected.\n", what); - pr_err("Use the --deprecated option or set CRIU_DEPRECATED environment.\n"); - pr_err("For details visit https://criu.org/Deprecation\n"); - return false; -} - static void rlimit_unlimit_nofile_self(void) { struct rlimit new; From b427927f79d38dffeecf496c07daa9872505d063 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 1 Aug 2018 16:31:17 +0000 Subject: [PATCH 1701/4375] config: use dynamic variables for configuration files The code to read and parse configuration files was writing the result of the global configuration file to one variable and the result from the configuration file in the user's home to another variable: char **global_conf = NULL; char **user_conf = NULL; With this change the code now uses dynamic memory allocation to handle the different configuration files. It used to be: * parse global config * parse user config * evaluate global config * evaluate user config * evaluate CLI And now it is: * parse global config * evaluate global config * parse user config * evaluate user config * evaluate CLI This change is in preparation for the upcoming setting of a configuration file via environment variable and RPC configuration file usage. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/config.c | 172 +++++++++++++++++++++++++++----------------------- 1 file changed, 94 insertions(+), 78 deletions(-) diff --git a/criu/config.c b/criu/config.c index 73ff7bc9d..112457088 100644 --- a/criu/config.c +++ b/criu/config.c @@ -31,9 +31,6 @@ struct cr_options opts; -char **global_conf = NULL; -char **user_conf = NULL; - static int count_elements(char **to_count) { int count = 0; @@ -152,37 +149,60 @@ static char ** parse_config(char *filepath) return configuration; } -static void init_configuration(int argc, char *argv[], bool no_default_config, - char *cfg_file) +#define PARSING_GLOBAL_CONF 1 +#define PARSING_USER_CONF 2 +#define PARSING_ENV_CONF 3 +#define PARSING_CMDLINE_CONF 4 +#define PARSING_ARGV 5 + +static int next_config(char **argv, char ***_argv, bool no_default_config, + int state, char *cfg_file) { char local_filepath[PATH_MAX + 1]; - char *home_dir = getenv("HOME"); + char *home_dir = NULL; - if ((cfg_file == NULL) && (!no_default_config)) { - global_conf = parse_config(GLOBAL_CONFIG_DIR DEFAULT_CONFIG_FILENAME); - if (!home_dir) { - pr_info("Unable to get $HOME directory, local configuration file will not be used."); - } else { - snprintf(local_filepath, PATH_MAX, "%s/%s%s", - home_dir, USER_CONFIG_DIR, DEFAULT_CONFIG_FILENAME); - user_conf = parse_config(local_filepath); - } - } else if (cfg_file != NULL) { - global_conf = parse_config(cfg_file); - if (global_conf == NULL) { - pr_err("Can't access configuration file %s.\n", cfg_file); - exit(1); - } + if (state > PARSING_ARGV) + return 0; + + switch(state) { + case PARSING_GLOBAL_CONF: + if (no_default_config) + break; + *_argv = parse_config(GLOBAL_CONFIG_DIR DEFAULT_CONFIG_FILENAME); + break; + case PARSING_USER_CONF: + if (no_default_config) + break; + home_dir = getenv("HOME"); + if (!home_dir) { + pr_info("Unable to get $HOME directory, local configuration file will not be used."); + } else { + snprintf(local_filepath, PATH_MAX, "%s/%s%s", + home_dir, USER_CONFIG_DIR, DEFAULT_CONFIG_FILENAME); + *_argv = parse_config(local_filepath); + } + break; + case PARSING_ENV_CONF: + break; + case PARSING_CMDLINE_CONF: + if (!cfg_file) + break; + *_argv = parse_config(cfg_file); + break; + case PARSING_ARGV: + *_argv = argv; + break; + default: + break; } + + return ++state; } -static int init_config(int argc, char **argv, int *global_cfg_argc, int *user_cfg_argc, - bool *usage_error) +static int pre_parse(int argc, char **argv, bool *usage_error, bool *no_default_config, + char **cfg_file) { - bool no_default_config = false; - char *cfg_file = NULL; int i; - /* * We are runnning before getopt(), so we need to pre-parse * the command line. @@ -200,24 +220,20 @@ static int init_config(int argc, char **argv, int *global_cfg_argc, int *user_cf *usage_error = false; return 1; } else if (!strcmp(argv[i], "--no-default-config")) { - no_default_config = true; + *no_default_config = true; } else if (!strcmp(argv[i], "--config")) { /* * getopt takes next string as required * argument automatically, we do the same */ - cfg_file = argv[i + 1]; + *cfg_file = argv[i + 1]; + *no_default_config = true; } else if (strstr(argv[i], "--config=") != NULL) { - cfg_file = argv[i] + strlen("--config="); + *cfg_file = argv[i] + strlen("--config="); + *no_default_config = true; } } - init_configuration(argc, argv, no_default_config, cfg_file); - if (global_conf != NULL) - *global_cfg_argc = count_elements(global_conf); - if (user_conf != NULL) - *user_cfg_argc = count_elements(user_conf); - return 0; } @@ -374,10 +390,6 @@ static int parse_join_ns(const char *ptr) return 0; } -#define PARSING_GLOBAL_CONF 1 -#define PARSING_USER_CONF 2 -#define PARSING_ARGV 3 - /* * parse_options() is the point where the getopt parsing happens. The CLI * parsing as well as the configuration file parsing happens here. @@ -389,10 +401,13 @@ static int parse_join_ns(const char *ptr) int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) { int state = PARSING_GLOBAL_CONF; - int global_cfg_argc = 0, user_cfg_argc = 0; int ret; - int opt; + int opt = -1; int idx; + bool no_default_config = false; + char *cfg_file = NULL; + char **_argv = NULL; + int _argc = 0; #define BOOL_OPT(OPT_NAME, SAVE_TO) \ @@ -479,54 +494,55 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) #undef BOOL_OPT + ret = pre_parse(argc, argv, usage_error, &no_default_config, + &cfg_file); - - ret = init_config(argc, argv, &global_cfg_argc, &user_cfg_argc, - usage_error); if (ret) return 2; while (1) { - char **_argv = NULL; - int _argc = 0; - idx = -1; - - switch (state) { - case PARSING_GLOBAL_CONF: - _argc = global_cfg_argc; - _argv = global_conf; - break; - case PARSING_USER_CONF: - _argc = user_cfg_argc; - _argv = user_conf; - break; - case PARSING_ARGV: - _argc = argc; - _argv = argv; - break; - default: - BUG(); - } - opt = getopt_long(_argc, _argv, short_opts, long_opts, &idx); + /* Only if opt is -1 we are going to the next configuration input */ if (opt == -1) { - switch (state) { - case PARSING_GLOBAL_CONF: - case PARSING_USER_CONF: - if (optind < _argc) { - pr_err("Unknown config parameter: %s\n", _argv[optind]); - return -1; + /* Do not free any memory if it points to argv */ + if (state != PARSING_ARGV + 1) { + int i; + for (i=1; i < _argc; i++) { + free(_argv[i]); } - break; + free(_argv); + ; } - if (state < PARSING_ARGV) { - state++; - optind = 0; + /* This needs to be reset for a new getopt() run */ + _argc = 0; + _argv = NULL; + + state = next_config(argv, &_argv, no_default_config, state, cfg_file); + + /* if next_config() returns 0 it means no more configs found */ + if (state == 0) + break; + + if (!_argv) continue; - } else { - break; - } + + _argc = count_elements(_argv); + optind = 0; } + + opt = getopt_long(_argc, _argv, short_opts, long_opts, &idx); + + /* + * The end of the current _argv has been reached, + * let's go to the next _argv + */ + if (opt == -1) + continue; + + /* + * If opt == 0 then getopt will directly fill out the corresponding + * field in CRIU's opts structure. + */ if (!opt) continue; From eb6229af0d4502d65ef42fceb96f2ecdce7fcdfd Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 1 Aug 2018 16:31:18 +0000 Subject: [PATCH 1702/4375] opts: use xstrdup () to assign char * options With the previous change to dynamically allocate memory for each possible configuration source (three different configuration files, CLI, RPC) the char * options can no longer directly point to the character strings extracted by getopt() as the memory might be free'd at some point. This introduces a macro to set the char * options which first does a xfree() and then a xstrdup(). Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cgroup.c | 2 +- criu/config.c | 23 ++++++++++++----------- criu/cr-service.c | 18 +++++++++--------- criu/crtools.c | 4 ++-- criu/include/cr_options.h | 6 ++++++ criu/lsm.c | 5 +++-- criu/plugin.c | 4 ++-- 7 files changed, 35 insertions(+), 27 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index 51759786e..c5d1284d0 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -1883,7 +1883,7 @@ int new_cg_root_add(char *controller, char *newroot) struct cg_root_opt *o; if (!controller) { - opts.new_global_cg_root = newroot; + SET_CHAR_OPTS(new_global_cg_root, newroot); return 0; } diff --git a/criu/config.c b/criu/config.c index 112457088..b50053fda 100644 --- a/criu/config.c +++ b/criu/config.c @@ -567,7 +567,7 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) opts.show_pages_content = true; break; case 'r': - opts.root = optarg; + SET_CHAR_OPTS(root, optarg); break; case 'd': opts.restore_detach = true; @@ -576,13 +576,13 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) opts.restore_sibling = true; break; case 'D': - opts.imgs_dir = optarg; + SET_CHAR_OPTS(imgs_dir, optarg); break; case 'W': - opts.work_dir = optarg; + SET_CHAR_OPTS(work_dir, optarg); break; case 'o': - opts.output = optarg; + SET_CHAR_OPTS(output, optarg); break; case 'J': if (parse_join_ns(optarg)) @@ -607,7 +607,7 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) break; } case 1046: - opts.pidfile = optarg; + SET_CHAR_OPTS(pidfile, optarg); break; case 1047: { @@ -627,7 +627,7 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) return 1; break; case 1051: - opts.addr = optarg; + SET_CHAR_OPTS(addr, optarg); break; case 1052: opts.port = atoi(optarg); @@ -641,7 +641,7 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) opts.handle_file_locks = true; break; case 1053: - opts.img_parent = optarg; + SET_CHAR_OPTS(img_parent, optarg); break; case 1057: if (parse_cpu_cap(&opts, optarg)) @@ -654,6 +654,7 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) pr_err("--ms is deprecated; see \"Check options\" of criu --help\n"); return 1; case 'L': + SET_CHAR_OPTS(libdir, optarg); opts.libdir = optarg; break; case 1059: @@ -701,7 +702,7 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) return 1; break; case 1068: - opts.freeze_cgroup = optarg; + SET_CHAR_OPTS(freeze_cgroup, optarg); break; case 1069: opts.ghost_limit = parse_size(optarg); @@ -711,7 +712,7 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) return -1; break; case 1071: - opts.lsm_profile = optarg; + SET_CHAR_OPTS(lsm_profile, optarg); opts.lsm_supplied = true; break; case 1072: @@ -756,10 +757,10 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) opts.check_experimental_features = true; break; case 1080: - opts.cgroup_props = optarg; + SET_CHAR_OPTS(cgroup_props, optarg); break; case 1081: - opts.cgroup_props_file = optarg; + SET_CHAR_OPTS(cgroup_props_file, optarg); break; case 1082: if (!cgp_add_dump_controller(optarg)) diff --git a/criu/cr-service.c b/criu/cr-service.c index e9401be3a..c7c28857e 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -261,7 +261,7 @@ static int setup_opts_from_req(int sk, CriuOpts *req) sprintf(images_dir_path, "/proc/%d/fd/%d", ids.pid, req->images_dir_fd); if (req->parent_img) - opts.img_parent = req->parent_img; + SET_CHAR_OPTS(img_parent, req->parent_img); if (open_image_dir(images_dir_path) < 0) { pr_perror("Can't open images directory"); @@ -292,9 +292,9 @@ static int setup_opts_from_req(int sk, CriuOpts *req) goto err; } - opts.output = req->log_file; + SET_CHAR_OPTS(output, req->log_file); } else - opts.output = DEFAULT_LOG_FILENAME; + SET_CHAR_OPTS(output, DEFAULT_LOG_FILENAME); log_set_loglevel(req->log_level); if (log_init(opts.output) == -1) { @@ -325,7 +325,7 @@ static int setup_opts_from_req(int sk, CriuOpts *req) } if (req->root) - opts.root = req->root; + SET_CHAR_OPTS(root, req->root); if (req->has_rst_sibling) { if (!opts.swrk_restore) { @@ -381,7 +381,7 @@ static int setup_opts_from_req(int sk, CriuOpts *req) if (!opts.lazy_pages) { opts.use_page_server = true; - opts.addr = req->ps->address; + SET_CHAR_OPTS(addr, req->ps->address); if (req->ps->has_fd) { if (!opts.swrk_restore) @@ -485,16 +485,16 @@ static int setup_opts_from_req(int sk, CriuOpts *req) } if (req->freeze_cgroup) - opts.freeze_cgroup = req->freeze_cgroup; + SET_CHAR_OPTS(freeze_cgroup, req->freeze_cgroup); if (req->has_timeout) opts.timeout = req->timeout; if (req->cgroup_props) - opts.cgroup_props = req->cgroup_props; + SET_CHAR_OPTS(cgroup_props, req->cgroup_props); if (req->cgroup_props_file) - opts.cgroup_props_file = req->cgroup_props_file; + SET_CHAR_OPTS(cgroup_props_file, req->cgroup_props_file); for (i = 0; i < req->n_cgroup_dump_controller; i++) { if (!cgp_add_dump_controller(req->cgroup_dump_controller[i])) @@ -1158,7 +1158,7 @@ int cr_service(bool daemon_mode) if (opts.addr == NULL) { pr_warn("Binding to local dir address!\n"); - opts.addr = CR_DEFAULT_SERVICE_ADDRESS; + SET_CHAR_OPTS(addr, CR_DEFAULT_SERVICE_ADDRESS); } strcpy(server_addr.sun_path, opts.addr); diff --git a/criu/crtools.c b/criu/crtools.c index 8156bb971..b0551a2a4 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -175,10 +175,10 @@ int main(int argc, char *argv[], char *envp[]) } if (opts.imgs_dir == NULL) - opts.imgs_dir = "."; + SET_CHAR_OPTS(imgs_dir, "."); if (opts.work_dir == NULL) - opts.work_dir = opts.imgs_dir; + SET_CHAR_OPTS(work_dir, opts.imgs_dir); if (optind >= argc) { pr_msg("Error: command is required\n"); diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index b937d5ac7..bcf7d1c98 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -6,6 +6,12 @@ #include "common/config.h" #include "common/list.h" +#define SET_CHAR_OPTS(__dest, __src) \ + do { \ + free(opts.__dest); \ + opts.__dest = xstrdup(__src); \ + } while(0) + /* * CPU capability options. */ diff --git a/criu/lsm.c b/criu/lsm.c index fd098581f..eec73ede5 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -230,15 +230,16 @@ int lsm_check_opts(void) return -1; } - opts.lsm_profile = aux; + SET_CHAR_OPTS(lsm_profile, aux); } else if (strcmp(opts.lsm_profile, "selinux") == 0) { if (kdat.lsm != LSMTYPE__SELINUX) { pr_err("selinux LSM specified but selinux not supported by kernel\n"); return -1; } - opts.lsm_profile = aux; + SET_CHAR_OPTS(lsm_profile, aux); } else if (strcmp(opts.lsm_profile, "none") == 0) { + xfree(opts.lsm_profile); opts.lsm_profile = NULL; } else { pr_err("unknown lsm %s\n", opts.lsm_profile); diff --git a/criu/plugin.c b/criu/plugin.c index 6d9511857..0db862924 100644 --- a/criu/plugin.c +++ b/criu/plugin.c @@ -203,12 +203,12 @@ int cr_plugin_init(int stage) if (opts.libdir == NULL) { path = getenv("CRIU_LIBS_DIR"); if (path) - opts.libdir = path; + SET_CHAR_OPTS(libdir, path); else { if (access(CR_PLUGIN_DEFAULT, F_OK)) return 0; - opts.libdir = CR_PLUGIN_DEFAULT; + SET_CHAR_OPTS(libdir, CR_PLUGIN_DEFAULT); } } From 9d225fadf2667822cbf1e3527d1c3e0cb260c8de Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 1 Aug 2018 16:31:19 +0000 Subject: [PATCH 1703/4375] config: add support for CRIU_CONFIG_FILE With this it is possible to point the environment variable CRIU_CONFIG_FILE to a CRIU configuration file. The order the configuration files are evaluated now is: 1. global (/etc/criu/default.conf) 2. user ($HOME/.criu/default.conf) 3. CRIU_CONFIG_FILE 4. --config FILENAME 5. CLI Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/config.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/criu/config.c b/criu/config.c index b50053fda..57684b45f 100644 --- a/criu/config.c +++ b/criu/config.c @@ -160,6 +160,7 @@ static int next_config(char **argv, char ***_argv, bool no_default_config, { char local_filepath[PATH_MAX + 1]; char *home_dir = NULL; + char *cfg_from_env = NULL; if (state > PARSING_ARGV) return 0; @@ -183,6 +184,10 @@ static int next_config(char **argv, char ***_argv, bool no_default_config, } break; case PARSING_ENV_CONF: + cfg_from_env = getenv("CRIU_CONFIG_FILE"); + if (!cfg_from_env) + break; + *_argv = parse_config(cfg_from_env); break; case PARSING_CMDLINE_CONF: if (!cfg_file) From a5fc4687731be5980fa224553fcdfce9e4cf3e9a Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 1 Aug 2018 16:31:20 +0000 Subject: [PATCH 1704/4375] RPC: Evaluate configuration file before switching to RPC mode When CRIU is started in RPC mode ('criu swrk') it used to ignore all command-line options and configuration files. This moves the jump to RPC mode after the configuration file parsing to enable configuration. With this configuration files are now also evaluated in RPC mode and it is possible to change the behavior of CRIU via the configuration file if used via RPC. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/crtools.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index b0551a2a4..3c6ca078b 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -119,22 +119,6 @@ int main(int argc, char *argv[], char *envp[]) init_opts(); - if (!strcmp(argv[1], "swrk")) { - if (argc < 3) - goto usage; - - if (early_init()) - return -1; - - /* - * This is to start criu service worker from libcriu calls. - * The usage is "criu swrk " and is not for CLI/scripts. - * The arguments semantics can change at any time with the - * corresponding lib call change. - */ - opts.swrk_restore = true; - return cr_service_work(atoi(argv[2])); - } ret = parse_options(argc, argv, &usage_error, &has_exec_cmd); @@ -148,6 +132,19 @@ int main(int argc, char *argv[], char *envp[]) if (early_init()) return -1; + if (!strcmp(argv[1], "swrk")) { + if (argc < 3) + goto usage; + /* + * This is to start criu service worker from libcriu calls. + * The usage is "criu swrk " and is not for CLI/scripts. + * The arguments semantics can change at any time with the + * corresponding lib call change. + */ + opts.swrk_restore = true; + return cr_service_work(atoi(argv[2])); + } + if (opts.deprecated_ok) pr_msg("Turn deprecated stuff ON\n"); if (opts.tcp_skip_in_flight) From dabe778c38820448af9075162067f5dce41c3ab8 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 1 Aug 2018 16:31:21 +0000 Subject: [PATCH 1705/4375] tests: add configuration file test via RPC This test checks the following things: * Does configuration file parsing work at all. * Does the parser detect wrong options. * Does the configuration file work via RPC. * Do the configuration file options not overwrite the RPC settings in the default setup. * Is it possible to tell CRIU to prefer the configuration file via RPC. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- Makefile | 1 + test/others/rpc/Makefile | 2 + test/others/rpc/config_file.py | 182 +++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100755 test/others/rpc/config_file.py diff --git a/Makefile b/Makefile index 60ad328b4..cc5717ef2 100644 --- a/Makefile +++ b/Makefile @@ -374,6 +374,7 @@ help: lint: flake8 --config=scripts/flake8.cfg test/zdtm.py + flake8 --config=scripts/flake8.cfg test/others/rpc/config_file.py include Makefile.install diff --git a/test/others/rpc/Makefile b/test/others/rpc/Makefile index 50cd063d0..08caa0c77 100644 --- a/test/others/rpc/Makefile +++ b/test/others/rpc/Makefile @@ -23,6 +23,8 @@ run: all chmod a+rw build/pidfile sudo -g '#1000' -u '#1000' ./run.sh sudo -g '#1000' -u '#1000' ./version.py + # run the configuration file via RPC test cases + ./config_file.py build criu: ../../../criu/criu cp ../../../criu/criu $@ diff --git a/test/others/rpc/config_file.py b/test/others/rpc/config_file.py new file mode 100755 index 000000000..b74cc0428 --- /dev/null +++ b/test/others/rpc/config_file.py @@ -0,0 +1,182 @@ +#!/usr/bin/python2 + +import os +import socket +import sys +import rpc_pb2 as rpc +import argparse +import subprocess +from tempfile import mkstemp +import time + +log_file = 'config_file_test.log' +does_not_exist = 'does-not.exist' + + +def setup_swrk(): + print('Connecting to CRIU in swrk mode.') + css = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) + swrk = subprocess.Popen(['./criu', "swrk", "%d" % css[0].fileno()]) + css[0].close() + return swrk, css[1] + + +def setup_config_file(content): + # Creating a temporary file which will be used as configuration file. + fd, path = mkstemp() + + with os.fdopen(fd, 'w') as f: + f.write(content) + + os.environ['CRIU_CONFIG_FILE'] = path + + return path + + +def cleanup_config_file(path): + del os.environ['CRIU_CONFIG_FILE'] + os.unlink(path) + + +def setup_criu_dump_request(): + # Create criu msg, set it's type to dump request + # and set dump options. Checkout more options in protobuf/rpc.proto + req = rpc.criu_req() + req.type = rpc.DUMP + req.opts.leave_running = True + req.opts.log_level = 4 + req.opts.log_file = log_file + req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY) + # Not necessary, just for testing + req.opts.tcp_established = True + req.opts.shell_job = True + return req + + +def do_rpc(s, req): + # Send request + s.send(req.SerializeToString()) + + # Recv response + resp = rpc.criu_resp() + MAX_MSG_SIZE = 1024 + resp.ParseFromString(s.recv(MAX_MSG_SIZE)) + + s.close() + return resp + + +def test_broken_configuration_file(): + # Testing RPC configuration file mode with a broken configuration file. + # This should fail + content = 'hopefully-this-option-will-never=exist' + path = setup_config_file(content) + swrk, s = setup_swrk() + s.close() + # This test is only about detecting wrong configuration files. + # If we do not sleep it might happen that we kill CRIU before + # it parses the configuration file. A short sleep makes sure + # that the configuration file has been parsed. Hopefully. + # (I am sure this will fail horribly at some point) + time.sleep(0.3) + swrk.kill() + return_code = swrk.wait() + # delete temporary file again + cleanup_config_file(path) + if return_code != 1: + print('FAIL: CRIU should have returned 1 instead of %d' % return_code) + sys.exit(-1) + + +def search_in_log_file(log, message): + with open(os.path.join(args['dir'], log)) as f: + if message not in f.read(): + print('FAIL: Missing the expected error message (%s) in the log file' % message) + sys.exit(-1) + + +def check_results(resp, log): + # Check if the specified log file exists + if not os.path.isfile(os.path.join(args['dir'], log)): + print('FAIL: Expected log file %s does not exist' % log) + sys.exit(-1) + # Dump should have failed with: 'The criu itself is within dumped tree' + if resp.type != rpc.DUMP: + print('FAIL: Unexpected msg type %r' % resp.type) + sys.exit(-1) + if 'The criu itself is within dumped tree' not in resp.cr_errmsg: + print('FAIL: Missing the expected error message in RPC response') + sys.exit(-1) + # Look into the log file for the same message + search_in_log_file(log, 'The criu itself is within dumped tree') + + +def test_rpc_without_configuration_file(): + # Testing without configuration file + # Just doing a dump and checking for the logfile + req = setup_criu_dump_request() + _, s = setup_swrk() + resp = do_rpc(s, req) + s.close() + check_results(resp, log_file) + + +def test_rpc_with_configuration_file(): + # Testing with configuration file + # Just doing a dump and checking for the logfile + + # Setting a different log file via configuration file + # This should not work as RPC settings overwrite configuration + # file settings in the default configuration. + log = does_not_exist + content = 'log-file ' + log + '\n' + content += 'no-tcp-established\nno-shell-job' + path = setup_config_file(content) + req = setup_criu_dump_request() + _, s = setup_swrk() + do_rpc(s, req) + s.close() + cleanup_config_file(path) + # Check if the specified log file exists + # It should not as configuration files do not overwrite RPC values. + if os.path.isfile(os.path.join(args['dir'], log)): + print('FAIL: log file %s should not exist' % log) + sys.exit(-1) + + +def test_rpc_with_configuration_file_overwriting_rpc(): + # Testing with configuration file + # Just doing a dump and checking for the logfile + + # Setting a different log file via configuration file + # This should not work as RPC settings overwrite configuration + # file settings in the default configuration. + log = does_not_exist + content = 'log-file ' + log + '\n' + content += 'no-tcp-established\nno-shell-job' + path = setup_config_file(content) + req = setup_criu_dump_request() + req.opts.config_file = path + _, s = setup_swrk() + resp = do_rpc(s, req) + s.close() + cleanup_config_file(path) + check_results(resp, log) + + +parser = argparse.ArgumentParser(description="Test config files using CRIU RPC") +parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed") + +args = vars(parser.parse_args()) + +try: + # optional cleanup + os.unlink(os.path.join(args['dir'], does_not_exist)) + os.unlink(os.path.join(args['dir'], log_file)) +except OSError: + pass + +test_broken_configuration_file() +test_rpc_without_configuration_file() +test_rpc_with_configuration_file() +test_rpc_with_configuration_file_overwriting_rpc() From 99d52ec7dd4543010860bec50a187d93eaa72634 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 1 Aug 2018 16:31:22 +0000 Subject: [PATCH 1706/4375] cr-service: add support for configuration files in RPC mode With this commit it is possible to specify a configuration file via RPC. In python this would look like this: req.opts.config_file = 'path/to/config_file' With this commit CRIU's configuration file handling works like this: * apply_config(global_conf) * apply_config(user_conf) * apply_config(environment variable) * apply_config(config file via CLI) * apply_rpc_options() or apply_cli_options() * apply_config(rpc_conf) (only for RPC) This is at least (probably) the third iteration of the RPC configuration file code and it still is complicated. Most CRIU options are correctly used by just writing the new values to the corresponding fields of the opts structure. For the RPC case there are, however, a few options (output, work_dir, imgs_dir) which need special handling. So the RPC configuration file is parsed twice. First time to get output, work_dir and imgs_dir. Once those are read and correctly used, the RPC code overwrites all options again by values set by the RPC interface. At the end the RPC configuration file is read a second time and finally overwrites the values set via RPC. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/config.c | 18 ++++---- criu/cr-service.c | 92 ++++++++++++++++++++++++++++++++++++--- criu/crtools.c | 3 +- criu/include/cr_options.h | 12 ++++- images/rpc.proto | 1 + 5 files changed, 108 insertions(+), 18 deletions(-) diff --git a/criu/config.c b/criu/config.c index 57684b45f..2e57a2af4 100644 --- a/criu/config.c +++ b/criu/config.c @@ -149,12 +149,6 @@ static char ** parse_config(char *filepath) return configuration; } -#define PARSING_GLOBAL_CONF 1 -#define PARSING_USER_CONF 2 -#define PARSING_ENV_CONF 3 -#define PARSING_CMDLINE_CONF 4 -#define PARSING_ARGV 5 - static int next_config(char **argv, char ***_argv, bool no_default_config, int state, char *cfg_file) { @@ -162,7 +156,7 @@ static int next_config(char **argv, char ***_argv, bool no_default_config, char *home_dir = NULL; char *cfg_from_env = NULL; - if (state > PARSING_ARGV) + if (state >= PARSING_LAST) return 0; switch(state) { @@ -197,6 +191,11 @@ static int next_config(char **argv, char ***_argv, bool no_default_config, case PARSING_ARGV: *_argv = argv; break; + case PARSING_RPC_CONF: + if (!rpc_cfg_file) + break; + *_argv = parse_config(rpc_cfg_file); + break; default: break; } @@ -403,9 +402,9 @@ static int parse_join_ns(const char *ptr) * correct, '1' if something failed and '2' if the CRIU help text should * be displayed. */ -int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) +int parse_options(int argc, char **argv, bool *usage_error, + bool *has_exec_cmd, int state) { - int state = PARSING_GLOBAL_CONF; int ret; int opt = -1; int idx; @@ -516,7 +515,6 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd) free(_argv[i]); } free(_argv); - ; } /* This needs to be reset for a new getopt() run */ _argc = 0; diff --git a/criu/cr-service.c b/criu/cr-service.c index c7c28857e..dc2ff05f7 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -242,7 +242,11 @@ static int setup_opts_from_req(int sk, CriuOpts *req) char images_dir_path[PATH_MAX]; char work_dir_path[PATH_MAX]; char status_fd[PATH_MAX]; + bool output_changed_by_rpc_conf = false; + bool work_changed_by_rpc_conf = false; + bool imgs_changed_by_rpc_conf = false; int i; + bool dummy = false; if (getsockopt(sk, SOL_SOCKET, SO_PEERCRED, &ids, &ids_len)) { pr_perror("Can't get socket options"); @@ -257,8 +261,68 @@ static int setup_opts_from_req(int sk, CriuOpts *req) BUG_ON(st.st_ino == -1); service_sk_ino = st.st_ino; - /* open images_dir */ - sprintf(images_dir_path, "/proc/%d/fd/%d", ids.pid, req->images_dir_fd); + /* + * Evaluate an additional configuration file if specified. + * This needs to happen twice, because it is needed early to detect + * things like work_dir, imgs_dir and logfile. The second parsing + * of the optional RPC configuration file happens at the end and + * overwrites all options set via RPC. + */ + if (req->config_file) { + char *tmp_output = NULL; + char *tmp_work = NULL; + char *tmp_imgs = NULL; + + if (opts.output) + tmp_output = xstrdup(opts.output); + if (opts.work_dir) + tmp_work = xstrdup(opts.work_dir); + if (opts.imgs_dir) + tmp_imgs = xstrdup(opts.imgs_dir); + xfree(opts.output); + xfree(opts.work_dir); + xfree(opts.imgs_dir); + opts.output = NULL; + opts.work_dir = NULL; + opts.imgs_dir = NULL; + rpc_cfg_file = req->config_file; + i = parse_options(0, NULL, &dummy, &dummy, PARSING_RPC_CONF); + pr_warn("parse_options returns %d\n", i); + if (i) { + xfree(tmp_output); + xfree(tmp_work); + xfree(tmp_imgs); + goto err; + } + if (tmp_output && opts.output && !strncmp(tmp_output, opts.output, PATH_MAX)) + output_changed_by_rpc_conf = true; + if (tmp_work && opts.work_dir && !strncmp(tmp_work, opts.work_dir, PATH_MAX)) + work_changed_by_rpc_conf = true; + if (tmp_imgs && opts.imgs_dir && !strncmp(tmp_imgs, opts.imgs_dir, PATH_MAX)) + imgs_changed_by_rpc_conf = true; + xfree(tmp_output); + xfree(tmp_work); + xfree(tmp_imgs); + } + + /* + * open images_dir + * This assumes that if opts.imgs_dir is set we have a value + * from the configuration file parser. The test to see that + * imgs_changed_by_rpc_conf is true is used to make sure the value + * is not the same as from one of the other configuration files. + * The idea is that only the RPC configuration file is able to + * overwrite RPC settings: + * * apply_config(global_conf) + * * apply_config(user_conf) + * * apply_config(environment variable) + * * apply_rpc_options() + * * apply_config(rpc_conf) + */ + if (opts.imgs_dir && imgs_changed_by_rpc_conf) + strncpy(images_dir_path, opts.imgs_dir, PATH_MAX); + else + sprintf(images_dir_path, "/proc/%d/fd/%d", ids.pid, req->images_dir_fd); if (req->parent_img) SET_CHAR_OPTS(img_parent, req->parent_img); @@ -275,7 +339,9 @@ static int setup_opts_from_req(int sk, CriuOpts *req) } /* chdir to work dir */ - if (req->has_work_dir_fd) + if (opts.work_dir && work_changed_by_rpc_conf) + strncpy(work_dir_path, opts.work_dir, PATH_MAX); + else if (req->has_work_dir_fd) sprintf(work_dir_path, "/proc/%d/fd/%d", ids.pid, req->work_dir_fd); else strcpy(work_dir_path, images_dir_path); @@ -286,15 +352,16 @@ static int setup_opts_from_req(int sk, CriuOpts *req) } /* initiate log file in work dir */ - if (req->log_file) { + if (req->log_file && !(opts.output && output_changed_by_rpc_conf)) { if (strchr(req->log_file, '/')) { pr_perror("No subdirs are allowed in log_file name"); goto err; } SET_CHAR_OPTS(output, req->log_file); - } else + } else if (!opts.output) { SET_CHAR_OPTS(output, DEFAULT_LOG_FILENAME); + } log_set_loglevel(req->log_level); if (log_init(opts.output) == -1) { @@ -381,7 +448,10 @@ static int setup_opts_from_req(int sk, CriuOpts *req) if (!opts.lazy_pages) { opts.use_page_server = true; - SET_CHAR_OPTS(addr, req->ps->address); + if (req->ps->address) + SET_CHAR_OPTS(addr, req->ps->address); + else + opts.addr = NULL; if (req->ps->has_fd) { if (!opts.swrk_restore) @@ -539,6 +609,16 @@ static int setup_opts_from_req(int sk, CriuOpts *req) if (check_namespace_opts()) goto err; + /* Evaluate additional configuration file a second time to overwrite + * all RPC settings. */ + if (req->config_file) { + rpc_cfg_file = req->config_file; + i = parse_options(0, NULL, &dummy, &dummy, PARSING_RPC_CONF); + if (i) + goto err; + } + log_set_loglevel(opts.log_level); + return 0; err: diff --git a/criu/crtools.c b/criu/crtools.c index 3c6ca078b..5d555ae56 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -101,6 +101,7 @@ int main(int argc, char *argv[], char *envp[]) bool usage_error = true; bool has_exec_cmd = false; bool has_sub_command; + int state = PARSING_GLOBAL_CONF; BUILD_BUG_ON(CTL_32 != SYSCTL_TYPE__CTL_32); BUILD_BUG_ON(__CTL_STR != SYSCTL_TYPE__CTL_STR); @@ -120,7 +121,7 @@ int main(int argc, char *argv[], char *envp[]) init_opts(); - ret = parse_options(argc, argv, &usage_error, &has_exec_cmd); + ret = parse_options(argc, argv, &usage_error, &has_exec_cmd, state); if (ret == 1) return 1; diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index bcf7d1c98..68281e8d5 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -6,6 +6,15 @@ #include "common/config.h" #include "common/list.h" +/* Configuration and CLI parsing order defines */ +#define PARSING_GLOBAL_CONF 1 +#define PARSING_USER_CONF 2 +#define PARSING_ENV_CONF 3 +#define PARSING_CMDLINE_CONF 4 +#define PARSING_ARGV 5 +#define PARSING_RPC_CONF 6 +#define PARSING_LAST 7 + #define SET_CHAR_OPTS(__dest, __src) \ do { \ free(opts.__dest); \ @@ -132,8 +141,9 @@ struct cr_options { }; extern struct cr_options opts; +char *rpc_cfg_file; -extern int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd); +extern int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd, int state); extern void init_opts(); #endif /* __CR_OPTIONS_H__ */ diff --git a/images/rpc.proto b/images/rpc.proto index 71f47d594..abf2f5d79 100644 --- a/images/rpc.proto +++ b/images/rpc.proto @@ -111,6 +111,7 @@ message criu_opts { optional bool lazy_pages = 48; optional int32 status_fd = 49; optional bool orphan_pts_master = 50; + optional string config_file = 51; } message criu_dump_resp { From a4c9efe152ebeeea4f65aaa594de565fdc0b7ab3 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 2 Aug 2018 10:30:34 +0000 Subject: [PATCH 1707/4375] cr-service: fix gcc-8 error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The latest patches to cr-service.c broke compilation with gcc-8: criu/cr-service.c: In function ‘setup_opts_from_req’: criu/cr-service.c:323:3: error: ‘strncpy’ specified bound 4096 equals destination size [-Werror=stringop-truncation] strncpy(images_dir_path, opts.imgs_dir, PATH_MAX); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ criu/cr-service.c:343:3: error: ‘strncpy’ specified bound 4096 equals destination size [-Werror=stringop-truncation] strncpy(work_dir_path, opts.work_dir, PATH_MAX); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors This fixes the errors by specifying the strncpy() size as 'PATH_MAX - 1'. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-service.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index dc2ff05f7..643aba9cf 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -320,7 +320,7 @@ static int setup_opts_from_req(int sk, CriuOpts *req) * * apply_config(rpc_conf) */ if (opts.imgs_dir && imgs_changed_by_rpc_conf) - strncpy(images_dir_path, opts.imgs_dir, PATH_MAX); + strncpy(images_dir_path, opts.imgs_dir, PATH_MAX - 1); else sprintf(images_dir_path, "/proc/%d/fd/%d", ids.pid, req->images_dir_fd); @@ -340,7 +340,7 @@ static int setup_opts_from_req(int sk, CriuOpts *req) /* chdir to work dir */ if (opts.work_dir && work_changed_by_rpc_conf) - strncpy(work_dir_path, opts.work_dir, PATH_MAX); + strncpy(work_dir_path, opts.work_dir, PATH_MAX - 1); else if (req->has_work_dir_fd) sprintf(work_dir_path, "/proc/%d/fd/%d", ids.pid, req->work_dir_fd); else From 682390035beabeba11f65ad76103da446fb27b3a Mon Sep 17 00:00:00 2001 From: Radoslaw Burny Date: Fri, 3 Aug 2018 12:13:43 +0200 Subject: [PATCH 1708/4375] Fix O(n^2) restore in terms of the number of fds. Since the processes and fds are restored from images in the increasing order, and they are stored in sorted lists, CRIU always needed (at least in my experiments) to traverse the whole list before inserting them. With this change, lists are traversed in reverse, so the fds should be inserted immediately. Acked-by: Kirill Tkhai Signed-off-by: Radoslaw Burny Signed-off-by: Andrei Vagin --- criu/files.c | 18 +++++++++++------- criu/include/pid.h | 5 +++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/criu/files.c b/criu/files.c index 4ed84305e..e59388f28 100644 --- a/criu/files.c +++ b/criu/files.c @@ -139,13 +139,17 @@ static void collect_task_fd(struct fdinfo_list_entry *new_fle, struct rst_info * { struct fdinfo_list_entry *fle; - /* fles in fds list are ordered by fd */ - list_for_each_entry(fle, &ri->fds, ps_list) { - if (new_fle->fe->fd < fle->fe->fd) + /* + * fles in fds list are ordered by fd. Fds are restored from img files + * in ascending order, so it is faster to insert them from the end of + * the list. + */ + list_for_each_entry_reverse(fle, &ri->fds, ps_list) { + if (fle->fe->fd < new_fle->fe->fd) break; } - list_add_tail(&new_fle->ps_list, &fle->ps_list); + list_add(&new_fle->ps_list, &fle->ps_list); } unsigned int find_unused_fd(struct pstree_item *task, int hint_fd) @@ -785,10 +789,10 @@ static void __collect_desc_fle(struct fdinfo_list_entry *new_le, struct file_des { struct fdinfo_list_entry *le; - list_for_each_entry(le, &fdesc->fd_info_head, desc_list) - if (pid_rst_prio(new_le->pid, le->pid)) + list_for_each_entry_reverse(le, &fdesc->fd_info_head, desc_list) + if (pid_rst_prio_eq(le->pid, new_le->pid)) break; - list_add_tail(&new_le->desc_list, &le->desc_list); + list_add(&new_le->desc_list, &le->desc_list); } static void collect_desc_fle(struct fdinfo_list_entry *new_le, diff --git a/criu/include/pid.h b/criu/include/pid.h index 81786ec4a..c749176fa 100644 --- a/criu/include/pid.h +++ b/criu/include/pid.h @@ -54,4 +54,9 @@ static inline bool pid_rst_prio(unsigned pid_a, unsigned pid_b) return pid_a < pid_b; } +static inline bool pid_rst_prio_eq(unsigned pid_a, unsigned pid_b) +{ + return pid_a <= pid_b; +} + #endif /* __CR_PID_H__ */ From e8a1dfe8350ef1bd8d926419cc5cb335360326ea Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 9 Aug 2018 10:12:21 +0000 Subject: [PATCH 1709/4375] check: add a feature check for external network namespaces This is obviously not a real check. This only exists, so that CRIU clients/users can check if this CRIU version supports the external network namespace feature. Theoretically the CRIU client or user could also parse the version, but especially for CLI users version comparison in the shell is not easy. This feature check does not exist for RPC as RPC has a special version call which does not require string parsing and the external network namespace feature is available for all CRIU versions newer than 3.9. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-check.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/criu/cr-check.c b/criu/cr-check.c index f496d25ad..3cdc45315 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1250,6 +1250,22 @@ static int check_link_nsid(void) return 0; } +static int check_external_net_ns(void) +{ + /* + * This is obviously not a real check. This only exists, so that + * CRIU clients/users can check if this CRIU version supports the + * external network namespace feature. Theoretically the CRIU client + * or user could also parse the version, but especially for CLI users + * version comparison in the shell is not easy. + * This feature check does not exist for RPC as RPC has a special + * version call which does not require string parsing and the external + * network namespace feature is available for all CRIU versions newer + * than 3.9. + */ + return 0; +} + struct feature_list { char *name; int (*func)(); @@ -1279,6 +1295,7 @@ static struct feature_list feature_list[] = { { "nsid", check_nsid }, { "link_nsid", check_link_nsid}, { "kcmp_epoll", check_kcmp_epoll}, + { "external_net_ns", check_external_net_ns}, { NULL, NULL }, }; From 72194f06705567e34284930c0003224f21687cb5 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 9 Aug 2018 10:12:22 +0000 Subject: [PATCH 1710/4375] criu/action-scripts: remove duplicate code Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/action-scripts.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/criu/action-scripts.c b/criu/action-scripts.c index 7b78a1360..d382547cd 100644 --- a/criu/action-scripts.c +++ b/criu/action-scripts.c @@ -126,15 +126,7 @@ int run_scripts(enum script_actions act) return 0; if (scripts_mode == SCRIPTS_RPC) { - int rpc_sk; - - pr_debug("\tRPC\n"); - rpc_sk = get_service_fd(RPC_SK_OFF); - if (rpc_sk < 0) { - ret = -1; - goto out; - } - ret = send_criu_rpc_script(act, (char *)action, rpc_sk, -1); + ret = rpc_send_fd(act, -1); goto out; } From 5f99c560826dec6f0d871a253087939967ad77f1 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 13 Aug 2018 16:29:08 +0300 Subject: [PATCH 1711/4375] compel: add APIs to get stack pointers We need to know what are stack pointers of every thread to ensure that the current stack page will not be treated as lazy. Signed-off-by: Mike Rapoport Acked-by: Alice Frosi Reviewed-by: Laurent Dufour --- .../aarch64/src/lib/include/uapi/asm/infect-types.h | 1 + .../arch/arm/src/lib/include/uapi/asm/infect-types.h | 1 + .../arch/ppc64/src/lib/include/uapi/asm/infect-types.h | 1 + .../arch/s390/src/lib/include/uapi/asm/infect-types.h | 1 + .../arch/x86/src/lib/include/uapi/asm/infect-types.h | 1 + compel/include/uapi/infect.h | 3 +++ compel/src/lib/infect.c | 10 ++++++++++ 7 files changed, 18 insertions(+) diff --git a/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h b/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h index eeb68be69..4662f7689 100644 --- a/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h @@ -20,6 +20,7 @@ typedef struct user_fpsimd_state user_fpregs_struct_t; #define REG_RES(r) ((uint64_t)(r).regs[0]) #define REG_IP(r) ((uint64_t)(r).pc) +#define REG_SP(r) ((uint64_t)((r).sp)) #define REG_SYSCALL_NR(r) ((uint64_t)(r).regs[8]) #define user_regs_native(pregs) true diff --git a/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h b/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h index 03442ee2b..b8286d404 100644 --- a/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h @@ -54,6 +54,7 @@ struct user_vfp_exc { #define REG_RES(regs) ((regs).ARM_r0) #define REG_IP(regs) ((regs).ARM_pc) +#define REG_SP(regs) ((regs).ARM_sp) #define REG_SYSCALL_NR(regs) ((regs).ARM_r7) #define user_regs_native(pregs) true diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h b/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h index 4b8a20055..89fc4aa3c 100644 --- a/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h @@ -74,6 +74,7 @@ typedef struct { #define REG_RES(regs) ((uint64_t)(regs).gpr[3]) #define REG_IP(regs) ((uint64_t)(regs).nip) +#define REG_SP(regs) ((uint64_t)(regs).gpr[1]) #define REG_SYSCALL_NR(regs) ((uint64_t)(regs).gpr[0]) #define user_regs_native(pregs) true diff --git a/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h b/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h index 938699877..fddf65d3b 100644 --- a/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h @@ -64,6 +64,7 @@ typedef struct { #define REG_RES(r) ((uint64_t)(r).prstatus.gprs[2]) #define REG_IP(r) ((uint64_t)(r).prstatus.psw.addr) +#define REG_SP(r) ((uint64_t)(r).prstatus.gprs[15]) /* * We assume that REG_SYSCALL_NR() is only used for pie code where we * always use svc 0 with opcode in %r1. diff --git a/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h b/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h index af42461ae..e6d394989 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/infect-types.h @@ -111,6 +111,7 @@ typedef struct xsave_struct user_fpregs_struct_t; #define REG_RES(regs) get_user_reg(®s, ax) #define REG_IP(regs) get_user_reg(®s, ip) +#define REG_SP(regs) get_user_reg(®s, sp) #define REG_SYSCALL_NR(regs) get_user_reg(®s, orig_ax) #define __NR(syscall, compat) ((compat) ? __NR32_##syscall : __NR_##syscall) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index f087f21f3..3b98f2d0b 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -165,4 +165,7 @@ extern void compel_relocs_apply(void *mem, void *vbase, size_t size, compel_relo extern unsigned long compel_task_size(void); +extern uint64_t compel_get_leader_sp(struct parasite_ctl *ctl); +extern uint64_t compel_get_thread_sp(struct parasite_thread_ctl *tctl); + #endif diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index d51b8aa88..4648e39b3 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -1585,3 +1585,13 @@ struct parasite_blob_desc *compel_parasite_blob_desc(struct parasite_ctl *ctl) { return &ctl->pblob; } + +uint64_t compel_get_leader_sp(struct parasite_ctl *ctl) +{ + return REG_SP(ctl->orig.regs); +} + +uint64_t compel_get_thread_sp(struct parasite_thread_ctl *tctl) +{ + return REG_SP(tctl->th.regs); +} From 8fae87ee7404e2184b175391cbb7afd513bdc924 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 13 Aug 2018 16:29:09 +0300 Subject: [PATCH 1712/4375] criu: cleanup stale declarations of parasite_{init, fini}_threads_seized Signed-off-by: Mike Rapoport --- criu/include/parasite-syscall.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index c9438a6fe..0e9d340cf 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -52,7 +52,4 @@ extern int parasite_dump_cgroup(struct parasite_ctl *ctl, struct parasite_dump_c extern struct parasite_tty_args *parasite_dump_tty(struct parasite_ctl *ctl, int fd, int type); -extern int parasite_init_threads_seized(struct parasite_ctl *ctl, struct pstree_item *item); -extern int parasite_fini_threads_seized(struct parasite_ctl *ctl); - #endif /* __CR_PARASITE_SYSCALL_H__ */ From af0f5f1ffec1cb10ac4e27340855958c651cd47b Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 13 Aug 2018 16:29:10 +0300 Subject: [PATCH 1713/4375] criu: dump: prepare parasite control for threads at infect time Currently parasite_thread_ctl for non-leader threads is initialized after we stop the compel daemon. Moving this initialization earlier will allow us to make stack pointers of all threads available during memory dump. Signed-off-by: Mike Rapoport --- criu/cr-dump.c | 3 ++- criu/include/parasite-syscall.h | 6 +++-- criu/include/pstree.h | 1 + criu/parasite-syscall.c | 40 +++++++++++++++++++++++++++------ 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index f7d9b2b09..a9e16a683 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -841,6 +841,7 @@ static int collect_file_locks(void) static int dump_task_thread(struct parasite_ctl *parasite_ctl, const struct pstree_item *item, int id) { + struct parasite_thread_ctl *tctl = dmpi(item)->thread_ctls[id]; struct pid *tid = &item->threads[id]; CoreEntry *core = item->core[id]; pid_t pid = tid->real; @@ -851,7 +852,7 @@ static int dump_task_thread(struct parasite_ctl *parasite_ctl, pr_info("Dumping core for thread (pid: %d)\n", pid); pr_info("----------------------------------------\n"); - ret = parasite_dump_thread_seized(parasite_ctl, id, tid, core); + ret = parasite_dump_thread_seized(tctl, parasite_ctl, id, tid, core); if (ret) { pr_err("Can't dump thread for pid %d\n", pid); goto err; diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h index 0e9d340cf..c86a724fd 100644 --- a/criu/include/parasite-syscall.h +++ b/criu/include/parasite-syscall.h @@ -21,6 +21,7 @@ struct parasite_dump_cgroup_args; struct rt_sigframe; struct parasite_ctl; +struct parasite_thread_ctl; extern int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct pstree_item *); extern int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct pstree_item *); @@ -32,8 +33,9 @@ extern int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc extern int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_misc *misc); extern int parasite_dump_creds(struct parasite_ctl *ctl, struct _CredsEntry *ce); extern int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, struct _CoreEntry *core); -extern int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, - struct pid *tid, struct _CoreEntry *core); +extern int parasite_dump_thread_seized(struct parasite_thread_ctl *tctl, + struct parasite_ctl *ctl, int id, + struct pid *tid, struct _CoreEntry *core); extern int dump_thread_core(int pid, CoreEntry *core, const struct parasite_dump_thread *dt); diff --git a/criu/include/pstree.h b/criu/include/pstree.h index 508d6df2b..4913aae44 100644 --- a/criu/include/pstree.h +++ b/criu/include/pstree.h @@ -56,6 +56,7 @@ struct dmp_info { struct ns_id *netns; struct page_pipe *mem_pp; struct parasite_ctl *parasite_ctl; + struct parasite_thread_ctl **thread_ctls; }; static inline struct dmp_info *dmpi(const struct pstree_item *i) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 267d3fa07..366c6c905 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -162,7 +162,8 @@ int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEn return dump_thread_core(pid, core, args); } -int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, +int parasite_dump_thread_seized(struct parasite_thread_ctl *tctl, + struct parasite_ctl *ctl, int id, struct pid *tid, CoreEntry *core) { struct parasite_dump_thread *args; @@ -171,7 +172,6 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, CredsEntry *creds = tc->creds; struct parasite_dump_creds *pc; int ret; - struct parasite_thread_ctl *tctl; BUG_ON(id == 0); /* Leader is dumped in dump_task_core_all */ @@ -180,10 +180,6 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id, pc = args->creds; pc->cap_last_cap = kdat.last_cap; - tctl = compel_prepare_thread(ctl, pid); - if (!tctl) - return -1; - tc->has_blk_sigset = true; memcpy(&tc->blk_sigset, compel_thread_sigmask(tctl), sizeof(k_rtsigset_t)); ret = compel_get_thread_regs(tctl, save_task_regs, core); @@ -468,12 +464,39 @@ static int make_sigframe(void *arg, struct rt_sigframe *sf, struct rt_sigframe * return construct_sigframe(sf, rtsf, bs, (CoreEntry *)arg); } +static int parasite_prepare_threads(struct parasite_ctl *ctl, + struct pstree_item *item) +{ + struct parasite_thread_ctl **thread_ctls; + int i; + + thread_ctls = xzalloc(sizeof(*thread_ctls) * item->nr_threads); + if (!thread_ctls) + return -1; + + for (i = 0; i < item->nr_threads; i++) { + struct pid *tid = &item->threads[i]; + + if (item->pid->real == tid->real) + continue; + + thread_ctls[i] = compel_prepare_thread(ctl, tid->real); + if (!thread_ctls[i]) + return -1; + } + + dmpi(item)->thread_ctls = thread_ctls; + + return 0; +} + struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, struct vm_area_list *vma_area_list) { struct parasite_ctl *ctl; struct infect_ctx *ictx; unsigned long p; + int ret; BUG_ON(item->threads[0].real != pid); @@ -487,6 +510,10 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, if (!ctl) return NULL; + ret = parasite_prepare_threads(ctl, item); + if (ret) + return NULL; + ictx = compel_infect_ctx(ctl); ictx->open_proc = do_open_proc; @@ -532,4 +559,3 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, return ctl; } - From 1a72f37a09c716a290c0ca49a85d7be73cac7c8d Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 13 Aug 2018 16:29:11 +0300 Subject: [PATCH 1714/4375] criu: dump: get stack pointers of all threads early The stack pointers will be later use by the memory dump to ensure that current stack pages are not treated as lazy. Signed-off-by: Mike Rapoport --- criu/include/pstree.h | 1 + criu/parasite-syscall.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/criu/include/pstree.h b/criu/include/pstree.h index 4913aae44..e6ad281e4 100644 --- a/criu/include/pstree.h +++ b/criu/include/pstree.h @@ -57,6 +57,7 @@ struct dmp_info { struct page_pipe *mem_pp; struct parasite_ctl *parasite_ctl; struct parasite_thread_ctl **thread_ctls; + uint64_t *thread_sp; }; static inline struct dmp_info *dmpi(const struct pstree_item *i) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 366c6c905..10504edff 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -468,24 +468,34 @@ static int parasite_prepare_threads(struct parasite_ctl *ctl, struct pstree_item *item) { struct parasite_thread_ctl **thread_ctls; + uint64_t *thread_sp; int i; thread_ctls = xzalloc(sizeof(*thread_ctls) * item->nr_threads); if (!thread_ctls) return -1; + thread_sp = xzalloc(sizeof(*thread_sp) * item->nr_threads); + if (!thread_sp) + return -1; + for (i = 0; i < item->nr_threads; i++) { struct pid *tid = &item->threads[i]; - if (item->pid->real == tid->real) + if (item->pid->real == tid->real) { + thread_sp[i] = compel_get_leader_sp(ctl); continue; + } thread_ctls[i] = compel_prepare_thread(ctl, tid->real); if (!thread_ctls[i]) return -1; + + thread_sp[i] = compel_get_thread_sp(thread_ctls[i]); } dmpi(item)->thread_ctls = thread_ctls; + dmpi(item)->thread_sp = thread_sp; return 0; } From a97255cb5929eccad0b87e185deff0f454067f41 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 13 Aug 2018 16:29:12 +0300 Subject: [PATCH 1715/4375] criu: mem: introduce generate_vma_iovs helper function Signed-off-by: Mike Rapoport --- criu/mem.c | 82 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/criu/mem.c b/criu/mem.c index 44d0e2585..a83007c90 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -330,6 +330,50 @@ static int detect_pid_reuse(struct pstree_item *item, return 0; } +static int generate_vma_iovs(struct pstree_item *item, struct vma_area *vma, + struct page_pipe *pp, struct page_xfer *xfer, + struct parasite_dump_pages_args *args, + struct parasite_ctl *ctl, pmc_t *pmc, + bool has_parent, bool pre_dump) +{ + u64 off = 0; + u64 *map; + int ret; + + if (!vma_area_is_private(vma, kdat.task_size) && + !vma_area_is(vma, VMA_ANON_SHARED)) + return 0; + + if (vma_entry_is(vma->e, VMA_AREA_AIORING)) { + if (pre_dump) + return 0; + has_parent = false; + } + + map = pmc_get_map(pmc, vma); + if (!map) + return -1; + + if (vma_area_is(vma, VMA_ANON_SHARED)) + return add_shmem_area(item->pid->real, vma->e, map); + +again: + ret = generate_iovs(vma, pp, map, &off, has_parent); + if (ret == -EAGAIN) { + BUG_ON(!(pp->flags & PP_CHUNK_MODE)); + + ret = drain_pages(pp, ctl, args); + if (!ret) + ret = xfer_pages(pp, xfer); + if (!ret) { + page_pipe_reinit(pp); + goto again; + } + } + + return ret; +} + static int __parasite_dump_pages_seized(struct pstree_item *item, struct parasite_dump_pages_args *args, struct vm_area_list *vma_area_list, @@ -344,6 +388,7 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, unsigned cpp_flags = 0; unsigned long pmc_size; int possible_pid_reuse = 0; + bool has_parent; pr_info("\n"); pr_info("Dumping pages (type: %d pid: %d)\n", CR_FD_PAGES, item->pid->real); @@ -409,41 +454,10 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, * Step 1 -- generate the pagemap */ args->off = 0; + has_parent = !!xfer.parent && !possible_pid_reuse; list_for_each_entry(vma_area, &vma_area_list->h, list) { - bool has_parent = !!xfer.parent; - u64 off = 0; - u64 *map; - - if (!vma_area_is_private(vma_area, kdat.task_size) && - !vma_area_is(vma_area, VMA_ANON_SHARED)) - continue; - if (vma_entry_is(vma_area->e, VMA_AREA_AIORING)) { - if (mdc->pre_dump) - continue; - has_parent = false; - } - - map = pmc_get_map(&pmc, vma_area); - if (!map) - goto out_xfer; - if (vma_area_is(vma_area, VMA_ANON_SHARED)) - ret = add_shmem_area(item->pid->real, vma_area->e, map); - else { -again: - ret = generate_iovs(vma_area, pp, map, &off, - has_parent && !possible_pid_reuse); - if (ret == -EAGAIN) { - BUG_ON(!(pp->flags & PP_CHUNK_MODE)); - - ret = drain_pages(pp, ctl, args); - if (!ret) - ret = xfer_pages(pp, &xfer); - if (!ret) { - page_pipe_reinit(pp); - goto again; - } - } - } + ret = generate_vma_iovs(item, vma_area, pp, &xfer, args, ctl, + &pmc, has_parent, mdc->pre_dump); if (ret < 0) goto out_xfer; } From 5432a964dcc70f050ae99f06ca8c00aa304159d9 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 13 Aug 2018 16:29:13 +0300 Subject: [PATCH 1716/4375] lazy-pages: don't mark current stack page as lazy Signed-off-by: Mike Rapoport --- criu/mem.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/criu/mem.c b/criu/mem.c index a83007c90..de9df5f68 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -142,6 +142,20 @@ bool page_in_parent(bool dirty) return __page_in_parent(dirty); } +static bool is_stack(struct pstree_item *item, unsigned long vaddr) +{ + int i; + + for (i = 0; i < item->nr_threads; i++) { + uint64_t sp = dmpi(item)->thread_sp[i]; + + if (!((sp ^ vaddr) & PAGE_MASK)) + return true; + } + + return false; +} + /* * This routine finds out what memory regions to grab from the * dumpee. The iovs generated are then fed into vmsplice to @@ -151,7 +165,7 @@ bool page_in_parent(bool dirty) * the memory contents is present in the pagent image set. */ -static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u64 *off, bool has_parent) +static int generate_iovs(struct pstree_item *item, struct vma_area *vma, struct page_pipe *pp, u64 *map, u64 *off, bool has_parent) { u64 *at = &map[PAGE_PFN(*off)]; unsigned long pfn, nr_to_scan; @@ -169,7 +183,7 @@ static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u vaddr = vma->e->start + *off + pfn * PAGE_SIZE; - if (vma_entry_can_be_lazy(vma->e)) + if (vma_entry_can_be_lazy(vma->e) && !is_stack(item, vaddr)) ppb_flags |= PPB_LAZY; /* @@ -358,7 +372,7 @@ static int generate_vma_iovs(struct pstree_item *item, struct vma_area *vma, return add_shmem_area(item->pid->real, vma->e, map); again: - ret = generate_iovs(vma, pp, map, &off, has_parent); + ret = generate_iovs(item,vma, pp, map, &off, has_parent); if (ret == -EAGAIN) { BUG_ON(!(pp->flags & PP_CHUNK_MODE)); From 43193f620aa0ed2045dcc5076d04bf51444262c9 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 9 Aug 2018 10:50:53 +0300 Subject: [PATCH 1717/4375] net: remove excess null terminating characters in messages Signed-off-by: Pavel Tikhomirov --- criu/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/net.c b/criu/net.c index cbd03dd0a..b87b3b33a 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1717,7 +1717,7 @@ static int run_ip_tool(char *arg1, char *arg2, char *arg3, char *arg4, int fdin, char *ip_tool_cmd; int ret; - pr_debug("\tRunning ip %s %s %s %s\n", arg1, arg2, arg3 ? : "\0", arg4 ? : "\0"); + pr_debug("\tRunning ip %s %s %s %s\n", arg1, arg2, arg3 ? : "", arg4 ? : ""); ip_tool_cmd = getenv("CR_IP_TOOL"); if (!ip_tool_cmd) @@ -1727,7 +1727,7 @@ static int run_ip_tool(char *arg1, char *arg2, char *arg3, char *arg4, int fdin, (char *[]) { "ip", arg1, arg2, arg3, arg4, NULL }, flags); if (ret) { if (!(flags & CRS_CAN_FAIL)) - pr_err("IP tool failed on %s %s %s %s\n", arg1, arg2, arg3 ? : "\0", arg4 ? : "\0"); + pr_err("IP tool failed on %s %s %s %s\n", arg1, arg2, arg3 ? : "", arg4 ? : ""); return -1; } From 787dd695b323e4b4ba3aa2349c39f58bcf0fcae7 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 10 Aug 2018 17:58:11 +0300 Subject: [PATCH 1718/4375] pagemap: Use ssize_t type in read_local_page Integer is too small for big memory slabs. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/pagemap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/pagemap.c b/criu/pagemap.c index b106f883e..8d00ca1e8 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -239,7 +239,7 @@ static int read_local_page(struct page_read *pr, unsigned long vaddr, unsigned long len, void *buf) { int fd = img_raw_fd(pr->pi); - int ret; + ssize_t ret; size_t curr = 0; /* @@ -253,7 +253,7 @@ static int read_local_page(struct page_read *pr, unsigned long vaddr, while (1) { ret = pread(fd, buf + curr, len - curr, pr->pi_off + curr); if (ret < 1) { - pr_perror("Can't read mapping page %d", ret); + pr_perror("Can't read mapping page %zd", ret); return -1; } curr += ret; From 1c37c0d46b062a59da2c41fcae47ae263606aaf5 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 13 Aug 2018 15:34:34 +0300 Subject: [PATCH 1719/4375] zdtm/fork: print children wait status 05:57:35.640: 1238: FAIL: fork.c:80: Task 16275 didn't exit (errno = 10 (No child processes)) There is no info about the killing signal in logs, add it. https://jira.sw.ru/browse/PSBM-87579 Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm/transition/fork.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/zdtm/transition/fork.c b/test/zdtm/transition/fork.c index 4940bc538..9ab160599 100644 --- a/test/zdtm/transition/fork.c +++ b/test/zdtm/transition/fork.c @@ -77,12 +77,12 @@ int main(int argc, char **argv) break; if (!WIFEXITED(status)) { - fail("Task %d didn't exit", wpid); + fail("Task %d didn't exit with status %d", wpid, status); goto out; } if (WEXITSTATUS(status) != 0) { - fail("Task %d exited with wrong code", wpid); + fail("Task %d exited with wrong status %d", wpid, status); goto out; } } From c5f8748b7239bdae65a8beeb6329a547781f0df9 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 10 Aug 2018 18:00:51 +0300 Subject: [PATCH 1720/4375] page-xfer: Handle partial splicing In case if pipe buffers are full the splicing may wakeup reader first with incomplete data transfer. Thus splice data in cycle. Signed-off-by: Cyrill Gorcunov Acked-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index e653de5b3..81a7dfd4a 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -147,11 +147,19 @@ static inline int send_psi(int sk, struct page_server_iov *pi) static int write_pages_to_server(struct page_xfer *xfer, int p, unsigned long len) { + ssize_t ret, left = len; + pr_debug("Splicing %lu bytes / %lu pages into socket\n", len, len / PAGE_SIZE); - if (splice(p, NULL, xfer->sk, NULL, len, SPLICE_F_MOVE) != len) { - pr_perror("Can't write pages to socket"); - return -1; + while (left > 0) { + ret = splice(p, NULL, xfer->sk, NULL, left, SPLICE_F_MOVE); + if (ret < 0) { + pr_perror("Can't write pages to socket"); + return -1; + } + + pr_debug("\tSpliced: %lu bytes sent\n", (unsigned long)ret); + left -= ret; } return 0; From 07da7b0f427ddeb4dd9311e5d1e8680094bd8f7e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 10 Aug 2018 17:53:01 +0300 Subject: [PATCH 1721/4375] compel -- Use unsigned long for arguments When checkpointing applications with really big memory slab (like in our vz7 test with 920G of memory) the int type get cutted, we should use long int instead, just like we do in other code pieces. Otherwise get | pie: 756: Daemon waits for command | (01.193097) Wait for ack 12 on daemon socket | (01.193112) Fetched ack: 12 12 0 | (01.193164) 988065 fdinfo 0: pos: 0 flags: 100002/0 | (01.193201) fdinfo: type: 0xb flags: 0100002/0 pos: 0 fd: 0 | (01.193279) 988065 fdinfo 1: pos: 0 flags: 100002/0 | (01.193307) fdinfo: type: 0xb flags: 0100002/0 pos: 0 fd: 1 | (01.193341) 988065 fdinfo 2: pos: 0 flags: 100002/0 | (01.193365) fdinfo: type: 0xb flags: 0100002/0 pos: 0 fd: 2 | (01.193375) ---------------------------------------- | (01.193405) Error (criu/parasite-syscall.c:243): BUG at criu/parasite-syscall.c:243 | pie: 756: Error (criu/pie/parasite.c:676): Trimmed message received (1> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/include/uapi/infect.h | 2 +- compel/src/lib/infect.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 3b98f2d0b..08beaffcd 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -56,7 +56,7 @@ extern int compel_cure(struct parasite_ctl *ctl); }) extern void *compel_parasite_args_p(struct parasite_ctl *ctl); -extern void *compel_parasite_args_s(struct parasite_ctl *ctl, int args_size); +extern void *compel_parasite_args_s(struct parasite_ctl *ctl, unsigned long args_size); extern int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, unsigned long arg1, diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 4648e39b3..8ff05d6ea 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -1351,7 +1351,7 @@ void *compel_parasite_args_p(struct parasite_ctl *ctl) return ctl->addr_args; } -void *compel_parasite_args_s(struct parasite_ctl *ctl, int args_size) +void *compel_parasite_args_s(struct parasite_ctl *ctl, unsigned long args_size) { BUG_ON(args_size > ctl->args_size); return compel_parasite_args_p(ctl); From f194124e0a822e4fa795dbd1f2252ad51c4422af Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 8 Aug 2018 12:50:08 +0300 Subject: [PATCH 1722/4375] zdtm: cleanup zdtmtst and zdtmtst.defaultroot cgroups after finishing test After running criu test, docker on the node becomes unusable, as it is confused by our leftover cgroups. Surely docker should be fixed to ignore custom cgroups (https://github.com/moby/moby/issues/37601), but we should not leave them after test also. v2: rmdir the holder only if it exists, remove racy wait and remove wrongly added cleanup method in class criu v3: bring back missed semicolon Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm.py | 11 +++++++++++ test/zdtm_umount_cgroups | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100755 test/zdtm_umount_cgroups diff --git a/test/zdtm.py b/test/zdtm.py index 99ec6aaac..25e965db3 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -569,6 +569,10 @@ class zdtm_test: subprocess.check_call(["make", "-C", "zdtm/"]) subprocess.check_call(["flock", "zdtm_mount_cgroups.lock", "./zdtm_mount_cgroups"]) + @staticmethod + def cleanup(): + subprocess.check_call(["flock", "zdtm_mount_cgroups.lock", "./zdtm_umount_cgroups"]) + class inhfd_test: def __init__(self, name, desc, flavor, freezer): @@ -674,6 +678,10 @@ class inhfd_test: def available(): pass + @staticmethod + def cleanup(): + pass + class groups_test(zdtm_test): def __init__(self, name, desc, flavor, freezer): @@ -2200,3 +2208,6 @@ for tst in test_classes.values(): tst.available() opts['action'](opts) + +for tst in test_classes.values(): + tst.cleanup() diff --git a/test/zdtm_umount_cgroups b/test/zdtm_umount_cgroups new file mode 100755 index 000000000..75a8ea28f --- /dev/null +++ b/test/zdtm_umount_cgroups @@ -0,0 +1,16 @@ +#!/bin/sh + +# Lets delete all test controllers after executing tests. + +cat /proc/self/cgroup | grep -q zdtmtst.defaultroot || exit 0 + +tdir=`mktemp -d zdtm.XXXXXX` +for i in "zdtmtst" "zdtmtst.defaultroot"; do + mount -t cgroup -o none,name=$i zdtm $tdir || { rmdir $tdir; exit 1; } + # remove a fake group if exists + if [ -d "$tdir/holder" ]; then + rmdir $tdir/holder || { umount -l $tdir && rmdir $tdir; exit 1; } + fi + umount -l $tdir || exit 1; +done +rmdir $tdir From 3795598cd55fca9abde460d9807319297fd23b12 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 8 Aug 2018 08:43:16 +0300 Subject: [PATCH 1723/4375] zdtm: handle inherit_fd-s in the rpc mode ./test//zdtm.py --set inhfd run --all --rpc Cc: Adrian Reber Signed-off-by: Andrei Vagin --- test/zdtm.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index 25e965db3..7b80f536d 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -821,6 +821,16 @@ class criu_rpc: if arg == '--tcp-established': criu.opts.tcp_established = True continue + if arg == '--restore-sibling': + criu.opts.rst_sibling = True + continue + if arg == "--inherit-fd": + inhfd = criu.opts.inherit_fd.add() + key = args.pop(0) + fd, key = key.split(":", 1) + inhfd.fd = int(fd[3:-1]) + inhfd.key = key + continue raise test_fail_exc('RPC for %s required' % arg) From d51695604b4ea4ffb9ca7bf70df54e00b2089f62 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 6 Aug 2018 10:20:55 +0300 Subject: [PATCH 1724/4375] files: fix naming confusion between RemapFilePathEntry and RegFileEntry call variables of type RemapFilePathEntry - "rpe" everywhere, similar as we already name them in oher places while on it remove unused second argument of open_remap_linked Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 73 ++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 6583d4df5..b56a0ea9b 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -371,18 +371,18 @@ err: } static inline void ghost_path(char *path, int plen, - struct reg_file_info *rfi, RemapFilePathEntry *rfe) + struct reg_file_info *rfi, RemapFilePathEntry *rpe) { - snprintf(path, plen, "%s.cr.%x.ghost", rfi->path, rfe->remap_id); + snprintf(path, plen, "%s.cr.%x.ghost", rfi->path, rpe->remap_id); } static int collect_remap_ghost(struct reg_file_info *rfi, - RemapFilePathEntry *rfe) + RemapFilePathEntry *rpe) { struct ghost_file *gf; list_for_each_entry(gf, &ghost_files, list) - if (gf->id == rfe->remap_id) + if (gf->id == rpe->remap_id) goto gf_found; /* @@ -391,7 +391,7 @@ static int collect_remap_ghost(struct reg_file_info *rfi, * issues with cross-device links. */ - pr_info("Opening ghost file %#x for %s\n", rfe->remap_id, rfi->path); + pr_info("Opening ghost file %#x for %s\n", rpe->remap_id, rfi->path); gf = shmalloc(sizeof(*gf)); if (!gf) @@ -408,7 +408,7 @@ static int collect_remap_ghost(struct reg_file_info *rfi, if (!gf->remap.rpath) return -1; gf->remap.rpath[0] = 0; - gf->id = rfe->remap_id; + gf->id = rpe->remap_id; list_add_tail(&gf->list, &ghost_files); gf_found: @@ -418,7 +418,7 @@ gf_found: } static int open_remap_ghost(struct reg_file_info *rfi, - RemapFilePathEntry *rfe) + RemapFilePathEntry *rpe) { struct ghost_file *gf = container_of(rfi->remap, struct ghost_file, remap); GhostFileEntry *gfe = NULL; @@ -427,7 +427,7 @@ static int open_remap_ghost(struct reg_file_info *rfi, if (rfi->remap->rpath[0]) return 0; - img = open_image(CR_FD_GHOST_FILE, O_RSTR, rfe->remap_id); + img = open_image(CR_FD_GHOST_FILE, O_RSTR, rpe->remap_id); if (!img) goto err; @@ -446,7 +446,7 @@ static int open_remap_ghost(struct reg_file_info *rfi, if (S_ISDIR(gfe->mode)) strncpy(gf->remap.rpath, rfi->path, PATH_MAX); else - ghost_path(gf->remap.rpath, PATH_MAX, rfi, rfe); + ghost_path(gf->remap.rpath, PATH_MAX, rfi, rpe); if (create_ghost(gf, gfe, img)) goto close_ifd; @@ -469,15 +469,15 @@ err: } static int collect_remap_linked(struct reg_file_info *rfi, - RemapFilePathEntry *rfe) + RemapFilePathEntry *rpe) { struct file_remap *rm; struct file_desc *rdesc; struct reg_file_info *rrfi; - rdesc = find_file_desc_raw(FD_TYPES__REG, rfe->remap_id); + rdesc = find_file_desc_raw(FD_TYPES__REG, rpe->remap_id); if (!rdesc) { - pr_err("Can't find target file %x\n", rfe->remap_id); + pr_err("Can't find target file %x\n", rpe->remap_id); return -1; } @@ -497,8 +497,7 @@ static int collect_remap_linked(struct reg_file_info *rfi, return 0; } -static int open_remap_linked(struct reg_file_info *rfi, - RemapFilePathEntry *rfe) +static int open_remap_linked(struct reg_file_info *rfi) { if (root_ns_mask & CLONE_NEWUSER) { int rfd; @@ -550,47 +549,47 @@ static int collect_remap_dead_process(struct reg_file_info *rfi, struct remap_info { struct list_head list; - RemapFilePathEntry *rfe; + RemapFilePathEntry *rpe; struct reg_file_info *rfi; }; static int collect_one_remap(void *obj, ProtobufCMessage *msg, struct cr_img *i) { struct remap_info *ri = obj; - RemapFilePathEntry *rfe; + RemapFilePathEntry *rpe; struct file_desc *fdesc; - ri->rfe = rfe = pb_msg(msg, RemapFilePathEntry); + ri->rpe = rpe = pb_msg(msg, RemapFilePathEntry); - if (!rfe->has_remap_type) { - rfe->has_remap_type = true; + if (!rpe->has_remap_type) { + rpe->has_remap_type = true; /* backward compatibility with images */ - if (rfe->remap_id & REMAP_GHOST) { - rfe->remap_id &= ~REMAP_GHOST; - rfe->remap_type = REMAP_TYPE__GHOST; + if (rpe->remap_id & REMAP_GHOST) { + rpe->remap_id &= ~REMAP_GHOST; + rpe->remap_type = REMAP_TYPE__GHOST; } else - rfe->remap_type = REMAP_TYPE__LINKED; + rpe->remap_type = REMAP_TYPE__LINKED; } - fdesc = find_file_desc_raw(FD_TYPES__REG, rfe->orig_id); + fdesc = find_file_desc_raw(FD_TYPES__REG, rpe->orig_id); if (fdesc == NULL) { - pr_err("Remap for non existing file %#x\n", rfe->orig_id); + pr_err("Remap for non existing file %#x\n", rpe->orig_id); return -1; } ri->rfi = container_of(fdesc, struct reg_file_info, d); - switch (rfe->remap_type) { + switch (rpe->remap_type) { case REMAP_TYPE__GHOST: - if (collect_remap_ghost(ri->rfi, ri->rfe)) + if (collect_remap_ghost(ri->rfi, ri->rpe)) return -1; break; case REMAP_TYPE__LINKED: - if (collect_remap_linked(ri->rfi, ri->rfe)) + if (collect_remap_linked(ri->rfi, ri->rpe)) return -1; break; case REMAP_TYPE__PROCFS: - if (collect_remap_dead_process(ri->rfi, rfe) < 0) + if (collect_remap_dead_process(ri->rfi, rpe) < 0) return -1; break; default: @@ -605,24 +604,24 @@ static int collect_one_remap(void *obj, ProtobufCMessage *msg, struct cr_img *i) static int prepare_one_remap(struct remap_info *ri) { int ret = -1; - RemapFilePathEntry *rfe = ri->rfe; + RemapFilePathEntry *rpe = ri->rpe; struct reg_file_info *rfi = ri->rfi; - pr_info("Configuring remap %#x -> %#x\n", rfi->rfe->id, rfe->remap_id); + pr_info("Configuring remap %#x -> %#x\n", rfi->rfe->id, rpe->remap_id); - switch (rfe->remap_type) { + switch (rpe->remap_type) { case REMAP_TYPE__LINKED: - ret = open_remap_linked(rfi, rfe); + ret = open_remap_linked(rfi); break; case REMAP_TYPE__GHOST: - ret = open_remap_ghost(rfi, rfe); + ret = open_remap_ghost(rfi, rpe); break; case REMAP_TYPE__PROCFS: /* handled earlier by collect_remap_dead_process */ ret = 0; break; default: - pr_err("unknown remap type %u\n", rfe->remap_type); + pr_err("unknown remap type %u\n", rpe->remap_type); goto out; } @@ -692,11 +691,11 @@ int try_clean_remaps(bool only_ghosts) int ret = 0; list_for_each_entry(ri, &remaps, list) { - if (ri->rfe->remap_type == REMAP_TYPE__GHOST) + if (ri->rpe->remap_type == REMAP_TYPE__GHOST) ret |= clean_one_remap(ri); else if (only_ghosts) continue; - else if (ri->rfe->remap_type == REMAP_TYPE__LINKED) + else if (ri->rpe->remap_type == REMAP_TYPE__LINKED) ret |= clean_one_remap(ri); } From ed2e5d40775a8fce02032a2bd3a38ca6a56b1c99 Mon Sep 17 00:00:00 2001 From: Pawel Stradomski Date: Mon, 30 Jul 2018 18:47:34 +0200 Subject: [PATCH 1725/4375] Fall back to opening image files readonly if readwrite fails. This can happen when running in user namespace with auto-dedup enabled. Right now this means auto-dedup gets disabled. Signed-off-by: Pawel Stradomski Signed-off-by: Andrei Vagin --- criu/mem.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/criu/mem.c b/criu/mem.c index de9df5f68..bf8498a7c 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -1304,6 +1304,15 @@ static int prepare_vma_ios(struct pstree_item *t, struct task_restore_args *ta) */ pages = open_image(CR_FD_PAGES, opts.auto_dedup ? O_RDWR : O_RSTR, rsti(t)->pages_img_id); + /* When running inside namespace we might lack privileges to open the file + * for writing. + * TODO: use userns_call to do the opening instead of downgrading to opening + * read-only. + */ + if (!pages && opts.auto_dedup) { + pr_warn("Failed to open image read-write, trying read-only instead. auto-dedup won't work\n"); + pages = open_image(CR_FD_PAGES, O_RSTR, rsti(t)->pages_img_id); + } if (!pages) return -1; From b939a4df020ba8a7c52499b2a1d3c01611f5626a Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 19 Jul 2018 11:28:00 +0300 Subject: [PATCH 1726/4375] dump/files: remove a leftover from dead_pid_conflict In commit 23b769498cb3 ("dump: optimize dead_pid_conflict by searching in rbtree") we'd replaced for_each_pstree_item and thread walk search with pstree_pid_by_virt (rb-tree search). The latter already found us the thread with conflicting pid if it exists, the only thing left is to skip if the thread is also a main thread of the thread group (as it was before patch). But some leftover left which checks something wrong: we index ->threads array with "i", but "i" is not a number of the thread it is a number of current dead pid. Not sure if it helps with the initial bug and duplicates, but it might: https://jira.sw.ru/browse/PSBM-55217 Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index b56a0ea9b..d6161fef0 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -964,18 +964,9 @@ int dead_pid_conflict(void) if (!node) continue; - if (node->state != TASK_THREAD) { - struct pstree_item *item; - - /* - * If the dead PID was given to a main thread of another - * process, this is handled during restore. - */ - item = node->item; - if (item->pid->real == item->threads[i].real || - item->threads[i].ns[0].virt != pid) - continue; - } + /* Main thread */ + if (node->state != TASK_THREAD) + continue; pr_err("Conflict with a dead task with the same PID as of this thread (virt %d, real %d).\n", node->ns[0].virt, node->real); From 23d619a53cefd20551b7d778c92a00a90371990d Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 27 Jul 2018 05:18:53 +0300 Subject: [PATCH 1727/4375] criu: add a few missing newlines in pr_err() Signed-off-by: Andrei Vagin --- criu/net.c | 4 ++-- criu/sk-unix.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/net.c b/criu/net.c index b87b3b33a..f523bc192 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1233,7 +1233,7 @@ static int veth_peer_info(struct net_link *link, struct newlink_req *req, return 0; } out: - pr_err("Unknown peer net namespace"); + pr_err("Unknown peer net namespace\n"); return -1; } @@ -1703,7 +1703,7 @@ static int restore_links() if (nrcreated == nrlinks) break; if (nrcreated == 0) { - pr_err("Unable to restore network links"); + pr_err("Unable to restore network links\n"); return -1; } } diff --git a/criu/sk-unix.c b/criu/sk-unix.c index d7086bbc6..c10ca9707 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -302,7 +302,7 @@ static int resolve_rel_name(uint32_t id, struct unix_sk_desc *sk, const struct f dir[ret] = 0; if (snprintf(path, sizeof(path), ".%s/%s", dir, sk->name) >= sizeof(path)) { - pr_err("The path .%s/%s is too long", dir, sk->name); + pr_err("The path .%s/%s is too long\n", dir, sk->name); goto err; } if (fstatat(mntns_root, path, &st, 0)) { From 5f8ee1053f9527bb877bb80339839536aade7d64 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Wed, 15 Aug 2018 11:14:22 +0200 Subject: [PATCH 1728/4375] s390: Fix to skip the test if GS not supported Signed-off-by: Alice Frosi Signed-off-by: Andrei Vagin --- test/zdtm/static/s390x_gs_threads.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/s390x_gs_threads.c b/test/zdtm/static/s390x_gs_threads.c index 7d3a07521..8d1442194 100644 --- a/test/zdtm/static/s390x_gs_threads.c +++ b/test/zdtm/static/s390x_gs_threads.c @@ -149,7 +149,7 @@ int main(int argc, char *argv[]) test_init(argc, argv); /* Enable guarded-storage */ if (syscall(__NR_guarded_storage, GS_ENABLE) != 0) { - if (errno == ENOSYS) { + if (errno == ENOSYS || errno == EOPNOTSUPP) { test_daemon(); test_waitsig(); skip("No guarded storage support"); From a853ccfbe04336a72a3730e4170b14c24463cd7e Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 2 Aug 2018 13:33:28 +0000 Subject: [PATCH 1729/4375] Documentation: update RPC configuration file section Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 609234bca..9d7b294b8 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -609,12 +609,25 @@ they are compatible with the ones present in an image file. CONFIGURATION FILES ------------------- -Criu supports usage of configuration files to avoid the need of writing every +*Criu* supports usage of configuration files to avoid the need of writing every option on command line, which is useful especially with repeated usage of same options. A specific configuration file can be passed with -"*--config* 'file'" option. If no file is passed, default configuration files -'/etc/criu/default.conf' and '$HOME/.criu/default.conf' are parsed (if -present on the system). Default configuration file parsing can be forbidden +the "*--config* 'file'" option. If no file is passed, the default configuration +files '/etc/criu/default.conf' and '$HOME/.criu/default.conf' are parsed (if +present on the system). If the environment variable CRIU_CONFIG_FILE is set, +it will also be parsed. + +The options parsed to CRIU via CLI, RPC or configuration file are evaluated +in the following order: + + - apply_config(/etc/criu/default.conf) + - apply_config($HOME/.criu/default.conf) + - apply_config(CRIU_CONFIG_FILE) + - apply_config(*--config* 'file') + - apply_config(CLI) or apply_config(RPC) + - apply_config(RPC configuration file) (only for RPC mode) + +Default configuration file parsing can be deactivated with "*--no-default-config*" if needed. Parsed configuration files are merged with command line options, which allows overriding boolean options. @@ -638,6 +651,23 @@ work-dir "/home/USERNAME/criu/my \"work\" directory" no-restore-sibling # this is another comment --------------- +Configuration files in RPC mode +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Not only does *criu* evaluate configuration files in CLI mode, it also +evaluates configuration files in RPC mode. Just as in CLI mode the +configuration file values are evaluated first. This means that any option +set via RPC will overwrite the configuration file setting. The user can +thus change *criu*'s default behavior but it is not possible to change +settings which are explicitly set by the RPC client. + +The RPC client can, however, specify an additional configuration file +which will be evaluated after the RPC options (see above for option evaluation +order). The RPC client can specify this additional configuration file +via "req.opts.config_file = '/path/to/file'". The values from this +configuration file will overwrite all other configuration file settings +or RPC options. *This can lead to undesired behavior of criu and +should only be used carefully.* + EXAMPLES -------- To checkpoint a program with pid of *1234* and write all image files into From 8f0225a82f9756e8f59f9c3fa40fa3a1ffc3a16d Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 22 Aug 2018 20:54:29 +0100 Subject: [PATCH 1730/4375] mount: Simplify ext_mount_parse_auto There are no functional changes. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/mount.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 62e012ec5..078654f63 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -77,17 +77,13 @@ int ext_mount_parse_auto(char *key) opts.autodetect_ext_mounts = true; if (*key == ':') { - while (1) { - key++; - if (*key == '\0') - break; - else if (*key == 'm') - opts.enable_external_masters = true; - else if (*key == 's') - opts.enable_external_sharing = true; - else - return -1; - } + key++; + if (*key == 'm') + opts.enable_external_masters = true; + else if (*key == 's') + opts.enable_external_sharing = true; + else if (*key != '\0') + return -1; } return 0; From 221f115189e5083fd7ee699c025d47d07c8bc0c3 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 22 Aug 2018 20:54:30 +0100 Subject: [PATCH 1731/4375] Fix typos Most of the typos were found by codespell. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 2 +- compel/arch/x86/src/lib/include/uapi/asm/cpu.h | 2 +- criu/arch/ppc64/vdso-pie.c | 2 +- criu/arch/x86/cpu.c | 4 ++-- criu/cgroup.c | 2 +- criu/config.c | 2 +- criu/cr-restore.c | 4 ++-- criu/crtools.c | 2 +- criu/eventpoll.c | 2 +- criu/filesystems.c | 2 +- criu/include/image.h | 2 +- criu/include/parasite.h | 4 ++-- criu/include/path.h | 2 +- criu/include/pstree.h | 2 +- criu/include/vma.h | 6 +++--- criu/log.c | 2 +- criu/mem.c | 4 ++-- criu/mount.c | 10 +++++----- criu/net.c | 6 +++--- criu/pie/parasite.c | 2 +- criu/pie/restorer.c | 8 ++++---- criu/seize.c | 2 +- criu/sk-queue.c | 2 +- criu/sk-unix.c | 2 +- criu/tty.c | 6 +++--- criu/tun.c | 2 +- criu/uffd.c | 10 +++++----- test/exhaustive/pipe.py | 6 +++--- test/exhaustive/unix.py | 16 ++++++++-------- test/zdtm/static/aio01.c | 2 +- test/zdtm/static/binfmt_misc.c | 4 ++-- test/zdtm/static/binfmt_misc.hook | 4 ++-- test/zdtm/static/cgroup_stray.c | 2 +- test/zdtm/static/cgroupns.c | 2 +- test/zdtm/static/different_creds.c | 2 +- test/zdtm/static/futex-rl.c | 2 +- test/zdtm/static/maps00.c | 2 +- test/zdtm/static/mount_paths.c | 2 +- test/zdtm/static/session01.c | 2 +- test/zdtm/static/vdso-proxy.c | 4 ++-- test/zdtm/static/vdso01.c | 2 +- test/zdtm/static/vsx.c | 2 +- test/zdtm/transition/maps008.c | 2 +- test/zdtm/transition/netlink00.c | 2 +- 44 files changed, 77 insertions(+), 77 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 9d7b294b8..6bb3f0f5d 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -617,7 +617,7 @@ files '/etc/criu/default.conf' and '$HOME/.criu/default.conf' are parsed (if present on the system). If the environment variable CRIU_CONFIG_FILE is set, it will also be parsed. -The options parsed to CRIU via CLI, RPC or configuration file are evaluated +The options passed to CRIU via CLI, RPC or configuration file are evaluated in the following order: - apply_config(/etc/criu/default.conf) diff --git a/compel/arch/x86/src/lib/include/uapi/asm/cpu.h b/compel/arch/x86/src/lib/include/uapi/asm/cpu.h index 6a0c91af4..bb1914da4 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/cpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/cpu.h @@ -11,7 +11,7 @@ * for us, so make sure they are at proper position between * versions. * - * In particular since we aready used leaf 11 we have + * In particular since we already used leaf 11 we have * to keep it here, since it's an ABI now. */ enum cpuid_leafs { diff --git a/criu/arch/ppc64/vdso-pie.c b/criu/arch/ppc64/vdso-pie.c index a7e017342..910c3d38b 100644 --- a/criu/arch/ppc64/vdso-pie.c +++ b/criu/arch/ppc64/vdso-pie.c @@ -70,7 +70,7 @@ static unsigned long put_trampoline(unsigned long at, struct vdso_symtable *sym) pr_debug("Checking '%s' at %lx\n", sym->symbols[i].name, sym->symbols[i].offset); - /* find the nearest followin symbol we are interested in */ + /* find the nearest following symbol we are interested in */ for (j=0; j < ARRAY_SIZE(sym->symbols); j++) { if (i==j || vdso_symbol_empty(&sym->symbols[j])) continue; diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index 35660929d..60b3b9e21 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -280,7 +280,7 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) */ if (memcmp(cpu_info->x86_capability, rt_cpu_info.x86_capability, sizeof(cpu_info->x86_capability))) { - pr_err("CPU capabilites do not match run time\n"); + pr_err("CPU capabilities do not match run time\n"); return -1; } @@ -335,7 +335,7 @@ static compel_cpuinfo_t *img_to_cpuinfo(CpuinfoX86Entry *img_x86_entry) /* * Copy caps from image and fill the left ones from - * run-time infomation for easier compatibility testing. + * run-time information for easier compatibility testing. */ size = sizeof(img_x86_entry->capability[0]) * img_x86_entry->n_capability; memcpy(cpu_info->x86_capability, img_x86_entry->capability, size); diff --git a/criu/cgroup.c b/criu/cgroup.c index c5d1284d0..868196a99 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -1471,7 +1471,7 @@ static int restore_devices_list(char *paux, size_t off, CgroupPropEntry *pr) ret = restore_cgroup_prop(&dev_deny, paux, off, false, false); /* - * An emptry string here means nothing is allowed, + * An empty string here means nothing is allowed, * and the kernel disallows writing an "" to devices.allow, * so let's just keep going. */ diff --git a/criu/config.c b/criu/config.c index 2e57a2af4..b1fd8d1a4 100644 --- a/criu/config.c +++ b/criu/config.c @@ -208,7 +208,7 @@ static int pre_parse(int argc, char **argv, bool *usage_error, bool *no_default_ { int i; /* - * We are runnning before getopt(), so we need to pre-parse + * We are running before getopt(), so we need to pre-parse * the command line. * * Check for --help / -h on commandline before parsing, otherwise diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 192c3a2be..6221c4b45 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1365,7 +1365,7 @@ static inline int fork_with_pid(struct pstree_item *item) } /* - * Some kernel modules, such as netwrok packet generator + * Some kernel modules, such as network packet generator * run kernel thread upon net-namespace creattion taking * the @pid we've been requeting via LAST_PID_PATH interface * so that we can't restore a take with pid needed. @@ -2279,7 +2279,7 @@ skip_ns_bouncing: out_kill: /* * The processes can be killed only when all of them have been created, - * otherwise an external proccesses can be killed. + * otherwise an external processes can be killed. */ if (root_ns_mask & CLONE_NEWPID) { int status; diff --git a/criu/crtools.c b/criu/crtools.c index 5d555ae56..17476d357 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -78,7 +78,7 @@ static int early_init(void) * limits. * * Note we have to do it before the service fd - * get inited and we dont exit with errors here + * get inited and we don't exit with errors here * because in worst scenario where clash of fd * happen we simply exit with explicit error * during real action stage. diff --git a/criu/eventpoll.c b/criu/eventpoll.c index a47cf015a..72e19e093 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -307,7 +307,7 @@ static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p) * Handling dup'ed or transferred target * files is tricky: we need to use kcmp * to find out where file came from. Until - * it's implemented lets use simplier approach + * it's implemented lets use simpler approach * just check the targets are blonging to the * pid's file set. */ diff --git a/criu/filesystems.c b/criu/filesystems.c index 59f7c99fe..d227427b8 100644 --- a/criu/filesystems.c +++ b/criu/filesystems.c @@ -171,7 +171,7 @@ static int binfmt_misc_dump(struct mount_info *pm) continue; if (!img) { - /* Create image only if an extry exists, i.e. here */ + /* Create image only if an entry exists, i.e. here */ img = open_image(CR_FD_BINFMT_MISC, O_DUMP); if (!img) goto out; diff --git a/criu/include/image.h b/criu/include/image.h index d576f5a13..1b2cdadf5 100644 --- a/criu/include/image.h +++ b/criu/include/image.h @@ -45,7 +45,7 @@ * contents modification especially when tasks are * migrating between different kernel versions * - heap - * "heap" area in application, currently for inforamtion only + * "heap" area in application, currently for information only * - file private * stands for privately memory mapped files * - file shared diff --git a/criu/include/parasite.h b/criu/include/parasite.h index 9e2e1498e..0a62f2439 100644 --- a/criu/include/parasite.h +++ b/criu/include/parasite.h @@ -152,7 +152,7 @@ struct parasite_dump_creds { * FIXME -- this structure is passed to parasite code * through parasite args area so in parasite_dump_creds() * call we check for size of this data fits the size of - * the area. Unfortunatelly, we _actually_ use more bytes + * the area. Unfortunately, we _actually_ use more bytes * than the sizeof() -- we put PARASITE_MAX_GROUPS int-s * in there, so the size check is not correct. * @@ -187,7 +187,7 @@ static inline void copy_sas(ThreadSasEntry *dst, const stack_t *src) * 1) struct parasite_drain_fd + all descriptors should fit into one page * 2) The value should be a multiple of CR_SCM_MAX_FD, because descriptors * are transferred with help of send_fds and recv_fds. - * 3) criu should work with a defaul value of the file limit (1024) + * 3) criu should work with a default value of the file limit (1024) */ #define PARASITE_MAX_FDS CR_SCM_MAX_FD * 3 diff --git a/criu/include/path.h b/criu/include/path.h index b00c64a89..c475986eb 100644 --- a/criu/include/path.h +++ b/criu/include/path.h @@ -4,7 +4,7 @@ #include "namespaces.h" #include "pstree.h" -/* Asolute paths are used on dump and relative paths are used on restore */ +/* Absolute paths are used on dump and relative paths are used on restore */ static inline int is_root(char *p) { return (!strcmp(p, "/")); diff --git a/criu/include/pstree.h b/criu/include/pstree.h index e6ad281e4..7303c1fed 100644 --- a/criu/include/pstree.h +++ b/criu/include/pstree.h @@ -65,7 +65,7 @@ static inline struct dmp_info *dmpi(const struct pstree_item *i) return (struct dmp_info *)(i + 1); } -/* ids is alocated and initialized for all alive tasks */ +/* ids is allocated and initialized for all alive tasks */ static inline int shared_fdtable(struct pstree_item *item) { return (item->parent && diff --git a/criu/include/vma.h b/criu/include/vma.h index 779466c21..c297c0d14 100644 --- a/criu/include/vma.h +++ b/criu/include/vma.h @@ -42,7 +42,7 @@ struct vma_area { char *aufs_fpath; /* full path from global root */ /* - * When several subsequent vmas have the same + * When several subsequent vmas have the same * dev:ino pair all 'tail' ones set this to true * and the vmst points to the head's stat buf. */ @@ -93,8 +93,8 @@ extern int parse_self_maps_lite(struct vm_area_list *vms); /* * vma_premmaped_start() can be used only in restorer. * In other cases vma_area->premmaped_addr must be used. - * This hack is required, because vma_area isn't tranfered in restorer and - * shmid is used to determing which vma-s are cowed. + * This hack is required, because vma_area isn't transferred in restorer and + * shmid is used to determine which vma-s are cowed. */ #define vma_premmaped_start(vma) ((vma)->shmid) diff --git a/criu/log.c b/criu/log.c index 43dcd106f..9e7703542 100644 --- a/criu/log.c +++ b/criu/log.c @@ -93,7 +93,7 @@ static void reset_buf_off(void) } /* - * Keeping the very first error messsage for RPC to report back. + * Keeping the very first error message for RPC to report back. */ struct str_and_lock { mutex_t l; diff --git a/criu/mem.c b/criu/mem.c index bf8498a7c..284af2954 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -642,7 +642,7 @@ static inline bool check_cow_vmas(struct vma_area *vma, struct vma_area *pvma) * memcmp'aring the contents. */ - /* ... coinside by start/stop pair (start is checked by caller) */ + /* ... coincide by start/stop pair (start is checked by caller) */ if (vma->e->end != pvma->e->end) return false; /* ... both be private (and thus have space in premmaped area) */ @@ -650,7 +650,7 @@ static inline bool check_cow_vmas(struct vma_area *vma, struct vma_area *pvma) return false; if (!vma_area_is_private(pvma, kdat.task_size)) return false; - /* ... have growsdown and anon flags coinside */ + /* ... have growsdown and anon flags coincide */ if ((vma->e->flags ^ pvma->e->flags) & (MAP_GROWSDOWN | MAP_ANONYMOUS)) return false; /* ... belong to the same file if being filemap */ diff --git a/criu/mount.c b/criu/mount.c index 078654f63..c83c1824a 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -584,7 +584,7 @@ static bool mnt_is_external(struct mount_info *m) } /* - * Having two children whith same mountpoint is unsupported. That can happen in + * Having two children with same mountpoint is unsupported. That can happen in * case of mount propagation inside of shared mounts, in that case it is hard * to find out mount propagation siblings and which of these mounts is above * (visible) and which is beneath (hidden). It would've broken mount restore @@ -1359,7 +1359,7 @@ int open_mountpoint(struct mount_info *pm) * namespace so that we can safely get rid of overmounts and get an * access to the mount. * In both cases we can't do the thing from criu's mount namespace, so - * we need to switch to mount's mount namespace, and later swtich back. + * we need to switch to mount's mount namespace, and later switch back. */ cwd_fd = open(".", O_DIRECTORY); if (cwd_fd < 0) { @@ -1377,7 +1377,7 @@ int open_mountpoint(struct mount_info *pm) /* * Mount is overmounted or probably we can't create a temporary - * direcotry for a cleaned mount + * directory for a cleaned mount */ if (fd < 0) { int pid, status; @@ -1707,7 +1707,7 @@ err: /* * _fn_f - pre-order traversal function - * _fn_f - post-order traversal function + * _fn_r - post-order traversal function * _plist - a postpone list. _el is added to this list, if _fn_f returns * a positive value, and all lower elements are not enumerated. */ @@ -2784,7 +2784,7 @@ static int get_mp_root(MntEntry *me, struct mount_info *mi) if (me->ext_mount) { me->ext_key = me->root; /* - * Puting the id of external mount which is provided by user, + * Putting the id of external mount which is provided by user, * to ->root can confuse mnt_is_external and other functions * which expect to see the path in the file system to the root * of these mount (mounts_equal, mnt_build_ids_tree, diff --git a/criu/net.c b/criu/net.c index f523bc192..0431b62f9 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2180,7 +2180,7 @@ static int collect_netns_id(struct ns_id *ns, void *oarg) if (!netns_id) return -1; - pr_debug("Fount the %d id for %d in %d\n", nsid, ns->id, arg->ns->id); + pr_debug("Found the %d id for %d in %d\n", nsid, ns->id, arg->ns->id); netns_id->target_ns_id = ns->id; netns_id->netnsid_value = nsid; @@ -2555,7 +2555,7 @@ int netns_keep_nsfd(void) } /* - * If we want to modify iptables, we need to recevied the current + * If we want to modify iptables, we need to received the current * configuration, change it and load a new one into the kernel. * iptables can change or add only one rule. * iptables-restore allows to make a few changes for one iteration, @@ -2807,7 +2807,7 @@ struct ns_id *get_socket_ns(int lfd) ns_fd = ioctl(lfd, SIOCGSKNS); if (ns_fd < 0) { - /* backward compatiblity with old kernels */ + /* backward compatibility with old kernels */ if (netns_nr == 1) return net_get_root_ns(); diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index 1567ed7a5..c32e31384 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -581,7 +581,7 @@ static int parasite_check_vdso_mark(struct parasite_vdso_vma_entry *args) if (is_vdso_mark(m)) { /* * Make sure we don't meet some corrupted entry - * where signature matches but verions is not! + * where signature matches but versions do not! */ if (m->version != VDSO_MARK_CUR_VERSION) { pr_err("vdso: Mark version mismatch!\n"); diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 5f442e4a2..186cbae40 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -255,7 +255,7 @@ static int restore_creds(struct thread_creds_args *args, int procfd) /* * Fourth -- trim bset. This can only be done while - * having the CAP_SETPCAP capablity. + * having the CAP_SETPCAP capability. */ for (b = 0; b < CR_CAP_SIZE; b++) { @@ -995,7 +995,7 @@ static int timerfd_arm(struct task_restore_args *args) t->val.it_value.tv_sec += (time_t)ts.tv_sec; - pr_debug("Ajust id %#x it_value(%llu, %llu) -> it_value(%llu, %llu)\n", + pr_debug("Adjust id %#x it_value(%llu, %llu) -> it_value(%llu, %llu)\n", t->id, (unsigned long long)ts.tv_sec, (unsigned long long)ts.tv_nsec, (unsigned long long)t->val.it_value.tv_sec, @@ -1499,7 +1499,7 @@ long __export_restore_task(struct task_restore_args *args) /* * New kernel interface with @PR_SET_MM_MAP will become * more widespread once kernel get deployed over the world. - * Thus lets be opportunistic and use new inteface as a try. + * Thus lets be opportunistic and use new interface as a try. */ prctl_map = (struct prctl_mm_map) { .start_code = args->mm.mm_start_code, @@ -1719,7 +1719,7 @@ long __export_restore_task(struct task_restore_args *args) std_log_set_fd(-1); /* - * The code that prepared the itimers makes shure the + * The code that prepared the itimers makes sure that the * code below doesn't fail due to bad timing values. */ diff --git a/criu/seize.c b/criu/seize.c index d47d4bfc1..b958d4bf9 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -192,7 +192,7 @@ static int seize_cgroup_tree(char *root_path, const char *state) /* * A freezer cgroup can contain tasks which will not be dumped - * and we need to wait them, because the are interupted them by ptrace. + * and we need to wait them, because the are interrupted them by ptrace. */ static int freezer_wait_processes() { diff --git a/criu/sk-queue.c b/criu/sk-queue.c index b5fb6b76c..4ce8ccf45 100644 --- a/criu/sk-queue.c +++ b/criu/sk-queue.c @@ -126,7 +126,7 @@ static int dump_packet_cmsg(struct msghdr *mh, SkPacketEntry *pe) if (n_rights) { /* * Even if user is sending more than one cmsg with - * rights, kernel merges them alltogether on recv. + * rights, kernel merges them altogether on recv. */ pr_err("Unexpected 2nd SCM_RIGHTS from the kernel\n"); return -1; diff --git a/criu/sk-unix.c b/criu/sk-unix.c index c10ca9707..b672ea065 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1586,7 +1586,7 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) * Order binding for sake of ghost sockets. We might rename * existing socket to some temp name, bind ghost, delete it, * and finally move the former back, thus while we're doing - * this stuff we should not be interruped by connection + * this stuff we should not be interrupted by connection * from another sockets. * * FIXME: Probably wort make it per address rather for diff --git a/criu/tty.c b/criu/tty.c index 30e3d7288..214d97a8e 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -546,7 +546,7 @@ static int do_open_tty_reg(int ns_root_fd, struct reg_file_info *rfi, void *arg) fd = do_open_reg_noseek_flags(ns_root_fd, rfi, arg); if (fd >= 0) { /* - * Peers might have differend modes set + * Peers might have different modes set * after creation before we've dumped * them. So simply setup mode from image * the regular file engine will check @@ -883,7 +883,7 @@ static int restore_tty_params(int fd, struct tty_info *info) /* * When we restore queued data we don't exit if error happened: - * the terminals never was a transport with guaranted delivery, + * the terminals never was a transport with guaranteed delivery, * it's up to application which uses it to guaratee the data * integrity. */ @@ -2208,7 +2208,7 @@ static void tty_dinfo_free(struct tty_dump_info *dinfo) * checkpoint procedure -- it's tail optimization, we trying * to defer this procedure until everything else passed * successfully because in real it is time consuming on - * its own which might require writting data back to the + * its own which might require writing data back to the * former peers if case something go wrong. * * Moreover when we gather PTYs peers into own list we diff --git a/criu/tun.c b/criu/tun.c index 1e5cba7c4..11e82f22a 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -120,7 +120,7 @@ static int list_tun_link(NetDeviceEntry *nde) strlcpy(tl->name, nde->name, sizeof(tl->name)); /* * Keep tun-flags not only for persistency fixup (see - * commend below), but also for TUNSETIFF -- we must + * comment below), but also for TUNSETIFF -- we must * open the device with the same flags it should live * with (i.e. -- with which it was created. */ diff --git a/criu/uffd.c b/criu/uffd.c index 2fe56b3ce..384889105 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -61,7 +61,7 @@ /* * Backround transfer parameters. - * The default xfer length is arbitraty set to 64Kbytes + * The default xfer length is arbitrary set to 64Kbytes * The limit of 4Mbytes matches the maximal chunk size we can have in * a pipe in the page-server */ @@ -494,7 +494,7 @@ static int copy_iovs(struct lazy_pages_info *src, struct lazy_pages_info *dst) goto free_iovs; /* - * The IOVs aready in flight for the parent process need to be + * The IOVs already in flight for the parent process need to be * transferred again for the child process */ merge_iov_lists(&dst->reqs, &dst->iovs); @@ -989,9 +989,9 @@ static struct lazy_iov *pick_next_range(struct lazy_pages_info *lpi) } /* - * This is very simple heurstics for backgroud transfer control. + * This is very simple heurstics for background transfer control. * The idea is to transfer larger chunks when there is no page faults - * and drop the backgroud transfer size each time #PF occurs to some + * and drop the background transfer size each time #PF occurs to some * default value. The default is empirically set to 64Kbytes */ static void update_xfer_len(struct lazy_pages_info *lpi, bool pf) @@ -1340,7 +1340,7 @@ static int lazy_sk_read_event(struct epoll_rfd *rfd) ret = recv(rfd->fd, &fin, sizeof(fin), 0); /* * epoll sets POLLIN | POLLHUP for the EOF case, so we get short - * read just befor hangup_event + * read just before hangup_event */ if (!ret) return 0; diff --git a/test/exhaustive/pipe.py b/test/exhaustive/pipe.py index 4e94cab93..47c052efa 100755 --- a/test/exhaustive/pipe.py +++ b/test/exhaustive/pipe.py @@ -13,8 +13,8 @@ criu_bin='../../criu/criu' def mix(nr_tasks, nr_pipes): # Returned is the list of combinations. # Each combination is the lists of pipe descriptors. - # Each pipe descriptor is a 2-elemtn tuple, that contains values - # for R and W ends of pipes, each being a bit-field denoting in + # Each pipe descriptor is a 2-elemtn tuple, that contains values + # for R and W ends of pipes, each being a bit-field denoting in # which tasks the respective end should be opened or not. # First -- make a full set of combinations for a single pipe. @@ -240,7 +240,7 @@ def run(comb, opts): # Kick the test to check its state s.sendto(res, '\0CRIUPCSK') except: - # Restore might have failed or smth else happenned + # Restore might have failed or smth else happened os.kill(pid, signal.SIGKILL) s.close() diff --git a/test/exhaustive/unix.py b/test/exhaustive/unix.py index 727aa0a7a..b3f40620e 100755 --- a/test/exhaustive/unix.py +++ b/test/exhaustive/unix.py @@ -194,7 +194,7 @@ class sock: self.sk_type = sock_type # Sockets that haven't yet been accept()-ed are in the # state, but user cannot operate on them. Also this - # invisibility contributes to state descriptionm since + # invisibility contributes to state description since # connection to not accepted socket is not the same # as connection to accepted one. self.visible = True @@ -240,7 +240,7 @@ class sock: def get_send_action(self, to, st): # However, if peer has a message from us at # the queue tail, sending a new one doesn't - # really make sence + # really make sense want_msg = True if len(to.inqueue) != 0: lmsg = to.inqueue[-1] @@ -412,8 +412,8 @@ class state: # Generates textual description of a state. Different states # may have same descriptions, e.g. if we have two sockets and - # only one of them is in listen state, we don't care which - # one in which. At the same time really different states + # only one of them is in listen state, we don't care which + # one in which. At the same time really different states # shouldn't map to the same string. def describe(self): sks = map(lambda x: x.describe(self), self.sockets) @@ -457,7 +457,7 @@ fail_desc = { } def chk_real_state(st): - # Befor enything else -- check that we still have + # Before enything else -- check that we still have # all the sockets at hands for sk in st.sockets: if not sk.visible: @@ -567,7 +567,7 @@ def chk_real_state(st): print 'FAIL: Connectivity %d -> %d lost' % \ (sk.sk_id, sk.peer) return CHK_FAIL_CONNECT - + # If sockets are not connected the recv above # would generate exception and the check would # fail. But just in case we've screwed the queues @@ -594,7 +594,7 @@ def chk_state(st, opts): # pid!=0 branch, but for simplicity we fork the kid which has the # same set of sockets we do, then dump it. Then restore and notify # via dgram socket to check its state. Current task still has all - # the same sockets :) so we close them not to produce bind() name + # the same sockets :) so we close them not to produce bind() name # conflicts on restore pid = os.fork() @@ -730,7 +730,7 @@ p.add_argument("--keep", help = "Don't stop on error", action = 'store_true') opts = p.parse_args() opts.depth = int(opts.depth) -# XXX: does it make any sence to mix two types in one go? +# XXX: does it make any sense to mix two types in one go? if opts.stream and opts.dgram: print 'Choose only one type' sys.exit(1) diff --git a/test/zdtm/static/aio01.c b/test/zdtm/static/aio01.c index f84fd359f..fda7572a1 100644 --- a/test/zdtm/static/aio01.c +++ b/test/zdtm/static/aio01.c @@ -91,7 +91,7 @@ int main(int argc, char **argv) test_msg("tail=%u, head=%u, nr=%u\n", tail[1], head[1], nr[1]); if (tail[0] != tail[1] || head[0] != head[1] || nr[0] != nr[1]) { - fail("missmatch"); + fail("mismatch"); return 1; } diff --git a/test/zdtm/static/binfmt_misc.c b/test/zdtm/static/binfmt_misc.c index 316c4b667..fec7e0353 100644 --- a/test/zdtm/static/binfmt_misc.c +++ b/test/zdtm/static/binfmt_misc.c @@ -20,7 +20,7 @@ const char *test_author = "Kirill Tkhai $tname/${name}_magic fi -if [ -e $tname/${name}_extention ]; then - echo -1 > $tname/${name}_extention +if [ -e $tname/${name}_extension ]; then + echo -1 > $tname/${name}_extension fi set -e diff --git a/test/zdtm/static/cgroup_stray.c b/test/zdtm/static/cgroup_stray.c index 16db9ba54..8532f84da 100644 --- a/test/zdtm/static/cgroup_stray.c +++ b/test/zdtm/static/cgroup_stray.c @@ -94,7 +94,7 @@ static bool pid_in_cgroup(pid_t pid, const char *controller, const char *path) { /* chop off trailing \n */ buf[strlen(buf)-1] = '\0'; - /* skip heirarchy no. */ + /* skip hierarchy no. */ pos = strstr(buf, ":"); if (!pos) { pr_err("invalid /proc/pid/cgroups file"); diff --git a/test/zdtm/static/cgroupns.c b/test/zdtm/static/cgroupns.c index 7bb0b1fda..7459af138 100644 --- a/test/zdtm/static/cgroupns.c +++ b/test/zdtm/static/cgroupns.c @@ -92,7 +92,7 @@ static bool pid_in_cgroup(pid_t pid, const char *controller, const char *path) { /* chop off trailing \n */ buf[strlen(buf)-1] = '\0'; - /* skip heirarchy no. */ + /* skip hierarchy no. */ pos = strstr(buf, ":"); if (!pos) { pr_err("invalid /proc/pid/cgroups file"); diff --git a/test/zdtm/static/different_creds.c b/test/zdtm/static/different_creds.c index 59fd1fa7f..44a87c43d 100644 --- a/test/zdtm/static/different_creds.c +++ b/test/zdtm/static/different_creds.c @@ -117,7 +117,7 @@ int main(int argc, char ** argv) } /* - * Wait for child to signal us that it has droped caps. + * Wait for child to signal us that it has dropped caps. */ if (read(pipefd[1], &c, 1) != 1) { pr_perror("read"); diff --git a/test/zdtm/static/futex-rl.c b/test/zdtm/static/futex-rl.c index 9a3181a2c..678e175e3 100644 --- a/test/zdtm/static/futex-rl.c +++ b/test/zdtm/static/futex-rl.c @@ -84,7 +84,7 @@ int main(int argc, char **argv) task_waiter_init(&args->waiter); args->result = 0; - test_msg("Createing thread\n"); + test_msg("Creating thread\n"); if (pthread_create(&thread, NULL, thread_fn, (void *)args)) { fail("Can't create thread\n"); exit(1); diff --git a/test/zdtm/static/maps00.c b/test/zdtm/static/maps00.c index aa3c29e6a..a6c68cd25 100644 --- a/test/zdtm/static/maps00.c +++ b/test/zdtm/static/maps00.c @@ -31,7 +31,7 @@ int check_prot(int src_prot, int dst_prot) { if (RW_PROT(src_prot) != RW_PROT(dst_prot)) return 0; - /* If exec bit will be enabled may depend on NX capablity of CPUs of + /* If exec bit will be enabled may depend on NX capability of CPUs of * source and destination nodes. In any case, migrated mapping should * not have less permissions than newly created one ** diff --git a/test/zdtm/static/mount_paths.c b/test/zdtm/static/mount_paths.c index ee05adb46..2377e9c94 100644 --- a/test/zdtm/static/mount_paths.c +++ b/test/zdtm/static/mount_paths.c @@ -8,7 +8,7 @@ #include "zdtmtst.h" -const char *test_doc = "Check that special charecters in paths are handled correctly"; +const char *test_doc = "Check that special characters in paths are handled correctly"; const char *test_author = "Andrew Vagin "; char *dirname; diff --git a/test/zdtm/static/session01.c b/test/zdtm/static/session01.c index 7e6dee255..20c0d51cb 100644 --- a/test/zdtm/static/session01.c +++ b/test/zdtm/static/session01.c @@ -252,7 +252,7 @@ int main(int argc, char ** argv) if (ret < 0) goto err; futex_set(&testcases[i].futex, 0); - test_msg("The process %d initilized\n", ret); + test_msg("The process %d initialized\n", ret); } test_daemon(); diff --git a/test/zdtm/static/vdso-proxy.c b/test/zdtm/static/vdso-proxy.c index eadd9af8b..2381127b7 100644 --- a/test/zdtm/static/vdso-proxy.c +++ b/test/zdtm/static/vdso-proxy.c @@ -118,7 +118,7 @@ int main(int argc, char *argv[]) test_msg("[NOTE]\tMappings before:\n"); nr_before = parse_maps(vmas_before); if (nr_before < 0) { - pr_perror("Faied to parse maps"); + pr_perror("Failed to parse maps"); return -1; } @@ -128,7 +128,7 @@ int main(int argc, char *argv[]) test_msg("[NOTE]\tMappings after:\n"); nr_after = parse_maps(vmas_after); if (nr_after < 0) { - pr_perror("Faied to parse maps"); + pr_perror("Failed to parse maps"); return -1; } diff --git a/test/zdtm/static/vdso01.c b/test/zdtm/static/vdso01.c index f571a87a8..be733663c 100644 --- a/test/zdtm/static/vdso01.c +++ b/test/zdtm/static/vdso01.c @@ -422,7 +422,7 @@ int main(int argc, char *argv[]) test_init(argc, argv); if (vdso_fill_self_symtable(&symtable)) { - pr_perror("Faied to parse vdso"); + pr_perror("Failed to parse vdso"); return -1; } diff --git a/test/zdtm/static/vsx.c b/test/zdtm/static/vsx.c index 33151cab7..be02cfe10 100644 --- a/test/zdtm/static/vsx.c +++ b/test/zdtm/static/vsx.c @@ -23,7 +23,7 @@ int main(int argc, char *argv[]) #include /* - * This test verifies that data stored in the VSX regsiters are still there + * This test verifies that data stored in the VSX registers are still there * once the restart is done. * * The test is filling the registers with dedicated values and then check diff --git a/test/zdtm/transition/maps008.c b/test/zdtm/transition/maps008.c index a89309d2f..5f6eb0887 100644 --- a/test/zdtm/transition/maps008.c +++ b/test/zdtm/transition/maps008.c @@ -18,7 +18,7 @@ const char *test_doc = "ps tree with anon shared vmas for dedup"; /* * 1. ps tree with non triavial anon shmem vmas is created first. * 2. Each process gets its portion of shmem vmas. - * 3. Each process continiously datagens its portion until + * 3. Each process continuously datagens its portion until * criu dump is finished. * 4. Each process datachecks all its shmem portions after restore. * 5. Contents of anon shmem vmas are checked for equality in diff --git a/test/zdtm/transition/netlink00.c b/test/zdtm/transition/netlink00.c index e69d579ba..c9b2303e8 100644 --- a/test/zdtm/transition/netlink00.c +++ b/test/zdtm/transition/netlink00.c @@ -86,7 +86,7 @@ int main(int argc, char *argv[]) pr_perror("bind failed"); goto out; } - //Preperation: + //Preparation: form_request_del(); send_request(); recv_reply(); From fb7611e6eb133f45c201ab51817b1e5ebfa6221d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 27 Mar 2018 12:58:15 +0300 Subject: [PATCH 1732/4375] sk-unix: Use unsigned values for inodes It is especially important when accessing a hash -- there must be no negative indices ever. https://jira.sw.ru/browse/PSBM-82945 Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index b672ea065..2091cad2f 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -117,7 +117,7 @@ struct unix_sk_listen_icon { static struct unix_sk_listen_icon *unix_listen_icons[SK_HASH_SIZE]; -static struct unix_sk_listen_icon *lookup_unix_listen_icons(int peer_ino) +static struct unix_sk_listen_icon *lookup_unix_listen_icons(unsigned int peer_ino) { struct unix_sk_listen_icon *ic; @@ -717,8 +717,8 @@ static int unix_collect_one(const struct unix_diag_msg *m, } if (tb[UNIX_DIAG_ICONS]) { - int len = nla_len(tb[UNIX_DIAG_ICONS]); - int i; + unsigned int len = nla_len(tb[UNIX_DIAG_ICONS]); + unsigned int i; d->icons = xmalloc(len); if (!d->icons) @@ -733,7 +733,7 @@ static int unix_collect_one(const struct unix_diag_msg *m, */ for (i = 0; i < d->nr_icons; i++) { struct unix_sk_listen_icon *e, **chain; - int n; + unsigned int n; e = xzalloc(sizeof(*e)); if (!e) From 2e7ef4f7b989cb3fa7e9e7ece8df6d937b4ca141 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 27 Aug 2018 15:22:39 +0100 Subject: [PATCH 1733/4375] mount: Reduce size of mkey in ext_mount_lookup Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/mount.c b/criu/mount.c index c83c1824a..d95e60334 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -94,7 +94,7 @@ static char *ext_mount_lookup(char *key) { char *v; int len = strlen(key); - char mkey[len + 8]; + char mkey[len + 6]; sprintf(mkey, "mnt[%s]", key); v = external_lookup_by_key(mkey); From d40c702dd86fca4f7e06e6365b799c9dfa03eec5 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 27 Aug 2018 14:28:56 +0100 Subject: [PATCH 1734/4375] zdtm: Call criu.available() only for `run` action When zdtm.py is executed with `list` sub-command the 'criu_bin' option is not defined and criu.available() fails. $ python test/zdtm.py list Traceback (most recent call last): File "test/zdtm.py", line 2243, in criu.available() File "test/zdtm.py", line 1185, in available if not os.access(opts['criu_bin'], os.X_OK): KeyError: u'criu_bin' However, we don't need to check the existence of criu_bin unless we use the `run` action. Signed-off-by: Radostin Stoyanov Acked-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/zdtm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 7b80f536d..23884166e 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -2213,7 +2213,8 @@ if opts.get('sat', False): if opts['debug']: sys.settrace(traceit) -criu.available() +if opts['action'] == 'run': + criu.available() for tst in test_classes.values(): tst.available() From 2b76b3246f31e7364e974e5a728661f461b5bb5f Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 23 Aug 2018 14:09:49 +0300 Subject: [PATCH 1735/4375] restore: avoid an unterminated string >>> CID 164715: (BUFFER_SIZE_WARNING) >>> Calling strncpy with a maximum size argument of 16 bytes on destination array "thread_args[i].comm" of size 16 bytes might leave the destination string unterminated. 3473 strncpy(thread_args[i].comm, core->tc->comm, TASK_COMM_LEN); Signed-off-by: Andrei Vagin Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 6221c4b45..5a1551a8b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3462,9 +3462,10 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns goto err; if (tcore->thread_core->comm) - strncpy(thread_args[i].comm, tcore->thread_core->comm, TASK_COMM_LEN); + strncpy(thread_args[i].comm, tcore->thread_core->comm, TASK_COMM_LEN - 1); else - strncpy(thread_args[i].comm, core->tc->comm, TASK_COMM_LEN); + strncpy(thread_args[i].comm, core->tc->comm, TASK_COMM_LEN - 1); + thread_args[i].comm[TASK_COMM_LEN - 1] = 0; if (thread_args[i].pid != pid) core_entry__free_unpacked(tcore, NULL); From eb8dc67f3f3a5e301330466e323aaf27a27d3cd1 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 29 Aug 2018 15:23:00 +0300 Subject: [PATCH 1736/4375] travis: exclude the code coverage job It fails too often and nobody knows how to fix it. Signed-off-by: Andrei Vagin --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2d6fc31ec..7e47b5a9e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,6 @@ env: - TR_ARCH=docker-test - TR_ARCH=fedora-rawhide - TR_ARCH=fedora-rawhide-aarch64 - - TR_ARCH=local GCOV=1 - TR_ARCH=centos matrix: allow_failures: From 43285af929382058baca6c0add6514e809e7cfb7 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 23 Aug 2018 18:18:09 +0300 Subject: [PATCH 1737/4375] criu: parasite_prepare_threads: free memory on error path Fixes cov 191305 Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/parasite-syscall.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 10504edff..b9788a4c2 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -477,7 +477,7 @@ static int parasite_prepare_threads(struct parasite_ctl *ctl, thread_sp = xzalloc(sizeof(*thread_sp) * item->nr_threads); if (!thread_sp) - return -1; + goto free_ctls; for (i = 0; i < item->nr_threads; i++) { struct pid *tid = &item->threads[i]; @@ -489,7 +489,7 @@ static int parasite_prepare_threads(struct parasite_ctl *ctl, thread_ctls[i] = compel_prepare_thread(ctl, tid->real); if (!thread_ctls[i]) - return -1; + goto free_sp; thread_sp[i] = compel_get_thread_sp(thread_ctls[i]); } @@ -498,6 +498,12 @@ static int parasite_prepare_threads(struct parasite_ctl *ctl, dmpi(item)->thread_sp = thread_sp; return 0; + +free_sp: + xfree(thread_sp); +free_ctls: + xfree(thread_ctls); + return -1; } struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, From 3023f4f1c8aee087f1a2fb4361cf77cda658a6e4 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 30 Aug 2018 14:13:54 +0100 Subject: [PATCH 1738/4375] util: Fix reversed IPv4/IPv6 port assignment Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/util.c b/criu/util.c index 16b1c7511..ad4be0e0b 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1299,9 +1299,9 @@ int setup_tcp_server(char *type) } if (saddr.ss_family == AF_INET6) { - opts.port = ntohs(((struct sockaddr_in *)&saddr)->sin_port); - } else if (saddr.ss_family == AF_INET) { opts.port = ntohs(((struct sockaddr_in6 *)&saddr)->sin6_port); + } else if (saddr.ss_family == AF_INET) { + opts.port = ntohs(((struct sockaddr_in *)&saddr)->sin_port); } pr_info("Using %u port\n", opts.port); From 69f8594362c6989f56ccddceb816ae72f69b7b7d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 31 Aug 2018 13:17:12 +0300 Subject: [PATCH 1739/4375] image: core -- Reserve tty fields Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- images/core.proto | 3 +++ 1 file changed, 3 insertions(+) diff --git a/images/core.proto b/images/core.proto index ce25b0971..312a983f0 100644 --- a/images/core.proto +++ b/images/core.proto @@ -48,6 +48,9 @@ message task_core_entry { optional int32 oom_score_adj = 14; repeated sa_entry sigactions = 15; + // Reserved for tty inheritance + //optional int32 tty_nr = 16; + //optional int32 tty_pgrp = 17; } message task_kobj_ids_entry { From 3ce615caefa47d1a753ca657ec5a0afcc2ae8997 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 31 Aug 2018 13:17:13 +0300 Subject: [PATCH 1740/4375] image: sk-packet -- Reserve fields To handle message addresses and ucreds. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- images/sk-packet.proto | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/images/sk-packet.proto b/images/sk-packet.proto index dcda280f6..e15dd382a 100644 --- a/images/sk-packet.proto +++ b/images/sk-packet.proto @@ -8,5 +8,9 @@ message scm_entry { message sk_packet_entry { required uint32 id_for = 1; required uint32 length = 2; + // Reserved for message address + // optional bytes addr = 3; repeated scm_entry scm = 4; + // Reserved for ucred restore + // optional sk_ucred_entry ucred = 128; } From ae758dc716fe27589a9f85aa599d0c63a866fadb Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 29 Aug 2018 12:24:41 +0100 Subject: [PATCH 1741/4375] config: Remove -c -f -F and -p options The -c and -f options were introduced on December 2011 with commit 485c4b50d137174c8fc66ec3a7761b4f7c4e9f8c show: Rework show procedure Added - ability to parse every single file crtools understands via magic number - dumped memory pages can be rendered in two modes -- as a simple set of pages' virtual addresses or in hexdummp fashion (via -c command line key). For example ./crtools -s -c -f pages-2557.img CR_FD_PAGES: pages-2557.img ---------------------------------------- 7fffb44ace20: 00 00 00 00 00 00 00 00 00 00 00 74 65 73 74 2f |. . . . . . . . . . . t e s t / | 7fffb44ace30: 74 65 73 74 2d 73 69 67 61 63 74 69 6f 6e 00 48 |t e s t - s i g a c t i o n . H | 7fffb44ace40: 4f 53 54 4e 41 4d 45 3d 6c 6f 63 61 6c 68 6f 73 |O S T N A M E = l o c a l h o s | 7fffb44ace50: 74 2e 6c 6f 63 61 6c 64 6f 6d 61 69 6e 00 54 45 |t . l o c a l d o m a i n . T E | The -p/--pid option was added on April 2013 with commit 73d7e283a7bd55872e569735d4055e06fe886689 show: Filter -D output with --pid option Show only image info relevant to given pid. Also reuse the introduced --pid argument for exec action. And the -F option was introduced on December 2013 with commit 7ab8a3261b5b6f2404155a397dd3950fb7a67c8f show: Implement simple images filtering The -F|--fields option specifies which fields (by name, comma separated) should be printed. For nested fields all names in path should be specified. All four options were used in combination with the deprecated --show command which has been decommissioned on February 2016 with commit a501b4804b3c95e1d83d64dd10ed95c37f0378bb show: Remove deprecated code The 'show' action has been deprecated since 1.6, let's finally drop it. The print_data() routine is kept for yet another (to be deprecated too) feature called 'criu exec'. Signed-off-by: Radostin Stoyanov Acked-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/config.c | 10 +--------- criu/include/cr_options.h | 1 - 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/criu/config.c b/criu/config.c index b1fd8d1a4..98b9e036f 100644 --- a/criu/config.c +++ b/criu/config.c @@ -418,19 +418,14 @@ int parse_options(int argc, char **argv, bool *usage_error, {OPT_NAME, no_argument, SAVE_TO, true},\ {"no-" OPT_NAME, no_argument, SAVE_TO, false} - static const char short_opts[] = "dSsRf:F:t:p:hcD:o:v::x::Vr:jJ:lW:L:M:"; + static const char short_opts[] = "dSsR:t:hD:o:v::x::Vr:jJ:lW:L:M:"; static struct option long_opts[] = { { "tree", required_argument, 0, 't' }, - /* The pid option is unused and never evaluated. */ - { "pid", required_argument, 0, 'p' }, { "leave-stopped", no_argument, 0, 's' }, { "leave-running", no_argument, 0, 'R' }, BOOL_OPT("restore-detached", &opts.restore_detach), BOOL_OPT("restore-sibling", &opts.restore_sibling), BOOL_OPT("daemon", &opts.restore_detach), - { "contents", no_argument, 0, 'c' }, - { "file", required_argument, 0, 'f' }, - { "fields", required_argument, 0, 'F' }, { "images-dir", required_argument, 0, 'D' }, { "work-dir", required_argument, 0, 'W' }, { "log-file", required_argument, 0, 'o' }, @@ -566,9 +561,6 @@ int parse_options(int argc, char **argv, bool *usage_error, if (opts.tree_id <= 0) goto bad_arg; break; - case 'c': - opts.show_pages_content = true; - break; case 'r': SET_CHAR_OPTS(root, optarg); break; diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index 68281e8d5..6b8a40e71 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -67,7 +67,6 @@ struct cr_options { int final_state; int check_extra_features; int check_experimental_features; - bool show_pages_content; union { int restore_detach; bool daemon_mode; From ab63f168ac83af3b36eee496f662f03170778ae2 Mon Sep 17 00:00:00 2001 From: "Kondo, Uchio" Date: Mon, 10 Sep 2018 21:53:36 +0300 Subject: [PATCH 1742/4375] mount: Add a detailed error message when opts.root is NULL Signed-off-by: Andrei Vagin --- criu/mount.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/criu/mount.c b/criu/mount.c index d95e60334..9161a0f78 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2476,6 +2476,11 @@ static int do_mount_one(struct mount_info *mi) pr_debug("\tMounting %s @%s (%d)\n", mi->fstype->name, mi->mountpoint, mi->need_plugin); if (rst_mnt_is_root(mi)) { + if (opts.root == NULL) { + pr_err("The --root option is required to restore a mount namespace\n"); + return -1; + } + /* do_mount_root() is called from populate_mnt_ns() */ if (mount(opts.root, mi->mountpoint, NULL, MS_BIND | MS_REC, NULL)) return -1; From b4ab1d8cbab1ee72134f03667fc0a92c7730c0f5 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 6 Sep 2018 11:27:43 +0200 Subject: [PATCH 1743/4375] RPC: fix wrong log_level handling In RPC mode the log_level was always reset to the default log level of 2, if no configuration file was used. This saves the log level set via RPC in opts.log_level and a configuration file can overwrite it later, but if it is only set via RPC this value is not ignored now. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-service.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/cr-service.c b/criu/cr-service.c index 643aba9cf..d7f12b9c0 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -363,6 +363,8 @@ static int setup_opts_from_req(int sk, CriuOpts *req) SET_CHAR_OPTS(output, DEFAULT_LOG_FILENAME); } + /* This is needed later to correctly set the log_level */ + opts.log_level = req->log_level; log_set_loglevel(req->log_level); if (log_init(opts.output) == -1) { pr_perror("Can't initiate log"); From cf77cfaccc22dcb1aa33e34da18dcbd929f19f42 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 11 Sep 2018 11:09:02 +0300 Subject: [PATCH 1744/4375] log: add line breaks to pr_warn for i in $(find . -name "*.[ch]" -type f); do sed -i 's/\(pr_warn(".*[^n]\)\("[),]\)/\1\\n\2/' $i done Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- compel/src/lib/infect.c | 2 +- criu/cr-restore.c | 2 +- criu/crtools.c | 2 +- criu/files-reg.c | 2 +- criu/namespaces.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 8ff05d6ea..abf3a0ab3 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -137,7 +137,7 @@ int compel_interrupt_task(int pid) */ ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL); if (ret < 0) { - pr_warn("SEIZE %d: can't interrupt task: %s", pid, strerror(errno)); + pr_warn("SEIZE %d: can't interrupt task: %s\n", pid, strerror(errno)); if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) pr_perror("Unable to detach from %d", pid); } diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 5a1551a8b..8ba413d1a 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2289,7 +2289,7 @@ out_kill: kill(root_item->pid->real, SIGKILL); if (waitpid(root_item->pid->real, &status, 0) < 0) - pr_warn("Unable to wait %d: %s", + pr_warn("Unable to wait %d: %s\n", root_item->pid->real, strerror(errno)); } else { struct pstree_item *pi; diff --git a/criu/crtools.c b/criu/crtools.c index 17476d357..1c47ca89e 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -235,7 +235,7 @@ int main(int argc, char *argv[], char *envp[]) opts.restore_detach && opts.final_state == TASK_STOPPED && opts.shell_job) - pr_warn("Stopped and detached shell job will get SIGHUP from OS."); + pr_warn("Stopped and detached shell job will get SIGHUP from OS.\n"); if (chdir(opts.work_dir)) { pr_perror("Can't change directory to %s", opts.work_dir); diff --git a/criu/files-reg.c b/criu/files-reg.c index d6161fef0..211c38b3f 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1355,7 +1355,7 @@ static int linkat_hard(int odir, char *opath, int ndir, char *npath, uid_t uid, if (!( (errno == EPERM || errno == EOVERFLOW) && (root_ns_mask & CLONE_NEWUSER) )) { errno_save = errno; - pr_warn("Can't link %s -> %s", opath, npath); + pr_warn("Can't link %s -> %s\n", opath, npath); errno = errno_save; return ret; } diff --git a/criu/namespaces.c b/criu/namespaces.c index f58f310ad..e8908e8ff 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -52,7 +52,7 @@ int check_namespace_opts(void) return -1; } if (join_ns_flags & CLONE_NEWUSER) - pr_warn("join-ns with user-namespace is not fully tested and dangerous"); + pr_warn("join-ns with user-namespace is not fully tested and dangerous\n"); errno = 0; return 0; From bfe5a85091108dd486b5abcb6ab28d5d96792d41 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 11 Sep 2018 11:09:03 +0300 Subject: [PATCH 1745/4375] mount: remove leading double slash As mnt_roots always has a slash at the beginning we don't need another: (00.156035) 1: mnt: Move the root to //tmp/.criu.mntns.ZKVJHl/15-0000000000 Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 9161a0f78..9d96f2778 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -3359,8 +3359,7 @@ int prepare_mnt_ns(void) } /* Set its root */ - path[0] = '/'; - print_ns_root(nsid, 0, path + 1, sizeof(path) - 1); + print_ns_root(nsid, 0, path, sizeof(path) - 1); if (cr_pivot_root(path)) goto err; From 70dd6eaad5bf95512e827787eb1b305b4c0dc96e Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 11 Sep 2018 11:09:04 +0300 Subject: [PATCH 1746/4375] mount: fix typos in root_path_from_parent colon operators are there obviously by mistake instead of semicolons Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 9d96f2778..bdc39b530 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -834,8 +834,8 @@ static int root_path_from_parent(struct mount_info *m, char *buf, int size) if (!m->parent) return -1; - p_len = strlen(m->parent->mountpoint), - m_len = strlen(m->mountpoint), + p_len = strlen(m->parent->mountpoint); + m_len = strlen(m->mountpoint); len = snprintf(buf, size, "%s", m->parent->root); if (len >= size) From 47bf04d297b319e39507f2ab0bf1592ab4a33bbd Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 11 Sep 2018 11:09:05 +0300 Subject: [PATCH 1747/4375] util: fixup issubpath to handle sub-paths ending with slash Before fix issubpath("./zdtm/static/mntns_shared_vs_private.test", "./") returned false, though should return true. Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/include/util.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/criu/include/util.h b/criu/include/util.h index 5c18e69f7..dd280ec3a 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -206,12 +206,10 @@ int vaddr_to_pfn(int fd, unsigned long vaddr, u64 *pfn); */ static inline bool strstartswith2(const char *str, const char *sub, char *end) { - const char *osub = sub; - while (1) { if (*sub == '\0') /* end of sub -- match */ { if (end) { - if (sub == osub + 1) /* pure root */ + if (*(sub-1) == '/') /* "/", "./" or "path/" */ *end = '/'; else *end = *str; From 8b88b3fc39969c1782c00f1dc601a3cd32a143f1 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 11 Sep 2018 11:09:06 +0300 Subject: [PATCH 1748/4375] files: don't add double slash to path in create_ghost Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 211c38b3f..b81b4da96 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -323,7 +323,13 @@ static int create_ghost(struct ghost_file *gf, GhostFileEntry *gfe, struct cr_im goto err; } - snprintf(path + ret, sizeof(path) - ret, "/%s", gf->remap.rpath); + /* Add a '/' only if we have no at the end */ + if (path[root_len-1] != '/') { + path[root_len++] = '/'; + path[root_len] = '\0'; + } + + snprintf(path + root_len, sizeof(path) - root_len, "%s", gf->remap.rpath); ret = -1; again: if (S_ISFIFO(gfe->mode)) { @@ -358,7 +364,7 @@ again: goto err; } - strcpy(gf->remap.rpath, path + root_len + 1); + strcpy(gf->remap.rpath, path + root_len); pr_debug("Remap rpath is %s\n", gf->remap.rpath); ret = -1; From 327e78f922da804766ac8d6864cf4b9e0d3d8ee7 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Aug 2018 14:00:16 +0300 Subject: [PATCH 1749/4375] x86: cpu -- Save xsave frame sizes in image Keep xsave sizes in image to be sure that on restore the application won't override memory out of xsave frame size if been calling xsave instruction directly. Here are some details: while been testing vz7 containers migration we've noticed that sometime applications do crash after restore, what is worse such execution abort may happen not immediately after the restore but after passing some time. After spending a lot of time we discovered that it is due to the fact that the migration is directed from an old cpu to a modern one which has extensions such as mpx. In result libc has cached small xsave size and then after restore any direct call to xsave instruction overwrite memory which is allocated with size less than needed. Thus we save xsave frame size in image and require it to match to prevent such situation. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmaill.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 33 ++++++++++++++++++++++++++++++--- images/cpuinfo.proto | 2 ++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index 60b3b9e21..fb377215b 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -92,6 +92,10 @@ int cpu_dump_cpuinfo(void) cpu_x86_info.capability = (void *)rt_cpu_info.x86_capability; cpu_x86_info.has_xfeatures_mask = true; cpu_x86_info.xfeatures_mask = rt_cpu_info.xfeatures_mask; + cpu_x86_info.has_xsave_size = true; + cpu_x86_info.xsave_size = rt_cpu_info.xsave_size; + cpu_x86_info.has_xsave_size_max = true; + cpu_x86_info.xsave_size_max = rt_cpu_info.xsave_size_max; if (rt_cpu_info.x86_model_id[0]) cpu_x86_info.model_id = rt_cpu_info.x86_model_id; @@ -259,14 +263,25 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) } /* - * Make sure the xsave features are at least not less - * than current cpu supports. + * Make sure the xsave features are compatible. We already hit the + * issue with libc where we've checkpointed the container on old + * machine but restored on more modern one and libc fetched new + * xsave frame size directly by xsave instruction with greedy + * feature mask causing programs to misbehave. */ - if (cpu_info->xfeatures_mask > rt_cpu_info.xfeatures_mask) { + if (cpu_info->xfeatures_mask != rt_cpu_info.xfeatures_mask) { uint64_t m = cpu_info->xfeatures_mask & ~rt_cpu_info.xfeatures_mask; pr_err("CPU xfeatures has unsupported bits (%#llx)\n", (unsigned long long)m); return -1; + } else if (cpu_info->xsave_size != rt_cpu_info.xsave_size) { + pr_err("CPU xsave size mismatch (%u/%u)\n", + cpu_info->xsave_size, rt_cpu_info.xsave_size); + return -1; + } else if (cpu_info->xsave_size_max != rt_cpu_info.xsave_size_max) { + pr_err("CPU xsave max size mismatch (%u/%u)\n", + cpu_info->xsave_size_max, rt_cpu_info.xsave_size_max); + return -1; } /* @@ -370,6 +385,18 @@ static compel_cpuinfo_t *img_to_cpuinfo(CpuinfoX86Entry *img_x86_entry) } else cpu_info->xfeatures_mask = img_x86_entry->xfeatures_mask; + /* + * Same for other fields. + */ + if (!img_x86_entry->has_xsave_size) + cpu_info->xsave_size = rt_cpu_info.xsave_size; + else + cpu_info->xsave_size = img_x86_entry->xsave_size; + if (!img_x86_entry->has_xsave_size_max) + cpu_info->xsave_size_max = rt_cpu_info.xsave_size_max; + else + cpu_info->xsave_size_max = img_x86_entry->xsave_size_max; + return cpu_info; } diff --git a/images/cpuinfo.proto b/images/cpuinfo.proto index b399503bd..8ee629c2c 100644 --- a/images/cpuinfo.proto +++ b/images/cpuinfo.proto @@ -17,6 +17,8 @@ message cpuinfo_x86_entry { optional string model_id = 7; optional uint64 xfeatures_mask = 8; + optional uint32 xsave_size = 9; + optional uint32 xsave_size_max = 10; } message cpuinfo_ppc64_entry { From 8595dec9ac7daaf0000981a0808dc6c0e27312b9 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Aug 2018 14:00:17 +0300 Subject: [PATCH 1750/4375] x86: cpu -- Make cpu_dump_cpuinfo more readable No func changes. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmaill.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index fb377215b..9751261ab 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -78,24 +78,25 @@ int cpu_dump_cpuinfo(void) if (!img) return -1; - cpu_info.x86_entry = &cpu_x86_info_ptr; - cpu_info.n_x86_entry = 1; + cpu_info.x86_entry = &cpu_x86_info_ptr; + cpu_info.n_x86_entry = 1; - cpu_x86_info.vendor_id = (rt_cpu_info.x86_vendor == X86_VENDOR_INTEL) ? + cpu_x86_info.vendor_id = (rt_cpu_info.x86_vendor == X86_VENDOR_INTEL) ? CPUINFO_X86_ENTRY__VENDOR__INTEL : CPUINFO_X86_ENTRY__VENDOR__AMD; - cpu_x86_info.cpu_family = rt_cpu_info.x86_family; - cpu_x86_info.model = rt_cpu_info.x86_model; - cpu_x86_info.stepping = rt_cpu_info.x86_mask; - cpu_x86_info.capability_ver = 2; - cpu_x86_info.n_capability = ARRAY_SIZE(rt_cpu_info.x86_capability); - cpu_x86_info.capability = (void *)rt_cpu_info.x86_capability; - cpu_x86_info.has_xfeatures_mask = true; - cpu_x86_info.xfeatures_mask = rt_cpu_info.xfeatures_mask; - cpu_x86_info.has_xsave_size = true; - cpu_x86_info.xsave_size = rt_cpu_info.xsave_size; - cpu_x86_info.has_xsave_size_max = true; - cpu_x86_info.xsave_size_max = rt_cpu_info.xsave_size_max; + + cpu_x86_info.cpu_family = rt_cpu_info.x86_family; + cpu_x86_info.model = rt_cpu_info.x86_model; + cpu_x86_info.stepping = rt_cpu_info.x86_mask; + cpu_x86_info.capability_ver = 2; + cpu_x86_info.n_capability = ARRAY_SIZE(rt_cpu_info.x86_capability); + cpu_x86_info.capability = (void *)rt_cpu_info.x86_capability; + cpu_x86_info.has_xfeatures_mask = true; + cpu_x86_info.xfeatures_mask = rt_cpu_info.xfeatures_mask; + cpu_x86_info.has_xsave_size = true; + cpu_x86_info.xsave_size = rt_cpu_info.xsave_size; + cpu_x86_info.has_xsave_size_max = true; + cpu_x86_info.xsave_size_max = rt_cpu_info.xsave_size_max; if (rt_cpu_info.x86_model_id[0]) cpu_x86_info.model_id = rt_cpu_info.x86_model_id; @@ -321,9 +322,9 @@ static compel_cpuinfo_t *img_to_cpuinfo(CpuinfoX86Entry *img_x86_entry) if (img_x86_entry->vendor_id != CPUINFO_X86_ENTRY__VENDOR__INTEL && img_x86_entry->vendor_id != CPUINFO_X86_ENTRY__VENDOR__AMD) { - pr_err("Image carries unknown vendor %u\n", - (unsigned)img_x86_entry->vendor_id); - return NULL; + pr_err("Image carries unknown vendor %u\n", + (unsigned)img_x86_entry->vendor_id); + return NULL; } for (i = 0; i < ARRAY_SIZE(ncapints); i++) { From cfc1d5644e8a2a2da9737a9e944361aa3aaf053c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Aug 2018 14:00:18 +0300 Subject: [PATCH 1751/4375] x86: cpu -- Use bitwise operator for option check Usually people simply leave cpu checkin in default mode (which is fpu level) but idea was to be able to compose a mixture of settings, for this sake CPU_CAP_ constants are bit shifts. Thus use bitwise operator for this. Same time define CPU_CAP_ as bit shifts explicitly and use explicit CPU_CAP_NONE compare where needed. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmaill.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 6 +++--- criu/include/cr_options.h | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index 9751261ab..c59f9d63f 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -236,7 +236,7 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) if (cpu_has_unsupported_features()) return -1; - if (opts.cpu_cap == CPU_CAP_FPU) { + if (opts.cpu_cap & CPU_CAP_FPU) { /* * If we're requested to check FPU only ignore * any other bit. It's up to a user if the @@ -288,7 +288,7 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) /* * Capability on instructions level only. */ - if (opts.cpu_cap == CPU_CAP_INS) + if (opts.cpu_cap & CPU_CAP_INS) return cpu_validate_ins_features(cpu_info); /* @@ -458,7 +458,7 @@ int cpuinfo_check(void) * still allow to check instructions only * and etc. */ - if (!opts.cpu_cap) + if (opts.cpu_cap == CPU_CAP_NONE) opts.cpu_cap = CPU_CAP_ALL; if (cpu_validate_cpuinfo()) diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index 6b8a40e71..9b726355c 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -24,11 +24,11 @@ /* * CPU capability options. */ -#define CPU_CAP_NONE (0u) -#define CPU_CAP_ALL (-1u) -#define CPU_CAP_FPU (1u) /* Only FPU capability required */ -#define CPU_CAP_CPU (2u) /* Strict CPU capability required */ -#define CPU_CAP_INS (4u) /* Instructions CPU capability */ +#define CPU_CAP_NONE (0u << 0) /* Don't check capability at all */ +#define CPU_CAP_FPU (1u << 0) /* Only FPU capability required */ +#define CPU_CAP_CPU (1u << 1) /* Strict CPU capability required */ +#define CPU_CAP_INS (1u << 2) /* Instructions CPU capability */ +#define CPU_CAP_ALL (CPU_CAP_FPU | CPU_CAP_CPU | CPU_CAP_INS) #define CPU_CAP_DEFAULT (CPU_CAP_FPU) struct cg_root_opt { From ddd373f490febc5a147082540c7a956339084d1e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Aug 2018 14:00:19 +0300 Subject: [PATCH 1752/4375] x86: cpu -- Move xsave testing into fpu capability block xsave sizes should sit in fpu capability block because instruction and strick mode checkig is a different thing. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmaill.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index c59f9d63f..6ffe97131 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -261,28 +261,28 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) } else return 0; #undef __mismatch_fpu_bit - } - /* - * Make sure the xsave features are compatible. We already hit the - * issue with libc where we've checkpointed the container on old - * machine but restored on more modern one and libc fetched new - * xsave frame size directly by xsave instruction with greedy - * feature mask causing programs to misbehave. - */ - if (cpu_info->xfeatures_mask != rt_cpu_info.xfeatures_mask) { - uint64_t m = cpu_info->xfeatures_mask & ~rt_cpu_info.xfeatures_mask; - pr_err("CPU xfeatures has unsupported bits (%#llx)\n", - (unsigned long long)m); - return -1; - } else if (cpu_info->xsave_size != rt_cpu_info.xsave_size) { - pr_err("CPU xsave size mismatch (%u/%u)\n", - cpu_info->xsave_size, rt_cpu_info.xsave_size); - return -1; - } else if (cpu_info->xsave_size_max != rt_cpu_info.xsave_size_max) { - pr_err("CPU xsave max size mismatch (%u/%u)\n", - cpu_info->xsave_size_max, rt_cpu_info.xsave_size_max); - return -1; + /* + * Make sure the xsave features are compatible. We already hit the + * issue with libc where we've checkpointed the container on old + * machine but restored on more modern one and libc fetched new + * xsave frame size directly by xsave instruction with greedy + * feature mask causing programs to misbehave. + */ + if (cpu_info->xfeatures_mask > rt_cpu_info.xfeatures_mask) { + uint64_t m = cpu_info->xfeatures_mask & ~rt_cpu_info.xfeatures_mask; + pr_err("CPU xfeatures has unsupported bits (%#llx)\n", + (unsigned long long)m); + return -1; + } else if (cpu_info->xsave_size != rt_cpu_info.xsave_size) { + pr_err("CPU xsave size mismatch (%u/%u)\n", + cpu_info->xsave_size, rt_cpu_info.xsave_size); + return -1; + } else if (cpu_info->xsave_size_max != rt_cpu_info.xsave_size_max) { + pr_err("CPU xsave max size mismatch (%u/%u)\n", + cpu_info->xsave_size_max, rt_cpu_info.xsave_size_max); + return -1; + } } /* From ee478bed970117c276aeecb28c80857eea9b6eca Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Aug 2018 14:00:20 +0300 Subject: [PATCH 1753/4375] x86: cpu -- Move strict capability mode into own block It should be there from the beginning but happen to escape. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmaill.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index 6ffe97131..1945a3dc3 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -294,10 +294,12 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) /* * Strict capability mode. Everything must match. */ - if (memcmp(cpu_info->x86_capability, rt_cpu_info.x86_capability, - sizeof(cpu_info->x86_capability))) { - pr_err("CPU capabilities do not match run time\n"); - return -1; + if (opts.cpu_cap & CPU_CAP_CPU) { + if (memcmp(cpu_info->x86_capability, rt_cpu_info.x86_capability, + sizeof(cpu_info->x86_capability))) { + pr_err("CPU capabilites do not match run time\n"); + return -1; + } } return 0; From f2bf496571a6a3fe11e83dc31c784d0733ce2052 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Aug 2018 14:00:21 +0300 Subject: [PATCH 1754/4375] x86: cpu -- Use special bit for image manipulation Current scheme of when to write and verify cpuinfo images is unclear: we define default mode to 'fpu' and this implies that no cpuinfo image get written on dump and read on restore. In turn if 'cpu' or 'ins' mode specified in command line we write and verify this image. This is all wrong -- we need to produce image if any mode ecxept 'none' is specified. The 'none' mode is designed exactly for skipping cpuinfo image production or verification. Because any non-default mode requires explicit --cpu-cap option to be passed we can use this and setup new CPU_CAP_IMAGE telling criu to write or read this image. Note the default mode doesn't break backward compatibility because by default we don't write or read the image at all. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmaill.com> Signed-off-by: Andrei Vagin --- criu/config.c | 4 ++++ criu/cr-dump.c | 2 +- criu/cr-restore.c | 2 +- criu/cr-service.c | 4 +++- criu/include/cr_options.h | 1 + 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/criu/config.c b/criu/config.c index 98b9e036f..089a70038 100644 --- a/criu/config.c +++ b/criu/config.c @@ -289,6 +289,7 @@ static int parse_cpu_cap(struct cr_options *opts, const char *optarg) if (!optarg) { ____cpu_set_cap(opts, CPU_CAP_ALL, false); + ____cpu_set_cap(opts, CPU_CAP_IMAGE, false); return 0; } @@ -324,6 +325,9 @@ static int parse_cpu_cap(struct cr_options *opts, const char *optarg) } else goto Esyntax; } + + if (opts->cpu_cap != CPU_CAP_NONE) + ____cpu_set_cap(opts, CPU_CAP_IMAGE, false); #undef ____cpu_set_cap return 0; diff --git a/criu/cr-dump.c b/criu/cr-dump.c index a9e16a683..22472d80b 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1791,7 +1791,7 @@ int cr_dump_tasks(pid_t pid) if (prepare_inventory(&he)) goto err; - if (opts.cpu_cap & (CPU_CAP_CPU | CPU_CAP_INS)) { + if (opts.cpu_cap & CPU_CAP_IMAGE) { if (cpu_dump_cpuinfo()) goto err; } diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 8ba413d1a..5037da2fb 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2364,7 +2364,7 @@ int cr_restore_tasks(void) if (vdso_init_restore()) goto err; - if (opts.cpu_cap & (CPU_CAP_INS | CPU_CAP_CPU)) { + if (opts.cpu_cap & CPU_CAP_IMAGE) { if (cpu_validate_cpuinfo()) goto err; } diff --git a/criu/cr-service.c b/criu/cr-service.c index d7f12b9c0..8b06f3bb8 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -511,8 +511,10 @@ static int setup_opts_from_req(int sk, CriuOpts *req) goto err; } - if (req->has_cpu_cap) + if (req->has_cpu_cap) { opts.cpu_cap = req->cpu_cap; + opts.cpu_cap |= CPU_CAP_IMAGE; + } /* * FIXME: For backward compatibility we setup diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index 9b726355c..25cba3951 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -28,6 +28,7 @@ #define CPU_CAP_FPU (1u << 0) /* Only FPU capability required */ #define CPU_CAP_CPU (1u << 1) /* Strict CPU capability required */ #define CPU_CAP_INS (1u << 2) /* Instructions CPU capability */ +#define CPU_CAP_IMAGE (1u << 3) /* Write capability on dump and read on restore*/ #define CPU_CAP_ALL (CPU_CAP_FPU | CPU_CAP_CPU | CPU_CAP_INS) #define CPU_CAP_DEFAULT (CPU_CAP_FPU) From 5b574fffc6b3d541cc7e25025ee375cd1ebc141d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Aug 2018 14:00:22 +0300 Subject: [PATCH 1755/4375] x86: cpu -- Update default cpu-cap option To preserve backward compatibility because strict mode now lays under own block. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmaill.com> Signed-off-by: Andrei Vagin --- criu/include/cr_options.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index 25cba3951..92a2d364d 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -30,7 +30,7 @@ #define CPU_CAP_INS (1u << 2) /* Instructions CPU capability */ #define CPU_CAP_IMAGE (1u << 3) /* Write capability on dump and read on restore*/ #define CPU_CAP_ALL (CPU_CAP_FPU | CPU_CAP_CPU | CPU_CAP_INS) -#define CPU_CAP_DEFAULT (CPU_CAP_FPU) +#define CPU_CAP_DEFAULT (CPU_CAP_FPU | CPU_CAP_CPU) struct cg_root_opt { struct list_head node; From cdd8643d640bd9d175b0a7e2a68ade13269b7872 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Aug 2018 14:00:23 +0300 Subject: [PATCH 1756/4375] x86: cpu -- Add more detailed mode description Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmaill.com> Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 6bb3f0f5d..4fc623b20 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -312,9 +312,17 @@ For example, the command line for the above example should look like this: *--cpu-cap* ['cap'[,'cap'...]]:: Specify CPU capabilities to write to an image file. The argument is a - comma-separated list of *none*, *fpu*, *cpu*, *ins*, *all*. If the - argument is omitted or set to *none*, capabilities will not be written, - which is the default behavior. + comma-separated list of: ++ + - *none* to ignore capabilities at all; the image will not be produced + on dump, neither any check performed on restore; + - *fpu* to check if FPU module is compatible; + - *ins* to check if CPU supports all instructions required; + - *cpu* to check if CPU capabilities are exactly matching; + - *all* for all above set. + ++ +By default the option is set to the combination of *fpu* and *cpu*. *--cgroup-root* ['controller':]/'newroot':: Change the root for the controller that will be dumped. By default, *criu* From 5d4e6bd63684196e566aab5cb7fda7576283711c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Aug 2018 14:00:24 +0300 Subject: [PATCH 1757/4375] x86: cpu -- Drop no longer needed early exit from cpu_validate_features Since now validation is bit based there is no longer need to exit early if fpu matches, we rather need over all possible options where several capability modes can be set. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmaill.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index 1945a3dc3..a3f173b31 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -258,8 +258,7 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) __mismatch_fpu_bit(X86_FEATURE_OSXSAVE), __mismatch_fpu_bit(X86_FEATURE_XSAVES)); return -1; - } else - return 0; + } #undef __mismatch_fpu_bit /* From fbb67af9fd17c8b3e8f1599dab4b4b05e83bcd22 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Aug 2018 14:00:25 +0300 Subject: [PATCH 1758/4375] x86: cpu -- Don't exit early if --cpu-cap=ins specified Since we're using bintmaps for options don't exit early if --cpu-cap=ins specified because there might be a combination of options. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index a3f173b31..ce62cb7cf 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -287,8 +287,10 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) /* * Capability on instructions level only. */ - if (opts.cpu_cap & CPU_CAP_INS) - return cpu_validate_ins_features(cpu_info); + if (opts.cpu_cap & CPU_CAP_INS) { + if (cpu_validate_ins_features(cpu_info)) + return -1; + } /* * Strict capability mode. Everything must match. From 51b4ca964e4cdc08887e578cdc2e4d177fa1b19f Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Aug 2018 14:00:26 +0300 Subject: [PATCH 1759/4375] x86: cpu -- Use native uint_x types Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index ce62cb7cf..eac701dce 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -7,7 +7,6 @@ #include #include "bitops.h" -#include "asm/types.h" #include "asm/cpu.h" #include #include @@ -112,7 +111,7 @@ int cpu_dump_cpuinfo(void) #define __ins_bit(__l, __v) (1u << ((__v) - 32u * (__l))) -static u32 x86_ins_capability_mask[NCAPINTS] = { +static uint32_t x86_ins_capability_mask[NCAPINTS] = { [CPUID_1_EDX] = __ins_bit(CPUID_1_EDX, X86_FEATURE_FPU) | __ins_bit(CPUID_1_EDX, X86_FEATURE_TSC) | @@ -215,8 +214,8 @@ static int cpu_validate_ins_features(compel_cpuinfo_t *cpu_info) size_t i; for (i = 0; i < ARRAY_SIZE(cpu_info->x86_capability); i++) { - u32 s = cpu_info->x86_capability[i] & x86_ins_capability_mask[i]; - u32 d = rt_cpu_info.x86_capability[i] & x86_ins_capability_mask[i]; + uint32_t s = cpu_info->x86_capability[i] & x86_ins_capability_mask[i]; + uint32_t d = rt_cpu_info.x86_capability[i] & x86_ins_capability_mask[i]; /* * Destination might be more feature rich From b44eaddb2957ce51db41e2b846df4e44c90b1ade Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 30 Aug 2018 14:00:27 +0300 Subject: [PATCH 1760/4375] x86: cpu -- Require compatibility on instruction level by default For a long time we've been demanding from cpus to be compatible on fpu frame level, but growing list of cpu features triggers inability for restored programs to proceed after restore due to specific intructions execution (such as avx2). Note the fpu frame may carry same size but not on instruction level where SIGILL may happen after the restore. Thus lets require instruction mode to be set and verified by default. Still one can drop this option via command line or rpc request. Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 2 +- criu/include/cr_options.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 4fc623b20..003d748ce 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -322,7 +322,7 @@ For example, the command line for the above example should look like this: - *all* for all above set. + -By default the option is set to the combination of *fpu* and *cpu*. +By default the option is set to *fpu* and *ins*. *--cgroup-root* ['controller':]/'newroot':: Change the root for the controller that will be dumped. By default, *criu* diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index 92a2d364d..c722e3ae2 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -30,7 +30,7 @@ #define CPU_CAP_INS (1u << 2) /* Instructions CPU capability */ #define CPU_CAP_IMAGE (1u << 3) /* Write capability on dump and read on restore*/ #define CPU_CAP_ALL (CPU_CAP_FPU | CPU_CAP_CPU | CPU_CAP_INS) -#define CPU_CAP_DEFAULT (CPU_CAP_FPU | CPU_CAP_CPU) +#define CPU_CAP_DEFAULT (CPU_CAP_FPU | CPU_CAP_INS) struct cg_root_opt { struct list_head node; From 4ce3fc0b9800044f219fb1bdbb1fbaacc61d9a2e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 14 Sep 2018 02:13:36 +0300 Subject: [PATCH 1761/4375] jenkins/criu-lazy-migration: clean old files Otherwise files from a previous build can affect the current one. Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin --- test/jenkins/criu-lazy-migration.pipeline | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jenkins/criu-lazy-migration.pipeline b/test/jenkins/criu-lazy-migration.pipeline index 7d655513c..2c863f170 100644 --- a/test/jenkins/criu-lazy-migration.pipeline +++ b/test/jenkins/criu-lazy-migration.pipeline @@ -13,6 +13,7 @@ pipeline { stages { stage('Build') { steps { + sh 'git clean -dxf' sh 'make' sh 'make -C test/zdtm' } From 4e212cebb6143da224f70f0e754c89b28d0b047f Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 19 Sep 2018 14:50:27 +0300 Subject: [PATCH 1762/4375] test: static/mnt_ext_auto -- Check if unshare successed Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/mnt_ext_auto.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/mnt_ext_auto.c b/test/zdtm/static/mnt_ext_auto.c index 947ea00cb..9181b370a 100644 --- a/test/zdtm/static/mnt_ext_auto.c +++ b/test/zdtm/static/mnt_ext_auto.c @@ -66,7 +66,10 @@ int main(int argc, char ** argv) } mkdir(src, 755); - unshare(CLONE_NEWNS); + if (unshare(CLONE_NEWNS)) { + pr_perror("unshare"); + return 1; + } mkdir(dst, 755); if (mount(src, dst, NULL, MS_BIND, NULL)) { pr_perror("bind"); From 76669e307be5016332afe996fc1bea11e959c5a6 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 19 Sep 2018 14:50:28 +0300 Subject: [PATCH 1763/4375] test: static/mnt_ext_master -- Check if unshare successed Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/mnt_ext_master.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/mnt_ext_master.c b/test/zdtm/static/mnt_ext_master.c index f2c8e38d4..12e9ebab1 100644 --- a/test/zdtm/static/mnt_ext_master.c +++ b/test/zdtm/static/mnt_ext_master.c @@ -43,7 +43,10 @@ int main(int argc, char ** argv) mkdir(src, 755); mkdir(dst, 755); - unshare(CLONE_NEWNS); + if (unshare(CLONE_NEWNS)) { + pr_perror("unshare"); + return 1; + } if (mount(src, dst, NULL, MS_BIND, NULL)) { pr_perror("bind"); From caca7c1ad276d2d68f6502c7157f93f14d940782 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 19 Sep 2018 14:50:29 +0300 Subject: [PATCH 1764/4375] test: static/mntns_root_bind -- Check if unshare successed Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/mntns_root_bind.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/mntns_root_bind.c b/test/zdtm/static/mntns_root_bind.c index 978143ec2..86c44e197 100644 --- a/test/zdtm/static/mntns_root_bind.c +++ b/test/zdtm/static/mntns_root_bind.c @@ -64,7 +64,10 @@ int main(int argc, char **argv) return 1; } if (pid == 0) { - unshare(CLONE_NEWNS); + if (unshare(CLONE_NEWNS)) { + pr_perror("unshare"); + return 1; + } if (mount(path, bpath, NULL, MS_BIND, NULL)) { pr_perror("mount"); return 1; From 9121d8b78ca30f790f871ee59621a63e0882cf82 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 19 Sep 2018 14:50:30 +0300 Subject: [PATCH 1765/4375] test: static/mntns_shared_bind -- Check if unshare successed Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/mntns_shared_bind.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/mntns_shared_bind.c b/test/zdtm/static/mntns_shared_bind.c index ef48bd8a2..b0d63af58 100644 --- a/test/zdtm/static/mntns_shared_bind.c +++ b/test/zdtm/static/mntns_shared_bind.c @@ -70,7 +70,10 @@ int main(int argc, char **argv) return 1; } if (pid == 0) { - unshare(CLONE_NEWNS); + if (unshare(CLONE_NEWNS)) { + pr_perror("unshare"); + return 1; + } if (mount(path, bpath, NULL, MS_BIND, NULL)) { pr_perror("mount"); return 1; From 15e66624720908a4ad03231507eb71cd55716ae1 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 19 Sep 2018 14:50:31 +0300 Subject: [PATCH 1766/4375] test: static/netns_sub -- Check if unshare successed Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/netns_sub.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/zdtm/static/netns_sub.c b/test/zdtm/static/netns_sub.c index 8428bca74..6515057d8 100644 --- a/test/zdtm/static/netns_sub.c +++ b/test/zdtm/static/netns_sub.c @@ -100,7 +100,10 @@ int main(int argc, char **argv) } if (pid1 == 0) { close(sk); - unshare(CLONE_NEWNET); + if (unshare(CLONE_NEWNET)) { + pr_perror("unshare"); + return 1; + } sk = create_socket(1); if (sk < 0) return 1; @@ -159,7 +162,10 @@ int main(int argc, char **argv) return -1; } if (pid2 == 0) { - unshare(CLONE_NEWNET); + if (unshare(CLONE_NEWNET)) { + pr_perror("unshare"); + return 1; + } sk = create_socket(2); if (sk < 0) return 1; From dbdd19fa1bc1b7c28c68b5aa3e67dca7bc407a49 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 19 Sep 2018 14:50:32 +0300 Subject: [PATCH 1767/4375] test: static/sk-unix-mntns -- Check if unshare successed Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/sk-unix-mntns.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/sk-unix-mntns.c b/test/zdtm/static/sk-unix-mntns.c index 84e65ee13..58f63797a 100644 --- a/test/zdtm/static/sk-unix-mntns.c +++ b/test/zdtm/static/sk-unix-mntns.c @@ -53,7 +53,10 @@ int main(int argc, char *argv[]) } if (pid == 0) { - unshare(CLONE_NEWNS); + if (unshare(CLONE_NEWNS)) { + pr_perror("unshare"); + return 1; + } if (mount(NULL, "/", NULL, MS_PRIVATE | MS_REC, NULL)) { pr_perror("mount"); return 1; From 1efdb547e24ddef17400bea44e1642a550dae8d5 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 19 Sep 2018 14:50:33 +0300 Subject: [PATCH 1768/4375] test: static/socket-tcp -- Check if unshare successed Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/socket-tcp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/socket-tcp.c b/test/zdtm/static/socket-tcp.c index 6b30fc42d..1db5a4dd6 100644 --- a/test/zdtm/static/socket-tcp.c +++ b/test/zdtm/static/socket-tcp.c @@ -68,7 +68,10 @@ int main(int argc, char **argv) socklen_t optlen; #ifdef ZDTM_CONNTRACK - unshare(CLONE_NEWNET); + if (unshare(CLONE_NEWNET)) { + pr_perror("unshare"); + return 1; + } if (system("ip link set up dev lo")) return 1; if (system("iptables -w -A INPUT -i lo -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT")) From 33dd782c1d57853d0dbb4498b15ebb03230294a4 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 19 Sep 2018 14:50:34 +0300 Subject: [PATCH 1769/4375] test: static/tun -- Check if unshare successed Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/tun.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/tun.c b/test/zdtm/static/tun.c index 98519e5d2..c38ac4836 100644 --- a/test/zdtm/static/tun.c +++ b/test/zdtm/static/tun.c @@ -120,7 +120,10 @@ int main(int argc, char **argv) test_init(argc, argv); #ifdef TUN_NS - unshare(CLONE_NEWNET); + if (unshare(CLONE_NEWNET)) { + pr_perror("unshare"); + return 1; + } system("ip link set up dev lo"); #endif /* fd[0] -- opened file */ From 6b8852cfcbd0d8cc7cfcfd0c0116708c9370c3a7 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 19 Sep 2018 14:50:35 +0300 Subject: [PATCH 1770/4375] test: static/socket-tcp -- Check for iptables success Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/socket-tcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/socket-tcp.c b/test/zdtm/static/socket-tcp.c index 1db5a4dd6..18eb3792c 100644 --- a/test/zdtm/static/socket-tcp.c +++ b/test/zdtm/static/socket-tcp.c @@ -76,7 +76,8 @@ int main(int argc, char **argv) return 1; if (system("iptables -w -A INPUT -i lo -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT")) return 1; - system("iptables -A INPUT -j DROP"); + if (system("iptables -A INPUT -j DROP")) + return 1; #endif #ifdef ZDTM_TCP_LOCAL From 19d3da0d9b0e38dffc5453febfb3c72a524dbe1d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 19 Sep 2018 14:50:36 +0300 Subject: [PATCH 1771/4375] test: static/tun -- More detailed errors and code shrink Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/tun.c | 59 +++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/test/zdtm/static/tun.c b/test/zdtm/static/tun.c index c38ac4836..f6bfeb91b 100644 --- a/test/zdtm/static/tun.c +++ b/test/zdtm/static/tun.c @@ -32,33 +32,28 @@ static int __open_tun(void) fd = open(TUN_DEVICE, O_RDWR); if (fd < 0) - pr_perror("Can't open tun file"); + pr_perror("Can't open tun file %s", TUN_DEVICE); return fd; } -static int set_tun_queue(int fd, unsigned flags) +static int set_tun_queue(int fd, const char *name, unsigned flags) { - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = flags; + struct ifreq ifr = { .ifr_flags = flags, }; if (ioctl(fd, TUNSETQUEUE, &ifr) < 0) { - pr_perror("Can't set queue"); + pr_perror("Can't set queue on %s", name); return -1; } return 0; } -static int __attach_tun(int fd, char *name, unsigned flags) +static int __attach_tun(int fd, const char *name, unsigned flags) { - struct ifreq ifr; + struct ifreq ifr = { .ifr_flags = flags, }; - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, name); - ifr.ifr_flags = flags; + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)-1); if (ioctl(fd, TUNSETIFF, &ifr) < 0) { if (!(flags & IFF_TUN_EXCL)) @@ -69,7 +64,7 @@ static int __attach_tun(int fd, char *name, unsigned flags) return fd; } -static int open_tun(char *name, unsigned flags) +static int open_tun(const char *name, unsigned flags) { int fd; @@ -80,9 +75,9 @@ static int open_tun(char *name, unsigned flags) return __attach_tun(fd, name, flags); } -static void check_tun(int fd, char *name, unsigned flags) +static void check_tun(int fd, const char *name, unsigned flags) { - struct ifreq ifr; + struct ifreq ifr = { }; if (ioctl(fd, TUNGETIFF, &ifr) > 0) { any_fail = 1; @@ -100,12 +95,12 @@ static void check_tun(int fd, char *name, unsigned flags) } } -static int dev_get_hwaddr(int fd, char *a) +static int dev_get_hwaddr(int fd, const char *name, char *a) { - struct ifreq ifr; + struct ifreq ifr = { }; if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { - pr_perror("Can't get hwaddr"); + pr_perror("Can't get hwaddr on %s", name); return -1; } @@ -130,55 +125,55 @@ int main(int argc, char **argv) fds[0] = __open_tun(); if (fds[0] < 0) { pr_perror("No file 0"); - return -1; + return 1; } /* fd[1] -- opened file with tun device */ fds[1] = open_tun("tunx0", IFF_TUN); if (fds[1] < 0) { pr_perror("No file 1"); - return -1; + return 1; } /* fd[2] and [3] -- two-queued device, with 3 detached */ fds[2] = open_tun("tunx1", IFF_TUN | IFF_MULTI_QUEUE); if (fds[2] < 0) { pr_perror("No file 2"); - return -1; + return 1; } fds[3] = open_tun("tunx1", IFF_TUN | IFF_MULTI_QUEUE); if (fds[3] < 0) { pr_perror("No file 3"); - return -1; + return 1; } - ret = set_tun_queue(fds[3], IFF_DETACH_QUEUE); + ret = set_tun_queue(fds[3], "tunx1", IFF_DETACH_QUEUE); if (ret < 0) - return -1; + return 1; /* special case -- persistent device */ ret = open_tun("tunx2", IFF_TUN); if (ret < 0) { pr_perror("No persistent device"); - return -1; + return 1; } if (ioctl(ret, TUNSETPERSIST, 1) < 0) { pr_perror("Can't make persistent"); - return -1; + return 1; } /* and one tap in fd[4] */ fds[4] = open_tun("tapx0", IFF_TAP); if (fds[4] < 0) { pr_perror("No tap"); - return -1; + return 1; } - if (dev_get_hwaddr(fds[4], addr) < 0) { + if (dev_get_hwaddr(fds[4], "tapx0", addr) < 0) { pr_perror("No hwaddr for tap?"); - return -1; + return 1; } close(ret); @@ -200,13 +195,13 @@ int main(int argc, char **argv) check_tun(fds[2], "tunx1", IFF_TUN | IFF_MULTI_QUEUE); check_tun(fds[3], "tunx1", IFF_TUN | IFF_MULTI_QUEUE); - ret = set_tun_queue(fds[2], IFF_DETACH_QUEUE); + ret = set_tun_queue(fds[2], "tunx1", IFF_DETACH_QUEUE); if (ret < 0) { any_fail = 1; fail("Queue not attached"); } - ret = set_tun_queue(fds[3], IFF_ATTACH_QUEUE); + ret = set_tun_queue(fds[3], "tunx1", IFF_ATTACH_QUEUE); if (ret < 0) { any_fail = 1; fail("Queue not detached"); @@ -226,7 +221,7 @@ int main(int argc, char **argv) } check_tun(fds[4], "tapx0", IFF_TAP); - if (dev_get_hwaddr(fds[4], a2) < 0) { + if (dev_get_hwaddr(fds[4], "tapx0", a2) < 0) { pr_perror("No hwaddr for tap? (2)"); any_fail = 1; } else if (memcmp(addr, a2, sizeof(addr))) { From 9c40efdd19b7ab2600161c5b947a68c33dcafe6e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 13 Sep 2018 02:41:11 +0300 Subject: [PATCH 1772/4375] service-fd: close a source file descriptor in install_service_fd() Currently, install_service_fd() always creates a new file descriptor, but it is going to be reworked to reuse a file descriptor when it is possible. Reviewed-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/action-scripts.c | 2 +- criu/cgroup.c | 1 - criu/cr-dump.c | 2 -- criu/cr-restore.c | 1 - criu/fdstore.c | 1 - criu/files.c | 5 +---- criu/image.c | 3 ++- criu/log.c | 1 - criu/mount.c | 1 - criu/namespaces.c | 2 -- criu/net.c | 1 - criu/util.c | 6 +++--- 12 files changed, 7 insertions(+), 19 deletions(-) diff --git a/criu/action-scripts.c b/criu/action-scripts.c index d382547cd..2803ec0f7 100644 --- a/criu/action-scripts.c +++ b/criu/action-scripts.c @@ -164,7 +164,7 @@ int add_rpc_notify(int sk) BUG_ON(scripts_mode == SCRIPTS_SHELL); scripts_mode = SCRIPTS_RPC; - if (install_service_fd(RPC_SK_OFF, sk) < 0) + if (install_service_fd(RPC_SK_OFF, dup(sk)) < 0) return -1; return 0; diff --git a/criu/cgroup.c b/criu/cgroup.c index 868196a99..26f159c74 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -1671,7 +1671,6 @@ static int prepare_cgroup_sfd(CgroupEntry *ce) } ret = install_service_fd(CGROUP_YARD, i); - close(i); if (ret < 0) goto err; diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 22472d80b..713653fcb 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1297,8 +1297,6 @@ static int dump_one_task(struct pstree_item *item, InventoryEntry *parent_ie) if (install_service_fd(CR_PROC_FD_OFF, pfd) < 0) goto err_cure_imgset; - - close(pfd); } ret = parasite_fixup_vdso(parasite_ctl, pid, &vmas); diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 5037da2fb..4ac664c6e 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2051,7 +2051,6 @@ static int restore_root_task(struct pstree_item *init) } ret = install_service_fd(CR_PROC_FD_OFF, fd); - close(fd); if (ret < 0) return -1; diff --git a/criu/fdstore.c b/criu/fdstore.c index 88a5a9a15..a4583fdf4 100644 --- a/criu/fdstore.c +++ b/criu/fdstore.c @@ -78,7 +78,6 @@ int fdstore_init(void) } ret = install_service_fd(FDSTORE_SK_OFF, sk); - close(sk); if (ret < 0) return -1; diff --git a/criu/files.c b/criu/files.c index e59388f28..81ee7004f 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1764,11 +1764,8 @@ int open_transport_socket(void) goto out; } - if (install_service_fd(TRANSPORT_FD_OFF, sock) < 0) { - close(sock); + if (install_service_fd(TRANSPORT_FD_OFF, sock) < 0) goto out; - } - close(sock); ret = 0; out: return ret; diff --git a/criu/image.c b/criu/image.c index 3564a8a41..a10c20aa5 100644 --- a/criu/image.c +++ b/criu/image.c @@ -472,7 +472,8 @@ int open_image_dir(char *dir) } ret = install_service_fd(IMG_FD_OFF, fd); - close(fd); + if (ret < 0) + return -1; fd = ret; if (opts.img_parent) { diff --git a/criu/log.c b/criu/log.c index 9e7703542..2f5b28a62 100644 --- a/criu/log.c +++ b/criu/log.c @@ -183,7 +183,6 @@ int log_init(const char *output) } fd = install_service_fd(LOG_FD_OFF, new_logfd); - close(new_logfd); if (fd < 0) goto err; diff --git a/criu/mount.c b/criu/mount.c index bdc39b530..218facb76 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -3398,7 +3398,6 @@ static int mntns_set_root_fd(pid_t pid, int fd) ret = install_service_fd(ROOT_FD_OFF, fd); if (ret >= 0) mntns_root_pid = pid; - close(fd); return ret; } diff --git a/criu/namespaces.c b/criu/namespaces.c index e8908e8ff..24cd61e2b 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -1427,11 +1427,9 @@ static int start_usernsd(void) if (install_service_fd(USERNSD_SK, sk[0]) < 0) { kill(usernsd_pid, SIGKILL); waitpid(usernsd_pid, NULL, 0); - close(sk[0]); return -1; } - close(sk[0]); return 0; } diff --git a/criu/net.c b/criu/net.c index 0431b62f9..40bf47b32 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2549,7 +2549,6 @@ int netns_keep_nsfd(void) pr_err("Can't install ns net reference\n"); else pr_info("Saved netns fd for links restore\n"); - close(ns_fd); return ret >= 0 ? 0 : -1; } diff --git a/criu/util.c b/criu/util.c index ad4be0e0b..66a6d4aae 100644 --- a/criu/util.c +++ b/criu/util.c @@ -314,7 +314,6 @@ static inline int set_proc_pid_fd(int pid, int fd) open_proc_pid = pid; ret = install_service_fd(PROC_PID_FD_OFF, fd); - close(fd); return ret; } @@ -348,7 +347,7 @@ void close_proc() int set_proc_fd(int fd) { - if (install_service_fd(PROC_FD_OFF, fd) < 0) + if (install_service_fd(PROC_FD_OFF, dup(fd)) < 0) return -1; return 0; } @@ -365,7 +364,6 @@ static int open_proc_sfd(char *path) } ret = install_service_fd(PROC_FD_OFF, fd); - close(fd); if (ret < 0) return -1; @@ -502,10 +500,12 @@ int install_service_fd(enum sfd_type type, int fd) if (dup3(fd, sfd, O_CLOEXEC) != sfd) { pr_perror("Dup %d -> %d failed", fd, sfd); + close(fd); return -1; } set_bit(type, sfd_map); + close(fd); return sfd; } From 04f505f62e4e9f55f1c532aa728d13269154ad3d Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 13 Sep 2018 02:41:12 +0300 Subject: [PATCH 1773/4375] check: don't close file descriptors in check_user_ns Do someone remember why we are doing this? Reviewed-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/namespaces.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/criu/namespaces.c b/criu/namespaces.c index 24cd61e2b..96cc2f0e5 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -857,7 +857,6 @@ static int check_user_ns(int pid) struct __user_cap_header_struct hdr; uid_t uid; gid_t gid; - int i; uid = host_uid(0); gid = host_gid(0); @@ -900,10 +899,6 @@ static int check_user_ns(int pid) return -1; } - close_old_fds(); - for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) - close_service_fd(i); - /* * Check that we are able to enter into other namespaces * from the target userns namespace. This signs that these From d3499999676dd5397cc6ec6bcfb8cf217108e975 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 13 Sep 2018 02:41:13 +0300 Subject: [PATCH 1774/4375] criu: remove all magic of service-fd when it isn't required Service descriptors are a set of file descriptors which isn't intercepted with restored file descriptors. In all cases, when we don't need to restore file descriptors, we can skip all magic of service-fd and just save descriptor numbers in a static array. Reviewed-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/util.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/criu/util.c b/criu/util.c index 66a6d4aae..2bae71ea8 100644 --- a/criu/util.c +++ b/criu/util.c @@ -454,8 +454,6 @@ int init_service_fd(void) } service_fd_rlim_cur = (int)rlimit.rlim_cur; - service_fd_base = service_fd_rlim_cur; - BUG_ON(service_fd_base < SERVICE_FD_MAX); return 0; } @@ -476,6 +474,7 @@ int service_fd_min_fd(struct pstree_item *item) } static DECLARE_BITMAP(sfd_map, SERVICE_FD_MAX); +static int sfd_arr[SERVICE_FD_MAX]; /* * Variable for marking areas of code, where service fds modifications * are prohibited. It's used to safe them from reusing their numbers @@ -498,6 +497,12 @@ int install_service_fd(enum sfd_type type, int fd) if (sfds_protected && !test_bit(type, sfd_map)) sfds_protection_bug(type); + if (service_fd_base == 0) { + sfd_arr[type] = fd; + set_bit(type, sfd_map); + return fd; + } + if (dup3(fd, sfd, O_CLOEXEC) != sfd) { pr_perror("Dup %d -> %d failed", fd, sfd); close(fd); @@ -516,6 +521,9 @@ int get_service_fd(enum sfd_type type) if (!test_bit(type, sfd_map)) return -1; + if (service_fd_base == 0) + return sfd_arr[type]; + return __get_service_fd(type, service_fd_id); } From a148e87469a36dc75e263259e39ed30336343fc8 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 13 Sep 2018 02:41:14 +0300 Subject: [PATCH 1775/4375] criu: set RLIMIT_NOFILE to maximum only on restore Reviewed-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 32 ++++++++++++++++++++++++++++++++ criu/crtools.c | 32 -------------------------------- criu/files.c | 3 ++- 3 files changed, 34 insertions(+), 33 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 4ac664c6e..3e1dc6d4b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2339,10 +2339,42 @@ int prepare_dummy_task_state(struct pstree_item *pi) return 0; } +static void rlimit_unlimit_nofile_self(void) +{ + struct rlimit new; + + new.rlim_cur = kdat.sysctl_nr_open; + new.rlim_max = kdat.sysctl_nr_open; + + if (prlimit(getpid(), RLIMIT_NOFILE, &new, NULL)) { + pr_perror("rlimir: Can't setup RLIMIT_NOFILE for self"); + return; + } else + pr_debug("rlimit: RLIMIT_NOFILE unlimited for self\n"); + service_fd_rlim_cur = kdat.sysctl_nr_open; +} + int cr_restore_tasks(void) { int ret = -1; + /* + * Service fd engine implies that file descriptors + * used won't be borrowed by the rest of the code + * and default 1024 limit is not enough for high + * loaded test/containers. Thus use kdat engine + * to fetch current system level limit for numbers + * of files allowed to open up and lift up own + * limits. + * + * Note we have to do it before the service fd + * get inited and we dont exit with errors here + * because in worst scenario where clash of fd + * happen we simply exit with explicit error + * during real action stage. + */ + rlimit_unlimit_nofile_self(); + if (cr_plugin_init(CR_PLUGIN_STAGE__RESTORE)) return -1; diff --git a/criu/crtools.c b/criu/crtools.c index 1c47ca89e..a452caebd 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -52,40 +52,8 @@ #include "setproctitle.h" #include "sysctl.h" -static void rlimit_unlimit_nofile_self(void) -{ - struct rlimit new; - - new.rlim_cur = kdat.sysctl_nr_open; - new.rlim_max = kdat.sysctl_nr_open; - - if (prlimit(getpid(), RLIMIT_NOFILE, &new, NULL)) { - pr_perror("rlimir: Can't setup RLIMIT_NOFILE for self"); - return; - } else - pr_debug("rlimit: RLIMIT_NOFILE unlimited for self\n"); -} - static int early_init(void) { - /* - * Service fd engine implies that file descritprs - * used won't be borrowed by the rest of the code - * and default 1024 limit is not enough for high - * loaded test/containers. Thus use kdat engine - * to fetch current system level limit for numbers - * of files allowed to open up and lift up own - * limits. - * - * Note we have to do it before the service fd - * get inited and we don't exit with errors here - * because in worst scenario where clash of fd - * happen we simply exit with explicit error - * during real action stage. - */ - if (!kerndat_files_stat(true)) - rlimit_unlimit_nofile_self(); - if (init_service_fd()) return 1; diff --git a/criu/files.c b/criu/files.c index 81ee7004f..115390f63 100644 --- a/criu/files.c +++ b/criu/files.c @@ -44,6 +44,7 @@ #include "autofs.h" #include "parasite.h" #include "parasite-syscall.h" +#include "kerndat.h" #include "protobuf.h" #include "util.h" @@ -898,7 +899,7 @@ int prepare_fd_pid(struct pstree_item *item) if (ret <= 0) break; - if (e->fd >= service_fd_min_fd(item)) { + if (e->fd >= kdat.sysctl_nr_open) { ret = -1; pr_err("Too big FD number to restore %d\n", e->fd); break; From 9388b78df1af01e529f524a75dd308ce845e3922 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 13 Sep 2018 02:41:15 +0300 Subject: [PATCH 1776/4375] criu: call kerndat_init() after log_init() We don't have rights to print anything into standard descriptors and we want to have all output in a specified log file. Reviewed-by: Kirill Tkhai Signed-off-by: Andrei Vagin --- criu/cr-service.c | 3 +++ criu/crtools.c | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 8b06f3bb8..dbeb1a881 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -371,6 +371,9 @@ static int setup_opts_from_req(int sk, CriuOpts *req) goto err; } + if (kerndat_init()) + return 1; + if (log_keep_err()) { pr_perror("Can't tune log"); goto err; diff --git a/criu/crtools.c b/criu/crtools.c index a452caebd..c9f0a195d 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -57,9 +57,6 @@ static int early_init(void) if (init_service_fd()) return 1; - if (kerndat_init()) - return 1; - return 0; } @@ -213,6 +210,9 @@ int main(int argc, char *argv[], char *envp[]) if (log_init(opts.output)) return 1; + if (kerndat_init()) + return 1; + if (opts.deprecated_ok) pr_debug("DEPRECATED ON\n"); From 29738509e4ccdd2feffae22f84333f1afa15bc8f Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 13 Sep 2018 18:28:05 +0100 Subject: [PATCH 1777/4375] remote: Refactor TCP server setup The function `setup_TCP_server_socket` (defined in img-remote.c) and `setup_tcp_server` (defined in util.c) have very similar functionality. Replace setup_TCP_server_socket() with setup_tcp_server() to reduce code duplication and to enable IPv6 support for the image-cache action of CRIU. We set SO_REUSEADDR flag to allow reuse of local addresses. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/include/util.h | 2 +- criu/page-xfer.c | 2 +- criu/util.c | 30 +++++++++++++++++++----------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/criu/include/util.h b/criu/include/util.h index dd280ec3a..af9b6c537 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -289,7 +289,7 @@ char *xsprintf(const char *fmt, ...) void print_data(unsigned long addr, unsigned char *data, size_t size); -int setup_tcp_server(char *type); +int setup_tcp_server(char *type, char *addr, unsigned short *port); int run_tcp_server(bool daemon_mode, int *ask, int cfd, int sk); int setup_tcp_client(char *addr); diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 81a7dfd4a..e5806124c 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -991,7 +991,7 @@ int cr_page_server(bool daemon_mode, bool lazy_dump, int cfd) goto no_server; } - sk = setup_tcp_server("page"); + sk = setup_tcp_server("page", opts.addr, &opts.port); if (sk == -1) return -1; no_server: diff --git a/criu/util.c b/criu/util.c index 2bae71ea8..872623072 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1245,7 +1245,8 @@ void print_data(unsigned long addr, unsigned char *data, size_t size) } } -static int get_sockaddr_in(struct sockaddr_storage *addr, char *host) +static int get_sockaddr_in(struct sockaddr_storage *addr, char *host, + unsigned short port) { memset(addr, 0, sizeof(*addr)); @@ -1262,25 +1263,26 @@ static int get_sockaddr_in(struct sockaddr_storage *addr, char *host) } if (addr->ss_family == AF_INET6) { - ((struct sockaddr_in6 *)addr)->sin6_port = htons(opts.port); + ((struct sockaddr_in6 *)addr)->sin6_port = htons(port); } else if (addr->ss_family == AF_INET) { - ((struct sockaddr_in *)addr)->sin_port = htons(opts.port); + ((struct sockaddr_in *)addr)->sin_port = htons(port); } return 0; } -int setup_tcp_server(char *type) +int setup_tcp_server(char *type, char *addr, unsigned short *port) { int sk = -1; + int sockopt = 1; struct sockaddr_storage saddr; socklen_t slen = sizeof(saddr); - if (get_sockaddr_in(&saddr, opts.addr)) { + if (get_sockaddr_in(&saddr, addr, (*port))) { return -1; } - pr_info("Starting %s server on port %u\n", type, opts.port); + pr_info("Starting %s server on port %u\n", type, *port); sk = socket(saddr.ss_family, SOCK_STREAM, IPPROTO_TCP); @@ -1289,6 +1291,12 @@ int setup_tcp_server(char *type) return -1; } + if (setsockopt( + sk, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)) == -1) { + pr_perror("Unable to set SO_REUSEADDR"); + goto out; + } + if (bind(sk, (struct sockaddr *)&saddr, slen)) { pr_perror("Can't bind %s server", type); goto out; @@ -1300,19 +1308,19 @@ int setup_tcp_server(char *type) } /* Get socket port in case of autobind */ - if (opts.port == 0) { + if ((*port) == 0) { if (getsockname(sk, (struct sockaddr *)&saddr, &slen)) { pr_perror("Can't get %s server name", type); goto out; } if (saddr.ss_family == AF_INET6) { - opts.port = ntohs(((struct sockaddr_in6 *)&saddr)->sin6_port); + (*port) = ntohs(((struct sockaddr_in *)&saddr)->sin_port); } else if (saddr.ss_family == AF_INET) { - opts.port = ntohs(((struct sockaddr_in *)&saddr)->sin_port); + (*port) = ntohs(((struct sockaddr_in6 *)&saddr)->sin6_port); } - pr_info("Using %u port\n", opts.port); + pr_info("Using %u port\n", (*port)); } return sk; @@ -1375,7 +1383,7 @@ int setup_tcp_client(char *addr) pr_info("Connecting to server %s:%u\n", addr, opts.port); - if (get_sockaddr_in(&saddr, addr)) + if (get_sockaddr_in(&saddr, addr, opts.port)) return -1; sk = socket(saddr.ss_family, SOCK_STREAM, IPPROTO_TCP); From 4fe75ecfc43c29594f31fa655a38cf3ea79b6cbd Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 13 Sep 2018 18:28:06 +0100 Subject: [PATCH 1778/4375] zdtm: Specify --address for remote_lazy_pages When --remote-lazy-pages is used the address option was not specified. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 23884166e..90f4d3573 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1132,7 +1132,7 @@ class criu: if self.__lazy_pages or self.__lazy_migrate: lp_opts = [] if self.__remote_lazy_pages or self.__lazy_migrate: - lp_opts += ['--page-server', "--port", "12345"] + lp_opts += ['--page-server', "--port", "12345", "--address", "127.0.0.1"] if self.__remote_lazy_pages: ps_opts = ["--pidfile", "ps.pid", "--port", "12345", "--lazy-pages"] From a7c384f6eebcebc8b49655601956c18c51735672 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 13 Sep 2018 18:28:07 +0100 Subject: [PATCH 1779/4375] util: Enable hostname resolution in tcp_client Add hostname resolution in setup_tcp_client(). This change allows a valid hostname to be provided as value for --address option when connecting to page server. This change is needed for the following path which removes setup_TCP_client_socket() from img-proxy.c. In this function the hostname resolution was implemented using gethostbyname() However, here we use `getaddrinfo` instead because gethostbyname() is marked obsolescent in POSIX.1-2001 and is removed in POSIX.1-2008 specifications. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 2 +- criu/include/util.h | 2 +- criu/util.c | 67 +++++++++++++++++++++++++++++++++--------- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 003d748ce..4194f5b0c 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -558,7 +558,7 @@ Launches *criu* in page server mode. It isn't supposed to use --daemon and --status-fd together. *--address* 'address':: - Page server IP address. + Page server IP address or hostname. *--port* 'number':: Page server port number. diff --git a/criu/include/util.h b/criu/include/util.h index af9b6c537..1e2fec81e 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -291,7 +291,7 @@ void print_data(unsigned long addr, unsigned char *data, size_t size); int setup_tcp_server(char *type, char *addr, unsigned short *port); int run_tcp_server(bool daemon_mode, int *ask, int cfd, int sk); -int setup_tcp_client(char *addr); +int setup_tcp_client(char *hostname); #define LAST_PID_PATH "sys/kernel/ns_last_pid" #define PID_MAX_PATH "sys/kernel/pid_max" diff --git a/criu/util.c b/criu/util.c index 872623072..748650537 100644 --- a/criu/util.c +++ b/criu/util.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -1376,28 +1377,66 @@ out: return -1; } -int setup_tcp_client(char *addr) +int setup_tcp_client(char *hostname) { struct sockaddr_storage saddr; - int sk; + struct addrinfo addr_criteria, *addr_list, *p; + char ipstr[INET6_ADDRSTRLEN]; + int sk = -1; + void *ip; - pr_info("Connecting to server %s:%u\n", addr, opts.port); + memset(&addr_criteria, 0, sizeof(addr_criteria)); + addr_criteria.ai_family = AF_UNSPEC; + addr_criteria.ai_socktype = SOCK_STREAM; + addr_criteria.ai_protocol = IPPROTO_TCP; - if (get_sockaddr_in(&saddr, addr, opts.port)) - return -1; - - sk = socket(saddr.ss_family, SOCK_STREAM, IPPROTO_TCP); - if (sk < 0) { - pr_perror("Can't create socket"); - return -1; + /* + * addr_list contains a list of addrinfo structures that corresponding + * to the criteria specified in hostname and addr_criteria. + */ + if (getaddrinfo(hostname, NULL, &addr_criteria, &addr_list)) { + pr_perror("Failed to resolve hostname: %s", hostname); + goto out; } - if (connect(sk, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { - pr_perror("Can't connect to server"); - close(sk); - return -1; + /* + * Iterate through addr_list and try to connect. The loop stops if the + * connection is successful or we reach the end of the list. + */ + for(p = addr_list; p != NULL; p = p->ai_next) { + + if (p->ai_family == AF_INET) { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; + ip = &(ipv4->sin_addr); + } else { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr; + ip = &(ipv6->sin6_addr); + } + + inet_ntop(p->ai_family, ip, ipstr, sizeof(ipstr)); + pr_info("Connecting to server %s:%u\n", ipstr, opts.port); + + if (get_sockaddr_in(&saddr, ipstr, opts.port)) + goto out; + + sk = socket(saddr.ss_family, SOCK_STREAM, IPPROTO_TCP); + if (sk < 0) { + pr_perror("Can't create socket"); + goto out; + } + + if (connect(sk, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { + pr_info("Can't connect to server %s:%u\n", ipstr, opts.port); + close(sk); + sk = -1; + } else { + /* Connected successfully */ + break; + } } +out: + freeaddrinfo(addr_list); return sk; } From 4416c58efe4f50ff0414c35e3869bd5c4ea9668c Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 13 Sep 2018 18:28:11 +0100 Subject: [PATCH 1780/4375] zdtm: Explicitly close opened files CPython currently uses a reference-counting scheme with (optional) delayed detection of cyclically linked garbage, which collects most objects as soon as they become unreachable, but is not guaranteed to collect garbage containing circular references. Some objects contain references to "external" resources such as open files. It is understood that these resources are freed when the object is garbage-collected, but since garbage collection is not guaranteed to happen, such objects also provide an explicit way to release the external resource, usually a close() method. Programs are strongly recommended to explicitly close such objects. Reference: https://docs.python.org/3.6/reference/datamodel.html Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- test/zdtm.py | 100 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 41 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 90f4d3573..97f9da009 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -108,13 +108,10 @@ def add_to_output(path): if not report_dir: return - fdi = open(path, "r") - fdo = open(os.path.join(report_dir, "output"), "a") - while True: - buf = fdi.read(1 << 20) - if not buf: - break - fdo.write(buf) + output_path = os.path.join(report_dir, "output") + with open(path, "r") as fdi, open(output_path, "a") as fdo: + for line in fdi: + fdo.write(line) prev_crash_reports = set(glob.glob("/tmp/zdtm-core-*.txt")) @@ -131,7 +128,8 @@ def check_core_files(): for i in reports: add_to_report(i, os.path.basename(i)) print_sep(i) - print(open(i).read()) + with open(i, "r") as report: + print(report.read()) print_sep(i) return True @@ -318,7 +316,8 @@ def tail(path): def rpidfile(path): - return open(path).readline().strip() + with open(path) as fd: + return fd.readline().strip() def wait_pid_die(pid, who, tmo = 30): @@ -502,7 +501,8 @@ class zdtm_test: if 'PASS' not in list(map(lambda s: s.strip(), res.split())): if os.access(self.__name + '.out.inprogress', os.F_OK): print_sep(self.__name + '.out.inprogress') - print(open(self.__name + '.out.inprogress').read()) + with open(self.__name + '.out.inprogress') as fd: + print(fd.read()) print_sep(self.__name + '.out.inprogress') raise test_fail_exc("result check") @@ -547,7 +547,8 @@ class zdtm_test: def print_output(self): if os.access(self.__name + '.out', os.R_OK): print("Test output: " + "=" * 32) - print(open(self.__name + '.out').read()) + with open(self.__name + '.out') as output: + print(output.read()) print(" <<< " + "=" * 32) def static(self): @@ -634,7 +635,8 @@ class inhfd_test: self.__my_file.write(self.__message) self.__my_file.flush() pid, status = os.waitpid(self.__peer_pid, 0) - print(open(self.__name + ".out").read()) + with open(self.__name + ".out") as output: + print(output.read()) self.__peer_pid = 0 if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 42: raise test_fail_exc("test failed with %d" % status) @@ -688,7 +690,8 @@ class groups_test(zdtm_test): zdtm_test.__init__(self, 'zdtm/lib/groups', desc, flavor, freezer) if flavor.ns: self.__real_name = name - self.__subs = map(lambda x: x.strip(), open(name).readlines()) + with open(name) as fd: + self.__subs = map(lambda x: x.strip(), fd.readlines()) print("Subs:\n%s" % '\n'.join(self.__subs)) else: self.__real_name = '' @@ -861,7 +864,8 @@ class criu_rpc: res = criu.restore() pidf = ctx.get('pidf') if pidf: - open(pidf, 'w').write('%d\n' % res.pid) + with open(pidf, 'w') as fd: + fd.write('%d\n' % res.pid) elif action == "page-server": res = criu.page_server_chld() p = criu_rpc_process() @@ -1005,7 +1009,8 @@ class criu: fcntl.fcntl(fd, fcntl.F_SETFD, fdflags & ~fcntl.FD_CLOEXEC) s_args += ["--status-fd", str(fd)] - ns_last_pid = open("/proc/sys/kernel/ns_last_pid").read() + with open("/proc/sys/kernel/ns_last_pid") as ns_last_pid_fd: + ns_last_pid = ns_last_pid_fd.read() ret = self.__criu.run(action, s_args, self.__criu_bin, self.__fault, strace, preexec, nowait) @@ -1031,7 +1036,8 @@ class criu: os.rename(os.path.join(__ddir, log), os.path.join(__ddir, log + ".fail")) # restore ns_last_pid to avoid a case when criu gets # PID of one of restored processes. - open("/proc/sys/kernel/ns_last_pid", "w+").write(ns_last_pid) + with open("/proc/sys/kernel/ns_last_pid", "w+") as fd: + fd.write(ns_last_pid) # try again without faults print("Run criu " + action) ret = self.__criu.run(action, s_args, self.__criu_bin, False, strace, preexec) @@ -1276,7 +1282,8 @@ def get_visible_state(test): cmaps = [[0, 0, ""]] last = 0 - for mp in open("/proc/%s/root/proc/%s/maps" % (test.getpid(), pid)): + mapsfd = open("/proc/%s/root/proc/%s/maps" % (test.getpid(), pid)) + for mp in mapsfd: m = list(map(lambda x: int('0x' + x, 0), mp.split()[0].split('-'))) m.append(mp.split()[1]) @@ -1291,14 +1298,16 @@ def get_visible_state(test): else: cmaps.append(m) last += 1 + mapsfd.close() maps[pid] = set(map(lambda x: '%x-%x %s' % (x[0], x[1], " ".join(x[2:])), cmaps)) cmounts = [] try: r = re.compile("^\S+\s\S+\s\S+\s(\S+)\s(\S+)\s\S+\s[^-]*?(shared)?[^-]*?(master)?[^-]*?-") - for m in open("/proc/%s/root/proc/%s/mountinfo" % (test.getpid(), pid)): - cmounts.append(r.match(m).groups()) + with open("/proc/%s/root/proc/%s/mountinfo" % (test.getpid(), pid)) as mountinfo: + for m in mountinfo: + cmounts.append(r.match(m).groups()) except IOError as e: if e.errno != errno.EINVAL: raise e @@ -1589,7 +1598,8 @@ class Launcher: print(u"# Timestamp: " + now.strftime("%Y-%m-%d %H:%M") + " (GMT+1)", file=self.__file_report) print(u"# ", file=self.__file_report) print(u"1.." + str(nr_tests), file=self.__file_report) - self.__taint = open("/proc/sys/kernel/tainted").read() + with open("/proc/sys/kernel/tainted") as taintfd: + self.__taint = taintfd.read() if int(self.__taint, 0) != 0: print("The kernel is tainted: %r" % self.__taint) if not opts["ignore_taint"]: @@ -1618,7 +1628,8 @@ class Launcher: if len(self.__subs) >= self.__max: self.wait() - taint = open("/proc/sys/kernel/tainted").read() + with open("/proc/sys/kernel/tainted") as taintfd: + taint = taintfd.read() if self.__taint != taint: raise Exception("The kernel is tainted: %r (%r)" % (taint, self.__taint)) @@ -1680,7 +1691,8 @@ class Launcher: self.__failed.append([sub['name'], failed_flavor]) if self.__file_report: testline = u"not ok %d - %s # flavor %s" % (self.__runtest, sub['name'], failed_flavor) - output = open(sub['log']).read() + with open(sub['log']) as sublog: + output = sublog.read() details = {'output': output} tc.add_error_info(output = output) print(testline, file=self.__file_report) @@ -1693,7 +1705,8 @@ class Launcher: print(testline, file=self.__file_report) if sub['log']: - print(open(sub['log']).read().encode('ascii', 'ignore')) + with open(sub['log']) as sublog: + print(sublog.read().encode('ascii', 'ignore')) os.unlink(sub['log']) return True @@ -1724,6 +1737,7 @@ class Launcher: if self.__file_report: ts = TestSuite(opts['title'], self.__junit_test_cases, os.getenv("NODE_NAME")) self.__junit_file.write(TestSuite.to_xml_string([ts])) + self.__junit_file.close() self.__file_report.close() if opts['keep_going']: @@ -1742,7 +1756,8 @@ class Launcher: def all_tests(opts): - desc = eval(open(opts['set'] + '.desc').read()) + with open(opts['set'] + '.desc') as fd: + desc = eval(fd.read()) files = [] mask = stat.S_IFREG | stat.S_IXUSR @@ -1772,7 +1787,8 @@ default_test = {} def get_test_desc(tname): d_path = tname + '.desc' if os.access(d_path, os.F_OK) and os.path.getsize(d_path) > 0: - return eval(open(d_path).read()) + with open(d_path) as fd: + return eval(fd.read()) return default_test @@ -1806,22 +1822,23 @@ def grep_errors(fname): first = True print_next = False before = [] - for l in open(fname): - before.append(l) - if len(before) > 5: - before.pop(0) - if "Error" in l: - if first: - print_fname(fname, 'log') - print_sep("grep Error", "-", 60) - first = False - for i in before: - print_next = print_error(i) - before = [] - else: - if print_next: - print_next = print_error(l) + with open(fname) as fd: + for l in fd: + before.append(l) + if len(before) > 5: + before.pop(0) + if "Error" in l: + if first: + print_fname(fname, 'log') + print_sep("grep Error", "-", 60) + first = False + for i in before: + print_next = print_error(i) before = [] + else: + if print_next: + print_next = print_error(l) + before = [] if not first: print_sep("ERROR OVER", "-", 60) @@ -1850,7 +1867,8 @@ def run_tests(opts): print("No such file") return - torun = map(lambda x: x.strip(), open(opts['from'])) + with open(opts['from']) as fd: + torun = map(lambda x: x.strip(), fd) opts['keep_going'] = False run_all = True else: From bd8fa1528ad85ebc1b7bae94b463a5135ea888b4 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 21 Sep 2018 07:46:19 +0300 Subject: [PATCH 1781/4375] test/rpc: Specify --address for page-server Signed-off-by: Andrei Vagin --- test/others/rpc/ps_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/others/rpc/ps_test.py b/test/others/rpc/ps_test.py index b25ff745e..a8f9d825f 100755 --- a/test/others/rpc/ps_test.py +++ b/test/others/rpc/ps_test.py @@ -52,6 +52,7 @@ else: print 'Dumping myself using page-server' req.type = rpc.DUMP req.opts.ps.port = resp.ps.port +req.opts.ps.address = "127.0.0.1" req.opts.log_file = 'dump.log' req.opts.leave_running = True From 7ce23b2a74196678a746d1402e5444179674c9a4 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 23 Sep 2018 15:31:51 +0100 Subject: [PATCH 1782/4375] python: Remove unused imports Auto-detected with pylint. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- coredump/criu_coredump/elf.py | 284 ++++++++++++++++---------------- lib/py/criu.py | 3 - lib/py/images/images.py | 161 +++++++++--------- scripts/magic-gen.py | 3 +- soccr/test/tcp-test.py | 2 +- test/crit-recode.py | 1 - test/exhaustive/unix.py | 1 - test/others/rpc/errno.py | 2 +- test/others/rpc/ps_test.py | 2 +- test/others/rpc/restore-loop.py | 2 +- test/others/rpc/test.py | 2 +- test/others/rpc/version.py | 1 - test/others/shell-job/run.py | 3 +- 13 files changed, 228 insertions(+), 239 deletions(-) diff --git a/coredump/criu_coredump/elf.py b/coredump/criu_coredump/elf.py index 070e4792e..1da06a6fd 100644 --- a/coredump/criu_coredump/elf.py +++ b/coredump/criu_coredump/elf.py @@ -1,11 +1,11 @@ # Define structures and constants for generating elf file. -from ctypes import * +import ctypes -Elf64_Half = c_uint16 # typedef uint16_t Elf64_Half; -Elf64_Word = c_uint32 # typedef uint32_t Elf64_Word; -Elf64_Addr = c_uint64 # typedef uint64_t Elf64_Addr; -Elf64_Off = c_uint64 # typedef uint64_t Elf64_Off; -Elf64_Xword = c_uint64 # typedef uint64_t Elf64_Xword; +Elf64_Half = ctypes.c_uint16 # typedef uint16_t Elf64_Half; +Elf64_Word = ctypes.c_uint32 # typedef uint32_t Elf64_Word; +Elf64_Addr = ctypes.c_uint64 # typedef uint64_t Elf64_Addr; +Elf64_Off = ctypes.c_uint64 # typedef uint64_t Elf64_Off; +Elf64_Xword = ctypes.c_uint64 # typedef uint64_t Elf64_Xword; # Elf64_Ehdr related constants. @@ -43,9 +43,9 @@ EM_X86_64 = 62 # #define EM_X86_64 62 /* AMD x86-64 architec # Legal values for e_version (version). EV_CURRENT = 1 # #define EV_CURRENT 1 /* Current version */ -class Elf64_Ehdr(Structure): # typedef struct +class Elf64_Ehdr(ctypes.Structure): # typedef struct _fields_ = [ # { - ("e_ident", c_ubyte*EI_NIDENT), # unsigned char e_ident[EI_NIDENT]; + ("e_ident", ctypes.c_ubyte*EI_NIDENT), # unsigned char e_ident[EI_NIDENT]; ("e_type", Elf64_Half), # Elf64_Half e_type; ("e_machine", Elf64_Half), # Elf64_Half e_machine; ("e_version", Elf64_Word), # Elf64_Word e_version; @@ -73,7 +73,7 @@ PF_X = 1 # #define PF_X (1 << 0) /* Segment is executable */ PF_W = 1 << 1 # #define PF_W (1 << 1) /* Segment is writable */ PF_R = 1 << 2 # #define PF_R (1 << 2) /* Segment is readable */ -class Elf64_Phdr(Structure): # typedef struct +class Elf64_Phdr(ctypes.Structure): # typedef struct _fields_ = [ # { ("p_type", Elf64_Word), # Elf64_Word p_type; ("p_flags", Elf64_Word), # Elf64_Word p_flags; @@ -88,14 +88,14 @@ class Elf64_Phdr(Structure): # typedef struct # Elf64_auxv_t related constants. -class _Elf64_auxv_t_U(Union): +class _Elf64_auxv_t_U(ctypes.Union): _fields_ = [ - ("a_val", c_uint64) + ("a_val", ctypes.c_uint64) ] -class Elf64_auxv_t(Structure): # typedef struct +class Elf64_auxv_t(ctypes.Structure): # typedef struct _fields_ = [ # { - ("a_type", c_uint64), # uint64_t a_type; /* Entry type */ + ("a_type", ctypes.c_uint64), # uint64_t a_type; /* Entry type */ ("a_un", _Elf64_auxv_t_U) # union # { # uint64_t a_val; /* Integer value */ @@ -118,7 +118,7 @@ NT_FILE = 0x46494c45 # #define NT_FILE 0x46494c45 /* Contains info # files */ NT_X86_XSTATE = 0x202 # #define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ -class Elf64_Nhdr(Structure): # typedef struct +class Elf64_Nhdr(ctypes.Structure): # typedef struct _fields_ = [ # { ("n_namesz", Elf64_Word), # Elf64_Word n_namesz; /* Length of the note's name. */ ("n_descsz", Elf64_Word), # Elf64_Word n_descsz; /* Length of the note's descriptor. */ @@ -128,7 +128,7 @@ class Elf64_Nhdr(Structure): # typedef struct # Elf64_Shdr related constants. -class Elf64_Shdr(Structure): # typedef struct +class Elf64_Shdr(ctypes.Structure): # typedef struct _fields_ = [ # { ("sh_name", Elf64_Word), # Elf64_Word sh_name; /* Section name (string tbl index) */ ("sh_type", Elf64_Word), # Elf64_Word sh_type; /* Section type */ @@ -146,73 +146,73 @@ class Elf64_Shdr(Structure): # typedef struct # elf_prstatus related constants. # Signal info. -class elf_siginfo(Structure): # struct elf_siginfo +class elf_siginfo(ctypes.Structure): # struct elf_siginfo _fields_ = [ # { - ("si_signo", c_int), # int si_signo; /* Signal number. */ - ("si_code", c_int), # int si_code; /* Extra code. */ - ("si_errno", c_int) # int si_errno; /* Errno. */ + ("si_signo", ctypes.c_int), # int si_signo; /* Signal number. */ + ("si_code", ctypes.c_int), # int si_code; /* Extra code. */ + ("si_errno", ctypes.c_int) # int si_errno; /* Errno. */ ] # }; # A time value that is accurate to the nearest # microsecond but also has a range of years. -class timeval(Structure): # struct timeval +class timeval(ctypes.Structure): # struct timeval _fields_ = [ # { - ("tv_sec", c_long), # __time_t tv_sec; /* Seconds. */ - ("tv_usec", c_long) # __suseconds_t tv_usec; /* Microseconds. */ + ("tv_sec", ctypes.c_long), # __time_t tv_sec; /* Seconds. */ + ("tv_usec", ctypes.c_long) # __suseconds_t tv_usec; /* Microseconds. */ ] # }; -class user_regs_struct(Structure): # struct user_regs_struct +class user_regs_struct(ctypes.Structure): # struct user_regs_struct _fields_ = [ # { - ("r15", c_ulonglong), # __extension__ unsigned long long int r15; - ("r14", c_ulonglong), # __extension__ unsigned long long int r14; - ("r13", c_ulonglong), # __extension__ unsigned long long int r13; - ("r12", c_ulonglong), # __extension__ unsigned long long int r12; - ("rbp", c_ulonglong), # __extension__ unsigned long long int rbp; - ("rbx", c_ulonglong), # __extension__ unsigned long long int rbx; - ("r11", c_ulonglong), # __extension__ unsigned long long int r11; - ("r10", c_ulonglong), # __extension__ unsigned long long int r10; - ("r9", c_ulonglong), # __extension__ unsigned long long int r9; - ("r8", c_ulonglong), # __extension__ unsigned long long int r8; - ("rax", c_ulonglong), # __extension__ unsigned long long int rax; - ("rcx", c_ulonglong), # __extension__ unsigned long long int rcx; - ("rdx", c_ulonglong), # __extension__ unsigned long long int rdx; - ("rsi", c_ulonglong), # __extension__ unsigned long long int rsi; - ("rdi", c_ulonglong), # __extension__ unsigned long long int rdi; - ("orig_rax", c_ulonglong), # __extension__ unsigned long long int orig_rax; - ("rip", c_ulonglong), # __extension__ unsigned long long int rip; - ("cs", c_ulonglong), # __extension__ unsigned long long int cs; - ("eflags", c_ulonglong), # __extension__ unsigned long long int eflags; - ("rsp", c_ulonglong), # __extension__ unsigned long long int rsp; - ("ss", c_ulonglong), # __extension__ unsigned long long int ss; - ("fs_base", c_ulonglong), # __extension__ unsigned long long int fs_base; - ("gs_base", c_ulonglong), # __extension__ unsigned long long int gs_base; - ("ds", c_ulonglong), # __extension__ unsigned long long int ds; - ("es", c_ulonglong), # __extension__ unsigned long long int es; - ("fs", c_ulonglong), # __extension__ unsigned long long int fs; - ("gs", c_ulonglong) # __extension__ unsigned long long int gs; + ("r15", ctypes.c_ulonglong), # __extension__ unsigned long long int r15; + ("r14", ctypes.c_ulonglong), # __extension__ unsigned long long int r14; + ("r13", ctypes.c_ulonglong), # __extension__ unsigned long long int r13; + ("r12", ctypes.c_ulonglong), # __extension__ unsigned long long int r12; + ("rbp", ctypes.c_ulonglong), # __extension__ unsigned long long int rbp; + ("rbx", ctypes.c_ulonglong), # __extension__ unsigned long long int rbx; + ("r11", ctypes.c_ulonglong), # __extension__ unsigned long long int r11; + ("r10", ctypes.c_ulonglong), # __extension__ unsigned long long int r10; + ("r9", ctypes.c_ulonglong), # __extension__ unsigned long long int r9; + ("r8", ctypes.c_ulonglong), # __extension__ unsigned long long int r8; + ("rax", ctypes.c_ulonglong), # __extension__ unsigned long long int rax; + ("rcx", ctypes.c_ulonglong), # __extension__ unsigned long long int rcx; + ("rdx", ctypes.c_ulonglong), # __extension__ unsigned long long int rdx; + ("rsi", ctypes.c_ulonglong), # __extension__ unsigned long long int rsi; + ("rdi", ctypes.c_ulonglong), # __extension__ unsigned long long int rdi; + ("orig_rax", ctypes.c_ulonglong), # __extension__ unsigned long long int orig_rax; + ("rip", ctypes.c_ulonglong), # __extension__ unsigned long long int rip; + ("cs", ctypes.c_ulonglong), # __extension__ unsigned long long int cs; + ("eflags", ctypes.c_ulonglong), # __extension__ unsigned long long int eflags; + ("rsp", ctypes.c_ulonglong), # __extension__ unsigned long long int rsp; + ("ss", ctypes.c_ulonglong), # __extension__ unsigned long long int ss; + ("fs_base", ctypes.c_ulonglong), # __extension__ unsigned long long int fs_base; + ("gs_base", ctypes.c_ulonglong), # __extension__ unsigned long long int gs_base; + ("ds", ctypes.c_ulonglong), # __extension__ unsigned long long int ds; + ("es", ctypes.c_ulonglong), # __extension__ unsigned long long int es; + ("fs", ctypes.c_ulonglong), # __extension__ unsigned long long int fs; + ("gs", ctypes.c_ulonglong) # __extension__ unsigned long long int gs; ] # }; -#elf_greg_t = c_ulonglong -#ELF_NGREG = sizeof(user_regs_struct)/sizeof(elf_greg_t) +#elf_greg_t = ctypes.c_ulonglong +#ELF_NGREG = ctypes.sizeof(user_regs_struct)/ctypes.sizeof(elf_greg_t) #elf_gregset_t = elf_greg_t*ELF_NGREG elf_gregset_t = user_regs_struct -class elf_prstatus(Structure): # struct elf_prstatus +class elf_prstatus(ctypes.Structure): # struct elf_prstatus _fields_ = [ # { ("pr_info", elf_siginfo), # struct elf_siginfo pr_info; /* Info associated with signal. */ - ("pr_cursig", c_short), # short int pr_cursig; /* Current signal. */ - ("pr_sigpend", c_ulong), # unsigned long int pr_sigpend; /* Set of pending signals. */ - ("pr_sighold", c_ulong), # unsigned long int pr_sighold; /* Set of held signals. */ - ("pr_pid", c_int), # __pid_t pr_pid; - ("pr_ppid", c_int), # __pid_t pr_ppid; - ("pr_pgrp", c_int), # __pid_t pr_pgrp; - ("pr_sid", c_int), # __pid_t pr_sid; + ("pr_cursig", ctypes.c_short), # short int pr_cursig; /* Current signal. */ + ("pr_sigpend", ctypes.c_ulong), # unsigned long int pr_sigpend; /* Set of pending signals. */ + ("pr_sighold", ctypes.c_ulong), # unsigned long int pr_sighold; /* Set of held signals. */ + ("pr_pid", ctypes.c_int), # __pid_t pr_pid; + ("pr_ppid", ctypes.c_int), # __pid_t pr_ppid; + ("pr_pgrp", ctypes.c_int), # __pid_t pr_pgrp; + ("pr_sid", ctypes.c_int), # __pid_t pr_sid; ("pr_utime", timeval), # struct timeval pr_utime; /* User time. */ ("pr_stime", timeval), # struct timeval pr_stime; /* System time. */ ("pr_cutime", timeval), # struct timeval pr_cutime; /* Cumulative user time. */ ("pr_cstime", timeval), # struct timeval pr_cstime; /* Cumulative system time. */ ("pr_reg", elf_gregset_t), # elf_gregset_t pr_reg; /* GP registers. */ - ("pr_fpvalid", c_int) # int pr_fpvalid; /* True if math copro being used. */ + ("pr_fpvalid", ctypes.c_int) # int pr_fpvalid; /* True if math copro being used. */ ] # }; @@ -220,43 +220,43 @@ class elf_prstatus(Structure): # struct elf_prstatus ELF_PRARGSZ = 80 # #define ELF_PRARGSZ (80) /* Number of chars for args. */ -class elf_prpsinfo(Structure): # struct elf_prpsinfo +class elf_prpsinfo(ctypes.Structure): # struct elf_prpsinfo _fields_ = [ # { - ("pr_state", c_byte), # char pr_state; /* Numeric process state. */ - ("pr_sname", c_char), # char pr_sname; /* Char for pr_state. */ - ("pr_zomb", c_byte), # char pr_zomb; /* Zombie. */ - ("pr_nice", c_byte), # char pr_nice; /* Nice val. */ - ("pr_flag", c_ulong), # unsigned long int pr_flag; /* Flags. */ + ("pr_state", ctypes.c_byte), # char pr_state; /* Numeric process state. */ + ("pr_sname", ctypes.c_char), # char pr_sname; /* Char for pr_state. */ + ("pr_zomb", ctypes.c_byte), # char pr_zomb; /* Zombie. */ + ("pr_nice", ctypes.c_byte), # char pr_nice; /* Nice val. */ + ("pr_flag", ctypes.c_ulong), # unsigned long int pr_flag; /* Flags. */ # #if __WORDSIZE == 32 # unsigned short int pr_uid; # unsigned short int pr_gid; # #else - ("pr_uid", c_uint), # unsigned int pr_uid; - ("pr_gid", c_uint), # unsigned int pr_gid; + ("pr_uid", ctypes.c_uint), # unsigned int pr_uid; + ("pr_gid", ctypes.c_uint), # unsigned int pr_gid; # #endif - ("pr_pid", c_int), # int pr_pid, pr_ppid, pr_pgrp, pr_sid; - ("pr_ppid", c_int), - ("pr_pgrp", c_int), - ("pr_sid", c_int), + ("pr_pid", ctypes.c_int), # int pr_pid, pr_ppid, pr_pgrp, pr_sid; + ("pr_ppid", ctypes.c_int), + ("pr_pgrp", ctypes.c_int), + ("pr_sid", ctypes.c_int), # /* Lots missing */ - ("pr_fname", c_char*16), # char pr_fname[16]; /* Filename of executable. */ - ("pr_psargs", c_char*ELF_PRARGSZ) # char pr_psargs[ELF_PRARGSZ]; /* Initial part of arg list. */ + ("pr_fname", ctypes.c_char*16), # char pr_fname[16]; /* Filename of executable. */ + ("pr_psargs", ctypes.c_char*ELF_PRARGSZ) # char pr_psargs[ELF_PRARGSZ]; /* Initial part of arg list. */ ] # }; -class user_fpregs_struct(Structure): # struct user_fpregs_struct +class user_fpregs_struct(ctypes.Structure): # struct user_fpregs_struct _fields_ = [ # { - ("cwd", c_ushort), # unsigned short int cwd; - ("swd", c_ushort), # unsigned short int swd; - ("ftw", c_ushort), # unsigned short int ftw; - ("fop", c_ushort), # unsigned short int fop; - ("rip", c_ulonglong), # __extension__ unsigned long long int rip; - ("rdp", c_ulonglong), # __extension__ unsigned long long int rdp; - ("mxcsr", c_uint), # unsigned int mxcsr; - ("mxcr_mask", c_uint), # unsigned int mxcr_mask; - ("st_space", c_uint*32), # unsigned int st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ - ("xmm_space", c_uint*64), # unsigned int xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */ - ("padding", c_uint*24), # unsigned int padding[24]; + ("cwd", ctypes.c_ushort), # unsigned short int cwd; + ("swd", ctypes.c_ushort), # unsigned short int swd; + ("ftw", ctypes.c_ushort), # unsigned short int ftw; + ("fop", ctypes.c_ushort), # unsigned short int fop; + ("rip", ctypes.c_ulonglong), # __extension__ unsigned long long int rip; + ("rdp", ctypes.c_ulonglong), # __extension__ unsigned long long int rdp; + ("mxcsr", ctypes.c_uint), # unsigned int mxcsr; + ("mxcr_mask", ctypes.c_uint), # unsigned int mxcr_mask; + ("st_space", ctypes.c_uint*32), # unsigned int st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ + ("xmm_space", ctypes.c_uint*64), # unsigned int xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */ + ("padding", ctypes.c_uint*24), # unsigned int padding[24]; ] # }; @@ -266,79 +266,79 @@ elf_fpregset_t = user_fpregs_struct # siginfo_t related constants. _SI_MAX_SIZE = 128 -_SI_PAD_SIZE = (_SI_MAX_SIZE/sizeof(c_int)) - 4 +_SI_PAD_SIZE = (_SI_MAX_SIZE/ctypes.sizeof(ctypes.c_int)) - 4 # /* kill(). */ -class _siginfo_t_U_kill(Structure): # struct +class _siginfo_t_U_kill(ctypes.Structure): # struct _fields_ = [ # { - ("si_pid", c_int), # __pid_t si_pid; /* Sending process ID. */ - ("si_uid", c_uint) # __uid_t si_uid; /* Real user ID of sending process. */ + ("si_pid", ctypes.c_int), # __pid_t si_pid; /* Sending process ID. */ + ("si_uid", ctypes.c_uint) # __uid_t si_uid; /* Real user ID of sending process. */ ] # } _kill; # Type for data associated with a signal. -class sigval_t(Union): # typedef union sigval +class sigval_t(ctypes.Union): # typedef union sigval _fields_ = [ # { - ("sival_int", c_int), # int sival_int; - ("sical_ptr", c_void_p), # void *sival_ptr; + ("sival_int", ctypes.c_int), # int sival_int; + ("sical_ptr", ctypes.c_void_p), # void *sival_ptr; ] # } sigval_t; # /* POSIX.1b timers. */ -class _siginfo_t_U_timer(Structure): # struct +class _siginfo_t_U_timer(ctypes.Structure): # struct _fields_ = [ # { - ("si_tid", c_int), # int si_tid; /* Timer ID. */ - ("si_overrun", c_int), # int si_overrun; /* Overrun count. */ + ("si_tid", ctypes.c_int), # int si_tid; /* Timer ID. */ + ("si_overrun", ctypes.c_int), # int si_overrun; /* Overrun count. */ ("si_sigval", sigval_t) # sigval_t si_sigval; /* Signal value. */ ] # } _timer; # /* POSIX.1b signals. */ -class _siginfo_t_U_rt(Structure): # struct +class _siginfo_t_U_rt(ctypes.Structure): # struct _fields_ = [ # { - ("si_pid", c_int), # __pid_t si_pid; /* Sending process ID. */ - ("si_uid", c_uint), # __uid_t si_uid; /* Real user ID of sending process. */ + ("si_pid", ctypes.c_int), # __pid_t si_pid; /* Sending process ID. */ + ("si_uid", ctypes.c_uint), # __uid_t si_uid; /* Real user ID of sending process. */ ("si_sigval", sigval_t) # sigval_t si_sigval; /* Signal value. */ ] # } _rt; # /* SIGCHLD. */ -class _siginfo_t_U_sigchld(Structure): # struct +class _siginfo_t_U_sigchld(ctypes.Structure): # struct _fields_ = [ # { - ("si_pid", c_int), # __pid_t si_pid; /* Which child. */ - ("si_uid", c_uint), # __uid_t si_uid; /* Real user ID of sending process. */ - ("si_status", c_int), # int si_status; /* Exit value or signal. */ - ("si_utime", c_long), # __sigchld_clock_t si_utime; - ("si_stime", c_long) # __sigchld_clock_t si_stime; + ("si_pid", ctypes.c_int), # __pid_t si_pid; /* Which child. */ + ("si_uid", ctypes.c_uint), # __uid_t si_uid; /* Real user ID of sending process. */ + ("si_status", ctypes.c_int), # int si_status; /* Exit value or signal. */ + ("si_utime", ctypes.c_long), # __sigchld_clock_t si_utime; + ("si_stime", ctypes.c_long) # __sigchld_clock_t si_stime; ] # } _sigchld; # /* SIGILL, SIGFPE, SIGSEGV, SIGBUS. */ -class _siginfo_t_U_sigfault(Structure): # struct +class _siginfo_t_U_sigfault(ctypes.Structure): # struct _fields_ = [ # { - ("si_addr", c_void_p), # void *si_addr; /* Faulting insn/memory ref. */ - ("si_addr_lsb", c_short) # short int si_addr_lsb; /* Valid LSB of the reported address. */ + ("si_addr", ctypes.c_void_p), # void *si_addr; /* Faulting insn/memory ref. */ + ("si_addr_lsb", ctypes.c_short) # short int si_addr_lsb; /* Valid LSB of the reported address. */ ] # } _sigfault; # /* SIGPOLL. */ -class _siginfo_t_U_sigpoll(Structure): # struct +class _siginfo_t_U_sigpoll(ctypes.Structure): # struct _fields_ = [ # { - ("si_band", c_long), # long int si_band; /* Band event for SIGPOLL. */ - ("si_fd", c_int) # int si_fd; + ("si_band", ctypes.c_long), # long int si_band; /* Band event for SIGPOLL. */ + ("si_fd", ctypes.c_int) # int si_fd; ] # } _sigpoll; # /* SIGSYS. */ -class _siginfo_t_U_sigsys(Structure): # struct +class _siginfo_t_U_sigsys(ctypes.Structure): # struct _fields_ = [ # { - ("_call_addr", c_void_p), # void *_call_addr; /* Calling user insn. */ - ("_syscall", c_int), # int _syscall; /* Triggering system call number. */ - ("_arch", c_uint) # unsigned int _arch; /* AUDIT_ARCH_* of syscall. */ + ("_call_addr", ctypes.c_void_p), # void *_call_addr; /* Calling user insn. */ + ("_syscall", ctypes.c_int), # int _syscall; /* Triggering system call number. */ + ("_arch", ctypes.c_uint) # unsigned int _arch; /* AUDIT_ARCH_* of syscall. */ ] # } _sigsys; -class _siginfo_t_U(Union): # union +class _siginfo_t_U(ctypes.Union): # union _fields_ = [ # { - ("_pad", c_int*_SI_PAD_SIZE), # int _pad[__SI_PAD_SIZE]; + ("_pad", ctypes.c_int*_SI_PAD_SIZE), # int _pad[__SI_PAD_SIZE]; # # /* kill(). */ ("_kill", _siginfo_t_U_kill), # struct @@ -396,12 +396,12 @@ class _siginfo_t_U(Union): # union # } _sigsys; ] # } _sifields; -class siginfo_t(Structure): # typedef struct +class siginfo_t(ctypes.Structure): # typedef struct _fields_ = [ # { - ("si_signo", c_int), # int si_signo; /* Signal number. */ - ("si_errno", c_int), # int si_errno; /* If non-zero, an errno value associated with + ("si_signo", ctypes.c_int), # int si_signo; /* Signal number. */ + ("si_errno", ctypes.c_int), # int si_errno; /* If non-zero, an errno value associated with # this signal, as defined in . */ - ("si_code", c_int), # int si_code; /* Signal code. */ + ("si_code", ctypes.c_int), # int si_code; /* Signal code. */ # ("_sifields", _siginfo_t_U) # union # { @@ -467,30 +467,30 @@ class siginfo_t(Structure): # typedef struct # xsave related. -class ymmh_struct(Structure): # struct ymmh_struct { +class ymmh_struct(ctypes.Structure): # struct ymmh_struct { _fields_ = [ - ("ymmh_space", 64*c_uint) # u32 ymmh_space[64]; + ("ymmh_space", 64*ctypes.c_uint) # u32 ymmh_space[64]; ] # } __packed; -class xsave_hdr_struct(Structure): # struct xsave_hdr_struct { +class xsave_hdr_struct(ctypes.Structure): # struct xsave_hdr_struct { _fields_ = [ - ("xstate_bv", c_ulonglong), # u64 xstate_bv; - ("reserved1", c_ulonglong*2), # u64 reserved1[2]; - ("reserved2", c_ulonglong*5) # u64 reserved2[5]; + ("xstate_bv", ctypes.c_ulonglong), # u64 xstate_bv; + ("reserved1", ctypes.c_ulonglong*2), # u64 reserved1[2]; + ("reserved2", ctypes.c_ulonglong*5) # u64 reserved2[5]; ] # } __packed; -class i387_fxsave_struct(Structure): # struct i387_fxsave_struct { +class i387_fxsave_struct(ctypes.Structure): # struct i387_fxsave_struct { _fields_ = [ - ("cwd", c_ushort), # u16 cwd; /* Control Word */ - ("swd", c_ushort), # u16 swd; /* Status Word */ - ("twd", c_ushort), # u16 twd; /* Tag Word */ - ("fop", c_ushort), # u16 fop; /* Last Instruction Opcode */ + ("cwd", ctypes.c_ushort), # u16 cwd; /* Control Word */ + ("swd", ctypes.c_ushort), # u16 swd; /* Status Word */ + ("twd", ctypes.c_ushort), # u16 twd; /* Tag Word */ + ("fop", ctypes.c_ushort), # u16 fop; /* Last Instruction Opcode */ # union { # struct { - ("rip", c_ulonglong), # u64 rip; /* Instruction Pointer */ - ("rdp", c_ulonglong), # u64 rdp; /* Data Pointer */ + ("rip", ctypes.c_ulonglong), # u64 rip; /* Instruction Pointer */ + ("rdp", ctypes.c_ulonglong), # u64 rdp; /* Data Pointer */ # }; # struct { # u32 fip; /* FPU IP Offset */ @@ -499,26 +499,26 @@ class i387_fxsave_struct(Structure): # struct i387_fxsave_struct { # u32 fos; /* FPU Operand Selector */ # }; # }; - ("mxcsr", c_uint), # u32 mxcsr; /* MXCSR Register State */ - ("mxcsr_mask", c_uint), # u32 mxcsr_mask; /* MXCSR Mask */ + ("mxcsr", ctypes.c_uint), # u32 mxcsr; /* MXCSR Register State */ + ("mxcsr_mask", ctypes.c_uint), # u32 mxcsr_mask; /* MXCSR Mask */ # # /* 8*16 bytes for each FP-reg = 128 bytes */ - ("st_space", c_uint*32), # u32 st_space[32]; + ("st_space", ctypes.c_uint*32), # u32 st_space[32]; # # /* 16*16 bytes for each XMM-reg = 256 bytes */ - ("xmm_space", c_uint*64), # u32 xmm_space[64]; + ("xmm_space", ctypes.c_uint*64), # u32 xmm_space[64]; # - ("padding", c_uint*12), # u32 padding[12]; + ("padding", ctypes.c_uint*12), # u32 padding[12]; # # union { - ("padding1", c_uint*12) # u32 padding1[12]; + ("padding1", ctypes.c_uint*12) # u32 padding1[12]; # u32 sw_reserved[12]; # }; # ] # } __aligned(16); -class elf_xsave_struct(Structure): # struct xsave_struct { +class elf_xsave_struct(ctypes.Structure): # struct xsave_struct { _fields_ = [ ("i387", i387_fxsave_struct), # struct i387_fxsave_struct i387; ("xsave_hdr", xsave_hdr_struct), # struct xsave_hdr_struct xsave_hdr; diff --git a/lib/py/criu.py b/lib/py/criu.py index 9465eefa2..de1a214a3 100644 --- a/lib/py/criu.py +++ b/lib/py/criu.py @@ -2,11 +2,8 @@ import socket import errno -import subprocess import fcntl import os -import signal -import sys import struct import pycriu.rpc_pb2 as rpc diff --git a/lib/py/images/images.py b/lib/py/images/images.py index eec25f5ac..217105fa8 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -39,16 +39,13 @@ # import io import base64 -import google import struct import os -import sys -import json -from . import pb2dict import array from . import magic -from .pb import * +from . import pb +from . import pb2dict if "encodebytes" not in dir(base64): base64.encodebytes = base64.encodestring @@ -187,16 +184,16 @@ class pagemap_handler: def load(self, f, pretty = False, no_payload = False): entries = [] - pb = pagemap_head() + pbuff = pb.pagemap_head() while True: buf = f.read(4) if buf == b'': break size, = struct.unpack('i', buf) - pb.ParseFromString(f.read(size)) - entries.append(pb2dict.pb2dict(pb, pretty)) + pbuff.ParseFromString(f.read(size)) + entries.append(pb2dict.pb2dict(pbuff, pretty)) - pb = pagemap_entry() + pbuff = pb.pagemap_entry() return entries @@ -205,15 +202,15 @@ class pagemap_handler: return self.load(f, pretty) def dump(self, entries, f): - pb = pagemap_head() + pbuff = pb.pagemap_head() for item in entries: - pb2dict.dict2pb(item, pb) - pb_str = pb.SerializeToString() + pb2dict.dict2pb(item, pbuff) + pb_str = pbuff.SerializeToString() size = len(pb_str) f.write(struct.pack('i', size)) f.write(pb_str) - pb = pagemap_entry() + pbuff = pb.pagemap_entry() def dumps(self, entries): f = io.BytesIO('') @@ -228,7 +225,7 @@ class ghost_file_handler: def load(self, f, pretty = False, no_payload = False): entries = [] - gf = ghost_file_entry() + gf = pb.ghost_file_entry() buf = f.read(4) size, = struct.unpack('i', buf) gf.ParseFromString(f.read(size)) @@ -237,7 +234,7 @@ class ghost_file_handler: if gf.chunks: entries.append(g_entry) while True: - gc = ghost_chunk_entry() + gc = pb.ghost_chunk_entry() buf = f.read(4) if buf == '': break @@ -263,19 +260,19 @@ class ghost_file_handler: return self.load(f, pretty) def dump(self, entries, f): - pb = ghost_file_entry() + pbuff = pb.ghost_file_entry() item = entries.pop(0) - pb2dict.dict2pb(item, pb) - pb_str = pb.SerializeToString() + pb2dict.dict2pb(item, pbuff) + pb_str = pbuff.SerializeToString() size = len(pb_str) f.write(struct.pack('i', size)) f.write(pb_str) - if pb.chunks: + if pbuff.chunks: for item in entries: - pb = ghost_chunk_entry() - pb2dict.dict2pb(item, pb) - pb_str = pb.SerializeToString() + pbuff = pb.ghost_chunk_entry() + pb2dict.dict2pb(item, pbuff) + pb_str = pbuff.SerializeToString() size = len(pb_str) f.write(struct.pack('i', size)) f.write(pb_str) @@ -387,7 +384,7 @@ class ipc_msg_queue_handler: if buf == '': break size, = struct.unpack('i', buf) - msg = ipc_msg() + msg = pb.ipc_msg() msg.ParseFromString(f.read(size)) rounded = round_up(msg.msize, sizeof_u64) data = f.read(msg.msize) @@ -399,7 +396,7 @@ class ipc_msg_queue_handler: def dump(self, extra, f, pb): entry = pb2dict.pb2dict(pb) for i in range (0, len(extra), 2): - msg = ipc_msg() + msg = pb.ipc_msg() pb2dict.dict2pb(extra[i], msg) msg_str = msg.SerializeToString() size = len(msg_str) @@ -418,7 +415,7 @@ class ipc_msg_queue_handler: if buf == '': break size, = struct.unpack('i', buf) - msg = ipc_msg() + msg = pb.ipc_msg() msg.ParseFromString(f.read(size)) rounded = round_up(msg.msize, sizeof_u64) f.seek(rounded, os.SEEK_CUR) @@ -452,65 +449,65 @@ class ipc_shm_handler: handlers = { - 'INVENTORY' : entry_handler(inventory_entry), - 'CORE' : entry_handler(core_entry), - 'IDS' : entry_handler(task_kobj_ids_entry), - 'CREDS' : entry_handler(creds_entry), - 'UTSNS' : entry_handler(utsns_entry), - 'IPC_VAR' : entry_handler(ipc_var_entry), - 'FS' : entry_handler(fs_entry), + 'INVENTORY' : entry_handler(pb.inventory_entry), + 'CORE' : entry_handler(pb.core_entry), + 'IDS' : entry_handler(pb.task_kobj_ids_entry), + 'CREDS' : entry_handler(pb.creds_entry), + 'UTSNS' : entry_handler(pb.utsns_entry), + 'IPC_VAR' : entry_handler(pb.ipc_var_entry), + 'FS' : entry_handler(pb.fs_entry), 'GHOST_FILE' : ghost_file_handler(), - 'MM' : entry_handler(mm_entry), - 'CGROUP' : entry_handler(cgroup_entry), - 'TCP_STREAM' : entry_handler(tcp_stream_entry, tcp_stream_extra_handler()), - 'STATS' : entry_handler(stats_entry), + 'MM' : entry_handler(pb.mm_entry), + 'CGROUP' : entry_handler(pb.cgroup_entry), + 'TCP_STREAM' : entry_handler(pb.tcp_stream_entry, tcp_stream_extra_handler()), + 'STATS' : entry_handler(pb.stats_entry), 'PAGEMAP' : pagemap_handler(), # Special one - 'PSTREE' : entry_handler(pstree_entry), - 'REG_FILES' : entry_handler(reg_file_entry), - 'NS_FILES' : entry_handler(ns_file_entry), - 'EVENTFD_FILE' : entry_handler(eventfd_file_entry), - 'EVENTPOLL_FILE' : entry_handler(eventpoll_file_entry), - 'EVENTPOLL_TFD' : entry_handler(eventpoll_tfd_entry), - 'SIGNALFD' : entry_handler(signalfd_entry), - 'TIMERFD' : entry_handler(timerfd_entry), - 'INOTIFY_FILE' : entry_handler(inotify_file_entry), - 'INOTIFY_WD' : entry_handler(inotify_wd_entry), - 'FANOTIFY_FILE' : entry_handler(fanotify_file_entry), - 'FANOTIFY_MARK' : entry_handler(fanotify_mark_entry), - 'VMAS' : entry_handler(vma_entry), - 'PIPES' : entry_handler(pipe_entry), - 'FIFO' : entry_handler(fifo_entry), - 'SIGACT' : entry_handler(sa_entry), - 'NETLINK_SK' : entry_handler(netlink_sk_entry), - 'REMAP_FPATH' : entry_handler(remap_file_path_entry), - 'MNTS' : entry_handler(mnt_entry), - 'TTY_FILES' : entry_handler(tty_file_entry), - 'TTY_INFO' : entry_handler(tty_info_entry), - 'TTY_DATA' : entry_handler(tty_data_entry), - 'RLIMIT' : entry_handler(rlimit_entry), - 'TUNFILE' : entry_handler(tunfile_entry), - 'EXT_FILES' : entry_handler(ext_file_entry), - 'IRMAP_CACHE' : entry_handler(irmap_cache_entry), - 'FILE_LOCKS' : entry_handler(file_lock_entry), - 'FDINFO' : entry_handler(fdinfo_entry), - 'UNIXSK' : entry_handler(unix_sk_entry), - 'INETSK' : entry_handler(inet_sk_entry), - 'PACKETSK' : entry_handler(packet_sock_entry), - 'ITIMERS' : entry_handler(itimer_entry), - 'POSIX_TIMERS' : entry_handler(posix_timer_entry), - 'NETDEV' : entry_handler(net_device_entry), - 'PIPES_DATA' : entry_handler(pipe_data_entry, pipes_data_extra_handler()), - 'FIFO_DATA' : entry_handler(pipe_data_entry, pipes_data_extra_handler()), - 'SK_QUEUES' : entry_handler(sk_packet_entry, sk_queues_extra_handler()), - 'IPCNS_SHM' : entry_handler(ipc_shm_entry, ipc_shm_handler()), - 'IPCNS_SEM' : entry_handler(ipc_sem_entry, ipc_sem_set_handler()), - 'IPCNS_MSG' : entry_handler(ipc_msg_entry, ipc_msg_queue_handler()), - 'NETNS' : entry_handler(netns_entry), - 'USERNS' : entry_handler(userns_entry), - 'SECCOMP' : entry_handler(seccomp_entry), - 'AUTOFS' : entry_handler(autofs_entry), - 'FILES' : entry_handler(file_entry), - 'CPUINFO' : entry_handler(cpuinfo_entry), + 'PSTREE' : entry_handler(pb.pstree_entry), + 'REG_FILES' : entry_handler(pb.reg_file_entry), + 'NS_FILES' : entry_handler(pb.ns_file_entry), + 'EVENTFD_FILE' : entry_handler(pb.eventfd_file_entry), + 'EVENTPOLL_FILE' : entry_handler(pb.eventpoll_file_entry), + 'EVENTPOLL_TFD' : entry_handler(pb.eventpoll_tfd_entry), + 'SIGNALFD' : entry_handler(pb.signalfd_entry), + 'TIMERFD' : entry_handler(pb.timerfd_entry), + 'INOTIFY_FILE' : entry_handler(pb.inotify_file_entry), + 'INOTIFY_WD' : entry_handler(pb.inotify_wd_entry), + 'FANOTIFY_FILE' : entry_handler(pb.fanotify_file_entry), + 'FANOTIFY_MARK' : entry_handler(pb.fanotify_mark_entry), + 'VMAS' : entry_handler(pb.vma_entry), + 'PIPES' : entry_handler(pb.pipe_entry), + 'FIFO' : entry_handler(pb.fifo_entry), + 'SIGACT' : entry_handler(pb.sa_entry), + 'NETLINK_SK' : entry_handler(pb.netlink_sk_entry), + 'REMAP_FPATH' : entry_handler(pb.remap_file_path_entry), + 'MNTS' : entry_handler(pb.mnt_entry), + 'TTY_FILES' : entry_handler(pb.tty_file_entry), + 'TTY_INFO' : entry_handler(pb.tty_info_entry), + 'TTY_DATA' : entry_handler(pb.tty_data_entry), + 'RLIMIT' : entry_handler(pb.rlimit_entry), + 'TUNFILE' : entry_handler(pb.tunfile_entry), + 'EXT_FILES' : entry_handler(pb.ext_file_entry), + 'IRMAP_CACHE' : entry_handler(pb.irmap_cache_entry), + 'FILE_LOCKS' : entry_handler(pb.file_lock_entry), + 'FDINFO' : entry_handler(pb.fdinfo_entry), + 'UNIXSK' : entry_handler(pb.unix_sk_entry), + 'INETSK' : entry_handler(pb.inet_sk_entry), + 'PACKETSK' : entry_handler(pb.packet_sock_entry), + 'ITIMERS' : entry_handler(pb.itimer_entry), + 'POSIX_TIMERS' : entry_handler(pb.posix_timer_entry), + 'NETDEV' : entry_handler(pb.net_device_entry), + 'PIPES_DATA' : entry_handler(pb.pipe_data_entry, pipes_data_extra_handler()), + 'FIFO_DATA' : entry_handler(pb.pipe_data_entry, pipes_data_extra_handler()), + 'SK_QUEUES' : entry_handler(pb.sk_packet_entry, sk_queues_extra_handler()), + 'IPCNS_SHM' : entry_handler(pb.ipc_shm_entry, ipc_shm_handler()), + 'IPCNS_SEM' : entry_handler(pb.ipc_sem_entry, ipc_sem_set_handler()), + 'IPCNS_MSG' : entry_handler(pb.ipc_msg_entry, ipc_msg_queue_handler()), + 'NETNS' : entry_handler(pb.netns_entry), + 'USERNS' : entry_handler(pb.userns_entry), + 'SECCOMP' : entry_handler(pb.seccomp_entry), + 'AUTOFS' : entry_handler(pb.autofs_entry), + 'FILES' : entry_handler(pb.file_entry), + 'CPUINFO' : entry_handler(pb.cpuinfo_entry), } def __rhandler(f): diff --git a/scripts/magic-gen.py b/scripts/magic-gen.py index 14a155a43..7088f634d 100755 --- a/scripts/magic-gen.py +++ b/scripts/magic-gen.py @@ -1,6 +1,5 @@ #!/bin/env python2 -import os, sys -import struct +import sys # This program parses criu magic.h file and produces # magic.py with all *_MAGIC constants except RAW and V1. diff --git a/soccr/test/tcp-test.py b/soccr/test/tcp-test.py index b7e8ee6d3..f401fc067 100755 --- a/soccr/test/tcp-test.py +++ b/soccr/test/tcp-test.py @@ -1,6 +1,6 @@ #!/usr/bin/env python2 -import os, sys, socket +import sys, socket import hashlib sk = socket.fromfd(3, socket.AF_INET, socket.SOCK_STREAM) diff --git a/test/crit-recode.py b/test/crit-recode.py index 0cb3341d3..441f7757e 100755 --- a/test/crit-recode.py +++ b/test/crit-recode.py @@ -5,7 +5,6 @@ import pycriu import sys import os import subprocess -import json find = subprocess.Popen(['find', 'test/dump/', '-size', '+0', '-name', '*.img'], stdout = subprocess.PIPE) diff --git a/test/exhaustive/unix.py b/test/exhaustive/unix.py index b3f40620e..24d245d8f 100755 --- a/test/exhaustive/unix.py +++ b/test/exhaustive/unix.py @@ -4,7 +4,6 @@ import sys import os import socket import argparse -import time import subprocess import signal import fcntl diff --git a/test/others/rpc/errno.py b/test/others/rpc/errno.py index f2a29914c..20937a0bf 100755 --- a/test/others/rpc/errno.py +++ b/test/others/rpc/errno.py @@ -1,7 +1,7 @@ #!/usr/bin/python2 # Test criu errno -import socket, os, imp, sys, errno +import socket, os, errno import rpc_pb2 as rpc import argparse diff --git a/test/others/rpc/ps_test.py b/test/others/rpc/ps_test.py index a8f9d825f..d40dbf090 100755 --- a/test/others/rpc/ps_test.py +++ b/test/others/rpc/ps_test.py @@ -1,6 +1,6 @@ #!/usr/bin/python2 -import socket, os, imp, sys, errno +import socket, os, sys, errno import rpc_pb2 as rpc import argparse diff --git a/test/others/rpc/restore-loop.py b/test/others/rpc/restore-loop.py index 1ea9bf320..2577a9949 100755 --- a/test/others/rpc/restore-loop.py +++ b/test/others/rpc/restore-loop.py @@ -1,6 +1,6 @@ #!/usr/bin/python2 -import socket, os, imp, sys +import socket, os, sys import rpc_pb2 as rpc import argparse diff --git a/test/others/rpc/test.py b/test/others/rpc/test.py index 63eef378e..56f03b038 100755 --- a/test/others/rpc/test.py +++ b/test/others/rpc/test.py @@ -1,6 +1,6 @@ #!/usr/bin/python2 -import socket, os, imp, sys +import socket, os, sys import rpc_pb2 as rpc import argparse diff --git a/test/others/rpc/version.py b/test/others/rpc/version.py index 93975f4ba..7c2cc2cdb 100755 --- a/test/others/rpc/version.py +++ b/test/others/rpc/version.py @@ -3,7 +3,6 @@ import socket import sys import rpc_pb2 as rpc -import argparse import subprocess print('Connecting to CRIU in swrk mode to check the version:') diff --git a/test/others/shell-job/run.py b/test/others/shell-job/run.py index 9e87d12e4..4f4dfadef 100755 --- a/test/others/shell-job/run.py +++ b/test/others/shell-job/run.py @@ -1,6 +1,6 @@ #!/usr/bin/env python2 import os, pty, sys, subprocess -import termios, fcntl, time, signal +import termios, fcntl, time cr_bin = "../../../criu/criu" @@ -62,4 +62,3 @@ pid, status = os.wait() if status != 0: print("A child process exited with %d" % status) sys.exit(1) - From 147660f02f0cbf1c20623b6312c426cb60c3f3a4 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 23 Sep 2018 15:31:52 +0100 Subject: [PATCH 1783/4375] Convert to python3 style print() syntax Use __future__ imports to keep this working for python2 Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- soccr/test/run.py | 8 ++-- soccr/test/tcp-test.py | 7 ++-- test/check_actions.py | 4 +- test/exhaustive/pipe.py | 26 ++++++------- test/exhaustive/unix.py | 67 ++++++++++++++++----------------- test/inhfd/fifo.py | 2 +- test/others/ext-tty/run.py | 4 +- test/others/mounts/mounts.py | 4 +- test/others/rpc/errno.py | 16 ++++---- test/others/rpc/ps_test.py | 20 +++++----- test/others/rpc/restore-loop.py | 8 ++-- test/others/rpc/test.py | 10 ++--- test/others/rpc/version.py | 2 +- 13 files changed, 89 insertions(+), 89 deletions(-) diff --git a/soccr/test/run.py b/soccr/test/run.py index c4d81fbd2..a25c29263 100644 --- a/soccr/test/run.py +++ b/soccr/test/run.py @@ -12,7 +12,7 @@ dst = os.getenv("TCP_DST", "127.0.0.1") sport = os.getenv("TCP_SPORT", "12345") dport = os.getenv("TCP_DPORT", "54321") -print sys.argv[1] +print(sys.argv[1]) args = [sys.argv[1], "--addr", src, "--port", sport, "--seq", "555", "--next", @@ -41,7 +41,7 @@ m.update(str2) str2 = m.hexdigest() if str2 != eval(s): - print "FAIL", repr(str2), repr(s) + print("FAIL", repr(str2), repr(s)) sys.exit(5); s = p1.stdout.read() @@ -51,7 +51,7 @@ str1 = m.hexdigest() s = p2.stdout.read() if str1 != eval(s): - print "FAIL", repr(str1), s + print("FAIL", repr(str1), s) sys.exit(5); if p1.wait(): @@ -59,4 +59,4 @@ if p1.wait(): if p2.wait(): sys.exit(1) -print "PASS" +print("PASS") diff --git a/soccr/test/tcp-test.py b/soccr/test/tcp-test.py index f401fc067..ff3fe29dc 100755 --- a/soccr/test/tcp-test.py +++ b/soccr/test/tcp-test.py @@ -1,5 +1,6 @@ #!/usr/bin/env python2 +from __future__ import print_function import sys, socket import hashlib @@ -7,13 +8,13 @@ sk = socket.fromfd(3, socket.AF_INET, socket.SOCK_STREAM) s = sys.stdin.read() ret = sk.send(s) -print >> sys.stderr, "%s: send() -> %d" % (sys.argv[1], ret) +print("%s: send() -> %d" % (sys.argv[1], ret), file=sys.stderr) sk.shutdown(socket.SHUT_WR) m = hashlib.md5() while True: s = sk.recv((1 << 20) * 10) if not s: break - print >> sys.stderr, "%s: recv() -> %d" % (sys.argv[1], len(s)) + print("%s: recv() -> %d" % (sys.argv[1], len(s)), file=sys.stderr) m.update(s) -print repr(m.hexdigest()) +print(repr(m.hexdigest())) diff --git a/test/check_actions.py b/test/check_actions.py index 96c07a758..0e3daf178 100755 --- a/test/check_actions.py +++ b/test/check_actions.py @@ -34,7 +34,7 @@ if actions: if errors: for x in errors: - print x + print(x) sys.exit(1) -print 'PASS' +print('PASS') diff --git a/test/exhaustive/pipe.py b/test/exhaustive/pipe.py index 47c052efa..b4453129a 100755 --- a/test/exhaustive/pipe.py +++ b/test/exhaustive/pipe.py @@ -34,7 +34,7 @@ def mix(nr_tasks, nr_pipes): # Called by a test sub-process. It just closes the not needed ends # of pipes and sleeps waiting for death. def make_pipes(task_nr, nr_pipes, pipes, comb, status_pipe): - print '\t\tMake pipes for %d' % task_nr + print('\t\tMake pipes for %d' % task_nr) # We need to make sure that pipes have their # ends according to comb for task_nr @@ -134,7 +134,7 @@ def check_pipes(kids, pipes, comb): # and waits for a signal (unix socket message) to start checking # the kids' FD tables. def make_comb(comb, opts, status_pipe): - print '\tMake pipes' + print('\tMake pipes') # 1st -- make needed pipes pipes = [] for p in xrange(0, opts.pipes): @@ -168,7 +168,7 @@ def make_comb(comb, opts, status_pipe): ex_code = 1 if k_res == '0' * opts.tasks: - print '\tWait for C/R' + print('\tWait for C/R') cmd_sk = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) cmd_sk.bind('\0CRIUPCSK') @@ -178,12 +178,12 @@ def make_comb(comb, opts, status_pipe): os.close(status_pipe) v = cmd_sk.recv(16) if v == '0': - print '\tCheck pipes' + print('\tCheck pipes') res = check_pipes(kids, pipes, comb) if res == None: ex_code = 0 else: - print '\tFAIL %s' % res + print('\tFAIL %s' % res) # Just kill kids, all checks are done by us, we don't need'em any more for t in kids: @@ -194,27 +194,27 @@ def make_comb(comb, opts, status_pipe): def cr_test(pid): - print 'C/R test' + print('C/R test') img_dir = 'pimg_%d' % pid try: os.mkdir(img_dir) subprocess.check_call([criu_bin, 'dump', '-t', '%d' % pid, '-D', img_dir, '-o', 'dump.log', '-v4', '-j']) except: - print '`- dump fail' + print('`- dump fail') return False try: os.waitpid(pid, 0) subprocess.check_call([criu_bin, 'restore', '-D', img_dir, '-o', 'rst.log', '-v4', '-j', '-d', '-S']) except: - print '`- restore fail' + print('`- restore fail') return False return True def run(comb, opts): - print 'Checking %r' % comb + print('Checking %r' % comb) cpipe = os.pipe() pid = os.fork() if pid == 0: @@ -230,7 +230,7 @@ def run(comb, opts): if res == '0': res = cr_test(pid) - print 'Wake up test' + print('Wake up test') s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) if res: res = '0' @@ -249,7 +249,7 @@ def run(comb, opts): if os.WIFEXITED(st): st = os.WEXITSTATUS(st) - print 'Done (%d, pid == %d)' % (st, pid) + print('Done (%d, pid == %d)' % (st, pid)) return st == 0 @@ -264,7 +264,7 @@ pipe_combs = mix(opts.tasks, opts.pipes) for comb in pipe_combs: if not run(comb, opts): - print 'FAIL' + print('FAIL') break else: - print 'PASS' + print('PASS') diff --git a/test/exhaustive/unix.py b/test/exhaustive/unix.py index 24d245d8f..6b1ed85d8 100755 --- a/test/exhaustive/unix.py +++ b/test/exhaustive/unix.py @@ -471,10 +471,10 @@ def chk_real_state(st): try: s_st = os.fstat(rsk.fileno()) except: - print 'FAIL: Socket %d lost' % sk.sk_id + print('FAIL: Socket %d lost' % sk.sk_id) return CHK_FAIL_SOCKET if not stat.S_ISSOCK(s_st.st_mode): - print 'FAIL: Not a socket %d at %d' % (sk.sk_id, rsk.fileno()) + print('FAIL: Not a socket %d at %d' % (sk.sk_id, rsk.fileno())) return CHK_FAIL_STAT # First -- check the listen states and names @@ -485,16 +485,16 @@ def chk_real_state(st): rsk = st.real_sockets[sk.sk_id] r_listen = rsk.getsockopt(socket.SOL_SOCKET, socket.SO_ACCEPTCONN) if (sk.listen and r_listen == 0) or (not sk.listen and r_listen == 1): - print "FAIL: Socket %d listen %d, expected %d" % \ - (sk.sk_id, r_listen, sk.listen and 1 or 0) + print("FAIL: Socket %d listen %d, expected %d" + % (sk.sk_id, r_listen, sk.listen and 1 or 0)) return CHK_FAIL_LISTEN if sk.name: r_name = rsk.getsockname() w_name = sock.real_name_for(sk.name) if r_name != w_name: - print 'FAIL: Socket %d name mismatch [%s], want [%s]' % \ - (sk.sk_id, r_name, w_name) + print('FAIL: Socket %d name mismatch [%s], want [%s]' + % (sk.sk_id, r_name, w_name)) return CHK_FAIL_NAME # Second -- check (accept) pending connections @@ -513,10 +513,10 @@ def chk_real_state(st): try: acc.do(st) except: - print 'FAIL: Cannot accept pending connection for %d' % sk.sk_id + print('FAIL: Cannot accept pending connection for %d' % sk.sk_id) return CHK_FAIL_ACCEPT - print ' `- did %s' % acc.show() + print(' `- did %s' % acc.show()) # Third -- check inqueues for sk in st.sockets: @@ -531,18 +531,18 @@ def chk_real_state(st): try: r_msg, m_from = rsk.recvfrom(128) except: - print 'FAIL: No message in queue for %d' % sk.sk_id + print('FAIL: No message in queue for %d' % sk.sk_id) return CHK_FAIL_RECV_0 w_msg = act_sendmsg.msgval(msg[1]) if r_msg != w_msg: - print 'FAIL: Message misorder: %s want %s (from %d)' % \ - (r_msg, w_msg, msg[0]) + print('FAIL: Message misorder: %s want %s (from %d)' + %(r_msg, w_msg, msg[0])) return CHK_FAIL_RECV_MIX # TODO -- check sender - print ' `- recvd %d.%d msg %s -> %d' % \ - (msg[0], msg[1], m_from, sk.sk_id) + print(' `- recvd %d.%d msg %s -> %d' + % (msg[0], msg[1], m_from, sk.sk_id)) # Finally, after all sockets are visible and all inqueues are # drained -- check the sockets connectivity @@ -563,8 +563,7 @@ def chk_real_state(st): rsk.send(msgv) rmsg = psk.recv(128) except: - print 'FAIL: Connectivity %d -> %d lost' % \ - (sk.sk_id, sk.peer) + print('FAIL: Connectivity %d -> %d lost' % (sk.sk_id, sk.peer)) return CHK_FAIL_CONNECT # If sockets are not connected the recv above @@ -573,17 +572,17 @@ def chk_real_state(st): # the hard way -- also check for the message being # delivered for real if rmsg != msgv: - print 'FAIL: Connectivity %d -> %d not verified' % \ - (sk.sk_id, sk.peer) + print('FAIL: Connectivity %d -> %d not verified' + % (sk.sk_id, sk.peer)) return CHK_FAIL_CONNECT2 - print ' `- checked %d -> %d with %s' % (sk.sk_id, sk.peer, msgv) + print(' `- checked %d -> %d with %s' % (sk.sk_id, sk.peer, msgv)) return CHK_PASS def chk_state(st, opts): - print "Will check state" + print("Will check state") sigsk_name = "\0" + "CRSIGSKC" signal_sk = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) @@ -606,25 +605,25 @@ def chk_state(st, opts): for rsk in st.real_sockets.values(): rsk.close() - print "`- dump" + print("`- dump") img_path = "sti_" + st.describe() try: os.mkdir(img_path) subprocess.check_call([criu_bin, "dump", "-t", "%d" % pid, "-D", img_path, "-v4", "-o", "dump.log", "-j"]) except: - print "Dump failed" + print("Dump failed") os.kill(pid, signal.SIGKILL) return CHK_FAIL_DUMP - print "`- restore" + print("`- restore") try: os.waitpid(pid, 0) subprocess.check_call([criu_bin, "restore", "-D", img_path, "-v4", "-o", "rst.log", "-j", "-d", "-S"]) except: - print "Restore failed" + print("Restore failed") return CHK_FAIL_RESTORE - print "`- check" + print("`- check") signal_sk = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) try: signal_sk.sendto('check', sigsk_name) @@ -636,11 +635,11 @@ def chk_state(st, opts): if os.WIFEXITED(status): status = os.WEXITSTATUS(status) if status != CHK_PASS: - print "`- exited with %d" % status + print("`- exited with %d" % status) return status elif os.WIFSIGNALED(status): status = os.WTERMSIG(status) - print "`- killed with %d" % status + print("`- killed with %d" % status) return CHK_FAIL_KILLED else: return CHK_FAIL_UNKNOWN @@ -649,7 +648,7 @@ def chk_state(st, opts): def run_state(st, opts): - print "Will run state" + print("Will run state") pid = os.fork() if pid != 0: wpid, status = os.wait() @@ -685,9 +684,9 @@ def proceed(st, seen, failed, opts, depth = 0): # using less steps and it's better to proceed as we have # depth to move forward and generate more states. seen[desc] = len(st.steps) - print '%s' % desc + print('%s' % desc) for s in st.steps: - print '\t%s' % s.show() + print('\t%s' % s.show()) if not opts.gen: ret = run_state(st, opts) @@ -731,7 +730,7 @@ opts.depth = int(opts.depth) # XXX: does it make any sense to mix two types in one go? if opts.stream and opts.dgram: - print 'Choose only one type' + print('Choose only one type') sys.exit(1) if opts.stream: @@ -739,7 +738,7 @@ if opts.stream: elif opts.dgram: sk_type = socket.SOCK_DGRAM else: - print 'Choose some type' + print('Choose some type') sys.exit(1) st = state(int(opts.sockets), sk_type) @@ -748,8 +747,8 @@ failed = set() proceed(st, seen, failed, opts) if len(failed) == 0: - print 'PASS (%d states)' % len(seen) + print('PASS (%d states)' % len(seen)) else: - print 'FAIL %d/%d' % (len(failed), len(seen)) + print('FAIL %d/%d' % (len(failed), len(seen))) for f in failed: - print "\t%-50s: %s" % (f[0], fail_desc.get(f[1], 'unknown reason %d' % f[1])) + print("\t%-50s: %s" % (f[0], fail_desc.get(f[1], 'unknown reason %d' % f[1]))) diff --git a/test/inhfd/fifo.py b/test/inhfd/fifo.py index 11703e1c0..40af371a1 100755 --- a/test/inhfd/fifo.py +++ b/test/inhfd/fifo.py @@ -13,7 +13,7 @@ def create_fds(): os.system("umount -l %s" % tdir) os.rmdir(tdir) - mnt_id = -1; + mnt_id = -1 with open("/proc/self/fdinfo/%d" % fd1.fileno()) as f: for l in f: l = l.split() diff --git a/test/others/ext-tty/run.py b/test/others/ext-tty/run.py index 052f9c1a1..f44b1d946 100755 --- a/test/others/ext-tty/run.py +++ b/test/others/ext-tty/run.py @@ -30,7 +30,7 @@ os.waitpid(-1, os.WNOHANG) # is the process alive os.close(new_master) _, status = os.wait() if not os.WIFSIGNALED(status) or os.WTERMSIG(status) != signal.SIGHUP: - print status + print(status) sys.exit(1) -print "PASS" +print("PASS") diff --git a/test/others/mounts/mounts.py b/test/others/mounts/mounts.py index 7f11d7dc0..474feed41 100755 --- a/test/others/mounts/mounts.py +++ b/test/others/mounts/mounts.py @@ -14,10 +14,10 @@ def mount(src, dst, shared, private, slave): else: cmd += " -t tmpfs none '%s'" % (dst) - print cmd + print(cmd) ret = os.system(cmd) if ret: - print "failed" + print("failed") root = tempfile.mkdtemp(prefix = "root.mount", dir = "/tmp") mount(None, root, 1, 0, 0) diff --git a/test/others/rpc/errno.py b/test/others/rpc/errno.py index 20937a0bf..ee9e90d8c 100755 --- a/test/others/rpc/errno.py +++ b/test/others/rpc/errno.py @@ -48,7 +48,7 @@ class test: raise Exception('Unexpected cr_errno ' + str(resp.cr_errno)) def no_process(self): - print 'Try to dump unexisting process' + print('Try to dump unexisting process') # Get pid of non-existing process. # Suppose max_pid is not taken by any process. with open("/proc/sys/kernel/pid_max", "r") as f: @@ -70,10 +70,10 @@ class test: self.check_resp(resp, rpc.DUMP, errno.ESRCH) - print 'Success' + print('Success') def process_exists(self): - print 'Try to restore process which pid is already taken by other process' + print('Try to restore process which pid is already taken by other process') # Perform self-dump req = self.get_base_req() @@ -95,10 +95,10 @@ class test: self.check_resp(resp, rpc.RESTORE, errno.EEXIST) - print 'Success' + print('Success') def bad_options(self): - print 'Try to send criu invalid opts' + print('Try to send criu invalid opts') # Subdirs are not allowed in log_file req = self.get_base_req() @@ -110,10 +110,10 @@ class test: self.check_resp(resp, rpc.DUMP, errno.EBADRQC) - print 'Success' + print('Success') def bad_request(self): - print 'Try to send criu invalid request type' + print('Try to send criu invalid request type') req = self.get_base_req() req.type = rpc.NOTIFY @@ -123,7 +123,7 @@ class test: self.check_resp(resp, rpc.EMPTY, None) - print 'Success' + print('Success') def run(self): self.no_process() diff --git a/test/others/rpc/ps_test.py b/test/others/rpc/ps_test.py index d40dbf090..1872120fc 100755 --- a/test/others/rpc/ps_test.py +++ b/test/others/rpc/ps_test.py @@ -15,7 +15,7 @@ s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) s.connect(args['socket']) # Start page-server -print 'Starting page-server' +print('Starting page-server') req = rpc.criu_req() req.type = rpc.PAGE_SERVER req.opts.log_file = 'page-server.log' @@ -29,7 +29,7 @@ MAX_MSG_SIZE = 1024 resp.ParseFromString(s.recv(MAX_MSG_SIZE)) if resp.type != rpc.PAGE_SERVER: - print 'Unexpected msg type' + print('Unexpected msg type') sys.exit(1) else: if resp.success: @@ -38,18 +38,18 @@ else: os.kill(resp.ps.pid, 0) except OSError as err: if err.errno == errno.ESRCH: - print 'No process with page-server pid %d' %(resp.ps.pid) + print('No process with page-server pid %d' %(resp.ps.pid)) else: - print 'Can\'t check that process %d exists' %(resp.ps.pid) + print('Can\'t check that process %d exists' %(resp.ps.pid)) sys.exit(1) - print 'Success, page-server pid %d started on port %u' %(resp.ps.pid, resp.ps.port) + print('Success, page-server pid %d started on port %u' %(resp.ps.pid, resp.ps.port)) else: - print 'Failed to start page-server' + print('Failed to start page-server') sys.exit(1) # Perform self-dump -print 'Dumping myself using page-server' +print('Dumping myself using page-server') req.type = rpc.DUMP req.opts.ps.port = resp.ps.port req.opts.ps.address = "127.0.0.1" @@ -64,11 +64,11 @@ s.send(req.SerializeToString()) resp.ParseFromString(s.recv(MAX_MSG_SIZE)) if resp.type != rpc.DUMP: - print 'Unexpected msg type' + print('Unexpected msg type') sys.exit(1) else: if resp.success: - print 'Success' + print('Success') else: - print 'Fail' + print('Fail') sys.exit(1) diff --git a/test/others/rpc/restore-loop.py b/test/others/rpc/restore-loop.py index 2577a9949..ce5786a56 100755 --- a/test/others/rpc/restore-loop.py +++ b/test/others/rpc/restore-loop.py @@ -34,12 +34,12 @@ MAX_MSG_SIZE = 1024 resp.ParseFromString(s.recv(MAX_MSG_SIZE)) if resp.type != rpc.RESTORE: - print 'Unexpected msg type' + print('Unexpected msg type') sys.exit(-1) else: if resp.success: - print 'Restore success' + print('Restore success') else: - print 'Restore fail' + print('Restore fail') sys.exit(-1) - print "PID of the restored program is %d\n" %(resp.restore.pid) + print("PID of the restored program is %d\n" %(resp.restore.pid)) diff --git a/test/others/rpc/test.py b/test/others/rpc/test.py index 56f03b038..fe67103ba 100755 --- a/test/others/rpc/test.py +++ b/test/others/rpc/test.py @@ -31,17 +31,17 @@ MAX_MSG_SIZE = 1024 resp.ParseFromString(s.recv(MAX_MSG_SIZE)) if resp.type != rpc.DUMP: - print 'Unexpected msg type' + print('Unexpected msg type') sys.exit(-1) else: if resp.success: - print 'Success' + print('Success') else: - print 'Fail' + print('Fail') sys.exit(-1) if resp.dump.restored: - print 'Restored' + print('Restored') # Connect to service socket s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) @@ -77,5 +77,5 @@ else: if resp.version.HasField('name'): print('CRIU name %s' % resp.version.name) else: - print 'Fail' + print('Fail') sys.exit(-1) diff --git a/test/others/rpc/version.py b/test/others/rpc/version.py index 7c2cc2cdb..5cca4e249 100755 --- a/test/others/rpc/version.py +++ b/test/others/rpc/version.py @@ -43,5 +43,5 @@ else: if resp.version.HasField('name'): print('CRIU name %s' % resp.version.name) else: - print 'Fail' + print('Fail') sys.exit(-1) From 7064cbaa350a6eb5029e71490897b7a3f6750051 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 23 Sep 2018 15:31:53 +0100 Subject: [PATCH 1784/4375] python: Remove unnecessary semicolons Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- lib/py/images/pb2dict.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index df0357bdd..18d4c68eb 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -68,14 +68,14 @@ mmap_prot_map = [ ('PROT_READ', 0x1), ('PROT_WRITE', 0x2), ('PROT_EXEC', 0x4), -]; +] mmap_flags_map = [ ('MAP_SHARED', 0x1), ('MAP_PRIVATE', 0x2), ('MAP_ANON', 0x20), ('MAP_GROWSDOWN', 0x0100), -]; +] mmap_status_map = [ ('VMA_AREA_NONE', 0 << 0), @@ -96,7 +96,7 @@ mmap_status_map = [ ('VMA_AREA_AIORING', 1 << 13), ('VMA_UNSUPP', 1 << 31), -]; +] rfile_flags_map = [ ('O_WRONLY', 0o1), @@ -104,13 +104,13 @@ rfile_flags_map = [ ('O_APPEND', 0o2000), ('O_DIRECT', 0o40000), ('O_LARGEFILE', 0o100000), -]; +] pmap_flags_map = [ ('PE_PARENT', 1 << 0), ('PE_LAZY', 1 << 1), ('PE_PRESENT', 1 << 2), -]; +] flags_maps = { 'mmap.prot' : mmap_prot_map, From c36b5dab05d7c5a7f95641379d3e12ac3dd6a861 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 23 Sep 2018 15:31:54 +0100 Subject: [PATCH 1785/4375] python: Replace xrange with range In Py2 `range` returns a list and `xrange` creates a sequence object that evaluates lazily. In Py3 `range` is equivalent to `xrange` in Py2. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- coredump/criu_coredump/coredump.py | 2 +- test/exhaustive/pipe.py | 10 +++++----- test/others/mounts/mounts.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/coredump/criu_coredump/coredump.py b/coredump/criu_coredump/coredump.py index df055dcb2..963e8c61b 100644 --- a/coredump/criu_coredump/coredump.py +++ b/coredump/criu_coredump/coredump.py @@ -625,7 +625,7 @@ class coredump_generator: off = 0# in pages for m in pagemap[1:]: found = False - for i in xrange(m["nr_pages"]): + for i in range(m["nr_pages"]): if m["vaddr"] + i*PAGESIZE == page_no*PAGESIZE: found = True break diff --git a/test/exhaustive/pipe.py b/test/exhaustive/pipe.py index b4453129a..17e065800 100755 --- a/test/exhaustive/pipe.py +++ b/test/exhaustive/pipe.py @@ -19,13 +19,13 @@ def mix(nr_tasks, nr_pipes): # First -- make a full set of combinations for a single pipe. max_idx = 1 << nr_tasks - pipe_mix = [[(r, w)] for r in xrange(0, max_idx) for w in xrange(0, max_idx)] + pipe_mix = [[(r, w)] for r in range(0, max_idx) for w in range(0, max_idx)] # Now, for every pipe throw another one into the game making # all possible combinations of what was seen before with the # newbie. pipes_mix = pipe_mix - for t in xrange(1, nr_pipes): + for t in range(1, nr_pipes): pipes_mix = [ o + n for o in pipes_mix for n in pipe_mix ] return pipes_mix @@ -38,7 +38,7 @@ def make_pipes(task_nr, nr_pipes, pipes, comb, status_pipe): # We need to make sure that pipes have their # ends according to comb for task_nr - for i in xrange(0, nr_pipes): + for i in range(0, nr_pipes): # Read end if not (comb[i][0] & (1 << task_nr)): os.close(pipes[i][0]) @@ -137,13 +137,13 @@ def make_comb(comb, opts, status_pipe): print('\tMake pipes') # 1st -- make needed pipes pipes = [] - for p in xrange(0, opts.pipes): + for p in range(0, opts.pipes): pipes.append(os.pipe()) # Fork the kids that'll make pipes kc_pipe = os.pipe() kids = [] - for t in xrange(0, opts.tasks): + for t in range(0, opts.tasks): pid = os.fork() if pid == 0: os.close(status_pipe) diff --git a/test/others/mounts/mounts.py b/test/others/mounts/mounts.py index 474feed41..dc65ba45c 100755 --- a/test/others/mounts/mounts.py +++ b/test/others/mounts/mounts.py @@ -23,7 +23,7 @@ root = tempfile.mkdtemp(prefix = "root.mount", dir = "/tmp") mount(None, root, 1, 0, 0) mounts = [root] -for i in xrange(10): +for i in range(10): dstdir = random.choice(mounts) dst = tempfile.mkdtemp(prefix = "mount", dir = dstdir) src = random.choice(mounts + [None]) From 64664bb24b765056f53a27ed312e23dbc023473a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 21 Sep 2018 11:41:43 +0300 Subject: [PATCH 1786/4375] tun: Define log prefix Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/tun.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/tun.c b/criu/tun.c index 11e82f22a..2e189c69c 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -24,6 +24,9 @@ #include "images/tun.pb-c.h" +#undef LOG_PREFIX +#define LOG_PREFIX "tun: " + #ifndef IFF_PERSIST #define IFF_PERSIST 0x0800 #endif From 348b2d1176e533d31088ed0dbc1200eb7a83ee34 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 21 Sep 2018 11:41:44 +0300 Subject: [PATCH 1787/4375] tun: Set net ns before opening master Opening tun device is tricky: the net device is allocated from current net namespace, thus we should set it first, otherwise all tuns which live in nested net namespace get moved to the toplevel one. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/tun.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/criu/tun.c b/criu/tun.c index 2e189c69c..e9c18c0ab 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -369,13 +369,14 @@ static int tunfile_open(struct file_desc *d, int *new_fd) struct tun_link *tl; ti = container_of(d, struct tunfile_info, d); - fd = open_reg_by_id(ti->tfe->id); - if (fd < 0) - return -1; ns_id = ti->tfe->ns_id; if (set_netns(ns_id)) - goto err; + return -1; + + fd = open_reg_by_id(ti->tfe->id); + if (fd < 0) + return -1; if (!ti->tfe->netdev) /* just-opened tun file */ From 19e9df29a3dd6dd2a0a23426353c6a523abaee77 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 21 Sep 2018 11:41:45 +0300 Subject: [PATCH 1788/4375] tun: Add support for multiple net ns The tun files may have same names but different net namespace so consider ns_id when searching for particluar tun device name. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/tun.h | 4 +++- criu/net.c | 2 +- criu/tun.c | 42 +++++++++++++++++++++++------------------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/criu/include/tun.h b/criu/include/tun.h index 2ccd007c2..ce0b266a6 100644 --- a/criu/include/tun.h +++ b/criu/include/tun.h @@ -5,6 +5,8 @@ #define TUN_MINOR 200 #endif +struct ns_id *ns; + #include #include "images/netdev.pb-c.h" @@ -12,7 +14,7 @@ extern const struct fdtype_ops tunfile_dump_ops; extern int dump_tun_link(NetDeviceEntry *nde, struct cr_imgset *fds, struct nlattr **info); struct net_link; -extern int restore_one_tun(struct net_link *link, int nlsk); +extern int restore_one_tun(struct ns_id *ns, struct net_link *link, int nlsk); extern struct collect_image_info tunfile_cinfo; extern int check_tun_cr(int no_tun_err); extern int check_tun_netns_cr(bool *result); diff --git a/criu/net.c b/criu/net.c index 40bf47b32..3eebf48bc 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1524,7 +1524,7 @@ static int __restore_link(struct ns_id *ns, struct net_link *link, int nlsk) case ND_TYPE__VETH: return restore_one_link(ns, link, nlsk, veth_link_info, NULL); case ND_TYPE__TUN: - return restore_one_tun(link, nlsk); + return restore_one_tun(ns, link, nlsk); case ND_TYPE__BRIDGE: return restore_one_link(ns, link, nlsk, bridge_link_info, NULL); case ND_TYPE__MACVLAN: diff --git a/criu/tun.c b/criu/tun.c index e9c18c0ab..b13148b0b 100644 --- a/criu/tun.c +++ b/criu/tun.c @@ -100,6 +100,7 @@ static LIST_HEAD(tun_links); struct tun_link { char name[IFNAMSIZ]; struct list_head l; + unsigned ns_id; union { struct { unsigned flags; @@ -112,7 +113,7 @@ struct tun_link { }; }; -static int list_tun_link(NetDeviceEntry *nde) +static int list_tun_link(NetDeviceEntry *nde, unsigned ns_id) { struct tun_link *tl; @@ -128,22 +129,24 @@ static int list_tun_link(NetDeviceEntry *nde) * with (i.e. -- with which it was created. */ tl->rst.flags = nde->tun->flags; + tl->ns_id = ns_id; list_add_tail(&tl->l, &tun_links); return 0; } -static struct tun_link *find_tun_link(char *name) +static struct tun_link *find_tun_link(char *name, unsigned int ns_id) { struct tun_link *tl; - list_for_each_entry(tl, &tun_links, l) - if (!strcmp(tl->name, name)) + list_for_each_entry(tl, &tun_links, l) { + if (!strcmp(tl->name, name) && + tl->ns_id == ns_id) return tl; - + } return NULL; } -static struct tun_link *__dump_tun_link_fd(int fd, char *name, unsigned flags) +static struct tun_link *__dump_tun_link_fd(int fd, char *name, unsigned ns_id, unsigned flags) { struct tun_link *tl; struct sock_fprog flt; @@ -152,6 +155,7 @@ static struct tun_link *__dump_tun_link_fd(int fd, char *name, unsigned flags) if (!tl) goto err; strlcpy(tl->name, name, sizeof(tl->name)); + tl->ns_id = ns_id; if (ioctl(fd, TUNGETVNETHDRSZ, &tl->dmp.vnethdr) < 0) { pr_perror("Can't dump vnethdr size for %s", name); @@ -193,16 +197,16 @@ err: return NULL; } -static struct tun_link *dump_tun_link_fd(int fd, char *name, unsigned flags) +static struct tun_link *dump_tun_link_fd(int fd, char *name, unsigned ns_id, unsigned flags) { struct tun_link *tl; - tl = find_tun_link(name); + tl = find_tun_link(name, ns_id); if (tl) return tl; - tl = __dump_tun_link_fd(fd, name, flags); - if (tl) + tl = __dump_tun_link_fd(fd, name, ns_id, flags); + if (tl) { /* * Keep this in list till links dumping code starts. * We can't let it dump all this stuff itself, since @@ -213,7 +217,7 @@ static struct tun_link *dump_tun_link_fd(int fd, char *name, unsigned flags) * will attach to the device and get the needed stuff. */ list_add(&tl->l, &tun_links); - + } return tl; } @@ -252,12 +256,12 @@ err: return -1; } -static struct tun_link *get_tun_link_fd(char *name, unsigned flags) +static struct tun_link *get_tun_link_fd(char *name, unsigned ns_id, unsigned flags) { struct tun_link *tl; int fd; - tl = find_tun_link(name); + tl = find_tun_link(name, ns_id); if (tl) return tl; @@ -283,7 +287,7 @@ static struct tun_link *get_tun_link_fd(char *name, unsigned flags) if (fd < 0) return NULL; - tl = __dump_tun_link_fd(fd, name, flags); + tl = __dump_tun_link_fd(fd, name, ns_id, flags); close(fd); return tl; @@ -339,7 +343,7 @@ static int dump_tunfile(int lfd, u32 id, const struct fd_parms *p) tfe.detached = true; } - if (dump_tun_link_fd(lfd, tfe.netdev, ifr.ifr_flags) == NULL) + if (dump_tun_link_fd(lfd, tfe.netdev, tfe.ns_id, ifr.ifr_flags) == NULL) return -1; } @@ -382,7 +386,7 @@ static int tunfile_open(struct file_desc *d, int *new_fd) /* just-opened tun file */ goto ok; - tl = find_tun_link(ti->tfe->netdev); + tl = find_tun_link(ti->tfe->netdev, ns_id); if (!tl) { pr_err("No tun device for file %s\n", ti->tfe->netdev); goto err; @@ -469,7 +473,7 @@ int dump_tun_link(NetDeviceEntry *nde, struct cr_imgset *fds, struct nlattr **in if (ret < 0) return ret; - tl = get_tun_link_fd(nde->name, tle.flags); + tl = get_tun_link_fd(nde->name, nde->peer_nsid, tle.flags); if (!tl) return ret; @@ -480,7 +484,7 @@ int dump_tun_link(NetDeviceEntry *nde, struct cr_imgset *fds, struct nlattr **in return write_netdev_img(nde, fds, info); } -int restore_one_tun(struct net_link *link, int nlsk) +int restore_one_tun(struct ns_id *ns, struct net_link *link, int nlsk) { NetDeviceEntry *nde = link->nde; int fd, ret = -1, aux; @@ -536,7 +540,7 @@ int restore_one_tun(struct net_link *link, int nlsk) goto out; } - ret = list_tun_link(nde); + ret = list_tun_link(nde, ns->id); out: close(fd); return ret; From 0fb2f0e56a4e5449f649c4620630838ed5c2f881 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Thu, 20 Sep 2018 22:41:12 +0000 Subject: [PATCH 1789/4375] soccr: print errno if connect() failed https://github.com/checkpoint-restore/criu/issues/557 Signed-off-by: Andrei Vagin Acked-by: Adrian Reber Signed-off-by: Andrei Vagin --- soccr/soccr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soccr/soccr.c b/soccr/soccr.c index d63a2ce2b..1e4827e48 100644 --- a/soccr/soccr.c +++ b/soccr/soccr.c @@ -526,7 +526,7 @@ static int libsoccr_set_sk_data_noq(struct libsoccr_sk *sk, if (connect(sk->fd, &sk->dst_addr->sa, addr_size) == -1 && errno != EINPROGRESS) { - loge("Can't connect inet socket back\n"); + logerr("Can't connect inet socket back"); return -1; } From a3a42a4ce706bebf268a6dffe622b8c6747b160b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Sep 2018 22:57:44 +0300 Subject: [PATCH 1790/4375] compiler: Add NELEMS_AS_ARRAY helper To count elems in accumulator. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- include/common/compiler.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/common/compiler.h b/include/common/compiler.h index eaf545b26..fc8abcfef 100644 --- a/include/common/compiler.h +++ b/include/common/compiler.h @@ -8,6 +8,7 @@ */ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#define NELEMS_AS_ARRAY(x,y) (sizeof(x) / sizeof((y)[0])) #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) #define ASSIGN_TYPED(a, b) do { (a) = (typeof(a))(b); } while (0) From 18cb72ac0c1a232a9aaaf4bdfb2d8fa10cd9943b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Sep 2018 22:57:56 +0300 Subject: [PATCH 1791/4375] net: Add prefixes for better logging Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 3 +++ criu/sk-netlink.c | 3 +++ criu/sk-packet.c | 3 +++ criu/sk-queue.c | 3 +++ criu/sk-tcp.c | 2 ++ criu/sockets.c | 3 +++ 6 files changed, 17 insertions(+) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index a5a092bc7..fcc242644 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -28,6 +28,9 @@ #include "util.h" #include "namespaces.h" +#undef LOG_PREFIX +#define LOG_PREFIX "inet: " + #define PB_ALEN_INET 1 #define PB_ALEN_INET6 4 diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c index f26c4dec0..e4163f538 100644 --- a/criu/sk-netlink.c +++ b/criu/sk-netlink.c @@ -14,6 +14,9 @@ #include "libnetlink.h" #include "namespaces.h" +#undef LOG_PREFIX +#define LOG_PREFIX "netlink: " + struct netlink_sk_desc { struct socket_desc sd; u32 portid; diff --git a/criu/sk-packet.c b/criu/sk-packet.c index 796aa6e83..0abe84071 100644 --- a/criu/sk-packet.c +++ b/criu/sk-packet.c @@ -22,6 +22,9 @@ #include "images/fdinfo.pb-c.h" #include "namespaces.h" +#undef LOG_PREFIX +#define LOG_PREFIX "packet: " + struct packet_sock_info { PacketSockEntry *pse; struct file_desc d; diff --git a/criu/sk-queue.c b/criu/sk-queue.c index 4ce8ccf45..d19de7504 100644 --- a/criu/sk-queue.c +++ b/criu/sk-queue.c @@ -24,6 +24,9 @@ #include "protobuf.h" #include "images/sk-packet.pb-c.h" +#undef LOG_PREFIX +#define LOG_PREFIX "skqueue: " + struct sk_packet { struct list_head list; SkPacketEntry *entry; diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c index 353125f2b..4fd2eb8e6 100644 --- a/criu/sk-tcp.c +++ b/criu/sk-tcp.c @@ -27,6 +27,8 @@ #include "protobuf.h" #include "images/tcp-stream.pb-c.h" +#undef LOG_PREFIX +#define LOG_PREFIX "tcp: " static LIST_HEAD(cpt_tcp_repair_sockets); static LIST_HEAD(rst_tcp_repair_sockets); diff --git a/criu/sockets.c b/criu/sockets.c index bda5e445b..574d83b8e 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -29,6 +29,9 @@ #include "util.h" #include "fdstore.h" +#undef LOG_PREFIX +#define LOG_PREFIX "sockets: " + #ifndef SOCK_DIAG_BY_FAMILY #define SOCK_DIAG_BY_FAMILY 20 #endif From e238854f4e9d051ee5e1cf592e76085b37ee5cd5 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 14 Sep 2018 11:37:05 +0300 Subject: [PATCH 1792/4375] sockets: Improve helpers to make sockets more readable Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/sockets.h | 24 +++++++++- criu/sk-unix.c | 13 +++-- criu/sockets.c | 105 +++++++++++++++++++++++++++-------------- 3 files changed, 99 insertions(+), 43 deletions(-) diff --git a/criu/include/sockets.h b/criu/include/sockets.h index 371d1a509..c6204d189 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -1,6 +1,7 @@ #ifndef __CR_SOCKETS_H__ #define __CR_SOCKETS_H__ +#include #include #include @@ -96,7 +97,26 @@ extern int set_netns(uint32_t ns_id); extern int kerndat_socket_netns(void); extern int kerndat_socket_unix_file(void); -extern const char *tcp_state_name(unsigned int state); -extern const char *socket_type_name(unsigned int type); +extern const char *tcp_state_name(unsigned int state, char *nm, size_t size); +extern const char *socket_type_name(unsigned int type, char *nm, size_t size); +extern const char *socket_family_name(unsigned int family, char *nm, size_t size); +extern const char *socket_proto_name(unsigned int proto, char *nm, size_t size); + +#define __tcp_state_name(state, a) tcp_state_name(state, a, sizeof(a)) +#define __socket_type_name(type, a) socket_type_name(type, a, sizeof(a)) +#define __socket_family_name(family, a) socket_family_name(family, a, sizeof(a)) +#define __socket_proto_name(proto, a) socket_proto_name(proto, a, sizeof(a)) + +#define __socket_info_helper(__h, __v) \ + ({ \ + char *__nm = alloca(32); \ + const char *__r = __h(__v, __nm, 32); \ + __r; \ + }) + +#define ___tcp_state_name(state) __socket_info_helper(tcp_state_name, state) +#define ___socket_type_name(type) __socket_info_helper(socket_type_name, type) +#define ___socket_family_name(family) __socket_info_helper(socket_family_name, family) +#define ___socket_proto_name(proto) __socket_info_helper(socket_proto_name, proto) #endif /* __CR_SOCKETS_H__ */ diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 2091cad2f..90124ed07 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -2060,9 +2060,12 @@ int unix_prepare_root_shared(void) pr_debug("ghost: Resolving addresses\n"); list_for_each_entry(ui, &unix_ghost_addr, ghost_node) { + char tp_name[32]; + char st_name[32]; + pr_debug("ghost: id %#x type %s state %s ino %d peer %d address %s\n", - ui->ue->id, socket_type_name(ui->ue->type), - tcp_state_name(ui->ue->state), + ui->ue->id, __socket_type_name(ui->ue->type, tp_name), + __tcp_state_name(ui->ue->state, st_name), ui->ue->ino, ui->peer ? ui->peer->ue->ino : 0, ui->name); @@ -2109,9 +2112,9 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) } pr_info(" `- Got id %#x ino %d type %s state %s peer %d (name %s%.*s dir %s)\n", - ui->ue->id, ui->ue->ino, socket_type_name(ui->ue->type), - tcp_state_name(ui->ue->state), ui->ue->peer, prefix, ulen, uname, - ui->name_dir ? ui->name_dir : "-"); + ui->ue->id, ui->ue->ino, ___socket_type_name(ui->ue->type), + ___tcp_state_name(ui->ue->state), ui->ue->peer, prefix, ulen, + uname, ui->name_dir ? ui->name_dir : "-"); if (ui->ue->peer || ui->name) { if (ui->ue->peer) diff --git a/criu/sockets.c b/criu/sockets.c index 574d83b8e..9de00df63 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -42,48 +42,81 @@ #define SO_GET_FILTER SO_ATTACH_FILTER #endif -const char *socket_type_name(unsigned int type) +static const char *__socket_const_name(char *dst, size_t len, const char **a, size_t n, unsigned int v) { - static const char *types[] = { - [SOCK_STREAM] = __stringify_1(SOCK_STREAM), - [SOCK_DGRAM] = __stringify_1(SOCK_DGRAM), - [SOCK_RAW] = __stringify_1(SOCK_RAW), - [SOCK_SEQPACKET] = __stringify_1(SOCK_SEQPACKET), - [SOCK_PACKET] = __stringify_1(SOCK_PACKET), - }; - size_t i; - - for (i = 0; i < ARRAY_SIZE(types); i++) { - if (type == i) - return types[i]; - } - - return "UNKNOWN"; + if (v < n) { + const char *name = a[v]; + if (name) + return name; + } + snprintf(dst, len, "%u", v); + return dst; } -const char *tcp_state_name(unsigned int state) +const char *socket_proto_name(unsigned int proto, char *nm, size_t size) { - static const char *states[] = { - [TCP_ESTABLISHED] = __stringify_1(TCP_ESTABLISHED), - [TCP_SYN_SENT] = __stringify_1(TCP_SYN_SENT), - [TCP_SYN_RECV] = __stringify_1(TCP_SYN_RECV), - [TCP_FIN_WAIT1] = __stringify_1(TCP_FIN_WAIT1), - [TCP_FIN_WAIT2] = __stringify_1(TCP_FIN_WAIT2), - [TCP_TIME_WAIT] = __stringify_1(TCP_TIME_WAIT), - [TCP_CLOSE] = __stringify_1(TCP_CLOSE), - [TCP_CLOSE_WAIT] = __stringify_1(TCP_CLOSE_WAIT), - [TCP_LAST_ACK] = __stringify_1(TCP_LAST_ACK), - [TCP_LISTEN] = __stringify_1(TCP_LISTEN), - [TCP_CLOSING] = __stringify_1(TCP_CLOSING), - }; - size_t i; + static const char *protos[] = { + [IPPROTO_IP] = __stringify_1(IPPROTO_IP), + [IPPROTO_ICMP] = __stringify_1(IPPROTO_ICMP), + [IPPROTO_IGMP] = __stringify_1(IPPROTO_IGMP), + [IPPROTO_IPIP] = __stringify_1(IPPROTO_IPIP), + [IPPROTO_TCP] = __stringify_1(IPPROTO_TCP), + [IPPROTO_EGP] = __stringify_1(IPPROTO_EGP), + [IPPROTO_UDP] = __stringify_1(IPPROTO_UDP), + [IPPROTO_DCCP] = __stringify_1(IPPROTO_DCCP), + [IPPROTO_IPV6] = __stringify_1(IPPROTO_IPV6), + [IPPROTO_RSVP] = __stringify_1(IPPROTO_RSVP), + [IPPROTO_GRE] = __stringify_1(IPPROTO_GRE), + [IPPROTO_ESP] = __stringify_1(IPPROTO_ESP), + [IPPROTO_AH] = __stringify_1(IPPROTO_AH), + [IPPROTO_UDPLITE] = __stringify_1(IPPROTO_UDPLITE), + [IPPROTO_RAW] = __stringify_1(IPPROTO_RAW), + }; + return __socket_const_name(nm, size, protos, ARRAY_SIZE(protos), proto); +} - for (i = 0; i < ARRAY_SIZE(states); i++) { - if (state == i) - return states[i]; - } +const char *socket_family_name(unsigned int family, char *nm, size_t size) +{ + static const char *families[] = { + [AF_UNIX] = __stringify_1(AF_UNIX), + [AF_INET] = __stringify_1(AF_INET), + [AF_BRIDGE] = __stringify_1(AF_BRIDGE), + [AF_INET6] = __stringify_1(AF_INET6), + [AF_KEY] = __stringify_1(AF_KEY), + [AF_NETLINK] = __stringify_1(AF_NETLINK), + [AF_PACKET] = __stringify_1(AF_PACKET), + }; + return __socket_const_name(nm, size, families, ARRAY_SIZE(families), family); +} - return "UNKNOWN"; +const char *socket_type_name(unsigned int type, char *nm, size_t size) +{ + static const char *types[] = { + [SOCK_STREAM] = __stringify_1(SOCK_STREAM), + [SOCK_DGRAM] = __stringify_1(SOCK_DGRAM), + [SOCK_RAW] = __stringify_1(SOCK_RAW), + [SOCK_SEQPACKET] = __stringify_1(SOCK_SEQPACKET), + [SOCK_PACKET] = __stringify_1(SOCK_PACKET), + }; + return __socket_const_name(nm, size, types, ARRAY_SIZE(types), type); +} + +const char *tcp_state_name(unsigned int state, char *nm, size_t size) +{ + static const char *states[] = { + [TCP_ESTABLISHED] = __stringify_1(TCP_ESTABLISHED), + [TCP_SYN_SENT] = __stringify_1(TCP_SYN_SENT), + [TCP_SYN_RECV] = __stringify_1(TCP_SYN_RECV), + [TCP_FIN_WAIT1] = __stringify_1(TCP_FIN_WAIT1), + [TCP_FIN_WAIT2] = __stringify_1(TCP_FIN_WAIT2), + [TCP_TIME_WAIT] = __stringify_1(TCP_TIME_WAIT), + [TCP_CLOSE] = __stringify_1(TCP_CLOSE), + [TCP_CLOSE_WAIT] = __stringify_1(TCP_CLOSE_WAIT), + [TCP_LAST_ACK] = __stringify_1(TCP_LAST_ACK), + [TCP_LISTEN] = __stringify_1(TCP_LISTEN), + [TCP_CLOSING] = __stringify_1(TCP_CLOSING), + }; + return __socket_const_name(nm, size, states, ARRAY_SIZE(states), state); } struct sock_diag_greq { From 07e53c77e1e4d0dbac3a456fc3fa87365b61b70a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Sep 2018 22:57:58 +0300 Subject: [PATCH 1793/4375] inet: More readable content in show methods This generates more readable data in logs. | (00.002930) inet: Collected: ino 0xc3f15b family AF_INET type SOCK_DGRAM port 8081 state TCP_CLOSE src_addr 127.0.0.10 | (00.002980) inet: Collected: ino 0xc3f159 family AF_INET type SOCK_RAW port 1 state TCP_CLOSE src_addr 127.0.0.14 | (00.002984) inet: Collected: ino 0xc3f158 family AF_INET type SOCK_RAW port 17 state TCP_CLOSE src_addr 127.0.0.12 | (00.002988) inet: Collected: ino 0xc3f156 family AF_INET type SOCK_RAW port 255 state TCP_CLOSE src_addr 0.0.0.0 | (00.003439) inet: Collected: ino 0xc3f15a family AF_INET6 type SOCK_RAW port 58 state TCP_CLOSE src_addr :: | (00.003449) inet: Collected: ino 0xc3f157 family AF_INET6 type SOCK_RAW port 255 state TCP_CLOSE src_addr :: Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index fcc242644..2e6de6b5b 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -84,10 +84,11 @@ static void show_one_inet(const char *act, const struct inet_sk_desc *sk) pr_perror("Failed to translate address"); } - pr_debug("\t%s: ino %#8x family %4d type %4d port %8d " - "state %2d src_addr %s\n", - act, sk->sd.ino, sk->sd.family, sk->type, sk->src_port, - sk->state, src_addr); + pr_debug("\t%s: ino %#8x family %-10s type %-14s port %8d " + "state %-16s src_addr %s\n", act, sk->sd.ino, + ___socket_family_name(sk->sd.family), + ___socket_type_name(sk->type), sk->src_port, + ___tcp_state_name(sk->state), src_addr); } static void show_one_inet_img(const char *act, const InetSkEntry *e) @@ -99,10 +100,13 @@ static void show_one_inet_img(const char *act, const InetSkEntry *e) pr_perror("Failed to translate address"); } - pr_debug("\t%s: family %d type %d proto %d port %d " - "state %d src_addr %s\n", - act, e->family, e->type, e->proto, e->src_port, - e->state, src_addr); + pr_debug("\t%s: family %-10s type %-14s proto %-16s port %d " + "state %-16s src_addr %s\n", act, + ___socket_family_name(e->family), + ___socket_type_name(e->type), + ___socket_proto_name(e->proto), + e->src_port, ___tcp_state_name(e->state), + src_addr); } static int can_dump_ipproto(int ino, int proto) From d9c7787ed3e49c2fe52baee0c65d87221b7f7136 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 2 Oct 2018 15:20:29 +0300 Subject: [PATCH 1794/4375] travis: lazy-pages: exclude futex test for older kernels Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- scripts/travis/travis-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index f46c99ff8..aaa208c14 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -93,7 +93,7 @@ if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then else LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns -x socket_listen -x socket_listen6 -x cmdlinenv00 - -x socket_close_data01 -x file_read -x lazy-thp" + -x socket_close_data01 -x file_read -x lazy-thp -x futex" fi LAZY_EXCLUDE="$LAZY_EXCLUDE -x maps04" From 3e7cfd114df53face3ae24e1c7c09ef1f766575b Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 2 Oct 2018 15:20:30 +0300 Subject: [PATCH 1795/4375] jenkins: split common part of lazy pages tests into a separate file Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/jenkins/criu-lazy-common.sh | 9 +++++++++ test/jenkins/criu-lazy-migration.sh | 10 +--------- test/jenkins/criu-lazy-pages.sh | 10 +--------- test/jenkins/criu-remote-lazy-pages.sh | 10 +--------- 4 files changed, 12 insertions(+), 27 deletions(-) create mode 100644 test/jenkins/criu-lazy-common.sh diff --git a/test/jenkins/criu-lazy-common.sh b/test/jenkins/criu-lazy-common.sh new file mode 100644 index 000000000..a1a77dd32 --- /dev/null +++ b/test/jenkins/criu-lazy-common.sh @@ -0,0 +1,9 @@ +KERN_MAJ=`uname -r | cut -d. -f1` +KERN_MIN=`uname -r | cut -d. -f2` +if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then + LAZY_EXCLUDE="-x cmdlinenv00 -x maps007" +else + LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns + -x socket_listen -x socket_listen6 -x cmdlinenv00 + -x socket_close_data01 -x file_read" +fi diff --git a/test/jenkins/criu-lazy-migration.sh b/test/jenkins/criu-lazy-migration.sh index 78ea2bfce..cf0ab0485 100755 --- a/test/jenkins/criu-lazy-migration.sh +++ b/test/jenkins/criu-lazy-migration.sh @@ -3,15 +3,7 @@ set -e source `dirname $0`/criu-lib.sh prep -KERN_MAJ=`uname -r | cut -d. -f1` -KERN_MIN=`uname -r | cut -d. -f2` -if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then - LAZY_EXCLUDE="-x cmdlinenv00 -x maps007" -else - LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns - -x socket_listen -x socket_listen6 -x cmdlinenv00 - -x socket_close_data01 -x file_read" -fi +source `dirname $0`/criu-lazy-common.sh # These tests seem to require complete separation of dump and restore namespaces LAZY_MIGRATE_EXCLUDE="-x fifo_loop -x file_locks -x ptrace_sig -x overmount_file -x file_lease -x cr_veth -x fifo -x overmount_sock -x unlink_largefile -x socket_udp-corked -x netns_sub_veth" diff --git a/test/jenkins/criu-lazy-pages.sh b/test/jenkins/criu-lazy-pages.sh index f31098c7a..a3ee9a4ec 100755 --- a/test/jenkins/criu-lazy-pages.sh +++ b/test/jenkins/criu-lazy-pages.sh @@ -3,15 +3,7 @@ set -e source `dirname $0`/criu-lib.sh prep -KERN_MAJ=`uname -r | cut -d. -f1` -KERN_MIN=`uname -r | cut -d. -f2` -if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then - LAZY_EXCLUDE="-x cmdlinenv00 -x maps007" -else - LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns - -x socket_listen -x socket_listen6 -x cmdlinenv00 - -x socket_close_data01 -x file_read" -fi +source `dirname $0`/criu-lazy-common.sh # lazy restore from images ./test/zdtm.py run --all --keep-going --report report --parallel 4 \ diff --git a/test/jenkins/criu-remote-lazy-pages.sh b/test/jenkins/criu-remote-lazy-pages.sh index 122aea72c..ea0d17f0e 100755 --- a/test/jenkins/criu-remote-lazy-pages.sh +++ b/test/jenkins/criu-remote-lazy-pages.sh @@ -3,15 +3,7 @@ set -e source `dirname $0`/criu-lib.sh prep -KERN_MAJ=`uname -r | cut -d. -f1` -KERN_MIN=`uname -r | cut -d. -f2` -if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then - LAZY_EXCLUDE="-x cmdlinenv00 -x maps007" -else - LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns - -x socket_listen -x socket_listen6 -x cmdlinenv00 - -x socket_close_data01 -x file_read" -fi +source `dirname $0`/criu-lazy-common.sh # lazy restore from "remote" dump ./test/zdtm.py run --all --keep-going --report report --parallel 4 \ From 114af54fe85661ea133617758df5300b2c1acbe0 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 2 Oct 2018 15:20:31 +0300 Subject: [PATCH 1796/4375] jenkins: lazy-pages: exclude maps04 On loaded systems running maps04 with lazy-pages takes too much time. The same functionality is anyway covered by other tests so excluding maps04 shouldn't decrease the test coverage. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/jenkins/criu-lazy-common.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/jenkins/criu-lazy-common.sh b/test/jenkins/criu-lazy-common.sh index a1a77dd32..7fdab40dd 100644 --- a/test/jenkins/criu-lazy-common.sh +++ b/test/jenkins/criu-lazy-common.sh @@ -7,3 +7,5 @@ else -x socket_listen -x socket_listen6 -x cmdlinenv00 -x socket_close_data01 -x file_read" fi + +LAZY_EXCLUDE="$LAZY_EXCLUDE -x maps04" From d13ff7e32aceab14c5f1323bd76ff7dea52d3053 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Thu, 20 Sep 2018 22:22:32 +0000 Subject: [PATCH 1797/4375] lint: check test/inhfd/ scripts Signed-off-by: Andrei Vagin Signed-off-by: Andrei Vagin --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index cc5717ef2..38887da99 100644 --- a/Makefile +++ b/Makefile @@ -374,6 +374,7 @@ help: lint: flake8 --config=scripts/flake8.cfg test/zdtm.py + flake8 --config=scripts/flake8.cfg test/inhfd/*.py flake8 --config=scripts/flake8.cfg test/others/rpc/config_file.py include Makefile.install From a96d2298760857c4701321d2bafcfea1603b1360 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Thu, 20 Sep 2018 22:22:34 +0000 Subject: [PATCH 1798/4375] test/inhfd: fix lint warnings Signed-off-by: Andrei Vagin Signed-off-by: Andrei Vagin --- test/inhfd/fifo.py | 16 ++++++++++------ test/inhfd/pipe.py | 5 ++++- test/inhfd/socket.py | 4 ++++ test/inhfd/tty.py | 10 ++++++++-- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/test/inhfd/fifo.py b/test/inhfd/fifo.py index 40af371a1..bd4017ec4 100755 --- a/test/inhfd/fifo.py +++ b/test/inhfd/fifo.py @@ -1,7 +1,9 @@ -import os, tempfile +import os +import tempfile id_str = "" + def create_fds(): tdir = tempfile.mkdtemp("zdtm.inhfd.XXXXXX") if os.system("mount -t tmpfs zdtm.inhfd %s" % tdir) != 0: @@ -15,10 +17,10 @@ def create_fds(): mnt_id = -1 with open("/proc/self/fdinfo/%d" % fd1.fileno()) as f: - for l in f: - l = l.split() - if l[0] == "mnt_id:": - mnt_id = int(l[1]) + for line in f: + line = line.split() + if line[0] == "mnt_id:": + mnt_id = int(line[1]) break else: raise Exception("Unable to find mnt_id") @@ -28,8 +30,10 @@ def create_fds(): return (fd2, fd1) + def filename(pipef): return id_str + def dump_opts(sockf): - return [ "--external", id_str ] + return ["--external", id_str] diff --git a/test/inhfd/pipe.py b/test/inhfd/pipe.py index 0f9115246..4635a6cc1 100755 --- a/test/inhfd/pipe.py +++ b/test/inhfd/pipe.py @@ -1,11 +1,14 @@ import os + def create_fds(): (fd1, fd2) = os.pipe() return (os.fdopen(fd2, "wb"), os.fdopen(fd1, "rb")) + def filename(pipef): return 'pipe:[%d]' % os.fstat(pipef.fileno()).st_ino + def dump_opts(sockf): - return [ ] + return [] diff --git a/test/inhfd/socket.py b/test/inhfd/socket.py index 45ae03367..d7e434046 100755 --- a/test/inhfd/socket.py +++ b/test/inhfd/socket.py @@ -1,15 +1,19 @@ import socket import os + def create_fds(): (sk1, sk2) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM) return (sk1.makefile("wb"), sk2.makefile("rb")) + def __sock_ino(sockf): return os.fstat(sockf.fileno()).st_ino + def filename(sockf): return 'socket:[%d]' % __sock_ino(sockf) + def dump_opts(sockf): return ['--external', 'unix[%d]' % __sock_ino(sockf)] diff --git a/test/inhfd/tty.py b/test/inhfd/tty.py index fbda13948..519b6bcbc 100755 --- a/test/inhfd/tty.py +++ b/test/inhfd/tty.py @@ -1,17 +1,23 @@ -import os, pty -import termios, fcntl +import fcntl +import os +import pty +import termios + def child_prep(fd): fcntl.ioctl(fd.fileno(), termios.TIOCSCTTY, 1) + def create_fds(): (fd1, fd2) = pty.openpty() return (os.fdopen(fd2, "wb"), os.fdopen(fd1, "rb")) + def filename(pipef): st = os.fstat(pipef.fileno()) return 'tty[%x:%x]' % (st.st_rdev, st.st_dev) + def dump_opts(sockf): st = os.fstat(sockf.fileno()) return ["--external", 'tty[%x:%x]' % (st.st_rdev, st.st_dev)] From 89c5fc9b068f9a08e3c6cb5fea2b45a46aaa5b57 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Thu, 20 Sep 2018 22:22:35 +0000 Subject: [PATCH 1799/4375] zdtm: create a few external descriptros Currently, we create only one external resource to check how it is handled by criu. It is better to create more than one. Signed-off-by: Andrei Vagin Signed-off-by: Andrei Vagin --- test/inhfd/fifo.py | 2 +- test/inhfd/pipe.py | 7 +++- test/inhfd/socket.py | 4 +- test/inhfd/tty.py | 20 ++++++++-- test/zdtm.py | 89 +++++++++++++++++++++++++++++--------------- 5 files changed, 84 insertions(+), 38 deletions(-) diff --git a/test/inhfd/fifo.py b/test/inhfd/fifo.py index bd4017ec4..64e5f8f13 100755 --- a/test/inhfd/fifo.py +++ b/test/inhfd/fifo.py @@ -28,7 +28,7 @@ def create_fds(): global id_str id_str = "file[%x:%x]" % (mnt_id, os.fstat(fd1.fileno()).st_ino) - return (fd2, fd1) + return [(fd2, fd1)] def filename(pipef): diff --git a/test/inhfd/pipe.py b/test/inhfd/pipe.py index 4635a6cc1..318dc862d 100755 --- a/test/inhfd/pipe.py +++ b/test/inhfd/pipe.py @@ -2,8 +2,11 @@ import os def create_fds(): - (fd1, fd2) = os.pipe() - return (os.fdopen(fd2, "wb"), os.fdopen(fd1, "rb")) + pipes = [] + for i in range(10): + (fd1, fd2) = os.pipe() + pipes.append((os.fdopen(fd2, "wb"), os.fdopen(fd1, "rb"))) + return pipes def filename(pipef): diff --git a/test/inhfd/socket.py b/test/inhfd/socket.py index d7e434046..feba0e0c6 100755 --- a/test/inhfd/socket.py +++ b/test/inhfd/socket.py @@ -4,7 +4,9 @@ import os def create_fds(): (sk1, sk2) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM) - return (sk1.makefile("wb"), sk2.makefile("rb")) + (sk3, sk4) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM) + return [(sk1.makefile("wb"), sk2.makefile("rb")), + (sk3.makefile("wb"), sk4.makefile("rb"))] def __sock_ino(sockf): diff --git a/test/inhfd/tty.py b/test/inhfd/tty.py index 519b6bcbc..ae76a96d4 100755 --- a/test/inhfd/tty.py +++ b/test/inhfd/tty.py @@ -1,16 +1,30 @@ +# vim: noet ts=8 sw=8 sts=8 import fcntl import os import pty import termios +ctl = False + + def child_prep(fd): + global ctl + if ctl: + return + ctl = True fcntl.ioctl(fd.fileno(), termios.TIOCSCTTY, 1) def create_fds(): - (fd1, fd2) = pty.openpty() - return (os.fdopen(fd2, "wb"), os.fdopen(fd1, "rb")) + ttys = [] + for i in range(10): + (fd1, fd2) = pty.openpty() + newattr = termios.tcgetattr(fd1) + newattr[3] &= ~termios.ICANON & ~termios.ECHO + termios.tcsetattr(fd1, termios.TCSADRAIN, newattr) + ttys.append((os.fdopen(fd1, "wb"), os.fdopen(fd2, "rb"))) + return ttys def filename(pipef): @@ -20,4 +34,4 @@ def filename(pipef): def dump_opts(sockf): st = os.fstat(sockf.fileno()) - return ["--external", 'tty[%x:%x]' % (st.st_rdev, st.st_dev)] + return "--external", 'tty[%x:%x]' % (st.st_rdev, st.st_dev) diff --git a/test/zdtm.py b/test/zdtm.py index 97f9da009..ea328c01f 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -580,28 +580,35 @@ class inhfd_test: self.__name = os.path.basename(name) print("Load %s" % name) self.__fdtyp = imp.load_source(self.__name, name) - self.__my_file = None self.__peer_pid = 0 - self.__peer_file = None - self.__peer_file_name = None - self.__dump_opts = None + self.__files = None + self.__peer_file_names = [] + self.__dump_opts = [] + + def __get_message(self, i): + return b"".join([random.choice(string.ascii_letters).encode() for _ in range(10)]) + b"%06d" % i def start(self): - self.__message = b"".join([random.choice(string.ascii_letters).encode() for _ in range(16)]) - (self.__my_file, peer_file) = self.__fdtyp.create_fds() + self.__files = self.__fdtyp.create_fds() # Check FDs returned for inter-connection - self.__my_file.write(self.__message) - self.__my_file.flush() - if peer_file.read(16) != self.__message: - raise test_fail_exc("FDs screwup") + i = 0 + for my_file, peer_file in self.__files: + msg = self.__get_message(i) + my_file.write(msg) + my_file.flush() + data = peer_file.read(len(msg)) + if data != msg: + raise test_fail_exc("FDs screwup: %r %r" % (msg, data)) + i += 1 start_pipe = os.pipe() self.__peer_pid = os.fork() if self.__peer_pid == 0: os.setsid() - getattr(self.__fdtyp, "child_prep", lambda fd: None)(peer_file) + for _, peer_file in self.__files: + getattr(self.__fdtyp, "child_prep", lambda fd: None)(peer_file) try: os.unlink(self.__name + ".out") @@ -611,29 +618,45 @@ class inhfd_test: os.dup2(fd, 1) os.dup2(fd, 2) os.close(0) - self.__my_file.close() + for my_file, _ in self.__files: + my_file.close() os.close(start_pipe[0]) os.close(start_pipe[1]) - try: - data = peer_file.read(16) - except Exception as e: - print("Unable to read a peer file: %s" % e) - sys.exit(1) + i = 0 + for _, peer_file in self.__files: + msg = self.__get_message(i) + my_file.close() + try: + data = peer_file.read(16) + except Exception as e: + print("Unable to read a peer file: %s" % e) + sys.exit(1) - if data != self.__message: - print("%r %r" % (data, self.__message)) - sys.exit(data == self.__message and 42 or 2) + if data != msg: + print("%r %r" % (data, msg)) + i += 1 + sys.exit(data == msg and 42 or 2) os.close(start_pipe[1]) os.read(start_pipe[0], 12) os.close(start_pipe[0]) - self.__peer_file_name = self.__fdtyp.filename(peer_file) - self.__dump_opts = self.__fdtyp.dump_opts(peer_file) + for _, peer_file in self.__files: + self.__peer_file_names.append(self.__fdtyp.filename(peer_file)) + self.__dump_opts += self.__fdtyp.dump_opts(peer_file) + + self.__fds = set(os.listdir("/proc/%s/fd" % self.__peer_pid)) def stop(self): - self.__my_file.write(self.__message) - self.__my_file.flush() + fds = set(os.listdir("/proc/%s/fd" % self.__peer_pid)) + if fds != self.__fds: + raise test_fail_exc("File descriptors mismatch: %s %s" % (fds, self.__fds)) + i = 0 + for my_file, _ in self.__files: + msg = self.__get_message(i) + my_file.write(msg) + my_file.flush() + i += 1 pid, status = os.waitpid(self.__peer_pid, 0) with open(self.__name + ".out") as output: print(output.read()) @@ -654,18 +677,22 @@ class inhfd_test: def gone(self, force = True): os.waitpid(self.__peer_pid, 0) wait_pid_die(self.__peer_pid, self.__name) - self.__my_file = None - self.__peer_file = None + self.__files = None def getdopts(self): return self.__dump_opts def getropts(self): - (self.__my_file, self.__peer_file) = self.__fdtyp.create_fds() - fd = self.__peer_file.fileno() - fdflags = fcntl.fcntl(fd, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC - fcntl.fcntl(fd, fcntl.F_SETFD, fdflags) - return ["--restore-sibling", "--inherit-fd", "fd[%d]:%s" % (fd, self.__peer_file_name)] + self.__files = self.__fdtyp.create_fds() + ropts = ["--restore-sibling"] + for i in range(len(self.__files)): + my_file, peer_file = self.__files[i] + fd = peer_file.fileno() + fdflags = fcntl.fcntl(fd, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC + fcntl.fcntl(fd, fcntl.F_SETFD, fdflags) + peer_file_name = self.__peer_file_names[i] + ropts.extend(["--inherit-fd", "fd[%d]:%s" % (fd, peer_file_name)]) + return ropts def print_output(self): pass From 37711acea00efb667dd2ca182b68e4dbcce8e3f9 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 27 Sep 2018 10:02:26 +0300 Subject: [PATCH 1800/4375] files: save inherited file descriptors in fdstore In this case: * don't need to care whether they intercept with restored file descriptors. * they don't copied into each restored process * don't need to close them one by one Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 9 +-- criu/files-reg.c | 4 ++ criu/files.c | 164 ++++++------------------------------------- criu/include/files.h | 3 +- criu/util.c | 4 -- 5 files changed, 30 insertions(+), 154 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 3e1dc6d4b..7c38fbb97 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -884,9 +884,6 @@ static int restore_one_alive_task(int pid, CoreEntry *core) if (collect_zombie_pids(ta) < 0) return -1; - if (inherit_fd_fini() < 0) - return -1; - if (prepare_proc_misc(pid, core->tc)) return -1; @@ -1019,9 +1016,6 @@ static int restore_one_zombie(CoreEntry *core) if (prepare_fds(current)) return -1; - if (inherit_fd_fini() < 0) - return -1; - if (lazy_pages_setup_zombie(vpid(current))) return -1; @@ -2409,6 +2403,9 @@ int cr_restore_tasks(void) if (fdstore_init()) goto err; + if (inherit_fd_move_to_fdstore()) + goto err; + if (crtools_prepare_shared() < 0) goto err; diff --git a/criu/files-reg.c b/criu/files-reg.c index b81b4da96..ec91f22c3 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1583,6 +1583,7 @@ int open_path(struct file_desc *d, struct reg_file_info *rfi; char *orig_path = NULL; char path[PATH_MAX]; + int inh_fd = -1; if (inherited_fd(d, &tmp)) return tmp; @@ -1592,6 +1593,7 @@ int open_path(struct file_desc *d, if (rfi->rfe->ext) { tmp = inherit_fd_lookup_id(rfi->rfe->name); if (tmp >= 0) { + inh_fd = tmp; mntns_root = open_pid_proc(PROC_SELF); snprintf(path, sizeof(path), "fd/%d", tmp); orig_path = rfi->path; @@ -1650,8 +1652,10 @@ ext: tmp = open_cb(mntns_root, rfi, arg); if (tmp < 0) { pr_perror("Can't open file %s", rfi->path); + close_safe(&inh_fd); return -1; } + close_safe(&inh_fd); if ((rfi->rfe->has_size || rfi->rfe->has_mode) && !rfi->size_mode_checked) { diff --git a/criu/files.c b/criu/files.c index 115390f63..0f88912a4 100644 --- a/criu/files.c +++ b/criu/files.c @@ -45,6 +45,7 @@ #include "parasite.h" #include "parasite-syscall.h" #include "kerndat.h" +#include "fdstore.h" #include "protobuf.h" #include "util.h" @@ -1049,10 +1050,6 @@ static int send_fd_to_self(int fd, struct fdinfo_list_entry *fle) if (fd == dfd) return 0; - /* make sure we won't clash with an inherit fd */ - if (inherit_fd_resolve_clash(dfd) < 0) - return -1; - BUG_ON(dfd == get_service_fd(TRANSPORT_FD_OFF)); pr_info("\t\t\tGoing to dup %d into %d\n", fd, dfd); @@ -1240,8 +1237,6 @@ splice: return ret; } -static struct inherit_fd *inherit_fd_lookup_fd(int fd, const char *caller); - int close_old_fds(void) { DIR *dir; @@ -1262,8 +1257,7 @@ int close_old_fds(void) return -1; } - if ((!is_any_service_fd(fd)) && (dirfd(dir) != fd) && - !inherit_fd_lookup_fd(fd, __FUNCTION__)) + if ((!is_any_service_fd(fd)) && (dirfd(dir) != fd)) close_safe(&fd); } @@ -1487,49 +1481,11 @@ struct inherit_fd { struct list_head inh_list; char *inh_id; /* file identifier */ int inh_fd; /* criu's descriptor to inherit */ - dev_t inh_dev; - ino_t inh_ino; - mode_t inh_mode; - dev_t inh_rdev; + int inh_fd_id; }; int inh_fd_max = -1; -/* - * Return 1 if inherit fd has been closed or reused, 0 otherwise. - * - * Some parts of the file restore engine can close an inherit fd - * explicitly by close() or implicitly by dup2() to reuse that descriptor. - * In some specific functions (for example, send_fd_to_self()), we - * check for clashes at the beginning of the function and, therefore, - * these specific functions will not reuse an inherit fd. However, to - * avoid adding a ton of clash detect and resolve code everywhere we close() - * and/or dup2(), we just make sure that when we're dup()ing or close()ing - * our inherit fd we're still dealing with the same fd that we inherited. - */ -static int inherit_fd_reused(struct inherit_fd *inh) -{ - struct stat sbuf; - - if (fstat(inh->inh_fd, &sbuf) == -1) { - if (errno == EBADF) { - pr_debug("Inherit fd %s -> %d has been closed\n", - inh->inh_id, inh->inh_fd); - return 1; - } - pr_perror("Can't fstat inherit fd %d", inh->inh_fd); - return -1; - } - - if (inh->inh_dev != sbuf.st_dev || inh->inh_ino != sbuf.st_ino || - inh->inh_mode != sbuf.st_mode || inh->inh_rdev != sbuf.st_rdev) { - pr_info("Inherit fd %s -> %d has been reused\n", - inh->inh_id, inh->inh_fd); - return 1; - } - return 0; -} - /* * We can't print diagnostics messages in this function because the * log file isn't initialized yet. @@ -1596,10 +1552,6 @@ int inherit_fd_add(int fd, char *key) inh->inh_id = key; inh->inh_fd = fd; - inh->inh_dev = sbuf.st_dev; - inh->inh_ino = sbuf.st_ino; - inh->inh_mode = sbuf.st_mode; - inh->inh_rdev = sbuf.st_rdev; list_add_tail(&inh->inh_list, &opts.inherit_fds); return 0; } @@ -1618,6 +1570,20 @@ void inherit_fd_log(void) } } +int inherit_fd_move_to_fdstore(void) +{ + struct inherit_fd *inh; + + list_for_each_entry(inh, &opts.inherit_fds, inh_list) { + inh->inh_fd_id = fdstore_add(inh->inh_fd); + if (inh->inh_fd_id < 0) + return -1; + close_safe(&inh->inh_fd); + } + + return 0; +} + /* * Look up the inherit fd list by a file identifier. */ @@ -1629,11 +1595,9 @@ int inherit_fd_lookup_id(char *id) ret = -1; list_for_each_entry(inh, &opts.inherit_fds, inh_list) { if (!strcmp(inh->inh_id, id)) { - if (!inherit_fd_reused(inh)) { - ret = inh->inh_fd; - pr_debug("Found id %s (fd %d) in inherit fd list\n", - id, ret); - } + ret = fdstore_get(inh->inh_fd_id); + pr_debug("Found id %s (fd %d) in inherit fd list\n", + id, ret); break; } } @@ -1656,96 +1620,12 @@ bool inherited_fd(struct file_desc *d, int *fd_p) if (fd_p == NULL) return true; - *fd_p = dup(i_fd); - if (*fd_p < 0) - pr_perror("Inherit fd DUP failed"); - else - pr_info("File %s will be restored from fd %d dumped " + *fd_p = i_fd; + pr_info("File %s will be restored from fd %d dumped " "from inherit fd %d\n", id_str, *fd_p, i_fd); return true; } -/* - * Look up the inherit fd list by a file descriptor. - */ -static struct inherit_fd *inherit_fd_lookup_fd(int fd, const char *caller) -{ - struct inherit_fd *ret; - struct inherit_fd *inh; - - ret = NULL; - list_for_each_entry(inh, &opts.inherit_fds, inh_list) { - if (inh->inh_fd == fd) { - if (!inherit_fd_reused(inh)) { - ret = inh; - pr_debug("Found fd %d (id %s) in inherit fd list (caller %s)\n", - fd, inh->inh_id, caller); - } - break; - } - } - return ret; -} - -/* - * If the specified fd clashes with an inherit fd, - * move the inherit fd. - */ -int inherit_fd_resolve_clash(int fd) -{ - int newfd; - struct inherit_fd *inh; - - inh = inherit_fd_lookup_fd(fd, __FUNCTION__); - if (inh == NULL) - return 0; - - newfd = dup(fd); - if (newfd == -1) { - pr_perror("Can't dup inherit fd %d", fd); - return -1; - } - - if (close(fd) == -1) { - close(newfd); - pr_perror("Can't close inherit fd %d", fd); - return -1; - } - - inh->inh_fd = newfd; - pr_debug("Inherit fd %d moved to %d to resolve clash\n", fd, inh->inh_fd); - return 0; -} - -/* - * Close all inherit fds. - */ -int inherit_fd_fini() -{ - int reused; - struct inherit_fd *inh; - - list_for_each_entry(inh, &opts.inherit_fds, inh_list) { - if (inh->inh_fd < 0) { - pr_err("File %s in inherit fd list has invalid fd %d\n", - inh->inh_id, inh->inh_fd); - return -1; - } - - reused = inherit_fd_reused(inh); - if (reused < 0) - return -1; - - if (!reused) { - pr_debug("Closing inherit fd %d -> %s\n", inh->inh_fd, - inh->inh_id); - if (close_safe(&inh->inh_fd) < 0) - return -1; - } - } - return 0; -} - int open_transport_socket(void) { pid_t pid = vpid(current); diff --git a/criu/include/files.h b/criu/include/files.h index 75757bd1d..2c1e1e723 100644 --- a/criu/include/files.h +++ b/criu/include/files.h @@ -190,8 +190,7 @@ extern int dump_unsupp_fd(struct fd_parms *p, int lfd, extern int inherit_fd_parse(char *optarg); extern int inherit_fd_add(int fd, char *key); extern void inherit_fd_log(void); -extern int inherit_fd_resolve_clash(int fd); -extern int inherit_fd_fini(void); +extern int inherit_fd_move_to_fdstore(void); extern int inherit_fd_lookup_id(char *id); diff --git a/criu/util.c b/criu/util.c index 748650537..b08f5af3a 100644 --- a/criu/util.c +++ b/criu/util.c @@ -242,10 +242,6 @@ int reopen_fd_as_safe(char *file, int line, int new_fd, int old_fd, bool allow_r int tmp; if (old_fd != new_fd) { - /* make sure we won't clash with an inherit fd */ - if (inherit_fd_resolve_clash(new_fd) < 0) - return -1; - if (!allow_reuse_fd) { if (fcntl(new_fd, F_GETFD) != -1 || errno != EBADF) { pr_err("fd %d already in use (called at %s:%d)\n", From ac3296c39fab01f54c08fdd69fe5cf7b7282999b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 27 Sep 2018 10:01:49 +0300 Subject: [PATCH 1801/4375] tty: allocate a separate tty info id for each external tty Otherwise all external tty-s will share the same tty info, what is obviously wrong. v2: allocate a separate tty index range for externl terminals Cc: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/tty.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/criu/tty.c b/criu/tty.c index 214d97a8e..38e1cab33 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -136,7 +136,7 @@ static int self_stdin_fdid = -1; * Pretty acceptable trade off in a sake of simplicity. */ -#define MAX_TTYS 1024 +#define MAX_TTYS 1088 /* * Custom indices should be even numbers just in case if we @@ -147,8 +147,9 @@ static int self_stdin_fdid = -1; #define CONSOLE_INDEX 1002 #define VT_INDEX 1004 #define CTTY_INDEX 1006 -#define ETTY_INDEX 1008 #define STTY_INDEX 1010 +#define ETTY_INDEX 1012 +#define ETTY_INDEX_MAX 1076 #define INDEX_ERR (MAX_TTYS + 1) static DECLARE_BITMAP(tty_bitmap, (MAX_TTYS << 1)); @@ -189,6 +190,20 @@ static int pty_get_index(struct tty_info *ti) return ti->tie->pty->index; } +static int ext_fd_get_index(int fd, const struct fd_parms *p) +{ + static int index; + + index++; + + if (index + ETTY_INDEX > ETTY_INDEX_MAX) { + pr_err("Too many external terminals\n"); + return INDEX_ERR; + } + + return index + ETTY_INDEX; +} + static int pty_open_ptmx(struct tty_info *info); static struct tty_driver ptm_driver = { @@ -229,6 +244,7 @@ static struct tty_driver ext_driver = { .name = "ext", .index = ETTY_INDEX, .open = open_ext_tty, + .fd_get_index = ext_fd_get_index, }; static struct tty_driver serial_driver = { From 3b1563ebd05cae9098713bf728e61344cbe3da43 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 3 Oct 2018 20:57:21 +0100 Subject: [PATCH 1802/4375] crit-images: Don't overwrite 'pb' with local var Rename the local variables 'pb' to 'pbuff' to avoid conflict with the imported 'pb' module. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- lib/py/images/images.py | 74 ++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/lib/py/images/images.py b/lib/py/images/images.py index 217105fa8..40fb74d39 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -91,13 +91,13 @@ class entry_handler: entry = {} # Read payload - pb = self.payload() + pbuff = self.payload() buf = f.read(4) if buf == b'': break size, = struct.unpack('i', buf) - pb.ParseFromString(f.read(size)) - entry = pb2dict.pb2dict(pb, pretty) + pbuff.ParseFromString(f.read(size)) + entry = pb2dict.pb2dict(pbuff, pretty) # Read extra if self.extra_handler: @@ -112,10 +112,10 @@ class entry_handler: num /= 1024.0 return "%.1fYB" % num - pl_size = self.extra_handler.skip(f, pb) + pl_size = self.extra_handler.skip(f, pbuff) entry['extra'] = '... <%s>' % human_readable(pl_size) else: - entry['extra'] = self.extra_handler.load(f, pb) + entry['extra'] = self.extra_handler.load(f, pbuff) entries.append(entry) @@ -138,16 +138,16 @@ class entry_handler: extra = entry.pop('extra', None) # Write payload - pb = self.payload() - pb2dict.dict2pb(entry, pb) - pb_str = pb.SerializeToString() + pbuff = self.payload() + pb2dict.dict2pb(entry, pbuff) + pb_str = pbuff.SerializeToString() size = len(pb_str) f.write(struct.pack('i', size)) f.write(pb_str) # Write extra if self.extra_handler and extra: - self.extra_handler.dump(extra, f, pb) + self.extra_handler.dump(extra, f, pbuff) def dumps(self, entries): """ @@ -312,7 +312,7 @@ class sk_queues_extra_handler: data = f.read(size) return base64.encodebytes(data) - def dump(self, extra, f, pb): + def dump(self, extra, f, _unused): data = base64.decodebytes(extra) f.write(data) @@ -322,31 +322,31 @@ class sk_queues_extra_handler: class tcp_stream_extra_handler: - def load(self, f, pb): + def load(self, f, pbuff): d = {} - inq = f.read(pb.inq_len) - outq = f.read(pb.outq_len) + inq = f.read(pbuff.inq_len) + outq = f.read(pbuff.outq_len) d['inq'] = base64.encodebytes(inq) d['outq'] = base64.encodebytes(outq) return d - def dump(self, extra, f, pb): + def dump(self, extra, f, _unused): inq = base64.decodebytes(extra['inq']) outq = base64.decodebytes(extra['outq']) f.write(inq) f.write(outq) - def skip(self, f, pb): + def skip(self, f, pbuff): f.seek(0, os.SEEK_END) - return pb.inq_len + pb.outq_len + return pbuff.inq_len + pbuff.outq_len class ipc_sem_set_handler: - def load(self, f, pb): - entry = pb2dict.pb2dict(pb) + def load(self, f, pbuff): + entry = pb2dict.pb2dict(pbuff) size = sizeof_u16 * entry['nsems'] rounded = round_up(size, sizeof_u64) s = array.array('H') @@ -356,8 +356,8 @@ class ipc_sem_set_handler: f.seek(rounded - size, 1) return s.tolist() - def dump(self, extra, f, pb): - entry = pb2dict.pb2dict(pb) + def dump(self, extra, f, pbuff): + entry = pb2dict.pb2dict(pbuff) size = sizeof_u16 * entry['nsems'] rounded = round_up(size, sizeof_u64) s = array.array('H') @@ -369,22 +369,22 @@ class ipc_sem_set_handler: f.write(s.tostring()) f.write('\0' * (rounded - size)) - def skip(self, f, pb): - entry = pb2dict.pb2dict(pb) + def skip(self, f, pbuff): + entry = pb2dict.pb2dict(pbuff) size = sizeof_u16 * entry['nsems'] f.seek(round_up(size, sizeof_u64), os.SEEK_CUR) return size class ipc_msg_queue_handler: - def load(self, f, pb): - entry = pb2dict.pb2dict(pb) + def load(self, f, pbuff): + entry = pb2dict.pb2dict(pbuff) messages = [] for x in range (0, entry['qnum']): buf = f.read(4) if buf == '': break size, = struct.unpack('i', buf) - msg = pb.ipc_msg() + msg = pbuff.ipc_msg() msg.ParseFromString(f.read(size)) rounded = round_up(msg.msize, sizeof_u64) data = f.read(msg.msize) @@ -393,10 +393,10 @@ class ipc_msg_queue_handler: messages.append(base64.encodebytes(data)) return messages - def dump(self, extra, f, pb): - entry = pb2dict.pb2dict(pb) + def dump(self, extra, f, pbuff): + entry = pb2dict.pb2dict(pbuff) for i in range (0, len(extra), 2): - msg = pb.ipc_msg() + msg = pbuff.ipc_msg() pb2dict.dict2pb(extra[i], msg) msg_str = msg.SerializeToString() size = len(msg_str) @@ -407,15 +407,15 @@ class ipc_msg_queue_handler: f.write(data[:msg.msize]) f.write('\0' * (rounded - msg.msize)) - def skip(self, f, pb): - entry = pb2dict.pb2dict(pb) + def skip(self, f, pbuff): + entry = pb2dict.pb2dict(pbuff) pl_len = 0 for x in range (0, entry['qnum']): buf = f.read(4) if buf == '': break size, = struct.unpack('i', buf) - msg = pb.ipc_msg() + msg = pbuff.ipc_msg() msg.ParseFromString(f.read(size)) rounded = round_up(msg.msize, sizeof_u64) f.seek(rounded, os.SEEK_CUR) @@ -424,24 +424,24 @@ class ipc_msg_queue_handler: return pl_len class ipc_shm_handler: - def load(self, f, pb): - entry = pb2dict.pb2dict(pb) + def load(self, f, pbuff): + entry = pb2dict.pb2dict(pbuff) size = entry['size'] data = f.read(size) rounded = round_up(size, sizeof_u32) f.seek(rounded - size, 1) return base64.encodebytes(data) - def dump(self, extra, f, pb): - entry = pb2dict.pb2dict(pb) + def dump(self, extra, f, pbuff): + entry = pb2dict.pb2dict(pbuff) size = entry['size'] data = base64.decodebytes(extra) rounded = round_up(size, sizeof_u32) f.write(data[:size]) f.write('\0' * (rounded - size)) - def skip(self, f, pb): - entry = pb2dict.pb2dict(pb) + def skip(self, f, pbuff): + entry = pb2dict.pb2dict(pbuff) size = entry['size'] rounded = round_up(size, sizeof_u32) f.seek(rounded, os.SEEK_CUR) From 76f8c09093be1a77f56c4e6f2ed4e3b1fff7d123 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 9 Oct 2018 08:50:50 +0100 Subject: [PATCH 1803/4375] crit-images: Fix reference to ipc_msg() Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- lib/py/images/images.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/py/images/images.py b/lib/py/images/images.py index 40fb74d39..7a9b9da6e 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -384,7 +384,7 @@ class ipc_msg_queue_handler: if buf == '': break size, = struct.unpack('i', buf) - msg = pbuff.ipc_msg() + msg = pb.ipc_msg() msg.ParseFromString(f.read(size)) rounded = round_up(msg.msize, sizeof_u64) data = f.read(msg.msize) @@ -396,7 +396,7 @@ class ipc_msg_queue_handler: def dump(self, extra, f, pbuff): entry = pb2dict.pb2dict(pbuff) for i in range (0, len(extra), 2): - msg = pbuff.ipc_msg() + msg = pb.ipc_msg() pb2dict.dict2pb(extra[i], msg) msg_str = msg.SerializeToString() size = len(msg_str) @@ -415,7 +415,7 @@ class ipc_msg_queue_handler: if buf == '': break size, = struct.unpack('i', buf) - msg = pbuff.ipc_msg() + msg = pb.ipc_msg() msg.ParseFromString(f.read(size)) rounded = round_up(msg.msize, sizeof_u64) f.seek(rounded, os.SEEK_CUR) From f84ea82bb144bc32f7f06a35525f4315b03e5662 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 28 Sep 2018 16:11:34 +0300 Subject: [PATCH 1804/4375] image/dedup: use userns_call to be able to open images for write When restoring a task in it's user namespace we had: "Unable to open pages-3.img: Permission denied" when trying to open pages images for write. (Write is needed for memory images deduplication feature to work.) These patch makes do_open_image open images fd through usernsd, to have root permissions. Also increase MAX_UNSFD_MSG_SIZE as path and metadata don't fit, and remove a workaround in prepare_vma_ios. Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/image.c | 39 ++++++++++++++++++++++++++++++++++++++- criu/include/namespaces.h | 2 +- criu/mem.c | 14 +++----------- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/criu/image.c b/criu/image.c index a10c20aa5..13aeec69f 100644 --- a/criu/image.c +++ b/criu/image.c @@ -17,6 +17,7 @@ #include "images/inventory.pb-c.h" #include "images/pagemap.pb-c.h" #include "proc_parse.h" +#include "namespaces.h" bool ns_per_id = false; bool img_common_magic = true; @@ -367,13 +368,49 @@ static int img_write_magic(struct cr_img *img, int oflags, int type) return write_img(img, &imgset_template[type].magic); } +struct openat_args { + char path[PATH_MAX]; + int flags; + int err; + int mode; +}; + +static int userns_openat(void *arg, int dfd, int pid) +{ + struct openat_args *pa = (struct openat_args *)arg; + int ret; + + ret = openat(dfd, pa->path, pa->flags, pa->mode); + if (ret < 0) + pa->err = errno; + + return ret; +} + static int do_open_image(struct cr_img *img, int dfd, int type, unsigned long oflags, char *path) { int ret, flags; flags = oflags & ~(O_NOBUF | O_SERVICE | O_FORCE_LOCAL); - ret = openat(dfd, path, flags, CR_FD_PERM); + /* + * For pages images dedup we need to open images read-write on + * restore, that may require proper capabilities, so we ask + * usernsd to do it for us + */ + if (root_ns_mask & CLONE_NEWUSER && + type == CR_FD_PAGES && oflags & O_RDWR) { + struct openat_args pa = { + .flags = flags, + .err = 0, + .mode = CR_FD_PERM, + }; + snprintf(pa.path, PATH_MAX, "%s", path); + ret = userns_call(userns_openat, UNS_FDOUT, &pa, sizeof(struct openat_args), dfd); + if (ret < 0) + errno = pa.err; + } else + ret = openat(dfd, path, flags, CR_FD_PERM); if (ret < 0) { if (!(flags & O_CREAT) && (errno == ENOENT || ret == -ENOENT)) { pr_info("No %s image\n", path); diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index 5fe8038bf..287abb3c8 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -198,7 +198,7 @@ typedef int (*uns_call_t)(void *arg, int fd, pid_t pid); */ #define UNS_FDOUT 0x2 -#define MAX_UNSFD_MSG_SIZE 4096 +#define MAX_UNSFD_MSG_SIZE 8192 /* * When we're restoring inside user namespace, some things are diff --git a/criu/mem.c b/criu/mem.c index 284af2954..8015a7e4e 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -1299,20 +1299,12 @@ static int prepare_vma_ios(struct pstree_item *t, struct task_restore_args *ta) { struct cr_img *pages; - /* if auto-dedup is on we need RDWR mode to be able to punch holes - * in the input files (in restorer.c) + /* + * If auto-dedup is on we need RDWR mode to be able to punch holes in + * the input files (in restorer.c) */ pages = open_image(CR_FD_PAGES, opts.auto_dedup ? O_RDWR : O_RSTR, rsti(t)->pages_img_id); - /* When running inside namespace we might lack privileges to open the file - * for writing. - * TODO: use userns_call to do the opening instead of downgrading to opening - * read-only. - */ - if (!pages && opts.auto_dedup) { - pr_warn("Failed to open image read-write, trying read-only instead. auto-dedup won't work\n"); - pages = open_image(CR_FD_PAGES, O_RSTR, rsti(t)->pages_img_id); - } if (!pages) return -1; From e4d8dc6f2904d31f5c2ba8ea9d415d04365f2592 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 28 Sep 2018 16:11:35 +0300 Subject: [PATCH 1805/4375] zdtm: check criu restore with --auto-dedup Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index ea328c01f..19e362cd8 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1156,6 +1156,9 @@ class criu: r_opts += ['--empty-ns', 'net'] r_opts += ['--action-script', os.getcwd() + '/empty-netns-prep.sh'] + if self.__dedup: + r_opts += ["--auto-dedup"] + self.__prev_dump_iter = None criu_dir = os.path.dirname(os.getcwd()) if os.getenv("GCOV"): From 8517bc7d27a6b535f9d418eaf30c63adbbe9b00b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 15 Oct 2018 19:16:13 +0300 Subject: [PATCH 1806/4375] service: use waitpid() when a child pid is known We want to wait a specific child. wait() waits any child. Signed-off-by: Andrei Vagin --- criu/cr-service.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index dbeb1a881..af9ccddd2 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -753,10 +753,11 @@ cout: exit(ret); } - wait(&status); - if (!WIFEXITED(status)) + if (waitpid(pid, &status, 0) != pid) { + pr_perror("Unable to wait %d", pid); goto out; - if (WEXITSTATUS(status) != 0) + } + if (status != 0) goto out; success = true; @@ -842,7 +843,10 @@ out_ch: close(start_pipe[1]); if (daemon_mode) { - wait(&ret); + if (waitpid(pid, &ret, 0) != pid) { + pr_perror("Unable to wait %d", pid); + goto out; + } if (WIFEXITED(ret)) { if (WEXITSTATUS(ret)) { pr_err("Child exited with an error\n"); @@ -990,20 +994,14 @@ static int handle_feature_check(int sk, CriuReq * msg) * be send from the parent process. */ ret = send_criu_msg(sk, &resp); - exit(ret); } - - ret = waitpid(pid, &status, 0); - if (ret == -1) + if (waitpid(pid, &status, 0) != pid) { + pr_perror("Unable to wait %d", pid); + goto out; + } + if (status != 0) goto out; - - if (WIFEXITED(status) && !WEXITSTATUS(status)) - /* - * The child process exited was able to send the answer. - * Nothing more to do here. - */ - return 0; /* * The child process was not able to send an answer. Tell @@ -1070,7 +1068,10 @@ cout: exit(ret); } - wait(&status); + if (waitpid(pid, &status, 0) != pid) { + pr_perror("Unable to wait %d", pid); + goto out; + } if (!WIFEXITED(status)) goto out; switch (WEXITSTATUS(status)) { From 87c036be90b2b3114ae56796b00f47782362ebbc Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 15 Oct 2018 19:16:14 +0300 Subject: [PATCH 1807/4375] service: call kerndat_init() before feature check setup_opts_from_req() sets up logging and call kerndat_init(). Investigated-by: Adrian Reber Fixes: 6e04f3b2dd06 ("criu: call kerndat_init() after log_init()") Signed-off-by: Andrei Vagin --- criu/cr-service.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index af9ccddd2..22ed7b503 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -971,6 +971,9 @@ static int handle_feature_check(int sk, CriuReq * msg) } if (pid == 0) { + /* kerndat_init() is called from setup_opts_from_req() */ + if (setup_opts_from_req(sk, msg->opts)) + exit(1); setproctitle("feature-check --rpc"); @@ -994,7 +997,7 @@ static int handle_feature_check(int sk, CriuReq * msg) * be send from the parent process. */ ret = send_criu_msg(sk, &resp); - exit(ret); + exit(!!ret); } if (waitpid(pid, &status, 0) != pid) { pr_perror("Unable to wait %d", pid); From c487ad187ad88d87e066c7de577811bc9a5bb224 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 15 Oct 2018 19:16:15 +0300 Subject: [PATCH 1808/4375] service: call cr_check() from a child process cr_check() initializes root_item and calls collect_pstree_ids. It was not designed to be called directly from a service process. Signed-off-by: Andrei Vagin --- criu/cr-service.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 22ed7b503..ed83fdf32 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -712,17 +712,36 @@ exit: return success ? 0 : 1; } -static int check(int sk) +static int check(int sk, CriuOpts *req) { + int pid, status; CriuResp resp = CRIU_RESP__INIT; resp.type = CRIU_REQ_TYPE__CHECK; - setproctitle("check --rpc"); + pid = fork(); + if (pid < 0) { + pr_perror("Can't fork"); + goto out; + } - if (!cr_check()) - resp.success = true; + if (pid == 0) { + setproctitle("check --rpc"); + if (setup_opts_from_req(sk, req)) + exit(1); + + exit(!!cr_check()); + } + if (waitpid(pid, &status, 0) != pid) { + pr_perror("Unable to wait %d", pid); + goto out; + } + if (status) + goto out; + + resp.success = true; +out: return send_criu_msg(sk, &resp); } @@ -1122,7 +1141,7 @@ more: ret = restore_using_req(sk, msg->opts); break; case CRIU_REQ_TYPE__CHECK: - ret = check(sk); + ret = check(sk, msg->opts); break; case CRIU_REQ_TYPE__PRE_DUMP: ret = pre_dump_loop(sk, msg); From de62bf764cea5ae25c2a57d8369dd1dcf4dcd602 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 15 Oct 2018 19:22:33 +0300 Subject: [PATCH 1809/4375] test/ipc_namespace: set random values less that IPCMNI for *mni sysctls There are a few patches in linux-next, which added this check: ipc: IPCMNI limit check for semmni ipc: IPCMNI limit check for msgmni and shmmni Signed-off-by: Andrei Vagin --- test/zdtm/static/ipc_namespace.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/zdtm/static/ipc_namespace.c b/test/zdtm/static/ipc_namespace.c index a7f0fd103..d01d654e5 100644 --- a/test/zdtm/static/ipc_namespace.c +++ b/test/zdtm/static/ipc_namespace.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "zdtmtst.h" @@ -237,6 +238,8 @@ static int rand_ipc_sysctl(char *name, unsigned int val) return 0; } +#define MAX_MNI (1<<15) + static int rand_ipc_sem(void) { int fd; @@ -249,8 +252,8 @@ static int rand_ipc_sem(void) pr_perror("Can't open %s", name); return fd; } - sprintf(buf, "%d %d %d %d\n", (unsigned)lrand48(), (unsigned)lrand48(), - (unsigned)lrand48(), (unsigned)lrand48()); + sprintf(buf, "%d %d %d %d\n", (unsigned) lrand48(), (unsigned) lrand48(), + (unsigned) lrand48(), (unsigned) lrand48() % MAX_MNI); ret = write(fd, buf, 128); if (ret < 0) { pr_perror("Can't write %s: %d", name, errno); @@ -260,8 +263,6 @@ static int rand_ipc_sem(void) return 0; } -#define INT_MAX ((int)(~0U>>1)) - static int rand_ipc_ns(void) { int ret; @@ -272,7 +273,7 @@ static int rand_ipc_ns(void) if (!ret) ret = rand_ipc_sysctl("/proc/sys/kernel/msgmnb", (unsigned)lrand48()); if (!ret) - ret = rand_ipc_sysctl("/proc/sys/kernel/msgmni", (unsigned)lrand48()); + ret = rand_ipc_sysctl("/proc/sys/kernel/msgmni", (unsigned)lrand48() % MAX_MNI); if (!ret) ret = rand_ipc_sysctl("/proc/sys/kernel/auto_msgmni", 0); if (!ret && (unsigned)lrand48() % 2) @@ -286,7 +287,7 @@ static int rand_ipc_ns(void) if (!ret) ret = rand_ipc_sysctl("/proc/sys/kernel/shmall", (unsigned)lrand48()); if (!ret) - ret = rand_ipc_sysctl("/proc/sys/kernel/shmmni", (unsigned)lrand48()); + ret = rand_ipc_sysctl("/proc/sys/kernel/shmmni", (unsigned)lrand48() % MAX_MNI); if (!ret) ret = rand_ipc_sysctl("/proc/sys/kernel/shm_rmid_forced", (unsigned)lrand48() & 1); From ae6839194ad6cd0f18bebde3139c89f47680bf0e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 15 Oct 2018 19:24:33 +0300 Subject: [PATCH 1810/4375] userns: exit from a child on error paths Here is one of popular error, when we call fork, then run a child code and instead of exiting from a child process, we returns from a current function with an error code. Signed-off-by: Andrei Vagin --- criu/namespaces.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/criu/namespaces.c b/criu/namespaces.c index 96cc2f0e5..05d75d533 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -862,27 +862,27 @@ static int check_user_ns(int pid) gid = host_gid(0); if (uid == INVALID_ID || gid == INVALID_ID) { pr_err("Unable to convert uid or gid\n"); - return -1; + exit(1); } if (prctl(PR_SET_KEEPCAPS, 1)) { pr_perror("Unable to set PR_SET_KEEPCAPS"); - return -1; + exit(1); } if (setresgid(gid, gid, gid)) { pr_perror("Unable to set group ID"); - return -1; + exit(1); } if (setgroups(0, NULL) < 0) { pr_perror("Unable to drop supplementary groups"); - return -1; + exit(1); } if (setresuid(uid, uid, uid)) { pr_perror("Unable to set user ID"); - return -1; + exit(1); } hdr.version = _LINUX_CAPABILITY_VERSION_3; @@ -890,13 +890,13 @@ static int check_user_ns(int pid) if (capget(&hdr, data) < 0) { pr_perror("capget"); - return -1; + exit(1); } data[0].effective = data[0].permitted; data[1].effective = data[1].permitted; if (capset(&hdr, data) < 0) { pr_perror("capset"); - return -1; + exit(1); } /* @@ -906,20 +906,20 @@ static int check_user_ns(int pid) */ if (switch_ns(pid, &user_ns_desc, NULL)) - exit(-1); + exit(1); if ((root_ns_mask & CLONE_NEWNET) && switch_ns(pid, &net_ns_desc, NULL)) - exit(-1); + exit(1); if ((root_ns_mask & CLONE_NEWUTS) && switch_ns(pid, &uts_ns_desc, NULL)) - exit(-1); + exit(1); if ((root_ns_mask & CLONE_NEWIPC) && switch_ns(pid, &ipc_ns_desc, NULL)) - exit(-1); + exit(1); if ((root_ns_mask & CLONE_NEWNS) && switch_ns(pid, &mnt_ns_desc, NULL)) - exit(-1); + exit(1); exit(0); } From eccdf07ae387765c377d29eb3ebfad4d7bc2fcf6 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 28 Oct 2018 01:44:57 +0300 Subject: [PATCH 1811/4375] python fix lint warnings flake8 started to report warnings like this: test/zdtm.py:1337:6: W605 invalid escape sequence '\S' Signed-off-by: Andrei Vagin --- scripts/flake8.cfg | 3 ++- test/zdtm.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/flake8.cfg b/scripts/flake8.cfg index 492129eca..9e98787a8 100644 --- a/scripts/flake8.cfg +++ b/scripts/flake8.cfg @@ -5,4 +5,5 @@ # E251 unexpected spaces around keyword / parameter equals # E101 indentation contains mixed spaces and tabs # E126 continuation line over-indented for hanging indent -ignore = W191,E128,E501,E251,E101,E126 +# W504 line break after binary operator +ignore = W191,E128,E501,E251,E101,E126,W504 diff --git a/test/zdtm.py b/test/zdtm.py index 19e362cd8..fc549c146 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -122,7 +122,7 @@ def check_core_files(): if not reports: return False - while subprocess.Popen("ps axf | grep 'abrt\.sh'", shell = True).wait() == 0: + while subprocess.Popen(r"ps axf | grep 'abrt\.sh'", shell = True).wait() == 0: time.sleep(1) for i in reports: @@ -189,7 +189,7 @@ class ns_flavor: def __copy_libs(self, binary): ldd = subprocess.Popen(["ldd", binary], stdout = subprocess.PIPE) - xl = re.compile('^(linux-gate.so|linux-vdso(64)?.so|not a dynamic|.*\s*ldd\s)') + xl = re.compile(r'^(linux-gate.so|linux-vdso(64)?.so|not a dynamic|.*\s*ldd\s)') # This Mayakovsky-style code gets list of libraries a binary # needs minus vdso and gate .so-s @@ -1334,7 +1334,7 @@ def get_visible_state(test): cmounts = [] try: - r = re.compile("^\S+\s\S+\s\S+\s(\S+)\s(\S+)\s\S+\s[^-]*?(shared)?[^-]*?(master)?[^-]*?-") + r = re.compile(r"^\S+\s\S+\s\S+\s(\S+)\s(\S+)\s\S+\s[^-]*?(shared)?[^-]*?(master)?[^-]*?-") with open("/proc/%s/root/proc/%s/mountinfo" % (test.getpid(), pid)) as mountinfo: for m in mountinfo: cmounts.append(r.match(m).groups()) From f25f9d57c88640b360bb2d6c1cd59423e1333ef9 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 28 Oct 2018 02:39:43 +0300 Subject: [PATCH 1812/4375] test/file_lock01: don't limit a maximum field width for device numbers Invalid lock info: lock: 1: FLOCK ADVISORY READ 61 103:00:1188168 0 EOF Signed-off-by: Andrei Vagin --- test/zdtm/static/file_locks01.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/file_locks01.c b/test/zdtm/static/file_locks01.c index 545238c13..c08c40b51 100644 --- a/test/zdtm/static/file_locks01.c +++ b/test/zdtm/static/file_locks01.c @@ -109,7 +109,7 @@ static int check_file_lock(int fd, char *expected_type, memset(fl_type, 0, sizeof(fl_type)); memset(fl_option, 0, sizeof(fl_option)); - num = sscanf(buf, "%*s %*d:%s %s %s %d %02x:%02x:%ld %*d %*s", + num = sscanf(buf, "%*s %*d:%s %s %s %d %x:%x:%ld %*d %*s", fl_flag, fl_type, fl_option, &fl_owner, &maj, &min, &i_no); if (num < 7) { From 2c5e8fd7ab02fc79f0281a5952dc52848a36cafe Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 31 Oct 2018 00:16:14 +0000 Subject: [PATCH 1813/4375] zdtm/x86: Don't override %ebx in fpu00 %ebx, %ecx aren't specified as clobbers in chk_proc_fpu(), while asm cpuid overwrites them. In the turn, %ebx is used as a code position by gcc now: 1661: e8 9a 00 00 00 call 1700 <__x86.get_pc_thunk.bx> 1666: 81 c3 46 68 00 00 add $0x6846,%ebx Which results in dereferencing some ugly garbage (result of cpuid). Let's use zdtm/lib cpuid() function instead. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/fpu00.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/test/zdtm/static/fpu00.c b/test/zdtm/static/fpu00.c index 3e168a2fe..04aa738fd 100644 --- a/test/zdtm/static/fpu00.c +++ b/test/zdtm/static/fpu00.c @@ -7,6 +7,9 @@ const char *test_doc = "Start a calculation, leaving FPU in a certain state,\n" const char *test_author = "Pavel Emelianov "; #if defined(__i386__) || defined(__x86_64__) + +#include "cpuid.h" + void start(float a, float b, float c, float d) { __asm__ volatile ( @@ -31,16 +34,15 @@ float finish(void) return res; } +#define CPUID_FEAT_EDX_FPU (1 << 0) + int chk_proc_fpu(void) { - unsigned long fi; + uint32_t eax, ebx, ecx, edx; - __asm__ volatile ( - "mov $1, %%eax\n" - "cpuid\n" - : "=d" (fi) : : "eax" - ); - return fi & (1 << 0); + cpuid(1, &eax, &ebx, &ecx, &edx); + + return edx & CPUID_FEAT_EDX_FPU; } #endif From 9ec094718176eaa003f48a3a3c797bca0645d1c7 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 30 Oct 2018 22:35:29 +0000 Subject: [PATCH 1814/4375] restorer: Remember to check ret codes for syscalls Looks like, we're missing the check which potentially can add us some troubles. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 186cbae40..d3b459c6c 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1263,11 +1263,19 @@ long __export_restore_task(struct task_restore_args *args) act.rt_sa_handler = sigchld_handler; act.rt_sa_flags = SA_SIGINFO | SA_RESTORER | SA_RESTART; act.rt_sa_restorer = cr_restore_rt; - sys_sigaction(SIGCHLD, &act, NULL, sizeof(k_rtsigset_t)); + ret = sys_sigaction(SIGCHLD, &act, NULL, sizeof(k_rtsigset_t)); + if (ret) { + pr_err("Failed to set SIGCHLD %ld\n", ret); + goto core_restore_end; + } ksigemptyset(&to_block); ksigaddset(&to_block, SIGCHLD); ret = sys_sigprocmask(SIG_UNBLOCK, &to_block, NULL, sizeof(k_rtsigset_t)); + if (ret) { + pr_err("Failed to unblock SIGCHLD %ld\n", ret); + goto core_restore_end; + } std_log_set_fd(args->logfd); std_log_set_loglevel(args->loglevel); @@ -1663,7 +1671,7 @@ long __export_restore_task(struct task_restore_args *args) } if (!args->compatible_mode) { - sys_sigaction(SIGCHLD, &args->sigchld_act, + ret = sys_sigaction(SIGCHLD, &args->sigchld_act, NULL, sizeof(k_rtsigset_t)); } else { void *stack = alloc_compat_syscall_stack(); @@ -1672,10 +1680,14 @@ long __export_restore_task(struct task_restore_args *args) pr_err("Failed to allocate 32-bit stack for sigaction\n"); goto core_restore_end; } - arch_compat_rt_sigaction(stack, SIGCHLD, + ret = arch_compat_rt_sigaction(stack, SIGCHLD, (void*)&args->sigchld_act); free_compat_syscall_stack(stack); } + if (ret) { + pr_err("Failed to restore SIGCHLD: %ld\n", ret); + goto core_restore_end; + } ret = restore_signals(args->siginfo, args->siginfo_n, true); if (ret) From b0c5881d5521adb6f0d73f17cbe74f1457397cae Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 30 Oct 2018 22:35:30 +0000 Subject: [PATCH 1815/4375] x86/compat: Use do_full_int80() instead of jump to ia32 mode Kernel will send signal with ABI of *syscall* that made rt_sigacation(). In sigaction_compat_abi(): > if (in_ia32_syscall()) > act->sa.sa_flags |= SA_IA32_ABI; So, we can omit switching to ia32 mode and just call int80 like in other places. We still need 32-bit argument for syscall (sig action pointer). As call32_from_64() switches mode, it's .text should be placed in lower 4Gb, which was the reason of segfault if linker places criu code above 4Gb. Oops, my bad. Fixes: #567 Reported-by: Andrey Vagin Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/call32.S | 7 +++++++ criu/arch/x86/sigaction_compat.c | 18 ++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/criu/arch/x86/call32.S b/criu/arch/x86/call32.S index c2ddd9fc2..8c32c4f7a 100644 --- a/criu/arch/x86/call32.S +++ b/criu/arch/x86/call32.S @@ -23,6 +23,13 @@ /* * @rdi: Stack to use * @esi: Pointer to function for calling + * + * Note: .code32 in this function doesn't guarantee that is will + * be place under 4GB by linker. + * Linker script would guarantee that, but it would break + * -fpie address randomization. In the end, the caller is + * responible for placing/checking that the code is + * accessible in 32-bit mode. */ ENTRY(call32_from_64) /* Callee-saving registers due to ABI */ diff --git a/criu/arch/x86/sigaction_compat.c b/criu/arch/x86/sigaction_compat.c index 5965ef79f..b38ba8011 100644 --- a/criu/arch/x86/sigaction_compat.c +++ b/criu/arch/x86/sigaction_compat.c @@ -29,17 +29,27 @@ extern char restore_rt_sigaction; int arch_compat_rt_sigaction(void *stack32, int sig, rt_sigaction_t_compat *act) { int ret; + struct syscall_args32 arg = {}; + unsigned long act_stack = (unsigned long)stack32; + + /* To make sure the 32-bit stack was allocated in caller */ + if (act_stack >= (uint32_t)-1) { + pr_err("compat rt_sigaction without 32-bit stack\n"); + return -1; + } /* * To be sure, that sigaction pointer lies under 4G, * coping it on the bottom of the stack. */ memcpy(stack32, act, sizeof(rt_sigaction_t_compat)); + arg.nr = __NR32_rt_sigaction; + arg.arg0 = sig; + arg.arg1 = (uint32_t)act_stack; /* act */ + arg.arg2 = 0; /* oldact */ + arg.arg3 = (uint32_t)sizeof(act->rt_sa_mask); /* sigsetsize */ - asm volatile ("\t movl %%ebx,%%ebx\n" : :"b"(sig)); /* signum */ - asm volatile ("\t movl %%ecx,%%ecx\n" : :"c"(stack32)); /* act */ - asm volatile ("\t movl %%edx,%%edx\n" : :"d"(sizeof(act->rt_sa_mask))); - call32_from_64(stack32 + PAGE_SIZE, &restore_rt_sigaction); + do_full_int80(&arg); asm volatile ("\t movl %%eax,%0\n" : "=r"(ret)); return ret; } From e2bd7af94cb7b43e2c0bed0546ef83c2f3eea25c Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 30 Oct 2018 22:35:31 +0000 Subject: [PATCH 1816/4375] x86/compat: Remove call32_from_64() helper It looks like, this one is no more needed. You were a hard child, RIP. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/Makefile | 1 - criu/arch/x86/call32.S | 83 ------------------------------ criu/arch/x86/include/asm/compat.h | 5 -- criu/pie/Makefile | 1 - 4 files changed, 90 deletions(-) delete mode 100644 criu/arch/x86/call32.S diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index 75fa782c8..20a40e4ae 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -15,5 +15,4 @@ obj-y += kerndat.o obj-y += sigframe.o ifeq ($(CONFIG_COMPAT),y) obj-y += sigaction_compat.o - obj-y += call32.o endif diff --git a/criu/arch/x86/call32.S b/criu/arch/x86/call32.S deleted file mode 100644 index 8c32c4f7a..000000000 --- a/criu/arch/x86/call32.S +++ /dev/null @@ -1,83 +0,0 @@ -/* - * call32.S - assembly helpers for mixed-bitness code - * From kernel selftests originally: tools/testing/selftests/x86/thunks.S - * Copyright (c) 2015 Andrew Lutomirski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * These are little helpers that make it easier to switch bitness on - * the fly. - */ - -#include "common/asm/linkage.h" - - .text - -/* - * @rdi: Stack to use - * @esi: Pointer to function for calling - * - * Note: .code32 in this function doesn't guarantee that is will - * be place under 4GB by linker. - * Linker script would guarantee that, but it would break - * -fpie address randomization. In the end, the caller is - * responible for placing/checking that the code is - * accessible in 32-bit mode. - */ -ENTRY(call32_from_64) - /* Callee-saving registers due to ABI */ - pushq %rbx - pushq %rbp - pushq %r12 - pushq %r13 - pushq %r14 - pushq %r15 - pushfq - - /* Switch stacks */ - sub $8, %rdi - mov %rsp,(%rdi) - mov %rdi,%rsp - - /* Push return address and 64-bit segment descriptor */ - sub $4, %rsp - movl $__USER_CS,(%rsp) - sub $4, %rsp - /* Using rip-relative addressing to get rid of R_X86_64_32S relocs */ - leaq 2f(%rip),%r12 - movl %r12d,(%rsp) - - /* Switch into compatibility mode */ - pushq $__USER32_CS - /* Using rip-relative addressing to get rid of R_X86_64_32S relocs */ - leaq 1f(%rip), %r12 - pushq %r12 - lretq - -1: .code32 - /* Run function and switch back */ - call *%esi - lret - -2: .code64 - /* Restore the stack */ - mov (%rsp),%rsp - add $8, %rdi - - /* Restore registers */ - popfq - popq %r15 - popq %r14 - popq %r13 - popq %r12 - popq %rbp - popq %rbx - ret -END(call32_from_64) diff --git a/criu/arch/x86/include/asm/compat.h b/criu/arch/x86/include/asm/compat.h index dce28adf6..cd1ae472d 100644 --- a/criu/arch/x86/include/asm/compat.h +++ b/criu/arch/x86/include/asm/compat.h @@ -60,11 +60,6 @@ static inline void do_full_int80(struct syscall_args32 *args) : : "r8", "r9", "r10", "r11"); } - -#ifdef CONFIG_COMPAT -extern unsigned long call32_from_64(void *stack, void *func); -#endif - #ifndef CR_NOGLIBC # undef sys_mmap # undef sys_munmap diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 8b05c14a0..24f97ea0d 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -25,7 +25,6 @@ restorer-obj-y += ./$(ARCH_DIR)/restorer.o ifeq ($(ARCH),x86) ifeq ($(CONFIG_COMPAT),y) - restorer-obj-y += ./$(ARCH_DIR)/call32.o restorer-obj-y += ./$(ARCH_DIR)/restorer_unmap.o restorer-obj-y += ./$(ARCH_DIR)/sigaction_compat_pie.o endif From 54daec1899cf4851387d53dc4ac1d74bf3556536 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 1 Nov 2018 07:36:15 +0300 Subject: [PATCH 1817/4375] test/file_locks: use struct flock instead of struct flock64 If we want to use flock64, we have to use fcntl64. Otherwise we will get errors like this: ERR: file_locks07.c:49: Can't set ofd lock (errno = 22 (Invalid argument)) Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin --- test/zdtm/static/file_locks00.c | 6 +++--- test/zdtm/static/file_locks06.c | 4 ++-- test/zdtm/static/file_locks07.c | 4 ++-- test/zdtm/static/file_locks08.c | 4 ++-- test/zdtm/static/ofd_file_locks.c | 12 ++++++------ test/zdtm/static/ofd_file_locks.h | 4 ++-- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/test/zdtm/static/file_locks00.c b/test/zdtm/static/file_locks00.c index 8a1ecc26f..f751e377a 100644 --- a/test/zdtm/static/file_locks00.c +++ b/test/zdtm/static/file_locks00.c @@ -22,7 +22,7 @@ char file1[PATH_MAX]; static int lock_reg(int fd, int cmd, int type, int whence, off_t offset, off_t len) { - struct flock64 lock; + struct flock lock; lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */ lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */ @@ -40,7 +40,7 @@ static int lock_reg(int fd, int cmd, int type, int whence, static int check_read_lock(int fd, int whence, off_t offset, off_t len) { - struct flock64 lock; + struct flock lock; int ret; lock.l_type = F_RDLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */ @@ -67,7 +67,7 @@ static int check_read_lock(int fd, int whence, off_t offset, off_t len) static int check_write_lock(int fd, int whence, off_t offset, off_t len) { - struct flock64 lock; + struct flock lock; int ret; pid_t ppid = getppid(); diff --git a/test/zdtm/static/file_locks06.c b/test/zdtm/static/file_locks06.c index 53f088f0d..9bc70c47d 100644 --- a/test/zdtm/static/file_locks06.c +++ b/test/zdtm/static/file_locks06.c @@ -12,7 +12,7 @@ char *filename; TEST_OPTION(filename, string, "file name", 1); -int init_lock(int *fd, struct flock64 *lck) +int init_lock(int *fd, struct flock *lck) { *fd = open(filename, O_RDWR | O_CREAT, 0666); if (*fd < 0) { @@ -45,7 +45,7 @@ void cleanup(int *fd) int main(int argc, char **argv) { int fd; - struct flock64 lck; + struct flock lck; test_init(argc, argv); if (init_lock(&fd, &lck)) diff --git a/test/zdtm/static/file_locks07.c b/test/zdtm/static/file_locks07.c index 8bd517491..b36f23011 100644 --- a/test/zdtm/static/file_locks07.c +++ b/test/zdtm/static/file_locks07.c @@ -14,12 +14,12 @@ TEST_OPTION(filename, string, "file name", 1); #define FILE_NUM 4 static int fds[FILE_NUM]; -static struct flock64 lcks[FILE_NUM]; +static struct flock lcks[FILE_NUM]; static short types[] = {F_RDLCK, F_RDLCK, F_RDLCK, F_RDLCK}; static off_t starts[] = {0, 10, 0, 70}; static off_t lens[] = {20, 30, 100, 200}; -void fill_lock(struct flock64 *lock, off_t start, off_t len, short int type) +void fill_lock(struct flock *lock, off_t start, off_t len, short int type) { lock->l_start = start; lock->l_len = len; diff --git a/test/zdtm/static/file_locks08.c b/test/zdtm/static/file_locks08.c index a654c205b..2d25b4b09 100644 --- a/test/zdtm/static/file_locks08.c +++ b/test/zdtm/static/file_locks08.c @@ -14,7 +14,7 @@ char *filename; TEST_OPTION(filename, string, "file name", 1); -int init_file_lock(int *fd, struct flock64 *lck) +int init_file_lock(int *fd, struct flock *lck) { *fd = open(filename, O_RDWR | O_CREAT, 0666); if (*fd < 0) { @@ -51,7 +51,7 @@ int main(int argc, char **argv) int status; int ret = 0; task_waiter_t tw; - struct flock64 lck; + struct flock lck; test_init(argc, argv); if (init_file_lock(&fd, &lck)) diff --git a/test/zdtm/static/ofd_file_locks.c b/test/zdtm/static/ofd_file_locks.c index 61495a202..c4a633625 100644 --- a/test/zdtm/static/ofd_file_locks.c +++ b/test/zdtm/static/ofd_file_locks.c @@ -7,7 +7,7 @@ #include "fs.h" #include "ofd_file_locks.h" -static int parse_ofd_lock(char *buf, struct flock64 *lck) +static int parse_ofd_lock(char *buf, struct flock *lck) { char fl_flag[10], fl_type[15], fl_option[10], fl_end[32]; long long start; @@ -48,7 +48,7 @@ static int parse_ofd_lock(char *buf, struct flock64 *lck) return 0; } -static int read_fd_ofd_lock(int pid, int fd, struct flock64 *lck) +static int read_fd_ofd_lock(int pid, int fd, struct flock *lck) { char path[PATH_MAX]; char buf[100]; @@ -77,7 +77,7 @@ static int read_fd_ofd_lock(int pid, int fd, struct flock64 *lck) return num; } -int check_lock_exists(const char *filename, struct flock64 *lck) +int check_lock_exists(const char *filename, struct flock *lck) { int ret = -1; int fd; @@ -116,16 +116,16 @@ out: return ret; } -static int check_file_locks_match(struct flock64 *orig_lck, struct flock64 *lck) +static int check_file_locks_match(struct flock *orig_lck, struct flock *lck) { return orig_lck->l_start == lck->l_start && orig_lck->l_len == lck->l_len && orig_lck->l_type == lck->l_type; } -int check_file_lock_restored(int pid, int fd, struct flock64 *lck) +int check_file_lock_restored(int pid, int fd, struct flock *lck) { - struct flock64 lck_restored; + struct flock lck_restored; if (read_fd_ofd_lock(pid, fd, &lck_restored)) return -1; diff --git a/test/zdtm/static/ofd_file_locks.h b/test/zdtm/static/ofd_file_locks.h index 0d500e1bf..6978446df 100644 --- a/test/zdtm/static/ofd_file_locks.h +++ b/test/zdtm/static/ofd_file_locks.h @@ -14,7 +14,7 @@ * from procfs and checking them after restoring. */ -extern int check_lock_exists(const char *filename, struct flock64 *lck); -extern int check_file_lock_restored(int pid, int fd, struct flock64 *lck); +extern int check_lock_exists(const char *filename, struct flock *lck); +extern int check_file_lock_restored(int pid, int fd, struct flock *lck); #endif /* ZDTM_OFD_FILE_LOCKS_H_ */ From d01899e15b95e8077a04138b02b5afe5bf1c4f49 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 1 Nov 2018 18:25:37 +0300 Subject: [PATCH 1818/4375] test/file_locks: use F_GETLK instead of F_GETLK64 F_GETLK64 has to be used with flock64 Reported-by: Mr Jenkins --- test/zdtm/static/file_locks00.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/zdtm/static/file_locks00.c b/test/zdtm/static/file_locks00.c index f751e377a..59e19cfe1 100644 --- a/test/zdtm/static/file_locks00.c +++ b/test/zdtm/static/file_locks00.c @@ -34,9 +34,9 @@ static int lock_reg(int fd, int cmd, int type, int whence, } #define set_read_lock(fd, whence, offset, len) \ - lock_reg(fd, F_SETLK64, F_RDLCK, whence, offset, len) + lock_reg(fd, F_SETLK, F_RDLCK, whence, offset, len) #define set_write_lock(fd, whence, offset, len) \ - lock_reg(fd, F_SETLK64, F_WRLCK, whence, offset, len) + lock_reg(fd, F_SETLK, F_WRLCK, whence, offset, len) static int check_read_lock(int fd, int whence, off_t offset, off_t len) { @@ -50,7 +50,7 @@ static int check_read_lock(int fd, int whence, off_t offset, off_t len) lock.l_pid = -1; errno = 0; - ret = fcntl(fd, F_GETLK64, &lock); + ret = fcntl(fd, F_GETLK, &lock); if (ret == -1) { pr_perror("F_GETLK failed."); return -1; @@ -79,7 +79,7 @@ static int check_write_lock(int fd, int whence, off_t offset, off_t len) lock.l_pid = -1; errno = 0; - ret = fcntl(fd, F_GETLK64, &lock); + ret = fcntl(fd, F_GETLK, &lock); if (ret == -1) { pr_perror("F_GETLK failed."); return -1; From 44a10467a621640e313979fbeefbca0d87629adc Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 29 Oct 2018 19:22:29 +0300 Subject: [PATCH 1819/4375] cgroup: allow to specify a new root for each controller separately A few controllers can be merged and before this patch, criu required to set a new root by specifying all merged controllers. This patch allows to specify a new root for each controller separately, but criu will check that all merged controllers will have the same path. https://github.com/checkpoint-restore/criu/issues/544 Signed-off-by: Andrei Vagin --- criu/cgroup.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index 26f159c74..22e722acf 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -186,7 +186,8 @@ int parse_cg_info(void) /* Check that co-mounted controllers from /proc/cgroups (e.g. cpu and cpuacct) * are contained in a comma separated string (e.g. from /proc/self/cgroup or * mount options). */ -static bool cgroup_contains(char **controllers, unsigned int n_controllers, char *name) +static bool cgroup_contains(char **controllers, + unsigned int n_controllers, char *name, u64 *mask) { unsigned int i; bool all_match = true; @@ -201,6 +202,8 @@ static bool cgroup_contains(char **controllers, unsigned int n_controllers, char case '\0': case ',': found = true; + if (mask) + *mask &= ~(1ULL << i); break; } } @@ -557,7 +560,7 @@ static int collect_cgroups(struct list_head *ctls) * controller from parse_cgroups(), so find that controller if * it exists. */ list_for_each_entry(cg, &cgroups, l) { - if (cgroup_contains(cg->controllers, cg->n_controllers, cc->name)) { + if (cgroup_contains(cg->controllers, cg->n_controllers, cc->name, NULL)) { current_controller = cg; break; } @@ -1021,7 +1024,7 @@ static int prepare_cgns(CgSetEntry *se) for (j = 0; j < n_controllers; j++) { CgControllerEntry *cur = controllers[j]; - if (cgroup_contains(cur->cnames, cur->n_cnames, ce->name)) { + if (cgroup_contains(cur->cnames, cur->n_cnames, ce->name, NULL)) { ctrl = cur; break; } @@ -1093,7 +1096,7 @@ static int move_in_cgroup(CgSetEntry *se, bool setup_cgns) for (j = 0; j < n_controllers; j++) { CgControllerEntry *cur = controllers[j]; - if (cgroup_contains(cur->cnames, cur->n_cnames, ce->name)) { + if (cgroup_contains(cur->cnames, cur->n_cnames, ce->name, NULL)) { ctrl = cur; break; } @@ -1758,7 +1761,7 @@ static int rewrite_cgsets(CgroupEntry *cge, char **controllers, int n_controller * and its path with stripping leading * "/" is matching to be renamed. */ - if (!(cgroup_contains(controllers, n_controllers, cg->name) && + if (!(cgroup_contains(controllers, n_controllers, cg->name, NULL) && strstartswith(cg->path + 1, dir))) continue; @@ -1813,20 +1816,32 @@ static int rewrite_cgroup_roots(CgroupEntry *cge) { int i, j; struct cg_root_opt *o; - char *newroot = NULL; for (i = 0; i < cge->n_controllers; i++) { CgControllerEntry *ctrl = cge->controllers[i]; - newroot = opts.new_global_cg_root; + u64 ctrl_mask = (1ULL << ctrl->n_cnames) - 1; + char *newroot = NULL; list_for_each_entry(o, &opts.new_cgroup_roots, node) { - if (cgroup_contains(ctrl->cnames, ctrl->n_cnames, o->controller)) { - newroot = o->newroot; - break; - } + unsigned old_mask = ctrl_mask; + cgroup_contains(ctrl->cnames, ctrl->n_cnames, + o->controller, &ctrl_mask); + if (old_mask != ctrl_mask) { + if (newroot && strcmp(newroot, o->newroot)) { + pr_err("CG paths mismatch: %s %s\n", + newroot, o->newroot); + return -1; + } + newroot = o->newroot; + } + if (!ctrl_mask) + break; } + if (!newroot) + newroot = opts.new_global_cg_root; + if (newroot) { for (j = 0; j < ctrl->n_dirs; j++) { CgroupDirEntry *cgde = ctrl->dirs[j]; From 12fb7f5af06062ff7d162bec6d5f521e99ae5258 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 31 Oct 2018 21:36:11 +0000 Subject: [PATCH 1820/4375] Go-criu clean up The Go bindings for CRIU and the P.Haul extension have been moved into a separate repository. This patch removes the following from the criu-dev branch: - lib/go/* - phaul/* - scripts/travis/phaul The removed files are available in https://github.com/checkpoint-restore/go-criu Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- README.md | 4 +- lib/go/.gitignore | 1 - lib/go/Makefile | 8 -- lib/go/src/criu/main.go | 177 -------------------------------------- lib/go/src/criu/notify.go | 52 ----------- lib/go/src/test/main.go | 114 ------------------------ 6 files changed, 3 insertions(+), 353 deletions(-) delete mode 100644 lib/go/.gitignore delete mode 100644 lib/go/Makefile delete mode 100644 lib/go/src/criu/main.go delete mode 100644 lib/go/src/criu/notify.go delete mode 100644 lib/go/src/test/main.go diff --git a/README.md b/README.md index abfec1dca..e28964604 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,9 @@ injection and libsoccr for TCP connections checkpoint-restore. True [live migration](https://criu.org/Live_migration) using CRIU is possible, but doing all the steps by hands might be complicated. The [phaul sub-project](https://criu.org/P.Haul) -provides a Go library that encapsulates most of the complexity. +provides a Go library that encapsulates most of the complexity. This library and the Go bindings +for CRIU are stored in the [go-criu](https://github.com/checkpoint-restore/go-criu) repository. + ### Parasite code injection diff --git a/lib/go/.gitignore b/lib/go/.gitignore deleted file mode 100644 index 8cab5691e..000000000 --- a/lib/go/.gitignore +++ /dev/null @@ -1 +0,0 @@ -src/rpc/rpc.pb.go diff --git a/lib/go/Makefile b/lib/go/Makefile deleted file mode 100644 index c8551d609..000000000 --- a/lib/go/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -all: test - -test: rpc - GOPATH=$(shell pwd):/usr/share/gocode go build -o test test - -rpc: - mkdir -p src/rpc/ - protoc --go_out=src/rpc/ --proto_path=../../images/ ../../images/rpc.proto diff --git a/lib/go/src/criu/main.go b/lib/go/src/criu/main.go deleted file mode 100644 index 90866ea18..000000000 --- a/lib/go/src/criu/main.go +++ /dev/null @@ -1,177 +0,0 @@ -package criu - -import ( - "errors" - "fmt" - "github.com/golang/protobuf/proto" - "os" - "os/exec" - "rpc" - "strconv" - "syscall" -) - -type Criu struct { - swrk_cmd *exec.Cmd - swrk_sk *os.File -} - -func MakeCriu() *Criu { - return &Criu{} -} - -func (c *Criu) Prepare() error { - fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_SEQPACKET, 0) - if err != nil { - return err - } - - cln := os.NewFile(uintptr(fds[0]), "criu-xprt-cln") - syscall.CloseOnExec(fds[0]) - srv := os.NewFile(uintptr(fds[1]), "criu-xprt-srv") - defer srv.Close() - - args := []string{"swrk", strconv.Itoa(fds[1])} - cmd := exec.Command("criu", args...) - - err = cmd.Start() - if err != nil { - cln.Close() - return err - } - - c.swrk_cmd = cmd - c.swrk_sk = cln - - return nil -} - -func (c *Criu) Cleanup() { - if c.swrk_cmd != nil { - c.swrk_sk.Close() - c.swrk_sk = nil - c.swrk_cmd.Wait() - c.swrk_cmd = nil - } -} - -func (c *Criu) sendAndRecv(req_b []byte) ([]byte, int, error) { - cln := c.swrk_sk - _, err := cln.Write(req_b) - if err != nil { - return nil, 0, err - } - - resp_b := make([]byte, 2*4096) - n, err := cln.Read(resp_b) - if err != nil { - return nil, 0, err - } - - return resp_b, n, nil -} - -func (c *Criu) doSwrk(req_type rpc.CriuReqType, opts *rpc.CriuOpts, nfy CriuNotify) error { - req := rpc.CriuReq{ - Type: &req_type, - Opts: opts, - } - - if nfy != nil { - opts.NotifyScripts = proto.Bool(true) - } - - if c.swrk_cmd == nil { - err := c.Prepare() - if err != nil { - return err - } - - defer c.Cleanup() - } - - for { - req_b, err := proto.Marshal(&req) - if err != nil { - return err - } - - resp_b, resp_s, err := c.sendAndRecv(req_b) - if err != nil { - return err - } - - resp := &rpc.CriuResp{} - err = proto.Unmarshal(resp_b[:resp_s], resp) - if err != nil { - return err - } - - if !resp.GetSuccess() { - return fmt.Errorf("operation failed (msg:%s err:%d)", - resp.GetCrErrmsg(), resp.GetCrErrno()) - } - - resp_type := resp.GetType() - if resp_type == req_type { - break - } - if resp_type != rpc.CriuReqType_NOTIFY { - return errors.New("unexpected responce") - } - if nfy == nil { - return errors.New("unexpected notify") - } - - notify := resp.GetNotify() - switch notify.GetScript() { - case "pre-dump": - err = nfy.PreDump() - case "post-dump": - err = nfy.PostDump() - case "pre-restore": - err = nfy.PreRestore() - case "post-restore": - err = nfy.PostRestore(notify.GetPid()) - case "network-lock": - err = nfy.NetworkLock() - case "network-unlock": - err = nfy.NetworkUnlock() - case "setup-namespaces": - err = nfy.SetupNamespaces(notify.GetPid()) - case "post-setup-namespaces": - err = nfy.PostSetupNamespaces() - case "post-resume": - err = nfy.PostResume() - default: - err = nil - } - - if err != nil { - return err - } - - req = rpc.CriuReq{ - Type: &resp_type, - NotifySuccess: proto.Bool(true), - } - } - - return nil -} - -func (c *Criu) Dump(opts rpc.CriuOpts, nfy CriuNotify) error { - return c.doSwrk(rpc.CriuReqType_DUMP, &opts, nfy) -} - -func (c *Criu) Restore(opts rpc.CriuOpts, nfy CriuNotify) error { - return c.doSwrk(rpc.CriuReqType_RESTORE, &opts, nfy) -} - -func (c *Criu) PreDump(opts rpc.CriuOpts, nfy CriuNotify) error { - return c.doSwrk(rpc.CriuReqType_PRE_DUMP, &opts, nfy) -} - -func (c *Criu) StartPageServer(opts rpc.CriuOpts) error { - return c.doSwrk(rpc.CriuReqType_PAGE_SERVER, &opts, nil) -} diff --git a/lib/go/src/criu/notify.go b/lib/go/src/criu/notify.go deleted file mode 100644 index 8ce16b7f7..000000000 --- a/lib/go/src/criu/notify.go +++ /dev/null @@ -1,52 +0,0 @@ -package criu - -type CriuNotify interface { - PreDump() error - PostDump() error - PreRestore() error - PostRestore(pid int32) error - NetworkLock() error - NetworkUnlock() error - SetupNamespaces(pid int32) error - PostSetupNamespaces() error - PostResume() error -} - -type CriuNoNotify struct { -} - -func (c CriuNoNotify) PreDump() error { - return nil -} - -func (c CriuNoNotify) PostDump() error { - return nil -} - -func (c CriuNoNotify) PreRestore() error { - return nil -} - -func (c CriuNoNotify) PostRestore(pid int32) error { - return nil -} - -func (c CriuNoNotify) NetworkLock() error { - return nil -} - -func (c CriuNoNotify) NetworkUnlock() error { - return nil -} - -func (c CriuNoNotify) SetupNamespaces(pid int32) error { - return nil -} - -func (c CriuNoNotify) PostSetupNamespaces() error { - return nil -} - -func (c CriuNoNotify) PostResume() error { - return nil -} diff --git a/lib/go/src/test/main.go b/lib/go/src/test/main.go deleted file mode 100644 index ae38befdf..000000000 --- a/lib/go/src/test/main.go +++ /dev/null @@ -1,114 +0,0 @@ -package main - -import ( - "criu" - "fmt" - "github.com/golang/protobuf/proto" - "os" - "rpc" - "strconv" -) - -type TestNfy struct { - criu.CriuNoNotify -} - -func (c TestNfy) PreDump() error { - fmt.Printf("TEST PRE DUMP\n") - return nil -} - -func doDump(c *criu.Criu, pid_s string, img_dir string, pre bool, prev_img string) error { - fmt.Printf("Dumping\n") - pid, _ := strconv.Atoi(pid_s) - img, err := os.Open(img_dir) - if err != nil { - return fmt.Errorf("can't open image dir (%s)", err) - } - defer img.Close() - - opts := rpc.CriuOpts{ - Pid: proto.Int32(int32(pid)), - ImagesDirFd: proto.Int32(int32(img.Fd())), - LogLevel: proto.Int32(4), - LogFile: proto.String("dump.log"), - } - - if prev_img != "" { - opts.ParentImg = proto.String(prev_img) - opts.TrackMem = proto.Bool(true) - } - - if pre { - err = c.PreDump(opts, TestNfy{}) - } else { - err = c.Dump(opts, TestNfy{}) - } - if err != nil { - return fmt.Errorf("dump fail (%s)", err) - } - - return nil -} - -// Usage: test $act $pid $images_dir -func main() { - c := criu.MakeCriu() - act := os.Args[1] - switch act { - case "dump": - err := doDump(c, os.Args[2], os.Args[3], false, "") - if err != nil { - fmt.Print(err) - os.Exit(1) - } - case "dump2": - err := c.Prepare() - if err != nil { - fmt.Print(err) - os.Exit(1) - } - - err = doDump(c, os.Args[2], os.Args[3]+"/pre", true, "") - if err != nil { - fmt.Printf("pre-dump failed") - fmt.Print(err) - os.Exit(1) - } - err = doDump(c, os.Args[2], os.Args[3], false, "./pre") - if err != nil { - fmt.Printf("dump failed") - fmt.Print(err) - os.Exit(1) - } - - c.Cleanup() - case "restore": - fmt.Printf("Restoring\n") - img, err := os.Open(os.Args[2]) - if err != nil { - fmt.Printf("can't open image dir") - os.Exit(1) - } - defer img.Close() - - opts := rpc.CriuOpts{ - ImagesDirFd: proto.Int32(int32(img.Fd())), - LogLevel: proto.Int32(4), - LogFile: proto.String("restore.log"), - } - - err = c.Restore(opts, nil) - if err != nil { - fmt.Printf("Error:") - fmt.Print(err) - fmt.Printf("\n") - os.Exit(1) - } - default: - fmt.Printf("unknown action\n") - os.Exit(1) - } - - fmt.Printf("Success\n") -} From 565498a7743ba61084a0c93900832f90641c9ba9 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 29 Oct 2018 17:05:48 +0100 Subject: [PATCH 1821/4375] tests: more python3 compatibility This makes two zdtm test scripts python3 compatible to run zdtm on a system without python2. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/zdtm/static/file_locks06.checkskip | 6 +++--- test/zdtm/static/socket-tcp-fin-wait1.hook | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/zdtm/static/file_locks06.checkskip b/test/zdtm/static/file_locks06.checkskip index e5a4775f8..06ab58521 100755 --- a/test/zdtm/static/file_locks06.checkskip +++ b/test/zdtm/static/file_locks06.checkskip @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python import fcntl import tempfile import struct @@ -12,8 +12,8 @@ try: fcntl.fcntl(fd.fileno(), F_OFD_SETLK, flock) except IOError as e: if e.errno == errno.EINVAL: - print "I/O error({0}): {1}".format(e.errno, e.strerror) - print "OFD locks are not supported." + print("I/O error({0}): {1}".format(e.errno, e.strerror)) + print("OFD locks are not supported.") exit(1) exit(0) diff --git a/test/zdtm/static/socket-tcp-fin-wait1.hook b/test/zdtm/static/socket-tcp-fin-wait1.hook index 9630e0d74..9504557da 100755 --- a/test/zdtm/static/socket-tcp-fin-wait1.hook +++ b/test/zdtm/static/socket-tcp-fin-wait1.hook @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python import sys sys.path.append("../crit") @@ -13,13 +13,13 @@ if sys.argv[1] in ["--pre-dump", "--post-restore"]: pid = os.getenv("ZDTM_TEST_PID") try: subprocess.Popen(["nsenter", "-t", pid, "-n", "ss", "-t", "-a", "-n"]).wait() - except OSError, e: + except OSError as e: pass if sys.argv[1] != "--post-restore": sys.exit(0) -print "Check TCP images" +print("Check TCP images") def get_sockets(image_dir): fname = os.path.join(image_dir, "inetsk.img") @@ -34,7 +34,7 @@ def get_sockets(image_dir): f = open(os.path.join(image_dir, "inetsk.img")) ids = pycriu.images.load(f) tcp_img = os.path.join(image_dir, "tcp-stream-%x.img" % int(s["ino"])) - print tcp_img + print(tcp_img) if os.access(tcp_img, os.F_OK): f = open(tcp_img) tcp = pycriu.images.load(f) @@ -65,6 +65,6 @@ for d in os.listdir(path): sockets_str = json.dumps(sockets, sys.stdout, indent=8, sort_keys=True) prev_str = json.dumps(prev, sys.stdout, indent=8, sort_keys=True) - print "\n".join(difflib.unified_diff(prev_str.split("\n"), sockets_str.split("\n"))) + print("\n".join(difflib.unified_diff(prev_str.split("\n"), sockets_str.split("\n")))) sys.exit(exit_code) From deef94ce7c3a062c210283c6fa899313673d93a5 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 4 Nov 2018 21:01:25 +0300 Subject: [PATCH 1822/4375] test: use yaml.safe_dump to avoid dump without tags safe_dump produces only standard YAML tags and cannot represent an arbitrary Python object. Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin --- test/zdtm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index fc549c146..5c529ebe4 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1726,7 +1726,8 @@ class Launcher: details = {'output': output} tc.add_error_info(output = output) print(testline, file=self.__file_report) - print("%s" % yaml.dump(details, explicit_start=True, explicit_end=True, default_style='|'), file=self.__file_report) + print("%s" % yaml.safe_dump(details, explicit_start=True, + explicit_end=True, default_style='|'), file=self.__file_report) if sub['log']: add_to_output(sub['log']) else: From 740ae4a360c6e91cd1640a21486eb884cb58f3cf Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 3 Oct 2018 14:54:11 +0300 Subject: [PATCH 1823/4375] x86: cpu -- Don't fail if member is not present in image When migrating from old images the particular xsave member might not be present in core-* image, which is fine we simply left data as initial zero state. https://jira.sw.ru/browse/PSBM-89215 Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 185ade407..ee016da00 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -438,9 +438,14 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) size_t size = pb_repeated_size(xsave, member); \ size_t xsize = (size_t)compel_fpu_feature_size(feature); \ if (xsize != size) { \ - pr_err("%s reported %zu bytes (expecting %zu)\n", \ - # feature, xsize, size); \ - return -1; \ + if (size) { \ + pr_err("%s reported %zu bytes (expecting %zu)\n",\ + # feature, xsize, size); \ + return -1; \ + } else { \ + pr_debug("%s is not present in image, ignore\n",\ + # feature); \ + } \ } \ xstate_bv |= (1UL << feature); \ xstate_size += xsize; \ From c74b83cd49c00589c0c0468ba5fe685b67fdbd0a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 6 Nov 2018 14:31:36 +0300 Subject: [PATCH 1824/4375] criu: Version 3.11 (for workgroups) So here it is -- the release with lots of new stuff and bugfixes. Mainly, the new code is for integration with Docker and to support modern hardware. Signed-off-by: Pavel Emelyanov --- Makefile.versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index 2e149de83..b5d2eeec7 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 10 +CRIU_VERSION_MINOR := 11 CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Granite Eagle +CRIU_VERSION_NAME := Glass Flamingo CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From d7d5f9fd2dedd966f206e5af2ed55620bbb5b6e6 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 5 Oct 2018 18:39:45 +0300 Subject: [PATCH 1825/4375] zdtm/sigpending: check only relevant part of siginfo Recently, a kernel behaviour how siginfo is copied into user-space was changed: 4ce5f9c9e754 ("signal: Use a smaller struct siginfo in the kernel") According to the rt_sigqueueinfo man page, the caller should set si_code, si_pid, si_uid, si_value and there is no guarantee about other fields. Signed-off-by: Andrei Vagin --- test/zdtm/static/sigpending.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/zdtm/static/sigpending.c b/test/zdtm/static/sigpending.c index b6d224c75..ac2fdcf84 100644 --- a/test/zdtm/static/sigpending.c +++ b/test/zdtm/static/sigpending.c @@ -46,9 +46,8 @@ typedef union cr_siginfo cr_siginfo_t; #define siginf_body(s) (&((cr_siginfo_t *)(s))->_info._sifields) -#ifdef __i386__ /* - * On x86_32 kernel puts only relevant union member when signal arrives, + * The kernel puts only relevant union member when signal arrives, * leaving _si_fields to be filled with junk from stack. Check only * first 12 bytes: * // POSIX.1b signals. @@ -61,9 +60,6 @@ typedef union cr_siginfo cr_siginfo_t; * Look at __copy_siginfo_to_user32() for more information. */ # define _si_fields_sz 12 -#else -# define _si_fields_sz (sizeof(siginfo_t) - offsetof(cr_siginfo_t, _info._sifields)) -#endif #define siginfo_filled (offsetof(cr_siginfo_t, _info._sifields) + _si_fields_sz) static pthread_mutex_t exit_lock; From be28d924cb01f4cbfc32e01c0e36c5f6863fa087 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 5 Feb 2019 01:46:04 +0300 Subject: [PATCH 1826/4375] lint/python: ignore E117 over-indented After recent update of flake8, we have a lot of e117 warnings: test/zdtm.py:1748:5: E117 over-indented test/zdtm.py:1751:5: E117 over-indented test/zdtm.py:1755:6: E117 over-indented test/zdtm.py:1757:7: E117 over-indented test/zdtm.py:1764:6: E117 over-indented test/zdtm.py:1766:5: E117 over-indented test/zdtm.py:1767:6: E117 over-indented Signed-off-by: Andrei Vagin --- scripts/flake8.cfg | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/flake8.cfg b/scripts/flake8.cfg index 9e98787a8..4231e843d 100644 --- a/scripts/flake8.cfg +++ b/scripts/flake8.cfg @@ -5,5 +5,6 @@ # E251 unexpected spaces around keyword / parameter equals # E101 indentation contains mixed spaces and tabs # E126 continuation line over-indented for hanging indent -# W504 line break after binary operator -ignore = W191,E128,E501,E251,E101,E126,W504 +# W504 line break after binary operator +# E117 over-indented +ignore = W191,E128,E501,E251,E101,E126,W504,E117 From 8f1155379c28f7abd526600e43a8330a5d3b8971 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Sep 2018 22:57:45 +0300 Subject: [PATCH 1827/4375] inet: raw -- Add constants needed to fetch properties of a raw socket Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/sk-inet.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/criu/include/sk-inet.h b/criu/include/sk-inet.h index 180f48e35..79966517b 100644 --- a/criu/include/sk-inet.h +++ b/criu/include/sk-inet.h @@ -16,6 +16,18 @@ #define TCP_REPAIR_OPTIONS 22 #endif +#ifndef IP_HDRINCL +# define IP_HDRINCL 3 +#endif + +#ifndef IP_NODEFRAG +# define IP_NODEFRAG 22 +#endif + +#ifndef IPV6_HDRINCL +# define IPV6_HDRINCL 36 +#endif + struct inet_sk_desc { struct socket_desc sd; unsigned int type; From 47ccf9a28bf201c84b55a74d090f1ffed5a66f30 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Sep 2018 22:57:46 +0300 Subject: [PATCH 1828/4375] inet: raw -- Check for kernel diag module support To collect raw sockets we need the kernel to support raw_diag module. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-check.c | 9 +++++++++ criu/sockets.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/criu/cr-check.c b/criu/cr-check.c index 3cdc45315..4bbe9e098 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1086,6 +1086,13 @@ static int check_kcmp_epoll(void) return 0; } +static int check_net_diag_raw(void) +{ + check_sock_diag(); + return (socket_test_collect_bit(AF_INET, IPPROTO_RAW) && + socket_test_collect_bit(AF_INET6, IPPROTO_RAW)) ? 0 : -1; +} + static int (*chk_feature)(void); /* @@ -1194,6 +1201,7 @@ int cr_check(void) ret |= check_uffd_noncoop(); ret |= check_sk_netns(); ret |= check_kcmp_epoll(); + ret |= check_net_diag_raw(); } /* @@ -1292,6 +1300,7 @@ static struct feature_list feature_list[] = { { "can_map_vdso", check_can_map_vdso}, { "sk_ns", check_sk_netns }, { "sk_unix_file", check_sk_unix_file }, + { "net_diag_raw", check_net_diag_raw }, { "nsid", check_nsid }, { "link_nsid", check_link_nsid}, { "kcmp_epoll", check_kcmp_epoll}, diff --git a/criu/sockets.c b/criu/sockets.c index 9de00df63..14ba5f602 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -141,9 +141,11 @@ enum socket_cl_bits INET_TCP_CL_BIT, INET_UDP_CL_BIT, INET_UDPLITE_CL_BIT, + INET_RAW_CL_BIT, INET6_TCP_CL_BIT, INET6_UDP_CL_BIT, INET6_UDPLITE_CL_BIT, + INET6_RAW_CL_BIT, UNIX_CL_BIT, PACKET_CL_BIT, _MAX_CL_BIT, @@ -169,6 +171,8 @@ enum socket_cl_bits get_collect_bit_nr(unsigned int family, unsigned int proto) return INET_UDP_CL_BIT; if (proto == IPPROTO_UDPLITE) return INET_UDPLITE_CL_BIT; + if (proto == IPPROTO_RAW) + return INET_RAW_CL_BIT; } if (family == AF_INET6) { if (proto == IPPROTO_TCP) @@ -177,6 +181,8 @@ enum socket_cl_bits get_collect_bit_nr(unsigned int family, unsigned int proto) return INET6_UDP_CL_BIT; if (proto == IPPROTO_UDPLITE) return INET6_UDPLITE_CL_BIT; + if (proto == IPPROTO_RAW) + return INET6_RAW_CL_BIT; } pr_err("Unknown pair family %d proto %d\n", family, proto); @@ -686,6 +692,9 @@ static int inet_receive_one(struct nlmsghdr *h, struct ns_id *ns, void *arg) case IPPROTO_UDPLITE: type = SOCK_DGRAM; break; + case IPPROTO_RAW: + type = SOCK_RAW; + break; default: BUG_ON(1); return -1; @@ -761,6 +770,18 @@ int collect_sockets(struct ns_id *ns) if (tmp) err = tmp; + /* Collect IPv4 RAW sockets */ + req.r.i.sdiag_family = AF_INET; + req.r.i.sdiag_protocol = IPPROTO_RAW; + req.r.i.idiag_ext = 0; + req.r.i.idiag_states = -1; /* All */ + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); + if (tmp) { + pr_warn("The current kernel doesn't support ipv4 raw_diag module\n"); + if (tmp != -ENOENT) + err = tmp; + } + /* Collect IPv6 TCP sockets */ req.r.i.sdiag_family = AF_INET6; req.r.i.sdiag_protocol = IPPROTO_TCP; @@ -792,6 +813,18 @@ int collect_sockets(struct ns_id *ns) if (tmp) err = tmp; + /* Collect IPv6 RAW sockets */ + req.r.i.sdiag_family = AF_INET6; + req.r.i.sdiag_protocol = IPPROTO_RAW; + req.r.i.idiag_ext = 0; + req.r.i.idiag_states = -1; /* All */ + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); + if (tmp) { + pr_warn("The current kernel doesn't support ipv6 raw_diag module\n"); + if (tmp != -ENOENT) + err = tmp; + } + req.r.p.sdiag_family = AF_PACKET; req.r.p.sdiag_protocol = 0; req.r.p.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MCLIST | From 347980d441b18e4785f34029a9bc8e74f1f5d429 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Sep 2018 22:57:47 +0300 Subject: [PATCH 1829/4375] inet: raw -- Fetch socket type and check for being raw in can_dump_ipproto Don't allow to proceed dumping since we don't support raw sockets restore yet. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 2e6de6b5b..18f415476 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -109,8 +109,14 @@ static void show_one_inet_img(const char *act, const InetSkEntry *e) src_addr); } -static int can_dump_ipproto(int ino, int proto) +static int can_dump_ipproto(int ino, int proto, int type) { + /* Raw sockets may have any protocol inside */ + if (type == SOCK_RAW) { + pr_err("Unsupported raw socket %x\n", ino); + return 0; + } + /* Make sure it's a proto we support */ switch (proto) { case IPPROTO_IP: @@ -338,14 +344,17 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa InetSkEntry ie = INET_SK_ENTRY__INIT; IpOptsEntry ipopts = IP_OPTS_ENTRY__INIT; SkOptsEntry skopts = SK_OPTS_ENTRY__INIT; - int ret = -1, err = -1, proto, aux; + int ret = -1, err = -1, proto, aux, type; ret = do_dump_opt(lfd, SOL_SOCKET, SO_PROTOCOL, &proto, sizeof(proto)); if (ret) goto err; - if (!can_dump_ipproto(p->stat.st_ino, proto)) + if (do_dump_opt(lfd, SOL_SOCKET, SO_TYPE, &type, sizeof(type))) + goto err; + + if (!can_dump_ipproto(p->stat.st_ino, proto, type)) goto err; sk = (struct inet_sk_desc *)lookup_socket(p->stat.st_ino, family, proto); From 536e57982e393bcaea20a65b672fae7134a6b07d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Sep 2018 22:57:48 +0300 Subject: [PATCH 1830/4375] inet: raw -- Reuse already known family and type in gen_uncon_sk No need to call for do_dump_opt, since these params are already fetched. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 18f415476..e43e13b7c 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -220,7 +220,8 @@ static int dump_sockaddr(union libsoccr_addr *sa, u32 *pb_port, u32 *pb_addr) return -1; } -static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int proto) +static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, + int proto, int family, int type) { struct inet_sk_desc *sk; union libsoccr_addr address; @@ -238,10 +239,8 @@ static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int if (!sk) goto err; - ret = do_dump_opt(lfd, SOL_SOCKET, SO_DOMAIN, &sk->sd.family, sizeof(sk->sd.family)); - ret |= do_dump_opt(lfd, SOL_SOCKET, SO_TYPE, &sk->type, sizeof(sk->type)); - if (ret) - goto err; + sk->sd.family = family; + sk->type = type; if (sk->sd.family == AF_INET) aux = sizeof(struct sockaddr_in); @@ -361,7 +360,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa if (IS_ERR(sk)) goto err; if (!sk) { - sk = gen_uncon_sk(lfd, p, proto); + sk = gen_uncon_sk(lfd, p, proto, family, type); if (!sk) goto err; } From 31c1955d130410a2a435a8c2c8d6497606802dd6 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Sep 2018 22:57:49 +0300 Subject: [PATCH 1831/4375] inet: raw -- Prepare gen_uncon_sk for raw sockets Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index e43e13b7c..e41e2bbd9 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -271,7 +271,7 @@ static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, sk->sd.ino = p->stat.st_ino; - if (proto == IPPROTO_TCP) { + if (type != SOCK_RAW && proto == IPPROTO_TCP) { struct { __u8 tcpi_state; __u8 tcpi_ca_state; From 76b2d8e93b211a70673cf7d429f7fa04efc46813 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 13 Sep 2018 22:57:50 +0300 Subject: [PATCH 1832/4375] inet: raw -- Skip IP_FREEBIND for ipv6 SOCK_RAW sockets IP_FREEBIND is not supported for SOCK_RAW ipv6 sockets. See kernel rawv6_setsockopt() for the details. For the rest of sockets, where they begin to support it: the actual magic happens in do_ipv6_setsockopt(), and IPV6_ADDRFORM optname changes sk->sk_prot to refer to tcp_prot, udp_prot and udplite_prot, which contains link to ip_setsockopt(). Signed-off-by: Kirill Tkhai Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index e41e2bbd9..a7b6399e9 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -840,7 +840,7 @@ int inet_bind(int sk, struct inet_sk_info *ii) * sockets could not be bound to them in this moment * without setting IP_FREEBIND. */ - if (ii->ie->family == AF_INET6) { + if (ii->ie->family == AF_INET6 && ii->ie->type != SOCK_RAW) { int yes = 1; if (restore_opt(sk, SOL_IP, IP_FREEBIND, &yes)) From 201e89856c09b1dac17cafdc0f9cd922dcfeeb74 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Sep 2018 22:57:51 +0300 Subject: [PATCH 1833/4375] inet: raw -- Add raw sockets into can_dump_inet_sk So they would pass this check. Note because we didn't allow raw socks in can_dump_ipproto this routine won't be reached and it's safe to modify it this way without breaking existing tests. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index a7b6399e9..3b4289474 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -155,9 +155,9 @@ static int can_dump_inet_sk(const struct inet_sk_desc *sk) return 1; } - if (sk->type != SOCK_STREAM) { + if (sk->type != SOCK_STREAM && sk->type != SOCK_RAW) { pr_err("Can't dump %d inet socket %x. " - "Only stream and dgram are supported.\n", + "Only stream, dgram and raw are supported.\n", sk->type, sk->sd.ino); return 0; } From 2da21b11e23b9030ffdd4c6991e2bcd8ddce06c8 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Sep 2018 22:57:52 +0300 Subject: [PATCH 1834/4375] inet: raw -- Add preloading raw_diag module Just like we do for other protocols. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sockets.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/sockets.c b/criu/sockets.c index 14ba5f602..5a0f66a3d 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -291,6 +291,9 @@ void preload_socket_modules(void) req.r.i.sdiag_protocol = IPPROTO_UDP; /* UDLITE is merged with UDP */ probe_diag(nl, &req, -ENOENT); + req.r.i.sdiag_protocol = IPPROTO_RAW; + probe_diag(nl, &req, -ENOENT); + close(nl); pr_info("Done probing\n"); } From 072778c4acf847c8f5f15798bcfedb9f8d52db9b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Sep 2018 22:57:53 +0300 Subject: [PATCH 1835/4375] inet: raw -- Split lookup_socket helper Raw sockets may have arbitrary protocol so we need different helper to lookup socket. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/sockets.h | 3 ++- criu/sockets.c | 24 ++++++++++++++++-------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/criu/include/sockets.h b/criu/include/sockets.h index c6204d189..65b230131 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -45,7 +45,8 @@ extern int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ extern struct collect_image_info netlink_sk_cinfo; -extern struct socket_desc *lookup_socket(unsigned ino, int family, int proto); +extern struct socket_desc *lookup_socket_ino(unsigned int ino, int family); +extern struct socket_desc *lookup_socket(unsigned int ino, int family, int proto); extern const struct fdtype_ops unix_dump_ops; extern const struct fdtype_ops inet_dump_ops; diff --git a/criu/sockets.c b/criu/sockets.c index 5a0f66a3d..510b84f66 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -426,26 +426,34 @@ static int restore_socket_filter(int sk, SkOptsEntry *soe) static struct socket_desc *sockets[SK_HASH_SIZE]; -struct socket_desc *lookup_socket(unsigned ino, int family, int proto) +struct socket_desc *lookup_socket_ino(unsigned int ino, int family) { struct socket_desc *sd; - if (!socket_test_collect_bit(family, proto)) { - pr_err("Sockets (family %d, proto %d) are not collected\n", - family, proto); - return ERR_PTR(-EINVAL); - } + pr_debug("Searching for socket %#x family %d\n", ino, family); - pr_debug("\tSearching for socket %x (family %d.%d)\n", ino, family, proto); - for (sd = sockets[ino % SK_HASH_SIZE]; sd; sd = sd->next) + for (sd = sockets[ino % SK_HASH_SIZE]; sd; sd = sd->next) { if (sd->ino == ino) { BUG_ON(sd->family != family); return sd; } + } return NULL; } + +struct socket_desc *lookup_socket(unsigned int ino, int family, int proto) +{ + if (!socket_test_collect_bit(family, proto)) { + pr_err("Sockets (family %d proto %d) are not collected\n", + family, proto); + return ERR_PTR(-EINVAL); + } + + return lookup_socket_ino(ino, family); +} + int sk_collect_one(unsigned ino, int family, struct socket_desc *d, struct ns_id *ns) { struct socket_desc **chain; From c2cbcaf8ac5d71844cee39087f81d6ec795eb635 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Sep 2018 22:57:54 +0300 Subject: [PATCH 1836/4375] inet: raw -- Add checkpoint and restore of raw sockets Just like with other inet sockets simply fetch additional data (such as ICMP) and restore it back then. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 154 +++++++++++++++++++++++++++++++++++-------- images/sk-inet.proto | 13 ++-- 2 files changed, 136 insertions(+), 31 deletions(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 3b4289474..813492220 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include "../soccr/soccr.h" @@ -112,10 +114,8 @@ static void show_one_inet_img(const char *act, const InetSkEntry *e) static int can_dump_ipproto(int ino, int proto, int type) { /* Raw sockets may have any protocol inside */ - if (type == SOCK_RAW) { - pr_err("Unsupported raw socket %x\n", ino); - return 0; - } + if (type == SOCK_RAW) + return 1; /* Make sure it's a proto we support */ switch (proto) { @@ -307,12 +307,76 @@ err: return NULL; } -static int dump_ip_opts(int sk, IpOptsEntry *ioe) +static int ip_raw_opts_alloc(int family, int proto, IpOptsRawEntry *r) +{ + if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) { + if (family == AF_INET6) + r->n_icmpv_filter = NELEMS_AS_ARRAY(struct icmp6_filter, + r->icmpv_filter); + else + r->n_icmpv_filter = NELEMS_AS_ARRAY(struct icmp_filter, + r->icmpv_filter); + r->icmpv_filter = xmalloc(pb_repeated_size(r, icmpv_filter)); + pr_debug("r->n_icmpv_filter %d size %d\n", + (int)r->n_icmpv_filter, + (int)pb_repeated_size(r, icmpv_filter)); + if (!r->icmpv_filter) + return -ENOMEM; + } + return 0; +} + +static void ip_raw_opts_free(IpOptsRawEntry *r) +{ + r->n_icmpv_filter = 0; + xfree(r->icmpv_filter); +} + +static int dump_ip_raw_opts(int sk, int family, int proto, IpOptsRawEntry *r) { int ret = 0; - ret |= dump_opt(sk, SOL_IP, IP_FREEBIND, &ioe->freebind); - ioe->has_freebind = ioe->freebind; + ret = ip_raw_opts_alloc(family, proto, r); + if (ret) + return ret; + + if (family == AF_INET6) { + ret |= dump_opt(sk, SOL_IPV6, IPV6_HDRINCL, &r->hdrincl); + + if (proto == IPPROTO_ICMPV6) + ret |= do_dump_opt(sk, SOL_ICMPV6, ICMPV6_FILTER, + r->icmpv_filter, + pb_repeated_size(r, icmpv_filter)); + } else { + ret |= dump_opt(sk, SOL_IP, IP_HDRINCL, &r->hdrincl); + ret |= dump_opt(sk, SOL_IP, IP_NODEFRAG, &r->nodefrag); + r->has_nodefrag = !!r->nodefrag; + + if (proto == IPPROTO_ICMP) + ret |= do_dump_opt(sk, SOL_RAW, ICMP_FILTER, + r->icmpv_filter, + pb_repeated_size(r, icmpv_filter)); + } + r->has_hdrincl = !!r->hdrincl; + + return ret; +} + +static int dump_ip_opts(int sk, int family, int type, int proto, IpOptsEntry *ioe) +{ + int ret = 0; + + if (type == SOCK_RAW) { + /* + * Raw sockets might need allocate more space + * and fetch additional options. + */ + ret |= dump_ip_raw_opts(sk, family, proto, ioe->raw); + } else { + /* Due to kernel code we can use SOL_IP instead of SOL_IPV6 */ + ret |= dump_opt(sk, SOL_IP, IP_FREEBIND, &ioe->freebind); + ioe->has_freebind = ioe->freebind; + } return ret; } @@ -342,6 +406,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa FileEntry fe = FILE_ENTRY__INIT; InetSkEntry ie = INET_SK_ENTRY__INIT; IpOptsEntry ipopts = IP_OPTS_ENTRY__INIT; + IpOptsRawEntry ipopts_raw = IP_OPTS_RAW_ENTRY__INIT; SkOptsEntry skopts = SK_OPTS_ENTRY__INIT; int ret = -1, err = -1, proto, aux, type; @@ -356,7 +421,10 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa if (!can_dump_ipproto(p->stat.st_ino, proto, type)) goto err; - sk = (struct inet_sk_desc *)lookup_socket(p->stat.st_ino, family, proto); + if (type == SOCK_RAW) + sk = (struct inet_sk_desc *)lookup_socket_ino(p->stat.st_ino, family); + else + sk = (struct inet_sk_desc *)lookup_socket(p->stat.st_ino, family, proto); if (IS_ERR(sk)) goto err; if (!sk) { @@ -366,21 +434,23 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa } sk->cork = false; - switch (proto) { - case IPPROTO_UDP: - case IPPROTO_UDPLITE: - if (dump_opt(lfd, SOL_UDP, UDP_CORK, &aux)) - return -1; - if (aux) { - sk->cork = true; - /* - * FIXME: it is possible to dump a corked socket with - * the empty send queue. - */ - pr_err("Can't dump corked dgram socket %x\n", sk->sd.ino); - goto err; + if (type != SOCK_RAW) { + switch (proto) { + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + if (dump_opt(lfd, SOL_UDP, UDP_CORK, &aux)) + return -1; + if (aux) { + sk->cork = true; + /* + * FIXME: it is possible to dump a corked socket with + * the empty send queue. + */ + pr_err("Can't dump corked dgram socket %x\n", sk->sd.ino); + goto err; + } + break; } - break; } if (!can_dump_inet_sk(sk)) @@ -405,6 +475,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa ie.fown = (FownEntry *)&p->fown; ie.opts = &skopts; ie.ip_opts = &ipopts; + ie.ip_opts->raw = &ipopts_raw; ie.n_src_addr = PB_ALEN_INET; ie.n_dst_addr = PB_ALEN_INET; @@ -451,7 +522,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa memcpy(ie.src_addr, sk->src_addr, pb_repeated_size(&ie, src_addr)); memcpy(ie.dst_addr, sk->dst_addr, pb_repeated_size(&ie, dst_addr)); - if (dump_ip_opts(lfd, &ipopts)) + if (dump_ip_opts(lfd, family, type, proto, &ipopts)) goto err; if (dump_socket_opts(lfd, &skopts)) @@ -465,7 +536,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa switch (proto) { case IPPROTO_TCP: - err = dump_one_tcp(lfd, sk); + err = (type != SOCK_RAW) ? dump_one_tcp(lfd, sk) : 0; break; case IPPROTO_UDP: case IPPROTO_UDPLITE: @@ -482,9 +553,14 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa fe.id = ie.id; fe.isk = &ie; + /* Unchain not need field back */ + if (type != SOCK_RAW) + ie.ip_opts->raw = NULL; + if (pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE)) goto err; err: + ip_raw_opts_free(&ipopts_raw); release_skopts(&skopts); xfree(ie.src_addr); xfree(ie.dst_addr); @@ -654,13 +730,37 @@ static int post_open_inet_sk(struct file_desc *d, int sk) return 0; } -int restore_ip_opts(int sk, IpOptsEntry *ioe) +static int restore_ip_raw_opts(int sk, int family, int proto, IpOptsRawEntry *r) +{ + int ret = 0; + + if (r->icmpv_filter) { + if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) { + ret |= do_restore_opt(sk, family == AF_INET6 ? SOL_ICMPV6 : SOL_RAW, + family == AF_INET6 ? ICMPV6_FILTER : ICMP_FILTER, + r->icmpv_filter, pb_repeated_size(r, icmpv_filter)); + } + } + + if (r->has_nodefrag) + ret |= restore_opt(sk, SOL_IP, IP_NODEFRAG, &r->nodefrag); + if (r->has_hdrincl) + ret |= restore_opt(sk, family == AF_INET6 ? SOL_IPV6 : SOL_IP, + family == AF_INET6 ? IPV6_HDRINCL : IP_HDRINCL, + &r->hdrincl); + + return ret; +} + +int restore_ip_opts(int sk, int family, int proto, IpOptsEntry *ioe) { int ret = 0; if (ioe->has_freebind) ret |= restore_opt(sk, SOL_IP, IP_FREEBIND, &ioe->freebind); + if (ioe->raw) + ret |= restore_ip_raw_opts(sk, family, proto, ioe->raw); return ret; } static int open_inet_sk(struct file_desc *d, int *new_fd) @@ -683,7 +783,7 @@ static int open_inet_sk(struct file_desc *d, int *new_fd) return -1; } - if ((ie->type != SOCK_STREAM) && (ie->type != SOCK_DGRAM)) { + if ((ie->type != SOCK_STREAM) && (ie->type != SOCK_DGRAM) && (ie->type != SOCK_RAW)) { pr_err("Unsupported socket type: %d\n", ie->type); return -1; } @@ -763,7 +863,7 @@ done: if (rst_file_params(sk, ie->fown, ie->flags)) goto err; - if (ie->ip_opts && restore_ip_opts(sk, ie->ip_opts)) + if (ie->ip_opts && restore_ip_opts(sk, ie->family, ie->proto, ie->ip_opts)) goto err; if (restore_socket_opts(sk, ie->opts)) diff --git a/images/sk-inet.proto b/images/sk-inet.proto index cb8245c2c..84306ad5a 100644 --- a/images/sk-inet.proto +++ b/images/sk-inet.proto @@ -4,11 +4,16 @@ import "opts.proto"; import "fown.proto"; import "sk-opts.proto"; +message ip_opts_raw_entry { + optional bool hdrincl = 1; + optional bool nodefrag = 2; + optional bool checksum = 3; + repeated uint32 icmpv_filter = 4; +} + message ip_opts_entry { - optional bool freebind = 1; - // For raw sockets support - // optional bool hdrincl = 2; - // optional bool nodefrag = 3; + optional bool freebind = 1; + optional ip_opts_raw_entry raw = 2; } message inet_sk_entry { From cfee62ac21b37d353239bfa20b73d3dec483189a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 13 Sep 2018 22:57:55 +0300 Subject: [PATCH 1837/4375] inet: raw -- Add socket-raw test Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/socket-raw.c | 382 +++++++++++++++++++++++++++++++ test/zdtm/static/socket-raw.desc | 1 + 3 files changed, 384 insertions(+) create mode 100644 test/zdtm/static/socket-raw.c create mode 100644 test/zdtm/static/socket-raw.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index fe67747db..7b8d66377 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -66,6 +66,7 @@ TST_NOFILE := \ sockets02 \ sockets_spair \ socket_queues \ + socket-raw \ socket-tcp \ socket-tcp-reseted \ socket-tcp6 \ diff --git a/test/zdtm/static/socket-raw.c b/test/zdtm/static/socket-raw.c new file mode 100644 index 000000000..355addb1c --- /dev/null +++ b/test/zdtm/static/socket-raw.c @@ -0,0 +1,382 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "zdtmtst.h" + +/* + * Some code snippets are taken from + * http://www.binarytides.com/raw-udp-sockets-c-linux/ + */ + +const char *test_doc = "Test RAW sockets (IPv4,6)\n"; +const char *test_author = "Cyrill Gorcunov "; + +#ifndef SO_IP_SET +# define SO_IP_SET 83 +#endif + +#ifndef IP_SET_OP_VERSION +# define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */ +#endif + +#define pr_debug(format, arg...) test_msg("DBG: %s:%d: " format, __FILE__, __LINE__, ## arg) + +struct ip_set_req_version { + unsigned int op; + unsigned int version; +}; + +struct pseudo_header { + uint32_t source_address; + uint32_t dest_address; + uint8_t placeholder; + uint8_t protocol; + uint16_t udp_length; +}; + +static int stop_icmp(int sk_icmp, int sk_icmpv6) +{ + struct icmp6_filter filter6 = { }; + struct icmp_filter filter = { }; + socklen_t aux; + int ret = 0; + + aux = sizeof(filter); + ret = getsockopt(sk_icmp, SOL_RAW, ICMP_FILTER, &filter, &aux); + if (ret < 0) { + pr_perror("stop_icmp: Can't fetch icmp filter"); + return ret; + } + + if (filter.data != (1 << ICMP_TIMESTAMP)) { + pr_err("data mismatch on icmp filter %d != %d\n", + filter.data, (1 << ICMP_TIMESTAMP)); + return -1; + } + + aux = sizeof(filter6); + ret = getsockopt(sk_icmpv6, SOL_ICMPV6, ICMPV6_FILTER, &filter6, &aux); + if (ret < 0) { + pr_perror("stop_icmp: Can't fetch icmpv6 filter"); + return ret; + } + + if (filter6.data[0] != (1 << ICMP_TIMESTAMP)) { + pr_err("data mismatch on icmp filter %d != %d\n", + filter6.data[0], (1 << ICMP_TIMESTAMP)); + return -1; + } + + return ret; +} + +static int start_icmp(int sk_icmp, int sk_icmpv6, + const char *a4, const char *a6, int port) +{ + struct sockaddr_in addr_client; + struct icmp6_filter filter6 = { }; + struct icmp_filter filter = { }; + int ret = 0; + + memset(&addr_client, 0, sizeof(addr_client)); + + addr_client.sin_family = AF_INET; + addr_client.sin_port = htons(port); + addr_client.sin_addr.s_addr = inet_addr(a4); + + ret = bind(sk_icmp, (struct sockaddr *)&addr_client, sizeof(addr_client)); + if (ret < 0) { + pr_perror("start_icmp: Can't bind RAW client socket"); + return ret; + } + pr_debug("start_icmp: Bound sk_icmp\n"); + + filter.data = (1 << ICMP_TIMESTAMP); + ret = setsockopt(sk_icmp, SOL_RAW, ICMP_FILTER, &filter, sizeof(filter)); + if (ret < 0) { + pr_perror("start_icmp: Can't setup icmp filter"); + return ret; + } + + filter6.data[0] = (1 << ICMP_TIMESTAMP); + ret = setsockopt(sk_icmpv6, SOL_ICMPV6, ICMPV6_FILTER, &filter6, sizeof(filter6)); + if (ret < 0) { + pr_perror("start_icmp: Can't setup icmpv6 filter"); + return ret; + } + + return ret; +} + +static unsigned short csum(unsigned short *ptr, int nbytes) +{ + unsigned short oddbyte; + register short answer; + register long sum; + + sum = 0; + while (nbytes > 1) { + sum += *ptr++; + nbytes -= 2; + } + + if (nbytes == 1) { + oddbyte = 0; + *((unsigned char *)&oddbyte) = *(unsigned char *)ptr; + sum += oddbyte; + } + + sum = (sum >> 16) + (sum & 0xffff); + sum = sum + (sum >> 16); + answer = (short)~sum; + + return answer; +} + +int main(int argc, char *argv[]) +{ + const char string_data[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const char string_client_ip[] = "127.0.0.12"; + const char string_serv_ip[] = "127.0.0.10"; + const char string_client_icmp_ip[] = "127.0.0.14"; + const char string_client_icmpv6_ip[] = "::14"; + char datagram[512], *data, *pseudogram; + char receiver[512]; + + struct ip_set_req_version req_version; + socklen_t size = sizeof(req_version); + + int sk_udp, sk_udp_serv; + int sk_raw, sk6_raw; + int sk_icmp, sk_icmpv6; + + struct udphdr *udph = (struct udphdr *)(datagram + sizeof(struct ip)); + struct iphdr *iph = (struct iphdr *)datagram; + struct sockaddr_in addr_serv, addr_client; + struct pseudo_header psh; + + int port_client = 8080; + int port_serv = 8081; + + int psize, one = 1; + const int *val = &one; + + socklen_t len = sizeof(struct sockaddr_in); + int ret, status; + + pid_t pid; + + task_waiter_t waiter; + + test_init(argc, argv); + + task_waiter_init(&waiter); + + sk_raw = socket(PF_INET, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW); + if (sk_raw < 0) { + pr_perror("Can't create IPv4 raw socket"); + exit(1); + } + pr_debug("sk_raw %d\n", sk_raw); + + /* Simply to make sure it can be recreated on restore */ + sk6_raw = socket(PF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW); + if (sk6_raw < 0) { + pr_perror("Can't create IPv6 raw socket"); + exit(1); + } + pr_debug("sk6_raw %d\n", sk6_raw); + + sk_udp = socket(PF_INET, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_UDP); + if (sk_udp < 0) { + pr_perror("Can't create IPv4 raw-udp socket"); + exit(1); + } + pr_debug("sk_udp %d\n", sk_udp); + + sk_icmp = socket(PF_INET, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_ICMP); + if (sk_icmp < 0) { + pr_perror("Can't create IPv4 raw icmp socket"); + exit(1); + } + pr_debug("sk_icmp %d\n", sk_icmp); + + sk_icmpv6 = socket(PF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_ICMPV6); + if (sk_icmpv6 < 0) { + pr_perror("Can't create IPv6 raw icmpv6 socket"); + exit(1); + } + pr_debug("sk_icmpv6 %d\n", sk_icmpv6); + + sk_udp_serv = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sk_udp_serv < 0) { + pr_perror("Can't create DGRAM server socket"); + exit(1); + } + pr_debug("sk_udp_serv %d\n", sk_udp_serv); + + memset(datagram, 0, sizeof(datagram)); + memset(receiver, 0, sizeof(receiver)); + memset(&addr_serv, 0, sizeof(addr_serv)); + memset(&addr_client, 0, sizeof(addr_client)); + + addr_client.sin_family = AF_INET; + addr_client.sin_port = htons(port_client); + addr_client.sin_addr.s_addr = inet_addr(string_client_ip); + + addr_serv.sin_family = AF_INET; + addr_serv.sin_port = htons(port_serv); + addr_serv.sin_addr.s_addr = inet_addr(string_serv_ip); + + ret = bind(sk_udp_serv, (struct sockaddr *)&addr_serv, sizeof(addr_serv)); + if (ret < 0) { + pr_perror("Can't bind DGRAM server socket"); + return 1; + } + pr_debug("Bound sk_udp_serv\n"); + + ret = bind(sk_udp, (struct sockaddr *)&addr_client, sizeof(addr_client)); + if (ret < 0) { + pr_perror("Can't bind DGRAM client socket"); + return 1; + } + pr_debug("Bound sk_udp\n"); + + if (start_icmp(sk_icmp, sk_icmpv6, string_client_icmp_ip, + string_client_icmpv6_ip, port_client)) + return 1; + + data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr); + strcpy(data, string_data); + + iph->ihl = 5; + iph->version = 4; + iph->tos = 0; + iph->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + strlen(string_data); + iph->id = htonl(54321); + iph->frag_off = 0; + iph->ttl = 255; + iph->protocol = IPPROTO_UDP; + iph->check = 0; + iph->saddr = inet_addr(string_client_ip); + iph->daddr = addr_serv.sin_addr.s_addr; + iph->check = csum((unsigned short *)datagram, sizeof(struct iphdr)); + + udph->source = htons(port_client); + udph->dest = htons(port_serv); + udph->len = htons(8 + strlen(data)); + udph->check = 0; + + psh.source_address = inet_addr(string_client_ip); + psh.dest_address = addr_serv.sin_addr.s_addr; + psh.placeholder = 0; + psh.protocol = IPPROTO_UDP; + psh.udp_length = htons(sizeof(struct udphdr) + strlen(string_data)); + + psize = sizeof(psh) + sizeof(struct udphdr) + strlen(string_data); + pseudogram = malloc(psize); + if (!pseudogram) { + pr_err("No free memory\n"); + exit(1); + } + + memcpy(pseudogram, (char *)&psh , sizeof(psh)); + memcpy(pseudogram + sizeof(psh), udph, sizeof(*udph) + strlen(string_data)); + + udph->check = csum((unsigned short *)pseudogram, psize); + free(pseudogram); + + if (setsockopt(sk_udp, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0) { + pr_perror("Error setting IP_HDRINCL"); + exit(1); + } + + pid = test_fork(); + if (pid == 0) { + task_waiter_wait4(&waiter, 2); + pr_debug("Gonna read data\n"); + ret = recvfrom(sk_udp_serv, receiver, sizeof(receiver), 0, + (struct sockaddr *)&addr_client, &len); + if (ret < 0) { + task_waiter_complete(&waiter, 2); + fail("Can't read data"); + exit(1); + } + receiver[ret] = '\0'; + pr_debug("Read %d bytes\n", ret); + + task_waiter_complete(&waiter, 3); + + if (strcmp(receiver, string_data)) { + pr_err("Data mismatch (got %s but expected %s)\n", + receiver, string_data); + exit(1); + } else + pr_debug("Data match\n"); + exit(0); + } else if (pid < 0) { + pr_err("Can't fork\n"); + exit(1); + } + + test_daemon(); + test_waitsig(); + + if (sendto(sk_udp, datagram, iph->tot_len, 0, + (struct sockaddr *)&addr_serv, sizeof(addr_serv)) < 0) { + kill(pid, SIGKILL); + fail("Can't send RAW data"); + exit(1); + } + + task_waiter_complete(&waiter, 2); + pr_debug("Sent %d bytes\n", (int)iph->tot_len); + task_waiter_wait4(&waiter, 3); + + ret = wait(&status); + if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status)) { + kill(pid, SIGKILL); + fail("Failed waiting server\n"); + exit(1); + } + + req_version.op = IP_SET_OP_VERSION; + ret = getsockopt(sk_raw, SOL_IP, SO_IP_SET, &req_version, &size); + if (ret) { + pr_perror("xt_set getsockopt"); + if (errno != ENOPROTOOPT) { + fail("Can't fetch SO_IP_SET"); + exit(1); + } + } else + test_msg("SO_IP_SET version = %d\n", req_version.version); + + if (stop_icmp(sk_icmp, sk_icmpv6)) { + fail("Failed on ICMP sockets"); + exit(1); + } + + pass(); + return 0; +} diff --git a/test/zdtm/static/socket-raw.desc b/test/zdtm/static/socket-raw.desc new file mode 100644 index 000000000..359b344c3 --- /dev/null +++ b/test/zdtm/static/socket-raw.desc @@ -0,0 +1 @@ +{'flags': 'suid', 'feature': 'net_diag_raw'} From 4e1c7f5134e2b88e69846f4d72b4fdabc803c5e1 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 28 Sep 2018 16:11:35 +0300 Subject: [PATCH 1838/4375] zdtm: check criu restore with --auto-dedup Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index 5c529ebe4..09ae49a9e 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1159,6 +1159,9 @@ class criu: if self.__dedup: r_opts += ["--auto-dedup"] + if self.__dedup: + r_opts += ["--auto-dedup"] + self.__prev_dump_iter = None criu_dir = os.path.dirname(os.getcwd()) if os.getenv("GCOV"): From 0d6bc8d1fbbee4a7345216452c641e96beb93055 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 25 Sep 2018 19:20:05 +0300 Subject: [PATCH 1839/4375] inet: raw -- Reserve image members for sockets options In vz7 we've a slightly different code base where fields 2 and 3 are already used. So lets reserve them and move raw member to another number. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- images/sk-inet.proto | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/images/sk-inet.proto b/images/sk-inet.proto index 84306ad5a..75d565dcd 100644 --- a/images/sk-inet.proto +++ b/images/sk-inet.proto @@ -13,7 +13,8 @@ message ip_opts_raw_entry { message ip_opts_entry { optional bool freebind = 1; - optional ip_opts_raw_entry raw = 2; + // Fields 2 and 3 are reserved for vz7 use + optional ip_opts_raw_entry raw = 4; } message inet_sk_entry { From b6ff98e0656b14ad9c7dc9281006bae0fb6aa043 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 28 Oct 2018 20:42:51 +0000 Subject: [PATCH 1840/4375] pstree: Avoid multiple calls to getpid() Signed-off-by: Radostin Stoyanov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/pstree.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/criu/pstree.c b/criu/pstree.c index 928fe2d17..695110c45 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -333,10 +333,10 @@ err: return ret; } -static int prepare_pstree_for_shell_job(void) +static int prepare_pstree_for_shell_job(pid_t pid) { - pid_t current_sid = getsid(getpid()); - pid_t current_gid = getpgid(getpid()); + pid_t current_sid = getsid(pid); + pid_t current_gid = getpgid(pid); struct pstree_item *pi; @@ -625,12 +625,12 @@ static int get_free_pid() return -1; } -static int prepare_pstree_ids(void) +static int prepare_pstree_ids(pid_t pid) { struct pstree_item *item, *child, *helper, *tmp; LIST_HEAD(helpers); - pid_t current_pgid = getpgid(getpid()); + pid_t current_pgid = getpgid(pid); /* * Some task can be reparented to init. A helper task should be added @@ -910,7 +910,7 @@ static int prepare_pstree_kobj_ids(void) int prepare_pstree(void) { int ret; - pid_t pid_max = 0, kpid_max = 0; + pid_t pid_max = 0, kpid_max = 0, pid; int fd; char buf[21]; @@ -945,12 +945,14 @@ int prepare_pstree(void) } } + pid = getpid(); + if (!ret) /* * Shell job may inherit sid/pgid from the current * shell, not from image. Set things up for this. */ - ret = prepare_pstree_for_shell_job(); + ret = prepare_pstree_for_shell_job(pid); if (!ret) /* * Walk the collected tree and prepare for restoring @@ -962,7 +964,7 @@ int prepare_pstree(void) * Session/Group leaders might be dead. Need to fix * pstree with properly injected helper tasks. */ - ret = prepare_pstree_ids(); + ret = prepare_pstree_ids(pid); return ret; } From a3c47a9f2225a8541ea69f60ae03eefc061d6536 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 22 Aug 2018 20:54:30 +0100 Subject: [PATCH 1841/4375] Fix typos Most of the typos were found by codespell. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/arch/x86/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index eac701dce..3808b9d33 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -297,7 +297,7 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) if (opts.cpu_cap & CPU_CAP_CPU) { if (memcmp(cpu_info->x86_capability, rt_cpu_info.x86_capability, sizeof(cpu_info->x86_capability))) { - pr_err("CPU capabilites do not match run time\n"); + pr_err("CPU capabilities do not match run time\n"); return -1; } } From 2543598c69bdb24b7437dcdb632236756a300446 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 27 Nov 2018 21:00:14 +0300 Subject: [PATCH 1842/4375] criu: don't leak a service fd Recently, I introduced a new mode when a service fd are not dupped into a fixed file descriptor number. A side effect of this is that we need to close the old descritpor if it was installed. Fixes: d3499999676d ("criu: remove all magic of service-fd when it isn't required") --- criu/util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/util.c b/criu/util.c index b08f5af3a..9c5ae7824 100644 --- a/criu/util.c +++ b/criu/util.c @@ -495,6 +495,8 @@ int install_service_fd(enum sfd_type type, int fd) sfds_protection_bug(type); if (service_fd_base == 0) { + if (test_bit(type, sfd_map)) + close(sfd_arr[type]); sfd_arr[type] = fd; set_bit(type, sfd_map); return fd; From b71727bc81cfaa9a3bb1eb4ad0228e2561bc9a81 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Fri, 16 Nov 2018 21:54:43 +0100 Subject: [PATCH 1843/4375] Print out if a RPC configuration file is used Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-service.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/criu/cr-service.c b/criu/cr-service.c index ed83fdf32..bcd1f5e41 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -371,6 +371,10 @@ static int setup_opts_from_req(int sk, CriuOpts *req) goto err; } + if (req->config_file) { + pr_debug("Overwriting RPC settings with values from %s\n", req->config_file); + } + if (kerndat_init()) return 1; From df107d633176801aab9773b49acbe3b2d9f23347 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 29 Nov 2018 09:24:01 +0000 Subject: [PATCH 1844/4375] Do not lock network if running in the host network namespace Related: https://github.com/checkpoint-restore/criu/issues/577 Restoring a runc container which is running in the host's network namespace locked the network (iptables-restore) without unlocking it. This disables network logging if running in the host's network namespace. Suggested-by: Andrei Vagin Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 7c38fbb97..41ea6652d 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2134,7 +2134,7 @@ static int restore_root_task(struct pstree_item *init) goto out_kill; } - if (opts.empty_ns & CLONE_NEWNET) { + if (root_ns_mask & opts.empty_ns & CLONE_NEWNET) { /* * Local TCP connections were locked by network_lock_internal() * on dump and normally should have been C/R-ed by respectively From daddcbdccb2b8e6367c0be38abea5a7a754a61c3 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 27 Nov 2018 23:20:57 +0000 Subject: [PATCH 1845/4375] ppc64/aarch64: Export __page_{shift, size} in libcompel Libcompel supplies to the parasite PAGE_SIZE during infection. On ppc64/aarch64 PAGE_SIZE can be different with Large pages, under the cover it returns __page_size. At this moment __page_size is located in criu binary, which prevents using libcompel as .so library in other applications than criu on ppc64/aarch64. Export __page_size and __page_shift in libcompel. Fixes: #572 Fixes: 2d965008d367 ("ppc64/aarch64: Dynamically define PAGE_SIZE") Cc: Adrian Reber Acked-by: Cyrill Gorcunov Reported-by: Alexey Shabalin Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/infect.c | 3 +++ compel/arch/ppc64/src/lib/infect.c | 3 +++ criu/arch/aarch64/crtools.c | 3 --- criu/arch/ppc64/crtools.c | 3 --- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compel/arch/aarch64/src/lib/infect.c b/compel/arch/aarch64/src/lib/infect.c index c4a2fde20..4b5939022 100644 --- a/compel/arch/aarch64/src/lib/infect.c +++ b/compel/arch/aarch64/src/lib/infect.c @@ -11,6 +11,9 @@ #include "infect.h" #include "infect-priv.h" +unsigned __page_size = 0; +unsigned __page_shift = 0; + /* * Injected syscall instruction */ diff --git a/compel/arch/ppc64/src/lib/infect.c b/compel/arch/ppc64/src/lib/infect.c index 96e1f3ba6..defed3d85 100644 --- a/compel/arch/ppc64/src/lib/infect.c +++ b/compel/arch/ppc64/src/lib/infect.c @@ -22,6 +22,9 @@ #define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */ #endif +unsigned __page_size = 0; +unsigned __page_shift = 0; + /* * Injected syscall instruction */ diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index b2ef1c312..f98743a23 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -21,9 +21,6 @@ #include "restorer.h" #include -unsigned __page_size = 0; -unsigned __page_shift = 0; - #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))(src)->e int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd) diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index 077c243b2..5a5966ad4 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -23,9 +23,6 @@ #include "images/core.pb-c.h" #include "images/creds.pb-c.h" -unsigned __page_size = 0; -unsigned __page_shift = 0; - static UserPpc64FpstateEntry *copy_fp_regs(uint64_t *fpregs) { UserPpc64FpstateEntry *fpe; From 7886b2572d57bacbbba40f047938f5bc287db2af Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 27 Nov 2018 23:20:58 +0000 Subject: [PATCH 1846/4375] Revert "compel: Move lib files into lib-y" This reverts commit 6b0292e12614. handle_binary() is needed for preparing PIE header during compilation. If we need to provide API for building another compel binary, probably it should be a separate library from libcompel.{a,so} IOW, there is no sense to have handle_binary() included into CRIU. For CRIU it's needed only during the build to generate parasite header. Move handle_elf() to compel binary from library, as it was previously corrected in commit 64bb75a859cd ("compel: Drop off handle-elf routines from library"). Acked-by: Cyrill Gorcunov Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/Makefile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index f751d6a74..7ef01aa01 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -24,10 +24,6 @@ host-lib-y += src/lib/log.o lib-y += arch/$(ARCH)/src/lib/cpu.o lib-y += arch/$(ARCH)/src/lib/infect.o -lib-y += arch/$(ARCH)/src/lib/handle-elf.o -host-lib-y += arch/$(ARCH)/src/lib/handle-elf.o -lib-y += src/lib/handle-elf.o -host-lib-y += src/lib/handle-elf.o lib-y += src/lib/infect-rpc.o lib-y += src/lib/infect-util.o lib-y += src/lib/infect.o @@ -40,6 +36,8 @@ HOSTCFLAGS += -DNO_RELOCS endif obj-y += src/main.o +obj-y += arch/$(ARCH)/src/lib/handle-elf.o +obj-y += src/lib/handle-elf.o host-ccflags-y += $(ccflags-y) From d4f3c7cd5518f00df42cdae34e395494befdb685 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 27 Nov 2018 23:20:59 +0000 Subject: [PATCH 1847/4375] compel: Provide piegen_opt_t in library Fixes: verify-elf: ERROR: ./usr/lib64/libcompel.so.1.0: undefined symbol: opts Acked-by: Cyrill Gorcunov Reported-by: Alexey Shabalin <> Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/src/lib/handle-elf.c | 2 ++ compel/src/main.c | 1 - test/compel/main.c | 7 ------- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index f1cf74ff4..ca7c53b71 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -18,6 +18,8 @@ #include "piegen.h" #include "log.h" +piegen_opt_t opts = {}; + /* Check if pointer is out-of-bound */ static bool __ptr_oob(const uintptr_t ptr, const uintptr_t start, const size_t size) { diff --git a/compel/src/main.c b/compel/src/main.c index 86d22abd3..51bac099f 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -60,7 +60,6 @@ static const flags_t flags = { #endif }; -piegen_opt_t opts = {}; const char *uninst_root; static int piegen(void) diff --git a/test/compel/main.c b/test/compel/main.c index 846095ea1..a6a014948 100644 --- a/test/compel/main.c +++ b/test/compel/main.c @@ -23,13 +23,6 @@ const size_t test_elf_buf_size = 4096; extern int handle_binary(void *mem, size_t size); extern void run_tests(void *mem); -/* To shut down error printing on tests for failures */ -piegen_opt_t opts = { - .fout = NULL, - .ferr = NULL, - .fdebug = NULL, -}; - int launch_test(void *mem, int expected_ret, const char *test_fmt, ...) { static unsigned test_nr = 1; From 5be76840706f6830d6d3f2712ff351167a4b9e90 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 22 Nov 2018 13:44:03 +0000 Subject: [PATCH 1848/4375] Fix kerndat_link_nsid() on systems with more than 10 interfaces On a system with more than 10 network interfaces the link_nsid check fails: $ criu check --feature link_nsid Warn (criu/cr-check.c:1237): NSID isn't supported The function kerndat_link_nsid() uses: nde.ifindex = 10; This fails as there is already an interface with ifindex 10. This patch moves the creation of the socket into the second network namespace and the feature check succeeds. Suggested-by: Jiri Benc Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/net.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/criu/net.c b/criu/net.c index 3eebf48bc..dff6083ad 100644 --- a/criu/net.c +++ b/criu/net.c @@ -3121,12 +3121,6 @@ int kerndat_link_nsid() }; int nsfd, sk, ret; - sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (sk < 0) { - pr_perror("Unable to create a netlink socket"); - exit(1); - } - if (unshare(CLONE_NEWNET)) { pr_perror("Unable create a network namespace"); exit(1); @@ -3141,6 +3135,12 @@ int kerndat_link_nsid() exit(1); } + sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (sk < 0) { + pr_perror("Unable to create a netlink socket"); + exit(1); + } + nde.type = ND_TYPE__VETH; nde.name = "veth"; nde.ifindex = 10; From f046de70e51d570a093acc8608cc1218500e401b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 27 Nov 2018 20:45:41 +0300 Subject: [PATCH 1849/4375] socket-tcp: ignore SIGPIPE The test is trying to write into a closed socket and the kernel sends SIGPIPE in this case, which is perfectly normal and should not fail the test. Signed-off-by: Andrei Vagin --- test/zdtm/static/socket-tcp-closed.c | 2 ++ test/zdtm/static/socket-tcp-reseted.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/test/zdtm/static/socket-tcp-closed.c b/test/zdtm/static/socket-tcp-closed.c index 0447e95b2..a51f9b96d 100644 --- a/test/zdtm/static/socket-tcp-closed.c +++ b/test/zdtm/static/socket-tcp-closed.c @@ -23,6 +23,7 @@ const char *test_author = "Andrey Vagin #include #include +#include static int port = 8880; @@ -43,6 +44,7 @@ int main(int argc, char **argv) #endif test_init(argc, argv); + signal(SIGPIPE, SIG_IGN); sk = socket(ZDTM_FAMILY, SOCK_STREAM, 0); if (sk < 0) { diff --git a/test/zdtm/static/socket-tcp-reseted.c b/test/zdtm/static/socket-tcp-reseted.c index ce52e1148..07ad36009 100644 --- a/test/zdtm/static/socket-tcp-reseted.c +++ b/test/zdtm/static/socket-tcp-reseted.c @@ -5,6 +5,7 @@ #include /* for sockaddr_in and inet_ntoa() */ #include #include +#include #ifdef ZDTM_IPV4V6 #define ZDTM_FAMILY AF_INET @@ -38,6 +39,7 @@ int main(int argc, char **argv) char cmd[4096], buf[10]; test_init(argc, argv); + signal(SIGPIPE, SIG_IGN); if ((fd_s = tcp_init_server(ZDTM_SRV_FAMILY, &port)) < 0) { pr_err("initializing server failed\n"); From ae2ab548eba820ccbc9e831f99a99f6e82ae9479 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 27 Nov 2018 20:45:42 +0300 Subject: [PATCH 1850/4375] test/abrt: skip core dumps from the seccomp_filter test It is expected behaviour. Signed-off-by: Andrei Vagin --- test/abrt.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/abrt.sh b/test/abrt.sh index 34f25b474..94aca2116 100755 --- a/test/abrt.sh +++ b/test/abrt.sh @@ -12,6 +12,11 @@ expr match "$comm" zombie00 && { exit 0 } +expr match "$comm" seccomp_filter && { + cat > /dev/null + exit 0 +} + report="/tmp/zdtm-core-$pid-$comm" exec &> ${report}.txt From 81c113e3257d13762c1fed1fe0b57e33b6d506b0 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 27 Nov 2018 20:45:43 +0300 Subject: [PATCH 1851/4375] test/alpine: add a new path to libxt libraries Signed-off-by: Andrei Vagin --- test/zdtm/static/socket-tcp-closed-last-ack.desc | 4 ++-- test/zdtm/static/socket-tcp-reseted.desc | 6 +++--- test/zdtm/static/socket-tcp-syn-sent.desc | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/zdtm/static/socket-tcp-closed-last-ack.desc b/test/zdtm/static/socket-tcp-closed-last-ack.desc index 590bc5848..8a9df7fc4 100644 --- a/test/zdtm/static/socket-tcp-closed-last-ack.desc +++ b/test/zdtm/static/socket-tcp-closed-last-ack.desc @@ -1,7 +1,7 @@ { 'deps': [ '/bin/sh', '/sbin/iptables', - '/usr/lib64/xtables/libxt_tcp.so|/lib/xtables/libxt_tcp.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_tcp.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so|/usr/lib/s390x-linux-gnu/xtables/libxt_tcp.so', - '/usr/lib64/xtables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so|/usr/lib/s390x-linux-gnu/xtables/libxt_standard.so', + '/usr/lib64/xtables/libxt_tcp.so|/lib/xtables/libxt_tcp.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_tcp.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so|/usr/lib/s390x-linux-gnu/xtables/libxt_tcp.so|/usr/lib/xtables/libxt_tcp.so', + '/usr/lib64/xtables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so|/usr/lib/s390x-linux-gnu/xtables/libxt_standard.so|/usr/lib/xtables/libxt_standard.so', ], 'opts': '--tcp-established', 'flags': 'suid nouser samens', diff --git a/test/zdtm/static/socket-tcp-reseted.desc b/test/zdtm/static/socket-tcp-reseted.desc index c026d9d61..c0e83aad7 100644 --- a/test/zdtm/static/socket-tcp-reseted.desc +++ b/test/zdtm/static/socket-tcp-reseted.desc @@ -1,8 +1,8 @@ { 'deps': [ '/bin/sh', '/sbin/iptables', - '/usr/lib64/xtables/libxt_tcp.so|/lib/xtables/libxt_tcp.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_tcp.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so', - '/usr/lib64/xtables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so', - '/usr/lib64/xtables/libipt_REJECT.so|/lib/xtables/libipt_REJECT.so|/usr/lib/powerpc64le-linux-gnu/xtables/libipt_REJECT.so|/usr/lib/x86_64-linux-gnu/xtables/libipt_REJECT.so', + '/usr/lib64/xtables/libxt_tcp.so|/lib/xtables/libxt_tcp.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_tcp.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so|/usr/lib/xtables/libxt_tcp.so', + '/usr/lib64/xtables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so|/usr/lib/xtables/libxt_standard.so', + '/usr/lib64/xtables/libipt_REJECT.so|/lib/xtables/libipt_REJECT.so|/usr/lib/powerpc64le-linux-gnu/xtables/libipt_REJECT.so|/usr/lib/x86_64-linux-gnu/xtables/libipt_REJECT.so|/usr/lib/xtables/libipt_REJECT.so', ], 'opts': '--tcp-established', 'flags': 'suid nouser samens', diff --git a/test/zdtm/static/socket-tcp-syn-sent.desc b/test/zdtm/static/socket-tcp-syn-sent.desc index 16ae49619..c5d1faa0e 100644 --- a/test/zdtm/static/socket-tcp-syn-sent.desc +++ b/test/zdtm/static/socket-tcp-syn-sent.desc @@ -1,7 +1,7 @@ { 'deps': [ '/bin/sh', '/sbin/iptables', - '/usr/lib64/xtables/libxt_tcp.so|/lib/xtables/libxt_tcp.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_tcp.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so', - '/usr/lib64/xtables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so', + '/usr/lib64/xtables/libxt_tcp.so|/lib/xtables/libxt_tcp.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_tcp.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so|/usr/lib/xtables/libxt_tcp.so', + '/usr/lib64/xtables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so|/usr/lib/xtables/libxt_standard.so', ], 'opts': '--tcp-established', 'flags': 'suid nouser samens', From bc522bcc9489b5a299a78c598e16d217a8d8ed2d Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 27 Nov 2018 20:45:44 +0300 Subject: [PATCH 1852/4375] test/socket-tcp: run iptables with -w Start test Test is SUID ./socket-tcp-nfconntrack --pidfile=socket-tcp-nfconntrack.pid --outfile=socket-tcp-nfconntrack.out Another app is currently holding the xtables lock. Perhaps you want to use the -w option? Signed-off-by: Andrei Vagin --- test/zdtm/static/socket-tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/socket-tcp.c b/test/zdtm/static/socket-tcp.c index 18eb3792c..5158fe348 100644 --- a/test/zdtm/static/socket-tcp.c +++ b/test/zdtm/static/socket-tcp.c @@ -76,7 +76,7 @@ int main(int argc, char **argv) return 1; if (system("iptables -w -A INPUT -i lo -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT")) return 1; - if (system("iptables -A INPUT -j DROP")) + if (system("iptables -w -A INPUT -j DROP")) return 1; #endif From 02018f01f19c848e1f69fc56132b74fccf45117e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 27 Nov 2018 20:45:45 +0300 Subject: [PATCH 1853/4375] travis: switch to the Ubuntu Xenial Signed-off-by: Andrei Vagin --- .travis.yml | 2 +- scripts/build/Dockerfile.fedora-asan.hdr | 2 +- scripts/travis/Makefile | 16 ++++++++++++---- test/zdtm.py | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7e47b5a9e..b69b87a3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: c sudo: required -dist: trusty +dist: xenial cache: ccache services: - docker diff --git a/scripts/build/Dockerfile.fedora-asan.hdr b/scripts/build/Dockerfile.fedora-asan.hdr index 8c77c2551..3ec09c1c0 100644 --- a/scripts/build/Dockerfile.fedora-asan.hdr +++ b/scripts/build/Dockerfile.fedora-asan.hdr @@ -1,2 +1,2 @@ -FROM fedora:27 +FROM fedora:29 ENV ASAN=1 diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index 1b2858280..07c46fa48 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -16,15 +16,23 @@ ZDTM_OPTIONS := alpine: ZDTM_OPTIONS=-x zdtm/static/binfmt_misc -x zdtm/static/netns-nf -x zdtm/static/sched_policy00 -x zdtm/static/seccomp_strict -x zdtm/static/sigaltstack -x zdtm/static/signalfd00 -x zdtm/static/config_inotify_irmap +define DOCKER_JSON +{ + "storage-driver": "devicemapper" +} +endef + +export DOCKER_JSON $(TARGETS): - echo 'DOCKER_OPTS="--storage-driver=devicemapper"' > /etc/default/docker - restart docker + echo "$$DOCKER_JSON" > /etc/docker/daemon.json + systemctl restart docker $(MAKE) -C ../build $@$(target-suffix) docker run --env-file docker.env --rm -it --privileged -v /lib/modules:/lib/modules --tmpfs /run criu-$@ scripts/travis/travis-tests fedora-asan: - echo 'DOCKER_OPTS="--storage-driver=devicemapper"' > /etc/default/docker - restart docker + ip6tables -L -n + echo "$$DOCKER_JSON" > /etc/docker/daemon.json + systemctl restart docker $(MAKE) -C ../build $@$(target-suffix) docker run --rm -it --privileged -v /lib/modules:/lib/modules --tmpfs /run criu-$@ ./scripts/travis/asan.sh $(ZDTM_OPTIONS) diff --git a/test/zdtm.py b/test/zdtm.py index 09ae49a9e..018ad0ec6 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1740,7 +1740,7 @@ class Launcher: if sub['log']: with open(sub['log']) as sublog: - print(sublog.read().encode('ascii', 'ignore')) + print("%s" % sublog.read().encode('ascii', 'ignore').decode('utf-8')) os.unlink(sub['log']) return True From b6a2f5a0e6924493bbb0d1b5e1c2aec0dbaaffd8 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 9 Nov 2018 21:51:21 +0000 Subject: [PATCH 1854/4375] Remove unused #include Acked-by: Cyrill Gorcunov Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 1 - criu/cr-restore.c | 1 - criu/sk-queue.c | 1 - 3 files changed, 3 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 713653fcb..184954f83 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -17,7 +17,6 @@ #include #include -#include #include #include diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 41ea6652d..e843dfc56 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -21,7 +21,6 @@ #include #include -#include #include "types.h" #include diff --git a/criu/sk-queue.c b/criu/sk-queue.c index d19de7504..613e38461 100644 --- a/criu/sk-queue.c +++ b/criu/sk-queue.c @@ -8,7 +8,6 @@ #include #include #include -#include #include "common/list.h" #include "imgset.h" From 48a7dd3c178742e458b5092f44ee37fbf327c3f8 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 9 Nov 2018 21:51:22 +0000 Subject: [PATCH 1855/4375] Remove unused #include Acked-by: Cyrill Gorcunov Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 1 - criu/files-reg.c | 1 - criu/fsnotify.c | 1 - criu/util.c | 1 - 4 files changed, 4 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index e843dfc56..6f122b40b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/criu/files-reg.c b/criu/files-reg.c index ec91f22c3..0c3c27dd6 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 001f006bb..916e121ca 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/criu/util.c b/criu/util.c index 9c5ae7824..2bf24a83d 100644 --- a/criu/util.c +++ b/criu/util.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include From 1bdfa1caacf5fe04e72cda83351f527291eb1db5 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 9 Nov 2018 21:51:23 +0000 Subject: [PATCH 1856/4375] Replace references to MAP_ANON with MAP_ANONYMOUS MAP_ANON has been deprecated, use MAP_ANONYMOUS instead. https://lkml.org/lkml/2007/2/3/55 Acked-by: Cyrill Gorcunov Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- compel/plugins/shmem/shmem.c | 2 +- criu/arch/x86/kerndat.c | 4 ++-- criu/bfd.c | 2 +- criu/cr-check.c | 2 +- criu/cr-restore.c | 6 +++--- criu/pipes.c | 2 +- criu/vdso.c | 4 ++-- test/zdtm/static/mem-touch.c | 2 +- test/zdtm/static/mprotect00.c | 2 +- test/zdtm/transition/file_read.c | 2 +- test/zdtm/transition/ptrace.c | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compel/plugins/shmem/shmem.c b/compel/plugins/shmem/shmem.c index c2d56c270..695d1931f 100644 --- a/compel/plugins/shmem/shmem.c +++ b/compel/plugins/shmem/shmem.c @@ -13,7 +13,7 @@ void *shmem_create(unsigned long size) struct shmem_plugin_msg spi; mem = (void *)sys_mmap(NULL, size, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANON, 0, 0); + MAP_SHARED | MAP_ANONYMOUS, 0, 0); if (mem == MAP_FAILED) return NULL; diff --git a/criu/arch/x86/kerndat.c b/criu/arch/x86/kerndat.c index 006196829..f7593251b 100644 --- a/criu/arch/x86/kerndat.c +++ b/criu/arch/x86/kerndat.c @@ -103,7 +103,7 @@ static void mmap_bug_test(void) void *map1, *map2; int err; - map1 = mmap_ia32(0, PAGE_SIZE, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); + map1 = mmap_ia32(0, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); /* 32-bit error, not sign-extended - can't use IS_ERR_VALUE() here */ err = (uintptr_t)map1 % PAGE_SIZE; if (err) { @@ -116,7 +116,7 @@ static void mmap_bug_test(void) exit(1); } - map2 = mmap_ia32(0, PAGE_SIZE, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); + map2 = mmap_ia32(0, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); err = (uintptr_t)map2 % PAGE_SIZE; if (err) { pr_err("ia32 mmap() failed: %d\n", err); diff --git a/criu/bfd.c b/criu/bfd.c index 1a1850780..05824551b 100644 --- a/criu/bfd.c +++ b/criu/bfd.c @@ -43,7 +43,7 @@ static int buf_get(struct xbuf *xb) int i; mem = mmap(NULL, BUFBATCH * BUFSIZE, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, 0, 0); + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); if (mem == MAP_FAILED) { pr_perror("No buf"); return -1; diff --git a/criu/cr-check.c b/criu/cr-check.c index 4bbe9e098..49ad6582b 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -746,7 +746,7 @@ static int check_aio_remap(void) if (!len) return -1; - naddr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, 0); + naddr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); if (naddr == MAP_FAILED) { pr_perror("Can't find place for new AIO ring"); return -1; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 6f122b40b..abfeaf662 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -843,7 +843,7 @@ static int restore_one_alive_task(int pid, CoreEntry *core) args_len = round_up(sizeof(*ta) + sizeof(struct thread_restore_args) * current->nr_threads, page_size()); - ta = mmap(NULL, args_len, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, 0); + ta = mmap(NULL, args_len, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); if (!ta) return -1; @@ -2761,7 +2761,7 @@ static int prepare_restorer_blob(void) restorer_len = pie_size(restorer); restorer = mmap(NULL, restorer_len, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANON, 0, 0); + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); if (restorer == MAP_FAILED) { pr_perror("Can't map restorer code"); return -1; @@ -3327,7 +3327,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns /* VMA we need for stacks and sigframes for threads */ if (mmap(mem, memzone_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0) != mem) { + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0) != mem) { pr_err("Can't mmap section for restore code\n"); goto err; } diff --git a/criu/pipes.c b/criu/pipes.c index 8e781c998..fd1a7e6bb 100644 --- a/criu/pipes.c +++ b/criu/pipes.c @@ -47,7 +47,7 @@ static int pipe_data_read(struct cr_img *img, struct pipe_data_rst *r) */ r->data = mmap(NULL, bytes, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANON, 0, 0); + MAP_SHARED | MAP_ANONYMOUS, 0, 0); if (r->data == MAP_FAILED) { pr_perror("Can't map mem for pipe buffers"); return -1; diff --git a/criu/vdso.c b/criu/vdso.c index ea142ea84..257cbcd92 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -505,7 +505,7 @@ static int vdso_fill_compat_symtable(struct vdso_maps *native, return 0; vdso_mmap = mmap(NULL, COMPAT_VDSO_BUF_SZ, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANON, -1, 0); + MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (vdso_mmap == MAP_FAILED) { pr_perror("Failed to mmap buf for compat vdso"); return -1; @@ -656,7 +656,7 @@ int kerndat_vdso_preserves_hint(void) void *new_addr; new_addr = mmap(0, vdso_size, PROT_NONE, - MAP_ANON | MAP_PRIVATE, -1, 0); + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (new_addr == MAP_FAILED) exit(1); diff --git a/test/zdtm/static/mem-touch.c b/test/zdtm/static/mem-touch.c index c14b48050..5c8c33998 100644 --- a/test/zdtm/static/mem-touch.c +++ b/test/zdtm/static/mem-touch.c @@ -23,7 +23,7 @@ int main(int argc, char **argv) test_init(argc, argv); - mem = mmap(NULL, MEM_PAGES * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0); + mem = mmap(NULL, MEM_PAGES * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); if (mem == MAP_FAILED) return 1; diff --git a/test/zdtm/static/mprotect00.c b/test/zdtm/static/mprotect00.c index be70135d6..463091a64 100644 --- a/test/zdtm/static/mprotect00.c +++ b/test/zdtm/static/mprotect00.c @@ -87,7 +87,7 @@ int main(int argc, char ** argv) exit(1); } - ptr = mmap(NULL, pagesize * (NUM_MPROTS + 1), PROT_NONE, MAP_PRIVATE | MAP_ANON, 0, 0); + ptr = mmap(NULL, pagesize * (NUM_MPROTS + 1), PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); if (ptr == MAP_FAILED) { pr_perror("calloc failed"); return -1; diff --git a/test/zdtm/transition/file_read.c b/test/zdtm/transition/file_read.c index 63926c069..50dffd8c4 100644 --- a/test/zdtm/transition/file_read.c +++ b/test/zdtm/transition/file_read.c @@ -121,7 +121,7 @@ static void chew_some_file(int num) char chew_file[PATH_MAX]; buf = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, 0, 0); + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); rv = MMAP_FAILED; if (buf == MAP_FAILED) goto out_exit; diff --git a/test/zdtm/transition/ptrace.c b/test/zdtm/transition/ptrace.c index dc6eca243..29e2e01d9 100644 --- a/test/zdtm/transition/ptrace.c +++ b/test/zdtm/transition/ptrace.c @@ -40,7 +40,7 @@ int main(int argc, char **argv) pids = (int *)mmap(NULL, sizeof(int) * nr_threads, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANON, 0, 0); + MAP_SHARED | MAP_ANONYMOUS, 0, 0); if (pids == MAP_FAILED) { pr_perror("Can't map"); exit(1); From 47503957200047df4e0fa838cd4d9d74d8cd26bc Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 9 Nov 2018 21:51:24 +0000 Subject: [PATCH 1857/4375] Remove duplicated include statements for filename in *.c; do if sort "$filename" | uniq -d | grep include; then echo "$filename" fi done Acked-by: Cyrill Gorcunov Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/cr-check.c | 1 - criu/cr-dump.c | 2 -- criu/cr-restore.c | 2 -- criu/cr-service.c | 2 -- criu/eventfd.c | 1 - criu/eventpoll.c | 1 - criu/fsnotify.c | 1 - criu/mount.c | 1 - criu/util.c | 6 ------ 9 files changed, 17 deletions(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index 49ad6582b..7addb9fb0 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 184954f83..e2ff90bb5 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -14,7 +13,6 @@ #include #include #include -#include #include diff --git a/criu/cr-restore.c b/criu/cr-restore.c index abfeaf662..07dc5bdaa 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -37,7 +37,6 @@ #include "sk-packet.h" #include "common/lock.h" #include "files.h" -#include "files-reg.h" #include "pipes.h" #include "fifo.h" #include "sk-inet.h" @@ -66,7 +65,6 @@ #include "plugin.h" #include "cgroup.h" #include "timerfd.h" -#include "file-lock.h" #include "action-scripts.h" #include "shmem.h" #include diff --git a/criu/cr-service.c b/criu/cr-service.c index bcd1f5e41..4a9983ac7 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -37,8 +37,6 @@ #include "irmap.h" #include "kerndat.h" #include "proc_parse.h" -#include -#include #include "common/scm.h" #include "uffd.h" diff --git a/criu/eventfd.c b/criu/eventfd.c index a3facada0..da31ce9f5 100644 --- a/criu/eventfd.c +++ b/criu/eventfd.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff --git a/criu/eventpoll.c b/criu/eventpoll.c index 72e19e093..e1384fa4b 100644 --- a/criu/eventpoll.c +++ b/criu/eventpoll.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 916e121ca..41b33765e 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff --git a/criu/mount.c b/criu/mount.c index 218facb76..5a97c1f1b 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/criu/util.c b/criu/util.c index 2bf24a83d..9221863ca 100644 --- a/criu/util.c +++ b/criu/util.c @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include #include #include @@ -19,14 +17,10 @@ #include #include #include -#include #include #include #include #include -#include -#include -#include #include #include #include From 2e9490f1c23d195def69f7afacd3488905ac68e2 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 9 Nov 2018 21:51:25 +0000 Subject: [PATCH 1858/4375] Remove unused #include Acked-by: Cyrill Gorcunov Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 1 - criu/fsnotify.c | 1 - criu/uffd.c | 1 - test/others/rpc/test-c.c | 1 - test/zdtm/static/inotify00.c | 1 - test/zdtm/static/inotify02.c | 1 - test/zdtm/static/mntns_ro_root.c | 1 - test/zdtm/static/netns-dev.c | 1 - 8 files changed, 8 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 07dc5bdaa..55e78cdc1 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/criu/fsnotify.c b/criu/fsnotify.c index 41b33765e..ed8a67a21 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/criu/uffd.c b/criu/uffd.c index 384889105..d0a4ed5a1 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include diff --git a/test/others/rpc/test-c.c b/test/others/rpc/test-c.c index f210a973a..751f9ba9d 100644 --- a/test/others/rpc/test-c.c +++ b/test/others/rpc/test-c.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #define MAX_MSG_SIZE 1024 diff --git a/test/zdtm/static/inotify00.c b/test/zdtm/static/inotify00.c index 3c7cab0a7..67088edd8 100644 --- a/test/zdtm/static/inotify00.c +++ b/test/zdtm/static/inotify00.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/test/zdtm/static/inotify02.c b/test/zdtm/static/inotify02.c index 9b343a873..b1b75d2e1 100644 --- a/test/zdtm/static/inotify02.c +++ b/test/zdtm/static/inotify02.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/test/zdtm/static/mntns_ro_root.c b/test/zdtm/static/mntns_ro_root.c index 8415eec30..8a7971018 100644 --- a/test/zdtm/static/mntns_ro_root.c +++ b/test/zdtm/static/mntns_ro_root.c @@ -11,7 +11,6 @@ #include #include #include -#include #include "zdtmtst.h" diff --git a/test/zdtm/static/netns-dev.c b/test/zdtm/static/netns-dev.c index 8763773cc..46bb90639 100644 --- a/test/zdtm/static/netns-dev.c +++ b/test/zdtm/static/netns-dev.c @@ -1,6 +1,5 @@ #include #include -#include #include #include "zdtmtst.h" From fab1708f7faac0605f614fafb0658e42cc444760 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 9 Nov 2018 21:51:26 +0000 Subject: [PATCH 1859/4375] cr-restore: Remove unused #include Acked-by: Cyrill Gorcunov Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 55e78cdc1..95892161a 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -7,7 +7,6 @@ #include #include -#include #include #include From c03c8d2129df04a0574fc5567c0f079a1b912891 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 15 Nov 2018 18:14:27 +0300 Subject: [PATCH 1860/4375] inet: raw -- Don't carry zero options into the image Otherwise there might be a raw socket with AF_INET family and IPPROTO_ICMPV6 protocol which surely don't have to restore it. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 813492220..cc7e1cc28 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -330,6 +330,7 @@ static void ip_raw_opts_free(IpOptsRawEntry *r) { r->n_icmpv_filter = 0; xfree(r->icmpv_filter); + r->icmpv_filter = NULL; } static int dump_ip_raw_opts(int sk, int family, int proto, IpOptsRawEntry *r) @@ -340,6 +341,11 @@ static int dump_ip_raw_opts(int sk, int family, int proto, IpOptsRawEntry *r) if (ret) return ret; + /* + * Either fill icmpv_filter if match or free + * so it won't fetch zeros to image. + */ + if (family == AF_INET6) { ret |= dump_opt(sk, SOL_IPV6, IPV6_HDRINCL, &r->hdrincl); @@ -347,6 +353,8 @@ static int dump_ip_raw_opts(int sk, int family, int proto, IpOptsRawEntry *r) ret |= do_dump_opt(sk, SOL_ICMPV6, ICMPV6_FILTER, r->icmpv_filter, pb_repeated_size(r, icmpv_filter)); + else + ip_raw_opts_free(r); } else { ret |= dump_opt(sk, SOL_IP, IP_HDRINCL, &r->hdrincl); ret |= dump_opt(sk, SOL_IP, IP_NODEFRAG, &r->nodefrag); @@ -356,6 +364,8 @@ static int dump_ip_raw_opts(int sk, int family, int proto, IpOptsRawEntry *r) ret |= do_dump_opt(sk, SOL_RAW, ICMP_FILTER, r->icmpv_filter, pb_repeated_size(r, icmpv_filter)); + else + ip_raw_opts_free(r); } r->has_hdrincl = !!r->hdrincl; From c2a74d661dafcc9bbd0c1e7ab13489f9b55ef881 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 15 Nov 2018 18:14:28 +0300 Subject: [PATCH 1861/4375] test: inet, raw -- Storm the test with all protos Raw sockets may carry any protocol they want so lets try them out. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/socket-raw.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/zdtm/static/socket-raw.c b/test/zdtm/static/socket-raw.c index 355addb1c..9a359485d 100644 --- a/test/zdtm/static/socket-raw.c +++ b/test/zdtm/static/socket-raw.c @@ -154,6 +154,30 @@ static unsigned short csum(unsigned short *ptr, int nbytes) return answer; } +/* + * Just create IPv6/IPv6 sockets with any protos + * to make sure criu won't BUG on unknown proto. + */ +static void raw_socks_storm(void) +{ + int sk4[IPPROTO_MAX]; + int sk6[IPPROTO_MAX]; + size_t i; + + + for (i = 1; i < ARRAY_SIZE(sk4); i++) { + sk4[i] = socket(PF_INET, SOCK_RAW | SOCK_NONBLOCK, i); + if (sk4[i] >= 0) + test_msg("Created IPv4 proto %zd: %d\n", i, sk4[i]); + } + + for (i = 1; i < ARRAY_SIZE(sk6); i++) { + sk6[i] = socket(PF_INET6, SOCK_RAW | SOCK_NONBLOCK, i); + if (sk6[i] >= 0) + test_msg("Created IPv6 proto %zd: %d\n", i, sk6[i]); + } +} + int main(int argc, char *argv[]) { const char string_data[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; @@ -340,6 +364,8 @@ int main(int argc, char *argv[]) exit(1); } + raw_socks_storm(); + test_daemon(); test_waitsig(); From c0b7e4845c955d83abe593afef50b4d0d14b21c5 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 5 Dec 2018 17:21:00 +0200 Subject: [PATCH 1862/4375] dump: lazy-migration: don't try to cleanup zombie processes The lazy memory dump used by the post copy migration cleans up page pipes and parasite from zombie tasks, although for such task they are never initialized. Fix it. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index e2ff90bb5..0e31da572 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1635,8 +1635,10 @@ static int cr_lazy_mem_dump(void) ret = cr_page_server(false, true, -1); for_each_pstree_item(item) { - destroy_page_pipe(dmpi(item)->mem_pp); - compel_cure_local(dmpi(item)->parasite_ctl); + if (item->pid->state != TASK_DEAD) { + destroy_page_pipe(dmpi(item)->mem_pp); + compel_cure_local(dmpi(item)->parasite_ctl); + } } if (ret) From 738d081def460487a49ea035191f11d6197585dc Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 5 Dec 2018 17:21:01 +0200 Subject: [PATCH 1863/4375] test/jenkins: actually test lazy migration The criu-lazy-migration.sh was copied from criu-lazy-pages.sh and was not updated enough to actually run zdtm.py with --lazy-migrate. Fix it. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/jenkins/criu-lazy-migration.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jenkins/criu-lazy-migration.sh b/test/jenkins/criu-lazy-migration.sh index cf0ab0485..30e3c0375 100755 --- a/test/jenkins/criu-lazy-migration.sh +++ b/test/jenkins/criu-lazy-migration.sh @@ -10,11 +10,11 @@ LAZY_MIGRATE_EXCLUDE="-x fifo_loop -x file_locks -x ptrace_sig -x overmount_file # lazy restore from images ./test/zdtm.py run --all --keep-going --report report --parallel 4 -f uns \ - --lazy-pages $LAZY_EXCLUDE $LAZY_MIGRATE_EXCLUDE || fail + --lazy-migrate $LAZY_EXCLUDE $LAZY_MIGRATE_EXCLUDE || fail # During pre-dump + lazy-pages we leave VM_NOHUGEPAGE set LAZY_EXCLUDE="$LAZY_EXCLUDE -x maps02" # lazy restore from images with pre-dumps ./test/zdtm.py run --all --keep-going --report report --parallel 4 -f uns \ - --lazy-pages --pre 2 $LAZY_EXCLUDE $LAZY_MIGRATE_EXCLUDE || fail + --lazy-migrate --pre 2 $LAZY_EXCLUDE $LAZY_MIGRATE_EXCLUDE || fail From 66ce84e67af66c5a9cc3fcbef308e044e23fa028 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 6 Dec 2018 09:46:12 +0000 Subject: [PATCH 1864/4375] list: Drop unused __list_for_each The macro __list_for_each is equivalent to list_for_each and it is not used anywhere. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- include/common/list.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/common/list.h b/include/common/list.h index 4e33475c1..b8b57c784 100644 --- a/include/common/list.h +++ b/include/common/list.h @@ -216,9 +216,6 @@ static inline void list_splice_tail_init(struct list_head *list, #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); pos = pos->prev) From bdd4c5a852e10ce77e51b046c1ae86e45390ad22 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 5 Dec 2018 09:59:24 +0000 Subject: [PATCH 1865/4375] log: Use USEC_PER_SEC instead of 1000000 Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/log.c b/criu/log.c index 2f5b28a62..a268ab8a4 100644 --- a/criu/log.c +++ b/criu/log.c @@ -51,7 +51,7 @@ static void timediff(struct timeval *from, struct timeval *to) to->tv_usec -= from->tv_usec; else { to->tv_sec--; - to->tv_usec += 1000000 - from->tv_usec; + to->tv_usec += USEC_PER_SEC - from->tv_usec; } } From 685f4caaee4faf95c27ee941b67b2743c34391d7 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 10 Dec 2018 17:44:10 +0200 Subject: [PATCH 1866/4375] pre-dump: don't allow --lazy-pages option Using --lazy-pages with pre-dump causes partial memory dump and it's not the intention. The whole point of pre-dump is to keep amount of memory that would be dumped during tasks freeze to minimum. Disallow running pre-dump with --lazy-pages. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/crtools.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/criu/crtools.c b/criu/crtools.c index c9f0a195d..c1431b46a 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -238,6 +238,11 @@ int main(int argc, char *argv[], char *envp[]) if (!opts.tree_id) goto opt_pid_missing; + if (opts.lazy_pages) { + pr_err("Cannot pre-dump with --lazy-pages\n"); + return 1; + } + return cr_pre_dump_tasks(opts.tree_id) != 0; } From 73d553f3160addb9456ffae28009f1c71e7de2e8 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 10 Dec 2018 17:44:11 +0200 Subject: [PATCH 1867/4375] test: lazy-migration: don't try to run pre-dump with --lazy-pages Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 018ad0ec6..3e98a56c5 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1123,7 +1123,7 @@ class criu: a_opts += ['--empty-ns', 'net'] nowait = False - if self.__lazy_migrate: + if self.__lazy_migrate and action == "dump": a_opts += ["--lazy-pages", "--port", "12345"] nowait = True self.__dump_process = self.__criu_act(action, opts = a_opts + opts, nowait = nowait) From 39863eeb1ec4d787c1037cf0c12cc3e51a59ffcd Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 10 Dec 2018 15:33:55 +0300 Subject: [PATCH 1868/4375] files-reg: make error message in clean_one_remap contain mntns path rmntns_root - is fd number of opened mntns root directory, these info doesn't help to identify mntns involved in logs, show path to these mntns instead. Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 0c3c27dd6..3d895d2bc 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -681,7 +681,7 @@ static int clean_one_remap(struct remap_info *ri) ret = unlinkat(rmntns_root, remap->rpath, remap->is_dir ? AT_REMOVEDIR : 0); if (ret < 0) { close(rmntns_root); - pr_perror("Couldn't unlink remap %d %s", rmntns_root, remap->rpath); + pr_perror("Couldn't unlink remap %s %s", path, remap->rpath); return -1; } close(rmntns_root); From 05ab416ae83e9247fc5937da70128d04cec60b80 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 10 Dec 2018 15:33:56 +0300 Subject: [PATCH 1869/4375] mount: make __depopulate_roots_yard static As these function is never used outside of criu/mount.c Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/mount.c b/criu/mount.c index 5a97c1f1b..f578c7b6a 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -3179,7 +3179,7 @@ static int populate_mnt_ns(void) return ret; } -int __depopulate_roots_yard(void) +static int __depopulate_roots_yard(void) { int ret = 0; From 2b602c363f060a8e830ff9b8ae1e004b745e7a16 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 4 Dec 2018 18:07:11 -0800 Subject: [PATCH 1870/4375] compel/Makefile: don't use `-fr` for cp No need to use either -r (recursive) or -f (force). Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compel/Makefile b/compel/Makefile index 7ef01aa01..45736f29e 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -62,10 +62,10 @@ install: compel/compel compel/$(LIBCOMPEL_SO) compel/$(LIBCOMPEL_A) $(Q) install -m 0644 compel/$(LIBCOMPEL_A) $(DESTDIR)$(LIBDIR) $(E) " INSTALL " compel uapi $(Q) mkdir -p $(DESTDIR)$(INCLUDEDIR)/compel/asm - $(Q) cp -fr compel/include/uapi/*.h $(DESTDIR)$(INCLUDEDIR)/compel/ - $(Q) cp -fr compel/include/uapi/asm/*.h $(DESTDIR)$(INCLUDEDIR)/compel/asm/ + $(Q) cp compel/include/uapi/*.h $(DESTDIR)$(INCLUDEDIR)/compel/ + $(Q) cp compel/include/uapi/asm/*.h $(DESTDIR)$(INCLUDEDIR)/compel/asm/ $(Q) mkdir -p $(DESTDIR)$(INCLUDEDIR)/compel/common/asm - $(Q) cp -fr include/common/compiler.h $(DESTDIR)$(INCLUDEDIR)/compel/common/ + $(Q) cp include/common/compiler.h $(DESTDIR)$(INCLUDEDIR)/compel/common/ .PHONY: install uninstall: From ae15718b1318682133cad6542d6fc3b20d194a4d Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 4 Dec 2018 18:07:12 -0800 Subject: [PATCH 1871/4375] Do not install .gitignore This avoids installing .gitignore file to compel includes. While at it, describe why this .gitignore is needed. Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- compel/plugins/Makefile | 6 ++++-- compel/plugins/include/uapi/std/asm/.gitignore | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 82c35be6a..60b78473c 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -87,8 +87,10 @@ install: compel/plugins/std.lib.a compel/plugins/fds.lib.a $(Q) mkdir -p $(DESTDIR)$(LIBEXECDIR)/compel/scripts $(Q) install -m 0644 compel/arch/$(ARCH)/scripts/compel-pack.lds.S $(DESTDIR)$(LIBEXECDIR)/compel/scripts $(E) " INSTALL " compel plugins uapi - $(Q) mkdir -p $(DESTDIR)$(INCLUDEDIR)/compel/plugins - $(Q) cp -frL compel/plugins/include/uapi/* $(DESTDIR)$(INCLUDEDIR)/compel/plugins/ + $(Q) mkdir -p $(DESTDIR)$(INCLUDEDIR)/compel/plugins/std/asm + $(Q) cp -fL compel/plugins/include/uapi/*.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins/ + $(Q) cp -fL compel/plugins/include/uapi/std/*.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins/std/ + $(Q) cp -fL compel/plugins/include/uapi/std/asm/*.h $(DESTDIR)$(INCLUDEDIR)/compel/plugins/std/asm/ .PHONY: install uninstall: diff --git a/compel/plugins/include/uapi/std/asm/.gitignore b/compel/plugins/include/uapi/std/asm/.gitignore index e69de29bb..5ca235408 100644 --- a/compel/plugins/include/uapi/std/asm/.gitignore +++ b/compel/plugins/include/uapi/std/asm/.gitignore @@ -0,0 +1 @@ +# Dear git, please keep this directory From 134c7c275bc99fbe9825030dfc616490c51158bf Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 12 Sep 2018 08:37:36 +0200 Subject: [PATCH 1872/4375] criu: fix segfault in pre-dump By accident I found a segfault using pre-dump in combination with the page-server. Doing the following I was able to trigger it: * criu page-server -D /tmp/1 * criu pre-dump -t PID -D /tmp/3 --track-mem * criu page-server -D /tmp/4 --prev-images-dir ../1 * criu pre-dump -t PID -D /tmp/3 --track-mem --> segfault ... (00.010090) Warn (criu/image.c:134): Failed to open parent directory ... (00.012984) Error (criu/mem.c:318): Pid-reuse detection failed: no parent inventory, check warnings in get_parent_stats ... (00.013037) Error (criu/mem.c:544): Can't dump page with parasite ... (00.013955) Pre-dumping tasks' memory (00.013966) Pre-dumping 8793 (00.014380) Transferring pages: Segmentation fault (core dumped) Looking in cr-dump.c at cr_pre_dump_finish(int ret) the function gets the return code of the previous operations in 'ret' but it is immediately overwritten and never used. In older CRIU versions it used to be: if (ret < 0) goto err; but that is gone now. So this reintroduces the check for the int parameter given to cr_pre_dump_finish() by the function caller. As the commands used to trigged the segfault do not make much sense the result is still not usable and the same 'Warn' and 'Error' messages are printed, but the segfault is gone. V2: * set the return value correctly Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 0e31da572..78648baeb 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1468,10 +1468,11 @@ static int setup_alarm_handler() return 0; } -static int cr_pre_dump_finish(int ret) +static int cr_pre_dump_finish(int status) { InventoryEntry he = INVENTORY_ENTRY__INIT; struct pstree_item *item; + int ret; /* * Restore registers for tasks only. The threads have not been @@ -1489,6 +1490,11 @@ static int cr_pre_dump_finish(int ret) timing_stop(TIME_FROZEN); + if (status < 0) { + ret = status; + goto err; + } + pr_info("Pre-dumping tasks' memory\n"); for_each_pstree_item(item) { struct parasite_ctl *ctl = dmpi(item)->parasite_ctl; From b1c9e7faaf6e8874aafd241f404a1a685ecc3c0b Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 19 Dec 2018 18:04:57 +0000 Subject: [PATCH 1873/4375] Fix RPC configuration file handling While writing runc test cases to verify that runc correctly uses RPC configuration files it became clear that some things were not working as they are supposed to. Looking closer at the code to set log files via RPC configuration files I discovered that the code seems wrong (at least I did not understand it any more (or the intentions behind it)). This code tries to simplify that logic a bit and add more comments to make clear what the intentions of the RPC configuration file code is. v2: - fix existing test case to test better (more correct) - make changes requested by Andrei v3: - more changes as requested by Andrei Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/cr-service.c | 61 +++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 4a9983ac7..532a87c81 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -267,22 +267,14 @@ static int setup_opts_from_req(int sk, CriuOpts *req) * overwrites all options set via RPC. */ if (req->config_file) { - char *tmp_output = NULL; - char *tmp_work = NULL; - char *tmp_imgs = NULL; + char *tmp_output = opts.output; + char *tmp_work = opts.work_dir; + char *tmp_imgs = opts.imgs_dir; - if (opts.output) - tmp_output = xstrdup(opts.output); - if (opts.work_dir) - tmp_work = xstrdup(opts.work_dir); - if (opts.imgs_dir) - tmp_imgs = xstrdup(opts.imgs_dir); - xfree(opts.output); - xfree(opts.work_dir); - xfree(opts.imgs_dir); opts.output = NULL; opts.work_dir = NULL; opts.imgs_dir = NULL; + rpc_cfg_file = req->config_file; i = parse_options(0, NULL, &dummy, &dummy, PARSING_RPC_CONF); pr_warn("parse_options returns %d\n", i); @@ -292,23 +284,42 @@ static int setup_opts_from_req(int sk, CriuOpts *req) xfree(tmp_imgs); goto err; } - if (tmp_output && opts.output && !strncmp(tmp_output, opts.output, PATH_MAX)) + /* If this is non-NULL, the RPC configuration file had a value, use it.*/ + if (opts.output) output_changed_by_rpc_conf = true; - if (tmp_work && opts.work_dir && !strncmp(tmp_work, opts.work_dir, PATH_MAX)) + /* If this is NULL, use the old value if it was set. */ + if (!opts.output && tmp_output) { + opts.output = tmp_output; + tmp_output = NULL; + } + + if (opts.work_dir) work_changed_by_rpc_conf = true; - if (tmp_imgs && opts.imgs_dir && !strncmp(tmp_imgs, opts.imgs_dir, PATH_MAX)) + if (!opts.work_dir && tmp_work) { + opts.work_dir = tmp_work; + tmp_work = NULL; + } + + if (opts.imgs_dir) imgs_changed_by_rpc_conf = true; + /* + * As the images directory is a required RPC setting, it is not + * necessary to use the value from other configuration files. + * Either it is set in the RPC configuration file or it is set + * via RPC. + */ xfree(tmp_output); xfree(tmp_work); xfree(tmp_imgs); } /* - * open images_dir + * open images_dir - images_dir_fd is a required RPC parameter + * * This assumes that if opts.imgs_dir is set we have a value * from the configuration file parser. The test to see that * imgs_changed_by_rpc_conf is true is used to make sure the value - * is not the same as from one of the other configuration files. + * is from the RPC configuration file. * The idea is that only the RPC configuration file is able to * overwrite RPC settings: * * apply_config(global_conf) @@ -317,7 +328,7 @@ static int setup_opts_from_req(int sk, CriuOpts *req) * * apply_rpc_options() * * apply_config(rpc_conf) */ - if (opts.imgs_dir && imgs_changed_by_rpc_conf) + if (imgs_changed_by_rpc_conf) strncpy(images_dir_path, opts.imgs_dir, PATH_MAX - 1); else sprintf(images_dir_path, "/proc/%d/fd/%d", ids.pid, req->images_dir_fd); @@ -337,11 +348,17 @@ static int setup_opts_from_req(int sk, CriuOpts *req) } /* chdir to work dir */ - if (opts.work_dir && work_changed_by_rpc_conf) + if (work_changed_by_rpc_conf) + /* Use the value from the RPC configuration file first. */ strncpy(work_dir_path, opts.work_dir, PATH_MAX - 1); else if (req->has_work_dir_fd) + /* Use the value set via RPC. */ sprintf(work_dir_path, "/proc/%d/fd/%d", ids.pid, req->work_dir_fd); + else if (opts.work_dir) + /* Use the value from one of the other configuration files. */ + strncpy(work_dir_path, opts.work_dir, PATH_MAX - 1); else + /* Use the images directory a work directory. */ strcpy(work_dir_path, images_dir_path); if (chdir(work_dir_path)) { @@ -350,7 +367,11 @@ static int setup_opts_from_req(int sk, CriuOpts *req) } /* initiate log file in work dir */ - if (req->log_file && !(opts.output && output_changed_by_rpc_conf)) { + if (req->log_file && !output_changed_by_rpc_conf) { + /* + * If RPC sets a log file and if there nothing from the + * RPC configuration file, use the RPC value. + */ if (strchr(req->log_file, '/')) { pr_perror("No subdirs are allowed in log_file name"); goto err; From bada5e1ada7ae487c4244cdec864a2bcad65238b Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 19 Dec 2018 18:04:58 +0000 Subject: [PATCH 1874/4375] Fix RPC configuration file test case The relevant test case test_rpc_with_configuration_file_overwriting_rpc() was actually designed around the broken behaviour. It was only working if a previous configuration file (set via environment variable in this case) and the RPC configuration file have the same name. The test case which tests that RPC configuration file settings are overwriting direct RPC settings now makes sure that no other configuration file is set via the environment variable. If it would be set, the test case would still succeed, even with the previous patch applied. Which is and which was the correct behaviour. So the main reason for this change is to test the more likely use case that the environment based configuration file and the RPC configuration file have different names. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- test/others/rpc/config_file.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/test/others/rpc/config_file.py b/test/others/rpc/config_file.py index b74cc0428..23a06615f 100755 --- a/test/others/rpc/config_file.py +++ b/test/others/rpc/config_file.py @@ -34,10 +34,18 @@ def setup_config_file(content): def cleanup_config_file(path): - del os.environ['CRIU_CONFIG_FILE'] + if os.environ.get('CRIU_CONFIG_FILE', None) is not None: + del os.environ['CRIU_CONFIG_FILE'] os.unlink(path) +def cleanup_output(path): + for f in (does_not_exist, log_file): + f = os.path.join(path, f) + if os.access(f, os.F_OK): + os.unlink(f) + + def setup_criu_dump_request(): # Create criu msg, set it's type to dump request # and set dump options. Checkout more options in protobuf/rpc.proto @@ -155,6 +163,9 @@ def test_rpc_with_configuration_file_overwriting_rpc(): content = 'log-file ' + log + '\n' content += 'no-tcp-established\nno-shell-job' path = setup_config_file(content) + # Only set the configuration file via RPC; + # not via environment variable + del os.environ['CRIU_CONFIG_FILE'] req = setup_criu_dump_request() req.opts.config_file = path _, s = setup_swrk() @@ -169,14 +180,13 @@ parser.add_argument('dir', type = str, help = "Directory where CRIU images shoul args = vars(parser.parse_args()) -try: - # optional cleanup - os.unlink(os.path.join(args['dir'], does_not_exist)) - os.unlink(os.path.join(args['dir'], log_file)) -except OSError: - pass +cleanup_output(args['dir']) test_broken_configuration_file() +cleanup_output(args['dir']) test_rpc_without_configuration_file() +cleanup_output(args['dir']) test_rpc_with_configuration_file() +cleanup_output(args['dir']) test_rpc_with_configuration_file_overwriting_rpc() +cleanup_output(args['dir']) From 5ecbc104f8282bf51465781a4cfd581af3d6d1db Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 19 Dec 2018 15:26:06 +0300 Subject: [PATCH 1875/4375] compel,x86: Drop call32.S symlink Not needed since e2bd7af94cb7b43e2c0bed0546ef83c2f3eea25c Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- compel/arch/x86/plugins/std/call32.S | 1 - 1 file changed, 1 deletion(-) delete mode 120000 compel/arch/x86/plugins/std/call32.S diff --git a/compel/arch/x86/plugins/std/call32.S b/compel/arch/x86/plugins/std/call32.S deleted file mode 120000 index b0fd67bc0..000000000 --- a/compel/arch/x86/plugins/std/call32.S +++ /dev/null @@ -1 +0,0 @@ -../../../../../criu/arch/x86/call32.S \ No newline at end of file From 42bc32f6c0ec9ad7f7298f62998611c3dfc3b79b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 1 Jan 2019 23:06:38 -0800 Subject: [PATCH 1876/4375] travis/docker: install docker from the test repo C/R in Docker from the stable repo is broken. Signed-off-by: Andrei Vagin --- scripts/travis/docker-test.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/travis/docker-test.sh b/scripts/travis/docker-test.sh index 0f034cfa6..14868e960 100755 --- a/scripts/travis/docker-test.sh +++ b/scripts/travis/docker-test.sh @@ -12,7 +12,7 @@ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ - stable" + stable test" apt-get update -qq @@ -50,6 +50,8 @@ for i in `seq 50`; do docker exec cr ps axf && docker checkpoint create cr checkpoint$i && sleep 1 && + docker ps && + (docker exec cr true && exit 1 || exit 0) && docker start --checkpoint checkpoint$i cr 2>&1 | tee log || { cat "`cat log | grep 'log file:' | sed 's/log file:\s*//'`" || true docker logs cr || true From 8800da2b77bf008fe490c161bf176cdf37f8ec7a Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 1 Jan 2019 23:06:39 -0800 Subject: [PATCH 1877/4375] files: don't use PROC_SELF during restoring file descriptors open_proc_pid(PROC_SELF) returns a non-service file descriptor, but it can take a place of a target file descriptor. Signed-off-by: Andrei Vagin --- criu/files-reg.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 3d895d2bc..265efe071 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1593,7 +1593,11 @@ int open_path(struct file_desc *d, tmp = inherit_fd_lookup_id(rfi->rfe->name); if (tmp >= 0) { inh_fd = tmp; - mntns_root = open_pid_proc(PROC_SELF); + /* + * PROC_SELF isn't used, because only service + * descriptors can be used here. + */ + mntns_root = open_pid_proc(getpid()); snprintf(path, sizeof(path), "fd/%d", tmp); orig_path = rfi->path; rfi->path = path; From 034fc1424fa32dd4b2a436f3ac216e121eb7eef0 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 1 Jan 2019 23:06:40 -0800 Subject: [PATCH 1878/4375] zdtm.py: cache test messages Currently, we rely on the fact that nobody else is using random and parent and child processes will get the same random values. Now, this test fails on the fedora rawhide. There will be nothing wrong if we will generate test messages before forking the test process. Signed-off-by: Andrei Vagin --- test/zdtm.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 3e98a56c5..9b88cee11 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -584,9 +584,14 @@ class inhfd_test: self.__files = None self.__peer_file_names = [] self.__dump_opts = [] + self.__messages = {} def __get_message(self, i): - return b"".join([random.choice(string.ascii_letters).encode() for _ in range(10)]) + b"%06d" % i + m = self.__messages.get(i, None) + if not m: + m = b"".join([random.choice(string.ascii_letters).encode() for _ in range(10)]) + b"%06d" % i + self.__messages[i] = m + return m def start(self): self.__files = self.__fdtyp.create_fds() From 5c71e3e028ebc7669ad0e00bc8fbbb4e41c7a5b9 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 1 Jan 2019 23:06:41 -0800 Subject: [PATCH 1879/4375] test/inhfd: redirect stdin to /dev/null Signed-off-by: Andrei Vagin --- test/zdtm.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 9b88cee11..5e19d9a90 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -622,7 +622,9 @@ class inhfd_test: fd = os.open(self.__name + ".out", os.O_WRONLY | os.O_APPEND | os.O_CREAT) os.dup2(fd, 1) os.dup2(fd, 2) - os.close(0) + os.close(fd) + fd = os.open("/dev/null", os.O_RDONLY) + os.dup2(fd, 0) for my_file, _ in self.__files: my_file.close() os.close(start_pipe[0]) From b8fdcd71f8788dc4e8020ae442e133a0a3a4513e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 1 Jan 2019 23:06:42 -0800 Subject: [PATCH 1880/4375] travis/fedora: install the kmod package This patch fixes the error: (00.074175) Error (criu/net.c:2638): Locking network failed: iptables-restore returned -1. This may be connected to disabled CONFIG_NETFILTER_XT_MARK kernel build config option. Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.fedora.tmpl | 3 ++- scripts/travis/Makefile | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index de45fd8cb..616b9ec42 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -33,7 +33,8 @@ RUN dnf install -y \ tar \ which \ e2fsprogs \ - asciidoc xmlto + asciidoc xmlto \ + kmod # Replace coreutils-single with "traditional" coreutils # to fix the following error on Fedora 28/rawhide while diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index 07c46fa48..77c937432 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -30,7 +30,6 @@ $(TARGETS): docker run --env-file docker.env --rm -it --privileged -v /lib/modules:/lib/modules --tmpfs /run criu-$@ scripts/travis/travis-tests fedora-asan: - ip6tables -L -n echo "$$DOCKER_JSON" > /etc/docker/daemon.json systemctl restart docker $(MAKE) -C ../build $@$(target-suffix) From 64c6e2959131371020dc9a7c58e87e48808f66ef Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 28 Dec 2018 08:10:07 +0000 Subject: [PATCH 1881/4375] namespaces: Use EINVAL instead of 22 Signed-off-by: Radostin Stoyanov Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/namespaces.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/namespaces.c b/criu/namespaces.c index 05d75d533..a228737ee 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -46,7 +46,7 @@ static unsigned int join_ns_flags; int check_namespace_opts(void) { - errno = 22; + errno = EINVAL; if (join_ns_flags & opts.empty_ns) { pr_err("Conflicting flags: --join-ns and --empty-ns\n"); return -1; @@ -71,7 +71,7 @@ static int check_int_str(char *str) return 0; } - errno = 22; + errno = EINVAL; val = strtol(str, &endptr, 10); if ((errno == ERANGE) || (endptr == str) || (*endptr != '\0') From 556223a646b7939e32b67f4d33d6148640d96fd0 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 4 Jan 2019 18:30:29 +0000 Subject: [PATCH 1882/4375] build: Show a note when building wihout libbsd Show a note that when libbsd is not installed CRIU is compiled without setproctitle() and strlcpy() support. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- Makefile.config | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile.config b/Makefile.config index 0e557805c..d89ccbb1a 100644 --- a/Makefile.config +++ b/Makefile.config @@ -5,6 +5,9 @@ include scripts/feature-tests.mak ifeq ($(call try-cc,$(FEATURE_TEST_LIBBSD_DEV),-lbsd),true) LIBS_FEATURES += -lbsd FEATURE_DEFINES += -DCONFIG_HAS_LIBBSD +else + $(info Note: Building without setproctitle() and strlcpy() support.) + $(info $(info) To enable these features, please install libbsd-devel (RPM) / libbsd-dev (DEB).) endif ifeq ($(call pkg-config-check,libselinux),y) From 8a90bc8302fa7af382e0598411b9bbf129f672a5 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 4 Jan 2019 20:44:18 +0000 Subject: [PATCH 1883/4375] test/static: Add test for --skip-in-flight Changes since v1: - Refactor test case based on Andrei's comments Changes since v2: - Use ZDTM_FAMILY instead of AF_INET Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 2 + test/zdtm/static/socket-tcp-skip-in-flight.c | 154 ++++++++++++++++++ .../static/socket-tcp-skip-in-flight.desc | 1 + 3 files changed, 157 insertions(+) create mode 100644 test/zdtm/static/socket-tcp-skip-in-flight.c create mode 100644 test/zdtm/static/socket-tcp-skip-in-flight.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 7b8d66377..2d13e7d2a 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -104,6 +104,7 @@ TST_NOFILE := \ socket-tcp-unconn \ socket-tcp6-unconn \ socket-tcp-syn-sent \ + socket-tcp-skip-in-flight \ sock_opts00 \ sock_opts01 \ sk-unix-unconn \ @@ -486,6 +487,7 @@ socket_listen4v6: CFLAGS += -D ZDTM_IPV4V6 socket-tcp6-closed: CFLAGS += -D ZDTM_IPV6 socket-tcp6-closed: CFLAGS += -D ZDTM_IPV4V6 socket-tcp-closed-last-ack: CFLAGS += -D ZDTM_TCP_LAST_ACK +socket-tcp-skip-in-flight: CFLAGS += -D ZDTM_IPV4V6 tun_ns: CFLAGS += -DTUN_NS mnt_ext_manual: CFLAGS += -D ZDTM_EXTMAP_MANUAL sigpending: LDLIBS += -lrt diff --git a/test/zdtm/static/socket-tcp-skip-in-flight.c b/test/zdtm/static/socket-tcp-skip-in-flight.c new file mode 100644 index 000000000..eef73d992 --- /dev/null +++ b/test/zdtm/static/socket-tcp-skip-in-flight.c @@ -0,0 +1,154 @@ +#include "zdtmtst.h" + +#ifdef ZDTM_IPV4V6 +#define ZDTM_FAMILY AF_INET +#elif defined(ZDTM_IPV6) +#define ZDTM_FAMILY AF_INET6 +#else +#define ZDTM_FAMILY AF_INET +#endif + +const char *test_doc = "Check that in-flight TCP connections are ignored\n"; +const char *test_author = "Radostin Stoyanov "; + +/* Description: + * Initialise server and client tcp sockets and verify that + * in-flight TCP connections are ignored. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 1234 +#define HOST "127.0.0.1" + +static int check_socket_state(int sk, int state) +{ + int err; + struct { + __u8 tcpi_state; + } info; + socklen_t len = sizeof(info); + + err = getsockopt(sk, IPPROTO_TCP, TCP_INFO, (void *)&info, &len); + if (err != 0) { + pr_perror("Can't get socket state\n"); + return -1; + } else if (info.tcpi_state != state) { + fail("Invalid socket state (%i)\n", (int)info.tcpi_state); + return -1; + } + + return 0; +} + +int open_socket() +{ + int fd; + fd = socket(ZDTM_FAMILY, SOCK_STREAM, 0); + if (fd < 0) { + fail("Failed to open socket\n"); + return -1; + } + return fd; +} + +int server() +{ + int fd_s; + struct sockaddr_in serv_addr; + + fd_s = open_socket(); + if (fd_s < 0) + return -1; + + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = ZDTM_FAMILY; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(PORT); + + if (bind(fd_s, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + fail("Failed to bind"); + return -1; + } + + listen(fd_s, 1); + + /* Listen but do not accept connect()-ed TCP connection. */ + + return fd_s; +} + +int client() +{ + int fd_c; + struct sockaddr_in serv_addr; + struct hostent *server; + + fd_c = open_socket(); + if (fd_c < 0) + return -1; + + server = gethostbyname(HOST); + if (server == NULL) { + fail("Failed to get host by name\n"); + return -1; + } + + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = ZDTM_FAMILY; + bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); + serv_addr.sin_port = htons(PORT); + if (connect(fd_c,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + fail("Failed to get host by name\n"); + return -1; + } + + return fd_c; +} + +int main(int argc, char **argv) +{ + int fd_s; + int fd_c; + + test_init(argc, argv); + + fd_s = server(); + if (fd_s < 0) { + fail("Failed to initialize server\n"); + return -1; + } + + fd_c = client(); + if (fd_c < 0) { + fail("Failed to initialize client\n"); + return -1; + } + + if (check_socket_state(fd_s, TCP_LISTEN)) { + fail("Server socket state before restore isn't TCP_LISTEN\n"); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (check_socket_state(fd_s, TCP_LISTEN)) { + fail("Server socket state after restore isn't TCP_LISTEN\n"); + return 1; + } + + close(fd_s); + close(fd_c); + + pass(); + return 0; +} diff --git a/test/zdtm/static/socket-tcp-skip-in-flight.desc b/test/zdtm/static/socket-tcp-skip-in-flight.desc new file mode 100644 index 000000000..0ef6e6d2b --- /dev/null +++ b/test/zdtm/static/socket-tcp-skip-in-flight.desc @@ -0,0 +1 @@ +{'opts': '--tcp-established --skip-in-flight'} From 88a52c2b82645c1bb403a646a8714f126c573889 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 20 Dec 2018 11:08:37 +0300 Subject: [PATCH 1884/4375] net: libnetlink -- Call error handler instead of unconditional error message To be able to zap error messages when needed. Without error handler we will continue printing error. This will placate diag modules probing since they are not mandatory features. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/libnetlink.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/criu/libnetlink.c b/criu/libnetlink.c index 986a05bca..2ce4a3826 100644 --- a/criu/libnetlink.c +++ b/criu/libnetlink.c @@ -21,13 +21,8 @@ static int nlmsg_receive(char *buf, int len, continue; if (hdr->nlmsg_type == NLMSG_DONE) { int *len = (int *)NLMSG_DATA(hdr); - - if (*len < 0) { - pr_err("ERROR %d reported by netlink (%s)\n", - *len, strerror(-*len)); - return *len; - } - + if (*len < 0) + return err_cb(*len, arg); return 0; } if (hdr->nlmsg_type == NLMSG_ERROR) { @@ -52,7 +47,8 @@ static int nlmsg_receive(char *buf, int len, static int rtnl_return_err(int err, void *arg) { - pr_warn("ERROR %d reported by netlink\n", err); + errno = -err; + pr_perror("ERROR %d reported by netlink", err); return err; } From 33166f29693520b7fccaa43671d5d41eb4bb89dc Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 20 Dec 2018 11:08:38 +0300 Subject: [PATCH 1885/4375] net: sockets -- Don't spam log with known errors For example if diag module is not built then we should not spam with error message but we will print an error if only a particular socket is really used. v2: - continue passing @ns into error handler because it should be balanced with receieve handler by number of arguments; while we don't use it yet in our handlers better to reserve it immediately for future use; - strictly speaking probing raw diag module has not much sense by now -- the kernel doesn't support its autoloading in some versions; still for code consistency we should do the same things for all modules. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/libnetlink.h | 2 +- criu/libnetlink.c | 10 ++-- criu/sockets.c | 101 ++++++++++++++++++++++++-------------- 3 files changed, 70 insertions(+), 43 deletions(-) diff --git a/criu/include/libnetlink.h b/criu/include/libnetlink.h index bf2eb2474..f21a0e750 100644 --- a/criu/include/libnetlink.h +++ b/criu/include/libnetlink.h @@ -6,7 +6,7 @@ struct ns_id; extern int do_rtnl_req(int nl, void *req, int size, int (*receive_callback)(struct nlmsghdr *h, struct ns_id *ns, void *), - int (*error_callback)(int err, void *), struct ns_id *ns, void *); + int (*error_callback)(int err, struct ns_id *ns, void *), struct ns_id *ns, void *); extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen); diff --git a/criu/libnetlink.c b/criu/libnetlink.c index 2ce4a3826..60e98e346 100644 --- a/criu/libnetlink.c +++ b/criu/libnetlink.c @@ -12,7 +12,7 @@ static int nlmsg_receive(char *buf, int len, int (*cb)(struct nlmsghdr *, struct ns_id *ns, void *), - int (*err_cb)(int, void *), struct ns_id *ns, void *arg) + int (*err_cb)(int, struct ns_id *, void *), struct ns_id *ns, void *arg) { struct nlmsghdr *hdr; @@ -22,7 +22,7 @@ static int nlmsg_receive(char *buf, int len, if (hdr->nlmsg_type == NLMSG_DONE) { int *len = (int *)NLMSG_DATA(hdr); if (*len < 0) - return err_cb(*len, arg); + return err_cb(*len, ns, arg); return 0; } if (hdr->nlmsg_type == NLMSG_ERROR) { @@ -36,7 +36,7 @@ static int nlmsg_receive(char *buf, int len, if (err->error == 0) return 0; - return err_cb(err->error, arg); + return err_cb(err->error, ns, arg); } if (cb(hdr, ns, arg)) return -1; @@ -45,7 +45,7 @@ static int nlmsg_receive(char *buf, int len, return 1; } -static int rtnl_return_err(int err, void *arg) +static int rtnl_return_err(int err, struct ns_id *ns, void *arg) { errno = -err; pr_perror("ERROR %d reported by netlink", err); @@ -54,7 +54,7 @@ static int rtnl_return_err(int err, void *arg) int do_rtnl_req(int nl, void *req, int size, int (*receive_callback)(struct nlmsghdr *h, struct ns_id *ns, void *), - int (*error_callback)(int err, void *), struct ns_id *ns, void *arg) + int (*error_callback)(int err, struct ns_id *ns, void *arg), struct ns_id *ns, void *arg) { struct msghdr msg; struct sockaddr_nl nladdr; diff --git a/criu/sockets.c b/criu/sockets.c index 510b84f66..48c71940d 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -212,7 +212,7 @@ static int probe_recv_one(struct nlmsghdr *h, struct ns_id *ns, void *arg) return -1; } -static int probe_err(int err, void *arg) +static int probe_err(int err, struct ns_id *ns, void *arg) { int expected_err = *(int *)arg; @@ -716,18 +716,57 @@ static int inet_receive_one(struct nlmsghdr *h, struct ns_id *ns, void *arg) static int do_collect_req(int nl, struct sock_diag_req *req, int size, int (*receive_callback)(struct nlmsghdr *h, struct ns_id *ns, void *), + int (*error_callback)(int err, struct ns_id *ns, void *), struct ns_id *ns, void *arg) { - int tmp; - - tmp = do_rtnl_req(nl, req, size, receive_callback, NULL, ns, arg); - + int tmp = do_rtnl_req(nl, req, size, receive_callback, error_callback, ns, arg); if (tmp == 0) set_collect_bit(req->r.n.sdiag_family, req->r.n.sdiag_protocol); - return tmp; } +static int collect_err(int err, struct ns_id *ns, void *arg) +{ + struct sock_diag_greq *gr = arg; + char family[32], proto[32]; + char msg[256]; + + /* + * If module is not compiled or unloaded, + * we should simply pass error up to a caller + * which then warn a user. + */ + if (err == -ENOENT) + return -ENOENT; + + /* + * Diag modules such as unix, packet, netlink + * may return EINVAL on older kernels. + */ + if (err == -EINVAL) { + if (gr->family == AF_UNIX || + gr->family == AF_PACKET || + gr->family == AF_NETLINK) + return -EINVAL; + } + + /* + * Rest is more serious, just print enough information. + * In case if everything is OK -- point as well. + */ + snprintf(msg, sizeof(msg), + "Sockects collect procedure family %s proto %s\n", + socket_family_name(gr->family, family, sizeof(family)), + socket_proto_name(gr->protocol, proto, sizeof(proto))); + + if (!err) + pr_info("%s: OK\n", msg); + else + pr_err("%s: %s\n", msg, strerror(-err)); + + return err; +} + int collect_sockets(struct ns_id *ns) { int err = 0, tmp; @@ -746,7 +785,7 @@ int collect_sockets(struct ns_id *ns) req.r.u.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_VFS | UDIAG_SHOW_PEER | UDIAG_SHOW_ICONS | UDIAG_SHOW_RQLEN; - tmp = do_collect_req(nl, &req, sizeof(req), unix_receive_one, ns, NULL); + tmp = do_collect_req(nl, &req, sizeof(req), unix_receive_one, collect_err, ns, &req.r.u); if (tmp) err = tmp; @@ -759,7 +798,7 @@ int collect_sockets(struct ns_id *ns) (1 << TCP_FIN_WAIT1) | (1 << TCP_FIN_WAIT2) | (1 << TCP_CLOSE_WAIT) | (1 << TCP_LAST_ACK) | (1 << TCP_CLOSING) | (1 << TCP_SYN_SENT); - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, collect_err, ns, &req.r.i); if (tmp) err = tmp; @@ -768,7 +807,7 @@ int collect_sockets(struct ns_id *ns) req.r.i.sdiag_protocol = IPPROTO_UDP; req.r.i.idiag_ext = 0; req.r.i.idiag_states = -1; /* All */ - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, collect_err, ns, &req.r.i); if (tmp) err = tmp; @@ -777,7 +816,7 @@ int collect_sockets(struct ns_id *ns) req.r.i.sdiag_protocol = IPPROTO_UDPLITE; req.r.i.idiag_ext = 0; req.r.i.idiag_states = -1; /* All */ - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, collect_err, ns, &req.r.i); if (tmp) err = tmp; @@ -786,12 +825,9 @@ int collect_sockets(struct ns_id *ns) req.r.i.sdiag_protocol = IPPROTO_RAW; req.r.i.idiag_ext = 0; req.r.i.idiag_states = -1; /* All */ - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); - if (tmp) { - pr_warn("The current kernel doesn't support ipv4 raw_diag module\n"); - if (tmp != -ENOENT) - err = tmp; - } + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, collect_err, ns, &req.r.i); + if (tmp) + err = tmp; /* Collect IPv6 TCP sockets */ req.r.i.sdiag_family = AF_INET6; @@ -802,7 +838,7 @@ int collect_sockets(struct ns_id *ns) (1 << TCP_FIN_WAIT1) | (1 << TCP_FIN_WAIT2) | (1 << TCP_CLOSE_WAIT) | (1 << TCP_LAST_ACK) | (1 << TCP_CLOSING) | (1 << TCP_SYN_SENT); - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, collect_err, ns, &req.r.i); if (tmp) err = tmp; @@ -811,7 +847,7 @@ int collect_sockets(struct ns_id *ns) req.r.i.sdiag_protocol = IPPROTO_UDP; req.r.i.idiag_ext = 0; req.r.i.idiag_states = -1; /* All */ - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, collect_err, ns, &req.r.i); if (tmp) err = tmp; @@ -820,7 +856,7 @@ int collect_sockets(struct ns_id *ns) req.r.i.sdiag_protocol = IPPROTO_UDPLITE; req.r.i.idiag_ext = 0; req.r.i.idiag_states = -1; /* All */ - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, collect_err, ns, &req.r.i); if (tmp) err = tmp; @@ -829,33 +865,24 @@ int collect_sockets(struct ns_id *ns) req.r.i.sdiag_protocol = IPPROTO_RAW; req.r.i.idiag_ext = 0; req.r.i.idiag_states = -1; /* All */ - tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, ns, &req.r.i); - if (tmp) { - pr_warn("The current kernel doesn't support ipv6 raw_diag module\n"); - if (tmp != -ENOENT) - err = tmp; - } + tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, collect_err, ns, &req.r.i); + if (tmp) + err = tmp; req.r.p.sdiag_family = AF_PACKET; req.r.p.sdiag_protocol = 0; req.r.p.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MCLIST | PACKET_SHOW_FANOUT | PACKET_SHOW_RING_CFG; - tmp = do_collect_req(nl, &req, sizeof(req), packet_receive_one, ns, NULL); - if (tmp) { - pr_warn("The current kernel doesn't support packet_diag\n"); - if (ns->ns_pid == 0 || tmp != -ENOENT) /* Fedora 19 */ - err = tmp; - } + tmp = do_collect_req(nl, &req, sizeof(req), packet_receive_one, collect_err, ns, &req.r.p); + if (tmp) + err = tmp; req.r.n.sdiag_family = AF_NETLINK; req.r.n.sdiag_protocol = NDIAG_PROTO_ALL; req.r.n.ndiag_show = NDIAG_SHOW_GROUPS; - tmp = do_collect_req(nl, &req, sizeof(req), netlink_receive_one, ns, NULL); - if (tmp) { - pr_warn("The current kernel doesn't support netlink_diag\n"); - if (ns->ns_pid == 0 || tmp != -ENOENT) /* Fedora 19 */ - err = tmp; - } + tmp = do_collect_req(nl, &req, sizeof(req), netlink_receive_one, collect_err, ns, &req.r.n); + if (tmp) + err = tmp; /* don't need anymore */ close(nl); From 9120080fdc2b1ae26d5b3172121fdd65dfbd39f0 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 20 Dec 2018 11:08:39 +0300 Subject: [PATCH 1886/4375] net: libnetlink -- Drop ERROR keyword from default handler Lets just use regular pr_perror helper prefix without additional 'ERROR' keyword which may confuse external tools. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/libnetlink.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/criu/libnetlink.c b/criu/libnetlink.c index 60e98e346..ca9968309 100644 --- a/criu/libnetlink.c +++ b/criu/libnetlink.c @@ -45,10 +45,14 @@ static int nlmsg_receive(char *buf, int len, return 1; } +/* + * Default errror handler: just point our an error + * and pass up to caller. + */ static int rtnl_return_err(int err, struct ns_id *ns, void *arg) { errno = -err; - pr_perror("ERROR %d reported by netlink", err); + pr_perror("%d reported by netlink", err); return err; } From d1212cab55359b54a9f33d038f2c79165cb4c79e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 20 Dec 2018 11:08:40 +0300 Subject: [PATCH 1887/4375] sockets: Be more verbose in collect_err So we would always know what is happening even if module is nor compiled or supported. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sockets.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/criu/sockets.c b/criu/sockets.c index 48c71940d..6601774a9 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -731,13 +731,20 @@ static int collect_err(int err, struct ns_id *ns, void *arg) char family[32], proto[32]; char msg[256]; + snprintf(msg, sizeof(msg), + "Sockects collect procedure family %s proto %s", + socket_family_name(gr->family, family, sizeof(family)), + socket_proto_name(gr->protocol, proto, sizeof(proto))); + /* * If module is not compiled or unloaded, * we should simply pass error up to a caller * which then warn a user. */ - if (err == -ENOENT) + if (err == -ENOENT) { + pr_debug("%s: %d\n", msg, err); return -ENOENT; + } /* * Diag modules such as unix, packet, netlink @@ -746,23 +753,20 @@ static int collect_err(int err, struct ns_id *ns, void *arg) if (err == -EINVAL) { if (gr->family == AF_UNIX || gr->family == AF_PACKET || - gr->family == AF_NETLINK) + gr->family == AF_NETLINK) { + pr_debug("%s: %d\n", msg, err); return -EINVAL; + } } /* * Rest is more serious, just print enough information. * In case if everything is OK -- point as well. */ - snprintf(msg, sizeof(msg), - "Sockects collect procedure family %s proto %s\n", - socket_family_name(gr->family, family, sizeof(family)), - socket_proto_name(gr->protocol, proto, sizeof(proto))); - if (!err) pr_info("%s: OK\n", msg); else - pr_err("%s: %s\n", msg, strerror(-err)); + pr_err("%s: %d: %s\n", msg, err, strerror(-err)); return err; } From 4d4bf2477f1768e91c21c28c7f0b7d0bb7c9435e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 20 Dec 2018 11:08:41 +0300 Subject: [PATCH 1888/4375] sockets: Don't exit with error if raw module unloaded In regular checkpoint (not "check" action) current architecture implies that basic diag modules such as tcp/udp and etc will be loaded. In turn raw diag in most case is either unloaded or even not compiled in the system. Thus for them just zap an error (but print this information inside log). If an application does use raw sockets in real we will fail later when being checkpointing the sockets itselves. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sockets.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/criu/sockets.c b/criu/sockets.c index 6601774a9..30072ac73 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -743,6 +743,18 @@ static int collect_err(int err, struct ns_id *ns, void *arg) */ if (err == -ENOENT) { pr_debug("%s: %d\n", msg, err); + /* + * Unlike other modules RAW sockets are + * always optional and not commonly used. + * Currently we warn user about lack of + * a particular module support in "check" + * procedure. Thus don't fail on lack of + * RAW diags in a regular dump. If we meet + * a raw socket we will simply fail on dump + * procedure because it won't be resolved. + */ + if (gr->protocol == IPPROTO_RAW) + return 0; return -ENOENT; } From e1d68095724f74b0551d7aa2bc032613c8c2d33f Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 11 Dec 2018 10:11:25 +0300 Subject: [PATCH 1889/4375] files-reg: fixup order in message at link error path Error messages in linkat_hard and open_path about link errors contradict each other, fix the wrong one. Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 265efe071..df36f082a 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1623,8 +1623,8 @@ int open_path(struct file_desc *d, static char tmp_path[PATH_MAX]; if (errno != EEXIST) { - pr_perror("Can't link %s -> %s", rfi->path, - rfi->remap->rpath); + pr_perror("Can't link %s -> %s", + rfi->remap->rpath, rfi->path); return -1; } From 1ff233356405a0a17a44bdab357b5fb54c2fb32b Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 9 Jan 2019 13:11:12 +0000 Subject: [PATCH 1890/4375] Printout early log messages Up until now any pr_* logging command (except pr_msg) was lost if logging has not been set up (log_init()). To make sure not logging messages are lost, vprint_on_level() now writes all messages (except LOG_MSG) to a temporary buffer which is written to the logging FD once that is set up. Improved-by: Andrei Vagin Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/log.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/criu/log.c b/criu/log.c index a268ab8a4..060d1ee6e 100644 --- a/criu/log.c +++ b/criu/log.c @@ -31,11 +31,21 @@ /* Enable timestamps if verbosity is increased from default */ #define LOG_TIMESTAMP (DEFAULT_LOGLEVEL + 1) #define LOG_BUF_LEN (8*1024) +#define EARLY_LOG_BUF_LEN 1024 static unsigned int current_loglevel = DEFAULT_LOGLEVEL; static char buffer[LOG_BUF_LEN]; static char buf_off = 0; +/* + * The early_log_buffer is used to store log messages before + * logging is set up to make sure no logs are lost. + */ +static char early_log_buffer[EARLY_LOG_BUF_LEN]; +static unsigned int early_log_buf_off = 0; + +/* If this is 0 the logging has not been set up yet. */ +static int init_done = 0; static struct timeval start; /* @@ -155,6 +165,45 @@ static void print_versions(void) buf.release, buf.version, buf.machine); } +struct early_log_hdr { + uint16_t level; + uint16_t len; +}; + +static void flush_early_log_buffer(int fd) +{ + unsigned int pos = 0; + int ret; + + while (pos < early_log_buf_off) { + /* + * The early_log_buffer contains all messages written + * before logging was set up. We only want to print + * out messages which correspond to the requested + * log_level. Therefore the early_log_buffer also contains + * the log_level and the size. This writes one messages, + * depending on the log_level, to the logging fd. Start + * with reading the log_level. + */ + struct early_log_hdr *hdr = (void *)early_log_buffer + pos; + pos += sizeof(hdr); + if (hdr->level <= current_loglevel) { + size_t size = 0; + while (size < hdr->len) { + ret = write(fd, early_log_buffer + pos + size, + hdr->len - size); + if (ret <= 0) + break; + size += ret; + } + } + pos += hdr->len; + } + if (early_log_buf_off) + pr_warn("The early log isn't empty\n"); + early_log_buf_off = 0; +} + int log_init(const char *output) { int new_logfd, fd; @@ -186,6 +235,14 @@ int log_init(const char *output) if (fd < 0) goto err; + init_done = 1; + + /* + * Once logging is setup this write out all early log messages. + * Only those messages which have to correct log level are printed. + */ + flush_early_log_buffer(fd); + print_versions(); return 0; @@ -258,6 +315,41 @@ unsigned int log_get_loglevel(void) return current_loglevel; } +static void early_vprint(const char *format, unsigned int loglevel, va_list params) +{ + unsigned int log_size = 0; + struct early_log_hdr *hdr; + + if (early_log_buf_off >= EARLY_LOG_BUF_LEN) + return; + + /* Save loglevel */ + + hdr = (void *)early_log_buffer + early_log_buf_off; + hdr->level = loglevel; + /* Skip the log entry size */ + early_log_buf_off += sizeof(hdr); + if (loglevel >= LOG_TIMESTAMP) { + /* + * If logging is not yet setup we just write zeros + * instead of a real timestamp. This way we can + * keep the same format as the other messages on + * log levels with timestamps (>=LOG_TIMESTAMP). + */ + log_size = snprintf(early_log_buffer + early_log_buf_off, + sizeof(early_log_buffer) - early_log_buf_off, + "(00.000000) "); + } + + log_size += vsnprintf(early_log_buffer + early_log_buf_off + log_size, + sizeof(early_log_buffer) - early_log_buf_off - log_size, + format, params); + + /* Save log entry size */ + hdr->len = log_size; + early_log_buf_off += log_size; +} + void vprint_on_level(unsigned int loglevel, const char *format, va_list params) { int fd, size, ret, off = 0; @@ -267,6 +359,14 @@ void vprint_on_level(unsigned int loglevel, const char *format, va_list params) fd = STDOUT_FILENO; off = buf_off; /* skip dangling timestamp */ } else { + /* + * If logging has not yet been initialized (init_done == 0) + * make sure all messages are written to the early_log_buffer. + */ + if (!init_done) { + early_vprint(format, loglevel, params); + return; + } if (loglevel > current_loglevel) return; fd = log_get_fd(); @@ -284,6 +384,7 @@ void vprint_on_level(unsigned int loglevel, const char *format, va_list params) off += ret; } + /* This is missing for messages in the early_log_buffer. */ if (loglevel == LOG_ERROR) log_note_err(buffer + buf_off); From 7cd1cf0b167c872a1f831ee76413f03ca7ca3c8c Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 9 Jan 2019 09:56:50 +0300 Subject: [PATCH 1891/4375] test/socket-tcp-skip-in-flight: clean up the test by using the test library The test library has functions to create tcp sockets. Cc: Radostin Stoyanov Signed-off-by: Andrei Vagin Reviewed-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- test/zdtm/static/socket-tcp-skip-in-flight.c | 146 +++++-------------- 1 file changed, 36 insertions(+), 110 deletions(-) diff --git a/test/zdtm/static/socket-tcp-skip-in-flight.c b/test/zdtm/static/socket-tcp-skip-in-flight.c index eef73d992..8805e7d1a 100644 --- a/test/zdtm/static/socket-tcp-skip-in-flight.c +++ b/test/zdtm/static/socket-tcp-skip-in-flight.c @@ -16,138 +16,64 @@ const char *test_author = "Radostin Stoyanov "; * in-flight TCP connections are ignored. */ -#include -#include -#include #include #include -#include -#include -#include -#include -#define PORT 1234 -#define HOST "127.0.0.1" +#include +#include +#include -static int check_socket_state(int sk, int state) -{ - int err; - struct { - __u8 tcpi_state; - } info; - socklen_t len = sizeof(info); - - err = getsockopt(sk, IPPROTO_TCP, TCP_INFO, (void *)&info, &len); - if (err != 0) { - pr_perror("Can't get socket state\n"); - return -1; - } else if (info.tcpi_state != state) { - fail("Invalid socket state (%i)\n", (int)info.tcpi_state); - return -1; - } - - return 0; -} - -int open_socket() -{ - int fd; - fd = socket(ZDTM_FAMILY, SOCK_STREAM, 0); - if (fd < 0) { - fail("Failed to open socket\n"); - return -1; - } - return fd; -} - -int server() -{ - int fd_s; - struct sockaddr_in serv_addr; - - fd_s = open_socket(); - if (fd_s < 0) - return -1; - - bzero((char *) &serv_addr, sizeof(serv_addr)); - serv_addr.sin_family = ZDTM_FAMILY; - serv_addr.sin_addr.s_addr = INADDR_ANY; - serv_addr.sin_port = htons(PORT); - - if (bind(fd_s, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { - fail("Failed to bind"); - return -1; - } - - listen(fd_s, 1); - - /* Listen but do not accept connect()-ed TCP connection. */ - - return fd_s; -} - -int client() -{ - int fd_c; - struct sockaddr_in serv_addr; - struct hostent *server; - - fd_c = open_socket(); - if (fd_c < 0) - return -1; - - server = gethostbyname(HOST); - if (server == NULL) { - fail("Failed to get host by name\n"); - return -1; - } - - bzero((char *) &serv_addr, sizeof(serv_addr)); - serv_addr.sin_family = ZDTM_FAMILY; - bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); - serv_addr.sin_port = htons(PORT); - if (connect(fd_c,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { - fail("Failed to get host by name\n"); - return -1; - } - - return fd_c; -} int main(int argc, char **argv) { - int fd_s; - int fd_c; + int port = 9990; + int fd_s, fd_c, fd; + int flags; test_init(argc, argv); - fd_s = server(); - if (fd_s < 0) { - fail("Failed to initialize server\n"); + fd_s = tcp_init_server(ZDTM_FAMILY, &port); + if (fd_s < 0) + return -1; + + flags = fcntl(fd_s, F_GETFL, 0); + if (fcntl(fd_s, F_SETFL, flags | O_NONBLOCK)) { + pr_perror("Unable to set O_NONBLOCK"); return -1; } - fd_c = client(); - if (fd_c < 0) { - fail("Failed to initialize client\n"); + fd_c = tcp_init_client(ZDTM_FAMILY, "localhost", port); + if (fd_c < 0) return -1; - } - - if (check_socket_state(fd_s, TCP_LISTEN)) { - fail("Server socket state before restore isn't TCP_LISTEN\n"); - return 1; - } test_daemon(); test_waitsig(); - if (check_socket_state(fd_s, TCP_LISTEN)) { - fail("Server socket state after restore isn't TCP_LISTEN\n"); + if (close(fd_c)) { + fail("Unable to close a client socket"); return 1; } - close(fd_s); + fd = tcp_accept_server(fd_s); + if (fd >= 0) + close(fd); + + fd_c = tcp_init_client(ZDTM_FAMILY, "localhost", port); + if (fd_c < 0) { + fail("Unable to create a client socket"); + return -1; + } + + fd = tcp_accept_server(fd_s); + if (fd < 0) { + fail("Unable to accept a new connection"); + return 1; + } + + close(fd); + close(fd_c); + close(fd_s); pass(); return 0; From 7fd39f96ae842daf79a8fc728283ef11d57be262 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 11 Jan 2019 12:23:52 +0000 Subject: [PATCH 1892/4375] mount: Fix cleanup_mnt_ns() when opts.root is set In commit c1404f66712e7bacd7cbc7cef1bb85c7c6ad698f mount: restore cwd after creating a roots yard (v2) were introduced changes to the function cleanup_mnt_ns() that handle the case when opts.root is set. However, after commit 2e8970beda5bfb7d56fd3351ae57d8dd1c69b2c7 mount: create a mount point for the root mount namespace in the roots yard the cleanup_mnt_ns() function always results in error: mnt: Can't remove the directory ...: No such file or directory when restore fails and opts.root has been set. Resolves #467 Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/mount.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index f578c7b6a..696aed526 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -3263,13 +3263,10 @@ int depopulate_roots_yard(int mntns_fd, bool only_ghosts) void cleanup_mnt_ns(void) { - char path[PATH_MAX], *root = opts.root ? : "/"; - if (mnt_roots == NULL) return; - snprintf(path, sizeof(path), "%s/%s", root, mnt_roots); - if (rmdir(path)) + if (rmdir(mnt_roots)) pr_perror("Can't remove the directory %s", mnt_roots); } From 901f5d48ec6ef485ea889a4a97011a12f4c3808e Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Wed, 9 Jan 2019 12:49:11 +0000 Subject: [PATCH 1893/4375] Fix gcc9 build failures I received this patch from Jeff Law as a fix for build failures with the upcoming GCC 9. The following is Jeff Law's description of the patch: Attached you'll find the fix for criu. You'll see it's just a matter of dropping the sp/esp clobber from the relevant asm statements. THe details: criu has a macro which defines an asm which appears to want to set a new stack pointer, then directly issue a sigreturn call to the kernel. Some variants clobber sp (aarch64, arm, x86), others do not (ppc, s390) While the asm does indeed set a new stack pointer, we never return from a sigreturn syscall -- at least not in the normal way. We actually return back to the point where the process was interrupted by the signal. So describing the affect of the asm on the stack pointer is pedantically correct, it actually has no real effect and can just be dropped to avoid the hard error from gcc-9. Suggested-by: Jeff Law Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h | 2 +- compel/arch/arm/src/lib/include/uapi/asm/sigframe.h | 2 +- compel/arch/x86/src/lib/include/uapi/asm/sigframe.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h b/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h index 6b511ce0c..6b9317b04 100644 --- a/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h @@ -39,7 +39,7 @@ struct rt_sigframe { "svc #0 \n" \ : \ : "r"(new_sp) \ - : "sp", "x8", "memory") + : "x8", "memory") /* cr_sigcontext is copied from arch/arm64/include/uapi/asm/sigcontext.h */ struct cr_sigcontext { diff --git a/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h b/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h index 3e7bc0104..b90c0f659 100644 --- a/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h @@ -73,7 +73,7 @@ struct rt_sigframe { "svc #0 \n" \ : \ : "r"(new_sp) \ - : "sp","memory") + : "memory") #define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->sig.uc) #define RT_SIGFRAME_REGIP(rt_sigframe) (rt_sigframe)->sig.uc.uc_mcontext.arm_ip diff --git a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h index 0ad45a539..c29de3bd5 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h @@ -162,7 +162,7 @@ struct rt_sigframe { "syscall \n" \ : \ : "r"(new_sp) \ - : "rax","rsp","memory") + : "rax","memory") #define ARCH_RT_SIGRETURN_COMPAT(new_sp) \ asm volatile( \ "pushq $"__stringify(USER32_CS)" \n" \ @@ -176,7 +176,7 @@ struct rt_sigframe { ".code64 \n" \ : \ : "rdi"(new_sp) \ - : "eax","esp", "r8", "r9", "r10", "r11", "memory") + : "eax", "r8", "r9", "r10", "r11", "memory") #define ARCH_RT_SIGRETURN(new_sp, rt_sigframe) \ do { \ From 1be8269cd0633fddfd29cda40b59da4bd95b5b26 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 17 Jan 2019 20:33:04 +0000 Subject: [PATCH 1894/4375] Avoid unnecessary getpid() calls getsid(0) and getpgid(0) will return session ID and PGID of the calling process. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 4 ++-- test/zdtm/static/session00.c | 4 ++-- test/zdtm/static/session01.c | 12 ++++++------ test/zdtm/static/session03.c | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 95892161a..8d3b9eb1a 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1488,7 +1488,7 @@ static void restore_sid(void) exit(1); } } else { - sid = getsid(getpid()); + sid = getsid(0); if (sid != current->sid) { /* Skip the root task if it's not init */ if (current == root_item && vpid(root_item) != INIT_PID) @@ -1593,7 +1593,7 @@ static int create_children_and_session(void) if (!restore_before_setsid(child)) continue; - BUG_ON(child->born_sid != -1 && getsid(getpid()) != child->born_sid); + BUG_ON(child->born_sid != -1 && getsid(0) != child->born_sid); ret = fork_with_pid(child); if (ret < 0) diff --git a/test/zdtm/static/session00.c b/test/zdtm/static/session00.c index 5889a92b9..4a239e159 100644 --- a/test/zdtm/static/session00.c +++ b/test/zdtm/static/session00.c @@ -90,7 +90,7 @@ static int fork_child(int i) close(p[1]); wait(NULL); - if (getsid(getpid()) != sid) { + if (getsid(0) != sid) { fail("The process %d (%x) has SID=%d (expected %d)", pid, testcases[i].flags, sid, testcases[i].sid); exit(1); @@ -117,7 +117,7 @@ static int fork_child(int i) close(p[1]); wait(NULL); - if (getsid(getpid()) != sid) { + if (getsid(0) != sid) { fail("The process %d (%x) has SID=%d (expected %d)", pid, testcases[i].flags, sid, testcases[i].sid); exit(1); diff --git a/test/zdtm/static/session01.c b/test/zdtm/static/session01.c index 20c0d51cb..48cfb26de 100644 --- a/test/zdtm/static/session01.c +++ b/test/zdtm/static/session01.c @@ -102,14 +102,14 @@ static int child(const int c) goto err; if (t->pid == t->sid) { - if (getpid() != getsid(getpid())) + if (getpid() != getsid(0)) if (setsid() < 0) goto err; if (fork_children(t, 1)) goto err; } if (t->pid == t->pgid) { - if (getpid() != getpgid(getpid())) + if (getpid() != getpgid(0)) if (setpgid(getpid(), getpid()) < 0) { pr_perror("setpgid() failed"); goto err; @@ -129,7 +129,7 @@ static int child(const int c) break; if (t->pgid != testcases[i].pid) continue; - if (getpgid(getpid()) != testcases[i].master.pid) + if (getpgid(0) != testcases[i].master.pid) if (setpgid(getpid(), testcases[i].master.pid) < 0) { pr_perror("setpgid() failed (%d) (%d)", c, i); goto err; @@ -161,7 +161,7 @@ static int child(const int c) /* Save the master copy */ t->master.ppid = getppid(); - t->master.sid = getsid(getpid()); + t->master.sid = getsid(0); futex_set_and_wake(&t->futex, c); @@ -169,8 +169,8 @@ static int child(const int c) check("pid", t->master.pid, getpid()); check("ppid", t->master.ppid, getppid()); - check("sid", t->master.sid, getsid(getpid())); - check("pgid", t->master.pgid, getpgid(getpid())); + check("sid", t->master.sid, getsid(0)); + check("pgid", t->master.pgid, getpgid(0)); futex_set_and_wake(&t->futex, c); diff --git a/test/zdtm/static/session03.c b/test/zdtm/static/session03.c index 04fb83461..2b3c46c32 100644 --- a/test/zdtm/static/session03.c +++ b/test/zdtm/static/session03.c @@ -177,7 +177,7 @@ static void handle_command() } break; case TEST_SETSID: - if (getsid(getpid()) == getpid()) + if (getsid(0) == getpid()) break; test_msg("%3d: setsid()\n", current); if(setsid() == -1) { From 9c9f93272364d913cc61f713ffbae51ef9c0dceb Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 18 Jan 2019 00:43:14 +0000 Subject: [PATCH 1895/4375] pstree: Restore task group leader when inherit SID The current behaviour of CRIU is to inherit the group leader of the parent process when migrating a session leader (with --shell-job). However, it is possible for a process to be group leader without being a session leader (e.g. a shell process). In this case CRIU should restore the original group ID of the process and inherit only the session ID. Closes #593 Signed-off-by: Radostin Stoyanov Reviewed-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/pstree.c | 27 ++++++++++++++++++--------- criu/tty.c | 13 +++++++++---- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/criu/pstree.c b/criu/pstree.c index 695110c45..92b4167aa 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -367,22 +367,31 @@ static int prepare_pstree_for_shell_job(pid_t pid) */ old_sid = root_item->sid; - old_gid = root_item->pgid; - pr_info("Migrating process tree (GID %d->%d SID %d->%d)\n", - old_gid, current_gid, old_sid, current_sid); + pr_info("Migrating process tree (SID %d->%d)\n", + old_sid, current_sid); for_each_pstree_item(pi) { - if (pi->pgid == old_gid) - pi->pgid = current_gid; if (pi->sid == old_sid) pi->sid = current_sid; } - if (lookup_create_item(current_sid) == NULL) - return -1; - if (lookup_create_item(current_gid) == NULL) - return -1; + old_gid = root_item->pgid; + if (old_gid != vpid(root_item)) { + if (lookup_create_item(current_sid) == NULL) + return -1; + + pr_info("Migrating process tree (GID %d->%d)\n", + old_gid, current_gid); + + for_each_pstree_item(pi) { + if (pi->pgid == old_gid) + pi->pgid = current_gid; + } + + if (lookup_create_item(current_gid) == NULL) + return -1; + } return 0; } diff --git a/criu/tty.c b/criu/tty.c index 38e1cab33..5aaca633a 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -1068,10 +1068,15 @@ out: * the process which keeps the master peer. */ if (root_item->sid != vpid(root_item)) { - pr_debug("Restore inherited group %d\n", - getpgid(getppid())); - if (tty_set_prgp(fd, getpgid(getppid()))) - goto err; + if (root_item->pgid == vpid(root_item)) { + if (tty_set_prgp(fd, root_item->pgid)) + goto err; + } else { + pr_debug("Restore inherited group %d\n", + getpgid(getppid())); + if (tty_set_prgp(fd, getpgid(getppid()))) + goto err; + } } } From e08c7dc2bcb53515ef90d76ab0e643a1277fd7fc Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 17 Jan 2019 08:43:31 +0000 Subject: [PATCH 1896/4375] criu(8): Fix typos Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 4194f5b0c..d7ba16fb3 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -172,7 +172,7 @@ In other words, do not use it unless really needed. *--external* 'type'*[*'id'*]:*'value':: Dump an instance of an external resource. The generic syntax is 'type' of resource, followed by resource 'id' (enclosed in literal - square brackets), and optional 'value' (prepended by a literal semicolon). + square brackets), and optional 'value' (prepended by a literal colon). The following resource types are currently supported: *mnt*, *dev*, *file*, *tty*, *unix*. Syntax depends on type. Note to restore external resources, either *--external* or *--inherit-fd* @@ -186,7 +186,7 @@ In other words, do not use it unless really needed. Dump all external bind mounts, autodetecting those. Optional 'flags' can contain *m* to also dump external master mounts, *s* to also dump external shared mounts (default behavior is to abort dumping - if such mounts are found). If 'flags' are not provided, semicolon + if such mounts are found). If 'flags' are not provided, colon is optional. *--external dev[*'major'*/*'minor'*]:*'name':: @@ -379,7 +379,7 @@ usually need to be escaped from shell. *--external* 'type'*[*'id'*]:*'value':: Restore an instance of an external resource. The generic syntax is 'type' of resource, followed by resource 'id' (enclosed in literal - square brackets), and optional 'value' (prepended by a literal semicolon). + square brackets), and optional 'value' (prepended by a literal colon). The following resource types are currently supported: *mnt*, *dev*, *veth*, *macvlan*. Syntax depends on type. Note to restore external resources dealing with opened file descriptors (such as dumped with @@ -572,7 +572,7 @@ Launches *criu* in page server mode. *--lazy-pages*:: Serve local memory dump to a remote *lazy-pages* daemon. In this mode the *page-server* reads local memory dump and allows the - remote *lazy-pages* deamon to request memory pages in random + remote *lazy-pages* daemon to request memory pages in random order. *lazy-pages* @@ -582,7 +582,7 @@ Launches *criu* in lazy-pages daemon mode. The *lazy-pages* daemon is responsible for managing user-level demand paging for the restored processes. It gets information required to fill the process memory pages from the *restore* and from the -checkpont directory. When a restored process access certain memory +checkpoint directory. When a restored process access certain memory page for the first time, the *lazy-pages* daemon injects its contents into the process address space. The memory pages that are not yet requested by the restored processes are injected in the background. From e4fa84a32a75fea6c8e3d5d1d0d13f513e857dde Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 17 Jan 2019 08:43:32 +0000 Subject: [PATCH 1897/4375] criu(8): Move --log-pid under restore The --log-pid option was introduced with commit fc7bedc50ab4ca08b1c96764a5bd1acbc1889fa6 crtools: make to be able to split messages by pid This option is applicable only for restore. Therefore, move the documentation from "Common options" to "restore". Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index d7ba16fb3..80ce1124a 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -65,9 +65,6 @@ The following levels are available: *-o*, *--log-file* 'file':: Write logging messages to 'file'. -*--log-pid*:: - Write separate logging files per each pid. - *--display-stats*:: During dump as well as during restore *criu* collects information like the time required to dump or restore the process or the @@ -373,6 +370,9 @@ usually need to be escaped from shell. Restore root task as a sibling (makes sense only with *--restore-detached*). +*--log-pid*:: + Write separate logging files per each pid. + *-r*, *--root* 'path':: Change the root filesystem to 'path' (when run in a mount namespace). From b42b3e2ada305fbde3c1851ed59371ae78d16a34 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 17 Jan 2019 08:43:33 +0000 Subject: [PATCH 1898/4375] criu(8): Move --tcp-close under restore The --tcp-close option was introduced with commit 2c37042821906f013634e305899cb25ff1a5a7b1 tcp: Add tcp-close option to restore connected TCP sockets in closed state This options is applicable only for restore. Therefore, move the documentation from 'dump' to 'restore'. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 80ce1124a..0a024292d 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -268,9 +268,6 @@ For example, the command line for the above example should look like this: The TCP stack on the client side is expected to handle the re-connect gracefully. -*--tcp-close*:: - Restore connected TCP sockets in closed state. - *--evasive-devices*:: Use any path to a device file if the original one is inaccessible. @@ -439,6 +436,9 @@ The 'mode' may be one of the following: the network has been locked between *dump* and *restore* phases so other side of a connection simply notice a kind of lag. +*--tcp-close*:: + Restore connected TCP sockets in closed state. + *--veth-pair* 'IN'*=*'OUT':: Correspondence between outside and inside names of veth devices. From bd6f9672d25e9ee77323f4bd95f0f09d71826794 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 17 Jan 2019 08:43:34 +0000 Subject: [PATCH 1899/4375] criu(8): Document --lsm-profile The option --lsm-profile was added with commit: 6af96c8404181e63d2424d1695fd7f8a42a291bf lsm: add a --lsm-profile flag In LXD, we use the container name in the LSM profile. If the container name is changed on migrate (on the host side), we want to use a different LSM profile name (a. la. --cgroup-root). This flag adds that support. A usage example is available in https://github.com/lxc/lxc/commit/13389b2963692a51162c703d8a64a79542b18949 Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 4 ++++ criu/crtools.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 0a024292d..ea02613dd 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -445,6 +445,10 @@ The 'mode' may be one of the following: *-l*, *--file-locks*:: Restore file locks from the image. +*--lsm-profile* 'type'*:*'name':: + Specify an LSM profile to be used during restore. The `type` can be + either *apparmor* or *selinux*. + *--auto-dedup*:: As soon as a page is restored it get punched out from image. diff --git a/criu/crtools.c b/criu/crtools.c index c1431b46a..72243dba0 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -402,6 +402,9 @@ usage: " --cgroup-dump-controller NAME\n" " define cgroup controller to be dumped\n" " and skip anything else present in system\n" +" --lsm-profile TYPE:NAME\n" +" Specify an LSM profile to be used during restore.\n" +" The type can be either 'apparmor' or 'selinux'.\n" " --skip-mnt PATH ignore this mountpoint when dumping the mount namespace\n" " --enable-fs FSNAMES a comma separated list of filesystem names or \"all\"\n" " force criu to (try to) dump/restore these filesystem's\n" From d8cc6423b2c5a29184521d31b46edfeb8408b093 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 17 Jan 2019 08:43:35 +0000 Subject: [PATCH 1900/4375] crtools: Drop unused header "lsm.h" The header "lsm.h" was added in crtools.c with commit 6af96c8 and it became unused after commit 09c131c. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/crtools.c | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/crtools.c b/criu/crtools.c index 72243dba0..a0077e5ab 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -45,7 +45,6 @@ #include "cgroup.h" #include "cpu.h" #include "fault-injection.h" -#include "lsm.h" #include "proc_parse.h" #include "kerndat.h" From 306d1cd4bb28aa7433843494a6dc05ab410e6546 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 17 Jan 2019 08:43:36 +0000 Subject: [PATCH 1901/4375] cr-service: Fix typo Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/include/cr-service.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/include/cr-service.h b/criu/include/cr-service.h index a417a4c15..37cf7b60b 100644 --- a/criu/include/cr-service.h +++ b/criu/include/cr-service.h @@ -3,7 +3,7 @@ #include "images/rpc.pb-c.h" -extern int cr_service(bool deamon_mode); +extern int cr_service(bool daemon_mode); int cr_service_work(int sk); extern int send_criu_dump_resp(int socket_fd, bool success, bool restored); From adaad53b7411be876edc64d5919cddd4321ff444 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 16 Nov 2018 21:28:51 +0000 Subject: [PATCH 1902/4375] cr-restore: Remove unnecessay line Signed-off-by: Radostin Stoyanov Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 8d3b9eb1a..b8f973f4e 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -137,7 +137,6 @@ static inline int stage_participants(int next_stage) case CR_STATE_RESTORE: return task_entries->nr_threads + task_entries->nr_helpers; case CR_STATE_RESTORE_SIGCHLD: - return task_entries->nr_threads; case CR_STATE_RESTORE_CREDS: return task_entries->nr_threads; } From 7549e93a8d7792c6977dc93f7378b841dd8e6334 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 16 Nov 2018 21:28:52 +0000 Subject: [PATCH 1903/4375] files: Simplify get_mem_dev_ops Signed-off-by: Radostin Stoyanov Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/files.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/criu/files.c b/criu/files.c index 0f88912a4..31f847ee9 100644 --- a/criu/files.c +++ b/criu/files.c @@ -426,21 +426,14 @@ static const struct fdtype_ops *get_mem_dev_ops(struct fd_parms *p, int minor) { const struct fdtype_ops *ops = NULL; - switch (minor) { - case 11: - /* - * If /dev/kmsg is opened in write-only mode the file position - * should not be set up upon restore, kernel doesn't allow that. - */ - if ((p->flags & O_ACCMODE) == O_WRONLY && p->pos == 0) - p->pos = -1ULL; - /* - * Fallthrough. - */ - default: - ops = ®file_dump_ops; - break; - }; + /* + * If /dev/kmsg is opened in write-only mode the file position + * should not be set up upon restore, kernel doesn't allow that. + */ + if (minor == 11 && (p->flags & O_ACCMODE) == O_WRONLY && p->pos == 0) + p->pos = -1ULL; + + ops = ®file_dump_ops; return ops; } From dcf0c915e2d1bfea0562137cd2565f4418d1592c Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 16 Nov 2018 21:28:53 +0000 Subject: [PATCH 1904/4375] tty: Goto err when fail to unlock master pty Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/tty.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/criu/tty.c b/criu/tty.c index 5aaca633a..ad9574858 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -997,7 +997,8 @@ static int pty_open_unpaired_slave(struct file_desc *d, struct tty_info *slave) goto err; } - unlock_pty(master); + if (unlock_pty(master)) + goto err; if (opts.orphan_pts_master && rpc_send_fd(ACT_ORPHAN_PTS_MASTER, master) == 0) { @@ -1036,7 +1037,8 @@ static int pty_open_unpaired_slave(struct file_desc *d, struct tty_info *slave) goto err; } - unlock_pty(master); + if (unlock_pty(master)) + goto err; fd = open_tty_reg(slave->reg_d, slave->tfe->flags); if (fd < 0) { @@ -1103,7 +1105,8 @@ static int pty_open_ptmx(struct tty_info *info) return -1; } - unlock_pty(master); + if (unlock_pty(master)) + goto err; if (restore_tty_params(master, info)) goto err; From 844a72371a044c1cdea8fac1f8881e7109c600c7 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 6 Jan 2019 15:44:26 +0000 Subject: [PATCH 1905/4375] rpc: Add interface for --tcp-close option Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/cr-service.c | 3 +++ images/rpc.proto | 1 + lib/c/criu.c | 11 +++++++++++ lib/c/criu.h | 2 ++ 4 files changed, 17 insertions(+) diff --git a/criu/cr-service.c b/criu/cr-service.c index 532a87c81..37cc6f7df 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -437,6 +437,9 @@ static int setup_opts_from_req(int sk, CriuOpts *req) if (req->has_tcp_skip_in_flight) opts.tcp_skip_in_flight = req->tcp_skip_in_flight; + if (req->has_tcp_close) + opts.tcp_close = req->tcp_close; + if (req->has_weak_sysctls) opts.weak_sysctls = req->weak_sysctls; diff --git a/images/rpc.proto b/images/rpc.proto index abf2f5d79..5c8226d25 100644 --- a/images/rpc.proto +++ b/images/rpc.proto @@ -112,6 +112,7 @@ message criu_opts { optional int32 status_fd = 49; optional bool orphan_pts_master = 50; optional string config_file = 51; + optional bool tcp_close = 52; } message criu_dump_resp { diff --git a/lib/c/criu.c b/lib/c/criu.c index ff9c9b87e..b70da4d81 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -321,6 +321,17 @@ void criu_set_tcp_skip_in_flight(bool tcp_skip_in_flight) criu_local_set_tcp_skip_in_flight(global_opts, tcp_skip_in_flight); } +void criu_local_set_tcp_close(criu_opts *opts, bool tcp_close) +{ + opts->rpc->has_tcp_close = true; + opts->rpc->tcp_close = tcp_close; +} + +void criu_set_tcp_close(bool tcp_close) +{ + criu_local_set_tcp_close(global_opts, tcp_close); +} + void criu_local_set_weak_sysctls(criu_opts *opts, bool val) { opts->rpc->has_weak_sysctls = true; diff --git a/lib/c/criu.h b/lib/c/criu.h index ae8683bc9..672246526 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -66,6 +66,7 @@ void criu_set_ext_unix_sk(bool ext_unix_sk); int criu_add_unix_sk(unsigned int inode); void criu_set_tcp_established(bool tcp_established); void criu_set_tcp_skip_in_flight(bool tcp_skip_in_flight); +void criu_set_tcp_close(bool tcp_close); void criu_set_weak_sysctls(bool val); void criu_set_evasive_devices(bool evasive_devices); void criu_set_shell_job(bool shell_job); @@ -175,6 +176,7 @@ void criu_local_set_ext_unix_sk(criu_opts *opts, bool ext_unix_sk); int criu_local_add_unix_sk(criu_opts *opts, unsigned int inode); void criu_local_set_tcp_established(criu_opts *opts, bool tcp_established); void criu_local_set_tcp_skip_in_flight(criu_opts *opts, bool tcp_skip_in_flight); +void criu_local_set_tcp_close(criu_opts *opts, bool tcp_close); void criu_local_set_weak_sysctls(criu_opts *opts, bool val); void criu_local_set_evasive_devices(criu_opts *opts, bool evasive_devices); void criu_local_set_shell_job(criu_opts *opts, bool shell_job); From e18a6d830a52b796708779b8ae8b1e8fd0d97ff6 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 6 Jan 2019 15:44:27 +0000 Subject: [PATCH 1906/4375] config: Add check_options helper The purpose of this helper function is to perform actions common to different interfaces, after all CRIU options have been parsed. This can be used, for instance, to verify that a specific option was passed to CRIU via CLI, RPC or config file. Signed-off-by: Radostin Stoyanov Acked-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/config.c | 33 +++++++++++++++++++++++++++++++++ criu/cr-service.c | 5 +++-- criu/crtools.c | 25 +------------------------ criu/include/cr_options.h | 1 + 4 files changed, 38 insertions(+), 26 deletions(-) diff --git a/criu/config.c b/criu/config.c index 089a70038..89cc17620 100644 --- a/criu/config.c +++ b/criu/config.c @@ -802,3 +802,36 @@ bad_arg: long_opts[idx].name, optarg); return 1; } + +int check_options() +{ + if (opts.tcp_established_ok) + pr_info("Will dump/restore TCP connections\n"); + if (opts.tcp_skip_in_flight) + pr_info("Will skip in-flight TCP connections\n"); + if (opts.tcp_close) + pr_info("Will drop all TCP connections on restore\n"); + if (opts.link_remap_ok) + pr_info("Will allow link remaps on FS\n"); + if (opts.weak_sysctls) + pr_info("Will skip non-existant sysctls on restore\n"); + + if (opts.deprecated_ok) + pr_info("Turn deprecated stuff ON\n"); + else if (getenv("CRIU_DEPRECATED")) { + pr_info("Turn deprecated stuff ON via env\n"); + opts.deprecated_ok = true; + } + + if (!opts.restore_detach && opts.restore_sibling) { + pr_err("--restore-sibling only makes sense with --restore-detach\n"); + return 1; + } + + if (check_namespace_opts()) { + pr_err("Error: namespace flags conflict\n"); + return 1; + } + + return 0; +} diff --git a/criu/cr-service.c b/criu/cr-service.c index 37cc6f7df..231a37f30 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -639,8 +639,6 @@ static int setup_opts_from_req(int sk, CriuOpts *req) if (req->orphan_pts_master) opts.orphan_pts_master = true; - if (check_namespace_opts()) - goto err; /* Evaluate additional configuration file a second time to overwrite * all RPC settings. */ @@ -650,7 +648,10 @@ static int setup_opts_from_req(int sk, CriuOpts *req) if (i) goto err; } + log_set_loglevel(opts.log_level); + if (check_options()) + goto err; return 0; diff --git a/criu/crtools.c b/criu/crtools.c index a0077e5ab..0a1483b06 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -110,31 +110,8 @@ int main(int argc, char *argv[], char *envp[]) return cr_service_work(atoi(argv[2])); } - if (opts.deprecated_ok) - pr_msg("Turn deprecated stuff ON\n"); - if (opts.tcp_skip_in_flight) - pr_msg("Will skip in-flight TCP connections\n"); - if (opts.tcp_established_ok) - pr_info("Will dump TCP connections\n"); - if (opts.link_remap_ok) - pr_info("Will allow link remaps on FS\n"); - if (opts.weak_sysctls) - pr_msg("Will skip non-existant sysctls on restore\n"); - - if (getenv("CRIU_DEPRECATED")) { - pr_msg("Turn deprecated stuff ON via env\n"); - opts.deprecated_ok = true; - } - - if (check_namespace_opts()) { - pr_msg("Error: namespace flags conflict\n"); + if (check_options()) return 1; - } - - if (!opts.restore_detach && opts.restore_sibling) { - pr_msg("--restore-sibling only makes sense with --restore-detach\n"); - return 1; - } if (opts.imgs_dir == NULL) SET_CHAR_OPTS(imgs_dir, "."); diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index c722e3ae2..9f152fac0 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -144,6 +144,7 @@ extern struct cr_options opts; char *rpc_cfg_file; extern int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd, int state); +extern int check_options(); extern void init_opts(); #endif /* __CR_OPTIONS_H__ */ From 6b84657ca4c37bff67bcd9201724ebdb69c45848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20W=C3=BChrer?= Date: Sat, 19 Jan 2019 11:49:17 +0100 Subject: [PATCH 1907/4375] c-lib: fixed memleaks, add criu_local_free_opts() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If `criu_local_init_opts()` is applied on the same opts-object several times, not all of the allocated memory gets freed. Therefore, the functions `criu_(local_)free_opts()` were introduced. These functions ensure, that opts get freed accordingly. Furthermore, `criu_(local_)free_opts()` gets part of the c-api, and can therefore be called by external projects too. Additionally, with this commit `criu_local_init_opts()` now uses `criu_local_free_opts()`, to free the opts-parameter if it was already initalized before. This commit also contains a fix in `send_req_and_recv_resp_sk()` which lead to a memory leak, if criu-notifications were received. Signed-off-by: Martin Wührer Signed-off-by: Andrei Vagin --- lib/c/criu.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++---- lib/c/criu.h | 2 + 2 files changed, 136 insertions(+), 9 deletions(-) diff --git a/lib/c/criu.c b/lib/c/criu.c index b70da4d81..11dc6e846 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -81,6 +81,128 @@ void criu_set_service_binary(const char *path) criu_local_set_service_binary(global_opts, path); } +void criu_local_free_opts(criu_opts *opts) +{ + int i; + + if (!opts) + return; + if (!opts->rpc) + return; + + if (opts->rpc->exec_cmd) { + for (i = 0; i < opts->rpc->n_exec_cmd; i++) { + free(opts->rpc->exec_cmd[i]); + } + free(opts->rpc->exec_cmd); + } + opts->rpc->n_exec_cmd = 0; + + if(opts->rpc->unix_sk_ino) { + for (i = 0; i < opts->rpc->n_unix_sk_ino; i++) { + free(opts->rpc->unix_sk_ino[i]); + } + free(opts->rpc->unix_sk_ino); + } + opts->rpc->n_unix_sk_ino = 0; + + if(opts->rpc->ext_mnt) { + for (i = 0; i < opts->rpc->n_ext_mnt; i++) { + if (opts->rpc->ext_mnt[i]) { + free(opts->rpc->ext_mnt[i]->val); + free(opts->rpc->ext_mnt[i]->key); + free(opts->rpc->ext_mnt[i]); + } + } + free(opts->rpc->ext_mnt); + } + opts->rpc->n_ext_mnt = 0; + + if(opts->rpc->cg_root) { + for (i = 0; i < opts->rpc->n_cg_root; i++) { + if (opts->rpc->cg_root[i]) { + free(opts->rpc->cg_root[i]->ctrl); + free(opts->rpc->cg_root[i]->path); + free(opts->rpc->cg_root[i]); + } + } + free(opts->rpc->cg_root); + } + opts->rpc->n_cg_root = 0; + + if(opts->rpc->veths) { + for (i = 0; i < opts->rpc->n_veths; i++) { + if (opts->rpc->veths[i]) { + free(opts->rpc->veths[i]->if_in); + free(opts->rpc->veths[i]->if_out); + free(opts->rpc->veths[i]); + } + } + free(opts->rpc->veths); + } + opts->rpc->n_veths = 0; + + if(opts->rpc->enable_fs) { + for (i = 0; i < opts->rpc->n_enable_fs; i++) { + free(opts->rpc->enable_fs[i]); + } + free(opts->rpc->enable_fs); + } + opts->rpc->n_enable_fs = 0; + + if(opts->rpc->skip_mnt) { + for (i = 0; i < opts->rpc->n_skip_mnt; i++) { + free(opts->rpc->skip_mnt[i]); + } + free(opts->rpc->skip_mnt); + } + opts->rpc->n_skip_mnt = 0; + + if(opts->rpc->irmap_scan_paths) { + for (i = 0; i < opts->rpc->n_irmap_scan_paths; i++) { + free(opts->rpc->irmap_scan_paths[i]); + } + free(opts->rpc->irmap_scan_paths); + } + opts->rpc->n_irmap_scan_paths = 0; + + if(opts->rpc->cgroup_dump_controller) { + for (i = 0; i < opts->rpc->n_cgroup_dump_controller; i++) { + free(opts->rpc->cgroup_dump_controller[i]); + } + free(opts->rpc->cgroup_dump_controller); + } + opts->rpc->n_cgroup_dump_controller = 0; + + if(opts->rpc->inherit_fd) { + for (i = 0; i < opts->rpc->n_inherit_fd; i++) { + if (opts->rpc->inherit_fd[i]) { + free(opts->rpc->inherit_fd[i]->key); + free(opts->rpc->inherit_fd[i]); + } + } + free(opts->rpc->inherit_fd); + } + opts->rpc->n_inherit_fd = 0; + + if(opts->rpc->external) { + for (i = 0; i < opts->rpc->n_external; i++) { + free(opts->rpc->external[i]); + } + free(opts->rpc->external); + } + opts->rpc->n_external = 0; + + free(opts->rpc->cgroup_props_file); + free(opts->rpc->cgroup_props); + free(opts->rpc->parent_img); + free(opts->rpc->root); + free(opts->rpc->freeze_cgroup); + free(opts->rpc->log_file); + free(opts->rpc); + free(opts); +} + int criu_local_init_opts(criu_opts **o) { criu_opts *opts = NULL; @@ -88,13 +210,8 @@ int criu_local_init_opts(criu_opts **o) opts = *o; - if (opts) { - if (opts->rpc) - criu_opts__free_unpacked(opts->rpc, NULL); - - free(opts); - opts = NULL; - } + criu_local_free_opts(opts); + *o = NULL; rpc = malloc(sizeof(CriuOpts)); if (rpc == NULL) { @@ -107,7 +224,7 @@ int criu_local_init_opts(criu_opts **o) opts = malloc(sizeof(criu_opts)); if (opts == NULL) { perror("Can't allocate memory for criu opts"); - criu_opts__free_unpacked(rpc, NULL); + criu_local_free_opts(opts); return -1; } @@ -127,6 +244,12 @@ int criu_init_opts(void) return criu_local_init_opts(&global_opts); } +void criu_free_opts(void) +{ + criu_local_free_opts(global_opts); + global_opts = NULL; +} + void criu_local_set_notify_cb(criu_opts *opts, int (*cb)(char *action, criu_notify_arg_t na)) { opts->notify = cb; @@ -1134,8 +1257,10 @@ again: ret = opts->notify((*resp)->notify->script, (*resp)->notify); ret = send_notify_ack(fd, ret); - if (!ret) + if (!ret) { + criu_resp__free_unpacked(*resp, NULL); goto again; + } else goto exit; } diff --git a/lib/c/criu.h b/lib/c/criu.h index 672246526..8acd342ab 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -56,6 +56,7 @@ void criu_set_service_comm(enum criu_service_comm); * the list down below. 0 on success, -1 on fail. */ int criu_init_opts(void); +void criu_free_opts(void); void criu_set_pid(int pid); void criu_set_images_dir_fd(int fd); /* must be set for dump/restore */ @@ -159,6 +160,7 @@ int criu_dump_iters(int (*more)(criu_predump_info pi)); typedef struct criu_opts criu_opts; int criu_local_init_opts(criu_opts **opts); +void criu_local_free_opts(criu_opts *opts); void criu_local_set_service_address(criu_opts *opts, char *path); void criu_local_set_service_fd(criu_opts *opts, int fd); From f07bd47fde59ebd14b1a830907c5259532fa5e3f Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 23 Jan 2019 12:02:19 -0800 Subject: [PATCH 1908/4375] images/Makefile: fix dep gen Since this part is inside "define" statement, double $ should be used to refer to internal functions, to call the patsubst when a define is called (rather than defined). This should fix dependency generation for images/ Reviewed-by: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- images/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/Makefile b/images/Makefile index 276f1fcf7..edaab0633 100644 --- a/images/Makefile +++ b/images/Makefile @@ -92,7 +92,7 @@ ifeq ($(PROTOUFIX),y) endif $(obj)/$(1).pb-c.d: $(obj)/$(1).pb-c.c $(addsuffix .pb-c.d,$(addprefix $(obj)/,$(2))) $(makefile-deps) $$(E) " DEP " $$@ - $$(Q) $$(CC) -M -MT $$@ -MT $(patsubst %.d,%.o,$$@) $$(CFLAGS) $$< -o $$@ + $$(Q) $$(CC) -M -MT $$@ -MT $$(patsubst %.d,%.o,$$@) $$(CFLAGS) $$< -o $$@ endef $(foreach file, $(proto-obj-y), \ From 6fe7e9eab41484330b23e7cdc98bcbda84cfab3f Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 23 Jan 2019 12:02:20 -0800 Subject: [PATCH 1909/4375] Makefile.config: don't silent twice Here $(Q) is substituted with either @ or nothing, depending on whether V is set, to either have verbose output or not. So, it does not make sense to add another @. Reviewed-by: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- Makefile.config | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Makefile.config b/Makefile.config index d89ccbb1a..a853705b3 100644 --- a/Makefile.config +++ b/Makefile.config @@ -44,24 +44,24 @@ FEATURES_LIST := TCP_REPAIR STRLCPY STRLCAT PTRACE_PEEKSIGINFO \ # $1 - config name define gen-feature-test ifeq ($$(call try-cc,$$(FEATURE_TEST_$(1)),$$(LIBS_FEATURES),$$(DEFINES)),true) - $(Q) @echo '#define CONFIG_HAS_$(1)' >> $$@ - $(Q) @echo '' >> $$@ + $(Q) echo '#define CONFIG_HAS_$(1)' >> $$@ + $(Q) echo '' >> $$@ endif endef define config-header-rule $(CONFIG_HEADER): scripts/feature-tests.mak $(CONFIG_FILE) - $$(call msg-gen, $$@) - $(Q) @echo '#ifndef __CR_CONFIG_H__' > $$@ - $(Q) @echo '#define __CR_CONFIG_H__' >> $$@ - $(Q) @echo '' >> $$@ + $(call msg-gen, $$@) + $(Q) echo '#ifndef __CR_CONFIG_H__' > $$@ + $(Q) echo '#define __CR_CONFIG_H__' >> $$@ + $(Q) echo '' >> $$@ $(call map,gen-feature-test,$(FEATURES_LIST)) - $(Q) @cat $(CONFIG_FILE) | sed -n -e '/^[^#]/s/^/#define CONFIG_/p' >> $$@ + $(Q) cat $(CONFIG_FILE) | sed -n -e '/^[^#]/s/^/#define CONFIG_/p' >> $$@ ifeq ($$(VDSO),y) - $(Q) @echo '#define CONFIG_VDSO' >> $$@ - $(Q) @echo '' >> $$@ + $(Q) echo '#define CONFIG_VDSO' >> $$@ + $(Q) echo '' >> $$@ endif - $(Q) @echo '#endif /* __CR_CONFIG_H__ */' >> $$@ + $(Q) echo '#endif /* __CR_CONFIG_H__ */' >> $$@ endef $(eval $(config-header-rule)) From b368e66165ab35f0ecffad44ffe4abf2193802ba Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 23 Jan 2019 12:02:21 -0800 Subject: [PATCH 1910/4375] test/others/libcriu/Makefile: fix phony targets Add run as a phony target. Move .PHONY declarations next to their targets. Reviewed-by: Cyrill Gorcunov Signed-off-by: Kir Kolyshkin Signed-off-by: Andrei Vagin --- test/others/libcriu/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/others/libcriu/Makefile b/test/others/libcriu/Makefile index d828f7e12..5289ed15a 100644 --- a/test/others/libcriu/Makefile +++ b/test/others/libcriu/Makefile @@ -5,9 +5,11 @@ TESTS += test_iters TESTS += test_errno all: $(TESTS) +.PHONY: all run: all ./run.sh +.PHONY: run define genb $(1): $(1).o lib.o @@ -21,6 +23,4 @@ $(foreach t, $(TESTS), $(eval $(call genb, $(t)))) clean: rm -rf $(TESTS) $(TESTS:%=%.o) lib.o - .PHONY: clean -.PHONY: all From f4ce0a7c08263adc81f78e1b447adca83297d4fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20W=C3=BChrer?= Date: Wed, 30 Jan 2019 10:34:45 +0100 Subject: [PATCH 1911/4375] c-lib: added set_page_server_address_port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to https://criu.org/API_compliance, the C-library doesn't support the pageserver option. This patch contains the functions `criu_(local_)set_page_server_address_port()` that allow to specify on which ip and tcp-port the pageserver is listening. This patch affects only the c-lib, as criu-rpc already supports the pageserver settings. Signed-off-by: Martin Wührer Signed-off-by: Andrei Vagin --- lib/c/criu.c | 31 +++++++++++++++++++++++++++++++ lib/c/criu.h | 2 ++ 2 files changed, 33 insertions(+) diff --git a/lib/c/criu.c b/lib/c/criu.c index 11dc6e846..6d299835d 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -193,6 +193,11 @@ void criu_local_free_opts(criu_opts *opts) } opts->rpc->n_external = 0; + if(opts->rpc->ps) { + free(opts->rpc->ps->address); + free(opts->rpc->ps); + } + free(opts->rpc->cgroup_props_file); free(opts->rpc->cgroup_props); free(opts->rpc->parent_img); @@ -1018,6 +1023,32 @@ int criu_add_external(char *key) return criu_local_add_external(global_opts, key); } +int criu_local_set_page_server_address_port(criu_opts *opts, const char *address, int port) +{ + opts->rpc->ps = malloc(sizeof(CriuPageServerInfo)); + if (opts->rpc->ps) { + criu_page_server_info__init(opts->rpc->ps); + + opts->rpc->ps->address = strdup(address); + if (!opts->rpc->ps->address) { + free(opts->rpc->ps); + opts->rpc->ps = NULL; + goto out; + } + + opts->rpc->ps->has_port = true; + opts->rpc->ps->port = port; + } + +out: + return -ENOMEM; +} + +int criu_set_page_server_address_port(const char *address, int port) +{ + return criu_local_set_page_server_address_port(global_opts, address, port); +} + static CriuResp *recv_resp(int socket_fd) { unsigned char *buf = NULL; diff --git a/lib/c/criu.h b/lib/c/criu.h index 8acd342ab..ceb303538 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -97,6 +97,7 @@ void criu_set_ghost_limit(unsigned int limit); int criu_add_irmap_path(char *path); int criu_add_inherit_fd(int fd, char *key); int criu_add_external(char *key); +int criu_set_page_server_address_port(const char *address, int port); /* * The criu_notify_arg_t na argument is an opaque @@ -211,6 +212,7 @@ int criu_local_add_cg_props_file(criu_opts *opts, char *path); int criu_local_add_cg_dump_controller(criu_opts *opts, char *name); int criu_local_add_inherit_fd(criu_opts *opts, int fd, char *key); int criu_local_add_external(criu_opts *opts, char *key); +int criu_local_set_page_server_address_port(criu_opts *opts, const char *address, int port); void criu_local_set_notify_cb(criu_opts *opts, int (*cb)(char *action, criu_notify_arg_t na)); From 7d7f663be5c93318cd101876246a02b5b870dd86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20W=C3=BChrer?= Date: Fri, 21 Dec 2018 08:00:21 +0100 Subject: [PATCH 1912/4375] c-lib: converted `char *`-args to `const char *` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As most of the `criu_(local_)*` functions already call `strdup()`, it is possible, to change the function signature to `const char *`. As the struct `criu_opts` already contains a `const char * service_binary`, also the member `service_address` is changed to `const char`. Additonally, also the function `criu_local_set_freeze_cgroup()` now calls `strdup()`. Signed-off-by: Martin Wührer Signed-off-by: Andrei Vagin --- lib/c/criu.c | 64 ++++++++++++++++++++++++++-------------------------- lib/c/criu.h | 58 +++++++++++++++++++++++------------------------ 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/lib/c/criu.c b/lib/c/criu.c index 6d299835d..31692c781 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -25,7 +25,7 @@ struct criu_opts { int (*notify)(char *action, criu_notify_arg_t na); enum criu_service_comm service_comm; union { - char *service_address; + const char *service_address; int service_fd; const char *service_binary; }; @@ -45,7 +45,7 @@ void criu_set_service_comm(enum criu_service_comm comm) criu_local_set_service_comm(global_opts, comm); } -void criu_local_set_service_address(criu_opts *opts, char *path) +void criu_local_set_service_address(criu_opts *opts, const char *path) { if (path) opts->service_address = path; @@ -53,7 +53,7 @@ void criu_local_set_service_address(criu_opts *opts, char *path) opts->service_address = CR_DEFAULT_SERVICE_ADDRESS; } -void criu_set_service_address(char *path) +void criu_set_service_address(const char *path) { criu_local_set_service_address(global_opts, path); } @@ -293,12 +293,12 @@ void criu_set_images_dir_fd(int fd) criu_local_set_images_dir_fd(global_opts, fd); } -void criu_local_set_parent_images(criu_opts *opts, char *path) +void criu_local_set_parent_images(criu_opts *opts, const char *path) { opts->rpc->parent_img = strdup(path); } -void criu_set_parent_images(char *path) +void criu_set_parent_images(const char *path) { criu_local_set_parent_images(global_opts, path); } @@ -515,12 +515,12 @@ void criu_set_log_level(int log_level) criu_local_set_log_level(global_opts, log_level); } -void criu_local_set_root(criu_opts *opts, char *root) +void criu_local_set_root(criu_opts *opts, const char *root) { opts->rpc->root = strdup(root); } -void criu_set_root(char *root) +void criu_set_root(const char *root) { criu_local_set_root(global_opts, root); } @@ -547,12 +547,12 @@ void criu_set_manage_cgroups_mode(enum criu_cg_mode mode) criu_local_set_manage_cgroups_mode(global_opts, mode); } -void criu_local_set_freeze_cgroup(criu_opts *opts, char *name) +void criu_local_set_freeze_cgroup(criu_opts *opts, const char *name) { - opts->rpc->freeze_cgroup = name; + opts->rpc->freeze_cgroup = strdup(name); } -void criu_set_freeze_cgroup(char *name) +void criu_set_freeze_cgroup(const char *name) { criu_local_set_freeze_cgroup(global_opts, name); } @@ -600,12 +600,12 @@ void criu_set_ext_masters(bool val) criu_local_set_ext_masters(global_opts, val); } -void criu_local_set_log_file(criu_opts *opts, char *log_file) +void criu_local_set_log_file(criu_opts *opts, const char *log_file) { opts->rpc->log_file = strdup(log_file); } -void criu_set_log_file(char *log_file) +void criu_set_log_file(const char *log_file) { criu_local_set_log_file(global_opts, log_file); } @@ -652,7 +652,7 @@ int criu_set_exec_cmd(int argc, char *argv[]) return criu_local_set_exec_cmd(global_opts, argc, argv); } -int criu_local_add_ext_mount(criu_opts *opts, char *key, char *val) +int criu_local_add_ext_mount(criu_opts *opts, const char *key, const char *val) { int nr; ExtMountMap **a, *m; @@ -689,12 +689,12 @@ er: return -ENOMEM; } -int criu_add_ext_mount(char *key, char *val) +int criu_add_ext_mount(const char *key, const char *val) { return criu_local_add_ext_mount(global_opts, key, val); } -int criu_local_add_cg_root(criu_opts *opts, char *ctrl, char *path) +int criu_local_add_cg_root(criu_opts *opts, const char *ctrl, const char *path) { int nr; CgroupRoot **a, *root; @@ -735,12 +735,12 @@ er: return -ENOMEM; } -int criu_add_cg_root(char *ctrl, char *path) +int criu_add_cg_root(const char *ctrl, const char *path) { return criu_local_add_cg_root(global_opts, ctrl, path); } -int criu_local_add_veth_pair(criu_opts *opts, char *in, char *out) +int criu_local_add_veth_pair(criu_opts *opts, const char *in, const char *out) { int nr; CriuVethPair **a, *p; @@ -777,12 +777,12 @@ er: return -ENOMEM; } -int criu_add_veth_pair(char *in, char *out) +int criu_add_veth_pair(const char *in, const char *out) { return criu_local_add_veth_pair(global_opts, in, out); } -int criu_local_add_enable_fs(criu_opts *opts, char *fs) +int criu_local_add_enable_fs(criu_opts *opts, const char *fs) { int nr; char *str = NULL; @@ -813,13 +813,13 @@ err: return -ENOMEM; } -int criu_add_enable_fs(char *fs) +int criu_add_enable_fs(const char *fs) { return criu_local_add_enable_fs(global_opts, fs); } -int criu_local_add_skip_mnt(criu_opts *opts, char *mnt) +int criu_local_add_skip_mnt(criu_opts *opts, const char *mnt) { int nr; char *str = NULL; @@ -850,7 +850,7 @@ err: return -ENOMEM; } -int criu_local_add_irmap_path(criu_opts *opts, char *path) +int criu_local_add_irmap_path(criu_opts *opts, const char *path) { int nr; char *my_path; @@ -882,7 +882,7 @@ err: return -ENOMEM; } -int criu_local_add_cg_props(criu_opts *opts, char *stream) +int criu_local_add_cg_props(criu_opts *opts, const char *stream) { char *new; @@ -895,7 +895,7 @@ int criu_local_add_cg_props(criu_opts *opts, char *stream) return 0; } -int criu_local_add_cg_props_file(criu_opts *opts, char *path) +int criu_local_add_cg_props_file(criu_opts *opts, const char *path) { char *new; @@ -908,7 +908,7 @@ int criu_local_add_cg_props_file(criu_opts *opts, char *path) return 0; } -int criu_local_add_cg_dump_controller(criu_opts *opts, char *name) +int criu_local_add_cg_dump_controller(criu_opts *opts, const char *name) { char **new, *ctrl_name; size_t nr; @@ -932,7 +932,7 @@ int criu_local_add_cg_dump_controller(criu_opts *opts, char *name) return 0; } -int criu_add_skip_mnt(char *mnt) +int criu_add_skip_mnt(const char *mnt) { return criu_local_add_skip_mnt(global_opts, mnt); } @@ -948,12 +948,12 @@ void criu_set_ghost_limit(unsigned int limit) criu_local_set_ghost_limit(global_opts, limit); } -int criu_add_irmap_path(char *path) +int criu_add_irmap_path(const char *path) { return criu_local_add_irmap_path(global_opts, path); } -int criu_local_add_inherit_fd(criu_opts *opts, int fd, char *key) +int criu_local_add_inherit_fd(criu_opts *opts, int fd, const char *key) { int nr; InheritFd **a, *f; @@ -989,12 +989,12 @@ er: return -ENOMEM; } -int criu_add_inherit_fd(int fd, char *key) +int criu_add_inherit_fd(int fd, const char *key) { return criu_local_add_inherit_fd(global_opts, fd, key); } -int criu_local_add_external(criu_opts *opts, char *key) +int criu_local_add_external(criu_opts *opts, const char *key) { int nr; char **a, *e = NULL; @@ -1018,7 +1018,7 @@ err: return -ENOMEM; } -int criu_add_external(char *key) +int criu_add_external(const char *key) { return criu_local_add_external(global_opts, key); } @@ -1516,7 +1516,7 @@ int criu_local_restore_child(criu_opts *opts) { int sk, ret = -1; enum criu_service_comm saved_comm; - char *saved_comm_data; + const char *saved_comm_data; bool save_comm; CriuReq req = CRIU_REQ__INIT; CriuResp *resp = NULL; diff --git a/lib/c/criu.h b/lib/c/criu.h index ceb303538..8fccf8ed7 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -41,7 +41,7 @@ enum criu_cg_mode { CRIU_CG_MODE_DEFAULT, }; -void criu_set_service_address(char *path); +void criu_set_service_address(const char *path); void criu_set_service_fd(int fd); void criu_set_service_binary(const char *path); @@ -60,7 +60,7 @@ void criu_free_opts(void); void criu_set_pid(int pid); void criu_set_images_dir_fd(int fd); /* must be set for dump/restore */ -void criu_set_parent_images(char *path); +void criu_set_parent_images(const char *path); void criu_set_work_dir_fd(int fd); void criu_set_leave_running(bool leave_running); void criu_set_ext_unix_sk(bool ext_unix_sk); @@ -77,26 +77,26 @@ void criu_set_auto_dedup(bool auto_dedup); void criu_set_force_irmap(bool force_irmap); void criu_set_link_remap(bool link_remap); void criu_set_log_level(int log_level); -void criu_set_log_file(char *log_file); +void criu_set_log_file(const char *log_file); void criu_set_cpu_cap(unsigned int cap); -void criu_set_root(char *root); +void criu_set_root(const char *root); void criu_set_manage_cgroups(bool manage); void criu_set_manage_cgroups_mode(enum criu_cg_mode mode); -void criu_set_freeze_cgroup(char *name); +void criu_set_freeze_cgroup(const char *name); void criu_set_timeout(unsigned int timeout); void criu_set_auto_ext_mnt(bool val); void criu_set_ext_sharing(bool val); void criu_set_ext_masters(bool val); int criu_set_exec_cmd(int argc, char *argv[]); -int criu_add_ext_mount(char *key, char *val); -int criu_add_veth_pair(char *in, char *out); -int criu_add_cg_root(char *ctrl, char *path); -int criu_add_enable_fs(char *fs); -int criu_add_skip_mnt(char *mnt); +int criu_add_ext_mount(const char *key, const char *val); +int criu_add_veth_pair(const char *in, const char *out); +int criu_add_cg_root(const char *ctrl, const char *path); +int criu_add_enable_fs(const char *fs); +int criu_add_skip_mnt(const char *mnt); void criu_set_ghost_limit(unsigned int limit); -int criu_add_irmap_path(char *path); -int criu_add_inherit_fd(int fd, char *key); -int criu_add_external(char *key); +int criu_add_irmap_path(const char *path); +int criu_add_inherit_fd(int fd, const char *key); +int criu_add_external(const char *key); int criu_set_page_server_address_port(const char *address, int port); /* @@ -163,7 +163,7 @@ typedef struct criu_opts criu_opts; int criu_local_init_opts(criu_opts **opts); void criu_local_free_opts(criu_opts *opts); -void criu_local_set_service_address(criu_opts *opts, char *path); +void criu_local_set_service_address(criu_opts *opts, const char *path); void criu_local_set_service_fd(criu_opts *opts, int fd); void criu_local_set_service_comm(criu_opts *opts, enum criu_service_comm); @@ -171,7 +171,7 @@ void criu_local_set_service_fd(criu_opts *opts, int fd); void criu_local_set_pid(criu_opts *opts, int pid); void criu_local_set_images_dir_fd(criu_opts *opts, int fd); /* must be set for dump/restore */ -void criu_local_set_parent_images(criu_opts *opts, char *path); +void criu_local_set_parent_images(criu_opts *opts, const char *path); void criu_local_set_service_binary(criu_opts *opts, const char *path); void criu_local_set_work_dir_fd(criu_opts *opts, int fd); void criu_local_set_leave_running(criu_opts *opts, bool leave_running); @@ -189,29 +189,29 @@ void criu_local_set_auto_dedup(criu_opts *opts, bool auto_dedup); void criu_local_set_force_irmap(criu_opts *opts, bool force_irmap); void criu_local_set_link_remap(criu_opts *opts, bool link_remap); void criu_local_set_log_level(criu_opts *opts, int log_level); -void criu_local_set_log_file(criu_opts *opts, char *log_file); +void criu_local_set_log_file(criu_opts *opts, const char *log_file); void criu_local_set_cpu_cap(criu_opts *opts, unsigned int cap); -void criu_local_set_root(criu_opts *opts, char *root); +void criu_local_set_root(criu_opts *opts, const char *root); void criu_local_set_manage_cgroups(criu_opts *opts, bool manage); void criu_local_set_manage_cgroups_mode(criu_opts *opts, enum criu_cg_mode mode); -void criu_local_set_freeze_cgroup(criu_opts *opts, char *name); +void criu_local_set_freeze_cgroup(criu_opts *opts, const char *name); void criu_local_set_timeout(criu_opts *opts, unsigned int timeout); void criu_local_set_auto_ext_mnt(criu_opts *opts, bool val); void criu_local_set_ext_sharing(criu_opts *opts, bool val); void criu_local_set_ext_masters(criu_opts *opts, bool val); int criu_local_set_exec_cmd(criu_opts *opts, int argc, char *argv[]); -int criu_local_add_ext_mount(criu_opts *opts, char *key, char *val); -int criu_local_add_veth_pair(criu_opts *opts, char *in, char *out); -int criu_local_add_cg_root(criu_opts *opts, char *ctrl, char *path); -int criu_local_add_enable_fs(criu_opts *opts, char *fs); -int criu_local_add_skip_mnt(criu_opts *opts, char *mnt); +int criu_local_add_ext_mount(criu_opts *opts, const char *key, const char *val); +int criu_local_add_veth_pair(criu_opts *opts, const char *in, const char *out); +int criu_local_add_cg_root(criu_opts *opts, const char *ctrl, const char *path); +int criu_local_add_enable_fs(criu_opts *opts, const char *fs); +int criu_local_add_skip_mnt(criu_opts *opts, const char *mnt); void criu_local_set_ghost_limit(criu_opts *opts, unsigned int limit); -int criu_local_add_irmap_path(criu_opts *opts, char *path); -int criu_local_add_cg_props(criu_opts *opts, char *stream); -int criu_local_add_cg_props_file(criu_opts *opts, char *path); -int criu_local_add_cg_dump_controller(criu_opts *opts, char *name); -int criu_local_add_inherit_fd(criu_opts *opts, int fd, char *key); -int criu_local_add_external(criu_opts *opts, char *key); +int criu_local_add_irmap_path(criu_opts *opts, const char *path); +int criu_local_add_cg_props(criu_opts *opts, const char *stream); +int criu_local_add_cg_props_file(criu_opts *opts, const char *path); +int criu_local_add_cg_dump_controller(criu_opts *opts, const char *name); +int criu_local_add_inherit_fd(criu_opts *opts, int fd, const char *key); +int criu_local_add_external(criu_opts *opts, const char *key); int criu_local_set_page_server_address_port(criu_opts *opts, const char *address, int port); void criu_local_set_notify_cb(criu_opts *opts, int (*cb)(char *action, criu_notify_arg_t na)); From 46b05658c1037aa4a18b4b9729a1af6836f1aa54 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 25 Jan 2019 21:27:27 +0000 Subject: [PATCH 1913/4375] config: Refactor configuration file parsing Split the function parse_config() into smaller parts by introducing the parse_statement(), and add more descriptive comments to improve readability. In addition, make sure that the last element of the array of strings 'configuration' is initialised to NULL, which is necessary to properly count the number of elements after parsing. Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/config.c | 164 +++++++++++++++++++++++++++----------------------- 1 file changed, 89 insertions(+), 75 deletions(-) diff --git a/criu/config.c b/criu/config.c index 89cc17620..091f7a7f8 100644 --- a/criu/config.c +++ b/criu/config.c @@ -40,20 +40,91 @@ static int count_elements(char **to_count) return count; } +/* Parse one statement in configuration file */ +int parse_statement(int i, char *line, char **configuration) +{ + int offset = 0, len = 0; + bool was_newline = true; + char *tmp_string, *quoted, *quotedptr; + + while (1) { + /* Ignore white-space */ + while ((isspace(*(line + offset)) && (*(line + offset) != '\n'))) offset++; + + /* Read a single word. A word is everything + * that doesn't contain white-space characters. */ + if (sscanf(line + offset, "%m[^ \t\n]s", &configuration[i]) != 1) { + configuration[i] = NULL; + break; + } + + /* Ignore comments - everything between '#' and '\n' */ + if (configuration[i][0] == '#') { + configuration[i] = NULL; + break; + } + + if ((configuration[i][0] == '\"') && (strchr(line + offset + 1, '"'))) { + /* Handle empty strings which strtok ignores */ + if (!strcmp(configuration[i], "\"\"")) { + configuration[i] = ""; + offset += strlen("\"\""); + } else if ((configuration[i] = strtok_r(line + offset, "\"", "edptr))) { + /* Handle escaping of quotes in quoted string */ + while (configuration[i][strlen(configuration[i]) - 1] == '\\') { + offset++; + len = strlen(configuration[i]); + configuration[i][len - 1] = '"'; + if (*quotedptr == '"') { + quotedptr++; + break; + } + quoted = strtok_r(NULL, "\"", "edptr); + tmp_string = xmalloc(len + strlen(quoted) + 1); + if (tmp_string == NULL) + return -1; + + memmove(tmp_string, configuration[i], len); + memmove(tmp_string + len, quoted, strlen(quoted) + 1); + configuration[i] = tmp_string; + } + offset += 2; + } + } + + offset += strlen(configuration[i]); + + if (was_newline) { + was_newline = false; + len = strlen(configuration[i]); + tmp_string = xrealloc(configuration[i], len + strlen("--") + 1); + if (tmp_string == NULL) + return -1; + + memmove(tmp_string + strlen("--"), tmp_string, len + 1); + memmove(tmp_string, "--", strlen("--")); + configuration[i] = tmp_string; + } + i++; + } + + return i; +} + +/* Parse a configuration file */ static char ** parse_config(char *filepath) { #define DEFAULT_CONFIG_SIZE 10 FILE* configfile = fopen(filepath, "r"); int config_size = DEFAULT_CONFIG_SIZE; - int i = 1, len = 0, offset; - size_t limit = 0; - bool was_newline; - char *tmp_string, *line = NULL, *quoted, *quotedptr; - char **configuration, **tmp_conf; + int i = 1; + size_t line_size = 0; + char *line = NULL; + char **configuration; - if (!configfile) { + if (!configfile) return NULL; - } + configuration = xmalloc(config_size * sizeof(char *)); if (configuration == NULL) { fclose(configfile); @@ -64,85 +135,28 @@ static char ** parse_config(char *filepath) */ configuration[0] = "criu"; - while ((len = getline(&line, &limit, configfile)) != -1) { - offset = 0; - was_newline = true; + while (getline(&line, &line_size, configfile) != -1) { + /* Extend configuration buffer if necessary */ if (i >= config_size - 1) { config_size *= 2; - tmp_conf = xrealloc(configuration, config_size * sizeof(char *)); - if (tmp_conf == NULL) { + configuration = xrealloc(configuration, config_size * sizeof(char *)); + if (configuration == NULL) { fclose(configfile); exit(1); } - configuration = tmp_conf; } - while (1) { - while ((isspace(*(line + offset)) && (*(line + offset) != '\n'))) offset++; - if (sscanf(line + offset, "%m[^ \t\n]s", &configuration[i]) != 1) { - configuration[i] = NULL; - break; - } - - if (configuration[i][0] == '#') { - if (sscanf(line, "%*[^\n]") != 0) { - pr_err("Error while reading configuration file %s\n", filepath); - fclose(configfile); - exit(1); - } - configuration[i] = NULL; - break; - } - if ((configuration[i][0] == '\"') && (strchr(line + offset + 1, '"'))) { - /* - * Handle empty strings which strtok ignores - */ - if (!strcmp(configuration[i], "\"\"")) { - configuration[i] = ""; - offset += strlen("\"\""); - } else if ((configuration[i] = strtok_r(line + offset, "\"", "edptr))) { - /* - * Handle escaping of quotes in quoted string - */ - while (configuration[i][strlen(configuration[i]) - 1] == '\\') { - offset++; - len = strlen(configuration[i]); - configuration[i][len - 1] = '"'; - if (*quotedptr == '"') { - quotedptr++; - break; - } - quoted = strtok_r(NULL, "\"", "edptr); - tmp_string = xmalloc(len + strlen(quoted) + 1); - if (tmp_string == NULL) { - fclose(configfile); - exit(1); - } - memmove(tmp_string, configuration[i], len); - memmove(tmp_string + len, quoted, strlen(quoted) + 1); - configuration[i] = tmp_string; - } - offset += 2; - } - } - offset += strlen(configuration[i]); - if (was_newline) { - was_newline = false; - len = strlen(configuration[i]); - tmp_string = xrealloc(configuration[i], len + strlen("--") + 1); - if (tmp_string == NULL) { - fclose(configfile); - exit(1); - } - memmove(tmp_string + strlen("--"), tmp_string, len + 1); - memmove(tmp_string, "--", strlen("--")); - configuration[i] = tmp_string; - } - i++; + i = parse_statement(i, line, configuration); + if (i < 0) { + fclose(configfile); + exit(1); } + free(line); line = NULL; } + /* Initialize the last element */ + configuration[i] = NULL; free(line); fclose(configfile); From f73e5d181ba111098ccc59570122740e0b75de87 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Jan 2019 17:14:36 +0100 Subject: [PATCH 1914/4375] Documentation: Remove unused a2x check a2x is never used although its presence is checked mandatorily. Let's remove this superfluous check and the unused entry. Signed-off-by: Takashi Iwai Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- Documentation/Makefile | 3 +-- scripts/nmk/Documentation/Makefile | 3 +-- test/others/bers/Makefile | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index fe640b0ee..3c93ec8a4 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -3,7 +3,6 @@ include $(__nmk_dir)include.mk include $(__nmk_dir)macro.mk ASCIIDOC := asciidoc -A2X := a2x XMLTO := xmlto FOOTER := footer.txt @@ -29,7 +28,7 @@ pdf: $(PDFS) .PHONY: all ps pdf check check: - $(Q) for B in $(ASCIIDOC) $(A2X) $(XMLTO); do \ + $(Q) for B in $(ASCIIDOC) $(XMLTO); do \ $$B --version > /dev/null || exit 1; \ done diff --git a/scripts/nmk/Documentation/Makefile b/scripts/nmk/Documentation/Makefile index 981449979..b7446e2f3 100644 --- a/scripts/nmk/Documentation/Makefile +++ b/scripts/nmk/Documentation/Makefile @@ -1,5 +1,4 @@ ASCIIDOC := asciidoc -A2X := a2x XMLTO := xmlto PS2PDF := ps2pdf @@ -20,7 +19,7 @@ all: check $(MANS) .PHONY: all ps pdf check clean check: - $(Q) for B in $(ASCIIDOC) $(A2X) $(XMLTO); do \ + $(Q) for B in $(ASCIIDOC) $(XMLTO); do \ $$B --version > /dev/null || exit 1; \ done diff --git a/test/others/bers/Makefile b/test/others/bers/Makefile index 74b6142e7..a1d689c35 100644 --- a/test/others/bers/Makefile +++ b/test/others/bers/Makefile @@ -9,7 +9,6 @@ endif export E Q ASCIIDOC := asciidoc -A2X := a2x XMLTO := xmlto SRC += bers.txt From 0493724c8eda31af84ddbb1817b2a99cccee51e3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Jan 2019 17:14:37 +0100 Subject: [PATCH 1915/4375] Documentation: Allow to use asciidoctor for formatting man pages Since asciidoc is based on Phyton 2, we want to move to alternative, and a promising one is asciidoctor. This patch allows to use asciidoctor for formatting man pages instead of asiidoc, by passing a make option, USE_ASCIIDOCTOR=yes. Although asciidoctor is almost compatible with asciidoc, it can produce a man page directly from a text file without XML, which is more efficiently. So in asciidoctor mode, we don't require xmlto. Signed-off-by: Takashi Iwai Signed-off-by: Andrei Vagin --- Documentation/Makefile | 13 +++++++++++++ scripts/nmk/Documentation/Makefile | 9 +++++++++ test/others/bers/Makefile | 9 +++++++++ 3 files changed, 31 insertions(+) diff --git a/Documentation/Makefile b/Documentation/Makefile index 3c93ec8a4..aa5d3ebbf 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -2,8 +2,13 @@ __nmk_dir ?= ../scripts/nmk/scripts/ include $(__nmk_dir)include.mk include $(__nmk_dir)macro.mk +ifneq ($(USE_ASCIIDOCTOR),) +ASCIIDOC := asciidoctor +XMLTO := +else ASCIIDOC := asciidoc XMLTO := xmlto +endif FOOTER := footer.txt SRC1 += crit.txt @@ -44,13 +49,21 @@ $(FOOTER): ../Makefile.versions %.1: %.txt $(FOOTER) custom.xsl $(call msg-gen, $@) +ifneq ($(USE_ASCIIDOCTOR),) + $(Q) $(ASCIIDOC) -b manpage -d manpage -o $@ $< +else $(Q) $(ASCIIDOC) -b docbook -d manpage -o $(patsubst %.1,%.xml,$@) $< $(Q) $(XMLTO) man -m custom.xsl $(patsubst %.1,%.xml,$@) 2>/dev/null +endif %.8: %.txt $(FOOTER) custom.xsl $(call msg-gen, $@) +ifneq ($(USE_ASCIIDOCTOR),) + $(Q) $(ASCIIDOC) -b manpage -d manpage -o $@ $< +else $(Q) $(ASCIIDOC) -b docbook -d manpage -o $(patsubst %.8,%.xml,$@) $< $(Q) $(XMLTO) man -m custom.xsl $(patsubst %.8,%.xml,$@) 2>/dev/null +endif %.ps: %.1 $(call msg-gen, $@) diff --git a/scripts/nmk/Documentation/Makefile b/scripts/nmk/Documentation/Makefile index b7446e2f3..4c037de67 100644 --- a/scripts/nmk/Documentation/Makefile +++ b/scripts/nmk/Documentation/Makefile @@ -1,5 +1,10 @@ +ifneq ($(USE_ASCIIDOCTOR),) +ASCIIDOC := asciidoctor +XMLTO := +else ASCIIDOC := asciidoc XMLTO := xmlto +endif PS2PDF := ps2pdf SRC += nmk.txt @@ -25,8 +30,12 @@ check: %.8: %.txt $(call msg-gen, $@) +ifneq ($(USE_ASCIIDOCTOR),) + $(Q) $(ASCIIDOC) -b manpage -d manpage -o $@ $< +else $(Q) $(ASCIIDOC) -b docbook -d manpage -o $(patsubst %.8,%.xml,$@) $< $(Q) $(XMLTO) man --skip-validation $(patsubst %.8,%.xml,$@) 2>/dev/null +endif %.ps: %.8 $(call msg-gen, $@) diff --git a/test/others/bers/Makefile b/test/others/bers/Makefile index a1d689c35..3034d46e3 100644 --- a/test/others/bers/Makefile +++ b/test/others/bers/Makefile @@ -8,8 +8,13 @@ endif export E Q +ifneq ($(USE_ASCIIDOCTOR),) +ASCIIDOC := asciidoctor +XMLTO := +else ASCIIDOC := asciidoc XMLTO := xmlto +endif SRC += bers.txt XMLS := $(patsubst %.txt,%.xml,$(SRC)) @@ -17,8 +22,12 @@ MANS := $(patsubst %.txt,%.8,$(SRC)) %.8: %.txt $(E) " GEN " $@ +ifneq ($(USE_ASCIIDOCTOR),) + $(Q) $(ASCIIDOC) -b manpage -d manpage -o $@ $< +else $(Q) $(ASCIIDOC) -b docbook -d manpage -o $(patsubst %.8,%.xml,$@) $< $(Q) $(XMLTO) man --skip-validation $(patsubst %.8,%.xml,$@) 2>/dev/null +endif docs: $(MANS) @true From 513ab44ac84c0328b5c5691d921e4339dd4506d3 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 29 Jan 2019 09:28:40 +0200 Subject: [PATCH 1916/4375] zdtm: add test for prctl(PR_SET_THP_DISABLE) Verify that enabling / disabling THP with prctl(PR_SET_THP_DISABLE) does not change VMA flags Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 2 ++ test/zdtm/static/thp_disable.c | 66 ++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 test/zdtm/static/thp_disable.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 2d13e7d2a..ddbc0fdd6 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -208,6 +208,7 @@ TST_NOFILE := \ netns_sub_veth \ unlink_multiple_largefiles \ config_inotify_irmap \ + thp_disable \ # jobctl00 \ ifneq ($(SRCARCH),arm) @@ -500,6 +501,7 @@ mntns_shared_bind02: CFLAGS += -DSHARED_BIND02 mntns_root_bind02: CFLAGS += -DROOT_BIND02 maps02: get_smaps_bits.o mlock_setuid: get_smaps_bits.o +thp_disable: get_smaps_bits.o inotify01: CFLAGS += -DINOTIFY01 unlink_fstat01+: CFLAGS += -DUNLINK_OVER unlink_fstat04: CFLAGS += -DUNLINK_FSTAT04 diff --git a/test/zdtm/static/thp_disable.c b/test/zdtm/static/thp_disable.c new file mode 100644 index 000000000..1ccc0123c --- /dev/null +++ b/test/zdtm/static/thp_disable.c @@ -0,0 +1,66 @@ +#include +#include +#include "zdtmtst.h" +#include "get_smaps_bits.h" + +#ifndef MADV_DONTDUMP +#define MADV_DONTDUMP 16 +#endif + +const char *test_doc = "Test prctl(THP_DISABLE) behaviour"; +const char *test_author = "Mike Rapoport "; + +#define MEM_SIZE (8192) + +int main(int argc, char **argv) +{ + unsigned long orig_flags = 0, new_flags = 0; + unsigned long orig_madv = 0, new_madv = 0; + void *area; + + test_init(argc, argv); + + area = mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (area == MAP_FAILED) { + pr_perror("mmap failed"); + return -1; + } + + test_msg("Fetch existing flags/adv\n"); + if (get_smaps_bits((unsigned long)area, &orig_flags, &orig_madv)) + return -1; + + if (prctl(PR_SET_THP_DISABLE, 1, 0, 0, 0)) { + pr_perror("Disabling THP failed"); + return -1; + } + + test_daemon(); + test_waitsig(); + + if (prctl(PR_SET_THP_DISABLE, 0, 0, 0, 0)) { + pr_perror("Enabling THP failed"); + return -1; + } + + test_msg("Fetch restored flags/adv\n"); + if (get_smaps_bits((unsigned long)area, &new_flags, &new_madv)) + return -1; + + if (orig_flags != new_flags) { + pr_err("Flags are changed %lx -> %lx\n", orig_flags, new_flags); + fail(); + return -1; + } + + if (orig_madv != new_madv) { + pr_err("Madvs are changed %lx -> %lx\n", orig_madv, new_madv); + fail(); + return -1; + } + + pass(); + + return 0; +} From e9822fc6fa04a611e23503ae57da013e5a4c313b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20W=C3=BChrer?= Date: Sat, 2 Feb 2019 10:34:59 +0100 Subject: [PATCH 1917/4375] c-lib: strdup for service_address and service_binary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The functions criu_(local_)set_service_address and criu_(local_)set_service_binary are the only functions that do not create a copy of the given string arguments. This may lead to problems, if the original string gets freed but criu relies on them. Additionally, the function criu_local_init_opts() assigns the default service_binary now to opt->service_binary instead of opt->service_address which is in my opinion the preferred way since both are types of an anonymous union. Signed-off-by: Martin Wührer --- lib/c/criu.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/lib/c/criu.c b/lib/c/criu.c index 31692c781..f53315894 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -35,6 +35,20 @@ struct criu_opts { static criu_opts *global_opts; static int saved_errno; +void criu_free_service(criu_opts *opts) +{ + switch(opts->service_comm) { + case CRIU_COMM_SK: + free((void*)(opts->service_address)); + break; + case CRIU_COMM_BIN: + free((void*)(opts->service_binary)); + break; + default: + break; + } +} + void criu_local_set_service_comm(criu_opts *opts, enum criu_service_comm comm) { opts->service_comm = comm; @@ -47,10 +61,11 @@ void criu_set_service_comm(enum criu_service_comm comm) void criu_local_set_service_address(criu_opts *opts, const char *path) { + criu_free_service(opts); if (path) - opts->service_address = path; + opts->service_address = strdup(path); else - opts->service_address = CR_DEFAULT_SERVICE_ADDRESS; + opts->service_address = strdup(CR_DEFAULT_SERVICE_ADDRESS); } void criu_set_service_address(const char *path) @@ -60,6 +75,7 @@ void criu_set_service_address(const char *path) void criu_local_set_service_fd(criu_opts *opts, int fd) { + criu_free_service(opts); opts->service_fd = fd; } @@ -70,10 +86,11 @@ void criu_set_service_fd(int fd) void criu_local_set_service_binary(criu_opts *opts, const char *path) { + criu_free_service(opts); if (path) - opts->service_binary = path; + opts->service_binary = strdup(path); else - opts->service_binary = CR_DEFAULT_SERVICE_BIN; + opts->service_binary = strdup(CR_DEFAULT_SERVICE_BIN); } void criu_set_service_binary(const char *path) @@ -205,6 +222,7 @@ void criu_local_free_opts(criu_opts *opts) free(opts->rpc->freeze_cgroup); free(opts->rpc->log_file); free(opts->rpc); + criu_free_service(opts); free(opts); } @@ -237,7 +255,7 @@ int criu_local_init_opts(criu_opts **o) opts->notify = NULL; opts->service_comm = CRIU_COMM_BIN; - opts->service_address = CR_DEFAULT_SERVICE_BIN; + opts->service_binary = strdup(CR_DEFAULT_SERVICE_BIN); *o = opts; From f487c965d441809da1f28b0337ec350d7bfb119e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 5 Feb 2019 10:26:36 +0200 Subject: [PATCH 1918/4375] zdtm/thp_disable: increase memory size to 2M Somehow in travis tests the mmap of 8K gets "rounded" down and the actual VMA starts 4K below the returned address. This causes /proc/pid/smaps parsing to fail. Increasing the allocation size to 2M seems to resolve the problem and until the root cause is identified it looks like a viable workaround. Signed-off-by: Mike Rapoport --- test/zdtm/static/thp_disable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/thp_disable.c b/test/zdtm/static/thp_disable.c index 1ccc0123c..a809caaff 100644 --- a/test/zdtm/static/thp_disable.c +++ b/test/zdtm/static/thp_disable.c @@ -10,7 +10,7 @@ const char *test_doc = "Test prctl(THP_DISABLE) behaviour"; const char *test_author = "Mike Rapoport "; -#define MEM_SIZE (8192) +#define MEM_SIZE (2 << 20) int main(int argc, char **argv) { From d416c78d71a159bad039d8349f0043b7fd33a570 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 5 Feb 2019 20:54:39 +0200 Subject: [PATCH 1919/4375] travis: lazy-pages: exclude most tests for kernels <4.18 Although non-cooperative userfaultfd events have been merged into the Linux kernel since 4.11 they were racy until 4.18. Exclude "dangerous" tests for older kernels. Signed-off-by: Mike Rapoport --- scripts/travis/travis-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index aaa208c14..5a8884f07 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -88,7 +88,7 @@ chmod 0777 test/zdtm/transition KERN_MAJ=`uname -r | cut -d. -f1` KERN_MIN=`uname -r | cut -d. -f2` -if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then +if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "18" ]; then LAZY_EXCLUDE="-x cmdlinenv00 -x maps007" else LAZY_EXCLUDE="-x maps007 -x fork -x fork2 -x uffd-events -x cgroupns From 204230436c21b7aa65136a3f6e866547e1d4da35 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 30 Jan 2019 09:01:11 +0000 Subject: [PATCH 1920/4375] image: Drop unused O_SHOW Signed-off-by: Radostin Stoyanov --- criu/include/image.h | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/include/image.h b/criu/include/image.h index 1b2cdadf5..48ba3ec00 100644 --- a/criu/include/image.h +++ b/criu/include/image.h @@ -101,7 +101,6 @@ extern bool img_common_magic; #define O_NOBUF (O_DIRECT) #define O_SERVICE (O_DIRECTORY) #define O_DUMP (O_WRONLY | O_CREAT | O_TRUNC) -#define O_SHOW (O_RDONLY | O_NOBUF) #define O_RSTR (O_RDONLY) #define O_FORCE_LOCAL (O_SYNC) From bffa1d33b665d02d91c50f7514ba2481d8923fb4 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 5 Feb 2019 21:25:57 +0000 Subject: [PATCH 1921/4375] uffd: Show error msg on open_page_read failure The value stored in 'ret' is never used. Instead, output an error message. Signed-off-by: Radostin Stoyanov --- criu/uffd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index d0a4ed5a1..e437f1f63 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -770,7 +770,7 @@ static int ud_open(int client, struct lazy_pages_info **_lpi) pr_flags |= PR_REMOTE; ret = open_page_read(lpi->pid, &lpi->pr, pr_flags); if (ret <= 0) { - ret = -1; + lp_err(lpi, "Failed to open pagemap\n"); goto out; } From 2ffd191bad638e889cb4577bcdadd51d268e5b4c Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 7 Feb 2019 17:28:03 +0000 Subject: [PATCH 1922/4375] cr-service: Don't log return val of parse_options The function parse_options() should return an integer 0, 1 or 2, where: 0 := Success 1 := Failure 2 := CRIU should display help text The current behaviour always creates a warning message which shows the return value of that function. However, when the return value is different than 0 (Success) CRIU will fail. Since the logging is not initialised when this message is created, it will be lost, and therefore it can be removed completely. Signed-off-by: Radostin Stoyanov --- criu/cr-service.c | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 231a37f30..7d841bb5d 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -277,7 +277,6 @@ static int setup_opts_from_req(int sk, CriuOpts *req) rpc_cfg_file = req->config_file; i = parse_options(0, NULL, &dummy, &dummy, PARSING_RPC_CONF); - pr_warn("parse_options returns %d\n", i); if (i) { xfree(tmp_output); xfree(tmp_work); From b76d864eb378ed3f3567185b2ef0a240781dfbd3 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sat, 9 Feb 2019 20:29:18 +0000 Subject: [PATCH 1923/4375] crtools: Move deprecated checks at the end The `show` and `exec` commands have been deprecated for some time, and it is unlikely to be called by users. It would be better to move them the end of the sequence of if-statements. Signed-off-by: Radostin Stoyanov --- criu/crtools.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index 0a1483b06..d18d107d5 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -124,11 +124,6 @@ int main(int argc, char *argv[], char *envp[]) goto usage; } - if (!strcmp(argv[optind], "exec")) { - pr_msg("The \"exec\" action is deprecated by the Compel library.\n"); - return -1; - } - has_sub_command = (argc - optind) > 1; if (has_exec_cmd) { @@ -237,12 +232,6 @@ int main(int argc, char *argv[], char *envp[]) return ret != 0; } - if (!strcmp(argv[optind], "show")) { - pr_msg("The \"show\" action is deprecated by the CRIT utility.\n"); - pr_msg("To view an image use the \"crit decode -i $name --pretty\" command.\n"); - return -1; - } - if (!strcmp(argv[optind], "lazy-pages")) return cr_lazy_pages(opts.daemon_mode) != 0; @@ -269,6 +258,17 @@ int main(int argc, char *argv[], char *envp[]) return cpuinfo_check(); } + if (!strcmp(argv[optind], "exec")) { + pr_msg("The \"exec\" action is deprecated by the Compel library.\n"); + return -1; + } + + if (!strcmp(argv[optind], "show")) { + pr_msg("The \"show\" action is deprecated by the CRIT utility.\n"); + pr_msg("To view an image use the \"crit decode -i $name --pretty\" command.\n"); + return -1; + } + pr_msg("Error: unknown command: %s\n", argv[optind]); usage: pr_msg("\n" From 8d1dfd3cc71af9d42f1e3540050a2951b577fb76 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 8 Feb 2019 13:34:13 +0000 Subject: [PATCH 1924/4375] mount: realloc info->source when resolve ext mount Use realloc() to change the size of the memory block pointed to by info->source instead of allocating new memory area and releasing the old one. If info->source is NULL then the call is equivalent to malloc(size). Signed-off-by: Radostin Stoyanov --- criu/mount.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 696aed526..6378cc68c 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -491,14 +491,13 @@ static int try_resolve_ext_mount(struct mount_info *info) int len; len = strlen(val) + sizeof("dev[]"); - source = xmalloc(len); + source = xrealloc(info->source, len); if (source == NULL) return -1; snprintf(source, len, "dev[%s]", val); info->fstype = fstype_auto(); BUG_ON(info->fstype->code != FSTYPE__AUTO); - xfree(info->source); info->source = source; return 1; } From c3462adea8fced0cae9b0cfac73ff9490c84f067 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 13 Dec 2018 12:02:50 +0300 Subject: [PATCH 1925/4375] mount: remove unused argument of do_restore_task_mnt_ns Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/mount.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 6378cc68c..41605db87 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -3006,7 +3006,7 @@ int mntns_maybe_create_roots(void) return create_mnt_roots(); } -static int do_restore_task_mnt_ns(struct ns_id *nsid, struct pstree_item *current) +static int do_restore_task_mnt_ns(struct ns_id *nsid) { int fd; @@ -3053,7 +3053,7 @@ int restore_task_mnt_ns(struct pstree_item *current) BUG_ON(nsid->type == NS_CRIU); - if (do_restore_task_mnt_ns(nsid, current)) + if (do_restore_task_mnt_ns(nsid)) return -1; } From d2e35f504acdef7d263d46e21cbb48bd7c132ed0 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 13 Dec 2018 12:02:51 +0300 Subject: [PATCH 1926/4375] mount: save the result of mnt_is_overmounted On restore we change mounts tree topology and paths in find_remap_mounts thus mns_is_overmounted does not account remaped overmounts. So to know which mounts will be actually overmounted after restore we need two much effort, better prepare these info in advance. That also should improve performance of mnt_is_overmounted on dump, as we reuse calculations from previous calls. v3: make mnt_is_overmounted boolean again Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/include/mount.h | 2 ++ criu/mount.c | 34 +++++++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/criu/include/mount.h b/criu/include/mount.h index ca17b059a..e7d026264 100644 --- a/criu/include/mount.h +++ b/criu/include/mount.h @@ -70,6 +70,8 @@ struct mount_info { struct list_head postpone; + int is_overmounted; + void *private; /* associated filesystem data */ }; diff --git a/criu/mount.c b/criu/mount.c index 41605db87..0ef66ec7d 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1154,13 +1154,25 @@ static bool mnt_is_overmounted(struct mount_info *mi) { struct mount_info *t, *c, *m = mi; + if (mi->is_overmounted != -1) + goto exit; + + mi->is_overmounted = 0; + while (m->parent) { + if (mi->parent->is_overmounted == 1) { + mi->is_overmounted = 1; + goto exit; + } + /* Check there is no sibling-overmount */ list_for_each_entry(t, &m->parent->children, siblings) { if (m == t) continue; - if (issubpath(m->mountpoint, t->mountpoint)) - return true; + if (issubpath(m->mountpoint, t->mountpoint)) { + mi->is_overmounted = 1; + goto exit; + } } /* @@ -1173,10 +1185,19 @@ static bool mnt_is_overmounted(struct mount_info *mi) /* Check there is no children-overmount */ list_for_each_entry(c, &mi->children, siblings) - if (!strcmp(c->mountpoint, mi->mountpoint)) - return true; + if (!strcmp(c->mountpoint, mi->mountpoint)) { + mi->is_overmounted = 1; + goto exit; + } - return false; +exit: + return mi->is_overmounted; +} + +static int set_is_overmounted(struct mount_info *mi) +{ + mnt_is_overmounted(mi); + return 0; } /* @@ -2721,6 +2742,7 @@ struct mount_info *mnt_entry_alloc() new = xzalloc(sizeof(struct mount_info)); if (new) { new->fd = -1; + new->is_overmounted = -1; INIT_LIST_HEAD(&new->children); INIT_LIST_HEAD(&new->siblings); INIT_LIST_HEAD(&new->mnt_slave_list); @@ -3158,6 +3180,8 @@ static int populate_mnt_ns(void) if (validate_mounts(mntinfo, false)) return -1; + mnt_tree_for_each(pms, set_is_overmounted); + if (find_remap_mounts(pms)) return -1; From fd0a3cd9efb960dd14c38471f29a306156ecb13d Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 14 Jan 2019 15:59:17 +0300 Subject: [PATCH 1927/4375] mount: remount ro mounts writable before ghost-file restore We can have ghost-files on readonly mounts, for them we will need to recreate the file on restore, and we can't do that if mount is readonly, so the idea is to remount the mount we want to operate on to be writable, and later after all ghost-files restored return mounts to their proper state if needed. There are three exceptions, where we don't remount: a) Overmounted mounts can't be easily remounted writable, as their mountpoints are invisible for us. b) If the mount has readonly superblock - there can be no ghost-files on such a mount. c) When we are in host mntns, we should not remount mounts in it, else if we face errors in between we'll forget to remount back. We have 3 places where we need to add these remount: 1) create_ghost() 2) clean_one_remap() 3) rfi_remap() For (1) and (2) we can just remount the mount writable without remounting it back as they are called in service mntns (the one we save in mnt_ns_fd), which will be destroyed with all it's mounts at the end. We mark such mounts as remounted in service mntns - REMOUNTED_RW_SERVICE. For (3) we need to remount these mounts back to readonly so we mark them with REMOUNTED_RW and later in remount_readonly_mounts all such mounts are re-remounted back. For (3) we also need to enter proper mntns of tmi before remounting. These solution v3 is better than v2 as for v2 we added additional remount for all bind-readonly mounts, now we do remounts only for those having ghost-files restore operations on them. These should be quiet a rare thing, so ~3 remounts added for each suitable mount is a relatively small price. note: Also I thought and tried to implement the complete remove of the step of remounting back to readonly, but it requires quiet a tricky playing with usernsd and only removes one remount (of ~3) for already a rare case so I don't thing it worth the effort. v2: minor commit message cleanup and remove warn v4: don't delay, only remount the mounts we explicitly want to write to just before operating, rename patch accordingly, reuse do_restore_task_mnt_ns, optimize inefficient ns_remount_readonly_mounts, and also add another exception. v5: simplify child status check, fix log messages and brackets, do not drop all flags but only the readonly flag Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 3 + criu/files-reg.c | 25 +++++++- criu/include/mount.h | 16 +++++ criu/mount.c | 143 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+), 3 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index b8f973f4e..75976dfa1 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3250,6 +3250,9 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns /* Wait when all tasks restored all files */ if (restore_wait_other_tasks()) goto err_nv; + if (root_ns_mask & CLONE_NEWNS && + remount_readonly_mounts()) + goto err_nv; } /* diff --git a/criu/files-reg.c b/criu/files-reg.c index df36f082a..5fad977ab 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -11,6 +11,7 @@ #include #include #include +#include #ifndef SEEK_DATA #define SEEK_DATA 3 @@ -312,6 +313,7 @@ err: static int create_ghost(struct ghost_file *gf, GhostFileEntry *gfe, struct cr_img *img) { + struct mount_info *mi; char path[PATH_MAX]; int ret, root_len; char *msg; @@ -330,6 +332,11 @@ static int create_ghost(struct ghost_file *gf, GhostFileEntry *gfe, struct cr_im snprintf(path + root_len, sizeof(path) - root_len, "%s", gf->remap.rpath); ret = -1; + + mi = lookup_mnt_id(gf->remap.rmnt_id); + /* We get here while in service mntns */ + if (mi && try_remount_writable(mi, false)) + goto err; again: if (S_ISFIFO(gfe->mode)) { if ((ret = mknod(path, gfe->mode, 0)) < 0) @@ -654,9 +661,10 @@ int prepare_remaps(void) static int clean_one_remap(struct remap_info *ri) { - char path[PATH_MAX]; - int mnt_id, ret, rmntns_root; struct file_remap *remap = ri->rfi->remap; + int mnt_id, ret, rmntns_root; + struct mount_info *mi; + char path[PATH_MAX]; if (remap->rpath[0] == 0) return 0; @@ -676,6 +684,13 @@ static int clean_one_remap(struct remap_info *ri) return -1; } + mi = lookup_mnt_id(mnt_id); + /* We get here while in service mntns */ + if (mi && try_remount_writable(mi, false)) { + close(rmntns_root); + return -1; + } + pr_info("Unlink remap %s\n", remap->rpath); ret = unlinkat(rmntns_root, remap->rpath, remap->is_dir ? AT_REMOVEDIR : 0); @@ -1556,9 +1571,13 @@ static int rfi_remap(struct reg_file_info *rfi, int *level) convert_path_from_another_mp(rfi->remap->rpath, rpath, sizeof(_rpath), rmi, tmi); out: - pr_debug("%d: Link %s -> %s\n", tmi->mnt_id, rpath, path); mntns_root = mntns_get_root_fd(tmi->nsid); + /* We get here while in task's mntns */ + if (try_remount_writable(tmi, true)) + return -1; + + pr_debug("%d: Link %s -> %s\n", tmi->mnt_id, rpath, path); out_root: *level = make_parent_dirs_if_need(mntns_root, path); if (*level < 0) diff --git a/criu/include/mount.h b/criu/include/mount.h index e7d026264..843f3c438 100644 --- a/criu/include/mount.h +++ b/criu/include/mount.h @@ -14,6 +14,18 @@ struct ns_id; #define MNT_UNREACHABLE INT_MIN +/* + * We have remounted these mount writable temporary, and we + * should return it back to readonly at the end of file restore. + */ +#define REMOUNTED_RW 1 +/* + * We have remounted these mount writable in service mount namespace, + * thus we shouldn't return it back to readonly, as service mntns + * will be destroyed anyway. + */ +#define REMOUNTED_RW_SERVICE 2 + struct mount_info { int mnt_id; int parent_mnt_id; @@ -71,6 +83,7 @@ struct mount_info { struct list_head postpone; int is_overmounted; + int remounted_rw; void *private; /* associated filesystem data */ }; @@ -128,4 +141,7 @@ extern struct mount_info *parse_mountinfo(pid_t pid, struct ns_id *nsid, bool fo extern int check_mnt_id(void); +extern int remount_readonly_mounts(void); +extern int try_remount_writable(struct mount_info *mi, bool ns); + #endif /* __CR_MOUNT_H__ */ diff --git a/criu/mount.c b/criu/mount.c index 0ef66ec7d..a10d11cdd 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -3677,3 +3677,146 @@ void clean_cr_time_mounts(void) } struct ns_desc mnt_ns_desc = NS_DESC_ENTRY(CLONE_NEWNS, "mnt"); + +static int call_helper_process(int (*call)(void *), void *arg) +{ + int pid, status; + + pid = clone_noasan(call, CLONE_VFORK | CLONE_VM | CLONE_FILES | + CLONE_IO | CLONE_SIGHAND | CLONE_SYSVSEM, arg); + if (pid == -1) { + pr_perror("Can't clone helper process"); + return -1; + } + + errno = 0; + if (waitpid(pid, &status, __WALL) != pid) { + pr_perror("Unable to wait %d", pid); + return -1; + } + + if (status) { + pr_err("Bad child exit status: %d\n", status); + return -1; + } + + return 0; +} + +static int ns_remount_writable(void *arg) +{ + struct mount_info *mi = (struct mount_info *)arg; + struct ns_id *ns = mi->nsid; + + if (do_restore_task_mnt_ns(ns)) + return 1; + pr_debug("Switched to mntns %u:%u/n", ns->id, ns->kid); + + if (mount(NULL, mi->ns_mountpoint, NULL, MS_REMOUNT | MS_BIND | + (mi->flags & ~(MS_PROPAGATE | MS_RDONLY)), NULL) == -1) { + pr_perror("Failed to remount %d:%s writable", mi->mnt_id, mi->mountpoint); + return 1; + } + return 0; +} + +int try_remount_writable(struct mount_info *mi, bool ns) +{ + int remounted = REMOUNTED_RW; + + /* Don't remount if we are in host mntns to be on the safe side */ + if (!(root_ns_mask & CLONE_NEWNS)) + return 0; + + if (!ns) + remounted = REMOUNTED_RW_SERVICE; + + if (mi->flags & MS_RDONLY && !(mi->remounted_rw & remounted)) { + if (mnt_is_overmounted(mi)) { + pr_err("The mount %d is overmounted so paths are invisible\n", mi->mnt_id); + return -1; + } + + /* There should be no ghost files on mounts with ro sb */ + if (mi->sb_flags & MS_RDONLY) { + pr_err("The mount %d has readonly sb\n", mi->mnt_id); + return -1; + } + + pr_info("Remount %d:%s writable\n", mi->mnt_id, mi->mountpoint); + if (!ns) { + if (mount(NULL, mi->mountpoint, NULL, MS_REMOUNT | MS_BIND | + (mi->flags & ~(MS_PROPAGATE | MS_RDONLY)), NULL) == -1) { + pr_perror("Failed to remount %d:%s writable", mi->mnt_id, mi->mountpoint); + return -1; + } + } else { + if (call_helper_process(ns_remount_writable, mi)) + return -1; + } + mi->remounted_rw |= remounted; + } + + return 0; +} + +static int __remount_readonly_mounts(struct ns_id *ns) +{ + struct mount_info *mi; + bool mntns_set = false; + + for (mi = mntinfo; mi; mi = mi->next) { + if (ns && mi->nsid != ns) + continue; + + if (!(mi->remounted_rw && REMOUNTED_RW)) + continue; + + /* + * Lets enter the mount namespace lazily, only if we've found the + * mount which should be remounted readonly. These saves us + * from entering mntns if we have no mounts to remount in it. + */ + if (ns && !mntns_set) { + if (do_restore_task_mnt_ns(ns)) + return -1; + mntns_set = true; + pr_debug("Switched to mntns %u:%u/n", ns->id, ns->kid); + } + + pr_info("Remount %d:%s back to readonly\n", mi->mnt_id, mi->mountpoint); + if (mount(NULL, mi->ns_mountpoint, NULL, + MS_REMOUNT | MS_BIND | (mi->flags & ~MS_PROPAGATE), + NULL)) { + pr_perror("Failed to restore %d:%s mount flags %x", + mi->mnt_id, mi->mountpoint, mi->flags); + return -1; + } + } + + return 0; +} + +static int ns_remount_readonly_mounts(void *arg) +{ + struct ns_id *nsid; + + for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { + if (nsid->nd != &mnt_ns_desc) + continue; + + if (__remount_readonly_mounts(nsid)) + return 1; + } + + return 0; +} + +int remount_readonly_mounts(void) +{ + /* + * Need a helper process because the root task can share fs via + * CLONE_FS and we would not be able to enter mount namespaces + */ + return call_helper_process(ns_remount_readonly_mounts, NULL); +} From 830d1a18946ed2516d8f9443bd10ca5b11a7a3da Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 13 Dec 2018 12:02:53 +0300 Subject: [PATCH 1928/4375] zdtm: ghost on readonly fs Test creates two shared mounts, both are readonly, on each mount we have a different ghost file. Also let these mounts have different mount flags. That makes us both test do_new_mount hunk for delaying readonly and do_bind_mount, as one mount will bind from another on restore. https://jira.sw.ru/browse/PSBM-82991 v2: minor cleanup Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/ghost_on_rofs.c | 179 ++++++++++++++++++++++++++++ test/zdtm/static/ghost_on_rofs.desc | 1 + 3 files changed, 181 insertions(+) create mode 100644 test/zdtm/static/ghost_on_rofs.c create mode 100644 test/zdtm/static/ghost_on_rofs.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index ddbc0fdd6..cb6c7441d 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -343,6 +343,7 @@ TST_DIR = \ shared_slave_mount_children \ non_uniform_share_propagation \ private_bind_propagation \ + ghost_on_rofs \ TST_DIR_FILE = \ chroot \ diff --git a/test/zdtm/static/ghost_on_rofs.c b/test/zdtm/static/ghost_on_rofs.c new file mode 100644 index 000000000..1a7922320 --- /dev/null +++ b/test/zdtm/static/ghost_on_rofs.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check ghost file on readonly fs mount restores fine"; +const char *test_author = "Pavel Tikhomirov "; + +#define GHOST_DATA "Ghost Data" + +char *dirname; +TEST_OPTION(dirname, string, "directory name", 1); + +int main(int argc, char **argv) +{ + char ro_mount[PATH_MAX], ro_bind_mount[PATH_MAX]; + char ghost_file[PATH_MAX], ghost_file_bind[PATH_MAX]; + char buf[sizeof(GHOST_DATA)]; + int fd, fd_bind; + + test_init(argc, argv); + + if (mkdir(dirname, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("zdtm_fs", dirname, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, dirname, NULL, MS_PRIVATE, NULL)) { + pr_perror("mount"); + return 1; + } + + ssprintf(ro_mount, "%s/ro_mount", dirname); + if (mkdir(ro_mount, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("ro_mount", ro_mount, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + /* + * Need shared mount to check the hunk in do_bind_mount, we + * would have ro_bind_mount binded from ro_mount or vice versa. + */ + if (mount(NULL, ro_mount, NULL, MS_SHARED, NULL)) { + pr_perror("mount"); + return 1; + } + + ssprintf(ro_bind_mount, "%s/ro_bind_mount", dirname); + if (mkdir(ro_bind_mount, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount(ro_mount, ro_bind_mount, NULL, MS_BIND, NULL)) { + pr_perror("mount"); + return 1; + } + + ssprintf(ghost_file, "%s/ghost_file", ro_mount); + fd = open(ghost_file, O_CREAT|O_WRONLY, 0600); + if (fd < 0) { + pr_perror("open"); + return 1; + } + + if (write(fd, GHOST_DATA, sizeof(GHOST_DATA)) != sizeof(GHOST_DATA)) { + pr_perror("write"); + return 1; + } + + ssprintf(ghost_file_bind, "%s/ghost_file_bind", ro_bind_mount); + fd_bind = open(ghost_file_bind, O_CREAT|O_WRONLY, 0600); + if (fd_bind < 0) { + pr_perror("open"); + return 1; + } + + if (write(fd_bind, GHOST_DATA, sizeof(GHOST_DATA)) != sizeof(GHOST_DATA)) { + pr_perror("write"); + return 1; + } + + close(fd); + close(fd_bind); + + fd = open(ghost_file, O_RDONLY); + if (fd < 0) { + pr_perror("open"); + return 1; + } + + fd_bind = open(ghost_file_bind, O_RDONLY); + if (fd_bind < 0) { + pr_perror("open"); + return 1; + } + + if (unlink(ghost_file)) { + pr_perror("unlink"); + return 1; + } + + if (unlink(ghost_file_bind)) { + pr_perror("unlink"); + return 1; + } + + if (mount(NULL, ro_mount, NULL, MS_RDONLY|MS_REMOUNT|MS_BIND, NULL)) { + pr_perror("mount"); + return 1; + } + + /* + * Need MS_NOSUID flag to check the hunk in do_bind_mount, case of + * different flags for mount and it's ->bind + */ + if (mount(NULL, ro_bind_mount, NULL, MS_NOSUID|MS_RDONLY|MS_REMOUNT|MS_BIND, NULL)) { + pr_perror("mount"); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (read(fd, buf, sizeof(GHOST_DATA)) != sizeof(GHOST_DATA)) { + fail("Can't read from ghost file"); + return 1; + } + + if (strcmp(buf, GHOST_DATA)) { + fail("Wrong data in a ghost file"); + return 1; + } + + if (read(fd_bind, buf, sizeof(GHOST_DATA)) != sizeof(GHOST_DATA)) { + fail("Can't read from ghost file on bind"); + return 1; + } + + if (strcmp(buf, GHOST_DATA)) { + fail("Wrong data in a ghost file on bind"); + return 1; + } + + close(fd); + close(fd_bind); + + if (umount(ro_bind_mount)) { + pr_perror("umount"); + return 1; + } + + if (umount(ro_mount)) { + pr_perror("umount"); + return 1; + } + + if (umount(dirname)) { + pr_perror("umount"); + return 1; + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/ghost_on_rofs.desc b/test/zdtm/static/ghost_on_rofs.desc new file mode 100644 index 000000000..7657ba45c --- /dev/null +++ b/test/zdtm/static/ghost_on_rofs.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns', 'flags': 'suid'} From 304deda565f0042865dc0eb9e17ae0af3e1b429a Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 13 Dec 2018 12:02:54 +0300 Subject: [PATCH 1929/4375] files: open files on overmounted mounts are not supported Files from such mounts can switch on restore to different files on the overmounting mount, as we yet don't fully control the mount on which the file is restored. v3: make mnt_is_overmounted boolean again Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- criu/files-reg.c | 13 +++++++++---- criu/include/mount.h | 1 + criu/mount.c | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 5fad977ab..360ba7511 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1261,7 +1261,7 @@ static bool should_check_size(int flags) int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p) { struct fd_link _link, *link; - struct ns_id *nsid; + struct mount_info *mi; struct cr_img *rimg; char ext_id[64]; FileEntry fe = FILE_ENTRY__INIT; @@ -1285,13 +1285,18 @@ int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p) goto ext; } - nsid = lookup_nsid_by_mnt_id(p->mnt_id); - if (nsid == NULL) { + mi = lookup_mnt_id(p->mnt_id); + if (mi == NULL) { pr_err("Can't lookup mount=%d for fd=%d path=%s\n", p->mnt_id, p->fd, link->name + 1); return -1; } + if (mnt_is_overmounted(mi)) { + pr_err("Open files on overmounted mounts are not supported yet\n"); + return -1; + } + if (p->mnt_id >= 0 && (root_ns_mask & CLONE_NEWNS)) { rfe.mnt_id = p->mnt_id; rfe.has_mnt_id = true; @@ -1308,7 +1313,7 @@ int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p) return -1; } - if (check_path_remap(link, p, lfd, id, nsid)) + if (check_path_remap(link, p, lfd, id, mi->nsid)) return -1; rfe.name = &link->name[1]; ext: diff --git a/criu/include/mount.h b/criu/include/mount.h index 843f3c438..d9b375f5d 100644 --- a/criu/include/mount.h +++ b/criu/include/mount.h @@ -143,5 +143,6 @@ extern int check_mnt_id(void); extern int remount_readonly_mounts(void); extern int try_remount_writable(struct mount_info *mi, bool ns); +extern bool mnt_is_overmounted(struct mount_info *mi); #endif /* __CR_MOUNT_H__ */ diff --git a/criu/mount.c b/criu/mount.c index a10d11cdd..118ba623e 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1150,7 +1150,7 @@ static int get_clean_fd(struct mount_info *mi) * root of our mount namespace as it is covered by other mount. * mnt_is_overmounted() checks if mount is not visible. */ -static bool mnt_is_overmounted(struct mount_info *mi) +bool mnt_is_overmounted(struct mount_info *mi) { struct mount_info *t, *c, *m = mi; From 0aef3d975e7eccea70f401716db74a6762f95b2e Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 13 Dec 2018 12:02:55 +0300 Subject: [PATCH 1930/4375] zdtm: test dumping file on overmounted mount fails Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/overmounted_file.c | 109 +++++++++++++++++++++++++ test/zdtm/static/overmounted_file.desc | 1 + 3 files changed, 111 insertions(+) create mode 100644 test/zdtm/static/overmounted_file.c create mode 100644 test/zdtm/static/overmounted_file.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index cb6c7441d..a31c202d5 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -344,6 +344,7 @@ TST_DIR = \ non_uniform_share_propagation \ private_bind_propagation \ ghost_on_rofs \ + overmounted_file \ TST_DIR_FILE = \ chroot \ diff --git a/test/zdtm/static/overmounted_file.c b/test/zdtm/static/overmounted_file.c new file mode 100644 index 000000000..ee1d1c58f --- /dev/null +++ b/test/zdtm/static/overmounted_file.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check open file on overmounted mounts doesn't dump"; +const char *test_author = "Pavel Tikhomirov "; + +#define DATA "Data" + +char *dirname; +TEST_OPTION(dirname, string, "directory name", 1); + +int main(int argc, char **argv) +{ + char overmounted[PATH_MAX]; + char buf[sizeof(DATA)]; + char file[PATH_MAX]; + int fd; + + test_init(argc, argv); + + if (mkdir(dirname, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("zdtm_fs", dirname, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + if (mount(NULL, dirname, NULL, MS_PRIVATE, NULL)) { + pr_perror("mount"); + return 1; + } + + ssprintf(overmounted, "%s/overmounted", dirname); + if (mkdir(overmounted, 0700)) { + pr_perror("mkdir"); + return 1; + } + + if (mount("overmounted", overmounted, "tmpfs", 0, NULL)) { + pr_perror("mount"); + return 1; + } + + ssprintf(file, "%s/file", overmounted); + fd = open(file, O_CREAT|O_WRONLY, 0600); + if (fd < 0) { + pr_perror("open"); + return 1; + } + + if (write(fd, DATA, sizeof(DATA)) != sizeof(DATA)) { + pr_perror("write"); + return 1; + } + close(fd); + + fd = open(file, O_RDONLY); + if (fd < 0) { + pr_perror("open"); + return 1; + } + + if (mount(overmounted, overmounted, NULL, MS_BIND, NULL)) { + pr_perror("mount"); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (read(fd, buf, sizeof(DATA)) != sizeof(DATA)) { + fail("Can't read from file"); + return 1; + } + + if (strcmp(buf, DATA)) { + fail("Wrong data in a file"); + return 1; + } + + close(fd); + + if (umount(overmounted)) { + pr_perror("umount"); + return 1; + } + + if (umount(overmounted)) { + pr_perror("umount"); + return 1; + } + + if (umount(dirname)) { + pr_perror("umount"); + return 1; + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/overmounted_file.desc b/test/zdtm/static/overmounted_file.desc new file mode 100644 index 000000000..0d8b7f2b4 --- /dev/null +++ b/test/zdtm/static/overmounted_file.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns', 'flags': 'suid crfail'} From f572d1de7e6d5d275edc8ce4c003ebf381dd0e0b Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 13 Dec 2018 12:02:56 +0300 Subject: [PATCH 1931/4375] zdtm.py: also check that mount flags are restored correct Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 5e19d9a90..7fd79a0b0 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1344,7 +1344,7 @@ def get_visible_state(test): cmounts = [] try: - r = re.compile(r"^\S+\s\S+\s\S+\s(\S+)\s(\S+)\s\S+\s[^-]*?(shared)?[^-]*?(master)?[^-]*?-") + r = re.compile(r"^\S+\s\S+\s\S+\s(\S+)\s(\S+)\s(\S+)\s[^-]*?(shared)?[^-]*?(master)?[^-]*?-") with open("/proc/%s/root/proc/%s/mountinfo" % (test.getpid(), pid)) as mountinfo: for m in mountinfo: cmounts.append(r.match(m).groups()) From 29af538da7025f9ea09b71b7935e465edf13d4c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20W=C3=BChrer?= Date: Tue, 5 Feb 2019 23:03:11 +0100 Subject: [PATCH 1932/4375] c-lib: added missing strdup-null checks. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit checks after each strdup() call if the call was successful. If not, the function that calls strdup() returns an error. This requires, that the return value of several functions has to be changed from void to int. Signed-off-by: Martin Wührer --- lib/c/criu.c | 76 +++++++++++++++++++++++++++++++++++++--------------- lib/c/criu.h | 24 ++++++++--------- 2 files changed, 66 insertions(+), 34 deletions(-) diff --git a/lib/c/criu.c b/lib/c/criu.c index f53315894..ad84e8837 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -59,18 +59,23 @@ void criu_set_service_comm(enum criu_service_comm comm) criu_local_set_service_comm(global_opts, comm); } -void criu_local_set_service_address(criu_opts *opts, const char *path) +int criu_local_set_service_address(criu_opts *opts, const char *path) { criu_free_service(opts); - if (path) + if (path) { opts->service_address = strdup(path); - else + } else { opts->service_address = strdup(CR_DEFAULT_SERVICE_ADDRESS); + } + if(opts->service_address == NULL) { + return -ENOMEM; + } + return 0; } -void criu_set_service_address(const char *path) +int criu_set_service_address(const char *path) { - criu_local_set_service_address(global_opts, path); + return criu_local_set_service_address(global_opts, path); } void criu_local_set_service_fd(criu_opts *opts, int fd) @@ -84,18 +89,23 @@ void criu_set_service_fd(int fd) criu_local_set_service_fd(global_opts, fd); } -void criu_local_set_service_binary(criu_opts *opts, const char *path) +int criu_local_set_service_binary(criu_opts *opts, const char *path) { criu_free_service(opts); - if (path) + if (path) { opts->service_binary = strdup(path); - else + } else { opts->service_binary = strdup(CR_DEFAULT_SERVICE_BIN); + } + if(opts->service_binary == NULL) { + return -ENOMEM; + } + return 0; } -void criu_set_service_binary(const char *path) +int criu_set_service_binary(const char *path) { - criu_local_set_service_binary(global_opts, path); + return criu_local_set_service_binary(global_opts, path); } void criu_local_free_opts(criu_opts *opts) @@ -257,6 +267,12 @@ int criu_local_init_opts(criu_opts **o) opts->service_comm = CRIU_COMM_BIN; opts->service_binary = strdup(CR_DEFAULT_SERVICE_BIN); + if(opts->service_binary == NULL) { + perror("Can't allocate memory for criu service setting"); + criu_local_free_opts(opts); + return -1; + } + *o = opts; return 0; @@ -311,14 +327,18 @@ void criu_set_images_dir_fd(int fd) criu_local_set_images_dir_fd(global_opts, fd); } -void criu_local_set_parent_images(criu_opts *opts, const char *path) +int criu_local_set_parent_images(criu_opts *opts, const char *path) { opts->rpc->parent_img = strdup(path); + if(opts->rpc->parent_img == NULL) { + return -ENOMEM; + } + return 0; } -void criu_set_parent_images(const char *path) +int criu_set_parent_images(const char *path) { - criu_local_set_parent_images(global_opts, path); + return criu_local_set_parent_images(global_opts, path); } void criu_local_set_track_mem(criu_opts *opts, bool track_mem) @@ -533,14 +553,18 @@ void criu_set_log_level(int log_level) criu_local_set_log_level(global_opts, log_level); } -void criu_local_set_root(criu_opts *opts, const char *root) +int criu_local_set_root(criu_opts *opts, const char *root) { opts->rpc->root = strdup(root); + if(opts->rpc->root == NULL) { + return -ENOMEM; + } + return 0; } -void criu_set_root(const char *root) +int criu_set_root(const char *root) { - criu_local_set_root(global_opts, root); + return criu_local_set_root(global_opts, root); } void criu_local_set_manage_cgroups(criu_opts *opts, bool manage) @@ -565,14 +589,18 @@ void criu_set_manage_cgroups_mode(enum criu_cg_mode mode) criu_local_set_manage_cgroups_mode(global_opts, mode); } -void criu_local_set_freeze_cgroup(criu_opts *opts, const char *name) +int criu_local_set_freeze_cgroup(criu_opts *opts, const char *name) { opts->rpc->freeze_cgroup = strdup(name); + if(opts->rpc->freeze_cgroup == NULL) { + return -ENOMEM; + } + return 0; } -void criu_set_freeze_cgroup(const char *name) +int criu_set_freeze_cgroup(const char *name) { - criu_local_set_freeze_cgroup(global_opts, name); + return criu_local_set_freeze_cgroup(global_opts, name); } void criu_local_set_timeout(criu_opts *opts, unsigned int timeout) @@ -618,14 +646,18 @@ void criu_set_ext_masters(bool val) criu_local_set_ext_masters(global_opts, val); } -void criu_local_set_log_file(criu_opts *opts, const char *log_file) +int criu_local_set_log_file(criu_opts *opts, const char *log_file) { opts->rpc->log_file = strdup(log_file); + if(opts->rpc->log_file == NULL) { + return -ENOMEM; + } + return 0; } -void criu_set_log_file(const char *log_file) +int criu_set_log_file(const char *log_file) { - criu_local_set_log_file(global_opts, log_file); + return criu_local_set_log_file(global_opts, log_file); } void criu_local_set_cpu_cap(criu_opts *opts, unsigned int cap) diff --git a/lib/c/criu.h b/lib/c/criu.h index 8fccf8ed7..f5095dd9b 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -41,9 +41,9 @@ enum criu_cg_mode { CRIU_CG_MODE_DEFAULT, }; -void criu_set_service_address(const char *path); +int criu_set_service_address(const char *path); void criu_set_service_fd(int fd); -void criu_set_service_binary(const char *path); +int criu_set_service_binary(const char *path); /* * You can choose if you want libcriu to connect to service socket @@ -60,7 +60,7 @@ void criu_free_opts(void); void criu_set_pid(int pid); void criu_set_images_dir_fd(int fd); /* must be set for dump/restore */ -void criu_set_parent_images(const char *path); +int criu_set_parent_images(const char *path); void criu_set_work_dir_fd(int fd); void criu_set_leave_running(bool leave_running); void criu_set_ext_unix_sk(bool ext_unix_sk); @@ -77,12 +77,12 @@ void criu_set_auto_dedup(bool auto_dedup); void criu_set_force_irmap(bool force_irmap); void criu_set_link_remap(bool link_remap); void criu_set_log_level(int log_level); -void criu_set_log_file(const char *log_file); +int criu_set_log_file(const char *log_file); void criu_set_cpu_cap(unsigned int cap); -void criu_set_root(const char *root); +int criu_set_root(const char *root); void criu_set_manage_cgroups(bool manage); void criu_set_manage_cgroups_mode(enum criu_cg_mode mode); -void criu_set_freeze_cgroup(const char *name); +int criu_set_freeze_cgroup(const char *name); void criu_set_timeout(unsigned int timeout); void criu_set_auto_ext_mnt(bool val); void criu_set_ext_sharing(bool val); @@ -163,7 +163,7 @@ typedef struct criu_opts criu_opts; int criu_local_init_opts(criu_opts **opts); void criu_local_free_opts(criu_opts *opts); -void criu_local_set_service_address(criu_opts *opts, const char *path); +int criu_local_set_service_address(criu_opts *opts, const char *path); void criu_local_set_service_fd(criu_opts *opts, int fd); void criu_local_set_service_comm(criu_opts *opts, enum criu_service_comm); @@ -171,8 +171,8 @@ void criu_local_set_service_fd(criu_opts *opts, int fd); void criu_local_set_pid(criu_opts *opts, int pid); void criu_local_set_images_dir_fd(criu_opts *opts, int fd); /* must be set for dump/restore */ -void criu_local_set_parent_images(criu_opts *opts, const char *path); -void criu_local_set_service_binary(criu_opts *opts, const char *path); +int criu_local_set_parent_images(criu_opts *opts, const char *path); +int criu_local_set_service_binary(criu_opts *opts, const char *path); void criu_local_set_work_dir_fd(criu_opts *opts, int fd); void criu_local_set_leave_running(criu_opts *opts, bool leave_running); void criu_local_set_ext_unix_sk(criu_opts *opts, bool ext_unix_sk); @@ -189,12 +189,12 @@ void criu_local_set_auto_dedup(criu_opts *opts, bool auto_dedup); void criu_local_set_force_irmap(criu_opts *opts, bool force_irmap); void criu_local_set_link_remap(criu_opts *opts, bool link_remap); void criu_local_set_log_level(criu_opts *opts, int log_level); -void criu_local_set_log_file(criu_opts *opts, const char *log_file); +int criu_local_set_log_file(criu_opts *opts, const char *log_file); void criu_local_set_cpu_cap(criu_opts *opts, unsigned int cap); -void criu_local_set_root(criu_opts *opts, const char *root); +int criu_local_set_root(criu_opts *opts, const char *root); void criu_local_set_manage_cgroups(criu_opts *opts, bool manage); void criu_local_set_manage_cgroups_mode(criu_opts *opts, enum criu_cg_mode mode); -void criu_local_set_freeze_cgroup(criu_opts *opts, const char *name); +int criu_local_set_freeze_cgroup(criu_opts *opts, const char *name); void criu_local_set_timeout(criu_opts *opts, unsigned int timeout); void criu_local_set_auto_ext_mnt(criu_opts *opts, bool val); void criu_local_set_ext_sharing(criu_opts *opts, bool val); From 9ede9253f5d04e7ade626ece8b96bb66bf6dc938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20W=C3=BChrer?= Date: Tue, 5 Feb 2019 23:07:23 +0100 Subject: [PATCH 1933/4375] c-lib: simplify service set by removing set_service_comm(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit removes the functions criu_(local_)set_service_comm(). These functions are not neccessary, because if set_service_address(), set_service_fd() or set_service_binary() has been called it is already clear, which service comm type should be used. Furhtermore, this commit reduces the number of misuses. E.g. if set_service_comm() was set to socket, but a binary was given via set_service_binary(). Signed-off-by: Martin Wührer --- lib/c/criu.c | 13 +++---------- lib/c/criu.h | 7 ------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/lib/c/criu.c b/lib/c/criu.c index ad84e8837..00ececa1f 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -49,19 +49,10 @@ void criu_free_service(criu_opts *opts) } } -void criu_local_set_service_comm(criu_opts *opts, enum criu_service_comm comm) -{ - opts->service_comm = comm; -} - -void criu_set_service_comm(enum criu_service_comm comm) -{ - criu_local_set_service_comm(global_opts, comm); -} - int criu_local_set_service_address(criu_opts *opts, const char *path) { criu_free_service(opts); + opts->service_comm = CRIU_COMM_SK; if (path) { opts->service_address = strdup(path); } else { @@ -81,6 +72,7 @@ int criu_set_service_address(const char *path) void criu_local_set_service_fd(criu_opts *opts, int fd) { criu_free_service(opts); + opts->service_comm = CRIU_COMM_FD; opts->service_fd = fd; } @@ -92,6 +84,7 @@ void criu_set_service_fd(int fd) int criu_local_set_service_binary(criu_opts *opts, const char *path) { criu_free_service(opts); + opts->service_comm = CRIU_COMM_BIN; if (path) { opts->service_binary = strdup(path); } else { diff --git a/lib/c/criu.h b/lib/c/criu.h index f5095dd9b..c4d80a4fd 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -45,12 +45,6 @@ int criu_set_service_address(const char *path); void criu_set_service_fd(int fd); int criu_set_service_binary(const char *path); -/* - * You can choose if you want libcriu to connect to service socket - * by itself, use provided file descriptor or spawn swrk by itself - */ -void criu_set_service_comm(enum criu_service_comm); - /* * Set opts to defaults. _Must_ be called first before using any functions from * the list down below. 0 on success, -1 on fail. @@ -165,7 +159,6 @@ void criu_local_free_opts(criu_opts *opts); int criu_local_set_service_address(criu_opts *opts, const char *path); void criu_local_set_service_fd(criu_opts *opts, int fd); -void criu_local_set_service_comm(criu_opts *opts, enum criu_service_comm); void criu_local_set_service_fd(criu_opts *opts, int fd); From c292fe54a1f779ac15fcc896e9164b682601ef39 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 12 Feb 2019 08:55:00 +0000 Subject: [PATCH 1934/4375] crtools: Remove unused #include Signed-off-by: Radostin Stoyanov --- criu/crtools.c | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/crtools.c b/criu/crtools.c index d18d107d5..1f050eeab 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include From d715f176ba6e7a0662db690647cf23e99282a3b1 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 12 Feb 2019 09:53:50 +0000 Subject: [PATCH 1935/4375] config: Fix -R option The '-R' is short for '--leave-running', which is a boolean option and does not require an argument. From getopt(3) man page: optstring is a string containing the legitimate option characters. If such a character is followed by a colon, the option requires an argument, ... Signed-off-by: Radostin Stoyanov --- criu/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/config.c b/criu/config.c index 091f7a7f8..35085a42d 100644 --- a/criu/config.c +++ b/criu/config.c @@ -436,7 +436,7 @@ int parse_options(int argc, char **argv, bool *usage_error, {OPT_NAME, no_argument, SAVE_TO, true},\ {"no-" OPT_NAME, no_argument, SAVE_TO, false} - static const char short_opts[] = "dSsR:t:hD:o:v::x::Vr:jJ:lW:L:M:"; + static const char short_opts[] = "dSsRt:hD:o:v::x::Vr:jJ:lW:L:M:"; static struct option long_opts[] = { { "tree", required_argument, 0, 't' }, { "leave-stopped", no_argument, 0, 's' }, From c77a52ec7fff8079727d027909ed15eafa16145f Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 12 Feb 2019 12:48:14 +0300 Subject: [PATCH 1936/4375] zdtm.py: expect test to fail if crfail flag is set Suppress the false positive fail in criu-live-migration job: https://ci.openvz.org/job/CRIU/job/criu-live-migration/job/criu-dev/1796/ [criu]# ./test/zdtm.py run -t zdtm/static/overmounted_file -f uns --lazy-migrate === Run 1/1 ================ zdtm/static/overmounted_file =================== Run zdtm/static/overmounted_file in uns ==================== Start test Test is SUID ./overmounted_file --pidfile=overmounted_file.pid --outfile=overmounted_file.out --dirname=overmounted_file.test Run criu dump Test zdtm/static/overmounted_file FAIL at criu dump exited with 1 ###### Send the 9 signal to 49 Wait for zdtm/static/overmounted_file(49) to die for 0.100000 Signed-off-by: Pavel Tikhomirov Signed-off-by: Andrei Vagin --- test/zdtm.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 7fd79a0b0..57a77f768 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1052,7 +1052,10 @@ class criu: os.close(status_fds[1]) if os.read(status_fds[0], 1) != b'\0': ret = ret.wait() - raise test_fail_exc("criu %s exited with %s" % (action, ret)) + if self.__test.blocking(): + raise test_fail_expected_exc(action) + else: + raise test_fail_exc("criu %s exited with %s" % (action, ret)) os.close(status_fds[0]) return ret From bac5566f0f8dd6b6e920b81558ed43e3e27eb845 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 15 Feb 2019 10:40:01 +0000 Subject: [PATCH 1937/4375] Fix typo in function name Signed-off-by: Radostin Stoyanov --- criu/cr-dump.c | 4 ++-- criu/image.c | 2 +- criu/include/crtools.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 78648baeb..d4ed40b91 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1482,7 +1482,7 @@ static int cr_pre_dump_finish(int status) if (ret) goto err; - ret = invertory_save_uptime(&he); + ret = inventory_save_uptime(&he); if (ret) goto err; @@ -1899,7 +1899,7 @@ int cr_dump_tasks(pid_t pid) if (ret) goto err; - ret = invertory_save_uptime(&he); + ret = inventory_save_uptime(&he); if (ret) goto err; diff --git a/criu/image.c b/criu/image.c index 13aeec69f..e1740ce94 100644 --- a/criu/image.c +++ b/criu/image.c @@ -107,7 +107,7 @@ int write_img_inventory(InventoryEntry *he) return 0; } -int invertory_save_uptime(InventoryEntry *he) +int inventory_save_uptime(InventoryEntry *he) { if (!opts.track_mem) return 0; diff --git a/criu/include/crtools.h b/criu/include/crtools.h index 7b2dc4523..c5a5b6499 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -12,7 +12,7 @@ extern int check_img_inventory(void); extern int write_img_inventory(InventoryEntry *he); -extern int invertory_save_uptime(InventoryEntry *he); +extern int inventory_save_uptime(InventoryEntry *he); extern InventoryEntry *get_parent_inventory(void); extern int prepare_inventory(InventoryEntry *he); struct pprep_head { From 4781e18244fd1883fb73760e0c3c99c3f2a54fbe Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 12 Feb 2019 22:59:12 +0000 Subject: [PATCH 1938/4375] criu(8): Update list of action-script hooks * "post-resume" was introduced with commit: 2ab599398ddbde3449f1b9d4d3f5152591854cff cr-restore: "post-resume" hook introduced This hook is called at the very end, when everything is restored and processes were resumed. Can be used for some actions, which require operation container, like restarting of systemd autofs services. * "post-setup-namespaces" was introduced with commit: eec66f3d30f9ccd75a8f1fab6920c20933eecd64 criu [PATCH] post-setup-namespaces Introduce post-setup-namespaces action script It needed to have possibility to run cutom script after mount namespace is configured * "orphan-pts-master" was introduced with commit: 6afe523d97d59e6bf29621b8aa0e6a4332f710fc tty: notify about orphan tty-s via rpc Now Docker creates a pty pair from a container devpts to use is as console. A slave tty is set as a control tty for the init process and bind-mounted into /dev/console. The master tty is handled externelly. Now CRIU can handle external resources, but here we have internal resources which are used externaly. Signed-off-by: Radostin Stoyanov --- Documentation/criu.txt | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index ea02613dd..53b92c28e 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -105,13 +105,17 @@ The following levels are available: *pre-restore*::: run prior to beginning a *restore* + *post-restore*::: + run upon *restore* completion + *pre-resume*::: run when all processes and resources are restored but tasks are stopped waiting for final kick to run. Must not fail. - *post-restore*::: - run upon *restore* completion + *post-resume*::: + called at the very end, when everything is + restored and processes were resumed *network-lock*::: run to lock network in a target network namespace @@ -120,10 +124,19 @@ The following levels are available: run to unlock network in a target network namespace *setup-namespaces*::: - run once root task just been created + run once root task has just been created with required namespaces. Note it is an early stage - of restore, when nothing is restored yet except for namespaces - themselves + of restore, when nothing is restored yet, except for + namespaces themselves + + *post-setup-namespaces*::: + called after the namespaces are configured + + *orphan-pts-master*::: + called after master pty is opened and unlocked. This + hook can be used only in the RPC mode, and the + notification message contains a file descriptor for + the master pty *-V*, *--version*:: Print program version and exit. From ee2916a56f6749cb17c3b0c32d72fcfcecd34f73 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 13 Feb 2019 13:32:36 +0000 Subject: [PATCH 1939/4375] util: Don't log errno on bad server address From man inet_pton(3): inet_pton() returns 1 on success (network address was successfully converted). 0 is returned if src does not contain a character string representing a valid network address in the specified address family. If af does not contain a valid address family, -1 is returned and errno is set to EAFNOSUPPORT. We can assume that the return value is 1 or 0 (because af is set to AF_INET4 or AF_INET6), therefore errno will not be set. If a user attempts to bind a server using invalid network address the following error message will be shown: Bad server address: Success Which is not very clear, with this change the error message will look like this: Invalid server address "localhost". The address must be in IPv4 or IPv6 format. Signed-off-by: Radostin Stoyanov --- criu/util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/util.c b/criu/util.c index 9221863ca..21e027fd7 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1250,7 +1250,8 @@ static int get_sockaddr_in(struct sockaddr_storage *addr, char *host, } else if (inet_pton(AF_INET6, host, &((struct sockaddr_in6 *)addr)->sin6_addr)) { addr->ss_family = AF_INET6; } else { - pr_perror("Bad server address"); + pr_err("Invalid server address \"%s\". " + "The address must be in IPv4 or IPv6 format.\n", host); return -1; } From 58fbe6de3a6bc92b540f1517b82c10361b86fe94 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 20 Feb 2019 18:27:25 +0000 Subject: [PATCH 1940/4375] page-xfer: Don't log addr/port on disconnect When the --ps-socket option is used with page-server, instead of --address and --port, this message would appear as: (00.028440) Disconnect from the page server (null):0 Signed-off-by: Radostin Stoyanov --- criu/page-xfer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index e5806124c..e3c9c7b25 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -1062,8 +1062,7 @@ int disconnect_from_page_server(void) if (page_server_sk == -1) return 0; - pr_info("Disconnect from the page server %s:%u\n", - opts.addr, opts.port); + pr_info("Disconnect from the page server\n"); if (opts.ps_socket != -1) /* From 681c05392df3476ee2d402fecc256e629b3b4fd9 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 18 Feb 2019 16:15:08 +0000 Subject: [PATCH 1941/4375] crit: display help message when using python3 Running crit with python2 gives following minimal help message: $ crit/crit usage: crit [-h] {decode,encode,info,x,show} ... crit: error: too few arguments Using a python3 only system crit shows the following error: $ crit/crit Traceback (most recent call last): File "crit/crit", line 6, in cli.main() File "/home/criu/crit/pycriu/cli.py", line 334, in main opts["func"](opts) KeyError: 'func' Using this patch the python3 output changes to: $ crit/crit usage: crit [-h] {decode,encode,info,x,show} ... crit: error: too few arguments Suggested-by: Andrei Vagin Signed-off-by: Adrian Reber --- lib/py/cli.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/py/cli.py b/lib/py/cli.py index 12597dbfb..abaf0720c 100755 --- a/lib/py/cli.py +++ b/lib/py/cli.py @@ -331,6 +331,11 @@ def main(): opts = vars(parser.parse_args()) + if not opts: + sys.stderr.write(parser.format_usage()) + sys.stderr.write("crit: error: too few arguments\n") + sys.exit(1) + opts["func"](opts) if __name__ == '__main__': From 635db4895afd9475f2bc526a94b455a8ffa27d2f Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 15 Feb 2019 09:53:48 +0000 Subject: [PATCH 1942/4375] socket-tcp-skip-in-flight: Don't fail on EAGAIN The server socket is marked as nonblocking, and if the client doesn't connect, accept() will fail and set errno to EAGAIN (or EWOULDBLOCK). Instead, use poll to wait for POLLIN event on the file descriptor. Suggested-by: Andrei Vagin Signed-off-by: Radostin Stoyanov --- test/zdtm/static/socket-tcp-skip-in-flight.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/socket-tcp-skip-in-flight.c b/test/zdtm/static/socket-tcp-skip-in-flight.c index 8805e7d1a..a26900a7d 100644 --- a/test/zdtm/static/socket-tcp-skip-in-flight.c +++ b/test/zdtm/static/socket-tcp-skip-in-flight.c @@ -1,3 +1,4 @@ +#include #include "zdtmtst.h" #ifdef ZDTM_IPV4V6 @@ -26,9 +27,11 @@ const char *test_author = "Radostin Stoyanov "; int main(int argc, char **argv) { + struct pollfd poll_set[1]; int port = 9990; int fd_s, fd_c, fd; int flags; + int ret; test_init(argc, argv); @@ -64,12 +67,20 @@ int main(int argc, char **argv) return -1; } + memset(poll_set, '\0', sizeof(poll_set)); + poll_set[0].fd = fd_s; + poll_set[0].events = POLLIN; + ret = poll(poll_set, 1, -1); + if (ret < 0) { + pr_perror("poll() failed"); + return 1; + } + fd = tcp_accept_server(fd_s); if (fd < 0) { fail("Unable to accept a new connection"); return 1; } - close(fd); close(fd_c); From fd9fb7d339ddf1d83139731f2d6b201c99b77c5d Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 15 Feb 2019 10:27:08 +0000 Subject: [PATCH 1943/4375] socket-tcp-skip-in-flight: Use set_nonblock Signed-off-by: Radostin Stoyanov --- test/zdtm/static/socket-tcp-skip-in-flight.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/zdtm/static/socket-tcp-skip-in-flight.c b/test/zdtm/static/socket-tcp-skip-in-flight.c index a26900a7d..99ca03ac5 100644 --- a/test/zdtm/static/socket-tcp-skip-in-flight.c +++ b/test/zdtm/static/socket-tcp-skip-in-flight.c @@ -30,7 +30,6 @@ int main(int argc, char **argv) struct pollfd poll_set[1]; int port = 9990; int fd_s, fd_c, fd; - int flags; int ret; test_init(argc, argv); @@ -39,9 +38,8 @@ int main(int argc, char **argv) if (fd_s < 0) return -1; - flags = fcntl(fd_s, F_GETFL, 0); - if (fcntl(fd_s, F_SETFL, flags | O_NONBLOCK)) { - pr_perror("Unable to set O_NONBLOCK"); + if (set_nonblock(fd_s, true)) { + pr_perror("setting O_NONBLOCK failed"); return -1; } From 44a3af2ddb12b919d51e6182093045dc816ff375 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 20 Feb 2019 09:51:39 +0000 Subject: [PATCH 1944/4375] page-xfer: Fix typo Signed-off-by: Radostin Stoyanov --- criu/include/page-xfer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index ee90ae65a..fa72273ea 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -57,7 +57,7 @@ extern int check_parent_page_xfer(int fd_type, unsigned long id); /* * The post-copy migration makes it necessary to receive pages from * remote dump. The protocol we use for that is quite simple: - * - lazy-pages sedns request containing PS_IOV_GET(nr_pages, vaddr, pid) + * - lazy-pages sends request containing PS_IOV_GET(nr_pages, vaddr, pid) * - dump-side page server responds with PS_IOV_ADD(nr_pages, vaddr, pid) or PS_IOV_ADD(0, 0, 0) if it failed to locate the required pages From 38769e94d622ca27396cf962475259f346babf82 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 18 Feb 2019 10:35:45 +0000 Subject: [PATCH 1945/4375] rpc/libcriu: Add lsm-profile option The --lsm-profile option allows a container engine to specify LSM profile name. Signed-off-by: Radostin Stoyanov --- criu/cr-service.c | 5 +++++ images/rpc.proto | 1 + lib/c/criu.c | 15 +++++++++++++++ lib/c/criu.h | 2 ++ 4 files changed, 23 insertions(+) diff --git a/criu/cr-service.c b/criu/cr-service.c index 7d841bb5d..368197703 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -589,6 +589,11 @@ static int setup_opts_from_req(int sk, CriuOpts *req) if (req->freeze_cgroup) SET_CHAR_OPTS(freeze_cgroup, req->freeze_cgroup); + if (req->lsm_profile) { + opts.lsm_supplied = true; + SET_CHAR_OPTS(lsm_profile, req->lsm_profile); + } + if (req->has_timeout) opts.timeout = req->timeout; diff --git a/images/rpc.proto b/images/rpc.proto index 5c8226d25..af0e99e30 100644 --- a/images/rpc.proto +++ b/images/rpc.proto @@ -113,6 +113,7 @@ message criu_opts { optional bool orphan_pts_master = 50; optional string config_file = 51; optional bool tcp_close = 52; + optional string lsm_profile = 53; } message criu_dump_resp { diff --git a/lib/c/criu.c b/lib/c/criu.c index 00ececa1f..6ac510a87 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -224,6 +224,7 @@ void criu_local_free_opts(criu_opts *opts) free(opts->rpc->root); free(opts->rpc->freeze_cgroup); free(opts->rpc->log_file); + free(opts->rpc->lsm_profile); free(opts->rpc); criu_free_service(opts); free(opts); @@ -596,6 +597,20 @@ int criu_set_freeze_cgroup(const char *name) return criu_local_set_freeze_cgroup(global_opts, name); } +int criu_local_set_lsm_profile(criu_opts *opts, const char *name) +{ + opts->rpc->lsm_profile = strdup(name); + if(opts->rpc->lsm_profile == NULL) { + return -ENOMEM; + } + return 0; +} + +int criu_set_lsm_profile(const char *name) +{ + return criu_local_set_lsm_profile(global_opts, name); +} + void criu_local_set_timeout(criu_opts *opts, unsigned int timeout) { opts->rpc->timeout = timeout; diff --git a/lib/c/criu.h b/lib/c/criu.h index c4d80a4fd..4462ce082 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -77,6 +77,7 @@ int criu_set_root(const char *root); void criu_set_manage_cgroups(bool manage); void criu_set_manage_cgroups_mode(enum criu_cg_mode mode); int criu_set_freeze_cgroup(const char *name); +int criu_set_lsm_profile(const char *name); void criu_set_timeout(unsigned int timeout); void criu_set_auto_ext_mnt(bool val); void criu_set_ext_sharing(bool val); @@ -188,6 +189,7 @@ int criu_local_set_root(criu_opts *opts, const char *root); void criu_local_set_manage_cgroups(criu_opts *opts, bool manage); void criu_local_set_manage_cgroups_mode(criu_opts *opts, enum criu_cg_mode mode); int criu_local_set_freeze_cgroup(criu_opts *opts, const char *name); +int criu_local_set_lsm_profile(criu_opts *opts, const char *name); void criu_local_set_timeout(criu_opts *opts, unsigned int timeout); void criu_local_set_auto_ext_mnt(criu_opts *opts, bool val); void criu_local_set_ext_sharing(criu_opts *opts, bool val); From d5d65ae2c40cb7200103d534f73cfa676d0d47f8 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 19 Feb 2019 19:58:48 +0000 Subject: [PATCH 1946/4375] seek_pagemap: Use pagemap_len() The variable `len` is used only to calculate the value of `end`. We already have the static inline function pagemap_len(), which can be used instead. Acked-by: Mike Rapoport Signed-off-by: Radostin Stoyanov --- criu/pagemap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/pagemap.c b/criu/pagemap.c index 8d00ca1e8..4c4e88685 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -150,8 +150,7 @@ static int seek_pagemap(struct page_read *pr, unsigned long vaddr) do { unsigned long start = pr->pe->vaddr; - unsigned long len = pr->pe->nr_pages * PAGE_SIZE; - unsigned long end = start + len; + unsigned long end = start + pagemap_len(pr->pe); if (vaddr < pr->cvaddr) break; From ee79bb3a1a7f9fbc0d2e8b9838128d2cd5edc5d5 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 22 Feb 2019 18:55:15 +0000 Subject: [PATCH 1947/4375] criu(8): Fix typo Signed-off-by: Radostin Stoyanov --- Documentation/criu.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 53b92c28e..414c9bb2d 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -568,8 +568,8 @@ Launches *criu* in page server mode. *--daemon*:: Runs page server as a daemon (background process). -*--status_fd*:: - Write \\0 to the FD and close it once page-server is ready to handle +*--status-fd*:: + Write \0 to the FD and close it once page-server is ready to handle requests. The status-fd allows to not daemonize a process and get its exit code at the end. It isn't supposed to use --daemon and --status-fd together. From d5cbd48a28ce679f92cc90e7eb439a6b770bde1e Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 13 Feb 2019 20:29:17 +0000 Subject: [PATCH 1948/4375] config: Add msg for obsolete use of port/address When the --ps-socket option is specified the provided file descriptor of a socket will be reused for incoming TCP connection. In such case the --address and --port options are ignored. Signed-off-by: Radostin Stoyanov --- criu/config.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/criu/config.c b/criu/config.c index 35085a42d..fdfb03064 100644 --- a/criu/config.c +++ b/criu/config.c @@ -842,6 +842,10 @@ int check_options() return 1; } + if (opts.ps_socket != -1 && (opts.addr || opts.port)) + pr_warn("Using --address or --port in " + "combination with --ps-socket is obsolete\n"); + if (check_namespace_opts()) { pr_err("Error: namespace flags conflict\n"); return 1; From 116e3cb64994e3dc1dfa66df953a1defa32c6d37 Mon Sep 17 00:00:00 2001 From: Mitul Karnik Date: Tue, 26 Feb 2019 10:03:02 +0000 Subject: [PATCH 1949/4375] test: Kill dead code from pipes test Signed-off-by: Mitul Karnik Signed-off-by: Andrei Vagin --- test/zdtm/static/pipe01.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/pipe01.c b/test/zdtm/static/pipe01.c index 85478b6ea..ec8d1fb61 100644 --- a/test/zdtm/static/pipe01.c +++ b/test/zdtm/static/pipe01.c @@ -108,8 +108,8 @@ int main(int argc, char ** argv) if (ret == 0) break; if (ret == -1) { - goto err; pr_perror("read() failed"); + goto err; } size -= ret; From 7f4779059d4c4090fb8ad27911e789aaef26464b Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 24 Feb 2019 23:00:26 +0000 Subject: [PATCH 1950/4375] util: Introduce fd_set_nonblocking() Combine the functionality of socket_set_non_blocking() and socket_set_blocking() into a new function, and move it in criu/util.c to enable reusability throughout the code base. Signed-off-by: Radostin Stoyanov --- criu/include/util.h | 1 + criu/util.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/criu/include/util.h b/criu/include/util.h index 1e2fec81e..5b91696ad 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -274,6 +274,7 @@ static inline int sk_wait_data(int sk) return poll(&pfd, 1, -1); } +void fd_set_nonblocking(int fd, bool on); void tcp_nodelay(int sk, bool on); void tcp_cork(int sk, bool on); diff --git a/criu/util.c b/criu/util.c index 21e027fd7..8a31e36f9 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1116,6 +1116,24 @@ int fd_has_data(int lfd) return ret; } +void fd_set_nonblocking(int fd, bool on) +{ + int flags = fcntl(fd, F_GETFL, NULL); + + if (flags < 0) { + pr_perror("Failed to obtain flags from fd %d", fd); + return; + } + + if (on) + flags |= O_NONBLOCK; + else + flags &= (~O_NONBLOCK); + + if (fcntl(fd, F_SETFL, flags) < 0) + pr_perror("Failed to set flags for fd %d", fd); +} + int make_yard(char *path) { if (mount("none", path, "tmpfs", 0, NULL)) { From a2565001854cd131e95ded5281f8f29b316fe538 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 26 Feb 2019 09:39:36 +0000 Subject: [PATCH 1951/4375] Rename version protobuf RPC members In rpc.proto the interface to query the CRIU version number uses major and minor as keywords. This creates errors when using the RPC definitions with C++: https://github.com/checkpoint-restore/criu/issues/625 In this commit the fields are renamed from major to major_number and from minor to minor_number. For existing programs using the RPC protobuf definition this should be a transparent change. Only for programs importing the latest rpc.proto it will require code changes. Signed-off-by: Adrian Reber --- criu/cr-service.c | 4 ++-- images/rpc.proto | 4 ++-- test/others/rpc/test.py | 4 ++-- test/others/rpc/version.py | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 368197703..1f1e5fa86 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -969,8 +969,8 @@ static int handle_version(int sk, CriuReq * msg) CriuVersion version = CRIU_VERSION__INIT; /* This assumes we will always have a major and minor version */ - version.major = CRIU_VERSION_MAJOR; - version.minor = CRIU_VERSION_MINOR; + version.major_number = CRIU_VERSION_MAJOR; + version.minor_number = CRIU_VERSION_MINOR; if (strcmp(CRIU_GITID, "0")) { version.gitid = CRIU_GITID; } diff --git a/images/rpc.proto b/images/rpc.proto index af0e99e30..e67471706 100644 --- a/images/rpc.proto +++ b/images/rpc.proto @@ -211,8 +211,8 @@ message criu_resp { /* Answer for criu_req_type.VERSION requests */ message criu_version { - required int32 major = 1; - required int32 minor = 2; + required int32 major_number = 1; + required int32 minor_number = 2; optional string gitid = 3; optional int32 sublevel = 4; optional int32 extra = 5; diff --git a/test/others/rpc/test.py b/test/others/rpc/test.py index fe67103ba..0addbaedc 100755 --- a/test/others/rpc/test.py +++ b/test/others/rpc/test.py @@ -66,8 +66,8 @@ if resp.type != rpc.VERSION: else: if resp.success: print('RPC: Success') - print('CRIU major %d' % resp.version.major) - print('CRIU minor %d' % resp.version.minor) + print('CRIU major %d' % resp.version.major_number) + print('CRIU minor %d' % resp.version.minor_number) if resp.version.HasField('gitid'): print('CRIU gitid %s' % resp.version.gitid) if resp.version.HasField('sublevel'): diff --git a/test/others/rpc/version.py b/test/others/rpc/version.py index 5cca4e249..247bc466d 100755 --- a/test/others/rpc/version.py +++ b/test/others/rpc/version.py @@ -32,8 +32,8 @@ if resp.type != rpc.VERSION: else: if resp.success: print('RPC: Success') - print('CRIU major %d' % resp.version.major) - print('CRIU minor %d' % resp.version.minor) + print('CRIU major %d' % resp.version.major_number) + print('CRIU minor %d' % resp.version.minor_number) if resp.version.HasField('gitid'): print('CRIU gitid %s' % resp.version.gitid) if resp.version.HasField('sublevel'): From 051ab38a2980a4d547ee7d50d0aa61e68637769b Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 7 Mar 2019 09:34:35 +0000 Subject: [PATCH 1952/4375] Remove irrelevant comment Support for printing early log messages was recently added, which makes this comment is no longer relevant. Signed-off-by: Radostin Stoyanov --- criu/files.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/criu/files.c b/criu/files.c index 31f847ee9..38b12ee4f 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1479,10 +1479,6 @@ struct inherit_fd { int inh_fd_max = -1; -/* - * We can't print diagnostics messages in this function because the - * log file isn't initialized yet. - */ int inherit_fd_parse(char *optarg) { char *cp = NULL; From 8bb2f2293730c12a884fd77c0d5d4f143cf26eb8 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 8 Mar 2019 08:07:49 +0000 Subject: [PATCH 1953/4375] readme: Update asciinema demo Signed-off-by: Radostin Stoyanov --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e28964604..95608a9ea 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,8 @@ Pages worth starting with are: - [Examples of more advanced usage](https://criu.org/Category:HOWTO) - Troubleshooting can be hard, some help can be found [here](https://criu.org/When_C/R_fails), [here](https://criu.org/What_cannot_be_checkpointed) and [here](https://criu.org/FAQ) -### A video tour on basic CRIU features -[![CRIU introduction](https://asciinema.org/a/7fnt2prsumvxiwf3ng61fgct3.png)](https://asciinema.org/a/7fnt2prsumvxiwf3ng61fgct3) +### Checkpoint and restore of simple loop process +[

](https://asciinema.org/a/232445) ## Advanced features From 3608293773459d6e46d223c6def964cb0e29e771 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 13 Mar 2019 12:48:19 +0000 Subject: [PATCH 1954/4375] criu: fix gcc9 rawhide compilation errors Signed-off-by: Adrian Reber --- compel/arch/x86/src/lib/include/uapi/asm/fpu.h | 12 +++++++----- compel/arch/x86/src/lib/include/uapi/asm/sigframe.h | 2 +- criu/arch/x86/include/asm/restore.h | 2 +- criu/sk-unix.c | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h index a32a00e9c..896c3f253 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h @@ -12,7 +12,9 @@ #define FP_XSTATE_MAGIC1 0x46505853U #define FP_XSTATE_MAGIC2 0x46505845U +#ifndef FP_XSTATE_MAGIC2_SIZE #define FP_XSTATE_MAGIC2_SIZE sizeof(FP_XSTATE_MAGIC2) +#endif #define XSTATE_FP 0x1 #define XSTATE_SSE 0x2 @@ -261,7 +263,7 @@ struct xsave_struct_ia32 { struct ymmh_struct ymmh; uint8_t extended_state_area[EXTENDED_STATE_AREA_SIZE]; }; -} __aligned(FXSAVE_ALIGN_BYTES) __packed; +} __aligned(FXSAVE_ALIGN_BYTES); typedef struct { /* @@ -286,7 +288,7 @@ struct user_i387_ia32_struct { uint32_t foo; /* FPU Operand Pointer Offset */ uint32_t fos; /* FPU Operand Pointer Selector */ uint32_t st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ -} __packed; +}; typedef struct { struct { @@ -294,12 +296,12 @@ typedef struct { /* Software status information [not touched by FSAVE]: */ uint32_t status; - } __packed fregs_state; + } fregs_state; union { struct xsave_struct_ia32 xsave; uint8_t __pad[sizeof(struct xsave_struct) + FP_XSTATE_MAGIC2_SIZE]; - } __aligned(FXSAVE_ALIGN_BYTES) __packed; -} __aligned(FXSAVE_ALIGN_BYTES) __packed fpu_state_ia32_t; + } __aligned(FXSAVE_ALIGN_BYTES); +} __aligned(FXSAVE_ALIGN_BYTES) fpu_state_ia32_t; /* * This one is used in restorer. diff --git a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h index c29de3bd5..768fb61ab 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h @@ -95,7 +95,7 @@ struct ucontext_ia32 { compat_stack_t uc_stack; struct rt_sigcontext_32 uc_mcontext; k_rtsigset_t uc_sigmask; /* mask last for extensibility */ -} __packed; +}; struct rt_sigframe_ia32 { uint32_t pretcode; diff --git a/criu/arch/x86/include/asm/restore.h b/criu/arch/x86/include/asm/restore.h index a3e7af92f..21787a7c8 100644 --- a/criu/arch/x86/include/asm/restore.h +++ b/criu/arch/x86/include/asm/restore.h @@ -17,7 +17,7 @@ : "g"(new_sp), \ "g"(restore_task_exec_start), \ "g"(task_args) \ - : "rsp", "rdi", "rsi", "rbx", "rax", "memory") + : "rdi", "rsi", "rbx", "rax", "memory") static inline void core_get_tls(CoreEntry *pcore, tls_t *ptls) { diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 90124ed07..26123515c 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -437,8 +437,8 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) */ if (peer->peer_ino != ue->ino) { if (!peer->name) { - pr_err("Unix socket %d with unreachable peer %d (%d/%s)\n", - ue->ino, ue->peer, peer->peer_ino, peer->name); + pr_err("Unix socket %d with unreachable peer %d (%d)\n", + ue->ino, ue->peer, peer->peer_ino); goto err; } } From 31f3a6a737d23ef2d41f5e7526bebeffc637316d Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 13 Mar 2019 14:34:10 +0000 Subject: [PATCH 1955/4375] test: fix compilation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit binfmt_misc.c:168:23: error: ‘sprintf’ may write a terminating nul past the end of the destination [-Werror=format-overflow=] 168 | sprintf(path, "%s/%s", dirname, NAME[i]); | ^ Signed-off-by: Adrian Reber --- test/zdtm/static/binfmt_misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/binfmt_misc.c b/test/zdtm/static/binfmt_misc.c index fec7e0353..72ab8c1ec 100644 --- a/test/zdtm/static/binfmt_misc.c +++ b/test/zdtm/static/binfmt_misc.c @@ -98,7 +98,7 @@ int dump_content(const char *path, char **dump) int main(int argc, char **argv) { char buf[MAX_REG_STR + 1]; - char path[PATH_MAX]; + char path[PATH_MAX*2 + 1]; char *dump[2]; int i, fd, len; From 9f176a9686717f235c1425b98775e48a75aeebe9 Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Thu, 14 Feb 2019 13:42:14 +0530 Subject: [PATCH 1956/4375] Access pathname relative to root of mntns Use faccessat() in check_path_remap() to check if the file (relative to root of mnt ns) is accessible or not. Signed-off-by: Ashutosh Mehra --- criu/files-reg.c | 5 +++- test/zdtm/static/Makefile | 1 + test/zdtm/static/pid_file.c | 52 +++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 test/zdtm/static/pid_file.c diff --git a/criu/files-reg.c b/criu/files-reg.c index 360ba7511..1a35166a5 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1137,6 +1137,9 @@ static int check_path_remap(struct fd_link *link, const struct fd_parms *parms, */ if (pid != 0) { bool is_dead = strip_deleted(link); + mntns_root = mntns_get_root_fd(nsid); + if (mntns_root < 0) + return -1; /* /proc/ will be "/proc/1 (deleted)" when it is * dead, but a path like /proc/1/mountinfo won't have @@ -1148,7 +1151,7 @@ static int check_path_remap(struct fd_link *link, const struct fd_parms *parms, */ if (!is_dead) { *end = 0; - is_dead = access(rpath, F_OK); + is_dead = faccessat(mntns_root, rpath, F_OK, 0); *end = '/'; } diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index a31c202d5..912168cfc 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -209,6 +209,7 @@ TST_NOFILE := \ unlink_multiple_largefiles \ config_inotify_irmap \ thp_disable \ + pid_file \ # jobctl00 \ ifneq ($(SRCARCH),arm) diff --git a/test/zdtm/static/pid_file.c b/test/zdtm/static/pid_file.c new file mode 100644 index 000000000..3ee6a3942 --- /dev/null +++ b/test/zdtm/static/pid_file.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check that environment didn't change"; +const char *test_author = "Andrei Vagin "; + +int main(int argc, char **argv) +{ + int fd, fd2; + struct stat st, st2; + + test_init(argc, argv); + + fd = open("/proc/1/status", O_RDONLY); + if (fd < 0) { + pr_perror("Unable to open /proc/1/status"); + return 1; + } + + test_daemon(); + test_waitsig(); + + fd2 = open("/proc/1/status", O_RDONLY); + if (fd2 < 0) { + pr_perror("Unable to open /proc/1/status"); + return 1; + } + if (fstat(fd, &st)) { + pr_perror("fstat"); + return 1; + } + if (fstat(fd2, &st2)) { + pr_perror("fstat"); + return 1; + } + close(fd); + close(fd2); + + if (st.st_ino != st2.st_ino) { + fail("inode numbers mismatch"); + return 1; + } + + pass(); + return 0; +} From 861afa0bc788ac347ee51de5c762c0cc6a217073 Mon Sep 17 00:00:00 2001 From: Mitul Karnik Date: Sat, 16 Mar 2019 14:52:04 +0000 Subject: [PATCH 1957/4375] Removing Unneeded Return Value Assignments Removed return value assignment statements as they are not referenced or used anywhere after the assignment is done. Fixes #334: Removing Unneeded Assignments Signed-off-by: Mitul Karnik Signed-off-by: Andrei Vagin --- compel/arch/s390/src/lib/infect.c | 2 +- criu/path.c | 2 +- test/zdtm/static/dumpable02.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compel/arch/s390/src/lib/infect.c b/compel/arch/s390/src/lib/infect.c index 940d04418..b690b8122 100644 --- a/compel/arch/s390/src/lib/infect.c +++ b/compel/arch/s390/src/lib/infect.c @@ -455,7 +455,7 @@ void *remote_mmap(struct parasite_ctl *ctl, if (ptrace_poke_area(pid, &arg_struct, where, sizeof(arg_struct))) { pr_err("Can't restore mmap args (pid: %d)\n", pid); if (map != 0) { - err = compel_syscall(ctl, __NR_munmap, NULL, map, + compel_syscall(ctl, __NR_munmap, NULL, map, length, 0, 0, 0, 0); map = 0; } diff --git a/criu/path.c b/criu/path.c index 70b0c472c..22a89a4aa 100644 --- a/criu/path.c +++ b/criu/path.c @@ -99,7 +99,7 @@ char *mnt_get_sibling_path(struct mount_info *m, rpath++; if (rpath[0] != '\0') - off = snprintf(path, len, "/%s", rpath); + snprintf(path, len, "/%s", rpath); return buf; } diff --git a/test/zdtm/static/dumpable02.c b/test/zdtm/static/dumpable02.c index bd632e13e..024371bd8 100644 --- a/test/zdtm/static/dumpable02.c +++ b/test/zdtm/static/dumpable02.c @@ -143,8 +143,8 @@ int main(int argc, char **argv) return 1; } - ret = execl(argv[0], "dumpable_server", NULL); - pr_perror("could not execv %s as a dumpable_server", argv[0]); + execl(argv[0], "dumpable_server", NULL); + pr_perror("could not execv %s as a dumpable_server\nError No: %d", argv[0], errno); return 1; } From 79fbdb92c1be02f14a6459b552ee658af5939431 Mon Sep 17 00:00:00 2001 From: Harshavardhan Unnibhavi Date: Sat, 9 Mar 2019 13:39:19 +0530 Subject: [PATCH 1958/4375] action-scripts: Reducing scope of variables https://github.com/checkpoint-restore/criu/issues/329 Signed-off-by: Harshavardhan Unnibhavi Signed-off-by: Andrei Vagin --- criu/action-scripts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/action-scripts.c b/criu/action-scripts.c index 2803ec0f7..2f7617c0f 100644 --- a/criu/action-scripts.c +++ b/criu/action-scripts.c @@ -49,7 +49,6 @@ static int run_shell_scripts(const char *action) { int retval = 0; struct script *script; - char image_dir[PATH_MAX]; static unsigned env_set = 0; #define ENV_IMGDIR 0x1 @@ -61,6 +60,7 @@ static int run_shell_scripts(const char *action) } if (!(env_set & ENV_IMGDIR)) { + char image_dir[PATH_MAX]; sprintf(image_dir, "/proc/%ld/fd/%d", (long) getpid(), get_service_fd(IMG_FD_OFF)); if (setenv("CRTOOLS_IMAGE_DIR", image_dir, 1)) { pr_perror("Can't set CRTOOLS_IMAGE_DIR=%s", image_dir); @@ -71,10 +71,10 @@ static int run_shell_scripts(const char *action) if (!(env_set & ENV_ROOTPID) && root_item) { int pid; - char root_item_pid[16]; pid = root_item->pid->real; if (pid != -1) { + char root_item_pid[16]; snprintf(root_item_pid, sizeof(root_item_pid), "%d", pid); if (setenv("CRTOOLS_INIT_PID", root_item_pid, 1)) { pr_perror("Can't set CRTOOLS_INIT_PID=%s", root_item_pid); From fd1653b85171ba13383d0260c2968bc83077f814 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 12 Mar 2019 21:55:13 +0300 Subject: [PATCH 1959/4375] tty: Make params setup synchronous It was never designed to run params in ansync mode, and i always been against this change because async here is too fragile. p.s.: I think this might be a reason for https://github.com/checkpoint-restore/criu/issues/647 Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/tty.c b/criu/tty.c index ad9574858..6fe11530a 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -894,7 +894,7 @@ static int restore_tty_params(int fd, struct tty_info *info) } } - return userns_call(do_restore_tty_parms, UNS_ASYNC, &p, sizeof(p), fd); + return userns_call(do_restore_tty_parms, 0, &p, sizeof(p), fd); } /* From d9c51a703478d4099ba104e244c43bead0b59e0e Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 12 Mar 2019 11:30:21 +0000 Subject: [PATCH 1960/4375] lsm: dump and restore any SELinux process label There was support for SELinux process labels in CRIU but because it was never tested or verified CRIU only supported the 'unconfined_t' process label. This was basically no SELinux support. For successful container checkpoint and restore on a SELinux enabled host it is necessary that the restored container has the same process context as before checkpointing. This commit only removes the check if the label is 'unconfined_t' and now stores any process label to be restored. For 'normal' processes started from the command-line which are usually running in the 'unconfined_t' this just works. For the container use case this needs additional policies. The latest container-selinux package on Fedora has the necessary policy to allow CRIU (running as 'container_runtime_t' when used from Podman) to transition the restored process to 'container_t'. Restoring a process running under systemd's control (which means 'unconfined_service_t' without additional policies) will fail because CRIU will be not allowed to change the context of the restored process. For each additional CRIU use case on SELinux enabled systems, besides container processes and command-line/shell processes, additional SELinux policies are required to allow CRIU to do a 'dyntransition' (change the Signed-off-by: Adrian Reber --- criu/lsm.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/criu/lsm.c b/criu/lsm.c index eec73ede5..849ec37cd 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -62,45 +62,41 @@ static int apparmor_get_label(pid_t pid, char **profile_name) static int selinux_get_label(pid_t pid, char **output) { security_context_t ctx; - char *pos, *last; + char *pos; int i; + int ret = -1; if (getpidcon_raw(pid, &ctx) < 0) { pr_perror("getting selinux profile failed"); return -1; } - *output = NULL; + *output = xstrdup((char *)ctx); + if (!*output) + goto err; /* - * Since SELinux attributes can be finer grained than at the task - * level, and we currently don't try to dump any of these other bits, - * let's only allow unconfined profiles, which look something like: + * Make sure it is a valid SELinux label. It should look like this: * * unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 */ pos = (char*)ctx; for (i = 0; i < 3; i++) { - last = pos; pos = strstr(pos, ":"); if (!pos) { pr_err("Invalid selinux context %s\n", (char *)ctx); - freecon(ctx); - return -1; + xfree(*output); + goto err; } *pos = 0; - if (!strstartswith(last, "unconfined_")) { - pr_err("Non unconfined selinux contexts not supported %s\n", last); - freecon(ctx); - return -1; - } - pos++; } - freecon(ctx); - return 0; + ret = 0; +err: + freecon(ctx); + return ret; } #endif From b701774f9dd8cc311c98ffdc7988ee6fddb27407 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 12 Mar 2019 18:32:51 +0000 Subject: [PATCH 1961/4375] net: add correct SELinux label to parasite socket If running on a system with SELinux enabled the socket for the communication between parasite daemon and the main CRIU process needs to be correctly labeled. Initially this was motivated by Podman's use case: The container is usually running as something like '...:...:container_t:...:....' and CRIU started from runc and Podman will run as '...:...:container_runtime_t:...:...'. As the parasite will be running with the same context as the container process: 'container_t'. Allowing a container process to connect via socket to the outside of the container ('container_runtime_t') is not desired and therefore CRIU needs to label the socket with the context of the container: 'container_t'. So this first gets the context of the root container process and tells SELinux to label the next created socket with the same label as the root container process. For this to work it is necessary to have the correct SELinux policies installed. For Fedora based systems this is part of the container-selinux package. This assumes that all processes CRIU wants to dump are labeled with the same SELinux context. If some of the child processes have different labels this will not work and needs additional SELinux policies. But the whole SELinux socket labeling relies on the correct SELinux being available. Signed-off-by: Adrian Reber --- criu/net.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/criu/net.c b/criu/net.c index dff6083ad..a5f632dd6 100644 --- a/criu/net.c +++ b/criu/net.c @@ -17,6 +17,10 @@ #include #include +#ifdef CONFIG_HAS_SELINUX +#include +#endif + #include "../soccr/soccr.h" #include "imgset.h" @@ -40,6 +44,7 @@ #include "protobuf.h" #include "images/netdev.pb-c.h" +#include "images/inventory.pb-c.h" #ifndef IFLA_LINK_NETNSID #define IFLA_LINK_NETNSID 37 @@ -2718,6 +2723,54 @@ static int prep_ns_sockets(struct ns_id *ns, bool for_dump) } else ns->net.nlsk = -1; +#ifdef CONFIG_HAS_SELINUX + /* + * If running on a system with SELinux enabled the socket for the + * communication between parasite daemon and the main + * CRIU process needs to be correctly labeled. + * Initially this was motivated by Podman's use case: The container + * is usually running as something like '...:...:container_t:...:....' + * and CRIU started from runc and Podman will run as + * '...:...:container_runtime_t:...:...'. As the parasite will be + * running with the same context as the container process: 'container_t'. + * Allowing a container process to connect via socket to the outside + * of the container ('container_runtime_t') is not desired and + * therefore CRIU needs to label the socket with the context of + * the container: 'container_t'. + * So this first gets the context of the root container process + * and tells SELinux to label the next created socket with + * the same label as the root container process. + * For this to work it is necessary to have the correct SELinux + * policies installed. For Fedora based systems this is part + * of the container-selinux package. + */ + security_context_t ctx; + + /* + * This assumes that all processes CRIU wants to dump are labeled + * with the same SELinux context. If some of the child processes + * have different labels this will not work and needs additional + * SELinux policies. But the whole SELinux socket labeling relies + * on the correct SELinux being available. + */ + if (kdat.lsm == LSMTYPE__SELINUX) { + ret = getpidcon_raw(root_item->pid->real, &ctx); + if (ret < 0) { + pr_perror("Getting SELinux context for PID %d failed", + root_item->pid->real); + goto err_sq; + } + + ret = setsockcreatecon(ctx); + freecon(ctx); + if (ret < 0) { + pr_perror("Setting SELinux socket context for PID %d failed", + root_item->pid->real); + goto err_sq; + } + } +#endif + ret = ns->net.seqsk = socket(PF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK, 0); if (ret < 0) { pr_perror("Can't create seqsk for parasite"); @@ -2725,6 +2778,23 @@ static int prep_ns_sockets(struct ns_id *ns, bool for_dump) } ret = 0; + +#ifdef CONFIG_HAS_SELINUX + /* + * Once the socket has been created, reset the SELinux socket labelling + * back to the default value of this process. + */ + if (kdat.lsm == LSMTYPE__SELINUX) { + ret = setsockcreatecon_raw(NULL); + if (ret < 0) { + pr_perror("Resetting SELinux socket context to " + "default for PID %d failed", + root_item->pid->real); + goto err_ret; + } + } +#endif + out: if (nsret >= 0 && restore_ns(nsret, &net_ns_desc) < 0) { nsret = -1; From 2844b95f67aae4c9867fc307d4996373d9a6bb8e Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Fri, 22 Mar 2019 07:55:18 +0000 Subject: [PATCH 1962/4375] test: add selinux00 test This tests if CRIU can restore a process with the same policy as during checkpointing. The test selinux00 is started and if SELinux is available the test process moves itself to another process context. To make this possible either a new SELinux policy needs to be available containing: https://github.com/fedora-selinux/selinux-policy/commit/2d537cabbb2df614ea598ac20873c653cbf271a8 Or for a short time SELinux is switched to permissive mode. The correct SELinux setup is done by zdtm/static/selinux00.checkskip and zdtm/static/selinux00.hook and after the test the previous SELinux policy state is restored. After the test case is restored the test case checks if it still has the same SELinux process context as before. If not the test cases fails. Signed-off-by: Adrian Reber --- test/zdtm/static/Makefile | 1 + test/zdtm/static/selinux00.c | 108 +++++++++++++++++++++++++++ test/zdtm/static/selinux00.checkskip | 25 +++++++ test/zdtm/static/selinux00.desc | 1 + test/zdtm/static/selinux00.hook | 32 ++++++++ 5 files changed, 167 insertions(+) create mode 100644 test/zdtm/static/selinux00.c create mode 100755 test/zdtm/static/selinux00.checkskip create mode 100644 test/zdtm/static/selinux00.desc create mode 100755 test/zdtm/static/selinux00.hook diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 912168cfc..8e3f39276 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -210,6 +210,7 @@ TST_NOFILE := \ config_inotify_irmap \ thp_disable \ pid_file \ + selinux00 \ # jobctl00 \ ifneq ($(SRCARCH),arm) diff --git a/test/zdtm/static/selinux00.c b/test/zdtm/static/selinux00.c new file mode 100644 index 000000000..dd9096a6f --- /dev/null +++ b/test/zdtm/static/selinux00.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "zdtmtst.h" + +/* Enabling the right policy happens in selinux00.hook and selinx00.checkskip */ + +const char *test_doc = "Check that a SELinux profile is restored"; +const char *test_author = "Adrian Reber "; + +/* This is all based on Tycho's apparmor code */ + +#define CONTEXT "unconfined_u:unconfined_r:unconfined_dbusd_t:s0" + +/* + * This is used to store the state of SELinux. For this test + * SELinux is switched to permissive mode and later the previous + * SELinux state is restored. + */ +char state; + +int check_for_selinux() +{ + if (access("/sys/fs/selinux", F_OK) == 0) + return 0; + return 1; +} + +int setprofile() +{ + int fd, len; + + fd = open("/proc/self/attr/current", O_WRONLY); + if (fd < 0) { + fail("Could not open /proc/self/attr/current\n"); + return -1; + } + + len = write(fd, CONTEXT, strlen(CONTEXT)); + close(fd); + + if (len < 0) { + fail("Could not write context\n"); + return -1; + } + + return 0; +} + +int checkprofile() +{ + int fd; + char context[1024]; + int len; + + + fd = open("/proc/self/attr/current", O_RDONLY); + if (fd < 0) { + fail("Could not open /proc/self/attr/current\n"); + return -1; + } + + len = read(fd, context, strlen(CONTEXT)); + close(fd); + if (len != strlen(CONTEXT)) { + fail("SELinux context has unexpected length %d, expected %zd\n", + len, strlen(CONTEXT)); + return -1; + } + + if (strncmp(context, CONTEXT, strlen(CONTEXT)) != 0) { + fail("Wrong SELinux context %s expected %s\n", context, CONTEXT); + return -1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + test_init(argc, argv); + + if (check_for_selinux()) { + skip("SELinux not found on this system."); + test_daemon(); + test_waitsig(); + pass(); + return 0; + } + + if (setprofile()) + return -1; + + test_daemon(); + test_waitsig(); + + if (checkprofile() == 0) + pass(); + + return 0; +} diff --git a/test/zdtm/static/selinux00.checkskip b/test/zdtm/static/selinux00.checkskip new file mode 100755 index 000000000..8d946a75e --- /dev/null +++ b/test/zdtm/static/selinux00.checkskip @@ -0,0 +1,25 @@ +#!/bin/bash + +test -d /sys/fs/selinux || exit 1 + +# See selinux00.hook for details + +getsebool unconfined_dyntrans_all > /dev/null 2>&1 +RESULT=$? +BOOLEAN=0 + +if [ "$RESULT" = "0" ]; then + BOOLEAN=1 +fi + +if [ "$BOOLEAN" = "1" ]; then + getsebool unconfined_dyntrans_all | grep off -q + RESULT=$? + echo $RESULT > /tmp/zdtm.selinux.state + if [ "$RESULT" = "0" ]; then + setsebool -P unconfined_dyntrans_all 1 + fi +else + cat /sys/fs/selinux/enforce > /tmp/zdtm.selinux.state + setenforce 0 +fi diff --git a/test/zdtm/static/selinux00.desc b/test/zdtm/static/selinux00.desc new file mode 100644 index 000000000..63df42aa6 --- /dev/null +++ b/test/zdtm/static/selinux00.desc @@ -0,0 +1 @@ +{'flavor': 'h'} diff --git a/test/zdtm/static/selinux00.hook b/test/zdtm/static/selinux00.hook new file mode 100755 index 000000000..300766e1f --- /dev/null +++ b/test/zdtm/static/selinux00.hook @@ -0,0 +1,32 @@ +#!/bin/sh + +# This script configures SELinux in such a way to enable the +# test 'selinux00' to be able to dyntransition from one +# SELinux context to another, as well as CRIU to change the +# context of a restored process. +# If a new enough selinux-policy is installed which includes +# https://github.com/fedora-selinux/selinux-policy/commit/2d537cabbb2df614ea598ac20873c653cbf271a8 +# then the boolean 'unconfined_dyntrans_all' will be changed +# to enable this test. If that boolean is not available, +# this just does 'setenforce 0'. + +# also see selinux00.checkskip + +getsebool unconfined_dyntrans_all > /dev/null 2>&1 +RESULT=$? +BOOLEAN=0 + +if [ "$RESULT" = "0" ]; then + BOOLEAN=1 +fi + +[ "$1" = "--post-restore" ] && { + if [ "$BOOLEAN" = "1" ]; then + setsebool -P unconfined_dyntrans_all `cat /tmp/zdtm.selinux.state` + else + setenforce `cat /tmp/zdtm.selinux.state` + rm -f /tmp/zdtm.selinux.state + fi +} + +exit 0 From b3a199186d4393be4c6f127eeb5942ef60976c87 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 22 Mar 2019 21:03:48 +0000 Subject: [PATCH 1963/4375] docker-test: Fix deprecated security-opt format The flag --security-opt doesn't use the colon separator (:) anymore to divide keys and values, instead it uses the equal symbol (=) for consistency with other similar flags, like --storage-opt. Deprecated in release: v1.11.0 Target for removal in release: v17.06 https://docs.docker.com/engine/deprecated/ #653 Signed-off-by: Radostin Stoyanov --- scripts/travis/docker-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/travis/docker-test.sh b/scripts/travis/docker-test.sh index 14868e960..ee96fef48 100755 --- a/scripts/travis/docker-test.sh +++ b/scripts/travis/docker-test.sh @@ -39,7 +39,7 @@ docker info criu --version -docker run --tmpfs /tmp --tmpfs /run --read-only --security-opt=seccomp:unconfined --name cr -d alpine /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done' +docker run --tmpfs /tmp --tmpfs /run --read-only --security-opt seccomp=unconfined --name cr -d alpine /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done' sleep 1 for i in `seq 50`; do From 0d5c0b2d3a32cd86562b80dd788eb8efd18d7ae6 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 28 Mar 2019 00:15:31 -0700 Subject: [PATCH 1964/4375] scripts/build: use the last stable release for s390 And get qemu-static from the 18.04 LTS Ubuntu repos. https://github.com/checkpoint-restore/criu/issues/652 Signed-off-by: Andrei Vagin --- scripts/build/Dockerfile.s390x.hdr | 2 +- scripts/build/extract-deb-pkg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build/Dockerfile.s390x.hdr b/scripts/build/Dockerfile.s390x.hdr index 7c92fe093..e02097f62 100644 --- a/scripts/build/Dockerfile.s390x.hdr +++ b/scripts/build/Dockerfile.s390x.hdr @@ -1,4 +1,4 @@ -FROM s390x/debian:jessie-backports +FROM s390x/debian:latest ENV QEMU_CPU z900 COPY scripts/build/qemu-user-static/usr/bin/qemu-s390x-static /usr/bin/qemu-s390x-static diff --git a/scripts/build/extract-deb-pkg b/scripts/build/extract-deb-pkg index f2c9e9238..44457bc5a 100755 --- a/scripts/build/extract-deb-pkg +++ b/scripts/build/extract-deb-pkg @@ -4,7 +4,7 @@ set -e set -u set -o pipefail MIRROR="https://mirrors.kernel.org/ubuntu" -PKGS="$MIRROR/dists/xenial/universe/binary-amd64/Packages.gz" +PKGS="$MIRROR/dists/bionic/universe/binary-amd64/Packages.gz" if [ $# -ne 1 ]; then echo "Usage: $0 package-name" 1>&2 From 1bc3e588dddbbbd7370ac6291e05b67247479dc5 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 26 Mar 2019 20:01:40 +0000 Subject: [PATCH 1965/4375] restore: support restoring threads with SELinux Restoring a multi-threaded process with CRIU's SELinux support fails because SELinux does not always support changing the process context of a multi-threaded process. Reading the man-page for setcon(), to change the context of a running process, it states that changing the SELinux context of a multi-threaded process can only work 'if the new security context is bounded by the old security context'. To be able to restore a process without the need to have 'the new security context [] bounded by the old security context', this sets the SELinux process context before creating the threads. Thus all threads are created with the process context of the main process. Signed-off-by: Adrian Reber --- criu/cr-restore.c | 7 +++++++ criu/include/restorer.h | 1 + criu/pie/restorer.c | 30 +++++++++++++++++++++++++----- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 75976dfa1..c9904faf0 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3527,6 +3527,13 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns task_args->auto_dedup = opts.auto_dedup; + /* + * In the restorer we need to know if it is SELinux or not. For SELinux + * we must change the process context before creating threads. For + * Apparmor we can change each thread after they have been created. + */ + task_args->lsm_type = kdat.lsm; + /* * Make root and cwd restore _that_ late not to break any * attempts to open files by paths above (e.g. /proc). diff --git a/criu/include/restorer.h b/criu/include/restorer.h index de14eff95..2884ce9e6 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -216,6 +216,7 @@ struct task_restore_args { #ifdef ARCH_HAS_LONG_PAGES unsigned page_size; #endif + int lsm_type; } __aligned(64); /* diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index d3b459c6c..6e18cc260 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -43,6 +43,7 @@ #include "images/creds.pb-c.h" #include "images/mm.pb-c.h" +#include "images/inventory.pb-c.h" #include "shmem.h" #include "restorer.h" @@ -179,7 +180,8 @@ static int lsm_set_label(char *label, int procfd) return 0; } -static int restore_creds(struct thread_creds_args *args, int procfd) +static int restore_creds(struct thread_creds_args *args, int procfd, + int lsm_type) { CredsEntry *ce = &args->creds; int b, i, ret; @@ -296,8 +298,16 @@ static int restore_creds(struct thread_creds_args *args, int procfd) return -1; } - if (lsm_set_label(args->lsm_profile, procfd) < 0) - return -1; + if (lsm_type != LSMTYPE__SELINUX) { + /* + * SELinux does not support setting the process context for + * threaded processes. So this is skipped if running with + * SELinux and instead the process context is set before the + * threads are created. + */ + if (lsm_set_label(args->lsm_profile, procfd) < 0) + return -1; + } return 0; } @@ -576,7 +586,8 @@ long __export_restore_thread(struct thread_restore_args *args) if (restore_seccomp(args)) BUG(); - ret = restore_creds(args->creds_args, args->ta->proc_fd); + ret = restore_creds(args->creds_args, args->ta->proc_fd, + args->ta->lsm_type); ret = ret || restore_dumpable_flag(&args->ta->mm); ret = ret || restore_pdeath_sig(args); if (ret) @@ -1556,6 +1567,14 @@ long __export_restore_task(struct task_restore_args *args) if (ret) goto core_restore_end; + /* SELinux (1) process context needs to be set before creating threads. */ + if (args->lsm_type == LSMTYPE__SELINUX) { + /* Only for SELinux */ + if (lsm_set_label(args->t->creds_args->lsm_profile, + args->proc_fd) < 0) + goto core_restore_end; + } + /* * We need to prepare a valid sigframe here, so * after sigreturn the kernel will pick up the @@ -1713,7 +1732,8 @@ long __export_restore_task(struct task_restore_args *args) * turning off TCP repair is CAP_SYS_NED_ADMIN protected, * thus restore* creds _after_ all of the above. */ - ret = restore_creds(args->t->creds_args, args->proc_fd); + ret = restore_creds(args->t->creds_args, args->proc_fd, + args->lsm_type); ret = ret || restore_dumpable_flag(&args->mm); ret = ret || restore_pdeath_sig(args->t); From 560590733396f8e45bd053b03b4f4b586b4a8d8f Mon Sep 17 00:00:00 2001 From: Zhang Ning Date: Thu, 4 Apr 2019 10:22:29 +0800 Subject: [PATCH 1966/4375] Android NDK: necessary Makefile changes 1, do not hardcode libnl's cflags when cross compile CRIU, libnl's header file should not point to host. 2, remove link to rt Android NDK doesn't have library rt, and CRIU is not really need it, so disable it to pass link Cc: Chen Hu Signed-off-by: Zhang Ning Reviewed-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> --- criu/Makefile | 2 +- criu/Makefile.packages | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/Makefile b/criu/Makefile index bcfb71622..797878176 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -26,7 +26,7 @@ ccflags-y += -iquote include ccflags-y += -iquote images ccflags-y += -iquote $(ARCH_DIR)/include ccflags-y += -iquote . -ccflags-y += -I/usr/include/libnl3 +ccflags-y += $(shell pkg-config --cflags libnl-3.0) ccflags-y += $(COMPEL_UAPI_INCLUDES) ccflags-y += $(CONFIG-DEFINES) diff --git a/criu/Makefile.packages b/criu/Makefile.packages index 2cea94781..b01b4b044 100644 --- a/criu/Makefile.packages +++ b/criu/Makefile.packages @@ -32,7 +32,7 @@ REQ-DEB-PKG-NAMES += python-future REQ-RPM-PKG-TEST-NAMES += $(PYTHON)-pyyaml endif -export LIBS += -lrt -lpthread -lprotobuf-c -ldl -lnl-3 -lsoccr -Lsoccr/ -lnet +export LIBS += -lprotobuf-c -ldl -lnl-3 -lsoccr -Lsoccr/ -lnet check-packages-failed: $(warning Can not find some of the required libraries) From 74bb7a56ea6422afb9e7a3f7203e5f57c2f03545 Mon Sep 17 00:00:00 2001 From: Zhang Ning Date: Thu, 4 Apr 2019 10:22:30 +0800 Subject: [PATCH 1967/4375] Android NDK: UNIX_PATH_MAX is defined in un.h in Android NDK, UNIX_PATH_MAX is already defined, add ifndef to check. linux/un.h: 22: #define UNIX_PATH_MAX 108 Cc: Chen Hu Signed-off-by: Zhang Ning Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> --- compel/src/lib/infect.c | 2 ++ criu/include/util-pie.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index abf3a0ab3..b7db6cf97 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -33,8 +33,10 @@ #include "common/scm.h" #include "common/scm-code.c" +#ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX (sizeof(struct sockaddr_un) - \ (size_t)((struct sockaddr_un *) 0)->sun_path) +#endif #define PARASITE_STACK_SIZE (16 << 10) diff --git a/criu/include/util-pie.h b/criu/include/util-pie.h index 31975dda8..ce78b0d19 100644 --- a/criu/include/util-pie.h +++ b/criu/include/util-pie.h @@ -4,8 +4,10 @@ #include #include +#ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX (sizeof(struct sockaddr_un) - \ (size_t)((struct sockaddr_un *) 0)->sun_path) +#endif #ifndef SO_PEEK_OFF #define SO_PEEK_OFF 42 From 31e3e01fe49c0f19fd8eda62a5bf5322c3bb38e5 Mon Sep 17 00:00:00 2001 From: Zhang Ning Date: Thu, 4 Apr 2019 10:22:31 +0800 Subject: [PATCH 1968/4375] Android NDK: no index function in strings.h due to Android NDK's strings.h doesn't have index function. Declare this function in CRIU, just like povit_root. still need to provide index function implement, for link CRIU. Cc: Chen Hu Signed-off-by: Zhang Ning Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> --- criu/config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/config.c b/criu/config.c index fdfb03064..d5354ae9c 100644 --- a/criu/config.c +++ b/criu/config.c @@ -378,6 +378,8 @@ Esyntax: return -1; } +extern char *index(const char *s, int c); + static size_t parse_size(char *optarg) { if (index(optarg, 'K')) From cffeb263b7a79d6ff4c2f01e479365338f80307e Mon Sep 17 00:00:00 2001 From: Zhang Ning Date: Thu, 4 Apr 2019 10:22:32 +0800 Subject: [PATCH 1969/4375] Add notes for Android NDK cross compile some notes for Android NDK cross compile. Signed-off-by: Zhang Ning Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> --- Documentation/HOWTO.cross-compile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/HOWTO.cross-compile b/Documentation/HOWTO.cross-compile index 749c08113..f1b17842b 100644 --- a/Documentation/HOWTO.cross-compile +++ b/Documentation/HOWTO.cross-compile @@ -29,3 +29,11 @@ This HOWTO explains how to cross-compile CRIU on x86 13. Compile CRIU: ARCH= CROSS_COMPILE=$TARGET- CFLAGS=`pkg-config --cflags libprotobuf-c` LDFLAGS="`pkg-config --libs libprotobuf-c`" make + +Special notes for Android NDK cross compile: + +1, Android NDK doesn't have some headers required by CRIU build, they are , + +2, Android NDK doesn't have some function required by CRIU build, they are aio*, fanotify_init, fanotify_mark, povit_root, index. + +3, in order to pass build with Android NDK, you implement them yourself, and link them to CRIU. From 43095fad2f69cca09f8bdeb9cc4af22e603af7c1 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 29 Mar 2019 13:52:35 +0300 Subject: [PATCH 1970/4375] rpc: reserve number for --check-mounts feature We want to commit --check-mounts feature to vz-criu. But to maintain image level compatibility between ms-criu and vz-criu one shouldn't use the same field id for different data. So add a comment that these id is reserved. --- images/rpc.proto | 1 + 1 file changed, 1 insertion(+) diff --git a/images/rpc.proto b/images/rpc.proto index e67471706..16c5d5028 100644 --- a/images/rpc.proto +++ b/images/rpc.proto @@ -114,6 +114,7 @@ message criu_opts { optional string config_file = 51; optional bool tcp_close = 52; optional string lsm_profile = 53; +/* optional bool check_mounts = 128; */ } message criu_dump_resp { From e65c7b55e9d9ef11f62161cfa0df213c5f0c3547 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 4 Apr 2019 02:49:27 +0100 Subject: [PATCH 1971/4375] zdtm: Replace imp module with importlib imp.load_source() has been deprecated [1]. The recommended alternative API for loading a module is exec_module() [2]. [1] https://docs.python.org/2.7/library/imp.html#imp.load_module [2] https://docs.python.org/3.4/library/importlib.html#importlib.abc.Loader.exec_module Signed-off-by: Radostin Stoyanov --- test/zdtm.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 57a77f768..3344c0022 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -18,7 +18,6 @@ import sys import linecache import random import string -import imp import fcntl import errno import datetime @@ -575,11 +574,23 @@ class zdtm_test: subprocess.check_call(["flock", "zdtm_mount_cgroups.lock", "./zdtm_umount_cgroups"]) +def load_module_from_file(name, path): + if sys.version_info[0] == 3 and sys.version_info[1] >= 5: + import importlib.util + spec = importlib.util.spec_from_file_location(name, path) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + else: + import imp + mod = imp.load_source(name, path) + return mod + + class inhfd_test: def __init__(self, name, desc, flavor, freezer): self.__name = os.path.basename(name) print("Load %s" % name) - self.__fdtyp = imp.load_source(self.__name, name) + self.__fdtyp = load_module_from_file(self.__name, name) self.__peer_pid = 0 self.__files = None self.__peer_file_names = [] From 6d69f65341169479f3493a13f08624fce714b030 Mon Sep 17 00:00:00 2001 From: Zhang Ning Date: Tue, 9 Apr 2019 09:20:56 +0800 Subject: [PATCH 1972/4375] Android NDK: elf.h missing defines in Android NDK, doesn't has define for: NT_X86_XSTATE NT_PRSTATUS so add these defines to pass compile. NOTE: add will have more build errors Cc: Chen Hu Signed-off-by: Zhang Ning Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/infect.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index 9cb5d82eb..cb3e7759a 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -20,6 +20,13 @@ #include "infect-priv.h" #include "log.h" +#ifndef NT_X86_XSTATE +#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ +#endif +#ifndef NT_PRSTATUS +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#endif + /* * Injected syscall instruction */ From ff7c66e6b14d544277f25bfc93278aef9500f93b Mon Sep 17 00:00:00 2001 From: Zhang Ning Date: Tue, 9 Apr 2019 09:20:57 +0800 Subject: [PATCH 1973/4375] Clang: __unused is illegal varible name for newer version clang with Android P's Clang versoin: 6.0.2, and Android NDK's Clang version 8.0.2 Clang will report below error: criu/compel/include/uapi/compel/sigframe-common.h:55:34: error: expected member name or ';' after declaration specifiers int __unused[32 - (sizeof (k_rtsigset_t) / sizeof (int))]; ~~~ ^ it takes __unused as an attribute, not a varible, chang to _unused, pass compile. Cc: Chen Hu Signed-off-by: Zhang Ning Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/include/uapi/sigframe-common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/include/uapi/sigframe-common.h b/compel/include/uapi/sigframe-common.h index 0796bb374..e35c8655e 100644 --- a/compel/include/uapi/sigframe-common.h +++ b/compel/include/uapi/sigframe-common.h @@ -52,7 +52,7 @@ struct rt_ucontext { rt_stack_t uc_stack; struct rt_sigcontext uc_mcontext; k_rtsigset_t uc_sigmask; /* mask last for extensibility */ - int __unused[32 - (sizeof (k_rtsigset_t) / sizeof (int))]; + int _unused[32 - (sizeof (k_rtsigset_t) / sizeof (int))]; unsigned long uc_regspace[128] __attribute__((aligned(8))); }; From de2c917aa725cb8a15d2a3aeacd303a13b565baa Mon Sep 17 00:00:00 2001 From: Zhang Ning Date: Tue, 9 Apr 2019 09:20:58 +0800 Subject: [PATCH 1974/4375] Android NDK/Clang: fix implicit macro define it reports: criu/pie/util-vdso-elf32.c:255:8: error: implicit declaration of function 'ELF32_ST_TYPE' is invalid in C99 [-Werror,-Wimplicit-function-declaration] if (ELF_ST_TYPE(sym->st_info) != STT_FUNC && ^ criu/include/util-vdso.h:72:21: note: expanded from macro 'ELF_ST_TYPE' ^ /opt/android-ndk/toolchains/llvm/prebuilt/linux-x86_64//sysroot/usr/include/linux/elf.h:114:26: note: expanded from macro 'ELF32_ST_TYPE' ^ criu/include/util-vdso.h:72:21: note: expanded from macro 'ELF_ST_TYPE' add #ifndef to check whether these macro is already defined. Cc: Chen Hu Signed-off-by: Zhang Ning Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/include/util-vdso.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/criu/include/util-vdso.h b/criu/include/util-vdso.h index 1318a5956..05b8326f5 100644 --- a/criu/include/util-vdso.h +++ b/criu/include/util-vdso.h @@ -68,8 +68,12 @@ struct vdso_maps { #define Word_t Elf32_Word #define Dyn_t Elf32_Dyn +#ifndef ELF_ST_TYPE #define ELF_ST_TYPE ELF32_ST_TYPE +#endif +#ifndef ELF_ST_BIND #define ELF_ST_BIND ELF32_ST_BIND +#endif #else /* CONFIG_VDSO_32 */ From f4fa53cf9b0f9d828199996bcd342e12df0fed49 Mon Sep 17 00:00:00 2001 From: Zhang Ning Date: Tue, 9 Apr 2019 09:20:59 +0800 Subject: [PATCH 1975/4375] Android NDK: __errno is already defined as a function criu/log.c:356:16: error: called object type 'int' is not a function or function pointer int __errno = errno; ^~~~~ /root/android-ndk/toolchains/llvm/prebuilt/linux-x86_64//sysroot/usr/include/errno.h:43:24: note: expanded from macro 'errno' ~~~~~~~^ criu/log.c:391:2: error: called object type 'int' is not a function or function pointer errno = __errno; ^~~~~ /root/android-ndk/toolchains/llvm/prebuilt/linux-x86_64//sysroot/usr/include/errno.h:43:24: note: expanded from macro 'errno' in Android NDK's errno.h: 42: int* __errno(void) __attribute_const__; 43: #define errno (*__errno()) so rename __errno to _errno to pass build Cc: Chen Hu Signed-off-by: Zhang Ning Reviewed-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/log.c | 4 ++-- test/zdtm/lib/msg.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/criu/log.c b/criu/log.c index 060d1ee6e..edd2511ce 100644 --- a/criu/log.c +++ b/criu/log.c @@ -353,7 +353,7 @@ static void early_vprint(const char *format, unsigned int loglevel, va_list para void vprint_on_level(unsigned int loglevel, const char *format, va_list params) { int fd, size, ret, off = 0; - int __errno = errno; + int _errno = errno; if (unlikely(loglevel == LOG_MSG)) { fd = STDOUT_FILENO; @@ -388,7 +388,7 @@ void vprint_on_level(unsigned int loglevel, const char *format, va_list params) if (loglevel == LOG_ERROR) log_note_err(buffer + buf_off); - errno = __errno; + errno = _errno; } void print_on_level(unsigned int loglevel, const char *format, ...) diff --git a/test/zdtm/lib/msg.c b/test/zdtm/lib/msg.c index 04cd40167..fe0994077 100644 --- a/test/zdtm/lib/msg.c +++ b/test/zdtm/lib/msg.c @@ -40,7 +40,7 @@ void test_msg(const char *format, ...) va_list arg; int off = 0; char buf[TEST_MSG_BUFFER_SIZE]; - int __errno = errno; + int _errno = errno; struct timeval tv; struct tm *tm; @@ -65,5 +65,5 @@ skip: va_end(arg); write(2, buf, off); - errno = __errno; + errno = _errno; } From e7aba32efe388f5ba570c271b0113a30834f7f8f Mon Sep 17 00:00:00 2001 From: Zhang Ning Date: Tue, 9 Apr 2019 09:21:00 +0800 Subject: [PATCH 1976/4375] tools.mk: support override CC/LD command line due to Android NDK's clang is x86_64-linux-android28-clang --sysroot ${SYSROOT_PATH} and it's ld is x86_64-linux-android-ld, it's not able to use a single pattern to discript clang and ld. and there is a error for x86_64-linux-android-ld. x86_64-linux-android-ld -L/home/ning/source/criu/protobuf-c/../target/lib -lprotobuf-c -r -z noexecstack -T ./compel/arch/x86/scripts/compel-pack.lds.S -o criu/pie/parasite.built-in.o criu/pie/parasite.o criu/pie/pie.lib.a ./compel/plugins/std.lib.a ./compel/compel-host hgen -f criu/pie/parasite.built-in.o -o criu/pie/parasite-blob.h Error (compel/src/lib/handle-elf-host.c:335): Unexpected undefined symbol: `'. External symbol in PIE? criu/pie/Makefile:49: recipe for target 'criu/pie/parasite-blob.h' failed rebuild with host ld, can pass build. so support override CC/LD from command line can pass build. Cc: Chen Hu Signed-off-by: Zhang Ning Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/tools.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nmk/scripts/tools.mk b/scripts/nmk/scripts/tools.mk index 485fe9f20..d756358d5 100644 --- a/scripts/nmk/scripts/tools.mk +++ b/scripts/nmk/scripts/tools.mk @@ -4,9 +4,9 @@ ifndef ____nmk_defined__tools # System tools shorthands RM := rm -f HOSTLD ?= ld -LD := $(CROSS_COMPILE)$(HOSTLD) +LD ?= $(CROSS_COMPILE)$(HOSTLD) HOSTCC ?= gcc -CC := $(CROSS_COMPILE)$(HOSTCC) +CC ?= $(CROSS_COMPILE)$(HOSTCC) CPP := $(CC) -E AS := $(CROSS_COMPILE)as AR := $(CROSS_COMPILE)ar From d52720a49d5696b28cbfba8a06e1b95c1c94a464 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 10 Apr 2019 15:03:02 +0100 Subject: [PATCH 1977/4375] travis-ci: Enable ia32 tests Travis CI with Xenial has 4.15 kernel these days - all support for ia32 C/R should be inplace. Finally :) Putting it into "allow_failures" to let it soak a bit. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- .travis.yml | 6 +++++- scripts/travis/travis-tests | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b69b87a3e..37db39412 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,8 @@ services: env: - TR_ARCH=local - TR_ARCH=local CLANG=1 + - TR_ARCH=local COMPAT_TEST=y + - TR_ARCH=local CLANG=1 COMPAT_TEST=y - TR_ARCH=alpine - TR_ARCH=fedora-asan - TR_ARCH=x86_64 @@ -29,7 +31,9 @@ matrix: - env: TR_ARCH=fedora-rawhide - env: TR_ARCH=fedora-rawhide-aarch64 - env: TR_ARCH=s390x - - env: TR_ARCH=local GCOV=1 + - env: TR_ARCH=local GCOV=1 + - env: TR_ARCH=local COMPAT_TEST=y + - env: TR_ARCH=local CLANG=1 COMPAT_TEST=y script: - sudo make CCACHE=1 -C scripts/travis $TR_ARCH after_success: diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 5a8884f07..01a2659f6 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -61,6 +61,30 @@ time make CC="$CC" -j4 [ -n "$SKIP_TRAVIS_TEST" ] && return +if [ "${COMPAT_TEST}x" = "yx" ] ; then + # Dirty hack to keep both ia32 & x86_64 shared libs on a machine: + # headers are probably not compatible, so apt-get doesn't allow + # installing both versions, while we need one for CRIU and one + # for 32-bit tests. A better way would involve launching docker.. + # But it would require making zdtm.py aware of docker and launching + # tests inside the CT. + INCOMPATIBLE_LIBS="libaio-dev libcap-dev libnl-3-dev libnl-route-3-dev" + IA32_PKGS="" + REFUGE=64-refuge + + mkdir "$REFUGE" + for i in $INCOMPATIBLE_LIBS ; do + for j in $(dpkg --listfiles $i | grep '\.so$') ; do + cp "$j" "$REFUGE/" + done + IA32_PKGS="$IA32_PKGS $i:i386" + done + apt-get remove $INCOMPATIBLE_LIBS + apt-get install --no-install-recommends $IA32_PKGS + mkdir -p /usr/lib/x86_64-linux-gnu/ + mv "$REFUGE"/* /usr/lib/x86_64-linux-gnu/ +fi + time make CC="$CC" -j4 -C test/zdtm [ -f "$CCACHE_LOGFILE" ] && cat $CCACHE_LOGFILE From 7905b9f65ec2addd12e6b9365f8b64ce59b67a75 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 10 Apr 2019 15:03:03 +0100 Subject: [PATCH 1978/4375] ia32: Add compatible sigmask to sigframe It has a different alignment - rework ugly macro RT_SIGFRAME_UC_SIGMASK into helpers. Fixes: #666 Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- .../src/lib/include/uapi/asm/sigframe.h | 5 +++ .../arm/src/lib/include/uapi/asm/sigframe.h | 5 +++ .../ppc64/src/lib/include/uapi/asm/sigframe.h | 5 +++ .../s390/src/lib/include/uapi/asm/sigframe.h | 5 +++ .../x86/src/lib/include/uapi/asm/sigframe.h | 38 ++++++++++++++++--- compel/arch/x86/src/lib/infect.c | 2 +- compel/src/lib/infect.c | 11 +----- criu/sigframe.c | 12 +----- 8 files changed, 57 insertions(+), 26 deletions(-) diff --git a/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h b/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h index 6b9317b04..bff714cca 100644 --- a/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/sigframe.h @@ -61,4 +61,9 @@ struct cr_sigcontext { #define RT_SIGFRAME_FPU(rt_sigframe) (&RT_SIGFRAME_AUX_CONTEXT(rt_sigframe)->fpsimd) #define RT_SIGFRAME_OFFSET(rt_sigframe) 0 +#define rt_sigframe_erase_sigset(sigframe) \ + memset(&sigframe->uc.uc_sigmask, 0, sizeof(k_rtsigset_t)) +#define rt_sigframe_copy_sigset(sigframe, from) \ + memcpy(&sigframe->uc.uc_sigmask, from, sizeof(k_rtsigset_t)) + #endif /* UAPI_COMPEL_ASM_SIGFRAME_H__ */ diff --git a/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h b/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h index b90c0f659..23ada50aa 100644 --- a/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/arm/src/lib/include/uapi/asm/sigframe.h @@ -82,4 +82,9 @@ struct rt_sigframe { #define RT_SIGFRAME_FPU(rt_sigframe) (&RT_SIGFRAME_AUX_SIGFRAME(rt_sigframe)->vfp) #define RT_SIGFRAME_OFFSET(rt_sigframe) 0 +#define rt_sigframe_erase_sigset(sigframe) \ + memset(&sigframe->sig.uc.uc_sigmask, 0, sizeof(k_rtsigset_t)) +#define rt_sigframe_copy_sigset(sigframe, from) \ + memcpy(&sigframe->sig.uc.uc_sigmask, from, sizeof(k_rtsigset_t)) + #endif /* UAPI_COMPEL_ASM_SIGFRAME_H__ */ diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h b/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h index 6f8b6ec54..9467a1b99 100644 --- a/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h @@ -63,6 +63,11 @@ struct rt_sigframe { #define RT_SIGFRAME_HAS_FPU(rt_sigframe) (1) #define RT_SIGFRAME_FPU(rt_sigframe) (&(rt_sigframe)->uc.uc_mcontext) +#define rt_sigframe_erase_sigset(sigframe) \ + memset(&sigframe->uc.uc_sigmask, 0, sizeof(k_rtsigset_t)) +#define rt_sigframe_copy_sigset(sigframe, from) \ + memcpy(&sigframe->uc.uc_sigmask, from, sizeof(k_rtsigset_t)) + #define MSR_TMA (1UL<<34) /* bit 29 Trans Mem state: Transactional */ #define MSR_TMS (1UL<<33) /* bit 30 Trans Mem state: Suspended */ #define MSR_TM (1UL<<32) /* bit 31 Trans Mem Available */ diff --git a/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h b/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h index 47c39f642..b6b894473 100644 --- a/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h @@ -72,4 +72,9 @@ struct rt_sigframe { #define RT_SIGFRAME_REGIP(rt_sigframe) (rt_sigframe)->uc.uc_mcontext.regs.psw.addr #define RT_SIGFRAME_HAS_FPU(rt_sigframe) (1) +#define rt_sigframe_erase_sigset(sigframe) \ + memset(&sigframe->uc.uc_sigmask, 0, sizeof(k_rtsigset_t)) +#define rt_sigframe_copy_sigset(sigframe, from) \ + memcpy(&sigframe->uc.uc_sigmask, from, sizeof(k_rtsigset_t)) + #endif /* UAPI_COMPEL_ASM_SIGFRAME_H__ */ diff --git a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h index 768fb61ab..51ca023f7 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -75,6 +76,7 @@ struct rt_sigcontext_32 { typedef uint32_t compat_uptr_t; typedef uint32_t compat_size_t; +typedef uint32_t compat_sigset_word; typedef struct compat_siginfo { int si_signo; @@ -89,12 +91,20 @@ typedef struct compat_sigaltstack { compat_size_t ss_size; } compat_stack_t; +#define _COMPAT_NSIG 64 +#define _COMPAT_NSIG_BPW 32 +#define _COMPAT_NSIG_WORDS (_COMPAT_NSIG / _COMPAT_NSIG_BPW) + +typedef struct { + compat_sigset_word sig[_COMPAT_NSIG_WORDS]; +} compat_sigset_t; + struct ucontext_ia32 { unsigned int uc_flags; unsigned int uc_link; compat_stack_t uc_stack; struct rt_sigcontext_32 uc_mcontext; - k_rtsigset_t uc_sigmask; /* mask last for extensibility */ + compat_sigset_t uc_sigmask; /* mask last for extensibility */ }; struct rt_sigframe_ia32 { @@ -127,10 +137,28 @@ struct rt_sigframe { bool is_native; }; -#define RT_SIGFRAME_UC_SIGMASK(rt_sigframe) \ - ((rt_sigframe->is_native) ? \ - (&rt_sigframe->native.uc.uc_sigmask) : \ - ((k_rtsigset_t *)(void *)&rt_sigframe->compat.uc.uc_sigmask)) +static inline +void rt_sigframe_copy_sigset(struct rt_sigframe *to, k_rtsigset_t *from) +{ + size_t sz = sizeof(k_rtsigset_t); + + BUILD_BUG_ON(sz != sizeof(compat_sigset_t)); + if (to->is_native) + memcpy(&to->native.uc.uc_sigmask, from, sz); + else + memcpy(&to->compat.uc.uc_sigmask, from, sz); +} + +static inline +void rt_sigframe_erase_sigset(struct rt_sigframe *sigframe) +{ + size_t sz = sizeof(k_rtsigset_t); + + if (sigframe->is_native) + memset(&sigframe->native.uc.uc_sigmask, 0, sz); + else + memset(&sigframe->compat.uc.uc_sigmask, 0, sz); +} #define RT_SIGFRAME_REGIP(rt_sigframe) \ ((rt_sigframe->is_native) ? \ diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index cb3e7759a..e76f7787d 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -116,7 +116,7 @@ void compel_convert_from_fxsr(struct user_i387_ia32_struct *env, struct i387_fxsave_struct *fxsave) { struct fpxreg *from = (struct fpxreg *)&fxsave->st_space[0]; - struct fpreg *to = (struct fpreg *)&env->st_space[0]; + struct fpreg *to = (struct fpreg *)env->st_space; int i; env->cwd = fxsave->cwd | 0xffff0000u; diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index b7db6cf97..09c2c53f9 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -1130,15 +1130,9 @@ static int save_regs_plain(void *to, user_regs_struct_t *r, user_fpregs_struct_t return 0; } -#ifndef RT_SIGFRAME_UC_SIGMASK -#define RT_SIGFRAME_UC_SIGMASK(sigframe) \ - (k_rtsigset_t*)(void *)&RT_SIGFRAME_UC(sigframe)->uc_sigmask -#endif - static int make_sigframe_plain(void *from, struct rt_sigframe *f, struct rt_sigframe *rtf, k_rtsigset_t *b) { struct plain_regs_struct *prs = from; - k_rtsigset_t *blk_sigset; /* * Make sure it's zeroified. @@ -1148,11 +1142,8 @@ static int make_sigframe_plain(void *from, struct rt_sigframe *f, struct rt_sigf if (sigreturn_prep_regs_plain(f, &prs->regs, &prs->fpregs)) return -1; - blk_sigset = RT_SIGFRAME_UC_SIGMASK(f); if (b) - memcpy(blk_sigset, b, sizeof(k_rtsigset_t)); - else - memset(blk_sigset, 0, sizeof(k_rtsigset_t)); + rt_sigframe_copy_sigset(f, b); if (RT_SIGFRAME_HAS_FPU(f)) { if (sigreturn_prep_fpu_frame_plain(f, rtf)) diff --git a/criu/sigframe.c b/criu/sigframe.c index 2b5ae7658..b8798efc3 100644 --- a/criu/sigframe.c +++ b/criu/sigframe.c @@ -18,18 +18,11 @@ static inline void setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas) } #endif -#ifndef RT_SIGFRAME_UC_SIGMASK -#define RT_SIGFRAME_UC_SIGMASK(sigframe) \ - (k_rtsigset_t*)&RT_SIGFRAME_UC(sigframe)->uc_sigmask -#endif - int construct_sigframe(struct rt_sigframe *sigframe, struct rt_sigframe *rsigframe, k_rtsigset_t *blkset, CoreEntry *core) { - k_rtsigset_t *blk_sigset; - /* * Copy basic register set in the first place: this will set * rt_sigframe type: native/compat. @@ -37,11 +30,10 @@ int construct_sigframe(struct rt_sigframe *sigframe, if (restore_gpregs(sigframe, CORE_THREAD_ARCH_INFO(core)->gpregs)) return -1; - blk_sigset = RT_SIGFRAME_UC_SIGMASK(sigframe); if (blkset) - memcpy(blk_sigset, blkset, sizeof(k_rtsigset_t)); + rt_sigframe_copy_sigset(sigframe, blkset); else - memset(blk_sigset, 0, sizeof(k_rtsigset_t)); + rt_sigframe_erase_sigset(sigframe); if (restore_fpu(sigframe, core)) return -1; From d2d3b6ff4823eb5b2d102eba5a2ee8e1eb9434bd Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 3 Apr 2019 16:22:00 +0300 Subject: [PATCH 1979/4375] sfd: Move service fds to separate file It has nothing to do with utils but rather a separate service engine. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/Makefile.crtools | 1 + criu/include/servicefd.h | 27 ++--- criu/include/util.h | 2 + criu/plugin.c | 6 + criu/servicefd.c | 251 +++++++++++++++++++++++++++++++++++++++ criu/util.c | 239 ------------------------------------- 6 files changed, 273 insertions(+), 253 deletions(-) create mode 100644 criu/servicefd.c diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index b8f24850f..3717467c2 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -84,6 +84,7 @@ obj-y += autofs.o obj-y += fdstore.o obj-y += uffd.o obj-y += config.o +obj-y += servicefd.o ifeq ($(VDSO),y) obj-y += pie-util-vdso.o diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h index bddf71c09..f8c281409 100644 --- a/criu/include/servicefd.h +++ b/criu/include/servicefd.h @@ -8,17 +8,17 @@ enum sfd_type { LOG_FD_OFF, IMG_FD_OFF, - PROC_FD_OFF, /* fd with /proc for all proc_ calls */ + PROC_FD_OFF, /* fd with /proc for all proc_ calls */ PROC_PID_FD_OFF, - CR_PROC_FD_OFF, /* some other's proc fd. - * For dump -- target ns' proc - * For restore -- CRIU ns' proc - */ - ROOT_FD_OFF, /* Root of the namespace we dump/restore */ + CR_PROC_FD_OFF, /* some other's proc fd: + * - For dump -- target ns' proc + * - For restore -- CRIU ns' proc + */ + ROOT_FD_OFF, /* Root of the namespace we dump/restore */ CGROUP_YARD, - USERNSD_SK, /* Socket for usernsd */ - NS_FD_OFF, /* Node's net namespace fd */ - TRANSPORT_FD_OFF, /* to transfer file descriptors */ + USERNSD_SK, /* Socket for usernsd */ + NS_FD_OFF, /* Node's net namespace fd */ + TRANSPORT_FD_OFF, /* to transfer file descriptors */ RPC_SK_OFF, FDSTORE_SK_OFF, @@ -28,14 +28,13 @@ enum sfd_type { struct pstree_item; extern bool sfds_protected; -extern void set_proc_self_fd(int fd); -extern int clone_service_fd(struct pstree_item *me); extern int init_service_fd(void); extern int get_service_fd(enum sfd_type type); +extern bool is_any_service_fd(int fd); +extern bool is_service_fd(int fd, enum sfd_type type); +extern int service_fd_min_fd(struct pstree_item *item); extern int install_service_fd(enum sfd_type type, int fd); extern int close_service_fd(enum sfd_type type); -extern bool is_service_fd(int fd, enum sfd_type type); -extern bool is_any_service_fd(int fd); -extern int service_fd_min_fd(struct pstree_item *); +extern int clone_service_fd(struct pstree_item *me); #endif /* __CR_SERVICE_FD_H__ */ diff --git a/criu/include/util.h b/criu/include/util.h index 5b91696ad..4e66dac60 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -180,6 +180,8 @@ extern int cr_daemon(int nochdir, int noclose, int *keep_fd, int close_fd); extern int close_status_fd(void); extern int is_root_user(void); +extern void set_proc_self_fd(int fd); + static inline bool dir_dots(const struct dirent *de) { return !strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."); diff --git a/criu/plugin.c b/criu/plugin.c index 0db862924..b97d3763a 100644 --- a/criu/plugin.c +++ b/criu/plugin.c @@ -10,6 +10,7 @@ #include "common/compiler.h" #include "xmalloc.h" #include "plugin.h" +#include "servicefd.h" #include "common/list.h" #include "log.h" @@ -90,6 +91,11 @@ static int verify_plugin(cr_plugin_desc_t *d) return 0; } +int criu_get_image_dir(void) +{ + return get_service_fd(IMG_FD_OFF); +} + static int cr_lib_load(int stage, char *path) { cr_plugin_desc_t *d; diff --git a/criu/servicefd.c b/criu/servicefd.c new file mode 100644 index 000000000..a9909735a --- /dev/null +++ b/criu/servicefd.c @@ -0,0 +1,251 @@ +#include +#include +#include +#include + +#include +#include +#include + +#include "common/compiler.h" +#include "common/list.h" + +#include "criu-log.h" + +#include "util.h" +#include "bitops.h" +#include "pstree.h" +#include "files.h" +#include "rst_info.h" +#include "servicefd.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "sfd: " + +/* Max potentially possible fd to be open by criu process */ +int service_fd_rlim_cur; + +/* Base of current process service fds set */ +static int service_fd_base; + +/* Id of current process in shared fdt */ +static int service_fd_id = 0; + +static DECLARE_BITMAP(sfd_map, SERVICE_FD_MAX); +static int sfd_arr[SERVICE_FD_MAX]; +/* + * Variable for marking areas of code, where service fds modifications + * are prohibited. It's used to safe them from reusing their numbers + * by ordinary files. See install_service_fd() and close_service_fd(). + */ +bool sfds_protected = false; + +int init_service_fd(void) +{ + struct rlimit64 rlimit; + + /* + * Service FDs are those that most likely won't + * conflict with any 'real-life' ones + */ + + if (syscall(__NR_prlimit64, getpid(), RLIMIT_NOFILE, NULL, &rlimit)) { + pr_perror("Can't get rlimit"); + return -1; + } + + service_fd_rlim_cur = (int)rlimit.rlim_cur; + return 0; +} + +static int __get_service_fd(enum sfd_type type, int service_fd_id) +{ + return service_fd_base - type - SERVICE_FD_MAX * service_fd_id; +} + +int get_service_fd(enum sfd_type type) +{ + BUG_ON((int)type <= SERVICE_FD_MIN || (int)type >= SERVICE_FD_MAX); + + if (!test_bit(type, sfd_map)) + return -1; + + if (service_fd_base == 0) + return sfd_arr[type]; + + return __get_service_fd(type, service_fd_id); +} + +bool is_any_service_fd(int fd) +{ + int sfd_min_fd = __get_service_fd(SERVICE_FD_MAX, service_fd_id); + int sfd_max_fd = __get_service_fd(SERVICE_FD_MIN, service_fd_id); + + if (fd > sfd_min_fd && fd < sfd_max_fd) { + int type = SERVICE_FD_MAX - (fd - sfd_min_fd); + if (type > SERVICE_FD_MIN && type < SERVICE_FD_MAX) + return !!test_bit(type, sfd_map); + } + + return false; +} + +bool is_service_fd(int fd, enum sfd_type type) +{ + return fd == get_service_fd(type); +} + +int service_fd_min_fd(struct pstree_item *item) +{ + struct fdt *fdt = rsti(item)->fdt; + int id = 0; + + if (fdt) + id = fdt->nr - 1; + return service_fd_rlim_cur - (SERVICE_FD_MAX - 1) - SERVICE_FD_MAX * id; +} + +static void sfds_protection_bug(enum sfd_type type) +{ + pr_err("Service fd %u is being modified in protected context\n", type); + print_stack_trace(current ? vpid(current) : 0); + BUG(); +} + +int install_service_fd(enum sfd_type type, int fd) +{ + int sfd = __get_service_fd(type, service_fd_id); + + BUG_ON((int)type <= SERVICE_FD_MIN || (int)type >= SERVICE_FD_MAX); + if (sfds_protected && !test_bit(type, sfd_map)) + sfds_protection_bug(type); + + if (service_fd_base == 0) { + if (test_bit(type, sfd_map)) + close(sfd_arr[type]); + sfd_arr[type] = fd; + set_bit(type, sfd_map); + return fd; + } + + if (dup3(fd, sfd, O_CLOEXEC) != sfd) { + pr_perror("Dup %d -> %d failed", fd, sfd); + close(fd); + return -1; + } + + set_bit(type, sfd_map); + close(fd); + return sfd; +} + +int close_service_fd(enum sfd_type type) +{ + int fd; + + if (sfds_protected) + sfds_protection_bug(type); + + fd = get_service_fd(type); + if (fd < 0) + return 0; + + if (close_safe(&fd)) + return -1; + + clear_bit(type, sfd_map); + return 0; +} + +static void move_service_fd(struct pstree_item *me, int type, int new_id, int new_base) +{ + int old = get_service_fd(type); + int new = new_base - type - SERVICE_FD_MAX * new_id; + int ret; + + if (old < 0) + return; + + ret = dup2(old, new); + if (ret == -1) { + if (errno != EBADF) + pr_perror("Unable to clone %d->%d", old, new); + } else if (!(rsti(me)->clone_flags & CLONE_FILES)) + close(old); +} + +static int choose_service_fd_base(struct pstree_item *me) +{ + int nr, real_nr, fdt_nr = 1, id = rsti(me)->service_fd_id; + + if (rsti(me)->fdt) { + /* The base is set by owner of fdt (id 0) */ + if (id != 0) + return service_fd_base; + fdt_nr = rsti(me)->fdt->nr; + } + /* Now find process's max used fd number */ + if (!list_empty(&rsti(me)->fds)) + nr = list_entry(rsti(me)->fds.prev, + struct fdinfo_list_entry, ps_list)->fe->fd; + else + nr = -1; + + nr = max(nr, inh_fd_max); + /* + * Service fds go after max fd near right border of alignment: + * + * ...|max_fd|max_fd+1|...|sfd first|...|sfd last (aligned)| + * + * So, they take maximum numbers of area allocated by kernel. + * See linux alloc_fdtable() for details. + */ + nr += (SERVICE_FD_MAX - SERVICE_FD_MIN) * fdt_nr; + nr += 16; /* Safety pad */ + real_nr = nr; + + nr /= (1024 / sizeof(void *)); + if (nr) + nr = 1 << (32 - __builtin_clz(nr)); + else + nr = 1; + nr *= (1024 / sizeof(void *)); + + if (nr > service_fd_rlim_cur) { + /* Right border is bigger, than rlim. OK, then just aligned value is enough */ + nr = round_down(service_fd_rlim_cur, (1024 / sizeof(void *))); + if (nr < real_nr) { + pr_err("Can't chose service_fd_base: %d %d\n", nr, real_nr); + return -1; + } + } + + return nr; +} + +int clone_service_fd(struct pstree_item *me) +{ + int id, new_base, i, ret = -1; + + new_base = choose_service_fd_base(me); + id = rsti(me)->service_fd_id; + + if (new_base == -1) + return -1; + if (service_fd_base == new_base && service_fd_id == id) + return 0; + + /* Dup sfds in memmove() style: they may overlap */ + if (get_service_fd(LOG_FD_OFF) < new_base - LOG_FD_OFF - SERVICE_FD_MAX * id) + for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) + move_service_fd(me, i, id, new_base); + else + for (i = SERVICE_FD_MAX - 1; i > SERVICE_FD_MIN; i--) + move_service_fd(me, i, id, new_base); + + service_fd_base = new_base; + service_fd_id = id; + ret = 0; + + return ret; +} diff --git a/criu/util.c b/criu/util.c index 8a31e36f9..fbf0db3d3 100644 --- a/criu/util.c +++ b/criu/util.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -17,8 +16,6 @@ #include #include #include -#include -#include #include #include #include @@ -29,12 +26,8 @@ #include #include -#include "bitops.h" #include "page.h" -#include "common/compiler.h" -#include "common/list.h" #include "util.h" -#include "rst-malloc.h" #include "image.h" #include "vma.h" #include "mem.h" @@ -43,7 +36,6 @@ #include "clone-noasan.h" #include "cr_options.h" -#include "servicefd.h" #include "cr-service.h" #include "files.h" #include "pstree.h" @@ -422,237 +414,6 @@ int do_open_proc(pid_t pid, int flags, const char *fmt, ...) return openat(dirfd, path, flags); } -/* Max potentially possible fd to be open by criu process */ -int service_fd_rlim_cur; -/* Base of current process service fds set */ -static int service_fd_base; -/* Id of current process in shared fdt */ -static int service_fd_id = 0; - -int init_service_fd(void) -{ - struct rlimit64 rlimit; - - /* - * Service FDs are those that most likely won't - * conflict with any 'real-life' ones - */ - - if (syscall(__NR_prlimit64, getpid(), RLIMIT_NOFILE, NULL, &rlimit)) { - pr_perror("Can't get rlimit"); - return -1; - } - - service_fd_rlim_cur = (int)rlimit.rlim_cur; - - return 0; -} - -static int __get_service_fd(enum sfd_type type, int service_fd_id) -{ - return service_fd_base - type - SERVICE_FD_MAX * service_fd_id; -} - -int service_fd_min_fd(struct pstree_item *item) -{ - struct fdt *fdt = rsti(item)->fdt; - int id = 0; - - if (fdt) - id = fdt->nr - 1; - return service_fd_rlim_cur - (SERVICE_FD_MAX - 1) - SERVICE_FD_MAX * id; -} - -static DECLARE_BITMAP(sfd_map, SERVICE_FD_MAX); -static int sfd_arr[SERVICE_FD_MAX]; -/* - * Variable for marking areas of code, where service fds modifications - * are prohibited. It's used to safe them from reusing their numbers - * by ordinary files. See install_service_fd() and close_service_fd(). - */ -bool sfds_protected = false; - -static void sfds_protection_bug(enum sfd_type type) -{ - pr_err("Service fd %u is being modified in protected context\n", type); - print_stack_trace(current ? vpid(current) : 0); - BUG(); -} - -int install_service_fd(enum sfd_type type, int fd) -{ - int sfd = __get_service_fd(type, service_fd_id); - - BUG_ON((int)type <= SERVICE_FD_MIN || (int)type >= SERVICE_FD_MAX); - if (sfds_protected && !test_bit(type, sfd_map)) - sfds_protection_bug(type); - - if (service_fd_base == 0) { - if (test_bit(type, sfd_map)) - close(sfd_arr[type]); - sfd_arr[type] = fd; - set_bit(type, sfd_map); - return fd; - } - - if (dup3(fd, sfd, O_CLOEXEC) != sfd) { - pr_perror("Dup %d -> %d failed", fd, sfd); - close(fd); - return -1; - } - - set_bit(type, sfd_map); - close(fd); - return sfd; -} - -int get_service_fd(enum sfd_type type) -{ - BUG_ON((int)type <= SERVICE_FD_MIN || (int)type >= SERVICE_FD_MAX); - - if (!test_bit(type, sfd_map)) - return -1; - - if (service_fd_base == 0) - return sfd_arr[type]; - - return __get_service_fd(type, service_fd_id); -} - -int criu_get_image_dir(void) -{ - return get_service_fd(IMG_FD_OFF); -} - -int close_service_fd(enum sfd_type type) -{ - int fd; - - if (sfds_protected) - sfds_protection_bug(type); - - fd = get_service_fd(type); - if (fd < 0) - return 0; - - if (close_safe(&fd)) - return -1; - - clear_bit(type, sfd_map); - return 0; -} - -static void move_service_fd(struct pstree_item *me, int type, int new_id, int new_base) -{ - int old = get_service_fd(type); - int new = new_base - type - SERVICE_FD_MAX * new_id; - int ret; - - if (old < 0) - return; - ret = dup2(old, new); - if (ret == -1) { - if (errno != EBADF) - pr_perror("Unable to clone %d->%d", old, new); - } else if (!(rsti(me)->clone_flags & CLONE_FILES)) - close(old); -} - -static int choose_service_fd_base(struct pstree_item *me) -{ - int nr, real_nr, fdt_nr = 1, id = rsti(me)->service_fd_id; - - if (rsti(me)->fdt) { - /* The base is set by owner of fdt (id 0) */ - if (id != 0) - return service_fd_base; - fdt_nr = rsti(me)->fdt->nr; - } - /* Now find process's max used fd number */ - if (!list_empty(&rsti(me)->fds)) - nr = list_entry(rsti(me)->fds.prev, - struct fdinfo_list_entry, ps_list)->fe->fd; - else - nr = -1; - - nr = max(nr, inh_fd_max); - /* - * Service fds go after max fd near right border of alignment: - * - * ...|max_fd|max_fd+1|...|sfd first|...|sfd last (aligned)| - * - * So, they take maximum numbers of area allocated by kernel. - * See linux alloc_fdtable() for details. - */ - nr += (SERVICE_FD_MAX - SERVICE_FD_MIN) * fdt_nr; - nr += 16; /* Safety pad */ - real_nr = nr; - - nr /= (1024 / sizeof(void *)); - if (nr) - nr = 1 << (32 - __builtin_clz(nr)); - else - nr = 1; - nr *= (1024 / sizeof(void *)); - - if (nr > service_fd_rlim_cur) { - /* Right border is bigger, than rlim. OK, then just aligned value is enough */ - nr = round_down(service_fd_rlim_cur, (1024 / sizeof(void *))); - if (nr < real_nr) { - pr_err("Can't chose service_fd_base: %d %d\n", nr, real_nr); - return -1; - } - } - - return nr; -} - -int clone_service_fd(struct pstree_item *me) -{ - int id, new_base, i, ret = -1; - - new_base = choose_service_fd_base(me); - id = rsti(me)->service_fd_id; - - if (new_base == -1) - return -1; - if (service_fd_base == new_base && service_fd_id == id) - return 0; - - /* Dup sfds in memmove() style: they may overlap */ - if (get_service_fd(LOG_FD_OFF) < new_base - LOG_FD_OFF - SERVICE_FD_MAX * id) - for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) - move_service_fd(me, i, id, new_base); - else - for (i = SERVICE_FD_MAX - 1; i > SERVICE_FD_MIN; i--) - move_service_fd(me, i, id, new_base); - - service_fd_base = new_base; - service_fd_id = id; - ret = 0; - - return ret; -} - -bool is_any_service_fd(int fd) -{ - int sfd_min_fd = __get_service_fd(SERVICE_FD_MAX, service_fd_id); - int sfd_max_fd = __get_service_fd(SERVICE_FD_MIN, service_fd_id); - - if (fd > sfd_min_fd && fd < sfd_max_fd) { - int type = SERVICE_FD_MAX - (fd - sfd_min_fd); - if (type > SERVICE_FD_MIN && type < SERVICE_FD_MAX) - return !!test_bit(type, sfd_map); - } - - return false; -} - -bool is_service_fd(int fd, enum sfd_type type) -{ - return fd == get_service_fd(type); -} - int copy_file(int fd_in, int fd_out, size_t bytes) { ssize_t written = 0; From 5adf790859c7b7f3b29e81f941bdd599a93b3baa Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Apr 2019 12:47:48 +0300 Subject: [PATCH 1980/4375] sfd: Make sure we're not overwriting existing files Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/criu-log.h | 1 + criu/include/servicefd.h | 19 +++++++++++++++++ criu/servicefd.c | 44 +++++++++++++++++++++++++++++++++++----- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/criu/include/criu-log.h b/criu/include/criu-log.h index b4a522bb9..c2a635ba7 100644 --- a/criu/include/criu-log.h +++ b/criu/include/criu-log.h @@ -34,6 +34,7 @@ extern int log_get_fd(void); extern void log_set_loglevel(unsigned int loglevel); extern unsigned int log_get_loglevel(void); +struct timeval; extern void log_get_logstart(struct timeval *); extern int write_pidfile(int pid); diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h index f8c281409..7be472cf4 100644 --- a/criu/include/servicefd.h +++ b/criu/include/servicefd.h @@ -1,7 +1,13 @@ #ifndef __CR_SERVICE_FD_H__ #define __CR_SERVICE_FD_H__ +#include #include +#include +#include +#include + +#include "criu-log.h" enum sfd_type { SERVICE_FD_MIN, @@ -28,6 +34,19 @@ enum sfd_type { struct pstree_item; extern bool sfds_protected; + +#define sfd_verify_target(_type, _old_fd, _new_fd) \ + ({ \ + int __ret = 0; \ + if (fcntl(_new_fd, F_GETFD) != -1 && errno != EBADF) { \ + pr_err("%s busy target %d -> %d\n", \ + sfd_type_name(_type), _old_fd, _new_fd); \ + __ret = -1; \ + } \ + __ret; \ + }) + +extern const char *sfd_type_name(enum sfd_type type); extern int init_service_fd(void); extern int get_service_fd(enum sfd_type type); extern bool is_any_service_fd(int fd); diff --git a/criu/servicefd.c b/criu/servicefd.c index a9909735a..d7e81836b 100644 --- a/criu/servicefd.c +++ b/criu/servicefd.c @@ -10,8 +10,6 @@ #include "common/compiler.h" #include "common/list.h" -#include "criu-log.h" - #include "util.h" #include "bitops.h" #include "pstree.h" @@ -40,6 +38,31 @@ static int sfd_arr[SERVICE_FD_MAX]; */ bool sfds_protected = false; +const char *sfd_type_name(enum sfd_type type) +{ + static const char *names[] = { + [SERVICE_FD_MIN] = __stringify_1(SERVICE_FD_MIN), + [LOG_FD_OFF] = __stringify_1(LOG_FD_OFF), + [IMG_FD_OFF] = __stringify_1(IMG_FD_OFF), + [PROC_FD_OFF] = __stringify_1(PROC_FD_OFF), + [PROC_PID_FD_OFF] = __stringify_1(PROC_PID_FD_OFF), + [CR_PROC_FD_OFF] = __stringify_1(CR_PROC_FD_OFF), + [ROOT_FD_OFF] = __stringify_1(ROOT_FD_OFF), + [CGROUP_YARD] = __stringify_1(CGROUP_YARD), + [USERNSD_SK] = __stringify_1(USERNSD_SK), + [NS_FD_OFF] = __stringify_1(NS_FD_OFF), + [TRANSPORT_FD_OFF] = __stringify_1(TRANSPORT_FD_OFF), + [RPC_SK_OFF] = __stringify_1(RPC_SK_OFF), + [FDSTORE_SK_OFF] = __stringify_1(FDSTORE_SK_OFF), + [SERVICE_FD_MAX] = __stringify_1(SERVICE_FD_MAX), + }; + + if (type < ARRAY_SIZE(names)) + return names[type]; + + return "UNKNOWN"; +} + int init_service_fd(void) { struct rlimit64 rlimit; @@ -107,7 +130,8 @@ int service_fd_min_fd(struct pstree_item *item) static void sfds_protection_bug(enum sfd_type type) { - pr_err("Service fd %u is being modified in protected context\n", type); + pr_err("Service fd %s is being modified in protected context\n", + sfd_type_name(type)); print_stack_trace(current ? vpid(current) : 0); BUG(); } @@ -128,8 +152,14 @@ int install_service_fd(enum sfd_type type, int fd) return fd; } + if (!test_bit(type, sfd_map)) { + if (sfd_verify_target(type, fd, sfd)) + return -1; + } + if (dup3(fd, sfd, O_CLOEXEC) != sfd) { - pr_perror("Dup %d -> %d failed", fd, sfd); + pr_perror("%s dup %d -> %d failed", + sfd_type_name(type), fd, sfd); close(fd); return -1; } @@ -166,10 +196,14 @@ static void move_service_fd(struct pstree_item *me, int type, int new_id, int ne if (old < 0) return; + if (!test_bit(type, sfd_map)) + sfd_verify_target(type, old, new); + ret = dup2(old, new); if (ret == -1) { if (errno != EBADF) - pr_perror("Unable to clone %d->%d", old, new); + pr_perror("%s unable to clone %d->%d", + sfd_type_name(type), old, new); } else if (!(rsti(me)->clone_flags & CLONE_FILES)) close(old); } From 32d6e7b54db1581705d8c167682fa342e6ab9e94 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 9 Apr 2019 18:24:19 +0300 Subject: [PATCH 1981/4375] early_init: Raise nr_open limit on particular commands For swrk, service, dump, restore we need to to raise nr_file limit to be able to process containers with huge number of files opened. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 32 ---------------------- criu/crtools.c | 69 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 34 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index c9904faf0..6a3d62450 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2326,42 +2326,10 @@ int prepare_dummy_task_state(struct pstree_item *pi) return 0; } -static void rlimit_unlimit_nofile_self(void) -{ - struct rlimit new; - - new.rlim_cur = kdat.sysctl_nr_open; - new.rlim_max = kdat.sysctl_nr_open; - - if (prlimit(getpid(), RLIMIT_NOFILE, &new, NULL)) { - pr_perror("rlimir: Can't setup RLIMIT_NOFILE for self"); - return; - } else - pr_debug("rlimit: RLIMIT_NOFILE unlimited for self\n"); - service_fd_rlim_cur = kdat.sysctl_nr_open; -} - int cr_restore_tasks(void) { int ret = -1; - /* - * Service fd engine implies that file descriptors - * used won't be borrowed by the rest of the code - * and default 1024 limit is not enough for high - * loaded test/containers. Thus use kdat engine - * to fetch current system level limit for numbers - * of files allowed to open up and lift up own - * limits. - * - * Note we have to do it before the service fd - * get inited and we dont exit with errors here - * because in worst scenario where clash of fd - * happen we simply exit with explicit error - * during real action stage. - */ - rlimit_unlimit_nofile_self(); - if (cr_plugin_init(CR_PLUGIN_STAGE__RESTORE)) return -1; diff --git a/criu/crtools.c b/criu/crtools.c index 1f050eeab..6a2955287 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -50,8 +50,73 @@ #include "setproctitle.h" #include "sysctl.h" -static int early_init(void) +static void rlimit_unlimit_nofile(void) { + struct rlimit new; + + new.rlim_cur = kdat.sysctl_nr_open; + new.rlim_max = kdat.sysctl_nr_open; + + if (prlimit(getpid(), RLIMIT_NOFILE, &new, NULL)) { + pr_perror("rlimit: Can't setup RLIMIT_NOFILE for self"); + return; + } else + pr_debug("rlimit: RLIMIT_NOFILE unlimited for self\n"); + + service_fd_rlim_cur = kdat.sysctl_nr_open; +} + +static int early_init(const char *cmd) +{ + static const char *nofile_cmds[] = { + "swrk", "service", + "dump", "pre-dump", + "restore", + }; + size_t i; + + /* + * Service fd engine implies that file descriptors + * used won't be borrowed by the rest of the code + * and default 1024 limit is not enough for high + * loaded test/containers. Thus use kdat engine + * to fetch current system level limit for numbers + * of files allowed to open up and lift up own + * limits. + * + * Note we have to do it before the service fd + * get inited and we dont exit with errors here + * because in worst scenario where clash of fd + * happen we simply exit with explicit error + * during real action stage. + * + * Same time raising limits cause kernel fdtable + * to bloat so we do this only on the @nofile_cmds: + * + * - on dump criu needs additional files for sfd, + * thus if container already has many files opened + * we need to have at least not less space when + * fetching fds from a target process; + * + * - on pre-dump we might need a lot of pipes to + * fetch huge number of pages to dump; + * + * - on restore we still need to raise limits since + * there is no guarantee that on dump we've not + * been hitting fd limit already; + * + * - swrk and service obtain requests on the fly, + * thus we don't know if on of above will be + * there thus raise limits. + */ + for (i = 0; i < ARRAY_SIZE(nofile_cmds); i++) { + if (strcmp(nofile_cmds[i], cmd)) + continue; + if (!kerndat_files_stat(true)) + rlimit_unlimit_nofile(); + break; + } + if (init_service_fd()) return 1; @@ -93,7 +158,7 @@ int main(int argc, char *argv[], char *envp[]) log_set_loglevel(opts.log_level); - if (early_init()) + if (early_init(argv[optind])) return -1; if (!strcmp(argv[1], "swrk")) { From b548ed9473e99f7def781d4fae6dab7a1d8b68b8 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 16 Apr 2019 02:03:18 +0300 Subject: [PATCH 1982/4375] criu: raise the task file limit for specific commands We don't need to do this from early_init. Cc: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 12 +++++++ criu/cr-restore.c | 3 ++ criu/crtools.c | 79 --------------------------------------------- criu/include/util.h | 2 ++ criu/servicefd.c | 14 ++++++++ criu/util.c | 20 ++++++++++++ 6 files changed, 51 insertions(+), 79 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index d4ed40b91..91b8b383a 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1557,6 +1557,11 @@ int cr_pre_dump_tasks(pid_t pid) struct pstree_item *item; int ret = -1; + /* + * We might need a lot of pipes to fetch huge number of pages to dump. + */ + rlimit_unlimit_nofile(); + root_item = alloc_pstree_item(); if (!root_item) goto err; @@ -1754,6 +1759,13 @@ int cr_dump_tasks(pid_t pid) pr_info("Dumping processes (pid: %d)\n", pid); pr_info("========================================\n"); + /* + * We will fetch all file descriptors for each task, their number can + * be bigger than a default file limit, so we need to raise it to the + * maximum. + */ + rlimit_unlimit_nofile(); + root_item = alloc_pstree_item(); if (!root_item) goto err; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 6a3d62450..a7b121b8c 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2330,6 +2330,9 @@ int cr_restore_tasks(void) { int ret = -1; + if (init_service_fd()) + return 1; + if (cr_plugin_init(CR_PLUGIN_STAGE__RESTORE)) return -1; diff --git a/criu/crtools.c b/criu/crtools.c index 6a2955287..9c8064462 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -20,9 +20,6 @@ #include -#include -#include - #include "int.h" #include "page.h" #include "common/compiler.h" @@ -50,79 +47,6 @@ #include "setproctitle.h" #include "sysctl.h" -static void rlimit_unlimit_nofile(void) -{ - struct rlimit new; - - new.rlim_cur = kdat.sysctl_nr_open; - new.rlim_max = kdat.sysctl_nr_open; - - if (prlimit(getpid(), RLIMIT_NOFILE, &new, NULL)) { - pr_perror("rlimit: Can't setup RLIMIT_NOFILE for self"); - return; - } else - pr_debug("rlimit: RLIMIT_NOFILE unlimited for self\n"); - - service_fd_rlim_cur = kdat.sysctl_nr_open; -} - -static int early_init(const char *cmd) -{ - static const char *nofile_cmds[] = { - "swrk", "service", - "dump", "pre-dump", - "restore", - }; - size_t i; - - /* - * Service fd engine implies that file descriptors - * used won't be borrowed by the rest of the code - * and default 1024 limit is not enough for high - * loaded test/containers. Thus use kdat engine - * to fetch current system level limit for numbers - * of files allowed to open up and lift up own - * limits. - * - * Note we have to do it before the service fd - * get inited and we dont exit with errors here - * because in worst scenario where clash of fd - * happen we simply exit with explicit error - * during real action stage. - * - * Same time raising limits cause kernel fdtable - * to bloat so we do this only on the @nofile_cmds: - * - * - on dump criu needs additional files for sfd, - * thus if container already has many files opened - * we need to have at least not less space when - * fetching fds from a target process; - * - * - on pre-dump we might need a lot of pipes to - * fetch huge number of pages to dump; - * - * - on restore we still need to raise limits since - * there is no guarantee that on dump we've not - * been hitting fd limit already; - * - * - swrk and service obtain requests on the fly, - * thus we don't know if on of above will be - * there thus raise limits. - */ - for (i = 0; i < ARRAY_SIZE(nofile_cmds); i++) { - if (strcmp(nofile_cmds[i], cmd)) - continue; - if (!kerndat_files_stat(true)) - rlimit_unlimit_nofile(); - break; - } - - if (init_service_fd()) - return 1; - - return 0; -} - int main(int argc, char *argv[], char *envp[]) { int ret = -1; @@ -158,9 +82,6 @@ int main(int argc, char *argv[], char *envp[]) log_set_loglevel(opts.log_level); - if (early_init(argv[optind])) - return -1; - if (!strcmp(argv[1], "swrk")) { if (argc < 3) goto usage; diff --git a/criu/include/util.h b/criu/include/util.h index 4e66dac60..621abb4a0 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -350,6 +350,8 @@ extern int epoll_del_rfd(int epfd, struct epoll_rfd *rfd); extern int epoll_run_rfds(int epfd, struct epoll_event *evs, int nr_fds, int tmo); extern int epoll_prepare(int nr_events, struct epoll_event **evs); +extern void rlimit_unlimit_nofile(void); + extern int call_in_child_process(int (*fn)(void *), void *arg); #ifdef __GLIBC__ extern void print_stack_trace(pid_t pid); diff --git a/criu/servicefd.c b/criu/servicefd.c index d7e81836b..82147921c 100644 --- a/criu/servicefd.c +++ b/criu/servicefd.c @@ -67,6 +67,20 @@ int init_service_fd(void) { struct rlimit64 rlimit; + /* + * Service fd engine implies that file descriptors used won't be + * borrowed by the rest of the code and default 1024 limit is not + * enough for high loaded test/containers. Thus use kdat engine to + * fetch current system level limit for numbers of files allowed to + * open up and lift up own limits. + * + * Note we have to do it before the service fd get initialized and we + * don't exit with errors here because in worst scenario where clash of + * fd happen we simply exit with explicit error during real action + * stage. + */ + rlimit_unlimit_nofile(); + /* * Service FDs are those that most likely won't * conflict with any 'real-life' ones diff --git a/criu/util.c b/criu/util.c index fbf0db3d3..9ba33ceb3 100644 --- a/criu/util.c +++ b/criu/util.c @@ -20,12 +20,15 @@ #include #include #include +#include +#include #include #include #include #include #include +#include "kerndat.h" #include "page.h" #include "util.h" #include "image.h" @@ -1348,6 +1351,23 @@ out: return ret; } +void rlimit_unlimit_nofile(void) +{ + struct rlimit new; + + new.rlim_cur = kdat.sysctl_nr_open; + new.rlim_max = kdat.sysctl_nr_open; + + if (prlimit(getpid(), RLIMIT_NOFILE, &new, NULL)) { + pr_perror("rlimit: Can't setup RLIMIT_NOFILE for self"); + return; + } else + pr_debug("rlimit: RLIMIT_NOFILE unlimited for self\n"); + + service_fd_rlim_cur = kdat.sysctl_nr_open; +} + + #ifdef __GLIBC__ #include void print_stack_trace(pid_t pid) From 6c8ea60491305482eb60d9b17a8635ab9248a5ab Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 6 Apr 2019 04:14:53 +0300 Subject: [PATCH 1983/4375] util: don't leak file descriprots to third-party tools https://github.com/containers/container-selinux/issues/68 Cc: Adrian Reber Signed-off-by: Andrei Vagin --- criu/filesystems.c | 7 ++----- criu/util.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/criu/filesystems.c b/criu/filesystems.c index d227427b8..8a2c41853 100644 --- a/criu/filesystems.c +++ b/criu/filesystems.c @@ -382,7 +382,6 @@ int collect_binfmt_misc(void) static int tmpfs_dump(struct mount_info *pm) { int ret = -1, fd = -1, userns_pid = -1; - char tmpfs_path[PSFDS]; struct cr_img *img; int tmp_fds[3], ntmp_fds = 0, i; @@ -417,12 +416,10 @@ static int tmpfs_dump(struct mount_info *pm) if (!img) goto out; - sprintf(tmpfs_path, "/proc/self/fd/%d", fd); - if (root_ns_mask & CLONE_NEWUSER) userns_pid = root_item->pid->real; - ret = cr_system_userns(-1, img_raw_fd(img), -1, "tar", (char *[]) + ret = cr_system_userns(fd, img_raw_fd(img), -1, "tar", (char *[]) { "tar", "--create", "--gzip", "--no-unquote", @@ -432,7 +429,7 @@ static int tmpfs_dump(struct mount_info *pm) "--preserve-permissions", "--sparse", "--numeric-owner", - "--directory", tmpfs_path, ".", NULL }, 0, userns_pid); + "--directory", "/proc/self/fd/0", ".", NULL }, 0, userns_pid); if (ret) pr_err("Can't dump tmpfs content\n"); diff --git a/criu/util.c b/criu/util.c index 9ba33ceb3..9dd5010a1 100644 --- a/criu/util.c +++ b/criu/util.c @@ -493,6 +493,37 @@ int cr_system(int in, int out, int err, char *cmd, char *const argv[], unsigned return cr_system_userns(in, out, err, cmd, argv, flags, -1); } +static int close_fds(int minfd) +{ + DIR *dir; + struct dirent *de; + int fd, ret, dfd; + + dir = opendir("/proc/self/fd"); + if (dir == NULL) + pr_perror("Can't open /proc/self/fd"); + dfd = dirfd(dir); + + while ((de = readdir(dir))) { + if (dir_dots(de)) + continue; + + ret = sscanf(de->d_name, "%d", &fd); + if (ret != 1) { + pr_err("Can't parse %s\n", de->d_name); + return -1; + } + if (dfd == fd) + continue; + if (fd < minfd) + continue; + close(fd); + } + closedir(dir); + + return 0; +} + int cr_system_userns(int in, int out, int err, char *cmd, char *const argv[], unsigned flags, int userns_pid) { @@ -556,6 +587,8 @@ int cr_system_userns(int in, int out, int err, char *cmd, if (reopen_fd_as_nocheck(STDERR_FILENO, err)) goto out_chld; + close_fds(STDERR_FILENO + 1); + execvp(cmd, argv); pr_perror("exec(%s, ...) failed", cmd); From 69e353628544cc6a68571ef59436cbe8f22bf4e6 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 16 Apr 2019 18:59:21 +0000 Subject: [PATCH 1984/4375] Bump SONAME to 2 libcriu.so used to have the SONAME $ readelf -d lib/c/libcriu.so | grep SONAME 0x000000000000000e (SONAME) Library soname: [libcriu.so.1] The recent changes to libcriu (removed and added functions, changes from `char *`-args to `const char *`) are breaking ABI and API. This requires a new SONAME of 2. This patch changes the SONAME to 2: $ readelf -d lib/c/libcriu.so | grep SONAME 0x000000000000000e (SONAME) Library soname: [libcriu.so.2] Signed-off-by: Adrian Reber --- Makefile.versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.versions b/Makefile.versions index b5d2eeec7..9c1b7448e 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -12,7 +12,7 @@ export CRIU_VERSION_EXTRA CRIU_VERSION_NAME CRIU_VERSION # # C library for CRIU. -CRIU_SO_VERSION_MAJOR := 1 +CRIU_SO_VERSION_MAJOR := 2 CRIU_SO_VERSION_MINOR := 0 export CRIU_SO_VERSION_MAJOR CRIU_SO_VERSION_MINOR From 59930e5afb722491b58443fb2706b60882fdd8c7 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 12 Apr 2019 09:04:43 +0100 Subject: [PATCH 1985/4375] tools.mk: Define CC if not set to 'default' FOO ?= bar is equivalent to ifeq ($(origin FOO), undefined) FOO = bar endif However, when CC is not set its value is 'default' rather than 'undefined'. >From [1]: 'undefined': if variable was never defined. 'default': if variable has a default definition, as is usual with CC and so on. See Variables Used by Implicit Rules. Note that if you have redefined a default variable, the origin function will return the origin of the later definition. [1] https://www.gnu.org/software/make/manual/make.html Signed-off-by: Radostin Stoyanov Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/tools.mk | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/nmk/scripts/tools.mk b/scripts/nmk/scripts/tools.mk index d756358d5..8620ded7c 100644 --- a/scripts/nmk/scripts/tools.mk +++ b/scripts/nmk/scripts/tools.mk @@ -4,9 +4,13 @@ ifndef ____nmk_defined__tools # System tools shorthands RM := rm -f HOSTLD ?= ld -LD ?= $(CROSS_COMPILE)$(HOSTLD) +ifeq ($(origin LD), default) +LD := $(CROSS_COMPILE)$(HOSTLD) +endif HOSTCC ?= gcc -CC ?= $(CROSS_COMPILE)$(HOSTCC) +ifeq ($(origin CC), default) +CC := $(CROSS_COMPILE)$(HOSTCC) +endif CPP := $(CC) -E AS := $(CROSS_COMPILE)as AR := $(CROSS_COMPILE)ar From 5412247572763ba6bc32b08b20e45aa6a81e286f Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 21 Apr 2019 01:32:37 -0700 Subject: [PATCH 1986/4375] arm: fix atomic_{add,sub}_return Now, this code doesn't pass this simple test: atomic_t a;; int c = 0; atomic_set(&a, c); c = atomic_inc(&a); if (c != 0) { pr_err("c = %x &a = %p\n", c, &a); return 1; } 08:28:51.771: 26187: ERR: fd.c:36: c = 7ef47a60 &a = 0x7ef47a60 Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- test/zdtm/lib/arch/arm/include/asm/atomic.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/zdtm/lib/arch/arm/include/asm/atomic.h b/test/zdtm/lib/arch/arm/include/asm/atomic.h index bcf3fe31b..0ff76408d 100644 --- a/test/zdtm/lib/arch/arm/include/asm/atomic.h +++ b/test/zdtm/lib/arch/arm/include/asm/atomic.h @@ -25,8 +25,8 @@ static inline unsigned int atomic_add_return(int i, atomic_t *v) " strex %1, %0, [%3]\n" " teq %1, #0\n" " bne 1b\n" - : "=&r" (result), "=&r" (tmp), "+Qo" (v) - : "r" (&v), "Ir" (i) + : "=&r" (result), "=&r" (tmp), "+Qo" (*v) + : "r" (v), "Ir" (i) : "cc"); smp_mb(); @@ -47,8 +47,8 @@ static inline unsigned int atomic_sub_return(int i, atomic_t *v) " strex %1, %0, [%3]\n" " teq %1, #0\n" " bne 1b\n" - : "=&r" (result), "=&r" (tmp), "+Qo" (v) - : "r" (&v), "Ir" (i) + : "=&r" (result), "=&r" (tmp), "+Qo" (*v) + : "r" (v), "Ir" (i) : "cc"); smp_mb(); From 437561d2bbc09d734ae276dbfca337569f454d54 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 25 Apr 2019 20:26:44 +0300 Subject: [PATCH 1987/4375] criu: Version 3.12 Suddenly it's a feature-reach release. We have support for Android build and several tempting C/R things -- raw sockets, selinux labels and ro ghost files. And a couple of fixes, of course. --- Makefile.versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index 9c1b7448e..6d4e15e3d 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 11 +CRIU_VERSION_MINOR := 12 CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Glass Flamingo +CRIU_VERSION_NAME := Ice Penguin CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From ae2ab5ddadc24c06c12c545f1160086713f78f59 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 2 May 2019 13:41:46 +0000 Subject: [PATCH 1988/4375] lsm: also dump and restore sockcreate The file /proc/PID/attr/sockcreate is used by SELinux to label newly created sockets with the label available at sockcreate. If it is NULL, the default label of the process will be used. This reads out that file during checkpoint and restores the value during restore. This value is irrelevant for existing sockets as they might have been created with another context. This is only to make sure that newly created sockets have the correct context. Signed-off-by: Adrian Reber --- criu/cr-restore.c | 36 ++++++++++++++++++++++++++++++++++++ criu/include/restorer.h | 2 ++ criu/lsm.c | 32 ++++++++++++++++++++++++++++++++ criu/pie/restorer.c | 15 ++++++++++----- images/creds.proto | 1 + 5 files changed, 81 insertions(+), 5 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index a7b121b8c..7933fe37b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2994,6 +2994,8 @@ static void rst_reloc_creds(struct thread_restore_args *thread_args, if (args->lsm_profile) args->lsm_profile = rst_mem_remap_ptr(args->mem_lsm_profile_pos, RM_PRIVATE); + if (args->lsm_sockcreate) + args->lsm_sockcreate = rst_mem_remap_ptr(args->mem_lsm_sockcreate_pos, RM_PRIVATE); if (args->groups) args->groups = rst_mem_remap_ptr(args->mem_groups_pos, RM_PRIVATE); @@ -3059,6 +3061,40 @@ rst_prep_creds_args(CredsEntry *ce, unsigned long *prev_pos) args->mem_lsm_profile_pos = 0; } + if (ce->lsm_sockcreate) { + char *rendered = NULL; + char *profile; + + profile = ce->lsm_sockcreate; + + if (validate_lsm(profile) < 0) + return ERR_PTR(-EINVAL); + + if (profile && render_lsm_profile(profile, &rendered)) { + return ERR_PTR(-EINVAL); + } + if (rendered) { + size_t lsm_sockcreate_len; + char *lsm_sockcreate; + + args->mem_lsm_sockcreate_pos = rst_mem_align_cpos(RM_PRIVATE); + lsm_sockcreate_len = strlen(rendered); + lsm_sockcreate = rst_mem_alloc(lsm_sockcreate_len + 1, RM_PRIVATE); + if (!lsm_sockcreate) { + xfree(rendered); + return ERR_PTR(-ENOMEM); + } + + args = rst_mem_remap_ptr(this_pos, RM_PRIVATE); + args->lsm_sockcreate = lsm_sockcreate; + strncpy(args->lsm_sockcreate, rendered, lsm_sockcreate_len); + xfree(rendered); + } + } else { + args->lsm_sockcreate = NULL; + args->mem_lsm_sockcreate_pos = 0; + } + /* * Zap fields which we can't use. */ diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 2884ce9e6..b83e9130c 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -69,8 +69,10 @@ struct thread_creds_args { unsigned int secbits; char *lsm_profile; unsigned int *groups; + char *lsm_sockcreate; unsigned long mem_lsm_profile_pos; + unsigned long mem_lsm_sockcreate_pos; unsigned long mem_groups_pos; unsigned long mem_pos_next; diff --git a/criu/lsm.c b/criu/lsm.c index 849ec37cd..b0ef0c396 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -98,6 +98,32 @@ err: freecon(ctx); return ret; } + +/* + * selinux_get_sockcreate_label reads /proc/PID/attr/sockcreate + * to see if the PID has a special label specified for sockets. + * Most of the time this will be empty and the process will use + * the process context also for sockets. + */ +static int selinux_get_sockcreate_label(pid_t pid, char **output) +{ + FILE *f; + + f = fopen_proc(pid, "attr/sockcreate"); + if (!f) + return -1; + + fscanf(f, "%ms", output); + /* + * No need to check the result of fscanf(). If there is something + * in /proc/PID/attr/sockcreate it will be copied to *output. If + * there is nothing it will stay NULL. So whatever fscanf() does + * it should be correct. + */ + + fclose(f); + return 0; +} #endif void kerndat_lsm(void) @@ -132,6 +158,7 @@ int collect_lsm_profile(pid_t pid, CredsEntry *ce) int ret; ce->lsm_profile = NULL; + ce->lsm_sockcreate = NULL; switch (kdat.lsm) { case LSMTYPE__NO_LSM: @@ -143,6 +170,9 @@ int collect_lsm_profile(pid_t pid, CredsEntry *ce) #ifdef CONFIG_HAS_SELINUX case LSMTYPE__SELINUX: ret = selinux_get_label(pid, &ce->lsm_profile); + if (ret) + break; + ret = selinux_get_sockcreate_label(pid, &ce->lsm_sockcreate); break; #endif default: @@ -153,6 +183,8 @@ int collect_lsm_profile(pid_t pid, CredsEntry *ce) if (ce->lsm_profile) pr_info("%d has lsm profile %s\n", pid, ce->lsm_profile); + if (ce->lsm_sockcreate) + pr_info("%d has lsm sockcreate label %s\n", pid, ce->lsm_sockcreate); return ret; } diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 6e18cc260..4f42605a0 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -149,7 +149,7 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) sys_exit_group(1); } -static int lsm_set_label(char *label, int procfd) +static int lsm_set_label(char *label, char *type, int procfd) { int ret = -1, len, lsmfd; char path[STD_LOG_SIMPLE_CHUNK]; @@ -157,9 +157,9 @@ static int lsm_set_label(char *label, int procfd) if (!label) return 0; - pr_info("restoring lsm profile %s\n", label); + pr_info("restoring lsm profile (%s) %s\n", type, label); - std_sprintf(path, "self/task/%ld/attr/current", sys_gettid()); + std_sprintf(path, "self/task/%ld/attr/%s", sys_gettid(), type); lsmfd = sys_openat(procfd, path, O_WRONLY, 0); if (lsmfd < 0) { @@ -305,9 +305,14 @@ static int restore_creds(struct thread_creds_args *args, int procfd, * SELinux and instead the process context is set before the * threads are created. */ - if (lsm_set_label(args->lsm_profile, procfd) < 0) + if (lsm_set_label(args->lsm_profile, "current", procfd) < 0) return -1; } + + /* Also set the sockcreate label for all threads */ + if (lsm_set_label(args->lsm_sockcreate, "sockcreate", procfd) < 0) + return -1; + return 0; } @@ -1571,7 +1576,7 @@ long __export_restore_task(struct task_restore_args *args) if (args->lsm_type == LSMTYPE__SELINUX) { /* Only for SELinux */ if (lsm_set_label(args->t->creds_args->lsm_profile, - args->proc_fd) < 0) + "current", args->proc_fd) < 0) goto core_restore_end; } diff --git a/images/creds.proto b/images/creds.proto index 29fb8652e..23b84c7e5 100644 --- a/images/creds.proto +++ b/images/creds.proto @@ -20,4 +20,5 @@ message creds_entry { repeated uint32 groups = 14; optional string lsm_profile = 15; + optional string lsm_sockcreate = 16; } From 149fed6480de9d4fb44632a9be69314fcbeeee58 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 2 May 2019 13:47:29 +0000 Subject: [PATCH 1989/4375] test: Verify that sockcreate does not change during restore This makes sure that sockcreate stays empty for selinux00 before and after checkpoint/restore. Signed-off-by: Adrian Reber --- test/zdtm/static/selinux00.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/zdtm/static/selinux00.c b/test/zdtm/static/selinux00.c index dd9096a6f..db8420eac 100644 --- a/test/zdtm/static/selinux00.c +++ b/test/zdtm/static/selinux00.c @@ -83,6 +83,31 @@ int checkprofile() return 0; } +int check_sockcreate() +{ + char *output = NULL; + FILE *f = fopen("/proc/self/attr/sockcreate", "r"); + int ret = fscanf(f, "%ms", &output); + fclose(f); + + if (ret >= 1) { + free(output); + /* sockcreate should be empty, if fscanf found something + * it is wrong.*/ + fail("sockcreate should be empty\n"); + return -1; + } + + if (output) { + free(output); + /* Same here, output should still be NULL. */ + fail("sockcreate should be empty\n"); + return -1; + } + + return 0; +} + int main(int argc, char **argv) { test_init(argc, argv); @@ -95,12 +120,21 @@ int main(int argc, char **argv) return 0; } + if (check_sockcreate()) + return -1; + if (setprofile()) return -1; + if (check_sockcreate()) + return -1; + test_daemon(); test_waitsig(); + if (check_sockcreate()) + return -1; + if (checkprofile() == 0) pass(); From 8f704c3eb66fba5ed44d956b3f569e1461a3d3b3 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 29 Apr 2019 15:21:59 +0200 Subject: [PATCH 1990/4375] sockets: dump and restore xattr security labels Restoring a SELinux process also requires to correctly label sockets. During checkpointing fgetxattr() is used to retrieve the "security.selinux" xattr and during restore setsockcreatecon() is used before a socket is created. Previous commits are already restoring the sockcreate SELinux setting if set by the process. Signed-off-by: Adrian Reber --- criu/include/lsm.h | 18 +++++++++++++++ criu/lsm.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ criu/sk-inet.c | 12 ++++++++++ criu/sockets.c | 4 ++++ images/fdinfo.proto | 1 + 5 files changed, 91 insertions(+) diff --git a/criu/include/lsm.h b/criu/include/lsm.h index b4fce1303..3b8271282 100644 --- a/criu/include/lsm.h +++ b/criu/include/lsm.h @@ -3,6 +3,7 @@ #include "images/inventory.pb-c.h" #include "images/creds.pb-c.h" +#include "images/fdinfo.pb-c.h" #define AA_SECURITYFS_PATH "/sys/kernel/security/apparmor" @@ -34,4 +35,21 @@ int validate_lsm(char *profile); int render_lsm_profile(char *profile, char **val); extern int lsm_check_opts(void); + +#ifdef CONFIG_HAS_SELINUX +int dump_xattr_security_selinux(int fd, FdinfoEntry *e); +int run_setsockcreatecon(FdinfoEntry *e); +int reset_setsockcreatecon(); +#else +static inline int dump_xattr_security_selinux(int fd, FdinfoEntry *e) { + return 0; +} +static inline int run_setsockcreatecon(FdinfoEntry *e) { + return 0; +} +static inline int reset_setsockcreatecon() { + return 0; +} +#endif + #endif /* __CR_LSM_H__ */ diff --git a/criu/lsm.c b/criu/lsm.c index b0ef0c396..ef6ba112b 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "common/config.h" @@ -11,10 +12,12 @@ #include "util.h" #include "cr_options.h" #include "lsm.h" +#include "fdstore.h" #include "protobuf.h" #include "images/inventory.pb-c.h" #include "images/creds.pb-c.h" +#include "images/fdinfo.pb-c.h" #ifdef CONFIG_HAS_SELINUX #include @@ -124,6 +127,59 @@ static int selinux_get_sockcreate_label(pid_t pid, char **output) fclose(f); return 0; } + +int reset_setsockcreatecon() +{ + return setsockcreatecon_raw(NULL); +} + +int run_setsockcreatecon(FdinfoEntry *e) +{ + char *ctx = NULL; + + /* Currently this only works for SELinux. */ + if (kdat.lsm != LSMTYPE__SELINUX) + return 0; + + ctx = e->xattr_security_selinux; + /* Writing to the FD using fsetxattr() did not work for some reason. */ + return setsockcreatecon_raw(ctx); +} + +int dump_xattr_security_selinux(int fd, FdinfoEntry *e) +{ + char *ctx = NULL; + int len; + int ret; + + /* Currently this only works for SELinux. */ + if (kdat.lsm != LSMTYPE__SELINUX) + return 0; + + /* Get the size of the xattr. */ + len = fgetxattr(fd, "security.selinux", ctx, 0); + if (len == -1) { + pr_err("Reading xattr %s to FD %d failed\n", ctx, fd); + return -1; + } + + ctx = xmalloc(len); + if (!ctx) { + pr_err("xmalloc to read xattr for FD %d failed\n", fd); + return -1; + } + + ret = fgetxattr(fd, "security.selinux", ctx, len); + if (len != ret) { + pr_err("Reading xattr %s to FD %d failed\n", ctx, fd); + return -1; + } + + e->xattr_security_selinux = ctx; + + return 0; +} + #endif void kerndat_lsm(void) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index cc7e1cc28..0b7f0d7ff 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -23,6 +23,9 @@ #include "files.h" #include "image.h" #include "log.h" +#include "lsm.h" +#include "kerndat.h" +#include "pstree.h" #include "rst-malloc.h" #include "sockets.h" #include "sk-inet.h" @@ -30,6 +33,8 @@ #include "util.h" #include "namespaces.h" +#include "images/inventory.pb-c.h" + #undef LOG_PREFIX #define LOG_PREFIX "inet: " @@ -804,12 +809,18 @@ static int open_inet_sk(struct file_desc *d, int *new_fd) if (set_netns(ie->ns_id)) return -1; + if (run_setsockcreatecon(fle->fe)) + return -1; + sk = socket(ie->family, ie->type, ie->proto); if (sk < 0) { pr_perror("Can't create inet socket"); return -1; } + if (reset_setsockcreatecon()) + return -1; + if (ie->v6only) { if (restore_opt(sk, SOL_IPV6, IPV6_V6ONLY, &yes) == -1) goto err; @@ -890,6 +901,7 @@ done: } *new_fd = sk; + return 1; err: close(sk); diff --git a/criu/sockets.c b/criu/sockets.c index 30072ac73..7f7453ca1 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -22,6 +22,7 @@ #include "util-pie.h" #include "sk-packet.h" #include "namespaces.h" +#include "lsm.h" #include "net.h" #include "xmalloc.h" #include "fs-magic.h" @@ -663,6 +664,9 @@ int dump_socket(struct fd_parms *p, int lfd, FdinfoEntry *e) int family; const struct fdtype_ops *ops; + if (dump_xattr_security_selinux(lfd, e)) + return -1; + if (dump_opt(lfd, SOL_SOCKET, SO_DOMAIN, &family)) return -1; diff --git a/images/fdinfo.proto b/images/fdinfo.proto index ed82ceffe..77e375aa9 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -47,6 +47,7 @@ message fdinfo_entry { required uint32 flags = 2; required fd_types type = 3; required uint32 fd = 4; + optional string xattr_security_selinux = 5; } message file_entry { From a1cf51841a42a71a0867919f744560e21c654193 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 30 Apr 2019 09:47:32 +0000 Subject: [PATCH 1991/4375] selinux: add socket label test This adds two more SELinux test to verfy that checkpointing and restoring SELinux socket labels works correctly, if the process uses setsockcreatecon() or if the process leaves the default context for newly created sockets. Signed-off-by: Adrian Reber --- test/zdtm/static/Makefile | 3 + test/zdtm/static/selinux01.c | 200 +++++++++++++++++++++++++++ test/zdtm/static/selinux01.checkskip | 1 + test/zdtm/static/selinux01.desc | 1 + test/zdtm/static/selinux01.hook | 1 + test/zdtm/static/selinux02.c | 1 + test/zdtm/static/selinux02.checkskip | 1 + test/zdtm/static/selinux02.desc | 1 + test/zdtm/static/selinux02.hook | 1 + 9 files changed, 210 insertions(+) create mode 100644 test/zdtm/static/selinux01.c create mode 120000 test/zdtm/static/selinux01.checkskip create mode 120000 test/zdtm/static/selinux01.desc create mode 120000 test/zdtm/static/selinux01.hook create mode 120000 test/zdtm/static/selinux02.c create mode 120000 test/zdtm/static/selinux02.checkskip create mode 120000 test/zdtm/static/selinux02.desc create mode 120000 test/zdtm/static/selinux02.hook diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 8e3f39276..1ffaa9039 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -211,6 +211,8 @@ TST_NOFILE := \ thp_disable \ pid_file \ selinux00 \ + selinux01 \ + selinux02 \ # jobctl00 \ ifneq ($(SRCARCH),arm) @@ -513,6 +515,7 @@ unlink_fstat041: CFLAGS += -DUNLINK_FSTAT041 -DUNLINK_FSTAT04 ghost_holes01: CFLAGS += -DTAIL_HOLE ghost_holes02: CFLAGS += -DHEAD_HOLE sk-freebind-false: CFLAGS += -DZDTM_FREEBIND_FALSE +selinux02: CFLAGS += -DUSING_SOCKCREATE stopped01: CFLAGS += -DZDTM_STOPPED_KILL stopped02: CFLAGS += -DZDTM_STOPPED_TKILL stopped12: CFLAGS += -DZDTM_STOPPED_KILL -DZDTM_STOPPED_TKILL diff --git a/test/zdtm/static/selinux01.c b/test/zdtm/static/selinux01.c new file mode 100644 index 000000000..9966455c4 --- /dev/null +++ b/test/zdtm/static/selinux01.c @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "zdtmtst.h" + +/* Enabling the right policy happens in selinux00.hook and selinx00.checkskip */ + +const char *test_doc = "Check that a SELinux socket context is restored"; +const char *test_author = "Adrian Reber "; + +/* This is all based on Tycho's apparmor code */ + +#define CONTEXT "unconfined_u:unconfined_r:unconfined_dbusd_t:s0" + +/* + * This is used to store the state of SELinux. For this test + * SELinux is switched to permissive mode and later the previous + * SELinux state is restored. + */ +char state; + +int check_for_selinux() +{ + if (access("/sys/fs/selinux", F_OK) == 0) + return 0; + return 1; +} + +int setprofile() +{ + int fd, len; + + fd = open("/proc/self/attr/current", O_WRONLY); + if (fd < 0) { + fail("Could not open /proc/self/attr/current\n"); + return -1; + } + + len = write(fd, CONTEXT, strlen(CONTEXT)); + close(fd); + + if (len < 0) { + fail("Could not write context\n"); + return -1; + } + + return 0; +} + +int set_sockcreate() +{ + int fd, len; + + fd = open("/proc/self/attr/sockcreate", O_WRONLY); + if (fd < 0) { + fail("Could not open /proc/self/attr/sockcreate\n"); + return -1; + } + + len = write(fd, CONTEXT, strlen(CONTEXT)); + close(fd); + + if (len < 0) { + fail("Could not write context\n"); + return -1; + } + + return 0; +} + +int check_sockcreate() +{ + int fd; + char context[1024]; + int len; + + + fd = open("/proc/self/attr/sockcreate", O_RDONLY); + if (fd < 0) { + fail("Could not open /proc/self/attr/sockcreate\n"); + return -1; + } + + len = read(fd, context, strlen(CONTEXT)); + close(fd); + if (len != strlen(CONTEXT)) { + fail("SELinux context has unexpected length %d, expected %zd\n", + len, strlen(CONTEXT)); + return -1; + } + + if (strncmp(context, CONTEXT, strlen(CONTEXT)) != 0) { + fail("Wrong SELinux context %s expected %s\n", context, CONTEXT); + return -1; + } + + return 0; +} + +int check_sockcreate_empty() +{ + char *output = NULL; + FILE *f = fopen("/proc/self/attr/sockcreate", "r"); + int ret = fscanf(f, "%ms", &output); + fclose(f); + + if (ret >= 1) { + free(output); + /* sockcreate should be empty, if fscanf found something + * it is wrong.*/ + fail("sockcreate should be empty\n"); + return -1; + } + + if (output) { + free(output); + /* Same here, output should still be NULL. */ + fail("sockcreate should be empty\n"); + return -1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + char ctx[1024]; + test_init(argc, argv); + + if (check_for_selinux()) { + skip("SELinux not found on this system."); + test_daemon(); + test_waitsig(); + pass(); + return 0; + } + +#ifdef USING_SOCKCREATE + if (set_sockcreate()) + return -1; +#else + if (check_sockcreate_empty()) + return -1; + + if (setprofile()) + return -1; + + if (check_sockcreate_empty()) + return -1; +#endif + + /* Open our test socket */ + int sk = socket(AF_INET, SOCK_STREAM, 0); + memset(ctx, 0, 1024); + /* Read out the socket label */ + if (fgetxattr(sk, "security.selinux", ctx, 1024) == -1) { + fail("Reading xattr 'security.selinux' failed.\n"); + return -1; + } + if (strncmp(ctx, CONTEXT, strlen(CONTEXT)) != 0) { + fail("Wrong SELinux context %s expected %s\n", ctx, CONTEXT); + return -1; + } + memset(ctx, 0, 1024); + + test_daemon(); + test_waitsig(); + + /* Read out the socket label again */ + + if (fgetxattr(sk, "security.selinux", ctx, 1024) == -1) { + fail("Reading xattr 'security.selinux' failed.\n"); + return -1; + } + if (strncmp(ctx, CONTEXT, strlen(CONTEXT)) != 0) { + fail("Wrong SELinux context %s expected %s\n", ctx, CONTEXT); + return -1; + } + +#ifdef USING_SOCKCREATE + if (check_sockcreate()) + return -1; +#else + if (check_sockcreate_empty()) + return -1; +#endif + + pass(); + + return 0; +} diff --git a/test/zdtm/static/selinux01.checkskip b/test/zdtm/static/selinux01.checkskip new file mode 120000 index 000000000..e8a172479 --- /dev/null +++ b/test/zdtm/static/selinux01.checkskip @@ -0,0 +1 @@ +selinux00.checkskip \ No newline at end of file diff --git a/test/zdtm/static/selinux01.desc b/test/zdtm/static/selinux01.desc new file mode 120000 index 000000000..2d2961a76 --- /dev/null +++ b/test/zdtm/static/selinux01.desc @@ -0,0 +1 @@ +selinux00.desc \ No newline at end of file diff --git a/test/zdtm/static/selinux01.hook b/test/zdtm/static/selinux01.hook new file mode 120000 index 000000000..dd7ed6bb3 --- /dev/null +++ b/test/zdtm/static/selinux01.hook @@ -0,0 +1 @@ +selinux00.hook \ No newline at end of file diff --git a/test/zdtm/static/selinux02.c b/test/zdtm/static/selinux02.c new file mode 120000 index 000000000..570267785 --- /dev/null +++ b/test/zdtm/static/selinux02.c @@ -0,0 +1 @@ +selinux01.c \ No newline at end of file diff --git a/test/zdtm/static/selinux02.checkskip b/test/zdtm/static/selinux02.checkskip new file mode 120000 index 000000000..2696e6e3d --- /dev/null +++ b/test/zdtm/static/selinux02.checkskip @@ -0,0 +1 @@ +selinux01.checkskip \ No newline at end of file diff --git a/test/zdtm/static/selinux02.desc b/test/zdtm/static/selinux02.desc new file mode 120000 index 000000000..9c6802c4d --- /dev/null +++ b/test/zdtm/static/selinux02.desc @@ -0,0 +1 @@ +selinux01.desc \ No newline at end of file diff --git a/test/zdtm/static/selinux02.hook b/test/zdtm/static/selinux02.hook new file mode 120000 index 000000000..e3ea0a6c8 --- /dev/null +++ b/test/zdtm/static/selinux02.hook @@ -0,0 +1 @@ +selinux01.hook \ No newline at end of file From 7caaed20d88da3a64a6501c010d9556dd898ed70 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Fri, 3 May 2019 06:27:51 +0000 Subject: [PATCH 1992/4375] lsm: fix compiler error 'unused-result' Reading out the xattr 'security.selinux' of checkpointed sockets with fscanf() works (at least in theory) without checking the result of fscanf(). There are, however, multiple CI failures when ignoring the return value of fscanf(). This adds ferror() to check if the stream has an actual error or if '-1' just mean EOF. Handle all errors of fscanf() // Andrei Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/lsm.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/criu/lsm.c b/criu/lsm.c index ef6ba112b..9c9ac7f80 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -33,8 +33,8 @@ static int apparmor_get_label(pid_t pid, char **profile_name) return -1; if (fscanf(f, "%ms", profile_name) != 1) { - fclose(f); pr_perror("err scanfing"); + fclose(f); return -1; } @@ -111,19 +111,23 @@ err: static int selinux_get_sockcreate_label(pid_t pid, char **output) { FILE *f; + int ret; f = fopen_proc(pid, "attr/sockcreate"); if (!f) return -1; - fscanf(f, "%ms", output); - /* - * No need to check the result of fscanf(). If there is something - * in /proc/PID/attr/sockcreate it will be copied to *output. If - * there is nothing it will stay NULL. So whatever fscanf() does - * it should be correct. - */ - + ret = fscanf(f, "%ms", output); + if (ret == -1 && errno != 0) { + pr_perror("Unable to parse /proc/%d/attr/sockcreate", pid); + /* + * Only if the error indicator is set it is a real error. + * -1 could also be EOF, which would mean that sockcreate + * was just empty, which is the most common case. + */ + fclose(f); + return -1; + } fclose(f); return 0; } From 6e36fb26b24c296cb27814816492c5722ae6e218 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 4 May 2019 20:01:52 -0700 Subject: [PATCH 1993/4375] lsm: don't reset socket contex if SELinux is disabled Fixes #693 --- criu/lsm.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/criu/lsm.c b/criu/lsm.c index 9c9ac7f80..592113839 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -134,7 +134,15 @@ static int selinux_get_sockcreate_label(pid_t pid, char **output) int reset_setsockcreatecon() { - return setsockcreatecon_raw(NULL); + /* Currently this only works for SELinux. */ + if (kdat.lsm != LSMTYPE__SELINUX) + return 0; + + if (setsockcreatecon_raw(NULL)) { + pr_perror("Unable to reset socket SELinux context"); + return -1; + } + return 0; } int run_setsockcreatecon(FdinfoEntry *e) @@ -147,7 +155,11 @@ int run_setsockcreatecon(FdinfoEntry *e) ctx = e->xattr_security_selinux; /* Writing to the FD using fsetxattr() did not work for some reason. */ - return setsockcreatecon_raw(ctx); + if (setsockcreatecon_raw(ctx)) { + pr_perror("Unable to set the %s socket SELinux context", ctx); + return -1; + } + return 0; } int dump_xattr_security_selinux(int fd, FdinfoEntry *e) From 05b98e74e47e7d4fb52c6ca17ee28088d2b3e4cb Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Sat, 4 May 2019 15:27:32 +0200 Subject: [PATCH 1994/4375] lsm: fix compiler error on Fedora 30 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes following compiler error: criu/lsm.c: In function ‘dump_xattr_security_selinux’: criu/include/log.h:51:2: error: ‘%s’ directive argument is null [-Werror=format-overflow=] 51 | print_on_level(LOG_ERROR, \ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 52 | "Error (%s:%d): " LOG_PREFIX fmt, \ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 53 | __FILE__, __LINE__, ##__VA_ARGS__) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ criu/lsm.c:166:3: note: in expansion of macro ‘pr_err’ 166 | pr_err("Reading xattr %s to FD %d failed\n", ctx, fd); | ^~~~~~ Signed-off-by: Adrian Reber --- criu/lsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/lsm.c b/criu/lsm.c index 592113839..420585ba4 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -175,7 +175,7 @@ int dump_xattr_security_selinux(int fd, FdinfoEntry *e) /* Get the size of the xattr. */ len = fgetxattr(fd, "security.selinux", ctx, 0); if (len == -1) { - pr_err("Reading xattr %s to FD %d failed\n", ctx, fd); + pr_err("Reading xattr security.selinux from FD %d failed\n", fd); return -1; } From f4de24c38ba2a5c3e323d4faaa4079c9aaac1060 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 15 May 2019 08:40:31 +0300 Subject: [PATCH 1995/4375] criu: Version 3.12.1 Changelog: * Restore SELinux socket labels Signed-off-by: Andrei Vagin --- Makefile.versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.versions b/Makefile.versions index 6d4e15e3d..a7820b3b3 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -2,7 +2,7 @@ # CRIU version. CRIU_VERSION_MAJOR := 3 CRIU_VERSION_MINOR := 12 -CRIU_VERSION_SUBLEVEL := +CRIU_VERSION_SUBLEVEL := 1 CRIU_VERSION_EXTRA := CRIU_VERSION_NAME := Ice Penguin CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) From 2a3e34155c734995edd6806f134809b67429e6a6 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 27 Jun 2019 15:51:50 +0100 Subject: [PATCH 1996/4375] zdtm: Refactor seccomp_filter_{threads,tsync} As discusses on the musl mailing list [1] when libc api is used to create a POSIX thread, and this thread is killed by seccomp, this breaks a fundamental assumption the C runtime relies on, causing any libc call (i.e. pthread_join) after the kill to have undefined behaviour. In order to work around the issue we could use SECCOMP_RET_ERRNO instead of SECCOMP_RET_KILL. This filter will set a magic value to user space as errno without executing the system call. [1] https://www.openwall.com/lists/musl/2019/06/26/7 Rresolves #725 Signed-off-by: Radostin Stoyanov --- test/zdtm/static/seccomp_filter_threads.c | 26 +++++++++++++++-------- test/zdtm/static/seccomp_filter_tsync.c | 23 ++++++++++---------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/test/zdtm/static/seccomp_filter_threads.c b/test/zdtm/static/seccomp_filter_threads.c index b3fa6089d..63ea4b5bd 100644 --- a/test/zdtm/static/seccomp_filter_threads.c +++ b/test/zdtm/static/seccomp_filter_threads.c @@ -39,6 +39,8 @@ static long sys_gettid(void) { return syscall(__NR_gettid); } static futex_t *wait_rdy; static futex_t *wait_run; +static int magic = 1234; + int get_seccomp_mode(pid_t pid) { FILE *f; @@ -70,7 +72,7 @@ int filter_syscall(int syscall_nr, unsigned int flags) struct sock_filter filter[] = { BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), - BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO | (SECCOMP_RET_DATA & magic)), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), }; @@ -87,9 +89,9 @@ int filter_syscall(int syscall_nr, unsigned int flags) return 0; } -void tigger_ptrace(void) { ptrace(PTRACE_TRACEME); } -void trigger_prctl(void) { prctl(PR_SET_PDEATHSIG, 9, 0, 0, 0); } -void trigger_mincore(void) { mincore(NULL, 0, NULL); } +int tigger_ptrace(void) { return ptrace(PTRACE_TRACEME); } +int trigger_prctl(void) { return prctl(PR_SET_PDEATHSIG, 9, 0, 0, 0); } +int trigger_mincore(void) { return mincore(NULL, 0, NULL); } #define gen_param(__syscall_nr, __trigger) \ { \ @@ -101,7 +103,7 @@ void trigger_mincore(void) { mincore(NULL, 0, NULL); } struct { char *syscall_name; unsigned int syscall_nr; - void (*trigger)(void); + int (*trigger)(void); } pthread_seccomp_params[] = { gen_param(__NR_ptrace, tigger_ptrace), gen_param(__NR_prctl, trigger_prctl), @@ -112,6 +114,7 @@ struct { void *thread_main(void *arg) { + int ret; size_t nr = (long) arg; if (filter_syscall(pthread_seccomp_params[nr].syscall_nr, 0) < 0) @@ -128,10 +131,12 @@ void *thread_main(void *arg) nr, pthread_seccomp_params[nr].syscall_name, sys_gettid()); - pthread_seccomp_params[nr].trigger(); + ret = pthread_seccomp_params[nr].trigger(); + if (ret == -1 && errno == magic) + return (void *)0; test_msg("Abnormal exit %zu thread %lu\n", nr, sys_gettid()); - pthread_exit((void *)1); + return (void *)1; } int main(int argc, char ** argv) @@ -167,7 +172,7 @@ int main(int argc, char ** argv) if (pid == 0) { pthread_t thread[ARRAY_SIZE(pthread_seccomp_params)]; - void *p = NULL; + void *ret; zdtm_seccomp = 1; @@ -180,10 +185,13 @@ int main(int argc, char ** argv) for (i = 0; i < ARRAY_SIZE(pthread_seccomp_params); i++) { test_msg("Waiting thread %zu\n", i); - if (pthread_join(thread[i], &p) != 0) { + if (pthread_join(thread[i], &ret) != 0) { pr_perror("pthread_join"); exit(1); } + + if (ret != 0) + syscall(__NR_exit, 1); } syscall(__NR_exit, 0); diff --git a/test/zdtm/static/seccomp_filter_tsync.c b/test/zdtm/static/seccomp_filter_tsync.c index 9b4742ba1..e374f0aff 100644 --- a/test/zdtm/static/seccomp_filter_tsync.c +++ b/test/zdtm/static/seccomp_filter_tsync.c @@ -34,6 +34,8 @@ const char *test_author = "Tycho Andersen "; pthread_mutex_t getpid_wait; +static int magic = 1234; + int get_seccomp_mode(pid_t pid) { FILE *f; @@ -65,7 +67,7 @@ int filter_syscall(int syscall_nr, unsigned int flags) struct sock_filter filter[] = { BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), - BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO | (SECCOMP_RET_DATA & magic)), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), }; @@ -84,14 +86,19 @@ int filter_syscall(int syscall_nr, unsigned int flags) void *wait_and_getpid(void *arg) { + int ret; + pthread_mutex_lock(&getpid_wait); pthread_mutex_unlock(&getpid_wait); pthread_mutex_destroy(&getpid_wait); - /* we expect the tg to get killed by the seccomp filter that was - * installed via TSYNC */ - ptrace(PTRACE_TRACEME); - pthread_exit((void *)1); + /* we expect seccomp to exit with + * an error and set errno = magic */ + ret = ptrace(PTRACE_TRACEME); + if (ret == -1 && errno == magic) + return (void *)0; + + return ((void *)1); } int main(int argc, char ** argv) @@ -159,12 +166,6 @@ int main(int argc, char ** argv) exit(1); } - /* Here we're abusing pthread exit slightly: if the thread gets - * to call pthread_exit, the value of p is one, but if it gets - * killed pthread_join doesn't set a value since the thread - * didn't, so the value is null; we exit 0 to indicate success - * as usual. - */ syscall(__NR_exit, p); } From 6d66dd5d89f48026fd8a7149bfbb83669e7ff508 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 2 May 2019 02:34:41 +0100 Subject: [PATCH 1997/4375] zdtm/ia32: fcntl() wrapper for old glibc(s) A bit nasty, but does the job to run ofd tests on glibc < v2.28. Other way would be to update glibc on Travis-CI ia32 tests, but I thought someone might want to run the tests outside Travis-CI. Fixes: #745 Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/file_locks06.c | 2 +- test/zdtm/static/file_locks07.c | 2 +- test/zdtm/static/file_locks08.c | 2 +- test/zdtm/static/ofd_file_locks.c | 60 +++++++++++++++++++++++++++++-- test/zdtm/static/ofd_file_locks.h | 1 + 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/test/zdtm/static/file_locks06.c b/test/zdtm/static/file_locks06.c index 9bc70c47d..780fb07ea 100644 --- a/test/zdtm/static/file_locks06.c +++ b/test/zdtm/static/file_locks06.c @@ -26,7 +26,7 @@ int init_lock(int *fd, struct flock *lck) lck->l_len = 0; lck->l_pid = 0; - if (fcntl(*fd, F_OFD_SETLK, lck) < 0) { + if (zdtm_fcntl(*fd, F_OFD_SETLK, lck) < 0) { pr_perror("Can't set ofd lock"); return -1; } diff --git a/test/zdtm/static/file_locks07.c b/test/zdtm/static/file_locks07.c index b36f23011..2fe169fcf 100644 --- a/test/zdtm/static/file_locks07.c +++ b/test/zdtm/static/file_locks07.c @@ -45,7 +45,7 @@ int init_file_locks(void) } for (i = 0; i < FILE_NUM; ++i) - if (fcntl(fds[i], F_OFD_SETLKW, &lcks[i]) < 0) { + if (zdtm_fcntl(fds[i], F_OFD_SETLKW, &lcks[i]) < 0) { pr_perror("Can't set ofd lock"); return -1; } diff --git a/test/zdtm/static/file_locks08.c b/test/zdtm/static/file_locks08.c index 2d25b4b09..fea8d9e7e 100644 --- a/test/zdtm/static/file_locks08.c +++ b/test/zdtm/static/file_locks08.c @@ -28,7 +28,7 @@ int init_file_lock(int *fd, struct flock *lck) lck->l_len = 0; /* lock whole file */ lck->l_pid = 0; /* should be 0 for ofd lock */ - if (fcntl(*fd, F_OFD_SETLKW, lck) < 0) { + if (zdtm_fcntl(*fd, F_OFD_SETLKW, lck) < 0) { pr_perror("Can't set ofd lock"); return -1; } diff --git a/test/zdtm/static/ofd_file_locks.c b/test/zdtm/static/ofd_file_locks.c index c4a633625..5b19532f8 100644 --- a/test/zdtm/static/ofd_file_locks.c +++ b/test/zdtm/static/ofd_file_locks.c @@ -86,7 +86,7 @@ int check_lock_exists(const char *filename, struct flock *lck) if (lck->l_type == F_RDLCK) { /* check, that there is no write lock */ - ret = fcntl(fd, F_OFD_GETLK, lck); + ret = zdtm_fcntl(fd, F_OFD_GETLK, lck); if (ret) { pr_err("fcntl failed (%i)\n", ret); goto out; @@ -99,7 +99,7 @@ int check_lock_exists(const char *filename, struct flock *lck) /* check, that lock is set */ lck->l_type = F_WRLCK; - ret = fcntl(fd, F_OFD_GETLK, lck); + ret = zdtm_fcntl(fd, F_OFD_GETLK, lck); if (ret) { pr_err("fcntl failed (%i)\n", ret); goto out; @@ -136,3 +136,59 @@ int check_file_lock_restored(int pid, int fd, struct flock *lck) } return 0; } + +/* + * fcntl() wrapper for ofd locks. + * + * Kernel requires ia32 processes to use fcntl64() syscall for ofd: + * COMPAT_SYSCALL_DEFINE3(fcntl, [..]) + * { + * switch (cmd) { + * case F_GETLK64: + * case F_SETLK64: + * case F_SETLKW64: + * case F_OFD_GETLK: + * case F_OFD_SETLK: + * case F_OFD_SETLKW: + * return -EINVAL; + * } + * + * Glibc does all the needed wraps for fcntl(), but only from v2.28. + * To make ofd tests run on the older glibc's - provide zdtm wrap. + * + * Note: we don't need the wraps in CRIU itself as parasite/restorer + * run in 64-bit mode as long as possible, including the time to play + * with ofd (and they are dumped from CRIU). + */ +int zdtm_fcntl(int fd, int cmd, struct flock *f) +{ +#if defined(__i386__) +#ifndef __NR_fcntl64 +# define __NR_fcntl64 221 +#endif + struct flock64 f64 = {}; + int ret; + + switch (cmd) { + case F_OFD_SETLK: + case F_OFD_SETLKW: + f64.l_type = f->l_type; + f64.l_whence = f->l_whence; + f64.l_start = f->l_start; + f64.l_len = f->l_len; + f64.l_pid = f->l_pid; + return syscall(__NR_fcntl64, fd, cmd, &f64); + case F_OFD_GETLK: + ret = syscall(__NR_fcntl64, fd, cmd, &f64); + f->l_type = f64.l_type; + f->l_whence = f64.l_whence; + f->l_start = f64.l_start; + f->l_len = f64.l_len; + f->l_pid = f64.l_pid; + return ret; + default: + break; + } +#endif + return fcntl(fd, cmd, f); +} diff --git a/test/zdtm/static/ofd_file_locks.h b/test/zdtm/static/ofd_file_locks.h index 6978446df..1b206a238 100644 --- a/test/zdtm/static/ofd_file_locks.h +++ b/test/zdtm/static/ofd_file_locks.h @@ -16,5 +16,6 @@ extern int check_lock_exists(const char *filename, struct flock *lck); extern int check_file_lock_restored(int pid, int fd, struct flock *lck); +extern int zdtm_fcntl(int fd, int cmd, struct flock *f); #endif /* ZDTM_OFD_FILE_LOCKS_H_ */ From 4662315fc4fd74228b551c3d5ddb42c2975f5749 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 12 Apr 2019 21:01:36 +0100 Subject: [PATCH 1998/4375] Convert spaces to tabs There are a few places where spaces have been used instead of tabs for indentation. This patch converts the spaces to tabs for consistency with the rest of the code base. Signed-off-by: Radostin Stoyanov --- .../arm/plugins/std/syscalls/syscall-aux.h | 12 ++-- .../lib/include/uapi/asm/processor-flags.h | 56 ++++++++-------- .../src/lib/include/uapi/asm/breakpoints.h | 4 +- .../arch/x86/src/lib/include/uapi/asm/fpu.h | 2 +- compel/arch/x86/src/lib/infect.c | 16 ++--- compel/include/uapi/sigframe-common.h | 4 +- criu/arch/x86/include/asm/parasite.h | 4 +- criu/arch/x86/include/asm/restorer.h | 12 ++-- criu/cr-check.c | 2 +- criu/cr-restore.c | 8 +-- criu/filesystems.c | 2 +- criu/include/aio.h | 18 +++--- criu/include/asm-generic/vdso.h | 4 +- criu/include/autofs.h | 62 +++++++++--------- criu/include/packet_diag.h | 60 ++++++++--------- criu/include/page-pipe.h | 10 +-- criu/include/ptrace-compat.h | 6 +- criu/include/sockets.h | 2 +- criu/include/util-pie.h | 2 +- criu/libnetlink.c | 2 +- criu/mount.c | 4 +- criu/net.c | 24 +++---- criu/pagemap-cache.c | 2 +- criu/sk-queue.c | 2 +- include/common/arch/arm/asm/atomic.h | 18 +++--- include/common/arch/ppc64/asm/atomic.h | 2 +- include/common/arch/ppc64/asm/linkage.h | 64 +++++++++---------- include/common/arch/x86/asm/cmpxchg.h | 2 +- lib/c/criu.c | 4 +- soccr/soccr.c | 14 ++-- 30 files changed, 212 insertions(+), 212 deletions(-) diff --git a/compel/arch/arm/plugins/std/syscalls/syscall-aux.h b/compel/arch/arm/plugins/std/syscalls/syscall-aux.h index 0b029301f..3d2056b5a 100644 --- a/compel/arch/arm/plugins/std/syscalls/syscall-aux.h +++ b/compel/arch/arm/plugins/std/syscalls/syscall-aux.h @@ -3,25 +3,25 @@ #endif #ifndef __ARM_NR_BASE -# define __ARM_NR_BASE 0x0f0000 +# define __ARM_NR_BASE 0x0f0000 #endif #ifndef __ARM_NR_breakpoint -# define __ARM_NR_breakpoint (__ARM_NR_BASE+1) +# define __ARM_NR_breakpoint (__ARM_NR_BASE+1) #endif #ifndef __ARM_NR_cacheflush -# define __ARM_NR_cacheflush (__ARM_NR_BASE+2) +# define __ARM_NR_cacheflush (__ARM_NR_BASE+2) #endif #ifndef __ARM_NR_usr26 -# define __ARM_NR_usr26 (__ARM_NR_BASE+3) +# define __ARM_NR_usr26 (__ARM_NR_BASE+3) #endif #ifndef __ARM_NR_usr32 -# define __ARM_NR_usr32 (__ARM_NR_BASE+4) +# define __ARM_NR_usr32 (__ARM_NR_BASE+4) #endif #ifndef __ARM_NR_set_tls -# define __ARM_NR_set_tls (__ARM_NR_BASE+5) +# define __ARM_NR_set_tls (__ARM_NR_BASE+5) #endif diff --git a/compel/arch/arm/src/lib/include/uapi/asm/processor-flags.h b/compel/arch/arm/src/lib/include/uapi/asm/processor-flags.h index fc00a9e64..8745f4459 100644 --- a/compel/arch/arm/src/lib/include/uapi/asm/processor-flags.h +++ b/compel/arch/arm/src/lib/include/uapi/asm/processor-flags.h @@ -6,37 +6,37 @@ /* * PSR bits */ -#define USR26_MODE 0x00000000 -#define FIQ26_MODE 0x00000001 -#define IRQ26_MODE 0x00000002 -#define SVC26_MODE 0x00000003 -#define USR_MODE 0x00000010 -#define FIQ_MODE 0x00000011 -#define IRQ_MODE 0x00000012 -#define SVC_MODE 0x00000013 -#define ABT_MODE 0x00000017 -#define UND_MODE 0x0000001b -#define SYSTEM_MODE 0x0000001f -#define MODE32_BIT 0x00000010 -#define MODE_MASK 0x0000001f -#define PSR_T_BIT 0x00000020 -#define PSR_F_BIT 0x00000040 -#define PSR_I_BIT 0x00000080 -#define PSR_A_BIT 0x00000100 -#define PSR_E_BIT 0x00000200 -#define PSR_J_BIT 0x01000000 -#define PSR_Q_BIT 0x08000000 -#define PSR_V_BIT 0x10000000 -#define PSR_C_BIT 0x20000000 -#define PSR_Z_BIT 0x40000000 -#define PSR_N_BIT 0x80000000 +#define USR26_MODE 0x00000000 +#define FIQ26_MODE 0x00000001 +#define IRQ26_MODE 0x00000002 +#define SVC26_MODE 0x00000003 +#define USR_MODE 0x00000010 +#define FIQ_MODE 0x00000011 +#define IRQ_MODE 0x00000012 +#define SVC_MODE 0x00000013 +#define ABT_MODE 0x00000017 +#define UND_MODE 0x0000001b +#define SYSTEM_MODE 0x0000001f +#define MODE32_BIT 0x00000010 +#define MODE_MASK 0x0000001f +#define PSR_T_BIT 0x00000020 +#define PSR_F_BIT 0x00000040 +#define PSR_I_BIT 0x00000080 +#define PSR_A_BIT 0x00000100 +#define PSR_E_BIT 0x00000200 +#define PSR_J_BIT 0x01000000 +#define PSR_Q_BIT 0x08000000 +#define PSR_V_BIT 0x10000000 +#define PSR_C_BIT 0x20000000 +#define PSR_Z_BIT 0x40000000 +#define PSR_N_BIT 0x80000000 /* * Groups of PSR bits */ -#define PSR_f 0xff000000 /* Flags */ -#define PSR_s 0x00ff0000 /* Status */ -#define PSR_x 0x0000ff00 /* Extension */ -#define PSR_c 0x000000ff /* Control */ +#define PSR_f 0xff000000 /* Flags */ +#define PSR_s 0x00ff0000 /* Status */ +#define PSR_x 0x0000ff00 /* Extension */ +#define PSR_c 0x000000ff /* Control */ #endif diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/breakpoints.h b/compel/arch/ppc64/src/lib/include/uapi/asm/breakpoints.h index 1ab89af76..5f090490d 100644 --- a/compel/arch/ppc64/src/lib/include/uapi/asm/breakpoints.h +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/breakpoints.h @@ -4,12 +4,12 @@ static inline int ptrace_set_breakpoint(pid_t pid, void *addr) { - return 0; + return 0; } static inline int ptrace_flush_breakpoints(pid_t pid) { - return 0; + return 0; } #endif diff --git a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h index 896c3f253..509f4488b 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h @@ -149,7 +149,7 @@ struct xsave_hdr_struct { * The high 128 bits are stored here. */ struct ymmh_struct { - uint32_t ymmh_space[64]; + uint32_t ymmh_space[64]; } __packed; /* Intel MPX support: */ diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index e76f7787d..0737e07a3 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -481,15 +481,15 @@ int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s) /* Copied from the gdb header gdb/nat/x86-dregs.h */ /* Debug registers' indices. */ -#define DR_FIRSTADDR 0 -#define DR_LASTADDR 3 -#define DR_NADDR 4 /* The number of debug address registers. */ -#define DR_STATUS 6 /* Index of debug status register (DR6). */ -#define DR_CONTROL 7 /* Index of debug control register (DR7). */ +#define DR_FIRSTADDR 0 +#define DR_LASTADDR 3 +#define DR_NADDR 4 /* The number of debug address registers. */ +#define DR_STATUS 6 /* Index of debug status register (DR6). */ +#define DR_CONTROL 7 /* Index of debug control register (DR7). */ -#define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit. */ -#define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit. */ -#define DR_ENABLE_SIZE 2 /* Two enable bits per debug register. */ +#define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit. */ +#define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit. */ +#define DR_ENABLE_SIZE 2 /* Two enable bits per debug register. */ /* Locally enable the break/watchpoint in the I'th debug register. */ #define X86_DR_LOCAL_ENABLE(i) (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))) diff --git a/compel/include/uapi/sigframe-common.h b/compel/include/uapi/sigframe-common.h index e35c8655e..fc93c5480 100644 --- a/compel/include/uapi/sigframe-common.h +++ b/compel/include/uapi/sigframe-common.h @@ -52,8 +52,8 @@ struct rt_ucontext { rt_stack_t uc_stack; struct rt_sigcontext uc_mcontext; k_rtsigset_t uc_sigmask; /* mask last for extensibility */ - int _unused[32 - (sizeof (k_rtsigset_t) / sizeof (int))]; - unsigned long uc_regspace[128] __attribute__((aligned(8))); + int _unused[32 - (sizeof (k_rtsigset_t) / sizeof (int))]; + unsigned long uc_regspace[128] __attribute__((aligned(8))); }; extern int sigreturn_prep_fpu_frame(struct rt_sigframe *frame, diff --git a/criu/arch/x86/include/asm/parasite.h b/criu/arch/x86/include/asm/parasite.h index 0ef1d9a86..6b4d4ac59 100644 --- a/criu/arch/x86/include/asm/parasite.h +++ b/criu/arch/x86/include/asm/parasite.h @@ -28,8 +28,8 @@ static int arch_get_user_desc(user_desc_t *desc) * }; */ asm volatile ( - " mov %0,%%eax \n" - " mov %1,%%rbx \n" + " mov %0,%%eax \n" + " mov %1,%%rbx \n" " int $0x80 \n" " mov %%eax,%0 \n" : "+m"(ret) diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index 15867aa12..3c43ce688 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -25,12 +25,12 @@ static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) } #endif /* !CONFIG_COMPAT */ -#define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \ - thread_args, clone_restore_fn) \ +#define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \ + thread_args, clone_restore_fn) \ asm volatile( \ "clone_emul: \n" \ "movq %2, %%rsi \n" \ - "subq $16, %%rsi \n" \ + "subq $16, %%rsi \n" \ "movq %6, %%rdi \n" \ "movq %%rdi, 8(%%rsi) \n" \ "movq %5, %%rdi \n" \ @@ -39,16 +39,16 @@ static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) "movq %3, %%rdx \n" \ "movq %4, %%r10 \n" \ "movl $"__stringify(__NR_clone)", %%eax \n" \ - "syscall \n" \ + "syscall \n" \ \ - "testq %%rax,%%rax \n" \ + "testq %%rax,%%rax \n" \ "jz thread_run \n" \ \ "movq %%rax, %0 \n" \ "jmp clone_end \n" \ \ "thread_run: \n" \ - "xorq %%rbp, %%rbp \n" \ + "xorq %%rbp, %%rbp \n" \ "popq %%rax \n" \ "popq %%rdi \n" \ "callq *%%rax \n" \ diff --git a/criu/cr-check.c b/criu/cr-check.c index 7addb9fb0..e24668305 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -468,7 +468,7 @@ err: } #ifndef SO_GET_FILTER -#define SO_GET_FILTER SO_ATTACH_FILTER +#define SO_GET_FILTER SO_ATTACH_FILTER #endif static int check_so_gets(void) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 7933fe37b..f25efb823 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -390,10 +390,10 @@ static int populate_root_fd_off(void) struct ns_id *mntns = NULL; int ret; - if (root_ns_mask & CLONE_NEWNS) { - mntns = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc); - BUG_ON(!mntns); - } + if (root_ns_mask & CLONE_NEWNS) { + mntns = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc); + BUG_ON(!mntns); + } ret = mntns_get_root_fd(mntns); if (ret < 0) diff --git a/criu/filesystems.c b/criu/filesystems.c index 8a2c41853..1e4550b37 100644 --- a/criu/filesystems.c +++ b/criu/filesystems.c @@ -58,7 +58,7 @@ static int parse_binfmt_misc_entry(struct bfd *f, BinfmtMiscEntry *bme) char *str; str = breadline(f); - if (IS_ERR(str)) + if (IS_ERR(str)) return -1; if (!str) break; diff --git a/criu/include/aio.h b/criu/include/aio.h index 9a58089b6..858ccd3cf 100644 --- a/criu/include/aio.h +++ b/criu/include/aio.h @@ -13,18 +13,18 @@ struct task_restore_args; int prepare_aios(struct pstree_item *t, struct task_restore_args *ta); struct aio_ring { - unsigned id; /* kernel internal index number */ - unsigned nr; /* number of io_events */ - unsigned head; /* Written to by userland or under ring_lock + unsigned id; /* kernel internal index number */ + unsigned nr; /* number of io_events */ + unsigned head; /* Written to by userland or under ring_lock * mutex by aio_read_events_ring(). */ - unsigned tail; + unsigned tail; - unsigned magic; - unsigned compat_features; - unsigned incompat_features; - unsigned header_length; /* size of aio_ring */ + unsigned magic; + unsigned compat_features; + unsigned incompat_features; + unsigned header_length; /* size of aio_ring */ - struct io_event io_events[0]; + struct io_event io_events[0]; }; struct rst_aio_ring { diff --git a/criu/include/asm-generic/vdso.h b/criu/include/asm-generic/vdso.h index 81e54d264..6c3e3d137 100644 --- a/criu/include/asm-generic/vdso.h +++ b/criu/include/asm-generic/vdso.h @@ -1,8 +1,8 @@ #ifndef __CR_ASM_GENERIC_VDSO_H__ #define __CR_ASM_GENERIC_VDSO_H__ -#define VDSO_PROT (PROT_READ | PROT_EXEC) -#define VVAR_PROT (PROT_READ) +#define VDSO_PROT (PROT_READ | PROT_EXEC) +#define VVAR_PROT (PROT_READ) /* Just in case of LPAE system PFN is u64. */ #define VDSO_BAD_PFN (-1ull) diff --git a/criu/include/autofs.h b/criu/include/autofs.h index d294277f6..c4618859b 100644 --- a/criu/include/autofs.h +++ b/criu/include/autofs.h @@ -20,70 +20,70 @@ int autofs_mount(struct mount_info *mi, const char *source, const #include -#define AUTOFS_DEVICE_NAME "autofs" +#define AUTOFS_DEVICE_NAME "autofs" #define AUTOFS_DEV_IOCTL_VERSION_MAJOR 1 #define AUTOFS_DEV_IOCTL_VERSION_MINOR 0 -#define AUTOFS_DEVID_LEN 16 +#define AUTOFS_DEVID_LEN 16 -#define AUTOFS_DEV_IOCTL_SIZE sizeof(struct autofs_dev_ioctl) +#define AUTOFS_DEV_IOCTL_SIZE sizeof(struct autofs_dev_ioctl) /* * An ioctl interface for autofs mount point control. */ struct args_protover { - __u32 version; + __u32 version; }; struct args_protosubver { - __u32 sub_version; + __u32 sub_version; }; struct args_openmount { - __u32 devid; + __u32 devid; }; struct args_ready { - __u32 token; + __u32 token; }; struct args_fail { - __u32 token; - __s32 status; + __u32 token; + __s32 status; }; struct args_setpipefd { - __s32 pipefd; + __s32 pipefd; }; struct args_timeout { - __u64 timeout; + __u64 timeout; }; struct args_requester { - __u32 uid; - __u32 gid; + __u32 uid; + __u32 gid; }; struct args_expire { - __u32 how; + __u32 how; }; struct args_askumount { - __u32 may_umount; + __u32 may_umount; }; struct args_ismountpoint { union { struct args_in { - __u32 type; + __u32 type; } in; struct args_out { - __u32 devid; - __u32 magic; + __u32 devid; + __u32 magic; } out; }; }; @@ -98,24 +98,24 @@ struct args_ismountpoint { struct autofs_dev_ioctl { __u32 ver_major; __u32 ver_minor; - __u32 size; /* total size of data passed in + __u32 size; /* total size of data passed in * including this struct */ - __s32 ioctlfd; /* automount command fd */ + __s32 ioctlfd; /* automount command fd */ /* Command parameters */ union { - struct args_protover protover; - struct args_protosubver protosubver; - struct args_openmount openmount; - struct args_ready ready; - struct args_fail fail; - struct args_setpipefd setpipefd; - struct args_timeout timeout; - struct args_requester requester; - struct args_expire expire; - struct args_askumount askumount; - struct args_ismountpoint ismountpoint; + struct args_protover protover; + struct args_protosubver protosubver; + struct args_openmount openmount; + struct args_ready ready; + struct args_fail fail; + struct args_setpipefd setpipefd; + struct args_timeout timeout; + struct args_requester requester; + struct args_expire expire; + struct args_askumount askumount; + struct args_ismountpoint ismountpoint; }; char path[0]; diff --git a/criu/include/packet_diag.h b/criu/include/packet_diag.h index e5d9193a8..287de84ec 100644 --- a/criu/include/packet_diag.h +++ b/criu/include/packet_diag.h @@ -12,18 +12,18 @@ struct packet_diag_req { __u32 pdiag_cookie[2]; }; -#define PACKET_SHOW_INFO 0x00000001 /* Basic packet_sk information */ -#define PACKET_SHOW_MCLIST 0x00000002 /* A set of packet_diag_mclist-s */ +#define PACKET_SHOW_INFO 0x00000001 /* Basic packet_sk information */ +#define PACKET_SHOW_MCLIST 0x00000002 /* A set of packet_diag_mclist-s */ #define PACKET_SHOW_RING_CFG 0x00000004 /* Rings configuration parameters */ #define PACKET_SHOW_FANOUT 0x00000008 struct packet_diag_msg { - __u8 pdiag_family; - __u8 pdiag_type; - __u16 pdiag_num; + __u8 pdiag_family; + __u8 pdiag_type; + __u16 pdiag_num; - __u32 pdiag_ino; - __u32 pdiag_cookie[2]; + __u32 pdiag_ino; + __u32 pdiag_cookie[2]; }; enum { @@ -37,18 +37,18 @@ enum { }; struct packet_diag_info { - __u32 pdi_index; - __u32 pdi_version; - __u32 pdi_reserve; - __u32 pdi_copy_thresh; - __u32 pdi_tstamp; - __u32 pdi_flags; + __u32 pdi_index; + __u32 pdi_version; + __u32 pdi_reserve; + __u32 pdi_copy_thresh; + __u32 pdi_tstamp; + __u32 pdi_flags; -#define PDI_RUNNING 0x1 -#define PDI_AUXDATA 0x2 -#define PDI_ORIGDEV 0x4 -#define PDI_VNETHDR 0x8 -#define PDI_LOSS 0x10 +#define PDI_RUNNING 0x1 +#define PDI_AUXDATA 0x2 +#define PDI_ORIGDEV 0x4 +#define PDI_VNETHDR 0x8 +#define PDI_LOSS 0x10 }; #ifndef MAX_ADDR_LEN @@ -56,21 +56,21 @@ struct packet_diag_info { #endif struct packet_diag_mclist { - __u32 pdmc_index; - __u32 pdmc_count; - __u16 pdmc_type; - __u16 pdmc_alen; - __u8 pdmc_addr[MAX_ADDR_LEN]; + __u32 pdmc_index; + __u32 pdmc_count; + __u16 pdmc_type; + __u16 pdmc_alen; + __u8 pdmc_addr[MAX_ADDR_LEN]; }; struct packet_diag_ring { - __u32 pdr_block_size; - __u32 pdr_block_nr; - __u32 pdr_frame_size; - __u32 pdr_frame_nr; - __u32 pdr_retire_tmo; - __u32 pdr_sizeof_priv; - __u32 pdr_features; + __u32 pdr_block_size; + __u32 pdr_block_nr; + __u32 pdr_frame_size; + __u32 pdr_frame_nr; + __u32 pdr_retire_tmo; + __u32 pdr_sizeof_priv; + __u32 pdr_features; }; #endif /* __CR_PACKET_DIAG_H__ */ diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h index 8fa1bfa5e..80e595871 100644 --- a/criu/include/page-pipe.h +++ b/criu/include/page-pipe.h @@ -6,11 +6,11 @@ #define PAGE_ALLOC_COSTLY_ORDER 3 /* from the kernel source code */ struct kernel_pipe_buffer { - struct page *page; - unsigned int offset, len; - const struct pipe_buf_operations *ops; - unsigned int flags; - unsigned long private; + struct page *page; + unsigned int offset, len; + const struct pipe_buf_operations *ops; + unsigned int flags; + unsigned long private; }; /* diff --git a/criu/include/ptrace-compat.h b/criu/include/ptrace-compat.h index 476da3536..e16fef036 100644 --- a/criu/include/ptrace-compat.h +++ b/criu/include/ptrace-compat.h @@ -7,9 +7,9 @@ #ifndef CONFIG_HAS_PTRACE_PEEKSIGINFO struct ptrace_peeksiginfo_args { - __u64 off; /* from which siginfo to start */ - __u32 flags; - __u32 nr; /* how may siginfos to take */ + __u64 off; /* from which siginfo to start */ + __u32 flags; + __u32 nr; /* how may siginfos to take */ }; #endif diff --git a/criu/include/sockets.h b/criu/include/sockets.h index 65b230131..cd98d18e0 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -92,7 +92,7 @@ static inline int sk_decode_shutdown(int val) extern int set_netns(uint32_t ns_id); #ifndef SIOCGSKNS -#define SIOCGSKNS 0x894C /* get socket network namespace */ +#define SIOCGSKNS 0x894C /* get socket network namespace */ #endif extern int kerndat_socket_netns(void); diff --git a/criu/include/util-pie.h b/criu/include/util-pie.h index ce78b0d19..a8137f441 100644 --- a/criu/include/util-pie.h +++ b/criu/include/util-pie.h @@ -10,7 +10,7 @@ #endif #ifndef SO_PEEK_OFF -#define SO_PEEK_OFF 42 +#define SO_PEEK_OFF 42 #endif #include "common/scm.h" diff --git a/criu/libnetlink.c b/criu/libnetlink.c index ca9968309..18a323b8d 100644 --- a/criu/libnetlink.c +++ b/criu/libnetlink.c @@ -222,5 +222,5 @@ int __wrap_nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int32_t nla_get_s32(const struct nlattr *nla) { - return *(const int32_t *) nla_data(nla); + return *(const int32_t *) nla_data(nla); } diff --git a/criu/mount.c b/criu/mount.c index 118ba623e..c03a435c5 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2325,8 +2325,8 @@ out: * mi->shared_id && !shared - create a new shared group */ if (restore_shared_options(mi, private, - mi->shared_id && !shared, - mi->master_id && !master)) + mi->shared_id && !shared, + mi->master_id && !master)) return -1; mi->mounted = true; diff --git a/criu/net.c b/criu/net.c index a5f632dd6..44b0ce224 100644 --- a/criu/net.c +++ b/criu/net.c @@ -344,7 +344,7 @@ static int ipv6_conf_op(char *tgt, SysctlEntry **conf, int n, int op, SysctlEntr * the kernel, simply write DEVCONFS_UNUSED * into the image so we would skip it. */ -#define DEVCONFS_UNUSED (-1u) +#define DEVCONFS_UNUSED (-1u) static int ipv4_conf_op_old(char *tgt, int *conf, int n, int op, int *def_conf) { @@ -2765,7 +2765,7 @@ static int prep_ns_sockets(struct ns_id *ns, bool for_dump) freecon(ctx); if (ret < 0) { pr_perror("Setting SELinux socket context for PID %d failed", - root_item->pid->real); + root_item->pid->real); goto err_sq; } } @@ -3019,22 +3019,22 @@ int move_veth_to_bridge(void) #ifndef NETNSA_MAX /* Attributes of RTM_NEWNSID/RTM_GETNSID messages */ enum { - NETNSA_NONE, + NETNSA_NONE, #define NETNSA_NSID_NOT_ASSIGNED -1 - NETNSA_NSID, - NETNSA_PID, - NETNSA_FD, - __NETNSA_MAX, + NETNSA_NSID, + NETNSA_PID, + NETNSA_FD, + __NETNSA_MAX, }; -#define NETNSA_MAX (__NETNSA_MAX - 1) +#define NETNSA_MAX (__NETNSA_MAX - 1) #endif static struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = { - [NETNSA_NONE] = { .type = NLA_UNSPEC }, - [NETNSA_NSID] = { .type = NLA_S32 }, - [NETNSA_PID] = { .type = NLA_U32 }, - [NETNSA_FD] = { .type = NLA_U32 }, + [NETNSA_NONE] = { .type = NLA_UNSPEC }, + [NETNSA_NSID] = { .type = NLA_S32 }, + [NETNSA_PID] = { .type = NLA_U32 }, + [NETNSA_FD] = { .type = NLA_U32 }, }; static int nsid_cb(struct nlmsghdr *msg, struct ns_id *ns, void *arg) diff --git a/criu/pagemap-cache.c b/criu/pagemap-cache.c index aa39dacaa..a1c2d42f4 100644 --- a/criu/pagemap-cache.c +++ b/criu/pagemap-cache.c @@ -119,7 +119,7 @@ static int pmc_fill_cache(pmc_t *pmc, const struct vma_area *vma) * is to walk page tables less. */ if (!pagemap_cache_disabled && - len < PMC_SIZE && (vma->e->start - low) < PMC_SIZE_GAP) { + len < PMC_SIZE && (vma->e->start - low) < PMC_SIZE_GAP) { size_t size_cov = len; size_t nr_vmas = 1; diff --git a/criu/sk-queue.c b/criu/sk-queue.c index 613e38461..fdf610170 100644 --- a/criu/sk-queue.c +++ b/criu/sk-queue.c @@ -29,7 +29,7 @@ struct sk_packet { struct list_head list; SkPacketEntry *entry; - char *data; + char *data; unsigned scm_len; int *scm; }; diff --git a/include/common/arch/arm/asm/atomic.h b/include/common/arch/arm/asm/atomic.h index 94e65cf3e..7998a20f2 100644 --- a/include/common/arch/arm/asm/atomic.h +++ b/include/common/arch/arm/asm/atomic.h @@ -29,9 +29,9 @@ static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) "teq %1, %4\n" "it eq\n" "strexeq %0, %5, [%3]\n" - : "=&r" (res), "=&r" (oldval), "+Qo" (ptr->counter) - : "r" (&ptr->counter), "Ir" (old), "r" (new) - : "cc"); + : "=&r" (res), "=&r" (oldval), "+Qo" (ptr->counter) + : "r" (&ptr->counter), "Ir" (old), "r" (new) + : "cc"); } while (res); smp_mb(); @@ -47,13 +47,13 @@ static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { - int ret; + int ret; - ret = v->counter; - if (ret == old) - v->counter = new; + ret = v->counter; + if (ret == old) + v->counter = new; - return ret; + return ret; } #else @@ -88,7 +88,7 @@ static inline int atomic_add_return(int i, atomic_t *v) " teq %1, #0\n" " bne 1b\n" : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) - : "r" (&v->counter), "Ir" (i) + : "r" (&v->counter), "Ir" (i) : "cc"); smp_mb(); diff --git a/include/common/arch/ppc64/asm/atomic.h b/include/common/arch/ppc64/asm/atomic.h index 461875c6e..4c6477412 100644 --- a/include/common/arch/ppc64/asm/atomic.h +++ b/include/common/arch/ppc64/asm/atomic.h @@ -8,7 +8,7 @@ */ typedef struct { - int counter; + int counter; } atomic_t; #include "common/arch/ppc64/asm/cmpxchg.h" diff --git a/include/common/arch/ppc64/asm/linkage.h b/include/common/arch/ppc64/asm/linkage.h index 506edc711..01a47ab1a 100644 --- a/include/common/arch/ppc64/asm/linkage.h +++ b/include/common/arch/ppc64/asm/linkage.h @@ -261,38 +261,38 @@ #define N_SLINE 68 #define N_SO 100 -#define __REG_R0 0 -#define __REG_R1 1 -#define __REG_R2 2 -#define __REG_R3 3 -#define __REG_R4 4 -#define __REG_R5 5 -#define __REG_R6 6 -#define __REG_R7 7 -#define __REG_R8 8 -#define __REG_R9 9 -#define __REG_R10 10 -#define __REG_R11 11 -#define __REG_R12 12 -#define __REG_R13 13 -#define __REG_R14 14 -#define __REG_R15 15 -#define __REG_R16 16 -#define __REG_R17 17 -#define __REG_R18 18 -#define __REG_R19 19 -#define __REG_R20 20 -#define __REG_R21 21 -#define __REG_R22 22 -#define __REG_R23 23 -#define __REG_R24 24 -#define __REG_R25 25 -#define __REG_R26 26 -#define __REG_R27 27 -#define __REG_R28 28 -#define __REG_R29 29 -#define __REG_R30 30 -#define __REG_R31 31 +#define __REG_R0 0 +#define __REG_R1 1 +#define __REG_R2 2 +#define __REG_R3 3 +#define __REG_R4 4 +#define __REG_R5 5 +#define __REG_R6 6 +#define __REG_R7 7 +#define __REG_R8 8 +#define __REG_R9 9 +#define __REG_R10 10 +#define __REG_R11 11 +#define __REG_R12 12 +#define __REG_R13 13 +#define __REG_R14 14 +#define __REG_R15 15 +#define __REG_R16 16 +#define __REG_R17 17 +#define __REG_R18 18 +#define __REG_R19 19 +#define __REG_R20 20 +#define __REG_R21 21 +#define __REG_R22 22 +#define __REG_R23 23 +#define __REG_R24 24 +#define __REG_R25 25 +#define __REG_R26 26 +#define __REG_R27 27 +#define __REG_R28 28 +#define __REG_R29 29 +#define __REG_R30 30 +#define __REG_R31 31 diff --git a/include/common/arch/x86/asm/cmpxchg.h b/include/common/arch/x86/asm/cmpxchg.h index 4b6951933..fa5eccf09 100644 --- a/include/common/arch/x86/asm/cmpxchg.h +++ b/include/common/arch/x86/asm/cmpxchg.h @@ -17,7 +17,7 @@ */ #define __xchg_op(ptr, arg, op, lock) \ ({ \ - __typeof__ (*(ptr)) __ret = (arg); \ + __typeof__ (*(ptr)) __ret = (arg); \ switch (sizeof(*(ptr))) { \ case __X86_CASE_B: \ asm volatile (lock #op "b %b0, %1\n" \ diff --git a/lib/c/criu.c b/lib/c/criu.c index 6ac510a87..9e36a9795 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -41,10 +41,10 @@ void criu_free_service(criu_opts *opts) case CRIU_COMM_SK: free((void*)(opts->service_address)); break; - case CRIU_COMM_BIN: + case CRIU_COMM_BIN: free((void*)(opts->service_binary)); break; - default: + default: break; } } diff --git a/soccr/soccr.c b/soccr/soccr.c index 1e4827e48..20eabfbd4 100644 --- a/soccr/soccr.c +++ b/soccr/soccr.c @@ -158,13 +158,13 @@ void libsoccr_release(struct libsoccr_sk *sk) } struct soccr_tcp_info { - __u8 tcpi_state; - __u8 tcpi_ca_state; - __u8 tcpi_retransmits; - __u8 tcpi_probes; - __u8 tcpi_backoff; - __u8 tcpi_options; - __u8 tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4; + __u8 tcpi_state; + __u8 tcpi_ca_state; + __u8 tcpi_retransmits; + __u8 tcpi_probes; + __u8 tcpi_backoff; + __u8 tcpi_options; + __u8 tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4; }; static int refresh_sk(struct libsoccr_sk *sk, From 94541a81c007475a139f3a1990cc36dda3d01773 Mon Sep 17 00:00:00 2001 From: hygonsoc Date: Mon, 15 Apr 2019 01:35:04 +0800 Subject: [PATCH 1999/4375] arch: add Hygon CPU Vendor ID("HygonGenuine") checking in compel_cpuid() to enable Hygon Dhyana, which can reuse most AMD CPU support codes. Signed-off-by: hygonsoc Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c index 9152765bf..617512167 100644 --- a/compel/arch/x86/src/lib/cpu.c +++ b/compel/arch/x86/src/lib/cpu.c @@ -269,7 +269,8 @@ int compel_cpuid(compel_cpuinfo_t *c) if (!strcmp(c->x86_vendor_id, "GenuineIntel")) { c->x86_vendor = X86_VENDOR_INTEL; - } else if (!strcmp(c->x86_vendor_id, "AuthenticAMD")) { + } else if (!strcmp(c->x86_vendor_id, "AuthenticAMD") || + !strcmp(c->x86_vendor_id, "HygonGenuine")) { c->x86_vendor = X86_VENDOR_AMD; } else { pr_err("Unsupported CPU vendor %s\n", From b61b260412ce2722924589f63a6cccf281ceb0df Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 18 Apr 2019 12:57:15 +0300 Subject: [PATCH 2000/4375] sk-inet: udp -- Don't fail on calling shutdown on disconnected socket If socket has been connected and shutted down, it may get disconnected then leaving shutdown mode set inside (which we pull into image). On restore we should not fail when calling shutdown over -- the kernel has a hack to inform listeners even on closed sockets. From userspace perspective to reuse such socket one have to connect it back, so should be safe. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/sk-inet.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 0b7f0d7ff..ca5c9bf2c 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -894,9 +894,14 @@ done: (ie->proto == IPPROTO_UDP || ie->proto == IPPROTO_UDPLITE)) { if (shutdown(sk, sk_decode_shutdown(ie->shutdown))) { - pr_perror("Can't shutdown socket into %d", - sk_decode_shutdown(ie->shutdown)); - goto err; + if (ie->state != TCP_CLOSE && errno != ENOTCONN) { + pr_perror("Can't shutdown socket into %d", + sk_decode_shutdown(ie->shutdown)); + goto err; + } else { + pr_debug("Called shutdown on closed socket, " + "proto %d ino %x", ie->proto, ie->ino); + } } } From bd4a52e82e4fd9c60857970a23f038fa16b94fbc Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 18 Apr 2019 12:57:16 +0300 Subject: [PATCH 2001/4375] test: socket_udplite -- Test shudowned sockets Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm/static/socket_udplite.c | 60 +++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/test/zdtm/static/socket_udplite.c b/test/zdtm/static/socket_udplite.c index d2510ef2f..229005a10 100644 --- a/test/zdtm/static/socket_udplite.c +++ b/test/zdtm/static/socket_udplite.c @@ -28,9 +28,9 @@ static char buf[8]; int main(int argc, char **argv) { - int ret, sk1, sk2; + int ret, sk1, sk2, sk3, sk4; socklen_t len = sizeof(struct sockaddr_in); - struct sockaddr_in addr1, addr2, addr; + struct sockaddr_in addr1, addr2, addr3, addr4, addr; test_init(argc, argv); @@ -74,6 +74,62 @@ int main(int argc, char **argv) return 1; } + sk3 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE); + if (sk3 < 0) { + pr_perror("Can't create socket"); + return 1; + } + + memset(&addr3, 0, sizeof(addr3)); + addr3.sin_family = AF_INET; + addr3.sin_addr.s_addr = inet_addr("127.0.0.1"); + addr3.sin_port = htons(port + 2); + + ret = bind(sk3, (struct sockaddr *)&addr3, len); + if (ret < 0) { + pr_perror("Can't bind socket"); + return 1; + } + + sk4 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE); + if (sk4 < 0) { + pr_perror("Can't create socket"); + return 1; + } + + memset(&addr4, 0, sizeof(addr4)); + addr4.sin_family = AF_INET; + addr4.sin_addr.s_addr = inet_addr("0.0.0.0"); + addr4.sin_port = htons(0); + + ret = bind(sk4, (struct sockaddr *)&addr4, len); + if (ret < 0) { + pr_perror("Can't bind socket"); + return 1; + } + + ret = connect(sk4, (struct sockaddr *)&addr3, len); + if (ret < 0) { + pr_perror("Can't connect"); + return 1; + } + + ret = connect(sk3, (struct sockaddr *)&addr4, len); + if (ret < 0) { + pr_perror("Can't connect"); + return 1; + } + + if (shutdown(sk4, SHUT_RDWR)) { + pr_perror("Can't shutdown socket"); + return 1; + } + + if (shutdown(sk3, SHUT_RDWR)) { + pr_perror("Can't shutdown socket"); + return 1; + } + test_daemon(); test_waitsig(); From 4a090153c7f61d705c9251cfe1fe24f24454e069 Mon Sep 17 00:00:00 2001 From: Zhang Ning Date: Thu, 18 Apr 2019 10:13:58 +0800 Subject: [PATCH 2002/4375] criu/clone: stack size is too small for Android stack for clone is too small, child process will get wild pointer, and segfault. Error (criu/cr-restore.c:1418): 6082 killed by signal 11: Segmentation fault Error (criu/cr-restore.c:2303): Restoring FAILED. enlarge stack size to 1024, then no segfault. Cc: Chen Hu Signed-off-by: Zhang Ning Signed-off-by: Andrei Vagin --- criu/clone-noasan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/clone-noasan.c b/criu/clone-noasan.c index c44e71969..5ca280eb8 100644 --- a/criu/clone-noasan.c +++ b/criu/clone-noasan.c @@ -21,7 +21,7 @@ */ int clone_noasan(int (*fn)(void *), int flags, void *arg) { - void *stack_ptr = (void *)round_down((unsigned long)&stack_ptr - 256, 16); + void *stack_ptr = (void *)round_down((unsigned long)&stack_ptr - 1024, 16); BUG_ON((flags & CLONE_VM) && !(flags & CLONE_VFORK)); /* * Reserve some bytes for clone() internal needs From 1904a98550427e5c8d545e50ce3cd3f1d3369835 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sun, 28 Apr 2019 20:22:49 +0200 Subject: [PATCH 2003/4375] compel/s390: Fix memset sizeof sizeof(sizeof(x)) is the size of size_t. Instead use the size of the array to ensure the entire array is zeroed. Signed-off-by: Rikard Falkeborn Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/arch/s390/src/lib/infect.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compel/arch/s390/src/lib/infect.c b/compel/arch/s390/src/lib/infect.c index b690b8122..fcb463fa8 100644 --- a/compel/arch/s390/src/lib/infect.c +++ b/compel/arch/s390/src/lib/infect.c @@ -148,10 +148,8 @@ int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, memcpy(&dst_ext->vxrs_high, &fpregs->vxrs_high, sizeof(fpregs->vxrs_high)); } else { - memset(&dst_ext->vxrs_low, 0, - sizeof(sizeof(fpregs->vxrs_low))); - memset(&dst_ext->vxrs_high, 0, - sizeof(sizeof(fpregs->vxrs_high))); + memset(&dst_ext->vxrs_low, 0, sizeof(dst_ext->vxrs_low)); + memset(&dst_ext->vxrs_high, 0, sizeof(dst_ext->vxrs_high)); } return 0; } From 468f818f89b00c557cfca2fcc8e93b2d0128c339 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sun, 28 Apr 2019 20:22:50 +0200 Subject: [PATCH 2004/4375] compel/s390: Fix return value in error path In a function with return type bool, returning a non-zero value is interpreted as returning true. In the error paths we want to return false to indicate failure. Change -1 to false to fix this. Signed-off-by: Rikard Falkeborn Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/arch/s390/src/lib/infect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/arch/s390/src/lib/infect.c b/compel/arch/s390/src/lib/infect.c index fcb463fa8..00e9c36d2 100644 --- a/compel/arch/s390/src/lib/infect.c +++ b/compel/arch/s390/src/lib/infect.c @@ -493,7 +493,7 @@ bool arch_can_dump_task(struct parasite_ctl *ctl) if (psw->mask & PSW_MASK_RI) { if (get_ri_cb(pid, &fpregs) < 0) { pr_perror("Can't dump process with RI bit active"); - return -1; + return false; } } /* We don't support 24 and 31 bit mode - only 64 bit */ From 66846b26a070928a9ebd1a7b6816ccf1912b1605 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sun, 28 Apr 2019 20:22:51 +0200 Subject: [PATCH 2005/4375] test/zdtm: Move assignment after return value check If read() fails we can not use the return value as index. Move the use of it to after the error check to avoid this. Signed-off-by: Rikard Falkeborn Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- test/zdtm/lib/ns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/lib/ns.c b/test/zdtm/lib/ns.c index 6b4a75399..3099f7495 100644 --- a/test/zdtm/lib/ns.c +++ b/test/zdtm/lib/ns.c @@ -325,11 +325,11 @@ int ns_init(int argc, char **argv) exit(1); } ret = read(fd, buf, sizeof(buf) - 1); - buf[ret] = '\0'; if (ret == -1) { fprintf(stderr, "read() failed: %m\n"); exit(1); } + buf[ret] = '\0'; pid = atoi(buf); fprintf(stderr, "kill(%d, SIGTERM)\n", pid); From bdf8972b6151ff31740f3986a0c92b4abd674ce0 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sun, 28 Apr 2019 20:22:52 +0200 Subject: [PATCH 2006/4375] test: remove unused variables Signed-off-by: Rikard Falkeborn Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- test/others/bers/bers.c | 4 +--- test/others/libcriu/test_errno.c | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/test/others/bers/bers.c b/test/others/bers/bers.c index 208325c67..0954868ff 100644 --- a/test/others/bers/bers.c +++ b/test/others/bers/bers.c @@ -93,7 +93,6 @@ static int sys_gettid(void) static void dirtify_memory(unsigned long *chunks, size_t nr_chunks, size_t chunk_size, int mode, const size_t nr_pages) { - void *page; size_t i; pr_trace("filling memory\n"); @@ -115,7 +114,7 @@ static void dirtify_memory(unsigned long *chunks, size_t nr_chunks, static void dirtify_files(int *fd, size_t nr_files, size_t size) { size_t buf[8192]; - size_t i, j, c; + size_t i; /* * Note we don't write any _sane_ data here, the only @@ -265,7 +264,6 @@ int main(int argc, char *argv[]) char workdir[PATH_MAX]; int opt, idx, pidfd; char pidbuf[32]; - int status; pid_t pid; size_t i; diff --git a/test/others/libcriu/test_errno.c b/test/others/libcriu/test_errno.c index e09144304..8bd19fe2f 100644 --- a/test/others/libcriu/test_errno.c +++ b/test/others/libcriu/test_errno.c @@ -56,7 +56,7 @@ static int no_process(void) size_t len; ssize_t count; char *buf = NULL; - int pid, fd, ret; + int pid, ret; printf("--- Try to dump unexisting process\n"); From 8bc0ad91213d43dfcf6698af23ad13faf63e5f40 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sun, 28 Apr 2019 20:22:53 +0200 Subject: [PATCH 2007/4375] files-reg: Remove redundant inner if Remove a redundant if-statement, since the same condition is already checked in the outer if-statement. Signed-off-by: Rikard Falkeborn Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/files-reg.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 1a35166a5..3072289ef 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1704,12 +1704,10 @@ ext: } if (rfi->rfe->has_mode && (st.st_mode != rfi->rfe->mode)) { - if (st.st_mode != rfi->rfe->mode) { - pr_err("File %s has bad mode 0%o (expect 0%o)\n", - rfi->path, (int)st.st_mode, - rfi->rfe->mode); - return -1; - } + pr_err("File %s has bad mode 0%o (expect 0%o)\n", + rfi->path, (int)st.st_mode, + rfi->rfe->mode); + return -1; } /* From e95b5c67ae74759c9d08dc5465b032a7e391c3b1 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sun, 28 Apr 2019 20:22:54 +0200 Subject: [PATCH 2008/4375] test: add missing va_end Signed-off-by: Rikard Falkeborn Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- test/zdtm/static/autofs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/zdtm/static/autofs.c b/test/zdtm/static/autofs.c index c2e047714..f74bc35ac 100644 --- a/test/zdtm/static/autofs.c +++ b/test/zdtm/static/autofs.c @@ -49,6 +49,7 @@ static char *xvstrcat(char *str, const char *fmt, va_list args) if (new) { va_copy(tmp, args); ret = vsnprintf(new + offset, delta, fmt, tmp); + va_end(tmp); if (ret >= delta) { /* NOTE: vsnprintf returns the amount of bytes * * to allocate. */ From d04eba411f0740d93649371605ab0ab9e9abdfb3 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sun, 28 Apr 2019 20:22:55 +0200 Subject: [PATCH 2009/4375] test/bers: Fix sizeof to memset sizeof(fd) is the size of the pointer. Make sure the entire array is set by using the number of elements times the size of the elements. Signed-off-by: Rikard Falkeborn Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- test/others/bers/bers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/others/bers/bers.c b/test/others/bers/bers.c index 0954868ff..90b70c349 100644 --- a/test/others/bers/bers.c +++ b/test/others/bers/bers.c @@ -138,7 +138,7 @@ static int create_files(shared_data_t *shared, int *fd, size_t nr_files) char path[PATH_MAX]; size_t i; - memset(fd, 0xff, sizeof(fd)); + memset(fd, 0xff, sizeof(*fd) * MAX_CHUNK); pr_info("\tCreating %lu files\n", shared->opt_files); From 3b579373c1463d4cddd458cb6171917846815528 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 2 May 2019 02:34:42 +0100 Subject: [PATCH 2010/4375] zdtm/vdso/ia32: Use uint64_t for /proc/self/maps Add some comments to state things those might be not obvious. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/vdso-proxy.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/test/zdtm/static/vdso-proxy.c b/test/zdtm/static/vdso-proxy.c index 2381127b7..66d6741f4 100644 --- a/test/zdtm/static/vdso-proxy.c +++ b/test/zdtm/static/vdso-proxy.c @@ -1,3 +1,4 @@ +#include #include #include @@ -8,6 +9,10 @@ const char *test_author = "Dmitry Safonov "; #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) #define VDSO_BAD_ADDR (-1ul) +/* + * Use constant MAX_VMAS - to minimize the risk of allocating a new + * mapping or changing the size of existent VMA with realloc() + */ #define MAX_VMAS 80 #define BUF_SIZE 1024 @@ -18,8 +23,13 @@ const char *test_author = "Dmitry Safonov "; * Also previous vdso/vvar vma should still be present after C/R. */ struct vm_area { - unsigned long start; - unsigned long end; + /* + * Intentionally use 64bit integer to make sure that it's possible + * to parse mappings >4Gb - those might appear on ia32 + * that's restored by x86_64 CRIU ¯\(°_o)/¯ + */ + uint64_t start; + uint64_t end; bool is_vvar_or_vdso; }; @@ -43,11 +53,12 @@ static int parse_maps(struct vm_area *vmas) if (fgets(buf, BUF_SIZE, maps) == NULL) break; - v->start = strtoul(buf, &end, 16); - v->end = strtoul(end + 1, NULL, 16); + v->start = strtoull(buf, &end, 16); + v->end = strtoull(end + 1, NULL, 16); v->is_vvar_or_vdso |= strstr(buf, "[vdso]") != NULL; v->is_vvar_or_vdso |= strstr(buf, "[vvar]") != NULL; - test_msg("[NOTE]\tVMA: [%#lx, %#lx]\n", v->start, v->end); + test_msg("[NOTE]\tVMA: [%#" PRIx64 ", %#" PRIx64 "]\n", + v->start, v->end); } if (i == MAX_VMAS) { @@ -88,7 +99,7 @@ static int check_vvar_vdso(struct vm_area *before, struct vm_area *after) continue; if (cmp < 0) {/* Lost mapping */ - test_msg("[NOTE]\tLost mapping: %#lx-%#lx\n", + test_msg("[NOTE]\tLost mapping: %#" PRIx64 "-%#" PRIx64 "\n", before[i].start, before[i].end); j--; if (before[i].is_vvar_or_vdso) { @@ -98,7 +109,7 @@ static int check_vvar_vdso(struct vm_area *before, struct vm_area *after) continue; } - test_msg("[NOTE]\tNew mapping appeared: %#lx-%#lx\n", + test_msg("[NOTE]\tNew mapping appeared: %#" PRIx64 "-%#" PRIx64 "\n", after[j].start, after[j].end); i--; } From a0662df6f9e74da75e6f8f5c60160d37d02db117 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 2 May 2019 02:34:43 +0100 Subject: [PATCH 2011/4375] zdtm/vdso/ia32: Ignore vsyscall page appear Not a major bummer. On the other side, it's also becomes less important as it seems that distribution switches from LEGACY_VSYSCALL_EMULATE to LEGACY_VSYSCALL_NONE (by security reasons). Might be not worth fixing at all in the end. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/vdso-proxy.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/zdtm/static/vdso-proxy.c b/test/zdtm/static/vdso-proxy.c index 66d6741f4..ecb71e892 100644 --- a/test/zdtm/static/vdso-proxy.c +++ b/test/zdtm/static/vdso-proxy.c @@ -8,7 +8,7 @@ const char *test_doc = "Compare mappings before/after C/R for vdso/vvar presence const char *test_author = "Dmitry Safonov "; #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) -#define VDSO_BAD_ADDR (-1ul) +#define VSYSCALL_START 0xffffffffff600000ULL /* * Use constant MAX_VMAS - to minimize the risk of allocating a new * mapping or changing the size of existent VMA with realloc() @@ -55,6 +55,18 @@ static int parse_maps(struct vm_area *vmas) v->start = strtoull(buf, &end, 16); v->end = strtoull(end + 1, NULL, 16); + +#if defined(__i386__) + /* + * XXX: ia32 is being restored from x86_64 and leaves + * emulated vsyscall "mapping". Hopefully, will be done + * per-process, ignore for now. + */ + if (v->start == VSYSCALL_START) { + i--; + continue; + } +#endif v->is_vvar_or_vdso |= strstr(buf, "[vdso]") != NULL; v->is_vvar_or_vdso |= strstr(buf, "[vvar]") != NULL; test_msg("[NOTE]\tVMA: [%#" PRIx64 ", %#" PRIx64 "]\n", From 0e22e245e5429a906efa72e0555600b6488c68dc Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 2 May 2019 02:34:44 +0100 Subject: [PATCH 2012/4375] x86/compel/infect: Be verbose on remote mmap failure Error-case print missing. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/infect.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index 0737e07a3..11e7f4c91 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -375,10 +375,13 @@ void *remote_mmap(struct parasite_ctl *ctl, if (err < 0) return NULL; + if (map == -EACCES && (prot & PROT_WRITE) && (prot & PROT_EXEC)) { + pr_warn("mmap(PROT_WRITE | PROT_EXEC) failed for %d, " + "check selinux execmem policy\n", ctl->rpid); + return NULL; + } if (IS_ERR_VALUE(map)) { - if (map == -EACCES && (prot & PROT_WRITE) && (prot & PROT_EXEC)) - pr_warn("mmap(PROT_WRITE | PROT_EXEC) failed for %d, " - "check selinux execmem policy\n", ctl->rpid); + pr_err("remote mmap() failed: %s\n", strerror(-map)); return NULL; } From 8c5b25cbf5216d1253f8d19e7279b75b94e3ec2e Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 2 May 2019 02:34:45 +0100 Subject: [PATCH 2013/4375] zdtm/thread-bomb: Limit stack size in thread-bomb ia32 thread-bomb test failed when compel refused to seize the test, trying to mmap() in remote process and getting ENOMEM. It turns to be true - remote process thread-bomb was filled with 8Mb mappings created by pthread_create() (the default stack size). So, that 1024 * 8Mb is a bit too much to place in 4Gb. Fix the test on 32-bit platforms by using much smaller stack. Also check the return value of pthread_create(). Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/transition/thread-bomb.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/test/zdtm/transition/thread-bomb.c b/test/zdtm/transition/thread-bomb.c index 0b794ef2e..6621b18ed 100644 --- a/test/zdtm/transition/thread-bomb.c +++ b/test/zdtm/transition/thread-bomb.c @@ -11,6 +11,10 @@ #define exit_group(code) \ syscall(__NR_exit_group, code) +static pthread_attr_t attr; +/* Having in mind setup with 64 Kb large pages */ +static const size_t stack_size = 64 * 1024; + static void *thread_fn(void *arg) { pthread_t t, p, *self; @@ -24,14 +28,27 @@ static void *thread_fn(void *arg) self = malloc(sizeof(*self)); *self = pthread_self(); - pthread_create(&t, NULL, thread_fn, self); + pthread_create(&t, &attr, thread_fn, self); return NULL; } int main(int argc, char **argv) { - char *val; int max_nr = 1024, i; + char *val; + int err; + + err = pthread_attr_init(&attr); + if (err) { + pr_err("pthread_attr_init(): %d\n", err); + exit(1); + } + + err = pthread_attr_setstacksize(&attr, stack_size); + if (err) { + pr_err("pthread_attr_setstacksize(): %d\n", err); + exit(1); + } val = getenv("ZDTM_THREAD_BOMB"); if (val) @@ -43,7 +60,11 @@ int main(int argc, char **argv) for (i = 0; i < max_nr; i++) { pthread_t p; - pthread_create(&p, NULL, thread_fn, NULL); + err = pthread_create(&p, &attr, thread_fn, NULL); + if (err) { + pr_err("pthread_create(): %d\n", err); + exit(1); + } } test_daemon(); From 4eb2df5ae6f525e55506a92b679e293e36d7f993 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 1 May 2019 14:59:44 +0100 Subject: [PATCH 2014/4375] cgroup: Add "ignore" mode for --manage-cgroups Since commit 6c572bee8f10 ("cgroup: Set "soft" mode by default") it become impossible to set ignore mode at all. Provide a user option to do that. Cc: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 2 ++ criu/config.c | 2 ++ criu/crtools.c | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 414c9bb2d..6111c3baf 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -440,6 +440,8 @@ The 'mode' may be one of the following: *strict*::: Restore all cgroups and their properties from the scratch, requiring them to not present in the system. + *ignore*::: Don't deal with cgroups and pretend that they don't exist. + *--cgroup-root* ['controller'*:*]/'newroot':: Change the root cgroup the controller will be installed into. No controller means that root is the default for all controllers not specified. diff --git a/criu/config.c b/criu/config.c index d5354ae9c..11c49e73b 100644 --- a/criu/config.c +++ b/criu/config.c @@ -368,6 +368,8 @@ static int parse_manage_cgroups(struct cr_options *opts, const char *optarg) opts->manage_cgroups = CG_MODE_FULL; } else if (!strcmp(optarg, "strict")) { opts->manage_cgroups = CG_MODE_STRICT; + } else if (!strcmp(optarg, "ignore")) { + opts->manage_cgroups = CG_MODE_IGNORE; } else goto Esyntax; diff --git a/criu/crtools.c b/criu/crtools.c index 9c8064462..55562a63e 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -345,7 +345,8 @@ usage: " --irmap-scan-path FILE\n" " add a path the irmap hints to scan\n" " --manage-cgroups [m] dump/restore process' cgroups; argument can be one of\n" -" 'none', 'props', 'soft' (default), 'full' or 'strict'\n" +" 'none', 'props', 'soft' (default), 'full', 'strict'\n" +" or 'ignore'\n" " --cgroup-root [controller:]/newroot\n" " on dump: change the root for the controller that will\n" " be dumped. By default, only the paths with tasks in\n" From 9c9d1516932a4905d6aa9979ca3233b45c7e54b4 Mon Sep 17 00:00:00 2001 From: Harshavardhan Unnibhavi Date: Sun, 7 Apr 2019 14:29:53 +0530 Subject: [PATCH 2015/4375] test/exhaustive: Replace map by list comprehension Fixes #331. https://github.com/checkpoint-restore/criu/issues/331 Signed-off-by: Harshavardhan Unnibhavi Signed-off-by: Andrei Vagin --- test/exhaustive/unix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/exhaustive/unix.py b/test/exhaustive/unix.py index 6b1ed85d8..41053bd0d 100755 --- a/test/exhaustive/unix.py +++ b/test/exhaustive/unix.py @@ -415,7 +415,7 @@ class state: # one in which. At the same time really different states # shouldn't map to the same string. def describe(self): - sks = map(lambda x: x.describe(self), self.sockets) + sks = [x.describe(self) for x in self.sockets] sks = sorted(sks) return '_'.join(sks) From 66428d2845250a15d633bc6d63966b8001bb4dcf Mon Sep 17 00:00:00 2001 From: guoqd Date: Mon, 22 Apr 2019 14:40:11 +0800 Subject: [PATCH 2016/4375] [coredump]: correct the parsing of reg_files from files.img Fixes #679 --- coredump/criu_coredump/coredump.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coredump/criu_coredump/coredump.py b/coredump/criu_coredump/coredump.py index 963e8c61b..2b0c37f1a 100644 --- a/coredump/criu_coredump/coredump.py +++ b/coredump/criu_coredump/coredump.py @@ -163,7 +163,8 @@ class coredump_generator: self.mms[pid] = self._img_open_and_strip("mm", True, pid) self.pagemaps[pid] = self._img_open_and_strip("pagemap", False, pid) - self.reg_files = self._img_open_and_strip("reg-files", False) + files = self._img_open_and_strip("files", False) + self.reg_files = [ x["reg"] for x in files if x["type"]=="REG" ] for pid in self.pstree: self.coredumps[pid] = self._gen_coredump(pid) From 8e59ed48bd31e52831b77a339a900ad77cce09e0 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sat, 4 May 2019 19:53:55 +0100 Subject: [PATCH 2017/4375] zdtm: Simplify string to boolean conversion The built-in bool() function returns a boolean value by converting the input using standard truth testing procedure. https://docs.python.org/3/library/functions.html#bool Signed-off-by: Radostin Stoyanov --- test/zdtm.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 3344c0022..fb859d1c7 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -940,23 +940,23 @@ class criu: self.__dump_path = None self.__iter = 0 self.__prev_dump_iter = None - self.__page_server = (opts['page_server'] and True or False) - self.__remote_lazy_pages = (opts['remote_lazy_pages'] and True or False) + self.__page_server = bool(opts['page_server']) + self.__remote_lazy_pages = bool(opts['remote_lazy_pages']) self.__lazy_pages = (self.__remote_lazy_pages or - opts['lazy_pages'] and True or False) - self.__lazy_migrate = (opts['lazy_migrate'] and True or False) - self.__restore_sibling = (opts['sibling'] and True or False) - self.__join_ns = (opts['join_ns'] and True or False) - self.__empty_ns = (opts['empty_ns'] and True or False) - self.__fault = (opts['fault']) + bool(opts['lazy_pages'])) + self.__lazy_migrate = bool(opts['lazy_migrate']) + self.__restore_sibling = bool(opts['sibling']) + self.__join_ns = bool(opts['join_ns']) + self.__empty_ns = bool(opts['empty_ns']) + self.__fault = opts['fault'] self.__script = opts['script'] - self.__sat = (opts['sat'] and True or False) - self.__dedup = (opts['dedup'] and True or False) - self.__mdedup = (opts['noauto_dedup'] and True or False) - self.__user = (opts['user'] and True or False) - self.__leave_stopped = (opts['stop'] and True or False) + self.__sat = bool(opts['sat']) + self.__dedup = bool(opts['dedup']) + self.__mdedup = bool(opts['noauto_dedup']) + self.__user = bool(opts['user']) + self.__leave_stopped = bool(opts['stop']) self.__criu = (opts['rpc'] and criu_rpc or criu_cli) - self.__show_stats = (opts['show_stats'] and True or False) + self.__show_stats = bool(opts['show_stats']) self.__lazy_pages_p = None self.__page_server_p = None self.__dump_process = None From 9483b12935dfe3160cc30cf0d1b402c6ceb70711 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 16 Apr 2019 17:16:46 +0100 Subject: [PATCH 2018/4375] sk-inet: restore SO_BROADCAST option Inet sockets may have broadcasting capability enabled. The SO_BROADCAST option is used to enable this feature. It is a Boolean flag option, which is defined, fetched, and set with the int data type. During checkpoint, CRIU should detect the state of this flag, and during restore, it should be set appropriately. Fixes #673 Reported-by: @dubukuangye Signed-off-by: Radostin Stoyanov --- criu/sk-inet.c | 4 ++++ criu/sockets.c | 9 +++++++++ images/sk-opts.proto | 1 + 3 files changed, 14 insertions(+) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index ca5c9bf2c..ebae53113 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -742,6 +742,10 @@ static int post_open_inet_sk(struct file_desc *d, int sk) if (!val && restore_opt(sk, SOL_SOCKET, SO_REUSEPORT, &val)) return -1; + val = ii->ie->opts->so_broadcast; + if (!val && restore_opt(sk, SOL_SOCKET, SO_BROADCAST, &val)) + return -1; + return 0; } diff --git a/criu/sockets.c b/criu/sockets.c index 7f7453ca1..312b55c6d 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -566,6 +566,11 @@ int restore_socket_opts(int sk, SkOptsEntry *soe) pr_debug("\tset no_check for socket\n"); ret |= restore_opt(sk, SOL_SOCKET, SO_NO_CHECK, &val); } + if (soe->has_so_broadcast && soe->so_broadcast) { + val = 1; + pr_debug("\tset broadcast for socket\n"); + ret |= restore_opt(sk, SOL_SOCKET, SO_BROADCAST, &val); + } tv.tv_sec = soe->so_snd_tmo_sec; tv.tv_usec = soe->so_snd_tmo_usec; @@ -647,6 +652,10 @@ int dump_socket_opts(int sk, SkOptsEntry *soe) soe->has_so_no_check = true; soe->so_no_check = val ? true : false; + ret |= dump_opt(sk, SOL_SOCKET, SO_BROADCAST, &val); + soe->has_so_broadcast = true; + soe->so_broadcast = val ? true : false; + ret |= dump_bound_dev(sk, soe); ret |= dump_socket_filter(sk, soe); diff --git a/images/sk-opts.proto b/images/sk-opts.proto index af61975e9..c93ec5fd5 100644 --- a/images/sk-opts.proto +++ b/images/sk-opts.proto @@ -22,6 +22,7 @@ message sk_opts_entry { repeated fixed64 so_filter = 16; optional bool so_reuseport = 17; + optional bool so_broadcast = 18; } enum sk_shutdown { From 5af2bd905fad41f0a18c4b6e675429c5e0b741c7 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 25 Apr 2019 12:13:19 +0100 Subject: [PATCH 2019/4375] zdtm: Add UDP broadcast test Signed-off-by: Radostin Stoyanov --- test/zdtm/static/Makefile | 1 + test/zdtm/static/socket_udp-broadcast.c | 47 +++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 test/zdtm/static/socket_udp-broadcast.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 1ffaa9039..7799c0b0a 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -30,6 +30,7 @@ TST_NOFILE := \ socket_listen6 \ socket_listen4v6 \ socket_udp \ + socket_udp-broadcast \ socket_udp-corked \ socket6_udp \ socket_udp_shutdown \ diff --git a/test/zdtm/static/socket_udp-broadcast.c b/test/zdtm/static/socket_udp-broadcast.c new file mode 100644 index 000000000..a5fb55444 --- /dev/null +++ b/test/zdtm/static/socket_udp-broadcast.c @@ -0,0 +1,47 @@ +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "test checkpoint/restore of SO_BROADCAST\n"; +const char *test_author = "Radostin Stoyanov \n"; + +/* Description: + * Create UDP socket, set SO_BROADCAST and verify its value after restore. + */ + +int main(int argc, char **argv) +{ + int sockfd; + int val; + socklen_t len = sizeof(val); + + test_init(argc, argv); + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { + pr_perror("Can't create socket"); + return 1; + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &(int){ 1 }, len)) { + pr_perror("setsockopt"); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (getsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &val, &len)) { + pr_perror("getsockopt"); + return 1; + } + + if (len != sizeof(val) || val != 1) { + fail("SO_BROADCAST not set"); + return 1; + } + + pass(); + return 0; +} From fad89f892dc7d0cf9c2989587627be5d462d446f Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 21 Apr 2019 07:48:41 +0100 Subject: [PATCH 2020/4375] util: cr_daemon: Drop keep_fd argument When running lazy-pages in daemon mode, file descriptor 3 is reused after fork to 'protect' the opened UNIX socket. However, fd 3 happens to correspond to the opened image directory. Thus, when this file descriptor is overwritten CRIU fails with the following error: $ criu lazy-pages -D --page-server \ --address --port -d ... (06.835596) Error (criu/image.c:470): Unable to open pagemap-1.img: Not a directory (06.835855) Error (criu/uffd.c:773): uffd: 1-7: Failed to open pagemap The need for keep_fd is really only necessary if the file descriptor we would like to 'protect' is 0, 1 or 2. Assuming that the standard file descriptors STDIN, STDOUT and STDERR are open this hack is unnecessary. Signed-off-by: Radostin Stoyanov --- criu/include/util.h | 2 +- criu/uffd.c | 2 +- criu/util.c | 14 ++------------ 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/criu/include/util.h b/criu/include/util.h index 621abb4a0..313aacd8c 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -176,7 +176,7 @@ extern int is_anon_link_type(char *link, char *type); extern int cr_system(int in, int out, int err, char *cmd, char *const argv[], unsigned flags); extern int cr_system_userns(int in, int out, int err, char *cmd, char *const argv[], unsigned flags, int userns_pid); -extern int cr_daemon(int nochdir, int noclose, int *keep_fd, int close_fd); +extern int cr_daemon(int nochdir, int noclose, int close_fd); extern int close_status_fd(void); extern int is_root_user(void); diff --git a/criu/uffd.c b/criu/uffd.c index e437f1f63..6699cb14a 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1427,7 +1427,7 @@ int cr_lazy_pages(bool daemon) return -1; if (daemon) { - ret = cr_daemon(1, 0, &lazy_sk, -1); + ret = cr_daemon(1, 0, -1); if (ret == -1) { pr_err("Can't run in the background\n"); return -1; diff --git a/criu/util.c b/criu/util.c index 9dd5010a1..97084939e 100644 --- a/criu/util.c +++ b/criu/util.c @@ -643,7 +643,7 @@ int close_status_fd(void) return close_safe(&opts.status_fd); } -int cr_daemon(int nochdir, int noclose, int *keep_fd, int close_fd) +int cr_daemon(int nochdir, int noclose, int close_fd) { int pid; @@ -666,16 +666,6 @@ int cr_daemon(int nochdir, int noclose, int *keep_fd, int close_fd) if (close_fd != -1) close(close_fd); - if ((*keep_fd != -1) && (*keep_fd != 3)) { - fd = dup2(*keep_fd, 3); - if (fd < 0) { - pr_perror("Dup2 failed"); - return -1; - } - close(*keep_fd); - *keep_fd = fd; - } - fd = open("/dev/null", O_RDWR); if (fd < 0) { pr_perror("Can't open /dev/null"); @@ -1144,7 +1134,7 @@ int run_tcp_server(bool daemon_mode, int *ask, int cfd, int sk) socklen_t clen = sizeof(caddr); if (daemon_mode) { - ret = cr_daemon(1, 0, ask, cfd); + ret = cr_daemon(1, 0, cfd); if (ret == -1) { pr_err("Can't run in the background\n"); goto out; From 635a66d8ae347e16b0f52baa7ea852e9648f6452 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 1 May 2019 19:41:34 +0100 Subject: [PATCH 2021/4375] config: Exit with error if ps-socket is std fd In daemon mode the standard file descriptors 0, 1 and 2 will be closed and ps-socket should not be one of them. Signed-off-by: Radostin Stoyanov --- criu/config.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/criu/config.c b/criu/config.c index 11c49e73b..bcf5176d9 100644 --- a/criu/config.c +++ b/criu/config.c @@ -846,9 +846,16 @@ int check_options() return 1; } - if (opts.ps_socket != -1 && (opts.addr || opts.port)) - pr_warn("Using --address or --port in " - "combination with --ps-socket is obsolete\n"); + if (opts.ps_socket != -1) { + if (opts.addr || opts.port) + pr_warn("Using --address or --port in " + "combination with --ps-socket is obsolete\n"); + if (opts.ps_socket <= STDERR_FILENO && opts.daemon_mode) { + pr_err("Standard file descriptors will be closed" + " in daemon mode\n"); + return 1; + } + } if (check_namespace_opts()) { pr_err("Error: namespace flags conflict\n"); From 530c03a202763e7a22f8c821ed5608731c2b28da Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 5 Apr 2019 14:06:44 +0100 Subject: [PATCH 2022/4375] crtools: Print err messages from check_options() When check_options() exits with an error (return value != 0) the logging is not yet initialised, and therefore the error messages are not printed out. Since this affects only command-line usage, and only when check_options() reports an error, flush the early log messages to STDERR. Signed-off-by: Radostin Stoyanov --- criu/crtools.c | 4 +++- criu/include/log.h | 2 ++ criu/log.c | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index 55562a63e..6c83b27da 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -95,8 +95,10 @@ int main(int argc, char *argv[], char *envp[]) return cr_service_work(atoi(argv[2])); } - if (check_options()) + if (check_options()) { + flush_early_log_buffer(STDERR_FILENO); return 1; + } if (opts.imgs_dir == NULL) SET_CHAR_OPTS(imgs_dir, "."); diff --git a/criu/include/log.h b/criu/include/log.h index 797be1bb2..15787b09f 100644 --- a/criu/include/log.h +++ b/criu/include/log.h @@ -30,6 +30,8 @@ extern void print_on_level(unsigned int loglevel, const char *format, ...) # define LOG_PREFIX #endif +void flush_early_log_buffer(int fd); + #define print_once(loglevel, fmt, ...) \ do { \ static bool __printed; \ diff --git a/criu/log.c b/criu/log.c index edd2511ce..1e43f663d 100644 --- a/criu/log.c +++ b/criu/log.c @@ -170,7 +170,7 @@ struct early_log_hdr { uint16_t len; }; -static void flush_early_log_buffer(int fd) +void flush_early_log_buffer(int fd) { unsigned int pos = 0; int ret; From 1bc68dd873cbc0bbeba0e365a3ababe120d2ef2e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 14 May 2019 11:34:22 +0300 Subject: [PATCH 2023/4375] lazy-pages: fix stack detection The commit 5432a964dcc7 ("lazy-pages: don't mark current stack page as lazy") tried to make the pages surrounding the stack pointers non-lazy. Unfortunately, it used a wrong mask for the detection. Fix it. Signed-off-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/mem.c b/criu/mem.c index 8015a7e4e..df87ed5b0 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -149,7 +149,7 @@ static bool is_stack(struct pstree_item *item, unsigned long vaddr) for (i = 0; i < item->nr_threads; i++) { uint64_t sp = dmpi(item)->thread_sp[i]; - if (!((sp ^ vaddr) & PAGE_MASK)) + if (!((sp ^ vaddr) & ~PAGE_MASK)) return true; } From 866bed0ed2ecfa1dd87367c3b4e0f6bb45a587f3 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 17 May 2019 23:53:00 +0100 Subject: [PATCH 2024/4375] build/pie: Add comments to build files And drop a stale comment that doesn't clearify anything. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 4 ++++ criu/pie/Makefile.library | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 24f97ea0d..739191308 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -1,3 +1,7 @@ +# Recipes to compile PIEs: parastie and restorer +# Compel will deal with converting the result binaries +# to a C array to be used in CRIU. + target := parasite restorer CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index f268b5ded..a48a0ea4c 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -1,3 +1,9 @@ +# PIE library is a static library that's going to be linked into +# *both* CRIU binary and PIEs (parasite/restorer). +# Please, make sure that you're including here only objects +# those will be used in CRIU too. For objects files only for PIEs +# edit their separate recipes criu/pie/Makefile + lib-name := pie.lib.a CFLAGS += -fno-stack-protector -DCR_NOGLIBC -fpie @@ -27,12 +33,6 @@ ifeq ($(SRCARCH),x86) CFLAGS_util-vdso-elf32.o += -DCONFIG_VDSO_32 endif -# -# We can't provide proper mount implementation -# in parasite code -- it requires run-time rellocation -# applications, which is not the target of the -# project. -# CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) asflags-y := -D__ASSEMBLY__ From 1b66b66b56517a1e522530efe159c7322bafd921 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 17 May 2019 23:53:01 +0100 Subject: [PATCH 2025/4375] arm/build: Move -marm cflag to CFLAGS_PIE I don't want to see CFLAGS redefined per-architecture in PIE makefiles in couple of places. Clean it up. The only expected per-arch ifdeffery should be object files. Also add a big comment about -marm vs -mthumb[2] Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 7 +++++++ criu/pie/Makefile | 4 ---- criu/pie/Makefile.library | 5 ----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 38887da99..50948787a 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,13 @@ ifeq ($(ARCH),arm) endif PROTOUFIX := y + # For simplicity - compile code in Arm mode without interwork. + # We could choose Thumb mode as default instead - but a dirty + # experiment shows that with 90Kb PIEs Thumb code doesn't save + # even one page. So, let's stick so far to Arm mode as it's more + # universal around all different Arm variations, until someone + # will find any use for Thumb mode. -dima + CFLAGS_PIE := -marm endif ifeq ($(ARCH),aarch64) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 739191308..c9e8a3d82 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -17,10 +17,6 @@ ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) compel_plugins := $(shell $(COMPEL_BIN) plugins) endif -ifeq ($(SRCARCH),arm) - ccflags-y += -marm -endif - asflags-y += -D__ASSEMBLY__ LDS := compel/arch/$(SRCARCH)/scripts/compel-pack.lds.S diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index a48a0ea4c..b7918438b 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -38,8 +38,3 @@ CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) asflags-y := -D__ASSEMBLY__ ccflags-y += $(COMPEL_UAPI_INCLUDES) ccflags-y += $(CFLAGS_PIE) - -ifeq ($(SRCARCH),arm) - ccflags-y += -marm -endif - From 9df47bb26f95214383554640a1f7ec65e7841cbc Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 17 May 2019 23:53:02 +0100 Subject: [PATCH 2026/4375] build: Move __ASSEMBLY__ define to the top Makefile __ASSEMBLY__ is used to guard C-related code in headers from asm-compatible defines. We actually want every .S file to be assembled with -D__ASSEMBLY__ not to burst with C in asm file. Move __ASSEMBLY__ from all local asflags to top Makefile's AFLAGS. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 3 ++- compel/plugins/Makefile | 2 +- criu/arch/aarch64/Makefile | 1 - criu/arch/arm/Makefile | 1 - criu/arch/x86/Makefile | 2 +- criu/pie/Makefile | 2 -- criu/pie/Makefile.library | 1 - 7 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 50948787a..84fc0841f 100644 --- a/Makefile +++ b/Makefile @@ -129,9 +129,10 @@ ifeq ($(GMON),1) export GMON GMONLDOPT endif +AFLAGS += -D__ASSEMBLY__ CFLAGS += $(USERCFLAGS) $(WARNINGS) $(DEFINES) -iquote include/ HOSTCFLAGS += $(WARNINGS) $(DEFINES) -iquote include/ -export CFLAGS USERCLFAGS HOSTCFLAGS +export AFLAGS CFLAGS USERCLFAGS HOSTCFLAGS # Default target all: criu lib crit diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 60b78473c..8f44ba86d 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -29,7 +29,7 @@ asflags-y += -iquote $(PLUGIN_ARCH_DIR) # General flags for assembly asflags-y += -fpie -Wstrict-prototypes -asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer +asflags-y += -nostdlib -fomit-frame-pointer asflags-y += -fno-stack-protector ldflags-y += -z noexecstack diff --git a/criu/arch/aarch64/Makefile b/criu/arch/aarch64/Makefile index 49ef6a480..fd721d12f 100644 --- a/criu/arch/aarch64/Makefile +++ b/criu/arch/aarch64/Makefile @@ -3,7 +3,6 @@ builtin-name := crtools.built-in.o ccflags-y += -iquote $(obj)/include -iquote criu/include ccflags-y += -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) -asflags-y += -D__ASSEMBLY__ ldflags-y += -r obj-y += cpu.o diff --git a/criu/arch/arm/Makefile b/criu/arch/arm/Makefile index d01c69a16..5142fbe12 100644 --- a/criu/arch/arm/Makefile +++ b/criu/arch/arm/Makefile @@ -4,7 +4,6 @@ ccflags-y += -iquote $(obj)/include ccflags-y += -iquote criu/include -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) -asflags-y += -D__ASSEMBLY__ ldflags-y += -r -z noexecstack obj-y += cpu.o diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index 20a40e4ae..ca92a241c 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -5,7 +5,7 @@ ccflags-y += -iquote criu/include -iquote include ccflags-y += $(COMPEL_UAPI_INCLUDES) asflags-y += -Wstrict-prototypes -asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer +asflags-y += -nostdlib -fomit-frame-pointer asflags-y += -iquote $(obj)/include ldflags-y += -r -z noexecstack diff --git a/criu/pie/Makefile b/criu/pie/Makefile index c9e8a3d82..5c0606786 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -17,8 +17,6 @@ ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) compel_plugins := $(shell $(COMPEL_BIN) plugins) endif -asflags-y += -D__ASSEMBLY__ - LDS := compel/arch/$(SRCARCH)/scripts/compel-pack.lds.S restorer-obj-y += ./$(ARCH_DIR)/restorer.o diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index b7918438b..577497f5a 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -35,6 +35,5 @@ endif CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) -asflags-y := -D__ASSEMBLY__ ccflags-y += $(COMPEL_UAPI_INCLUDES) ccflags-y += $(CFLAGS_PIE) From 9f081e576b965ee593a4ea0c568364937b502d96 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 17 May 2019 23:53:03 +0100 Subject: [PATCH 2027/4375] make: Don't export ccflags-y As far as I know, difference between CFLAGS and ccflags-y in kernel is that CFLAGS are global and exported and ccflags-y are per-Makefile. So, exporting ccflags-y should be omitted. While at it, remove COMPEL_UAPI_INCLUDES - they're added to CFLAGS straight away and exported to sub-makes, so no-one need to include them twice. Also, remove from sub-Makefiles -iquote(s) for includes those are already added in criu/Makefile Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/Makefile | 24 ++++++++++-------------- criu/Makefile.crtools | 1 - criu/arch/aarch64/Makefile | 3 --- criu/arch/arm/Makefile | 4 ---- criu/arch/ppc64/Makefile | 3 --- criu/arch/s390/Makefile | 3 --- criu/arch/x86/Makefile | 4 ---- criu/pie/Makefile | 1 - criu/pie/Makefile.library | 2 -- 9 files changed, 10 insertions(+), 35 deletions(-) diff --git a/criu/Makefile b/criu/Makefile index 797878176..1e9a16789 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -7,9 +7,8 @@ PIE_DIR := criu/pie export ARCH_DIR PIE_DIR ifeq ($(filter clean mrproper,$(MAKECMDGOALS)),) - COMPEL_UAPI_INCLUDES := $(shell $(COMPEL_BIN) includes) - export COMPEL_UAPI_INCLUDES - COMPEL_LIBS := $(shell $(COMPEL_BIN) --static libs) + CFLAGS += $(shell $(COMPEL_BIN) includes) + COMPEL_LIBS := $(shell $(COMPEL_BIN) --static libs) endif # @@ -20,17 +19,14 @@ CONFIG-DEFINES += -DUSER_CONFIG_DIR='".criu/"' # # General flags. -ccflags-y += -fno-strict-aliasing -ccflags-y += -iquote criu/include -ccflags-y += -iquote include -ccflags-y += -iquote images -ccflags-y += -iquote $(ARCH_DIR)/include -ccflags-y += -iquote . -ccflags-y += $(shell pkg-config --cflags libnl-3.0) -ccflags-y += $(COMPEL_UAPI_INCLUDES) -ccflags-y += $(CONFIG-DEFINES) - -export ccflags-y +CFLAGS += -fno-strict-aliasing +CFLAGS += -iquote criu/include +CFLAGS += -iquote include +CFLAGS += -iquote images +CFLAGS += -iquote $(ARCH_DIR)/include +CFLAGS += -iquote . +CFLAGS += $(shell pkg-config --cflags libnl-3.0) +CFLAGS += $(CONFIG-DEFINES) ifeq ($(GMON),1) CFLAGS += -pg diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 3717467c2..05d587d44 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -1,5 +1,4 @@ ccflags-y += -iquote criu/$(ARCH) -ccflags-y += $(COMPEL_UAPI_INCLUDES) CFLAGS_REMOVE_clone-noasan.o += $(CFLAGS-ASAN) CFLAGS_kerndat.o += -DKDAT_MAGIC_2=${shell echo $${SOURCE_DATE_EPOCH:-$$(date +%s)}} -DKDAT_RUNDIR=\"$(RUNDIR)\" ldflags-y += -r diff --git a/criu/arch/aarch64/Makefile b/criu/arch/aarch64/Makefile index fd721d12f..b26487367 100644 --- a/criu/arch/aarch64/Makefile +++ b/criu/arch/aarch64/Makefile @@ -1,8 +1,5 @@ builtin-name := crtools.built-in.o -ccflags-y += -iquote $(obj)/include -iquote criu/include -ccflags-y += -iquote include -ccflags-y += $(COMPEL_UAPI_INCLUDES) ldflags-y += -r obj-y += cpu.o diff --git a/criu/arch/arm/Makefile b/criu/arch/arm/Makefile index 5142fbe12..b111e5959 100644 --- a/criu/arch/arm/Makefile +++ b/criu/arch/arm/Makefile @@ -1,9 +1,5 @@ builtin-name := crtools.built-in.o -ccflags-y += -iquote $(obj)/include -ccflags-y += -iquote criu/include -iquote include -ccflags-y += $(COMPEL_UAPI_INCLUDES) - ldflags-y += -r -z noexecstack obj-y += cpu.o diff --git a/criu/arch/ppc64/Makefile b/criu/arch/ppc64/Makefile index ff0a71207..f37337f74 100644 --- a/criu/arch/ppc64/Makefile +++ b/criu/arch/ppc64/Makefile @@ -1,8 +1,5 @@ builtin-name := crtools.built-in.o -ccflags-y += -iquote $(obj)/include -ccflags-y += -iquote criu/include -iquote include -ccflags-y += $(COMPEL_UAPI_INCLUDES) ldflags-y += -r obj-y += cpu.o diff --git a/criu/arch/s390/Makefile b/criu/arch/s390/Makefile index ff0a71207..f37337f74 100644 --- a/criu/arch/s390/Makefile +++ b/criu/arch/s390/Makefile @@ -1,8 +1,5 @@ builtin-name := crtools.built-in.o -ccflags-y += -iquote $(obj)/include -ccflags-y += -iquote criu/include -iquote include -ccflags-y += $(COMPEL_UAPI_INCLUDES) ldflags-y += -r obj-y += cpu.o diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile index ca92a241c..618e85bb3 100644 --- a/criu/arch/x86/Makefile +++ b/criu/arch/x86/Makefile @@ -1,9 +1,5 @@ builtin-name := crtools.built-in.o -ccflags-y += -iquote $(obj)/include -ccflags-y += -iquote criu/include -iquote include -ccflags-y += $(COMPEL_UAPI_INCLUDES) - asflags-y += -Wstrict-prototypes asflags-y += -nostdlib -fomit-frame-pointer asflags-y += -iquote $(obj)/include diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 5c0606786..526e4e1ad 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -5,7 +5,6 @@ target := parasite restorer CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) -ccflags-y += $(COMPEL_UAPI_INCLUDES) ccflags-y += $(CFLAGS_PIE) ccflags-y += -DCR_NOGLIBC ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 577497f5a..467dfd6b6 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -34,6 +34,4 @@ ifeq ($(SRCARCH),x86) endif CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) - -ccflags-y += $(COMPEL_UAPI_INCLUDES) ccflags-y += $(CFLAGS_PIE) From e689144cb0b2ba39030ac2a880eac5a05a7c1b03 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 17 May 2019 23:53:04 +0100 Subject: [PATCH 2028/4375] Makefile.crtools: Remove bogus ccflags-y There ain't even such path in sources. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/Makefile.crtools | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 05d587d44..13ea22775 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -1,4 +1,3 @@ -ccflags-y += -iquote criu/$(ARCH) CFLAGS_REMOVE_clone-noasan.o += $(CFLAGS-ASAN) CFLAGS_kerndat.o += -DKDAT_MAGIC_2=${shell echo $${SOURCE_DATE_EPOCH:-$$(date +%s)}} -DKDAT_RUNDIR=\"$(RUNDIR)\" ldflags-y += -r From a989c6add06120285cb9edc5020ea5ed27f1a0ac Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 17 May 2019 23:53:05 +0100 Subject: [PATCH 2029/4375] build: Use cflags from compel for pie.lib.a As pie.lib.a linked also to PIEs - we need to use missing flags as -nostdlib and -fomit-frame-pointer. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/Makefile | 1 + criu/pie/Makefile | 1 - criu/pie/Makefile.library | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/Makefile b/criu/Makefile index 1e9a16789..3de6eb217 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -9,6 +9,7 @@ export ARCH_DIR PIE_DIR ifeq ($(filter clean mrproper,$(MAKECMDGOALS)),) CFLAGS += $(shell $(COMPEL_BIN) includes) COMPEL_LIBS := $(shell $(COMPEL_BIN) --static libs) + CFLAGS_PIE += $(shell $(COMPEL_BIN) cflags) endif # diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 526e4e1ad..35aa78bd3 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -11,7 +11,6 @@ ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) - CFLAGS += $(shell $(COMPEL_BIN) cflags) LDFLAGS += $(shell $(COMPEL_BIN) ldflags) compel_plugins := $(shell $(COMPEL_BIN) plugins) endif diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 467dfd6b6..2d11ad923 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -6,7 +6,7 @@ lib-name := pie.lib.a -CFLAGS += -fno-stack-protector -DCR_NOGLIBC -fpie +CFLAGS += -DCR_NOGLIBC lib-y += util.o From 3dc4034d00b52a0cdab9d730f1190d81c9fc1130 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 17 May 2019 23:53:06 +0100 Subject: [PATCH 2030/4375] compel: Don't use CFLAGS_PIE for libcompel.so It's needed for PIEs, but not for the library. It comes earlier than commit 61e6c01d0964, but I don't see the point. Regardles, I'm a bit afraid to break s390, hopefully testing covers the platform. This and the next one "make: Move CR_NOGLIBC into CFLAGS_PIE" should be reverted/dropped from criu-dev if they turn to be breaking something. Cc: Michael Holzheu Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/compel/Makefile b/compel/Makefile index 45736f29e..de9318c42 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -11,7 +11,6 @@ ccflags-y += -iquote compel/arch/$(ARCH)/src/lib/include ccflags-y += -iquote compel/include ccflags-y += -fno-strict-aliasing ccflags-y += -fPIC -ccflags-y += $(CFLAGS_PIE) ldflags-y += -r # From 60d79020428269fec714fcfb97dafcc9ec77600b Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 17 May 2019 23:53:07 +0100 Subject: [PATCH 2031/4375] make: Move CR_NOGLIBC into CFLAGS_PIE Lesser duplication, cleaner Makefiles. Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 2 ++ compel/plugins/Makefile | 2 +- criu/pie/Makefile | 1 - criu/pie/Makefile.library | 2 -- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 84fc0841f..cee8a42c9 100644 --- a/Makefile +++ b/Makefile @@ -85,6 +85,8 @@ ifeq ($(ARCH),s390) DEFINES := -DCONFIG_S390 CFLAGS_PIE := -fno-optimize-sibling-calls endif + +CFLAGS_PIE += -DCR_NOGLIBC export CFLAGS_PIE LDARCH ?= $(SRCARCH) diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 8f44ba86d..a326e2a66 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -1,5 +1,5 @@ CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) -CFLAGS += -DCR_NOGLIBC -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 +CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 PLUGIN_ARCH_DIR := compel/arch/$(ARCH)/plugins diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 35aa78bd3..bb65f8908 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -6,7 +6,6 @@ target := parasite restorer CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) ccflags-y += $(CFLAGS_PIE) -ccflags-y += -DCR_NOGLIBC ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 2d11ad923..423c782aa 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -6,8 +6,6 @@ lib-name := pie.lib.a -CFLAGS += -DCR_NOGLIBC - lib-y += util.o ifeq ($(VDSO),y) From 97f8c0f359a5f9a7a9e3f2165e887531e2d7b7b9 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 17 May 2019 23:53:08 +0100 Subject: [PATCH 2032/4375] criu/ia32: Consolidate compat vdso and move to arch/x86 Do the cleanup that was long pending by XXX :) Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/x86/include/asm/restorer.h | 8 -------- criu/arch/x86/include/asm/vdso.h | 24 ++++++++++++++++++++++++ criu/include/util-vdso.h | 13 ++----------- criu/pie/parasite-vdso.c | 14 ++------------ 4 files changed, 28 insertions(+), 31 deletions(-) diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index 3c43ce688..25559b57c 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -72,14 +72,6 @@ static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) : "r"(ret) \ : "memory") -#ifndef ARCH_MAP_VDSO_32 -# define ARCH_MAP_VDSO_32 0x2002 -#endif - -#ifndef ARCH_MAP_VDSO_64 -# define ARCH_MAP_VDSO_64 0x2003 -#endif - static inline void __setup_sas_compat(struct ucontext_ia32* uc, ThreadSasEntry *sas) { diff --git a/criu/arch/x86/include/asm/vdso.h b/criu/arch/x86/include/asm/vdso.h index d6c2f1b8c..ae893b8d7 100644 --- a/criu/arch/x86/include/asm/vdso.h +++ b/criu/arch/x86/include/asm/vdso.h @@ -23,5 +23,29 @@ "__kernel_sigreturn", \ "__kernel_rt_sigreturn" +#ifndef ARCH_MAP_VDSO_32 +# define ARCH_MAP_VDSO_32 0x2002 +#endif + +#ifndef ARCH_MAP_VDSO_64 +# define ARCH_MAP_VDSO_64 0x2003 +#endif + +#if defined(CONFIG_COMPAT) && !defined(__ASSEMBLY__) +struct vdso_symtable; +extern int vdso_fill_symtable(uintptr_t mem, size_t size, + struct vdso_symtable *t); +extern int vdso_fill_symtable_compat(uintptr_t mem, size_t size, + struct vdso_symtable *t); + +static inline int __vdso_fill_symtable(uintptr_t mem, size_t size, + struct vdso_symtable *t, bool compat_vdso) +{ + if (compat_vdso) + return vdso_fill_symtable_compat(mem, size, t); + else + return vdso_fill_symtable(mem, size, t); +} +#endif #endif /* __CR_ASM_VDSO_H__ */ diff --git a/criu/include/util-vdso.h b/criu/include/util-vdso.h index 05b8326f5..c74360c87 100644 --- a/criu/include/util-vdso.h +++ b/criu/include/util-vdso.h @@ -75,6 +75,8 @@ struct vdso_maps { #define ELF_ST_BIND ELF32_ST_BIND #endif +# define vdso_fill_symtable vdso_fill_symtable_compat + #else /* CONFIG_VDSO_32 */ #define Ehdr_t Elf64_Ehdr @@ -92,17 +94,6 @@ struct vdso_maps { #endif /* CONFIG_VDSO_32 */ -#if defined(CONFIG_VDSO_32) -# define vdso_fill_symtable vdso_fill_symtable_compat -#endif - extern int vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t); -#if defined(CONFIG_X86_64) && defined(CONFIG_COMPAT) -#ifndef ARCH_MAP_VDSO_32 -# define ARCH_MAP_VDSO_32 0x2002 -#endif -extern int vdso_fill_symtable_compat(uintptr_t mem, size_t size, - struct vdso_symtable *t); -#endif #endif /* __CR_UTIL_VDSO_H__ */ diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 8072c11f7..dc73fb53e 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -74,18 +74,8 @@ int vdso_do_park(struct vdso_maps *rt, unsigned long park_at, return ret; } -/* XXX: move in arch/ */ -#if defined(CONFIG_X86_64) && defined(CONFIG_COMPAT) -int __vdso_fill_symtable(uintptr_t mem, size_t size, - struct vdso_symtable *t, bool compat_vdso) -{ - if (compat_vdso) - return vdso_fill_symtable_compat(mem, size, t); - else - return vdso_fill_symtable(mem, size, t); -} -#else -int __vdso_fill_symtable(uintptr_t mem, size_t size, +#ifndef CONFIG_COMPAT +static int __vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t, bool __always_unused compat_vdso) { return vdso_fill_symtable(mem, size, t); From 13c275ad26393d9d823a4654368928b1fc417a0b Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 17 May 2019 23:53:09 +0100 Subject: [PATCH 2033/4375] build/criu/pie: Move trampolines to restorer-obj-y We don't need patching vdso neither in parasite nor in criu. Move it to restorer-only objects. Note that we need filling symtables everywhere (kdat/parasite/restorer), this change doesn't move util-vdso.o which has vdso_fill_symtable(). [those files ask for a proper rename, but it's not directly related to the change, so yet TODO] Reviewed-by: Cyrill Gorcunov Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/Makefile | 12 ++++++++++++ criu/pie/Makefile.library | 10 +--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index bb65f8908..bdff44816 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -25,6 +25,18 @@ ifeq ($(ARCH),x86) endif endif +ifeq ($(VDSO),y) + restorer-obj-y += parasite-vdso.o ./$(ARCH_DIR)/vdso-pie.o + + ifeq ($(SRCARCH),aarch64) + restorer-obj-y += ./$(ARCH_DIR)/intraprocedure.o + endif + + ifeq ($(SRCARCH),ppc64) + restorer-obj-y += ./$(ARCH_DIR)/vdso-trampoline.o + endif +endif + define gen-pie-rules $(1)-obj-y += $(1).o $(1)-obj-e += pie.lib.a diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 423c782aa..0a33a8861 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -9,15 +9,7 @@ lib-name := pie.lib.a lib-y += util.o ifeq ($(VDSO),y) - lib-y += util-vdso.o parasite-vdso.o ./$(ARCH_DIR)/vdso-pie.o - - ifeq ($(SRCARCH),aarch64) - lib-y += ./$(ARCH_DIR)/intraprocedure.o - endif - - ifeq ($(SRCARCH),ppc64) - lib-y += ./$(ARCH_DIR)/vdso-trampoline.o - endif + lib-y += util-vdso.o endif ifeq ($(SRCARCH),ppc64) From 11b3825ca3d9bf5bd2593bb2ce9ae282d72734f9 Mon Sep 17 00:00:00 2001 From: Zhang Ning Date: Tue, 16 Apr 2019 15:45:05 +0800 Subject: [PATCH 2034/4375] x86/crtools: do not error when YMM is missing for Intel Apollo Lake SOC, its cpuinfo and fpu features: cpu: x86_family 6 x86_vendor_id GenuineIntel x86_model_id Intel(R) Celeron(R) CPU J3455 @ 1.50GHz cpu: fpu: xfeatures_mask 0x11 xsave_size 1088 xsave_size_max 1088 xsaves_size 704 cpu: fpu: x87 floating point registers xstate_offsets 0 / 0 xstate_sizes 160 / 160 this CPU doesn't have AVX registers, YMM feature. when CRIU runs on this CPU, it will report dump error: Dumping GP/FPU registers for 4888 Error (criu/arch/x86/crtools.c:362): x86: Corruption in XFEATURE_YMM area (expected 64 but 0 obtained) Error (criu/cr-dump.c:1278): Can't infect (pid: 4888) with parasite that's because x86/crtools.c will still valid YMM xsave frame, thus fail to dump. bypass unsupported feature, to make CRIU runs this kinds of CPUs. Cc: Chen Hu Signed-off-by: Zhang Ning Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index ee016da00..efc23e5fe 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -354,7 +354,7 @@ static bool valid_xsave_frame(CoreEntry *core) }; for (i = 0; i < ARRAY_SIZE(features); i++) { - if (!features[i].ptr && i > 0) + if (!features[i].ptr) continue; if (features[i].expected > features[i].obtained) { From ac495fbd3f761daa65abbe1c4a49baae0acb6c2c Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 06:11:23 +0000 Subject: [PATCH 2035/4375] autofs: fix coverity RESOURCE_LEAK criu-3.12/criu/autofs.c:114: leaked_storage: Variable "path" going out of scope leaks the storage it points to. criu-3.12/criu/autofs.c:254: leaked_storage: Variable "opts" going out of scope leaks the storage it points to. criu-3.12/criu/autofs.c:719: leaked_storage: Variable "path" going out of scope leaks the storage it points to. criu-3.12/criu/autofs.c:980: leaked_storage: Variable "img" going out of scope leaks the storage it points to. Signed-off-by: Adrian Reber --- criu/autofs.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/criu/autofs.c b/criu/autofs.c index 576edef68..a2dc60ffc 100644 --- a/criu/autofs.c +++ b/criu/autofs.c @@ -110,8 +110,10 @@ static int autofs_kernel_pipe_alive(int pgrp, int fd, int ino) return -1; if (stat(path, &buf) < 0) { - if (errno == ENOENT) + if (errno == ENOENT) { + xfree(path); return 0; + } pr_perror("Failed to stat %s", path); return -1; } @@ -208,6 +210,7 @@ static int parse_options(char *options, AutofsEntry *entry, long *pipe_ino) { char **opts; int nr_opts, i; + int parse_error = 0; entry->fd = AUTOFS_OPT_UNKNOWN; entry->timeout = AUTOFS_OPT_UNKNOWN; @@ -250,14 +253,19 @@ static int parse_options(char *options, AutofsEntry *entry, long *pipe_ino) else if (!strncmp(opt, "gid=", strlen("gid="))) err = xatoi(opt + strlen("gid="), &entry->gid); - if (err) - return -1; + if (err) { + parse_error = 1; + break; + } } for (i = 0; i < nr_opts; i++) xfree(opts[i]); xfree(opts); + if (parse_error) + return -1; + if (entry->fd == AUTOFS_OPT_UNKNOWN) { pr_err("Failed to find fd option\n"); return -1; @@ -716,6 +724,7 @@ static int autofs_create_dentries(const struct mount_info *mi, char *mnt_path) return -1; if (mkdir(path, 0555) < 0) { pr_perror("Failed to create autofs dentry %s", path); + free(path); return -1; } free(path); @@ -967,6 +976,7 @@ static int autofs_add_mount_info(struct pprep_head *ph) static int autofs_restore_entry(struct mount_info *mi, AutofsEntry **entry) { struct cr_img *img; + int ret; img = open_image(CR_FD_AUTOFS, O_RSTR, mi->s_dev); if (!img) @@ -976,10 +986,11 @@ static int autofs_restore_entry(struct mount_info *mi, AutofsEntry **entry) return -1; } - if (pb_read_one_eof(img, entry, PB_AUTOFS) < 0) - return -1; + ret = pb_read_one_eof(img, entry, PB_AUTOFS); close_image(img); + if (ret < 0) + return -1; return 0; } From 8502bc2010637c74310bec135605f53a24972ab4 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 06:55:26 +0000 Subject: [PATCH 2036/4375] cgroup: fix clang 'free released memory' criu-3.12/criu/cgroup.c:927:2: warning: Attempt to free released memory Signed-off-by: Adrian Reber --- criu/cgroup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/cgroup.c b/criu/cgroup.c index 22e722acf..332c79fb9 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -818,6 +818,7 @@ static int dump_controllers(CgroupEntry *cg) if (ce->n_dirs > 0) if (dump_cg_dirs(&cur->heads, cur->n_heads, &ce->dirs, 0) < 0) { xfree(cg->controllers); + cg->controllers = NULL; return -1; } cg->controllers[i++] = ce++; From c189a9bbf2e8b7a7c05cab747c728cf6e286997e Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 06:09:31 +0000 Subject: [PATCH 2037/4375] compel: fix clang 'value stored is never read' criu-3.12/compel/src/lib/infect.c:276:3: warning: Value stored to 'ret' is never read Signed-off-by: Adrian Reber --- compel/src/lib/infect.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 09c2c53f9..f0bcaf334 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -273,7 +273,6 @@ try_again: goto err; } - ret = 0; if (free_status) free_status(pid, ss, data); goto try_again; From defbd43351bf291c72dee48e62b43e3d7eed15a9 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 14 May 2019 18:11:26 +0000 Subject: [PATCH 2038/4375] cr-service: fix coverity STRING_OVERFLOW criu-3.12/criu/cr-service.c:1305: fixed_size_dest: You might overrun the 108-character fixed-size string "server_addr.sun_path" by copying "opts.addr" without checking the length. Signed-off-by: Adrian Reber --- criu/cr-service.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 1f1e5fa86..52b86bb05 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -1302,7 +1302,8 @@ int cr_service(bool daemon_mode) SET_CHAR_OPTS(addr, CR_DEFAULT_SERVICE_ADDRESS); } - strcpy(server_addr.sun_path, opts.addr); + strncpy(server_addr.sun_path, opts.addr, + sizeof(server_addr.sun_path) - 1); server_addr_len = strlen(server_addr.sun_path) + sizeof(server_addr.sun_family); From 7d152adf65881d9d6d273fe738be773d05163c2f Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 07:23:27 +0000 Subject: [PATCH 2039/4375] cr-service: fix clang 'dereference of a null pointer' criu-3.12/criu/cr-service.c:933:7: warning: Access to field 'keep_open' results in a dereference of a null pointer (loaded from variable 'msg') Signed-off-by: Adrian Reber --- criu/cr-service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 52b86bb05..cb76de4f4 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -1156,7 +1156,7 @@ int cr_service_work(int sk) CriuReq *msg = 0; more: - if (recv_criu_msg(sk, &msg) == -1) { + if (recv_criu_msg(sk, &msg) != 0) { pr_perror("Can't recv request"); goto err; } From 57d4a78aa392dc12b1569f7c85541f41515a094c Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 07:42:35 +0000 Subject: [PATCH 2040/4375] files: fix coverity RESOURCE_LEAK criu-3.12/criu/files.c:1250: leaked_storage: Variable "dir" going out of scope leaks the storage it points to. Signed-off-by: Adrian Reber --- criu/files.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/files.c b/criu/files.c index 38b12ee4f..ffdaa459f 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1247,6 +1247,8 @@ int close_old_fds(void) ret = sscanf(de->d_name, "%d", &fd); if (ret != 1) { pr_err("Can't parse %s\n", de->d_name); + closedir(dir); + close_pid_proc(); return -1; } From 920c4a6afcee6d660b002ba8370da3400f325eb9 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 14 May 2019 18:01:31 +0000 Subject: [PATCH 2041/4375] files-reg: fix coverity NULL_RETURNS criu-3.12/criu/files-reg.c:1574: dereference: Dereferencing "rmi", which is known to be "NULL". criu-3.12/criu/files-reg.c:1582: dereference: Dereferencing "tmi", which is known to be "NULL". Signed-off-by: Adrian Reber --- criu/files-reg.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/criu/files-reg.c b/criu/files-reg.c index 3072289ef..ff0ae7d69 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1553,6 +1553,9 @@ static int rfi_remap(struct reg_file_info *rfi, int *level) } mi = lookup_mnt_id(rfi->rfe->mnt_id); + if (mi == NULL) + return -1; + if (rfi->rfe->mnt_id == rfi->remap->rmnt_id) { /* Both links on the same mount point */ tmi = mi; @@ -1562,6 +1565,8 @@ static int rfi_remap(struct reg_file_info *rfi, int *level) } rmi = lookup_mnt_id(rfi->remap->rmnt_id); + if (rmi == NULL) + return -1; /* * Find the common bind-mount. We know that one mount point was From 288a4a953a53492586e86880ee1347d647411a92 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 08:06:55 +0000 Subject: [PATCH 2042/4375] image: fix clang 'dereference of a null pointer' criu-3.12/criu/include/image.h:129:9: warning: Dereference of null pointer Signed-off-by: Adrian Reber --- criu/include/image.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/include/image.h b/criu/include/image.h index 48ba3ec00..2baa39496 100644 --- a/criu/include/image.h +++ b/criu/include/image.h @@ -133,6 +133,8 @@ extern int open_image_lazy(struct cr_img *img); static inline int img_raw_fd(struct cr_img *img) { + if (!img) + return -1; if (lazy_image(img) && open_image_lazy(img)) return -1; From 688f02a1390b62d4b41f651b5d3ee26cecf0e721 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 14 May 2019 16:51:50 +0000 Subject: [PATCH 2043/4375] log: fix coverity OVERRUN This fixes a coverity buffer overflow warning: criu-3.12/criu/log.c:344: overrun-local: Overrunning array of 1024 bytes at byte offset 1031 by dereferencing pointer "early_log_buffer + early_log_buf_off + log_size". [Note: The source code implementation of the function has been overridden by a builtin model.] Signed-off-by: Adrian Reber --- criu/log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/log.c b/criu/log.c index 1e43f663d..8bdf83534 100644 --- a/criu/log.c +++ b/criu/log.c @@ -320,7 +320,7 @@ static void early_vprint(const char *format, unsigned int loglevel, va_list para unsigned int log_size = 0; struct early_log_hdr *hdr; - if (early_log_buf_off >= EARLY_LOG_BUF_LEN) + if ((early_log_buf_off + sizeof(hdr)) >= EARLY_LOG_BUF_LEN) return; /* Save loglevel */ From 27dd87e99a3324ff281d182ec69435603253a9bb Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 14 May 2019 16:55:20 +0000 Subject: [PATCH 2044/4375] libcriu: fix coverity RESOURCE_LEAK criu-3.12/lib/c/criu.c:255: leaked_storage: Variable "rpc" going out of scope leaks the storage it points to. Signed-off-by: Adrian Reber --- lib/c/criu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/c/criu.c b/lib/c/criu.c index 9e36a9795..c7a96b82e 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -252,6 +252,7 @@ int criu_local_init_opts(criu_opts **o) if (opts == NULL) { perror("Can't allocate memory for criu opts"); criu_local_free_opts(opts); + free(rpc); return -1; } From fe1c72a098ca7e44b9e3720609c3415d78f9faac Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 14:24:37 +0000 Subject: [PATCH 2045/4375] lib/c: fix coverity DEADCODE criu-3.12/lib/c/criu.c:869: dead_error_line: Execution cannot reach this statement: "free(ptr);". criu-3.12/lib/c/criu.c:906: dead_error_line: Execution cannot reach this statement: "free(ptr);". Signed-off-by: Adrian Reber --- lib/c/criu.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/c/criu.c b/lib/c/criu.c index c7a96b82e..17d5c3983 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -866,8 +866,6 @@ int criu_local_add_enable_fs(criu_opts *opts, const char *fs) err: if (str) free(str); - if (ptr) - free(ptr); return -ENOMEM; } @@ -903,8 +901,6 @@ int criu_local_add_skip_mnt(criu_opts *opts, const char *mnt) err: if (str) free(str); - if (ptr) - free(ptr); return -ENOMEM; } From beecbf096842fd0ce8c4d927ee71089ab2a8a1db Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 05:49:30 +0000 Subject: [PATCH 2046/4375] lsm: fix clang 'Use of memory after it is freed' criu-3.12/criu/lsm.c:257:3: warning: Use of memory after it is freed Signed-off-by: Adrian Reber --- criu/lsm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/lsm.c b/criu/lsm.c index 420585ba4..9d7e55c11 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -89,6 +89,7 @@ static int selinux_get_label(pid_t pid, char **output) if (!pos) { pr_err("Invalid selinux context %s\n", (char *)ctx); xfree(*output); + *output = NULL; goto err; } From 75edc02f66d5822584a0fffac2be0b3c038cf46f Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 09:39:55 +0000 Subject: [PATCH 2047/4375] mem: fix coverity RESOURCE_LEAK criu-3.12/criu/mem.c:597:3: warning: Value stored to 'ret' is never read criu-3.12/criu/mem.c:632: leaked_storage: Variable "img" going out of scope leaks the storage it points to. Signed-off-by: Adrian Reber --- criu/mem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/criu/mem.c b/criu/mem.c index df87ed5b0..f79e04cc4 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -594,7 +594,6 @@ int prepare_mm_pid(struct pstree_item *i) if (!vma) break; - ret = 0; ri->vmas.nr++; if (!img) vma->e = ri->mm->vmas[vn++]; @@ -603,6 +602,7 @@ int prepare_mm_pid(struct pstree_item *i) if (ret <= 0) { xfree(vma); close_image(img); + img = NULL; break; } } @@ -629,6 +629,8 @@ int prepare_mm_pid(struct pstree_item *i) break; } + if (img) + close_image(img); return ret; } From 08a283d29ea711230fcc83183538335bee9f6c64 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 11:57:05 +0000 Subject: [PATCH 2048/4375] pagemap: fix clang 'free released memory' criu-3.12/criu/pagemap.c:460:2: warning: Attempt to free released memory Signed-off-by: Adrian Reber --- criu/pagemap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/pagemap.c b/criu/pagemap.c index 4c4e88685..ee4ae1b19 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -458,6 +458,7 @@ static void free_pagemaps(struct page_read *pr) pagemap_entry__free_unpacked(pr->pmes[i], NULL); xfree(pr->pmes); + pr->pmes = NULL; } static void advance_piov(struct page_read_iov *piov, ssize_t len) From 82d6ef6d8ad1c3fdf4a8e09e6412dda4c95f1b68 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 11:59:05 +0000 Subject: [PATCH 2049/4375] pagemap: fix coverity FORWARD_NULL criu-3.12/criu/pagemap.c:694: var_deref_model: Passing "pr" to "free_pagemaps", which dereferences null "pr->pmes" Signed-off-by: Adrian Reber --- criu/pagemap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/criu/pagemap.c b/criu/pagemap.c index ee4ae1b19..6bcd0d70e 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -678,11 +678,13 @@ static int init_pagemaps(struct page_read *pr) pr->nr_pmes++; if (pr->nr_pmes >= nr_pmes) { + PagemapEntry **new; nr_pmes += nr_realloc; - pr->pmes = xrealloc(pr->pmes, + new = xrealloc(pr->pmes, nr_pmes * sizeof(*pr->pmes)); - if (!pr->pmes) + if (!new) goto free_pagemaps; + pr->pmes = new; } } From bf2d03b7856afc003cf1b269bf84dcbe4349e387 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 11:48:14 +0000 Subject: [PATCH 2050/4375] page-xfer: fix clang 'value is never read' criu-3.12/criu/page-xfer.c:988:3: warning: Value stored to 'ret' is never read Signed-off-by: Adrian Reber --- criu/page-xfer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index e3c9c7b25..8868ed226 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -985,7 +985,6 @@ int cr_page_server(bool daemon_mode, bool lazy_dump, int cfd) return -1; if (opts.ps_socket != -1) { - ret = 0; ask = opts.ps_socket; pr_info("Re-using ps socket %d\n", ask); goto no_server; From 5b358ebdc3b792c2d6f5c44b94d86369e38fc16c Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 12:02:40 +0000 Subject: [PATCH 2051/4375] pie/restorer: fix clang 'value is never read' criu-3.12/criu/pie/restorer.c:1514:2: warning: Value stored to 'ret' is never read Signed-off-by: Adrian Reber --- criu/pie/restorer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 4f42605a0..f2db115ff 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1511,8 +1511,6 @@ long __export_restore_task(struct task_restore_args *args) } } - ret = 0; - /* * Tune up the task fields. */ From 0df6ddba6974af926a4db171bf8876e762a0d355 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 12:17:35 +0000 Subject: [PATCH 2052/4375] proc_parse: fix coverity RESOURCE_LEAK criu-3.12/criu/proc_parse.c:2280: leaked_storage: Variable "dir" going out of scope leaks the storage it points to. Signed-off-by: Adrian Reber Signed-off-by: Andrei Vagin --- criu/proc_parse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 1a5722eaf..3d852d755 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -2277,6 +2277,7 @@ int parse_threads(int pid, struct pid **_t, int *_n) tmp = xrealloc(t, nr * sizeof(struct pid)); if (!tmp) { xfree(t); + closedir(dir); return -1; } t = tmp; From b87b02729accb25f0f9d14c0f1413358c268866d Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 14 May 2019 16:56:39 +0000 Subject: [PATCH 2053/4375] sk-inet: fix coverity RESOURCE_LEAK criu-3.12/criu/sk-inet.c:822: leaked_handle: Handle variable "sk" going out of scope leaks the handle. Signed-off-by: Adrian Reber --- criu/sk-inet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index ebae53113..fed3181f0 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -823,7 +823,7 @@ static int open_inet_sk(struct file_desc *d, int *new_fd) } if (reset_setsockcreatecon()) - return -1; + goto err; if (ie->v6only) { if (restore_opt(sk, SOL_IPV6, IPV6_V6ONLY, &yes) == -1) From 6f44f78310b7dc070301be4c5871f98dd25f17b2 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 12:28:45 +0000 Subject: [PATCH 2054/4375] sk-inet: fix clang 'potential memory leak' criu-3.12/criu/sk-inet.c:581:2: warning: Potential leak of memory pointed to by 'ie.ifname' Signed-off-by: Adrian Reber --- criu/sk-inet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index fed3181f0..90ab492ed 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -579,6 +579,7 @@ err: release_skopts(&skopts); xfree(ie.src_addr); xfree(ie.dst_addr); + xfree(ie.ifname); return err; } From 9406f1be4e97e3da3b3d1b87d738cd7490a3b7d1 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 12:33:40 +0000 Subject: [PATCH 2055/4375] sk-queue: fix clang 'potential memory leak' criu-3.12/criu/sk-queue.c:272:6: warning: Potential leak of memory pointed to by 'pe.scm' Signed-off-by: Adrian Reber --- criu/sk-queue.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/sk-queue.c b/criu/sk-queue.c index fdf610170..776eb5aaf 100644 --- a/criu/sk-queue.c +++ b/criu/sk-queue.c @@ -273,6 +273,8 @@ err_set_sock: pr_perror("setsockopt failed on restore"); ret = -1; } + if (pe.scm) + release_cmsg(&pe); err_brk: xfree(data); return ret; From 2f74e55a18164d9ab309dd4979853effb4776a72 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 12:38:32 +0000 Subject: [PATCH 2056/4375] sk-unix: fix clang 'value is never read' criu-3.12/criu/sk-unix.c:1545:5: warning: Value stored to 'ret' is never read Signed-off-by: Adrian Reber --- criu/sk-unix.c | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 26123515c..35a6befa7 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1542,7 +1542,6 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) pos = strrchr(path, '/')) { *pos = '\0'; if (rmdir(path)) { - ret = - errno; pr_perror("ghost: Can't remove directory %s on id %#x ino %d", path, ui->ue->id, ui->ue->ino); return -1; From 88d8979b5dd7e8dd85b3b1f8cab4bf6e8960efac Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 12:40:50 +0000 Subject: [PATCH 2057/4375] sk-unix: fix coverity RESOURCE_LEAK criu-3.12/criu/sk-unix.c:1893: leaked_handle: Handle variable "sk" going out of scope leaks the handle. Signed-off-by: Adrian Reber --- criu/sk-unix.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 35a6befa7..c339ccf56 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1888,13 +1888,16 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) } } - if (bind_unix_sk(sk, ui)) + if (bind_unix_sk(sk, ui)) { + close(sk); return -1; + } if (ui->ue->state == TCP_LISTEN) { pr_info("\tPutting %d into listen state\n", ui->ue->ino); if (listen(sk, ui->ue->backlog) < 0) { pr_perror("Can't make usk listen"); + close(sk); return -1; } ui->listen = 1; From 5a29e253f6c6eba8a45f3b31a2a6f57ff0f4fc71 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 14 May 2019 18:22:29 +0000 Subject: [PATCH 2058/4375] util: fix coverity FORWARD_NULL criu-3.12/criu/util.c:505: var_deref_model: Passing null pointer "dir" to "dirfd", which dereferences it. (The dereference is assumed on the basis of the 'nonnull' parameter attribute.) Signed-off-by: Adrian Reber --- criu/util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/criu/util.c b/criu/util.c index 97084939e..04b5c3e71 100644 --- a/criu/util.c +++ b/criu/util.c @@ -500,8 +500,10 @@ static int close_fds(int minfd) int fd, ret, dfd; dir = opendir("/proc/self/fd"); - if (dir == NULL) + if (dir == NULL) { pr_perror("Can't open /proc/self/fd"); + return -1; + } dfd = dirfd(dir); while ((de = readdir(dir))) { From 7765a6c3fcfb5f707c4518ad9fdc59eeb62a99aa Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 07:59:23 +0000 Subject: [PATCH 2059/4375] image: fix coverity RESOURCE_LEAK criu-3.12/criu/image.c:103: leaked_storage: Variable "img" going out of scope leaks the storage it points to. Signed-off-by: Adrian Reber --- criu/image.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/criu/image.c b/criu/image.c index e1740ce94..5239ab474 100644 --- a/criu/image.c +++ b/criu/image.c @@ -92,6 +92,7 @@ out_close: int write_img_inventory(InventoryEntry *he) { struct cr_img *img; + int ret; pr_info("Writing image inventory (version %u)\n", CRTOOLS_IMAGES_V1); @@ -99,11 +100,12 @@ int write_img_inventory(InventoryEntry *he) if (!img) return -1; - if (pb_write_one(img, he, PB_INVENTORY) < 0) - return -1; + ret = pb_write_one(img, he, PB_INVENTORY); xfree(he->root_ids); close_image(img); + if (ret < 0) + return -1; return 0; } From da652c8b375309f3f609b0225e818443296861e7 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 12:36:49 +0000 Subject: [PATCH 2060/4375] sk-unix: fix coverity NULL_RETURNS criu-3.12/criu/sk-unix.c:1225: dereference: Dereferencing "ns", which is known to be "NULL". Signed-off-by: Adrian Reber --- criu/sk-unix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index c339ccf56..f0620e676 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1208,14 +1208,14 @@ static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd, if (prev_root_fd && (root_ns_mask & CLONE_NEWNS)) { if (ui->ue->mnt_id >= 0) { ns = lookup_nsid_by_mnt_id(ui->ue->mnt_id); - if (ns == NULL) - goto err; } else { if (root == NULL) root = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc); ns = root; } + if (ns == NULL) + goto err; *prev_root_fd = open("/", O_RDONLY); if (*prev_root_fd < 0) { pr_perror("Can't open current root"); From 8accfe6cc9d65cdf2203fc58ac3075c16b729e23 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sat, 18 May 2019 16:26:53 +0100 Subject: [PATCH 2061/4375] python: Drop six dependency From the python-six module is used only six.string_types in the is_string() function. An alternative solution is to use basestring with additional if statement for Python 3 compatibility. This change avoids the dependency on the six module. However, this module is required by junit_xml and it is not listed as a dependency in the CentOS 7 package python2-junit_xml. Signed-off-by: Radostin Stoyanov --- lib/py/images/pb2dict.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index 18d4c68eb..4e2c171d5 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -4,7 +4,7 @@ from ipaddress import IPv4Address, ip_address from ipaddress import IPv6Address import socket import collections -import os, six +import os # pb2dict and dict2pb are methods to convert pb to/from dict. # Inspired by: @@ -216,7 +216,10 @@ def get_bytes_dec(field): return decode_base64 def is_string(value): - return isinstance(value, six.string_types) + # Python 3 compatibility + if not hasattr(__builtins__, "basestring"): + basestring = (str, bytes) + return isinstance(value, basestring) def _pb2dict_cast(field, value, pretty = False, is_hex = False): if not is_hex: From bf62dbbe085efadfa08b0562603a7a8d0fce3a87 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 22 May 2019 15:50:30 +0100 Subject: [PATCH 2062/4375] make: Use asciidoctor by default The final release of asciidoc was on Sep 29, 2017 and the development is continued under asciidoctor. With commit 0493724 (Documentation: Allow to use asciidoctor for formatting man pages) was added support for this tool by introducing USE_ASCIIDOCTOR. However, using asciidoctor by default might be a better option. With this change CRIU will use asciidoctor if installed. Otherwise, it will fallback to asciidoc. Signed-off-by: Radostin Stoyanov --- scripts/build/Dockerfile.alpine | 2 +- scripts/build/Dockerfile.centos | 2 +- scripts/build/Dockerfile.fedora.tmpl | 2 +- scripts/nmk/scripts/tools.mk | 2 ++ scripts/travis/travis-tests | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index aab6184d7..a91e01637 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -36,7 +36,7 @@ RUN apk add \ bash \ go \ e2fsprogs \ - asciidoc xmlto + asciidoctor # The rpc test cases are running as user #1000, let's add the user RUN adduser -u 1000 -D test diff --git a/scripts/build/Dockerfile.centos b/scripts/build/Dockerfile.centos index d8e70ac47..2ed3a2db9 100644 --- a/scripts/build/Dockerfile.centos +++ b/scripts/build/Dockerfile.centos @@ -32,7 +32,7 @@ RUN yum install -y \ which \ e2fsprogs \ python2-pip \ - asciidoc xmlto + rubygem-asciidoctor COPY . /criu WORKDIR /criu diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index 616b9ec42..22ebaed9c 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -33,7 +33,7 @@ RUN dnf install -y \ tar \ which \ e2fsprogs \ - asciidoc xmlto \ + rubygem-asciidoctor \ kmod # Replace coreutils-single with "traditional" coreutils diff --git a/scripts/nmk/scripts/tools.mk b/scripts/nmk/scripts/tools.mk index 8620ded7c..ce3d85dea 100644 --- a/scripts/nmk/scripts/tools.mk +++ b/scripts/nmk/scripts/tools.mk @@ -35,6 +35,8 @@ CTAGS := ctags export RM HOSTLD LD HOSTCC CC CPP AS AR STRIP OBJCOPY OBJDUMP export NM SH MAKE MKDIR AWK PERL PYTHON SH CSCOPE +export USE_ASCIIDOCTOR ?= $(shell which asciidoctor 2>/dev/null) + # # Footer. ____nmk_defined__tools = y diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 01a2659f6..47ff199cf 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -4,7 +4,7 @@ set -x -e TRAVIS_PKGS="protobuf-c-compiler libprotobuf-c0-dev libaio-dev libprotobuf-dev protobuf-compiler libcap-dev libnl-3-dev gcc-multilib gdb bash python-protobuf - libnet-dev util-linux asciidoc xmlto libnl-route-3-dev" + libnet-dev util-linux asciidoctor libnl-route-3-dev" travis_prep () { [ -n "$SKIP_TRAVIS_PREP" ] && return From 5156f2dc0d126904748bd86fdf8f342a24959aaa Mon Sep 17 00:00:00 2001 From: Pavel Emelianov Date: Thu, 23 May 2019 08:58:04 +0000 Subject: [PATCH 2063/4375] mem: Update stats for overflow page pipes Since commit b5dff62e we skipped updating dump stats for pages that overflowed the page-pipe and thus got flushed in "chunk" mode. Signed-off-by: Pavel Emelyanov Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/mem.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/criu/mem.c b/criu/mem.c index f79e04cc4..b1d13188b 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -170,13 +170,14 @@ static int generate_iovs(struct pstree_item *item, struct vma_area *vma, struct u64 *at = &map[PAGE_PFN(*off)]; unsigned long pfn, nr_to_scan; unsigned long pages[3] = {}; + int ret = 0; nr_to_scan = (vma_area_len(vma) - *off) / PAGE_SIZE; for (pfn = 0; pfn < nr_to_scan; pfn++) { unsigned long vaddr; unsigned int ppb_flags = 0; - int ret; + int st; if (!should_dump_page(vma->e, at[pfn])) continue; @@ -195,19 +196,22 @@ static int generate_iovs(struct pstree_item *item, struct vma_area *vma, struct if (has_parent && page_in_parent(at[pfn] & PME_SOFT_DIRTY)) { ret = page_pipe_add_hole(pp, vaddr, PP_HOLE_PARENT); - pages[0]++; + st = 0; } else { ret = page_pipe_add_page(pp, vaddr, ppb_flags); if (ppb_flags & PPB_LAZY && opts.lazy_pages) - pages[1]++; + st = 1; else - pages[2]++; + st = 2; } if (ret) { - *off += pfn * PAGE_SIZE; - return ret; + /* Do not do pfn++, just bail out */ + pr_debug("Pagemap full\n"); + break; } + + pages[st]++; } *off += pfn * PAGE_SIZE; @@ -219,7 +223,7 @@ static int generate_iovs(struct pstree_item *item, struct vma_area *vma, struct pr_info("Pagemap generated: %lu pages (%lu lazy) %lu holes\n", pages[2] + pages[1], pages[1], pages[0]); - return 0; + return ret; } static struct parasite_dump_pages_args *prep_dump_pages_args(struct parasite_ctl *ctl, From 72ce634f43f6d241faf064eaccae2be0cb51e7de Mon Sep 17 00:00:00 2001 From: Pavel Emelianov Date: Thu, 23 May 2019 08:58:35 +0000 Subject: [PATCH 2064/4375] shmem: Save pages stats too Shmem pages are written in the same set of images as regular pages are, but stats for those are not collected. Fix this, but keep the counts separate to have more info. Signed-off-by: Pavel Emelyanov Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/stats.h | 4 ++++ criu/shmem.c | 17 +++++++++++++++-- criu/stats.c | 7 +++++++ images/stats.proto | 4 ++++ 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/criu/include/stats.h b/criu/include/stats.h index 07690b8ea..bab9a0507 100644 --- a/criu/include/stats.h +++ b/criu/include/stats.h @@ -29,6 +29,10 @@ enum { CNT_PAGE_PIPES, CNT_PAGE_PIPE_BUFS, + CNT_SHPAGES_SCANNED, + CNT_SHPAGES_SKIPPED_PARENT, + CNT_SHPAGES_WRITTEN, + DUMP_CNT_NR_STATS, }; diff --git a/criu/shmem.c b/criu/shmem.c index 358d848db..bc9f23bd7 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -11,6 +11,7 @@ #include "image.h" #include "cr_options.h" #include "kerndat.h" +#include "stats.h" #include "page-pipe.h" #include "page-xfer.h" #include "rst-malloc.h" @@ -676,6 +677,7 @@ static int do_dump_one_shmem(int fd, void *addr, struct shmem_info *si) struct page_xfer xfer; int err, ret = -1; unsigned long pfn, nrpages, next_data_pnf = 0, next_hole_pfn = 0; + unsigned long pages[2] = {}; nrpages = (si->size + PAGE_SIZE - 1) / PAGE_SIZE; @@ -693,6 +695,7 @@ static int do_dump_one_shmem(int fd, void *addr, struct shmem_info *si) unsigned int pgstate = PST_DIRTY; bool use_mc = true; unsigned long pgaddr; + int st = -1; if (pfn >= next_hole_pfn && next_data_segment(fd, pfn, &next_data_pnf, &next_hole_pfn)) @@ -714,10 +717,13 @@ static int do_dump_one_shmem(int fd, void *addr, struct shmem_info *si) again: if (pgstate == PST_ZERO) ret = 0; - else if (xfer.parent && page_in_parent(pgstate == PST_DIRTY)) + else if (xfer.parent && page_in_parent(pgstate == PST_DIRTY)) { ret = page_pipe_add_hole(pp, pgaddr, PP_HOLE_PARENT); - else + st = 0; + } else { ret = page_pipe_add_page(pp, pgaddr, 0); + st = 1; + } if (ret == -EAGAIN) { ret = dump_pages(pp, &xfer); @@ -727,8 +733,15 @@ again: goto again; } else if (ret) goto err_xfer; + + if (st >= 0) + pages[st]++; } + cnt_add(CNT_SHPAGES_SCANNED, nrpages); + cnt_add(CNT_SHPAGES_SKIPPED_PARENT, pages[0]); + cnt_add(CNT_SHPAGES_WRITTEN, pages[1]); + ret = dump_pages(pp, &xfer); err_xfer: diff --git a/criu/stats.c b/criu/stats.c index 64679b134..a64383542 100644 --- a/criu/stats.c +++ b/criu/stats.c @@ -165,6 +165,13 @@ void write_stats(int what) ds_entry.page_pipe_bufs = dstats->counts[CNT_PAGE_PIPE_BUFS]; ds_entry.has_page_pipe_bufs = true; + ds_entry.shpages_scanned = dstats->counts[CNT_SHPAGES_SCANNED]; + ds_entry.has_shpages_scanned = true; + ds_entry.shpages_skipped_parent = dstats->counts[CNT_SHPAGES_SKIPPED_PARENT]; + ds_entry.has_shpages_skipped_parent = true; + ds_entry.shpages_written = dstats->counts[CNT_SHPAGES_WRITTEN]; + ds_entry.has_shpages_written = true; + name = "dump"; } else if (what == RESTORE_STATS) { stats.restore = &rs_entry; diff --git a/images/stats.proto b/images/stats.proto index d76503441..68d2f1bbb 100644 --- a/images/stats.proto +++ b/images/stats.proto @@ -16,6 +16,10 @@ message dump_stats_entry { required uint64 pages_lazy = 9; optional uint64 page_pipes = 10; optional uint64 page_pipe_bufs = 11; + + optional uint64 shpages_scanned = 12; + optional uint64 shpages_skipped_parent = 13; + optional uint64 shpages_written = 14; } message restore_stats_entry { From b336fa2e3237f9f93a09aea546fb1164b7c151a1 Mon Sep 17 00:00:00 2001 From: Pavel Emelianov Date: Thu, 23 May 2019 08:59:05 +0000 Subject: [PATCH 2065/4375] zdtm: Check pages stats after dump After dump command -- verify that the amount of bytes counted in stats-dump matches the real sizes of pages-*.img files. Signed-off-by: Pavel Emelyanov Acked-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- test/zdtm.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index fb859d1c7..abe92f9d0 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1098,13 +1098,32 @@ class criu: else: raise test_fail_exc("CRIU %s" % action) + def __stats_file(self, action): + return os.path.join(self.__ddir(), "stats-%s" % action) + def show_stats(self, action): if not self.__show_stats: return - subprocess.Popen([self.__crit_bin, "show", - os.path.join(self.__dump_path, - str(self.__iter), "stats-%s" % action)]).wait() + subprocess.Popen([self.__crit_bin, "show", self.__stats_file(action)]).wait() + + def check_pages_counts(self): + stats_written = -1 + with open(self.__stats_file("dump"), 'rb') as stfile: + stats = crpc.images.load(stfile) + stent = stats['entries'][0]['dump'] + stats_written = int(stent['shpages_written']) + int(stent['pages_written']) + + real_written = 0 + for f in os.listdir(self.__ddir()): + if f.startswith('pages-'): + real_written += os.path.getsize(os.path.join(self.__ddir(), f)) + + r_pages = real_written / 4096 + r_off = real_written % 4096 + if (stats_written != r_pages) or (r_off != 0): + print("ERROR: bad page counts, stats = %d real = %d(%d)" % (stats_written, r_pages, r_off)) + raise test_fail_exc("page counts mismatch") def dump(self, action, opts = []): self.__iter += 1 @@ -1152,6 +1171,7 @@ class criu: self.__criu_act("dedup", opts = []) self.show_stats("dump") + self.check_pages_counts() if self.__leave_stopped: pstree_check_stopped(self.__test.getpid()) From 77d88920fb8f59cd688bd659507ea2199f69d3c1 Mon Sep 17 00:00:00 2001 From: Pavel Emelianov Date: Thu, 23 May 2019 08:59:26 +0000 Subject: [PATCH 2066/4375] stats: Make dstats shmem Dumping shmem segments causing stats "pages written" counter to mismatch the real pages* sizes. This is due to ipcns' dumping happens in another process and the relevant shmem dumping counters remain in its address space. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/stats.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/criu/stats.c b/criu/stats.c index a64383542..7410b5ced 100644 --- a/criu/stats.c +++ b/criu/stats.c @@ -201,7 +201,15 @@ void write_stats(int what) int init_stats(int what) { if (what == DUMP_STATS) { - dstats = xzalloc(sizeof(*dstats)); + /* + * Dumping happens via one process most of the time, + * so we are typically OK with the plain malloc, but + * when dumping namespaces we fork() a separate process + * for it and when it goes and dumps shmem segments + * it will alter the CNT_SHPAGES_ counters, so we need + * to have them in shmem. + */ + dstats = shmalloc(sizeof(*dstats)); return dstats ? 0 : -1; } From 7338a0e74ceca1fb111a27fd327b3e835a2e726f Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 21 May 2019 00:13:27 -0700 Subject: [PATCH 2067/4375] util: use F_DUPFD when we don't want to overwrite an existing descriptor Right now we use fcntl(F_GETFD) to check whether a target descriptor is used and then we call dup2(). Actually, we can do this for one system call. Cc: Cyrill Gorcunov Signed-off-by: Andrei Vagin Reviewed-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/include/servicefd.h | 11 ----------- criu/servicefd.c | 37 +++++++++++++++++++++++-------------- criu/util.c | 18 +++++++++--------- 3 files changed, 32 insertions(+), 34 deletions(-) diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h index 7be472cf4..986c46af5 100644 --- a/criu/include/servicefd.h +++ b/criu/include/servicefd.h @@ -35,17 +35,6 @@ struct pstree_item; extern bool sfds_protected; -#define sfd_verify_target(_type, _old_fd, _new_fd) \ - ({ \ - int __ret = 0; \ - if (fcntl(_new_fd, F_GETFD) != -1 && errno != EBADF) { \ - pr_err("%s busy target %d -> %d\n", \ - sfd_type_name(_type), _old_fd, _new_fd); \ - __ret = -1; \ - } \ - __ret; \ - }) - extern const char *sfd_type_name(enum sfd_type type); extern int init_service_fd(void); extern int get_service_fd(enum sfd_type type); diff --git a/criu/servicefd.c b/criu/servicefd.c index 82147921c..dc423895b 100644 --- a/criu/servicefd.c +++ b/criu/servicefd.c @@ -153,6 +153,7 @@ static void sfds_protection_bug(enum sfd_type type) int install_service_fd(enum sfd_type type, int fd) { int sfd = __get_service_fd(type, service_fd_id); + int tmp; BUG_ON((int)type <= SERVICE_FD_MIN || (int)type >= SERVICE_FD_MAX); if (sfds_protected && !test_bit(type, sfd_map)) @@ -166,16 +167,19 @@ int install_service_fd(enum sfd_type type, int fd) return fd; } - if (!test_bit(type, sfd_map)) { - if (sfd_verify_target(type, fd, sfd)) - return -1; - } - - if (dup3(fd, sfd, O_CLOEXEC) != sfd) { + if (!test_bit(type, sfd_map)) + tmp = fcntl(fd, F_DUPFD, sfd); + else + tmp = dup3(fd, sfd, O_CLOEXEC); + if (tmp < 0) { pr_perror("%s dup %d -> %d failed", sfd_type_name(type), fd, sfd); close(fd); return -1; + } else if (tmp != sfd) { + pr_err("%s busy target %d -> %d\n", sfd_type_name(type), fd, sfd); + close(fd); + return -1; } set_bit(type, sfd_map); @@ -201,25 +205,30 @@ int close_service_fd(enum sfd_type type) return 0; } -static void move_service_fd(struct pstree_item *me, int type, int new_id, int new_base) +static int move_service_fd(struct pstree_item *me, int type, int new_id, int new_base) { int old = get_service_fd(type); int new = new_base - type - SERVICE_FD_MAX * new_id; int ret; if (old < 0) - return; + return 0; if (!test_bit(type, sfd_map)) - sfd_verify_target(type, old, new); - - ret = dup2(old, new); + ret = fcntl(old, F_DUPFD, new); + else + ret = dup2(old, new); if (ret == -1) { - if (errno != EBADF) - pr_perror("%s unable to clone %d->%d", - sfd_type_name(type), old, new); + pr_perror("%s unable to clone %d->%d", + sfd_type_name(type), old, new); + return -1; + } else if (ret != new) { + pr_err("%s busy target %d -> %d\n", sfd_type_name(type), old, new); + return -1; } else if (!(rsti(me)->clone_flags & CLONE_FILES)) close(old); + + return 0; } static int choose_service_fd_base(struct pstree_item *me) diff --git a/criu/util.c b/criu/util.c index 04b5c3e71..0617c97b3 100644 --- a/criu/util.c +++ b/criu/util.c @@ -230,19 +230,19 @@ int reopen_fd_as_safe(char *file, int line, int new_fd, int old_fd, bool allow_r int tmp; if (old_fd != new_fd) { - if (!allow_reuse_fd) { - if (fcntl(new_fd, F_GETFD) != -1 || errno != EBADF) { - pr_err("fd %d already in use (called at %s:%d)\n", - new_fd, file, line); - return -1; - } - } - - tmp = dup2(old_fd, new_fd); + if (!allow_reuse_fd) + tmp = fcntl(old_fd, F_DUPFD, new_fd); + else + tmp = dup2(old_fd, new_fd); if (tmp < 0) { pr_perror("Dup %d -> %d failed (called at %s:%d)", old_fd, new_fd, file, line); return tmp; + } else if (tmp != new_fd) { + close(tmp); + pr_err("fd %d already in use (called at %s:%d)\n", + new_fd, file, line); + return -1; } /* Just to have error message if failed */ From 31c3f3bc1b40386e626b9d43f2bf7e584a8edf5e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 26 May 2019 20:53:57 -0700 Subject: [PATCH 2068/4375] test/s390: add a new patch to xtables libraries Signed-off-by: Andrei Vagin --- test/zdtm/static/socket-tcp-reseted.desc | 6 +++--- test/zdtm/static/socket-tcp-syn-sent.desc | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/zdtm/static/socket-tcp-reseted.desc b/test/zdtm/static/socket-tcp-reseted.desc index c0e83aad7..94425b44e 100644 --- a/test/zdtm/static/socket-tcp-reseted.desc +++ b/test/zdtm/static/socket-tcp-reseted.desc @@ -1,8 +1,8 @@ { 'deps': [ '/bin/sh', '/sbin/iptables', - '/usr/lib64/xtables/libxt_tcp.so|/lib/xtables/libxt_tcp.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_tcp.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so|/usr/lib/xtables/libxt_tcp.so', - '/usr/lib64/xtables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so|/usr/lib/xtables/libxt_standard.so', - '/usr/lib64/xtables/libipt_REJECT.so|/lib/xtables/libipt_REJECT.so|/usr/lib/powerpc64le-linux-gnu/xtables/libipt_REJECT.so|/usr/lib/x86_64-linux-gnu/xtables/libipt_REJECT.so|/usr/lib/xtables/libipt_REJECT.so', + '/usr/lib64/xtables/libxt_tcp.so|/lib/xtables/libxt_tcp.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_tcp.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so|/usr/lib/xtables/libxt_tcp.so|/usr/lib/s390x-linux-gnu/xtables/libxt_tcp.so', + '/usr/lib64/xtables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so|/usr/lib/xtables/libxt_standard.so|/usr/lib/s390x-linux-gnu/xtables/libxt_standard.so', + '/usr/lib64/xtables/libipt_REJECT.so|/lib/xtables/libipt_REJECT.so|/usr/lib/powerpc64le-linux-gnu/xtables/libipt_REJECT.so|/usr/lib/x86_64-linux-gnu/xtables/libipt_REJECT.so|/usr/lib/xtables/libipt_REJECT.so|/usr/lib/s390x-linux-gnu/xtables/libipt_REJECT.so', ], 'opts': '--tcp-established', 'flags': 'suid nouser samens', diff --git a/test/zdtm/static/socket-tcp-syn-sent.desc b/test/zdtm/static/socket-tcp-syn-sent.desc index c5d1faa0e..b9f3d5e6d 100644 --- a/test/zdtm/static/socket-tcp-syn-sent.desc +++ b/test/zdtm/static/socket-tcp-syn-sent.desc @@ -1,7 +1,7 @@ { 'deps': [ '/bin/sh', '/sbin/iptables', - '/usr/lib64/xtables/libxt_tcp.so|/lib/xtables/libxt_tcp.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_tcp.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so|/usr/lib/xtables/libxt_tcp.so', - '/usr/lib64/xtables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so|/usr/lib/xtables/libxt_standard.so', + '/usr/lib64/xtables/libxt_tcp.so|/lib/xtables/libxt_tcp.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_tcp.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so|/usr/lib/xtables/libxt_tcp.so|/usr/lib/s390x-linux-gnu/xtables/libxt_tcp.so', + '/usr/lib64/xtables/libxt_standard.so|/lib/xtables/libxt_standard.so|/usr/lib/powerpc64le-linux-gnu/xtables/libxt_standard.so|/usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so|/usr/lib/xtables/libxt_standard.so|/usr/lib/s390x-linux-gnu/xtables/libxt_standard.so', ], 'opts': '--tcp-established', 'flags': 'suid nouser samens', From c399235244cb2a2b7b2c11cf44f785a3be7ed822 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 26 May 2019 19:34:15 +0100 Subject: [PATCH 2069/4375] aarch64: Remove stack pointer from clobber list Since gcc version 9.1 was added the restriction that the clobber list of an inline assembly should not contain the stack pointer register. https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=9d1cdb749a1 In commit 901f5d4 have been fixed most of the build failures related to this gcc restriction. In this patch is resolved a build error that occurs only on aarch64. Signed-off-by: Radostin Stoyanov --- criu/arch/aarch64/include/asm/restore.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/arch/aarch64/include/asm/restore.h b/criu/arch/aarch64/include/asm/restore.h index 2345a579a..3d794ffb5 100644 --- a/criu/arch/aarch64/include/asm/restore.h +++ b/criu/arch/aarch64/include/asm/restore.h @@ -15,7 +15,7 @@ : "r"(new_sp), \ "r"(restore_task_exec_start), \ "r"(task_args) \ - : "sp", "x0", "memory") + : "x0", "memory") static inline void core_get_tls(CoreEntry *pcore, tls_t *ptls) { From 33bc00a1589c35ce03a749811ab2fe6f9cf86766 Mon Sep 17 00:00:00 2001 From: Pavel Emelianov Date: Tue, 28 May 2019 08:47:51 +0000 Subject: [PATCH 2070/4375] zdtm: Check stats file presence before reading In some cases the stats-dump file can be missing, so do not crash the whole zdtm.py in this case. https://ci.openvz.org/job/CRIU/job/criu-live-migration/job/criu-dev/2362/console Signed-off-by: Pavel Emelyanov --- test/zdtm.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index abe92f9d0..a01947557 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1108,6 +1108,9 @@ class criu: subprocess.Popen([self.__crit_bin, "show", self.__stats_file(action)]).wait() def check_pages_counts(self): + if not os.access(self.__stats_file("dump"), os.R_OK): + return + stats_written = -1 with open(self.__stats_file("dump"), 'rb') as stfile: stats = crpc.images.load(stfile) From 831ae18dacd249bd683785ab6c94fb955c3e16ad Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 28 May 2019 08:24:58 +0100 Subject: [PATCH 2071/4375] pb2dict: Fix is_string() check for Python 2 In the __main__ module, __builtins__ is the built-in module builtins. In any other module, __builtins__ is an alias for the dictionary of the builtins module itself. [1] Thus, hasattr(__builtins__, "basestring") would only work in __main__ module. Since pb2dict is part of pycriu and is intended to be called by modules other than __main__, we can assume that __builtins__ would always be a dictionary (not a module). In Python 2, basestring is a superclass for str and unicode. [2] However, the assignment statement creates a variable basestring in the local scope of the function is_string() which, in Python 2, causes a failure with UnboundLocalError. In order to mitigate this issue the local variable name has been changed to string_types. Fixes #708 [1] https://docs.python.org/2/reference/executionmodel.html#builtins-and-restricted-execution [2] https://docs.python.org/2/library/functions.html#basestring Signed-off-by: Radostin Stoyanov --- lib/py/images/pb2dict.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index 4e2c171d5..af14db24d 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -217,9 +217,11 @@ def get_bytes_dec(field): def is_string(value): # Python 3 compatibility - if not hasattr(__builtins__, "basestring"): - basestring = (str, bytes) - return isinstance(value, basestring) + if "basestring" in __builtins__: + string_types = basestring + else: + string_types = (str, bytes) + return isinstance(value, string_types) def _pb2dict_cast(field, value, pretty = False, is_hex = False): if not is_hex: From cd58de7a2b8abec9efee21bf30f6e0ab53131a52 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 29 May 2019 11:58:10 +0100 Subject: [PATCH 2072/4375] pb2dict: Resolve Python 2/3 compatibility issues In Python 3, bytes has only a decode() method, and string has only an encode() method. [1] The modules quopri and base64 from the Python Standard Library perform quoted-printable transport encoding and decoding with both Python 2 [2] and Python 3 [3]. [1] https://docs.python.org/3/howto/pyporting.html#text-versus-binary-data [2] https://docs.python.org/2/library/quopri.html [3] https://docs.python.org/3/library/quopri.html Signed-off-by: Radostin Stoyanov --- lib/py/images/pb2dict.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index af14db24d..c4ce736e8 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -5,6 +5,12 @@ from ipaddress import IPv6Address import socket import collections import os +import base64 +import quopri + +if "encodebytes" not in dir(base64): + base64.encodebytes = base64.encodestring + base64.decodebytes = base64.decodestring # pb2dict and dict2pb are methods to convert pb to/from dict. # Inspired by: @@ -189,14 +195,14 @@ def encode_dev(field, value): return dev[0] << kern_minorbits | dev[1] def encode_base64(value): - return value.encode('base64') + return base64.encodebytes(value) def decode_base64(value): - return value.decode('base64') + return base64.decodebytes(value) def encode_unix(value): - return value.encode('quopri') + return quopri.encodestring(value) def decode_unix(value): - return value.decode('quopri') + return quopri.decodestring(value) encode = { 'unix_name': encode_unix } decode = { 'unix_name': decode_unix } From 37d3781576dce63fc8ede7de7d72d2f1c12d654a Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 29 May 2019 17:15:04 +0100 Subject: [PATCH 2073/4375] cr-check: Add check for mremap() of special mappings During restore any VMA that's a subject to ASLR should be moved at the same address as was on a checkpoint. Previously, ports to non-x86 architectures had problems with VDSO mremap(). On those platforms kernel needs "landing" for return to userspace in some cases. Usually, vdso provides this landing and finishes restoring of registers. That's `int80_landing_pad` on ia32. On arm64/arm32 it's sigtrap for SA_RESTORER - to proceed after signal processing. That's why kernel needs to track the position of landing. On modern kernels for platform we support it's already done - however, for older kernels some patches needs to be backported for C/R. Provide the checks for mremap() of special VMAs: that CRIU has suitable kernel to work on and if we'll have some new platforms - that kernel tracks the position of landing. Signed-off-by: Dmitry Safonov --- criu/cr-check.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 1 deletion(-) diff --git a/criu/cr-check.c b/criu/cr-check.c index e24668305..75a665cfb 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -582,7 +582,7 @@ static pid_t fork_and_ptrace_attach(int (*child_setup)(void)) return pid; } -static int check_ptrace_peeksiginfo() +static int check_ptrace_peeksiginfo(void) { struct ptrace_peeksiginfo_args arg; siginfo_t siginfo; @@ -611,6 +611,177 @@ static int check_ptrace_peeksiginfo() return ret; } +struct special_mapping { + const char *name; + void *addr; + size_t size; +}; + +static int parse_special_maps(struct special_mapping *vmas, size_t nr) +{ + FILE *maps; + char buf[256]; + int ret = 0; + + maps = fopen_proc(PROC_SELF, "maps"); + if (!maps) + return -1; + + while (fgets(buf, sizeof(buf), maps)) { + unsigned long start, end; + int r, tail; + size_t i; + + r = sscanf(buf, "%lx-%lx %*s %*s %*s %*s %n\n", + &start, &end, &tail); + if (r != 2) { + fclose(maps); + pr_err("Bad maps format %d.%d (%s)\n", r, tail, buf + tail); + return -1; + } + + for (i = 0; i < nr; i++) { + if (strcmp(buf + tail, vmas[i].name) != 0) + continue; + if (vmas[i].addr != MAP_FAILED) { + pr_err("Special mapping meet twice: %s\n", vmas[i].name); + ret = -1; + goto out; + } + vmas[i].addr = (void *)start; + vmas[i].size = end - start; + } + } + +out: + fclose(maps); + return ret; +} + +static void dummy_sighandler(int sig) +{ +} + +/* + * The idea of test is checking if the kernel correctly tracks positions + * of special_mappings: vdso/vvar/sigpage/... + * Per-architecture commits added handling for mremap() somewhere between + * v4.8...v4.14. If the kernel doesn't have one of those patches, + * a process will crash after receiving a signal (we use SIGUSR1 for + * the test here). That's because after processing a signal the kernel + * needs a "landing" to return to userspace, which is based on vdso/sigpage. + * If the kernel doesn't track the position of mapping - we land in the void. + * And we definitely mremap() support by the fact that those special_mappings + * are subjects for ASLR. (See #288 as a reference) + */ +static void check_special_mapping_mremap_child(struct special_mapping *vmas, + size_t nr) +{ + size_t i, parking_size = 0; + void *parking_lot; + pid_t self = getpid(); + + for (i = 0; i < nr; i++) { + if (vmas[i].addr != MAP_FAILED) + parking_size += vmas[i].size; + } + + if (signal(SIGUSR1, dummy_sighandler) == SIG_ERR) { + pr_perror("signal() failed"); + exit(1); + } + + parking_lot = mmap(NULL, parking_size, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (parking_lot == MAP_FAILED) { + pr_perror("mmap(%zu) failed", parking_size); + exit(1); + } + + for (i = 0; i < nr; i++) { + unsigned long ret; + + if (vmas[i].addr == MAP_FAILED) + continue; + + ret = syscall(__NR_mremap, (unsigned long)vmas[i].addr, + vmas[i].size, vmas[i].size, + MREMAP_FIXED | MREMAP_MAYMOVE, + (unsigned long)parking_lot); + if (ret != (unsigned long)parking_lot) + syscall(__NR_exit, 1); + parking_lot += vmas[i].size; + } + + syscall(__NR_kill, self, SIGUSR1); + syscall(__NR_exit, 0); +} + +static int check_special_mapping_mremap(void) +{ + struct special_mapping special_vmas[] = { + { + .name = "[vvar]\n", + .addr = MAP_FAILED, + }, + { + .name = "[vdso]\n", + .addr = MAP_FAILED, + }, + { + .name = "[sigpage]\n", + .addr = MAP_FAILED, + }, + /* XXX: { .name = "[uprobes]\n" }, */ + /* + * Not subjects for ASLR, skipping: + * { .name = "[vectors]\n", }, + * { .name = "[vsyscall]\n" }, + */ + }; + size_t vmas_nr = ARRAY_SIZE(special_vmas); + pid_t child; + int stat; + + if (parse_special_maps(special_vmas, vmas_nr)) + return -1; + + child = fork(); + if (child < 0) { + pr_perror("%s(): failed to fork()", __func__); + return -1; + } + + if (child == 0) + check_special_mapping_mremap_child(special_vmas, vmas_nr); + + if (waitpid(child, &stat, 0) != child) { + if (errno == ECHILD) { + pr_err("BUG: Someone waited for the child already\n"); + return -1; + } + /* Probably, we're interrupted with a signal - cleanup */ + pr_err("Failed to wait for a child %d\n", errno); + kill(child, SIGKILL); + return -1; + } + + if (WIFSIGNALED(stat)) { + pr_err("Child killed by signal %d\n", WTERMSIG(stat)); + pr_err("Your kernel probably lacks the support for mremapping special mappings\n"); + return -1; + } else if (WIFEXITED(stat)) { + if (WEXITSTATUS(stat) == 0) + return 0; + pr_err("Child exited with %d\n", WEXITSTATUS(stat)); + return -1; + } + + pr_err("BUG: waitpid() returned stat=%d\n", stat); + /* We're not killing the child here - it's predestined to die anyway. */ + return -1; +} + static int check_ptrace_suspend_seccomp(void) { pid_t pid; @@ -1172,6 +1343,7 @@ int cr_check(void) CHECK_CAT1(check_ipc()); CHECK_CAT1(check_sigqueuinfo()); CHECK_CAT1(check_ptrace_peeksiginfo()); + CHECK_CAT1(check_special_mapping_mremap()); /* * Category 2 - required for specific cases. From 8824579c8ae31aae0dfa1a02619566c3acedade8 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 29 May 2019 17:15:05 +0100 Subject: [PATCH 2074/4375] vdso/arm: Add vdso symbols from kernel Signed-off-by: Dmitry Safonov --- criu/arch/arm/include/asm/vdso.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 criu/arch/arm/include/asm/vdso.h diff --git a/criu/arch/arm/include/asm/vdso.h b/criu/arch/arm/include/asm/vdso.h new file mode 100644 index 000000000..cf9d500be --- /dev/null +++ b/criu/arch/arm/include/asm/vdso.h @@ -0,0 +1,17 @@ +#ifndef __CR_ASM_VDSO_H__ +#define __CR_ASM_VDSO_H__ + +#include "asm/int.h" +#include "asm-generic/vdso.h" + +/* This definition is used in pie/util-vdso.c to initialize the vdso symbol + * name string table 'vdso_symbols' + * + * Poke from kernel file arch/arm/vdso/vdso.lds.S + */ +#define VDSO_SYMBOL_MAX 2 +#define ARCH_VDSO_SYMBOLS \ + "__vdso_clock_gettime", \ + "__vdso_gettimeofday" + +#endif /* __CR_ASM_VDSO_H__ */ From d2b4eddf52e3675524b9dbb93d5573dfb724c27a Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 29 May 2019 17:15:06 +0100 Subject: [PATCH 2075/4375] parasite-vdso: Add ugly casts for arm32 criu/pie/parasite-vdso.c: In function 'remap_rt_vdso': criu/pie/parasite-vdso.c:144:17: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] if (sys_munmap((void *)vma_vdso->start, vma_entry_len(vma_vdso))) { ^ criu/pie/parasite-vdso.c:154:17: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] if (sys_munmap((void *)vma_vvar->start, vma_entry_len(vma_vvar))) { ^ cc1: all warnings being treated as errors Signed-off-by: Dmitry Safonov --- criu/pie/parasite-vdso.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index dc73fb53e..90e20f767 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -127,11 +127,17 @@ static int remap_rt_vdso(VmaEntry *vma_vdso, VmaEntry *vma_vvar, { unsigned long rt_vvar_addr = vdso_rt_parked_at; unsigned long rt_vdso_addr = vdso_rt_parked_at; + void *remap_addr; int ret; pr_info("Runtime vdso/vvar matches dumpee, remap inplace\n"); - if (sys_munmap((void *)vma_vdso->start, vma_entry_len(vma_vdso))) { + /* + * Ugly casts for 32bit platforms, which don't like uint64_t + * cast to (void *) + */ + remap_addr = (void *)(uintptr_t)vma_vdso->start; + if (sys_munmap(remap_addr, vma_entry_len(vma_vdso))) { pr_err("Failed to unmap dumpee vdso\n"); return -1; } @@ -141,7 +147,8 @@ static int remap_rt_vdso(VmaEntry *vma_vdso, VmaEntry *vma_vvar, vma_vdso->start, sym_rt->vdso_size); } - if (sys_munmap((void *)vma_vvar->start, vma_entry_len(vma_vvar))) { + remap_addr = (void *)(uintptr_t)vma_vvar->start; + if (sys_munmap(remap_addr, vma_entry_len(vma_vvar))) { pr_err("Failed to unmap dumpee vvar\n"); return -1; } From d6ce398eb42319ee546a9064e9ce346c59cfa294 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 29 May 2019 17:15:07 +0100 Subject: [PATCH 2076/4375] vdso/arm32: Add vdso trampoline support Signed-off-by: Dmitry Safonov --- criu/arch/arm/vdso-pie.c | 58 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 criu/arch/arm/vdso-pie.c diff --git a/criu/arch/arm/vdso-pie.c b/criu/arch/arm/vdso-pie.c new file mode 100644 index 000000000..0ec8bd9a8 --- /dev/null +++ b/criu/arch/arm/vdso-pie.c @@ -0,0 +1,58 @@ +#include + +#include "asm/types.h" + +#include +#include +#include "parasite-vdso.h" +#include "log.h" +#include "common/bug.h" + +#ifdef LOG_PREFIX +# undef LOG_PREFIX +#endif +#define LOG_PREFIX "vdso: " + +static void insert_trampoline(uintptr_t from, uintptr_t to) +{ + struct { + uint32_t ldr_pc; + uint32_t imm32; + uint32_t guards; + } __packed jmp = { + .ldr_pc = 0xe51ff004, /* ldr pc, [pc, #-4] */ + .imm32 = to, + .guards = 0xe1200070, /* bkpt 0x0000 */ + }; + void *iflush_start = (void *)from; + void *iflush_end = iflush_start + sizeof(jmp); + + memcpy((void *)from, &jmp, sizeof(jmp)); + + __builtin___clear_cache(iflush_start, iflush_end); +} + +int vdso_redirect_calls(unsigned long base_to, unsigned long base_from, + struct vdso_symtable *sto, struct vdso_symtable *sfrom, + bool compat_vdso) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sto->symbols); i++) { + uintptr_t from, to; + + if (vdso_symbol_empty(&sfrom->symbols[i])) + continue; + + pr_debug("jmp: %lx/%lx -> %lx/%lx (index %d)\n", + base_from, sfrom->symbols[i].offset, + base_to, sto->symbols[i].offset, i); + + from = base_from + sfrom->symbols[i].offset; + to = base_to + sto->symbols[i].offset; + + insert_trampoline(from, to); + } + + return 0; +} From a856c48e7756ba4f6f2cf5a2e14efadc413e3368 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov <0x7f454c46@gmail.com> Date: Wed, 29 May 2019 17:15:08 +0100 Subject: [PATCH 2077/4375] arm: Build {pie-, }util-vdso with CONFIG_VDSO_32 Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> --- Makefile | 2 +- criu/Makefile.crtools | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index cee8a42c9..475d4abaf 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ endif # Architecture specific options. ifeq ($(ARCH),arm) ARMV := $(shell echo $(UNAME-M) | sed -nr 's/armv([[:digit:]]).*/\1/p; t; i7') - DEFINES := -DCONFIG_ARMV$(ARMV) + DEFINES := -DCONFIG_ARMV$(ARMV) -DCONFIG_VDSO_32 ifeq ($(ARMV),6) USERCFLAGS += -march=armv6 diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 13ea22775..dd4dc3783 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -87,7 +87,7 @@ obj-y += servicefd.o ifeq ($(VDSO),y) obj-y += pie-util-vdso.o obj-y += vdso.o -obj-y += pie-util-vdso-elf32.o +obj-$(CONFIG_COMPAT) += pie-util-vdso-elf32.o CFLAGS_pie-util-vdso-elf32.o += -DCONFIG_VDSO_32 obj-$(CONFIG_COMPAT) += vdso-compat.o CFLAGS_REMOVE_vdso-compat.o += $(CFLAGS-ASAN) $(CFLAGS-GCOV) From 934a050788bd9b508ae22441f434a93d23e8ac10 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov <0x7f454c46@gmail.com> Date: Wed, 29 May 2019 17:15:09 +0100 Subject: [PATCH 2078/4375] arm: Provide aeabi helpers in ARM format We're building PIEs in arm format rather than in thumb. Copy helpers from libgcc, provide a proper define and link them into blobs. Also substitute tabs by spaces, how it should have been in pie/Makefile - tabs are for recipes. Fixes: LINK criu/pie/parasite.built-in.o criu/pie/pie.lib.a(util-vdso.o): In function `elf_hash': /criu/criu/pie/util-vdso.c:61: undefined reference to `__aeabi_uidivmod' /criu/scripts/nmk/scripts/build.mk:209: recipe for target 'criu/pie/parasite.built-in.o' failed Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> --- criu/arch/arm/aeabi-helpers.S | 96 +++++++++++++ criu/arch/arm/uidiv.S | 186 -------------------------- criu/pie/Makefile | 4 +- criu/pie/Makefile.library | 4 + include/common/arch/arm/asm/linkage.h | 4 + 5 files changed, 106 insertions(+), 188 deletions(-) create mode 100644 criu/arch/arm/aeabi-helpers.S delete mode 100644 criu/arch/arm/uidiv.S diff --git a/criu/arch/arm/aeabi-helpers.S b/criu/arch/arm/aeabi-helpers.S new file mode 100644 index 000000000..ea8561d48 --- /dev/null +++ b/criu/arch/arm/aeabi-helpers.S @@ -0,0 +1,96 @@ +/* + * Code borrowed from gcc, arm/lib1funcs.S + * and adapted to CRIU macros. + */ + +#if defined(__thumb__) +/* + * We don't support compiling PIEs in Thumb mode, + * see top Makefile for details (ARM CFLAGS_PIE section). +*/ +#error Unsupported Thumb mode +#endif + +#include "common/asm/linkage.h" + +#define RET bx lr +#define RETc(x) bx##x lr +#define LSYM(x) .x + +.macro do_it cond, suffix="" +.endm + +.macro ARM_DIV2_ORDER divisor, order + clz \order, \divisor + rsb \order, \order, #31 +.endm + +.macro ARM_DIV_BODY dividend, divisor, result, curbit + clz \curbit, \dividend + clz \result, \divisor + sub \curbit, \result, \curbit + rsbs \curbit, \curbit, #31 + addne \curbit, \curbit, \curbit, lsl #1 + mov \result, #0 + addne pc, pc, \curbit, lsl #2 + nop + .set shift, 32 + .rept 32 + .set shift, shift - 1 + cmp \dividend, \divisor, lsl #shift + adc \result, \result, \result + subcs \dividend, \dividend, \divisor, lsl #shift + .endr +.endm + +/* + * XXX: as an optimization add udiv instruction based version. + * It's possible to check if CPU supports the instruction by + * reading Instruction Set Attribute Register (ID_ISAR0) + * and checking fields "Divide_instrs". + */ +ENTRY(__aeabi_uidiv) + /* Note: if called via udivsi3_skip_div0_test, this will unnecessarily + check for division-by-zero a second time. */ +LSYM(udivsi3_skip_div0_test): + subs r2, r1, #1 + do_it eq + RETc(eq) + bcc LSYM(Ldiv0) + cmp r0, r1 + bls 11f + tst r1, r2 + beq 12f + + ARM_DIV_BODY r0, r1, r2, r3 + + mov r0, r2 + RET + +11: do_it eq, e + moveq r0, #1 + movne r0, #0 + RET + +12: ARM_DIV2_ORDER r1, r2 + + mov r0, r0, lsr r2 + RET + +LSYM(Ldiv0): + .byte 0xf0, 0x01, 0xf0, 0xe7 @ the instruction UDF #32 generates the signal SIGTRAP in Linux + +END(__aeabi_uidiv) +ALIAS(__udivsi3, __aeabi_uidiv) + +ENTRY(__aeabi_uidivmod) + cmp r1, #0 + beq LSYM(Ldiv0) + stmfd sp!, { r0, r1, lr } + bl LSYM(udivsi3_skip_div0_test) + ldmfd sp!, { r1, r2, lr } + mul r3, r2, r0 + sub r1, r1, r3 + RET +END(__aeabi_uidivmod) +ALIAS(__umodsi3, __aeabi_uidiv) diff --git a/criu/arch/arm/uidiv.S b/criu/arch/arm/uidiv.S deleted file mode 100644 index e77f6100c..000000000 --- a/criu/arch/arm/uidiv.S +++ /dev/null @@ -1,186 +0,0 @@ -.globl __aeabi_uidiv - -work .req r4 @ XXXX is this safe ? -dividend .req r0 -divisor .req r1 -overdone .req r2 -result .req r2 -curbit .req r3 - -#define LSYM(x) x - -.macro THUMB_DIV_MOD_BODY modulo - @ Load the constant 0x10000000 into our work register. - mov work, #1 - lsl work, #28 -LSYM(Loop1): - @ Unless the divisor is very big, shift it up in multiples of - @ four bits, since this is the amount of unwinding in the main - @ division loop. Continue shifting until the divisor is - @ larger than the dividend. - cmp divisor, work - bhs LSYM(Lbignum) - cmp divisor, dividend - bhs LSYM(Lbignum) - lsl divisor, #4 - lsl curbit, #4 - b LSYM(Loop1) -LSYM(Lbignum): - @ Set work to 0x80000000 - lsl work, #3 -LSYM(Loop2): - @ For very big divisors, we must shift it a bit at a time, or - @ we will be in danger of overflowing. - cmp divisor, work - bhs LSYM(Loop3) - cmp divisor, dividend - bhs LSYM(Loop3) - lsl divisor, #1 - lsl curbit, #1 - b LSYM(Loop2) -LSYM(Loop3): - @ Test for possible subtractions ... - .if \modulo - @ ... On the final pass, this may subtract too much from the dividend, - @ so keep track of which subtractions are done, we can fix them up - @ afterwards. - mov overdone, #0 - cmp dividend, divisor - blo LSYM(Lover1) - sub dividend, dividend, divisor -LSYM(Lover1): - lsr work, divisor, #1 - cmp dividend, work - blo LSYM(Lover2) - sub dividend, dividend, work - mov ip, curbit - mov work, #1 - ror curbit, work - orr overdone, curbit - mov curbit, ip -LSYM(Lover2): - lsr work, divisor, #2 - cmp dividend, work - blo LSYM(Lover3) - sub dividend, dividend, work - mov ip, curbit - mov work, #2 - ror curbit, work - orr overdone, curbit - mov curbit, ip -LSYM(Lover3): - lsr work, divisor, #3 - cmp dividend, work - blo LSYM(Lover4) - sub dividend, dividend, work - mov ip, curbit - mov work, #3 - ror curbit, work - orr overdone, curbit - mov curbit, ip -LSYM(Lover4): - mov ip, curbit - .else - @ ... and note which bits are done in the result. On the final pass, - @ this may subtract too much from the dividend, but the result will be ok, - @ since the "bit" will have been shifted out at the bottom. - cmp dividend, divisor - blo LSYM(Lover1) - sub dividend, dividend, divisor - orr result, result, curbit -LSYM(Lover1): - lsr work, divisor, #1 - cmp dividend, work - blo LSYM(Lover2) - sub dividend, dividend, work - lsr work, curbit, #1 - orr result, work -LSYM(Lover2): - lsr work, divisor, #2 - cmp dividend, work - blo LSYM(Lover3) - sub dividend, dividend, work - lsr work, curbit, #2 - orr result, work -LSYM(Lover3): - lsr work, divisor, #3 - cmp dividend, work - blo LSYM(Lover4) - sub dividend, dividend, work - lsr work, curbit, #3 - orr result, work -LSYM(Lover4): - .endif - - cmp dividend, #0 @ Early termination? - beq LSYM(Lover5) - lsr curbit, #4 @ No, any more bits to do? - beq LSYM(Lover5) - lsr divisor, #4 - b LSYM(Loop3) -LSYM(Lover5): - .if \modulo - @ Any subtractions that we should not have done will be recorded in - @ the top three bits of "overdone". Exactly which were not needed - @ are governed by the position of the bit, stored in ip. - mov work, #0xe - lsl work, #28 - and overdone, work - beq LSYM(Lgot_result) - - @ If we terminated early, because dividend became zero, then the - @ bit in ip will not be in the bottom nibble, and we should not - @ perform the additions below. We must test for this though - @ (rather relying upon the TSTs to prevent the additions) since - @ the bit in ip could be in the top two bits which might then match - @ with one of the smaller RORs. - mov curbit, ip - mov work, #0x7 - tst curbit, work - beq LSYM(Lgot_result) - - mov curbit, ip - mov work, #3 - ror curbit, work - tst overdone, curbit - beq LSYM(Lover6) - lsr work, divisor, #3 - add dividend, work -LSYM(Lover6): - mov curbit, ip - mov work, #2 - ror curbit, work - tst overdone, curbit - beq LSYM(Lover7) - lsr work, divisor, #2 - add dividend, work -LSYM(Lover7): - mov curbit, ip - mov work, #1 - ror curbit, work - tst overdone, curbit - beq LSYM(Lgot_result) - lsr work, divisor, #1 - add dividend, work - .endif -LSYM(Lgot_result): -.endm - - - .thumb - .text - -__aeabi_uidiv: - mov curbit, #1 - mov result, #0 - - push { work } - cmp dividend, divisor - blo LSYM(Lgot_result) - - THUMB_DIV_MOD_BODY 0 - - mov r0, result - pop { work } - - bx lr diff --git a/criu/pie/Makefile b/criu/pie/Makefile index bdff44816..ade186346 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -10,8 +10,8 @@ ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) - LDFLAGS += $(shell $(COMPEL_BIN) ldflags) - compel_plugins := $(shell $(COMPEL_BIN) plugins) + LDFLAGS += $(shell $(COMPEL_BIN) ldflags) + compel_plugins := $(shell $(COMPEL_BIN) plugins) endif LDS := compel/arch/$(SRCARCH)/scripts/compel-pack.lds.S diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 0a33a8861..2d2d1faf1 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -23,5 +23,9 @@ ifeq ($(SRCARCH),x86) CFLAGS_util-vdso-elf32.o += -DCONFIG_VDSO_32 endif +ifeq ($(SRCARCH),arm) + lib-y += ./$(ARCH_DIR)/aeabi-helpers.o +endif + CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) ccflags-y += $(CFLAGS_PIE) diff --git a/include/common/arch/arm/asm/linkage.h b/include/common/arch/arm/asm/linkage.h index 738064233..a93898be5 100644 --- a/include/common/arch/arm/asm/linkage.h +++ b/include/common/arch/arm/asm/linkage.h @@ -19,6 +19,10 @@ #define END(sym) \ .size sym, . - sym +#define ALIAS(sym_new, sym_old) \ + .globl sym_new; \ + .set sym_new, sym_old + #endif /* __ASSEMBLY__ */ #endif /* __CR_LINKAGE_H__ */ From 670648c931d6851e2483576fa25158001b4b4ba0 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 29 May 2019 17:15:10 +0100 Subject: [PATCH 2079/4375] arm/pie: Provide __clear_cache() After patching code - we need to flush CPU cache, it's done with __builtin___clear_cache(). As we don't link to libgcc, provide a helper that wraps ARM-specific syscall. Fixes: LINK criu/pie/restorer.built-in.o ld: ./criu/arch/arm/vdso-pie.o: in function `insert_trampoline': /root/criu/criu/arch/arm/vdso-pie.c:32: undefined reference to `__clear_cache' Signed-off-by: Dmitry Safonov --- compel/arch/arm/plugins/std/syscalls/syscall.def | 1 + criu/arch/arm/pie-cacheflush.c | 7 +++++++ criu/pie/Makefile.library | 1 + 3 files changed, 9 insertions(+) create mode 100644 criu/arch/arm/pie-cacheflush.c diff --git a/compel/arch/arm/plugins/std/syscalls/syscall.def b/compel/arch/arm/plugins/std/syscalls/syscall.def index bcd61d4a1..653a7539b 100644 --- a/compel/arch/arm/plugins/std/syscalls/syscall.def +++ b/compel/arch/arm/plugins/std/syscalls/syscall.def @@ -110,3 +110,4 @@ gettimeofday 169 78 (struct timeval *tv, struct timezone *tz) preadv_raw 69 361 (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) userfaultfd 282 388 (int flags) fallocate 47 352 (int fd, int mode, loff_t offset, loff_t len) +cacheflush ! 983042 (void *start, void *end, int flags) diff --git a/criu/arch/arm/pie-cacheflush.c b/criu/arch/arm/pie-cacheflush.c new file mode 100644 index 000000000..e6fd71f1e --- /dev/null +++ b/criu/arch/arm/pie-cacheflush.c @@ -0,0 +1,7 @@ +#include + +/* That's __builtin___clear_cache() to flush CPU cache */ +void __clear_cache(void *start, void *end) +{ + sys_cacheflush(start, end, 0); +} diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 2d2d1faf1..b1ac600c6 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -25,6 +25,7 @@ endif ifeq ($(SRCARCH),arm) lib-y += ./$(ARCH_DIR)/aeabi-helpers.o + lib-y += ./$(ARCH_DIR)/pie-cacheflush.o endif CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) From b2efa720ce91c7f032869c6fcfc6aebb8ea95447 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 29 May 2019 17:15:11 +0100 Subject: [PATCH 2080/4375] rt-vdso: Be verbose if !blobs_matches() (00.251007) pie: 4: vdso: Runtime vdso mismatches dumpee, generate proxy And I want to know why :) Signed-off-by: Dmitry Safonov --- criu/pie/parasite-vdso.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 90e20f767..00bc2bffa 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -95,23 +95,44 @@ static int __vdso_fill_symtable(uintptr_t mem, size_t size, static bool blobs_matches(VmaEntry *vdso_img, VmaEntry *vvar_img, struct vdso_symtable *sym_img, struct vdso_symtable *sym_rt) { + unsigned long vdso_size = vma_entry_len(vdso_img); + unsigned long rt_vdso_size = sym_rt->vdso_size; size_t i; - if (vma_entry_len(vdso_img) != sym_rt->vdso_size) + if (vdso_size != rt_vdso_size) { + pr_info("size differs: %lx != %lx (rt)\n", + vdso_size, rt_vdso_size); return false; + } for (i = 0; i < ARRAY_SIZE(sym_img->symbols); i++) { - if (sym_img->symbols[i].offset != sym_rt->symbols[i].offset) + unsigned long sym_offset = sym_img->symbols[i].offset; + unsigned long rt_sym_offset = sym_rt->symbols[i].offset; + char *sym_name = sym_img->symbols[i].name; + + if (sym_offset != rt_sym_offset) { + pr_info("[%zu]`%s` offset differs: %lx != %lx (rt)\n", + i, sym_name, sym_offset, rt_sym_offset); return false; + } } if (vvar_img && sym_rt->vvar_size != VVAR_BAD_SIZE) { bool vdso_firstly = (vvar_img->start > vdso_img->start); + unsigned long vvar_size = vma_entry_len(vvar_img); + unsigned long rt_vvar_size = sym_rt->vvar_size; - if (sym_rt->vvar_size != vma_entry_len(vvar_img)) + if (vvar_size != rt_vvar_size) { + pr_info("vvar size differs: %lx != %lx (rt)\n", + vdso_size, rt_vdso_size); return false; + } - return (vdso_firstly == sym_rt->vdso_before_vvar); + if (vdso_firstly != sym_rt->vdso_before_vvar) { + pr_info("[%s] pair has different order\n", + vdso_firstly ? "vdso/vvar" : "vvar/vdso"); + return false; + } } return true; From ee6412fa20e683868cbc33ba4ff6526bf5523e82 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 29 May 2019 17:15:12 +0100 Subject: [PATCH 2081/4375] x86/vdso: Don't insert trampolines in vsyscall The patch "util-vdso: Check chain for STN_UNDEF" fixed an issue about not discovering present symbols on vdso. While it's a good and a proper fix, as the result __kernel_vsyscall started being patched. Which in result broke zdtm trampoline test on ia32. So, let's omit patching vsyscall while #512 issue is not fixed. We might actually refrain patching it for long time as it doesn't access vvar, so there is little sense in doing patching. Signed-off-by: Dmitry Safonov --- criu/arch/x86/include/asm/vdso.h | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/criu/arch/x86/include/asm/vdso.h b/criu/arch/x86/include/asm/vdso.h index ae893b8d7..046db2336 100644 --- a/criu/arch/x86/include/asm/vdso.h +++ b/criu/arch/x86/include/asm/vdso.h @@ -12,17 +12,38 @@ * This is a minimal amount of symbols * we should support at the moment. */ -#define VDSO_SYMBOL_MAX 7 +#define VDSO_SYMBOL_MAX 6 +/* + * XXX: we don't patch __kernel_vsyscall as it's too small: + * + * byte *before* *after* + * 0x0 push %ecx mov $[rt-vdso],%eax + * 0x1 push %edx ^ + * 0x2 push %ebp ^ + * 0x3 mov %esp,%ebp ^ + * 0x5 sysenter jmp *%eax + * 0x7 int $0x80 int3 + * 0x9 pop %ebp int3 + * 0xa pop %edx int3 + * 0xb pop %ecx pop %ecx + * 0xc ret ret + * + * As restarting a syscall is quite likely after restore, + * the patched version quitly crashes. + * vsyscall will be patched again when addressing: + * https://github.com/checkpoint-restore/criu/issues/512 + */ #define ARCH_VDSO_SYMBOLS \ "__vdso_clock_gettime", \ "__vdso_getcpu", \ "__vdso_gettimeofday", \ "__vdso_time", \ - "__kernel_vsyscall", \ "__kernel_sigreturn", \ "__kernel_rt_sigreturn" +/* "__kernel_vsyscall", */ + #ifndef ARCH_MAP_VDSO_32 # define ARCH_MAP_VDSO_32 0x2002 #endif From a96f0f1877a7b0c2fbb975043c96c32584d8f501 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 29 May 2019 17:15:13 +0100 Subject: [PATCH 2082/4375] util-vdso: Check chain for STN_UNDEF Rather than chain[chain] != STN_UNDEF. Seems like, on !ARM32 vdso there are more symbols and less chance to hit this "feature". Fixes parsing of __vdso_clock_gettime symbol on v5.1 arm kernel. Signed-off-by: Dmitry Safonov --- criu/pie/util-vdso.c | 2 +- test/zdtm/static/vdso01.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/pie/util-vdso.c b/criu/pie/util-vdso.c index 6213df9a4..104da0633 100644 --- a/criu/pie/util-vdso.c +++ b/criu/pie/util-vdso.c @@ -242,7 +242,7 @@ static void parse_elf_symbols(uintptr_t mem, size_t size, Phdr_t *load, const char * symbol = vdso_symbols[i]; k = elf_hash((const unsigned char *)symbol); - for (j = bucket[k % nbucket]; j < nchain && chain[j] != STN_UNDEF; j = chain[j]) { + for (j = bucket[k % nbucket]; j < nchain && j != STN_UNDEF; j = chain[j]) { addr = mem + dyn_symtab->d_un.d_ptr - load->p_vaddr; Sym_t *sym; char *name; diff --git a/test/zdtm/static/vdso01.c b/test/zdtm/static/vdso01.c index be733663c..269688c5e 100644 --- a/test/zdtm/static/vdso01.c +++ b/test/zdtm/static/vdso01.c @@ -246,7 +246,7 @@ static int vdso_fill_symtable(char *mem, size_t size, struct vdso_symtable *t) for (i = 0; i < ARRAY_SIZE(vdso_symbols); i++) { k = elf_hash((const unsigned char *)vdso_symbols[i]); - for (j = bucket[k % nbucket]; j < nchain && chain[j] != STN_UNDEF; j = chain[j]) { + for (j = bucket[k % nbucket]; j < nchain && j != STN_UNDEF; j = chain[j]) { Sym_t *sym = (void *)&mem[dyn_symtab->d_un.d_ptr - load->p_vaddr]; char *name; From e73df268af04e84ecf65c830b49bb687c1a54c7e Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 29 May 2019 17:15:14 +0100 Subject: [PATCH 2083/4375] pie/build: Add CFLAGS_PIE to CFLAGS There is a little difference between ccflags-y and CFLAGS, except the local/global visibility: nmk adds $(CFLAGS) to nmk-asflags and assembles using them, but without ccflags-y. The other possible way would be adding asflags-y with CFLAGS_PIE, but I'm not convinced - let's update CFLAGS for the time being. Signed-off-by: Dmitry Safonov --- criu/pie/Makefile | 2 +- criu/pie/Makefile.library | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/pie/Makefile b/criu/pie/Makefile index ade186346..47443c26b 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -5,7 +5,7 @@ target := parasite restorer CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) -ccflags-y += $(CFLAGS_PIE) +CFLAGS += $(CFLAGS_PIE) ccflags-y += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 ccflags-y += -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=0 diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index b1ac600c6..d802417de 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -29,4 +29,4 @@ ifeq ($(SRCARCH),arm) endif CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) -ccflags-y += $(CFLAGS_PIE) +CFLAGS += $(CFLAGS_PIE) From de53191179ad3413e4ce3d18ed915e4ecdc39ed7 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 29 May 2019 17:15:15 +0100 Subject: [PATCH 2084/4375] criu/vdso: Purge CONFIG_VDSO Vigorously remove the config ifdef. The config option *never* had any excuse to exist: - for x86 we were grand - for ppc64/arm64 patches to support mremap() on vdso were long ago accepted, but regardless - it's not possible to disable CONFIG_VDSO for those platforms in kernel - for s390 - patches were mainstreamed not that long ago, but it's not possible to disable the kernel config - for arm32 it's possible to disable the kernel config, but kernel returns to userspace historically through sigpage, not vdso. That's the only platform that criu disallows to have CONFIG_VDSO=y in kernel, but that's just meaningles. A kernel patch for sigpage mremap() has gone into v4.13: commit 280e87e98c09 ("ARM: 8683/1: ARM32: Support mremap() for sigpage/vDSO"). So, removing the config was long-lived item on my TODO list that bligted arm32 users and made changes to vdso more complex by all "needed" iffdeferry. Get rid of it with fire. Fixes: #446 Signed-off-by: Dmitry Safonov --- Makefile | 6 +----- Makefile.config | 4 ---- criu/Makefile.crtools | 3 --- criu/cr-restore.c | 6 ------ criu/include/kerndat.h | 4 ---- criu/include/parasite-vdso.h | 9 --------- criu/include/restorer.h | 2 -- criu/include/vdso.h | 13 ------------- criu/mem.c | 3 +-- criu/pie/Makefile | 15 ++++++--------- criu/pie/Makefile.library | 9 +-------- criu/pie/parasite.c | 8 -------- criu/pie/restorer.c | 8 -------- criu/proc_parse.c | 14 -------------- 14 files changed, 9 insertions(+), 95 deletions(-) diff --git a/Makefile b/Makefile index 475d4abaf..09cf2406a 100644 --- a/Makefile +++ b/Makefile @@ -56,19 +56,16 @@ ifeq ($(ARCH),arm) endif ifeq ($(ARCH),aarch64) - VDSO := y DEFINES := -DCONFIG_AARCH64 endif ifeq ($(ARCH),ppc64) LDARCH := powerpc:common64 - VDSO := y DEFINES := -DCONFIG_PPC64 -D__SANE_USERSPACE_TYPES__ endif ifeq ($(ARCH),x86) LDARCH := i386:x86-64 - VDSO := y DEFINES := -DCONFIG_X86_64 endif @@ -81,7 +78,6 @@ endif ifeq ($(ARCH),s390) ARCH := s390 SRCARCH := s390 - VDSO := y DEFINES := -DCONFIG_S390 CFLAGS_PIE := -fno-optimize-sibling-calls endif @@ -90,7 +86,7 @@ CFLAGS_PIE += -DCR_NOGLIBC export CFLAGS_PIE LDARCH ?= $(SRCARCH) -export LDARCH VDSO +export LDARCH export PROTOUFIX DEFINES # diff --git a/Makefile.config b/Makefile.config index a853705b3..008a82289 100644 --- a/Makefile.config +++ b/Makefile.config @@ -57,10 +57,6 @@ $(CONFIG_HEADER): scripts/feature-tests.mak $(CONFIG_FILE) $(Q) echo '' >> $$@ $(call map,gen-feature-test,$(FEATURES_LIST)) $(Q) cat $(CONFIG_FILE) | sed -n -e '/^[^#]/s/^/#define CONFIG_/p' >> $$@ -ifeq ($$(VDSO),y) - $(Q) echo '#define CONFIG_VDSO' >> $$@ - $(Q) echo '' >> $$@ -endif $(Q) echo '#endif /* __CR_CONFIG_H__ */' >> $$@ endef diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index dd4dc3783..383ed1940 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -83,15 +83,12 @@ obj-y += fdstore.o obj-y += uffd.o obj-y += config.o obj-y += servicefd.o - -ifeq ($(VDSO),y) obj-y += pie-util-vdso.o obj-y += vdso.o obj-$(CONFIG_COMPAT) += pie-util-vdso-elf32.o CFLAGS_pie-util-vdso-elf32.o += -DCONFIG_VDSO_32 obj-$(CONFIG_COMPAT) += vdso-compat.o CFLAGS_REMOVE_vdso-compat.o += $(CFLAGS-ASAN) $(CFLAGS-GCOV) -endif PROTOBUF_GEN := scripts/protobuf-gen.sh diff --git a/criu/cr-restore.c b/criu/cr-restore.c index f25efb823..23be81140 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3225,10 +3225,8 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns struct thread_restore_args *thread_args; struct restore_mem_zone *mz; -#ifdef CONFIG_VDSO struct vdso_maps vdso_maps_rt; unsigned long vdso_rt_size = 0; -#endif struct vm_area_list self_vmas; struct vm_area_list *vmas = &rsti(current)->vmas; @@ -3279,7 +3277,6 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns pr_info("%d threads require %ldK of memory\n", current->nr_threads, KBYTES(task_args->bootstrap_len)); -#ifdef CONFIG_VDSO if (core_is_compat(core)) vdso_maps_rt = vdso_maps_compat; else @@ -3291,7 +3288,6 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns if (vdso_rt_size && vdso_maps_rt.sym.vvar_size) vdso_rt_size += ALIGN(vdso_maps_rt.sym.vvar_size, PAGE_SIZE); task_args->bootstrap_len += vdso_rt_size; -#endif /* * Restorer is a blob (code + args) that will get mapped in some @@ -3506,7 +3502,6 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns } -#ifdef CONFIG_VDSO /* * Restorer needs own copy of vdso parameters. Runtime * vdso must be kept non intersecting with anything else, @@ -3518,7 +3513,6 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns task_args->vdso_maps_rt = vdso_maps_rt; task_args->vdso_rt_size = vdso_rt_size; task_args->can_map_vdso = kdat.can_map_vdso; -#endif new_sp = restorer_stack(task_args->t->mz); diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 2740dd3b1..75e2130b2 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -5,9 +5,7 @@ #include "int.h" #include "common/config.h" #include "asm/kerndat.h" -#ifdef CONFIG_VDSO #include "util-vdso.h" -#endif struct stat; @@ -61,11 +59,9 @@ struct kerndat_s { bool has_thp_disable; bool can_map_vdso; bool vdso_hint_reliable; -#ifdef CONFIG_VDSO struct vdso_symtable vdso_sym; #ifdef CONFIG_COMPAT struct vdso_symtable vdso_sym_compat; -#endif #endif bool has_nsid; bool has_link_nsid; diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index 6667fe5c4..3cf67bbb3 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -2,9 +2,6 @@ #define __CR_PARASITE_VDSO_H__ #include "common/config.h" - -#ifdef CONFIG_VDSO - #include "util-vdso.h" #include "images/vma.pb-c.h" @@ -95,10 +92,4 @@ extern int vdso_redirect_calls(unsigned long base_to, unsigned long base_from, struct vdso_symtable *to, struct vdso_symtable *from, bool compat_vdso); -#else /* CONFIG_VDSO */ -#define vdso_do_park(sym_rt, park_at, park_size) (0) -#define vdso_map_compat(map_at) (0) - -#endif /* CONFIG_VDSO */ - #endif /* __CR_PARASITE_VDSO_H__ */ diff --git a/criu/include/restorer.h b/criu/include/restorer.h index b83e9130c..effbc3655 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -207,11 +207,9 @@ struct task_restore_args { bool can_map_vdso; bool auto_dedup; -#ifdef CONFIG_VDSO unsigned long vdso_rt_size; struct vdso_maps vdso_maps_rt; /* runtime vdso symbols */ unsigned long vdso_rt_parked_at; /* safe place to keep vdso */ -#endif void **breakpoint; enum faults fault_strategy; diff --git a/criu/include/vdso.h b/criu/include/vdso.h index 1719f3fb7..fd30772b4 100644 --- a/criu/include/vdso.h +++ b/criu/include/vdso.h @@ -5,9 +5,6 @@ #include #include "common/config.h" - -#ifdef CONFIG_VDSO - #include "util-vdso.h" extern struct vdso_maps vdso_maps; @@ -26,14 +23,4 @@ extern void compat_vdso_helper(struct vdso_maps *native, int pipe_fd, int err_fd, void *vdso_buf, size_t buf_size); #endif -#else /* CONFIG_VDSO */ - -#define vdso_init_dump() (0) -#define vdso_init_restore() (0) -#define kerndat_vdso_fill_symtable() (0) -#define kerndat_vdso_preserves_hint() (0) -#define parasite_fixup_vdso(ctl, pid, vma_area_list) (0) - -#endif /* CONFIG_VDSO */ - #endif /* __CR_VDSO_H__ */ diff --git a/criu/mem.c b/criu/mem.c index b1d13188b..6a1a87a1e 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -101,7 +101,6 @@ static inline bool __page_in_parent(bool dirty) bool should_dump_page(VmaEntry *vmae, u64 pme) { -#ifdef CONFIG_VDSO /* * vDSO area must be always dumped because on restore * we might need to generate a proxy. @@ -117,7 +116,7 @@ bool should_dump_page(VmaEntry *vmae, u64 pme) */ if (vma_entry_is(vmae, VMA_AREA_VVAR)) return false; -#endif + /* * Optimisation for private mapping pages, that haven't * yet being COW-ed diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 47443c26b..1ad456f43 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -16,6 +16,7 @@ endif LDS := compel/arch/$(SRCARCH)/scripts/compel-pack.lds.S +restorer-obj-y += parasite-vdso.o ./$(ARCH_DIR)/vdso-pie.o restorer-obj-y += ./$(ARCH_DIR)/restorer.o ifeq ($(ARCH),x86) @@ -25,16 +26,12 @@ ifeq ($(ARCH),x86) endif endif -ifeq ($(VDSO),y) - restorer-obj-y += parasite-vdso.o ./$(ARCH_DIR)/vdso-pie.o +ifeq ($(SRCARCH),aarch64) + restorer-obj-y += ./$(ARCH_DIR)/intraprocedure.o +endif - ifeq ($(SRCARCH),aarch64) - restorer-obj-y += ./$(ARCH_DIR)/intraprocedure.o - endif - - ifeq ($(SRCARCH),ppc64) - restorer-obj-y += ./$(ARCH_DIR)/vdso-trampoline.o - endif +ifeq ($(SRCARCH),ppc64) + restorer-obj-y += ./$(ARCH_DIR)/vdso-trampoline.o endif define gen-pie-rules diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index d802417de..658c8a4eb 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -7,14 +7,7 @@ lib-name := pie.lib.a lib-y += util.o - -ifeq ($(VDSO),y) - lib-y += util-vdso.o -endif - -ifeq ($(SRCARCH),ppc64) - lib-y += ./$(ARCH_DIR)/misc.o -endif +lib-y += util-vdso.o ifeq ($(SRCARCH),x86) ifeq ($(CONFIG_COMPAT),y) diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index c32e31384..01bacd311 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -573,7 +573,6 @@ err_io: #undef __tty_ioctl } -#ifdef CONFIG_VDSO static int parasite_check_vdso_mark(struct parasite_vdso_vma_entry *args) { struct vdso_mark *m = (void *)args->start; @@ -609,13 +608,6 @@ static int parasite_check_vdso_mark(struct parasite_vdso_vma_entry *args) return 0; } -#else -static inline int parasite_check_vdso_mark(struct parasite_vdso_vma_entry *args) -{ - pr_err("Unexpected VDSO check command\n"); - return -1; -} -#endif static int parasite_dump_cgroup(struct parasite_dump_cgroup_args *args) { diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index f2db115ff..513be74e0 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1081,11 +1081,7 @@ static void restore_posix_timers(struct task_restore_args *args) * sys_munmap must not return here. The control process must * trap us on the exit from sys_munmap. */ -#ifdef CONFIG_VDSO unsigned long vdso_rt_size = 0; -#else -#define vdso_rt_size (0) -#endif void *bootstrap_start = NULL; unsigned int bootstrap_len = 0; @@ -1259,9 +1255,7 @@ long __export_restore_task(struct task_restore_args *args) bootstrap_start = args->bootstrap_start; bootstrap_len = args->bootstrap_len; -#ifdef CONFIG_VDSO vdso_rt_size = args->vdso_rt_size; -#endif fi_strategy = args->fault_strategy; @@ -1446,7 +1440,6 @@ long __export_restore_task(struct task_restore_args *args) sys_close(args->vma_ios_fd); -#ifdef CONFIG_VDSO /* * Proxify vDSO. */ @@ -1454,7 +1447,6 @@ long __export_restore_task(struct task_restore_args *args) args->vmas, args->vmas_n, args->compatible_mode, fault_injected(FI_VDSO_TRAMPOLINES))) goto core_restore_end; -#endif /* * Walk though all VMAs again to drop PROT_WRITE diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 3d852d755..f6ebb1fd6 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -502,7 +502,6 @@ err: return -1; } -#ifdef CONFIG_VDSO static inline int handle_vdso_vma(struct vma_area *vma) { vma->e->status |= VMA_AREA_REGULAR; @@ -518,19 +517,6 @@ static inline int handle_vvar_vma(struct vma_area *vma) vma->e->status |= VMA_AREA_VVAR; return 0; } -#else -static inline int handle_vdso_vma(struct vma_area *vma) -{ - pr_warn_once("Found vDSO area without support\n"); - return -1; -} - -static inline int handle_vvar_vma(struct vma_area *vma) -{ - pr_warn_once("Found VVAR area without support\n"); - return -1; -} -#endif static int handle_vma(pid_t pid, struct vma_area *vma_area, const char *file_path, DIR *map_files_dir, From bd7920717fed499761b5c7ddec08f326c613e0d4 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sat, 18 May 2019 09:28:36 +0100 Subject: [PATCH 2085/4375] zdtm: Fix memory and resource leaks These errors were found by Cppcheck 1.84 Signed-off-by: Radostin Stoyanov --- test/zdtm/static/autofs.c | 11 ++++++----- test/zdtm/static/caps00.c | 1 + test/zdtm/static/packet_sock_mmap.c | 1 + test/zdtm/static/s390x_runtime_instr.c | 2 ++ test/zdtm/static/sock_peercred.c | 18 +++++++++++------- test/zdtm/static/unlink_multiple_largefiles.c | 10 +++++++--- test/zdtm/static/vdso-proxy.c | 8 ++++---- test/zdtm/transition/lazy-thp.c | 2 ++ 8 files changed, 34 insertions(+), 19 deletions(-) diff --git a/test/zdtm/static/autofs.c b/test/zdtm/static/autofs.c index f74bc35ac..4360f90f0 100644 --- a/test/zdtm/static/autofs.c +++ b/test/zdtm/static/autofs.c @@ -312,7 +312,7 @@ static int autofs_open_mount(int devid, const char *mountpoint) { struct autofs_dev_ioctl *param; size_t size; - int fd; + int ret; size = sizeof(struct autofs_dev_ioctl) + strlen(mountpoint) + 1; param = malloc(size); @@ -325,13 +325,14 @@ static int autofs_open_mount(int devid, const char *mountpoint) if (ioctl(autofs_dev, AUTOFS_DEV_IOCTL_OPENMOUNT, param) < 0) { pr_perror("failed to open autofs mount %s", mountpoint); - return -errno; + ret = -errno; + goto out; } - fd = param->ioctlfd; + ret = param->ioctlfd; +out: free(param); - - return fd; + return ret; } static int autofs_report_result(int token, int devid, const char *mountpoint, diff --git a/test/zdtm/static/caps00.c b/test/zdtm/static/caps00.c index 62484c4f4..7a256c08a 100644 --- a/test/zdtm/static/caps00.c +++ b/test/zdtm/static/caps00.c @@ -47,6 +47,7 @@ int main(int argc, char **argv) if (f) { if (fscanf(f, "%d", &cap_last_cap) != 1) { pr_perror("Unable to read cal_last_cap"); + fclose(f); return 1; } fclose(f); diff --git a/test/zdtm/static/packet_sock_mmap.c b/test/zdtm/static/packet_sock_mmap.c index edf96c66e..2a82950bc 100644 --- a/test/zdtm/static/packet_sock_mmap.c +++ b/test/zdtm/static/packet_sock_mmap.c @@ -47,6 +47,7 @@ static void check_map_is_there(unsigned long addr, int sk) sscanf(line, "%lx-%*x %*s %*s %x:%x %d %*s", &start, &maj, &min, &ino); if ((start == addr) && ss.st_dev == makedev(maj, min) && ss.st_ino == ino) { pass(); + fclose(f); return; } } diff --git a/test/zdtm/static/s390x_runtime_instr.c b/test/zdtm/static/s390x_runtime_instr.c index 6be32c3c1..e0a5742d9 100644 --- a/test/zdtm/static/s390x_runtime_instr.c +++ b/test/zdtm/static/s390x_runtime_instr.c @@ -147,9 +147,11 @@ int main(int argc, char **argv) test_waitsig(); skip("RI not supported"); pass(); + free(buf); return 0; } fail("Fail with error %d", errno); + free(buf); return -1; } /* Set buffer for RI */ diff --git a/test/zdtm/static/sock_peercred.c b/test/zdtm/static/sock_peercred.c index e681ecec9..069cc52f7 100644 --- a/test/zdtm/static/sock_peercred.c +++ b/test/zdtm/static/sock_peercred.c @@ -67,6 +67,7 @@ int main(int argc, char **argv) socklen_t len; char *stack; pid_t pid; + int exit_code = 1; test_init(argc, argv); @@ -78,7 +79,7 @@ int main(int argc, char **argv) stack = malloc(2 * STACK_SIZE); if (!stack) { pr_err("malloc\n"); - return 1; + goto out; } /* Find unused fd */ @@ -89,18 +90,18 @@ int main(int argc, char **argv) if (fd == INT_MAX) { pr_err("INT_MAX happens...\n"); - return 1; + goto out; } pid = clone(child_func, stack + STACK_SIZE, CLONE_FILES|SIGCHLD, (void *)(unsigned long)fd); if (pid == -1) { pr_perror("clone"); - return 1; + goto out; } if (wait(&status) == -1 || status) { pr_perror("wait error: status=%d\n", status); - return 1; + goto out; } test_daemon(); @@ -109,15 +110,18 @@ int main(int argc, char **argv) len = sizeof(ucred); if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) { fail("Can't getsockopt()"); - return 1; + goto out; } if (ucred.pid != pid || ucred.gid != getuid() + UID_INC || ucred.gid != getgid() + GID_INC) { fail("Wrong pid, uid or gid\n"); - return 1; + goto out; } pass(); - return 0; + exit_code = 0; + out: + free(stack); + return exit_code; } diff --git a/test/zdtm/static/unlink_multiple_largefiles.c b/test/zdtm/static/unlink_multiple_largefiles.c index a87093439..7cf628606 100644 --- a/test/zdtm/static/unlink_multiple_largefiles.c +++ b/test/zdtm/static/unlink_multiple_largefiles.c @@ -31,7 +31,7 @@ void create_check_pattern(char *buf, size_t count, unsigned char seed) struct fiemap *read_fiemap(int fd) { test_msg("Obtaining fiemap for fd %d\n", fd); - struct fiemap *fiemap; + struct fiemap *fiemap, *tmp; int extents_size; fiemap = malloc(sizeof(struct fiemap)); @@ -48,16 +48,19 @@ struct fiemap *read_fiemap(int fd) if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) { pr_perror("FIEMAP ioctl failed"); + free(fiemap); return NULL; } extents_size = sizeof(struct fiemap_extent) * fiemap->fm_mapped_extents; - fiemap = realloc(fiemap,sizeof(struct fiemap) + extents_size); - if (fiemap == NULL) { + tmp = realloc(fiemap, sizeof(struct fiemap) + extents_size); + if (tmp == NULL) { + free(fiemap); pr_perror("Cannot resize fiemap"); return NULL; } + fiemap = tmp; memset(fiemap->fm_extents, 0, extents_size); fiemap->fm_extent_count = fiemap->fm_mapped_extents; @@ -65,6 +68,7 @@ struct fiemap *read_fiemap(int fd) if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) { pr_perror("fiemap ioctl() failed"); + free(fiemap); return NULL; } test_msg("Debugkillme: %x\n", fiemap->fm_mapped_extents); diff --git a/test/zdtm/static/vdso-proxy.c b/test/zdtm/static/vdso-proxy.c index ecb71e892..2946eb790 100644 --- a/test/zdtm/static/vdso-proxy.c +++ b/test/zdtm/static/vdso-proxy.c @@ -73,13 +73,13 @@ static int parse_maps(struct vm_area *vmas) v->start, v->end); } - if (i == MAX_VMAS) { - pr_err("Number of VMAs is bigger than reserved array's size\n"); + if (fclose(maps)) { + pr_err("Failed to close maps file: %m\n"); return -1; } - if (fclose(maps)) { - pr_err("Failed to close maps file: %m\n"); + if (i == MAX_VMAS) { + pr_err("Number of VMAs is bigger than reserved array's size\n"); return -1; } diff --git a/test/zdtm/transition/lazy-thp.c b/test/zdtm/transition/lazy-thp.c index f7af41446..a0cf33041 100644 --- a/test/zdtm/transition/lazy-thp.c +++ b/test/zdtm/transition/lazy-thp.c @@ -57,5 +57,7 @@ int main(int argc, char ** argv) } pass(); + free(org); + free(mem); return 0; } From 75adf0e6087b8cbba850013db11ecf296a90f3cf Mon Sep 17 00:00:00 2001 From: Uchio Kondo Date: Fri, 1 Mar 2019 18:48:06 +0900 Subject: [PATCH 2086/4375] c-lib: Support to build a static archive Signed-off-by: Uchio Kondo --- lib/Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/Makefile b/lib/Makefile index 94632848e..0c9841071 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,4 +1,5 @@ CRIU_SO := libcriu.so +CRIU_A := libcriu.a UAPI_HEADERS := lib/c/criu.h images/rpc.proto # @@ -19,8 +20,12 @@ ldflags-so += -lprotobuf-c lib/c/$(CRIU_SO): lib/c/built-in.o $(call msg-link, $@) $(Q) $(CC) -shared $(cflags-so) -o $@ $^ $(ldflags-so) $(LDFLAGS) +lib/c/$(CRIU_A): lib/c/built-in.o + $(call msg-link, $@) + $(Q) $(AR) rcs $@ $^ lib-c: lib/c/$(CRIU_SO) -.PHONY: lib-c +lib-a: lib/c/$(CRIU_A) +.PHONY: lib-c lib-a # # Python bindings. From 6adf006b87fbc7f1f714af11452242f915b39890 Mon Sep 17 00:00:00 2001 From: Uchio Kondo Date: Fri, 8 Mar 2019 15:08:32 +0900 Subject: [PATCH 2087/4375] c-lib: Add lib-a into all-y targets Signed-off-by: Uchio Kondo --- lib/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Makefile b/lib/Makefile index 0c9841071..7b95956ab 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -6,7 +6,7 @@ UAPI_HEADERS := lib/c/criu.h images/rpc.proto # File to keep track of files installed by setup.py CRIT_SETUP_FILES := lib/.crit-setup.files -all-y += lib-c lib-py +all-y += lib-c lib-a lib-py # # C language bindings. From a29b348bae98d1f4154782c790e875d789cb3982 Mon Sep 17 00:00:00 2001 From: Uchio Kondo Date: Wed, 29 May 2019 13:48:17 +0900 Subject: [PATCH 2088/4375] Add CRIU_A to cleanup target - This patch is from the comment by Radostin Stoyanov @rst0git Signed-off-by: Uchio Kondo --- lib/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Makefile b/lib/Makefile index 7b95956ab..4a131e88e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -42,7 +42,7 @@ clean-lib: $(Q) $(MAKE) $(build)=lib/py clean .PHONY: clean-lib clean: clean-lib -cleanup-y += lib/c/$(CRIU_SO) lib/c/criu.pc +cleanup-y += lib/c/$(CRIU_SO) lib/c/$(CRIU_A) lib/c/criu.pc mrproper: clean install: lib-c lib-py crit/crit lib/c/criu.pc.in From 6a2cd621cb4195dbeea7a694ffc4beb785892942 Mon Sep 17 00:00:00 2001 From: Uchio Kondo Date: Fri, 7 Jun 2019 17:11:02 +0900 Subject: [PATCH 2089/4375] c-lib: Install and uninstall libcriu.a Signed-off-by: Uchio Kondo --- lib/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Makefile b/lib/Makefile index 4a131e88e..67c50b95a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -45,12 +45,13 @@ clean: clean-lib cleanup-y += lib/c/$(CRIU_SO) lib/c/$(CRIU_A) lib/c/criu.pc mrproper: clean -install: lib-c lib-py crit/crit lib/c/criu.pc.in +install: lib-c lib-a lib-py crit/crit lib/c/criu.pc.in $(E) " INSTALL " lib $(Q) mkdir -p $(DESTDIR)$(LIBDIR) $(Q) install -m 755 lib/c/$(CRIU_SO) $(DESTDIR)$(LIBDIR)/$(CRIU_SO).$(CRIU_SO_VERSION_MAJOR).$(CRIU_SO_VERSION_MINOR) $(Q) ln -fns $(CRIU_SO).$(CRIU_SO_VERSION_MAJOR).$(CRIU_SO_VERSION_MINOR) $(DESTDIR)$(LIBDIR)/$(CRIU_SO).$(CRIU_SO_VERSION_MAJOR) $(Q) ln -fns $(CRIU_SO).$(CRIU_SO_VERSION_MAJOR).$(CRIU_SO_VERSION_MINOR) $(DESTDIR)$(LIBDIR)/$(CRIU_SO) + $(Q) install -m 755 lib/c/$(CRIU_A) $(DESTDIR)$(LIBDIR)/$(CRIU_A) $(Q) mkdir -p $(DESTDIR)$(INCLUDEDIR)/criu/ $(Q) install -m 644 $(UAPI_HEADERS) $(DESTDIR)$(INCLUDEDIR)/criu/ $(E) " INSTALL " pkgconfig/criu.pc @@ -65,6 +66,7 @@ uninstall: $(E) " UNINSTALL" $(CRIU_SO) $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBDIR)/,$(CRIU_SO).$(CRIU_SO_VERSION_MAJOR)) $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBDIR)/,$(CRIU_SO)) + $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBDIR)/,$(CRIU_A)) $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBDIR)/,$(CRIU_SO).$(CRIU_SO_VERSION_MAJOR).$(CRIU_SO_VERSION_MINOR)) $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR)/criu/,$(notdir $(UAPI_HEADERS))) $(E) " UNINSTALL" pkgconfig/criu.pc From ffec56803412afbb3f13d16d57101742e50984c6 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 4 Jun 2019 10:11:28 +0300 Subject: [PATCH 2090/4375] fsnotify: More precious error handling - make sure the alloc_openable is not failed with memory error, so that we should not lookup via irmap - irmap lookup should provide us a copy of the path instead of reference to irmap entry https://github.com/checkpoint-restore/criu/issues/698 Signed-off-by: Cyrill Gorcunov Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/fsnotify.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/criu/fsnotify.c b/criu/fsnotify.c index ed8a67a21..09093c0be 100644 --- a/criu/fsnotify.c +++ b/criu/fsnotify.c @@ -175,7 +175,7 @@ static char *alloc_openable(unsigned int s_dev, unsigned long i_ino, FhEntry *f_ if (st.st_ino == i_ino) { path = xstrdup(buf); if (path == NULL) - goto err; + return ERR_PTR(-ENOMEM); if (root_ns_mask & CLONE_NEWNS) { f_handle->has_mnt_id = true; f_handle->mnt_id = m->mnt_id; @@ -227,8 +227,8 @@ out: int check_open_handle(unsigned int s_dev, unsigned long i_ino, FhEntry *f_handle) { + char *path, *irmap_path; int fd = -1; - char *path; if (fault_injected(FI_CHECK_OPEN_HANDLE)) { fd = -1; @@ -262,6 +262,8 @@ fault: path = alloc_openable(s_dev, i_ino, f_handle); if (!IS_ERR_OR_NULL(path)) goto out; + else if (IS_ERR(path) && PTR_ERR(path) == -ENOMEM) + goto err; if ((mi->fstype->code == FSTYPE__TMPFS) || (mi->fstype->code == FSTYPE__DEVTMPFS)) { @@ -284,11 +286,14 @@ fault: } pr_warn("\tHandle 0x%x:0x%lx cannot be opened\n", s_dev, i_ino); - path = irmap_lookup(s_dev, i_ino); - if (!path) { + irmap_path = irmap_lookup(s_dev, i_ino); + if (!irmap_path) { pr_err("\tCan't dump that handle\n"); return -1; } + path = xstrdup(irmap_path); + if (!path) + goto err; out: pr_debug("\tDumping %s as path for handle\n", path); f_handle->path = path; From b7230b6132b8eefb46da61ac158a99612d15dc10 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 31 Mar 2019 11:43:16 +0100 Subject: [PATCH 2091/4375] make: config -- Link with GnuTLS There are two notable open-source libraries that provide TLS implementation - OpenSSL and GnuTLS. The license of OpenSSL is incompatible with CRIU's license, and threfore GnuTLS is the recommended choice. GnuTLS offers an API to access secure communication protocols. These protocols provide privacy over insecure lines, and are designed to prevent eavesdropping, tampering or message forgery. Signed-off-by: Radostin Stoyanov --- Makefile.config | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Makefile.config b/Makefile.config index 008a82289..6f7324069 100644 --- a/Makefile.config +++ b/Makefile.config @@ -15,6 +15,14 @@ ifeq ($(call pkg-config-check,libselinux),y) FEATURE_DEFINES += -DCONFIG_HAS_SELINUX endif +ifeq ($(NO_GNUTLS)x$(call pkg-config-check,gnutls),xy) + LIBS_FEATURES += -lgnutls + export CONFIG_GNUTLS := y + FEATURE_DEFINES += -DCONFIG_GNUTLS +else + $(info Note: Building without GnuTLS support) +endif + export LIBS += $(LIBS_FEATURES) CONFIG_FILE = .config From 76a41209b0942fcc76508f1bdee7e7119c79f625 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 31 Mar 2019 12:05:22 +0100 Subject: [PATCH 2092/4375] page-xfer: Add TLS support with X509 certificates This commit adds Transport Layer Security (TLS) support for remote page-server connections. The following command-line options are introduced with this commit: --tls-cacert FILE Trust certificates signed only by this CA --tls-cacrl FILE CA certificate revocation list --tls-cert FILE TLS certificate --tls-key FILE TLS private key --tls Use TLS to secure remote connections The default PKI locations are: CA certificate /etc/pki/CA/cacert.pem CA revocation list /etc/pki/CA/cacrl.pem Client/server certificate /etc/pki/criu/cert.pem Client/server private key /etc/pki/criu/private/key.pem The files cacert.pem and cacrl.pem are optional. If they are not present, and not explicitly specified with a command-line option, CRIU will use only the system's trusted CAs to verify the remote peer's identity. This implies that if a CA certificate is specified using "--tls-cacert" only this CA will be used for verification. If CA certificate (cacert.pem) is not present, certificate revocation list (cacrl.pem) will be ignored. Both (client and server) sides require a private key and certificate. When the "--tls" option is specified, a TLS handshake (key exchange) will be performed immediately after the remote TCP connection has been accepted. X.509 certificates can be generated as follows: -------------------------%<------------------------- # Generate CA key and certificate echo -ne "ca\ncert_signing_key" > temp certtool --generate-privkey > cakey.pem certtool --generate-self-signed \ --template temp \ --load-privkey cakey.pem \ --outfile cacert.pem # Generate server key and certificate echo -ne "cn=$HOSTNAME\nencryption_key\nsigning_key" > temp certtool --generate-privkey > key.pem certtool --generate-certificate \ --template temp \ --load-privkey key.pem \ --load-ca-certificate cacert.pem \ --load-ca-privkey cakey.pem \ --outfile cert.pem rm temp mkdir -p /etc/pki/CA mkdir -p /etc/pki/criu/private mv cacert.pem /etc/pki/CA/ mv cert.pem /etc/pki/criu/ mv key.pem /etc/pki/criu/private -------------------------%<------------------------- Usage Example: Page-server: [src]# criu page-server -D --port --tls [dst]# criu dump --page-server --address --port \ -t -D --tls Lazy migration: [src]# criu dump --lazy-pages --port -t -D --tls [dst]# criu lazy-pages --page-server --address --port \ -D --tls [dst]# criu restore -D --lazy-pages Signed-off-by: Radostin Stoyanov --- Documentation/criu.txt | 27 +++ Makefile | 1 + criu/Makefile | 3 +- criu/Makefile.crtools | 1 + criu/config.c | 24 +++ criu/crtools.c | 5 + criu/include/cr_options.h | 5 + criu/include/tls.h | 26 +++ criu/page-xfer.c | 119 +++++++++---- criu/tls.c | 366 ++++++++++++++++++++++++++++++++++++++ criu/uffd.c | 3 + 11 files changed, 546 insertions(+), 34 deletions(-) create mode 100644 criu/include/tls.h create mode 100644 criu/tls.c diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 6111c3baf..94fc5428a 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -594,6 +594,33 @@ Launches *criu* in page server mode. remote *lazy-pages* daemon to request memory pages in random order. +*--tls-cacert* 'file':: + Specifies the path to a trusted Certificate Authority (CA) certificate + file to be used for verification of a client or server certificate. + The 'file' must be in PEM format. When this option is used only the + specified CA is used for verification. Otherwise, the system's trusted CAs + and, if present, '/etc/pki/CA/cacert.pem' will be used. + +*--tls-cacrl* 'file':: + Specifies a path to a Certificate Revocation List (CRL) 'file' which + contains a list of revoked certificates that should no longer be trusted. + The 'file' must be in PEM format. When this option is not specified, the + file, if present, '/etc/pki/CA/cacrl.pem' will be used. + +*--tls-cert* 'file':: + Specifies a path to a file that contains a X.509 certificate to present + to the remote entity. The 'file' must be in PEM format. When this option + is not specified, the default location ('/etc/pki/criu/cert.pem') will be + used. + +*--tls-key* 'file':: + Specifies a path to a file that contains TLS private key. The 'file' must + be in PEM format. When this option is not the default location + ('/etc/pki/criu/private/key.pem') will be used. + +*--tls*:: + Use TLS to secure remote connections. + *lazy-pages* ~~~~~~~~~~~~ Launches *criu* in lazy-pages daemon mode. diff --git a/Makefile b/Makefile index 09cf2406a..9d83862d1 100644 --- a/Makefile +++ b/Makefile @@ -193,6 +193,7 @@ include Makefile.config else # To clean all files, enable make/build options here export CONFIG_COMPAT := y +export CONFIG_GNUTLS := y endif # diff --git a/criu/Makefile b/criu/Makefile index 3de6eb217..4134e5052 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -1,5 +1,5 @@ # here is a workaround for a bug in libnl-3: -# 6a8d90f5fec4 "attr: Allow attribute type 0" +# 6a8d90f5fec4 "attr: Allow attribute type 0" WRAPFLAGS += -Wl,--wrap=nla_parse,--wrap=nlmsg_parse ARCH_DIR := criu/arch/$(SRCARCH) @@ -14,6 +14,7 @@ endif # # Configuration file paths +CONFIG-DEFINES += -DSYSCONFDIR='"/etc"' CONFIG-DEFINES += -DGLOBAL_CONFIG_DIR='"/etc/criu/"' CONFIG-DEFINES += -DDEFAULT_CONFIG_FILENAME='"default.conf"' CONFIG-DEFINES += -DUSER_CONFIG_DIR='".criu/"' diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 383ed1940..4588ea5b8 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -73,6 +73,7 @@ obj-y += string.o obj-y += sysctl.o obj-y += sysfs_parse.o obj-y += timerfd.o +obj-$(CONFIG_GNUTLS) += tls.o obj-y += tty.o obj-y += tun.o obj-y += util.o diff --git a/criu/config.c b/criu/config.c index bcf5176d9..bfdd6c658 100644 --- a/criu/config.c +++ b/criu/config.c @@ -510,6 +510,11 @@ int parse_options(int argc, char **argv, bool *usage_error, { "ps-socket", required_argument, 0, 1091}, { "config", required_argument, 0, 1089}, { "no-default-config", no_argument, 0, 1090}, + { "tls-cacert", required_argument, 0, 1092}, + { "tls-cacrl", required_argument, 0, 1093}, + { "tls-cert", required_argument, 0, 1094}, + { "tls-key", required_argument, 0, 1095}, + BOOL_OPT("tls", &opts.tls), { }, }; @@ -796,6 +801,18 @@ int parse_options(int argc, char **argv, bool *usage_error, case 1091: opts.ps_socket = atoi(optarg); break; + case 1092: + SET_CHAR_OPTS(tls_cacert, optarg); + break; + case 1093: + SET_CHAR_OPTS(tls_cacrl, optarg); + break; + case 1094: + SET_CHAR_OPTS(tls_cert, optarg); + break; + case 1095: + SET_CHAR_OPTS(tls_key, optarg); + break; case 'V': pr_msg("Version: %s\n", CRIU_VERSION); if (strcmp(CRIU_GITID, "0")) @@ -857,6 +874,13 @@ int check_options() } } +#ifndef CONFIG_GNUTLS + if (opts.tls) { + pr_err("CRIU was built without TLS support\n"); + return 1; + } +#endif + if (check_namespace_opts()) { pr_err("Error: namespace flags conflict\n"); return 1; diff --git a/criu/crtools.c b/criu/crtools.c index 6c83b27da..a07df064c 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -427,6 +427,11 @@ usage: " -d|--daemon run in the background after creating socket\n" " --status-fd FD write \\0 to the FD and close it once process is ready\n" " to handle requests\n" +" --tls-cacert FILE trust certificates signed only by this CA\n" +" --tls-cacrl FILE path to CA certificate revocation list file\n" +" --tls-cert FILE path to TLS certificate file\n" +" --tls-key FILE path to TLS private key file\n" +" --tls use TLS to secure remote connection\n" "\n" "Configuration file options:\n" " --config FILEPATH pass a specific configuration file\n" diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index 9f152fac0..fcba278e0 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -138,6 +138,11 @@ struct cr_options { pid_t tree_id; int log_level; char *imgs_dir; + char *tls_cacert; + char *tls_cacrl; + char *tls_cert; + char *tls_key; + int tls; }; extern struct cr_options opts; diff --git a/criu/include/tls.h b/criu/include/tls.h new file mode 100644 index 000000000..aa2517887 --- /dev/null +++ b/criu/include/tls.h @@ -0,0 +1,26 @@ +#ifndef __CR_TLS_H__ +#define __CR_TLS_H__ + +# ifdef CONFIG_GNUTLS + +int tls_x509_init(int sockfd, bool is_server); +void tls_terminate_session(); + +ssize_t tls_send(const void *buf, size_t len, int flags); +ssize_t tls_recv(void *buf, size_t len, int flags); + +int tls_send_data_from_fd(int fd, unsigned long len); +int tls_recv_data_to_fd(int fd, unsigned long len); + +# else /* CONFIG_GNUTLS */ + +#define tls_x509_init(sockfd, is_server) (0) +#define tls_send(buf, len, flags) (-1) +#define tls_recv(buf, len, flags) (-1) +#define tls_send_data_from_fd(fd, len) (-1) +#define tls_recv_data_to_fd(fd, len) (-1) +#define tls_terminate_session() + +#endif /* CONFIG_HAS_GNUTLS */ + +#endif /* __CR_TLS_H__ */ diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 8868ed226..f74716100 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -21,6 +21,7 @@ #include "parasite-syscall.h" #include "rst_info.h" #include "stats.h" +#include "tls.h" static int page_server_sk = -1; @@ -128,13 +129,22 @@ static inline u32 decode_ps_flags(u32 cmd) return cmd >> PS_CMD_BITS; } +static inline int __send(int sk, const void *buf, size_t sz, int fl) +{ + return opts.tls ? tls_send(buf, sz, fl) : send(sk, buf, sz, fl); +} + +static inline int __recv(int sk, void *buf, size_t sz, int fl) +{ + return opts.tls ? tls_recv(buf, sz, fl) : recv(sk, buf, sz, fl); +} + static inline int send_psi_flags(int sk, struct page_server_iov *pi, int flags) { - if (send(sk, pi, sizeof(*pi), flags) != sizeof(*pi)) { + if (__send(sk, pi, sizeof(*pi), flags) != sizeof(*pi)) { pr_perror("Can't send PSI %d to server", pi->cmd); return -1; } - return 0; } @@ -149,17 +159,28 @@ static int write_pages_to_server(struct page_xfer *xfer, { ssize_t ret, left = len; - pr_debug("Splicing %lu bytes / %lu pages into socket\n", len, len / PAGE_SIZE); + if (opts.tls) { + pr_debug("Sending %lu bytes / %lu pages\n", + len, len / PAGE_SIZE); - while (left > 0) { - ret = splice(p, NULL, xfer->sk, NULL, left, SPLICE_F_MOVE); - if (ret < 0) { - pr_perror("Can't write pages to socket"); + if (tls_send_data_from_fd(p, len)) return -1; - } + } else { + pr_debug("Splicing %lu bytes / %lu pages into socket\n", + len, len / PAGE_SIZE); - pr_debug("\tSpliced: %lu bytes sent\n", (unsigned long)ret); - left -= ret; + while (left > 0) { + ret = splice(p, NULL, xfer->sk, NULL, left, + SPLICE_F_MOVE); + if (ret < 0) { + pr_perror("Can't write pages to socket"); + return -1; + } + + pr_debug("\tSpliced: %lu bytes sent\n", + (unsigned long)ret); + left -= ret; + } } return 0; @@ -205,7 +226,7 @@ static int open_page_server_xfer(struct page_xfer *xfer, int fd_type, unsigned l /* Push the command NOW */ tcp_nodelay(xfer->sk, true); - if (read(xfer->sk, &has_parent, 1) != 1) { + if (__recv(xfer->sk, &has_parent, 1, 0) != 1) { pr_perror("The page server doesn't answer"); return -1; } @@ -539,7 +560,7 @@ static int page_server_check_parent(int sk, struct page_server_iov *pi) if (ret < 0) return -1; - if (write(sk, &ret, sizeof(ret)) != sizeof(ret)) { + if (__send(sk, &ret, sizeof(ret), 0) != sizeof(ret)) { pr_perror("Unable to send response"); return -1; } @@ -560,7 +581,7 @@ static int check_parent_server_xfer(int fd_type, unsigned long img_id) tcp_nodelay(page_server_sk, true); - if (read(page_server_sk, &has_parent, sizeof(int)) != sizeof(int)) { + if (__recv(page_server_sk, &has_parent, sizeof(int), 0) != sizeof(int)) { pr_perror("The page server doesn't answer"); return -1; } @@ -624,8 +645,7 @@ static int page_server_open(int sk, struct page_server_iov *pi) if (sk >= 0) { char has_parent = !!cxfer.loc_xfer.parent; - - if (write(sk, &has_parent, 1) != 1) { + if (__send(sk, &has_parent, 1, 0) != 1) { pr_perror("Unable to send response"); close_page_xfer(&cxfer.loc_xfer); return -1; @@ -684,14 +704,23 @@ static int page_server_add(int sk, struct page_server_iov *pi, u32 flags) return -1; } - chunk = splice(sk, NULL, cxfer.p[1], NULL, chunk, SPLICE_F_MOVE | SPLICE_F_NONBLOCK); - if (chunk < 0) { - pr_perror("Can't read from socket"); - return -1; - } - if (chunk == 0) { - pr_err("A socket was closed unexpectedly\n"); - return -1; + if (opts.tls) { + if(tls_recv_data_to_fd(cxfer.p[1], chunk)) { + pr_err("Can't read from socket\n"); + return -1; + } + } else { + chunk = splice(sk, NULL, cxfer.p[1], NULL, chunk, + SPLICE_F_MOVE | SPLICE_F_NONBLOCK); + + if (chunk < 0) { + pr_perror("Can't read from socket"); + return -1; + } + if (chunk == 0) { + pr_err("A socket was closed unexpectedly\n"); + return -1; + } } if (lxfer->write_pages(lxfer, cxfer.p[0], chunk)) @@ -733,9 +762,16 @@ static int page_server_get_pages(int sk, struct page_server_iov *pi) return -1; len = pi->nr_pages * PAGE_SIZE; - ret = splice(pipe_read_dest.p[0], NULL, sk, NULL, len, SPLICE_F_MOVE); - if (ret != len) - return -1; + + if (opts.tls) { + if (tls_send_data_from_fd(pipe_read_dest.p[0], len)) + return -1; + } else { + ret = splice(pipe_read_dest.p[0], NULL, sk, NULL, len, + SPLICE_F_MOVE); + if (ret != len) + return -1; + } tcp_nodelay(sk, true); @@ -773,7 +809,7 @@ static int page_server_serve(int sk) struct page_server_iov pi; u32 cmd; - ret = recv(sk, &pi, sizeof(pi), MSG_WAITALL); + ret = __recv(sk, &pi, sizeof(pi), MSG_WAITALL); if (!ret) break; @@ -823,7 +859,7 @@ static int page_server_serve(int sk) * An answer must be sent back to inform another side, * that all data were received */ - if (write(sk, &status, sizeof(status)) != sizeof(status)) { + if (__send(sk, &status, sizeof(status), 0) != sizeof(status)) { pr_perror("Can't send the final package"); ret = -1; } @@ -856,14 +892,15 @@ static int page_server_serve(int sk) * Wait when a remote side closes the connection * to avoid TIME_WAIT bucket */ - if (read(sk, &c, sizeof(c)) != 0) { pr_perror("Unexpected data"); ret = -1; } } + tls_terminate_session(); page_server_close(); + pr_info("Session over\n"); close(sk); @@ -1011,6 +1048,11 @@ no_server: if (ret != 0) return ret > 0 ? 0 : -1; + if (tls_x509_init(ask, true)) { + close(sk); + return -1; + } + if (ask >= 0) ret = page_server_serve(ask); @@ -1034,6 +1076,11 @@ static int connect_to_page_server(void) page_server_sk = setup_tcp_client(opts.addr); if (page_server_sk == -1) return -1; + + if (tls_x509_init(page_server_sk, false)) { + close(page_server_sk); + return -1; + } out: /* * CORK the socket at the very beginning. As per ANK @@ -1076,14 +1123,16 @@ int disconnect_from_page_server(void) if (send_psi(page_server_sk, &pi)) goto out; - if (read(page_server_sk, &status, sizeof(status)) != sizeof(status)) { + if (__recv(page_server_sk, &status, sizeof(status), 0) != sizeof(status)) { pr_perror("The page server doesn't answer"); goto out; } ret = 0; out: + tls_terminate_session(); close_safe(&page_server_sk); + return ret ? : status; } @@ -1160,10 +1209,14 @@ static int page_server_read(struct ps_async_read *ar, int flags) need = ar->goal - ar->rb; } - ret = recv(page_server_sk, buf, need, flags); + ret = __recv(page_server_sk, buf, need, flags); if (ret < 0) { - pr_perror("Error reading async data from page server"); - return -1; + if (flags == MSG_DONTWAIT && (errno == EAGAIN || errno == EINTR)) { + ret = 0; + } else { + pr_perror("Error reading data from page server"); + return -1; + } } ar->rb += ret; diff --git a/criu/tls.c b/criu/tls.c new file mode 100644 index 000000000..a6bf25db4 --- /dev/null +++ b/criu/tls.c @@ -0,0 +1,366 @@ +#include +#include +#include +#include + +#include + +#include "cr_options.h" +#include "xmalloc.h" + +/* Compatability with GnuTLS verson <3.5 */ +#ifndef GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR +# define GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR GNUTLS_E_CERTIFICATE_ERROR +#endif + +#undef LOG_PREFIX +#define LOG_PREFIX "tls: " + +#define CRIU_PKI_DIR SYSCONFDIR "/pki" +#define CRIU_CACERT CRIU_PKI_DIR "/CA/cacert.pem" +#define CRIU_CACRL CRIU_PKI_DIR "/CA/cacrl.pem" +#define CRIU_CERT CRIU_PKI_DIR "/criu/cert.pem" +#define CRIU_KEY CRIU_PKI_DIR "/criu/private/key.pem" + +#define SPLICE_BUF_SZ_MAX (PIPE_BUF * 100) + +#define tls_perror(msg, ret) pr_err("%s: %s\n", msg, gnutls_strerror(ret)) + +static gnutls_session_t session; +static gnutls_certificate_credentials_t x509_cred; +static int tls_sk = -1; +static int tls_sk_flags = 0; + +void tls_terminate_session() +{ + int ret; + + if (!opts.tls) + return; + + if (session) { + do { + /* don't wait for peer to close connection */ + ret = gnutls_bye(session, GNUTLS_SHUT_WR); + } while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); + gnutls_deinit(session); + } + + tls_sk = -1; + if (x509_cred) + gnutls_certificate_free_credentials(x509_cred); +} + +ssize_t tls_send(const void *buf, size_t len, int flags) +{ + int ret; + + tls_sk_flags = flags; + ret = gnutls_record_send(session, buf, len); + tls_sk_flags = 0; + + if (ret < 0) { + switch(ret) { + case GNUTLS_E_AGAIN: + errno = EAGAIN; + break; + case GNUTLS_E_INTERRUPTED: + errno = EINTR; + break; + case GNUTLS_E_UNEXPECTED_PACKET_LENGTH: + errno = ENOMSG; + break; + default: + tls_perror("Failed to send data", ret); + errno = EIO; + break; + } + } + + return ret; +} + +/* + * Read data from a file descriptor, then encrypt and send it with GnuTLS. + * This function is used for cases when we would otherwise use splice() + * to transfer data from PIPE to TCP socket. + */ +int tls_send_data_from_fd(int fd, unsigned long len) +{ + ssize_t copied; + unsigned long buf_size = min(len, (unsigned long)SPLICE_BUF_SZ_MAX); + void *buf = xmalloc(buf_size); + + if (!buf) + return -1; + + while (len > 0) { + int ret, sent; + + copied = read(fd, buf, min(len, buf_size)); + if (copied <= 0) { + pr_perror("Can't read from pipe"); + goto err; + } + + for(sent = 0; sent < copied; sent += ret) { + ret = tls_send((buf + sent), (copied - sent), 0); + if (ret < 0) { + tls_perror("Failed sending data", ret); + goto err; + } + } + len -= copied; + } +err: + xfree(buf); + return (len > 0); +} + +ssize_t tls_recv(void *buf, size_t len, int flags) +{ + int ret; + + tls_sk_flags = flags; + ret = gnutls_record_recv(session, buf, len); + tls_sk_flags = 0; + + /* Check if there are any data to receive in the gnutls buffers. */ + if (flags == MSG_DONTWAIT + && (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)) { + size_t pending = gnutls_record_check_pending(session); + if (pending > 0) { + pr_debug("Receiving pending data (%zu bytes)\n", pending); + ret = gnutls_record_recv(session, buf, len); + } + } + + if (ret < 0) { + switch (ret) { + case GNUTLS_E_AGAIN: + errno = EAGAIN; + break; + case GNUTLS_E_INTERRUPTED: + errno = EINTR; + break; + default: + tls_perror("Failed receiving data", ret); + errno = EIO; + break; + } + ret = -1; + } + + return ret; +} + +/* + * Read and decrypt data with GnuTLS, then write it to a file descriptor. + * This function is used for cases when we would otherwise use splice() + * to transfer data from a TCP socket to a PIPE. + */ +int tls_recv_data_to_fd(int fd, unsigned long len) +{ + gnutls_packet_t packet; + + while (len > 0) { + int ret, w; + gnutls_datum_t pdata; + + ret = gnutls_record_recv_packet(session, &packet); + if (ret == 0) { + pr_info("Connection closed by peer\n"); + break; + } else if (ret < 0) { + tls_perror("Received corrupted data", ret); + break; + } + + gnutls_packet_get(packet, &pdata, NULL); + for(w = 0; w < pdata.size; w += ret) { + ret = write(fd, (pdata.data + w), (pdata.size - w)); + if (ret < 0) { + pr_perror("Failed writing to fd"); + goto err; + } + } + len -= pdata.size; + } +err: + gnutls_packet_deinit(packet); + return (len > 0); +} + +static inline void tls_handshake_verification_status_print(int ret, unsigned status) +{ + gnutls_datum_t out; + int type = gnutls_certificate_type_get(session); + + if (!gnutls_certificate_verification_status_print(status, type, &out, 0)) + pr_err("%s\n", out.data); + + gnutls_free(out.data); +} + +static int tls_x509_verify_peer_cert(void) +{ + int ret; + unsigned status; + + ret = gnutls_certificate_verify_peers3(session, opts.addr, &status); + if (ret != GNUTLS_E_SUCCESS) { + tls_perror("Unable to verify TLS peer", ret); + return -1; + } + + if (status != 0) { + pr_err("Invalid certificate\n"); + tls_handshake_verification_status_print( + GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR, status); + return -1; + } + + return 0; +} + +static int tls_handshake() +{ + int ret = -1; + while (ret != GNUTLS_E_SUCCESS) { + ret = gnutls_handshake(session); + if (gnutls_error_is_fatal(ret)) { + tls_perror("TLS handshake failed", ret); + return -1; + } + } + pr_info("TLS handshake completed\n"); + return 0; +} + +static int tls_x509_setup_creds() +{ + int ret; + char *cacert = CRIU_CACERT; + char *cacrl = CRIU_CACRL; + char *cert = CRIU_CERT; + char *key = CRIU_KEY; + gnutls_x509_crt_fmt_t pem = GNUTLS_X509_FMT_PEM; + + if (opts.tls_cacert) + cacert = opts.tls_cacert; + if (opts.tls_cacrl) + cacrl = opts.tls_cacrl; + if (opts.tls_cert) + cert = opts.tls_cert; + if (opts.tls_key) + key = opts.tls_key; + + ret = gnutls_certificate_allocate_credentials(&x509_cred); + if (ret != GNUTLS_E_SUCCESS) { + tls_perror("Failed to allocate x509 credentials", ret); + return -1; + } + + if (!opts.tls_cacert) { + ret = gnutls_certificate_set_x509_system_trust(x509_cred); + if (ret < 0) { + tls_perror("Failed to load default trusted CAs", ret); + return -1; + } + } + + ret = gnutls_certificate_set_x509_trust_file(x509_cred, cacert, pem); + if (ret == 0) { + pr_info("No trusted CA certificates added (%s)\n", cacert); + if (opts.tls_cacert) + return -1; + } + + if (!access(cacrl, R_OK)) { + ret = gnutls_certificate_set_x509_crl_file(x509_cred, cacrl, pem); + if (ret < 0) { + tls_perror("Can't set certificate revocation list", ret); + return -1; + } + } else if (opts.tls_cacrl) { + pr_perror("Can't read certificate revocation list %s", cacrl); + return -1; + } + + ret = gnutls_certificate_set_x509_key_file(x509_cred, cert, key, pem); + if (ret != GNUTLS_E_SUCCESS) { + tls_perror("Failed to set certificate/private key pair", ret); + return -1; + } + + return 0; +} + +static ssize_t _tls_push_cb(void *p, const void* data, size_t sz) +{ + int fd = *(int *)(p); + return send(fd, data, sz, tls_sk_flags); +} + +static ssize_t _tls_pull_cb(void *p, void* data, size_t sz) +{ + int fd = *(int *)(p); + return recv(fd, data, sz, tls_sk_flags); +} + +static int tls_x509_setup_session(unsigned int flags) +{ + int ret; + + ret = gnutls_init(&session, flags); + if (ret != GNUTLS_E_SUCCESS) { + tls_perror("Failed to initialize session", ret); + return -1; + } + + ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); + if (ret != GNUTLS_E_SUCCESS) { + tls_perror("Failed to set session credentials", ret); + return -1; + } + + ret = gnutls_set_default_priority(session); + if (ret != GNUTLS_E_SUCCESS) { + tls_perror("Failed to set priority", ret); + return -1; + } + + gnutls_transport_set_ptr(session, &tls_sk); + gnutls_transport_set_push_function(session, _tls_push_cb); + gnutls_transport_set_pull_function(session, _tls_pull_cb); + + if (flags == GNUTLS_SERVER) { + /* Require client certificate */ + gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUIRE); + /* Do not advertise trusted CAs to the client */ + gnutls_certificate_send_x509_rdn_sequence(session, 1); + } + + return 0; +} + +int tls_x509_init(int sockfd, bool is_server) +{ + if (!opts.tls) + return 0; + + tls_sk = sockfd; + if (tls_x509_setup_creds()) + goto err; + if (tls_x509_setup_session(is_server ? GNUTLS_SERVER : GNUTLS_CLIENT)) + goto err; + if (tls_handshake()) + goto err; + if (tls_x509_verify_peer_cert()) + goto err; + + return 0; +err: + tls_terminate_session(); + return -1; +} diff --git a/criu/uffd.c b/criu/uffd.c index 6699cb14a..5c1e32184 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -37,6 +37,7 @@ #include "page-xfer.h" #include "common/lock.h" #include "rst-malloc.h" +#include "tls.h" #include "fdstore.h" #include "util.h" @@ -1469,5 +1470,7 @@ int cr_lazy_pages(bool daemon) ret = handle_requests(epollfd, events, nr_fds); + tls_terminate_session(); + return ret; } From d4b4a6e6c3eb507b600dabcc9910103f2ab11d29 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 6 May 2019 14:12:36 +0100 Subject: [PATCH 2093/4375] tls: Add --tls-no-cn-verify option By default, CRIU will verify the certificate of a server (with gnutls_certificate_verify_peers3()) by providing the value specified with "--address" as a hostname. As part of the verification process, this value will be compared against the common name (CN) included in the TLS certificate of the server. If the CN doesn't match the TLS handshake will be terminated and CRIU will exit with an error. Although, this is an important feature that is used to mitigate MITM attacks, a user might need to disable such hostname verification for a particular use case or testing purposes. For instance, this option is needed when the common name included in the certificate corresponds to the server's domain name and an IP address is being used to establish connection. Signed-off-by: Radostin Stoyanov --- criu/config.c | 1 + criu/crtools.c | 1 + criu/include/cr_options.h | 1 + criu/tls.c | 6 +++++- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/criu/config.c b/criu/config.c index bfdd6c658..39aa071c9 100644 --- a/criu/config.c +++ b/criu/config.c @@ -515,6 +515,7 @@ int parse_options(int argc, char **argv, bool *usage_error, { "tls-cert", required_argument, 0, 1094}, { "tls-key", required_argument, 0, 1095}, BOOL_OPT("tls", &opts.tls), + {"tls-no-cn-verify", no_argument, &opts.tls_no_cn_verify, true}, { }, }; diff --git a/criu/crtools.c b/criu/crtools.c index a07df064c..a94875684 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -432,6 +432,7 @@ usage: " --tls-cert FILE path to TLS certificate file\n" " --tls-key FILE path to TLS private key file\n" " --tls use TLS to secure remote connection\n" +" --tls-no-cn-verify do not verify common name in server certificate\n" "\n" "Configuration file options:\n" " --config FILEPATH pass a specific configuration file\n" diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index fcba278e0..82f76ad94 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -143,6 +143,7 @@ struct cr_options { char *tls_cert; char *tls_key; int tls; + int tls_no_cn_verify; }; extern struct cr_options opts; diff --git a/criu/tls.c b/criu/tls.c index a6bf25db4..db9cc4f5a 100644 --- a/criu/tls.c +++ b/criu/tls.c @@ -206,8 +206,12 @@ static int tls_x509_verify_peer_cert(void) { int ret; unsigned status; + const char *hostname = NULL; - ret = gnutls_certificate_verify_peers3(session, opts.addr, &status); + if (!opts.tls_no_cn_verify) + hostname = opts.addr; + + ret = gnutls_certificate_verify_peers3(session, hostname, &status); if (ret != GNUTLS_E_SUCCESS) { tls_perror("Unable to verify TLS peer", ret); return -1; From 43842046984701db42286ebcd96f0270a063044f Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 4 Apr 2019 00:44:22 +0100 Subject: [PATCH 2094/4375] rpc: Add support for TLS options Signed-off-by: Radostin Stoyanov --- criu/cr-service.c | 13 +++++++++++++ images/rpc.proto | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/criu/cr-service.c b/criu/cr-service.c index cb76de4f4..0938db02b 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -608,6 +608,19 @@ static int setup_opts_from_req(int sk, CriuOpts *req) goto err; } + if (req->tls_cacert) + SET_CHAR_OPTS(tls_cacert, req->tls_cacert); + if (req->tls_cacrl) + SET_CHAR_OPTS(tls_cacrl, req->tls_cacrl); + if (req->tls_cert) + SET_CHAR_OPTS(tls_cert, req->tls_cert); + if (req->tls_key) + SET_CHAR_OPTS(tls_key, req->tls_key); + if (req->tls) + opts.tls = req->tls; + if (req->tls_no_cn_verify) + opts.tls_no_cn_verify = req->tls_no_cn_verify; + if (req->has_auto_ext_mnt) opts.autodetect_ext_mounts = req->auto_ext_mnt; diff --git a/images/rpc.proto b/images/rpc.proto index 16c5d5028..15e677a77 100644 --- a/images/rpc.proto +++ b/images/rpc.proto @@ -114,6 +114,12 @@ message criu_opts { optional string config_file = 51; optional bool tcp_close = 52; optional string lsm_profile = 53; + optional string tls_cacert = 54; + optional string tls_cacrl = 55; + optional string tls_cert = 56; + optional string tls_key = 57; + optional bool tls = 58; + optional bool tls_no_cn_verify = 59; /* optional bool check_mounts = 128; */ } From b12d4f275850f4f9d65a961028cb50e355985fcf Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 8 May 2019 21:09:33 +0100 Subject: [PATCH 2095/4375] zdtm: Add --tls option Signed-off-by: Radostin Stoyanov --- test/pki/cacert.pem | 23 ++++++ test/pki/cert.pem | 24 ++++++ test/pki/key.pem | 182 ++++++++++++++++++++++++++++++++++++++++++++ test/zdtm.py | 23 ++++-- 4 files changed, 246 insertions(+), 6 deletions(-) create mode 100644 test/pki/cacert.pem create mode 100644 test/pki/cert.pem create mode 100644 test/pki/key.pem diff --git a/test/pki/cacert.pem b/test/pki/cacert.pem new file mode 100644 index 000000000..2f8706616 --- /dev/null +++ b/test/pki/cacert.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID0TCCAjmgAwIBAgIUWzgmx9p7y7mkrNptGX9+0acjpa4wDQYJKoZIhvcNAQEL +BQAwADAeFw0xOTA1MDYxMjAzMDJaFw0yMDA1MDUxMjAzMDJaMAAwggGiMA0GCSqG +SIb3DQEBAQUAA4IBjwAwggGKAoIBgQD0p0lJUlq917GmJuCBeP2eLNd1/MUg1ojy +s7rrpinPYtLZqqquUhp32lfQtt3uJLjkhTrseZd86zWi3SMZlGs8zGGmKfqg0vaG +BXIgpEIr5C0wU9995kL9A6LS+eFZR6vJQETO5T22tjponoqEPOXeU8VaiC9jNipC +uFJT0wyC0bKIo+TUn573kxsGMt8jMOv0tc/okUlH16UAsYrmN7kWzgkWTJPddB7S +v5a9ibpPkbh+wrIGK5A6V5hTZ8U1wz2bE6/Xp+qjsD2R3jeU6f1tDvc8FZilabQy +Rmbxggucl1G3Ulo6Nvor1lhog72eZlHZujzf/5e/aMiZ7Br6plZ1/WTwtNgoCw6A +rgpLDraasQohiK6opYs2rr7uuiQxPLLVWE/RryXwUEoPXzxaf782XtXxkB0UhGvz +y2JBxCVPn7uUGuyEYywjTjI2UFvsMcXnMiQ4WaAfMbAmrBWM7EQ4b7VpD2c+OZkQ +J/AJeg85/ovTAtHPjhPP+0a9hnirktkCAwEAAaNDMEEwDwYDVR0TAQH/BAUwAwEB +/zAPBgNVHQ8BAf8EBQMDBwQAMB0GA1UdDgQWBBQOg6AA8Qu/m/O/II5spzYsTnsn +pjANBgkqhkiG9w0BAQsFAAOCAYEA1KKtw+ILKOg1AhGwgPsJXAWZoSIt7hdLaJ3P +WGyTWHLKKoJiGlLj3bSsJcMmMO+UwHBH9lmXrOWe/xcOvob2H+7dXbddQ0pX1wzK +KJKzSG35FZ2BfuSn5oEDtRsHnN2Ikc5MYz1a+F4w2tVL/Hcxld+oSAodDlCbGoe+ +0MkI5f1KhdAw00l/5IO7xPOcThjHw+nB5/cZTQ+l4zLWCWaXkor4IAEq/plPcdX1 +uoLSj3JruLz7/ts/EgG+ARAzXQrJ+LM2hdPB1NiaVxFq7MSWM6FybUdmMYgbP5s4 +RMNqI/M+bU9K5LRySDaiPhDXUoVULuqG1a23GQwXLOjF0JbrUQewfAaTO7TaPFh1 +lr25j9Fc9/gcXZjvLl+CEIv6P/haGOwySCTCks0F5bDehbLjZStPmugcnJflXdBn +lzoejlw2rePojQMlffQsaRGmmhj0beU4WQBfGACcZQB8GFNxQB8aynf0CK7Dvvb0 +9c9y4k0gHL7RxeLoQfq+smzKm+Eo +-----END CERTIFICATE----- diff --git a/test/pki/cert.pem b/test/pki/cert.pem new file mode 100644 index 000000000..a0946ee41 --- /dev/null +++ b/test/pki/cert.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEAzCCAmugAwIBAgIUKV6zLC//OJDnmOYBuIG1Gvmv+V4wDQYJKoZIhvcNAQEL +BQAwADAeFw0xOTA1MDYxMjAzMDJaFw0yMDA1MDUxMjAzMDJaMBQxEjAQBgNVBAMT +CWxvY2FsaG9zdDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBANX1nv4J +U8+TEb2bWej5O2nOowpw2zSYTDAQ1oyAvV3P99Y6GZCuVZ1uT/7DWat0uRpcdmNi +HvownkO4VmDZdVqgiK1eHzY5YBJ7hBVDs3tpWNuN7eJPjnskNmJqKQ6l9rxYl/au +781T+tdtHp1ATtToMgVJxWaUx5lrpEJdmYc8Y6GpAA42D+rI3o4Sll3mI5rPCk16 +QY5dT2lnL2HuCKzM2bjWat6b3lMpfNz3A/blU9E/462Zxr/yKK/0yy3SBZhYzrrQ +1/erjIpm4I0sakHIOexM1AQliFiowFzVvr/paiXApWGOcuBJVIbmPI/bEGuTh0nr +3pmiF0YrkDCRhargElYcz64KQ9IxPFCKcKjkMnFPjTStZ7rcMyqKvGczqFaM5a6c +9gIn2ieUrVZ38yvtI5Lo/uxZ5IjXqB1Fdg4xi2tyf9WMHKy2tydBr9bTjfQRXfNT +/Zm3woDXOYsHzj+Sf6ntLVCkO1fnczw03fPRV03/uVRa5mPGyyj9xdPBqwIDAQAB +o2EwXzAMBgNVHRMBAf8EAjAAMA8GA1UdDwEB/wQFAwMHoAAwHQYDVR0OBBYEFEtF +ELehnIjLzoh/W51TGm2B00QAMB8GA1UdIwQYMBaAFA6DoADxC7+b878gjmynNixO +eyemMA0GCSqGSIb3DQEBCwUAA4IBgQA17NZCaiCgD9P4GPWgdVNkWUrmc8itJuIB +z3c9RdJGduxb9W/D7IW//D3hIblOPorNi3+08kO/IRMGah874MDCprMNppk94WGj +Kgqi/rsxq+rT6bcZXxMrcOIg0j2EvTPIgPh7trd8nHVWxNT/hvFClDtBJ2ssL2Tz +76EA7smDCUsfdzFJ2Xvk95fSTL49nfT2j9N/YoLaBQtCIxWAVZHKiCF2K+yXufHz +B/9UlXwsPJfqxM75dYWXFEqvhNf08YRHT1e1GRrybNGrNKF864KbLsnASdK4N5wu +sK9vZJ7VkLDQz+YpZkbm+UgOYK/BY3M8IX+F+WngV+43fr6Wh89TSgD7acEBvQTm +q1y9FipRvz0my7fwBh6UlYDja6/3yw6/YfN7uMFGsOOSgpNDCrMLqesf8l1HdQUF +VaVJyDjgFswV9KykAeJK2KU8QI7TGHv9soW60sr97DgUtCh4a6OPXLt79Ji3RSNw +MbU54JnpnfmMAj/0suDymdrJWv8EJKc= +-----END CERTIFICATE----- diff --git a/test/pki/key.pem b/test/pki/key.pem new file mode 100644 index 000000000..eda1aa761 --- /dev/null +++ b/test/pki/key.pem @@ -0,0 +1,182 @@ +Public Key Info: + Public Key Algorithm: RSA + Key Security Level: High (3072 bits) + +modulus: + 00:d5:f5:9e:fe:09:53:cf:93:11:bd:9b:59:e8:f9:3b + 69:ce:a3:0a:70:db:34:98:4c:30:10:d6:8c:80:bd:5d + cf:f7:d6:3a:19:90:ae:55:9d:6e:4f:fe:c3:59:ab:74 + b9:1a:5c:76:63:62:1e:fa:30:9e:43:b8:56:60:d9:75 + 5a:a0:88:ad:5e:1f:36:39:60:12:7b:84:15:43:b3:7b + 69:58:db:8d:ed:e2:4f:8e:7b:24:36:62:6a:29:0e:a5 + f6:bc:58:97:f6:ae:ef:cd:53:fa:d7:6d:1e:9d:40:4e + d4:e8:32:05:49:c5:66:94:c7:99:6b:a4:42:5d:99:87 + 3c:63:a1:a9:00:0e:36:0f:ea:c8:de:8e:12:96:5d:e6 + 23:9a:cf:0a:4d:7a:41:8e:5d:4f:69:67:2f:61:ee:08 + ac:cc:d9:b8:d6:6a:de:9b:de:53:29:7c:dc:f7:03:f6 + e5:53:d1:3f:e3:ad:99:c6:bf:f2:28:af:f4:cb:2d:d2 + 05:98:58:ce:ba:d0:d7:f7:ab:8c:8a:66:e0:8d:2c:6a + 41:c8:39:ec:4c:d4:04:25:88:58:a8:c0:5c:d5:be:bf + e9:6a:25:c0:a5:61:8e:72:e0:49:54:86:e6:3c:8f:db + 10:6b:93:87:49:eb:de:99:a2:17:46:2b:90:30:91:85 + aa:e0:12:56:1c:cf:ae:0a:43:d2:31:3c:50:8a:70:a8 + e4:32:71:4f:8d:34:ad:67:ba:dc:33:2a:8a:bc:67:33 + a8:56:8c:e5:ae:9c:f6:02:27:da:27:94:ad:56:77:f3 + 2b:ed:23:92:e8:fe:ec:59:e4:88:d7:a8:1d:45:76:0e + 31:8b:6b:72:7f:d5:8c:1c:ac:b6:b7:27:41:af:d6:d3 + 8d:f4:11:5d:f3:53:fd:99:b7:c2:80:d7:39:8b:07:ce + 3f:92:7f:a9:ed:2d:50:a4:3b:57:e7:73:3c:34:dd:f3 + d1:57:4d:ff:b9:54:5a:e6:63:c6:cb:28:fd:c5:d3:c1 + ab: + +public exponent: + 01:00:01: + +private exponent: + 1e:38:b0:79:7f:85:c8:17:24:f5:5c:41:29:e8:32:5d + 32:a3:d2:f0:b7:f5:c8:e1:52:14:be:c9:5f:d1:df:b3 + 65:75:6c:05:7a:6b:35:8a:a4:2f:46:73:ff:71:79:6e + 3f:eb:f9:88:f6:2e:1b:f6:cc:14:12:b0:98:c3:7e:91 + 0b:85:e2:bf:1d:b7:82:09:30:f3:23:68:01:85:13:94 + 80:c9:9a:55:94:96:da:30:48:a0:29:ec:86:da:1b:d5 + 2b:2b:74:63:92:b8:2a:8f:87:29:f0:ae:d7:55:63:0d + 2d:b3:0b:0e:2d:84:dc:d5:08:b5:ac:a0:f7:29:9d:71 + 89:3d:27:6a:eb:96:f5:4e:9b:8a:dc:14:82:0a:c7:5c + 16:1c:d2:7e:b9:1b:13:69:d8:b2:b1:b1:7e:aa:a9:ad + 06:ce:66:0e:5b:50:10:42:2a:0a:fd:29:14:f7:09:63 + c1:20:18:5f:27:81:46:12:8c:b8:f4:89:a6:3d:55:a1 + d4:64:fc:f2:db:d7:9c:f5:be:f7:9d:88:5c:6d:36:a4 + 4b:ea:c5:e3:ea:32:81:6b:f3:47:b5:35:d5:c4:1a:b2 + ae:12:9d:19:a3:ec:a4:af:41:7e:5e:34:9d:f5:bc:b9 + 1f:a3:c2:32:b4:fc:95:a7:7a:54:04:e2:d6:4e:10:2f + 66:68:8b:3b:20:ea:05:db:2e:72:01:11:e7:7c:f8:72 + 0f:60:be:f1:27:19:ad:3a:6f:e9:70:56:3a:86:6e:46 + 0d:e3:55:31:66:77:09:84:48:b9:25:4b:c3:26:70:12 + ca:a4:5f:c6:3d:6a:e5:db:4d:63:04:b8:09:07:c9:30 + 85:08:9d:77:40:26:60:da:10:c2:53:d2:00:0d:9e:d9 + d5:71:06:30:eb:fb:f7:3f:82:1f:b3:9a:f3:4d:24:86 + 2e:94:fd:06:9e:dc:26:68:fa:64:c3:f9:fa:08:c4:b2 + ec:7a:f5:55:c5:10:b5:e2:2d:de:ba:04:30:10:5b:99 + + +prime1: + 00:fb:d1:47:9d:9e:73:f8:1e:09:21:fd:89:16:05:56 + af:a5:cf:52:d5:cd:f7:26:18:d1:84:3a:36:65:0b:a2 + cd:f9:b8:99:c0:c7:ef:00:c9:2f:c9:92:1a:1d:3d:86 + 58:3b:b1:be:d4:8c:c6:1b:df:ba:ee:87:aa:d1:22:47 + 18:bd:de:01:0f:0d:cb:ac:d0:48:a4:f4:93:e2:a6:cb + b5:b7:f5:f5:72:dd:ec:ac:13:e8:3d:62:23:54:ac:52 + ff:ee:9a:e1:7f:b0:ae:3b:41:38:d8:39:2b:40:ef:25 + 81:50:b0:98:db:f8:40:16:6e:1a:41:79:22:90:58:99 + 80:c2:0d:ba:b5:d3:54:ec:28:33:e4:b0:58:ea:de:61 + a1:b7:30:0b:9d:dc:73:62:c2:07:d3:75:91:48:49:dd + be:cf:b2:90:95:8f:29:6c:6f:f6:68:cb:cf:d5:24:a3 + d7:37:81:1b:34:3b:af:9a:48:52:af:53:7c:f7:32:a2 + 3f: + +prime2: + 00:d9:83:5e:be:0a:ea:0b:d9:66:63:56:3b:9e:44:aa + 46:6d:8d:6c:10:81:4b:de:19:5d:2c:16:7e:30:7c:ad + 23:9a:89:53:cc:18:e8:e8:51:2b:79:35:d0:67:7d:9e + 8f:be:ea:63:5e:14:c0:6b:ba:02:6c:4a:da:07:70:9d + 14:fa:be:1e:40:47:50:6f:f2:5a:87:9e:b6:b1:b8:55 + 2c:b6:a2:e3:b0:24:ba:ea:9b:55:87:8b:4b:cf:40:4a + 25:b4:89:cf:9e:76:ca:79:4a:f4:74:b7:ee:cf:6c:8f + cb:e3:3d:9e:86:3b:44:b7:70:ec:05:0c:68:ce:d6:c3 + a2:ec:e6:11:d6:2f:f7:80:26:a9:5c:aa:b9:a6:33:84 + a9:00:43:cf:72:07:8a:91:59:a2:b1:de:79:07:6b:81 + 67:a5:c2:4b:fd:29:8a:1a:96:66:57:66:d4:37:9a:98 + 69:d1:19:24:53:b1:a4:54:68:1e:8c:2b:b4:93:19:ed + 95: + +coefficient: + 00:90:9a:7f:6f:14:a8:bc:79:3f:25:e5:62:f9:5d:29 + 78:a4:78:8e:7a:e4:8a:62:8a:7f:9c:ae:75:95:fe:ee + 1a:99:53:40:01:76:29:7d:48:85:28:a2:2a:9f:0f:10 + 8c:19:6a:36:6b:e1:ac:a2:07:b9:72:5c:b9:a6:20:bb + 8f:cb:f5:ea:dd:3f:0e:ab:9d:c1:57:7e:7b:96:f9:da + b0:52:3c:3f:62:94:e7:5c:04:9e:ac:60:cd:4d:ec:7e + 68:d3:fb:2a:b4:02:f0:0e:be:37:bc:2a:f8:6e:8d:31 + b5:38:67:00:9e:67:9f:71:d0:88:36:32:69:4b:20:73 + eb:a1:d9:bc:72:c2:7e:39:1a:36:cc:c1:45:a2:14:37 + e6:ca:db:4d:0b:5b:68:a4:ff:b7:7b:b1:db:2f:70:27 + a1:6c:31:3f:c0:c3:23:04:b0:7a:e2:0d:21:ba:5a:80 + 52:c1:a1:2b:57:72:20:b6:ed:b1:e8:3b:95:88:81:90 + 5d: + +exp1: + 00:ef:ce:66:20:01:44:b9:35:89:46:f8:56:33:45:54 + 3f:23:6d:23:9a:7e:71:6d:b3:56:db:50:40:7a:cb:b0 + f7:ec:67:52:ec:96:b9:d1:8a:c6:5a:74:2b:30:4b:66 + 03:e2:9d:2b:78:e8:b2:c4:da:b3:fe:f1:ed:c7:09:98 + a1:44:37:05:d5:1b:33:2a:58:93:c5:9b:30:b6:38:57 + 68:af:4e:a8:b7:02:06:9f:fc:b9:3e:b3:95:a7:ce:0f + a0:b0:ce:88:0e:7c:e7:ff:7f:e6:2d:6b:8b:f8:63:85 + d8:f7:49:a5:d8:5d:3a:52:e1:f9:58:fe:8d:de:de:b1 + 18:40:34:a8:e8:fc:df:33:a2:39:81:00:3b:3d:38:17 + cb:d4:53:09:cd:04:a2:51:9b:2b:ae:c1:98:60:3a:0f + d4:e5:a0:4c:36:51:46:86:80:bd:2d:21:62:c3:bd:07 + d6:2d:82:62:b0:c4:62:3f:4f:be:86:3e:c0:93:fc:81 + 2b: + +exp2: + 11:e4:73:93:b0:74:26:3b:60:e7:c4:fd:2c:7c:bb:81 + 05:9b:ff:8a:b0:08:1c:a1:fb:7f:17:ee:93:70:7e:11 + 92:b1:bf:39:e7:c6:a8:ed:9c:64:e1:1f:5e:93:ff:ca + 15:4b:54:97:35:9f:ca:7c:c7:9c:3e:e0:06:82:a5:f9 + 46:d3:02:cc:08:d1:be:13:b2:8c:bb:6a:8d:dd:fa:eb + ad:ae:62:8a:67:cb:14:67:68:b6:b8:a7:a8:c9:c2:0f + ad:f5:34:25:f5:e1:9b:ee:a5:83:40:6a:1d:97:f1:90 + 35:06:29:97:23:22:f8:f0:0a:0a:34:46:1e:d5:9d:cc + 36:2e:8a:c3:12:b9:0a:4a:a3:dd:e2:91:58:f1:9d:f5 + 04:f7:8f:05:f3:46:db:c4:02:d5:1c:d6:d9:dc:67:0d + ae:9d:f8:00:40:3d:83:08:62:2c:c8:61:a6:9d:49:f2 + 52:67:fe:0c:00:6d:e3:1f:99:7b:b0:50:af:55:0f:ad + + + +Public Key PIN: + pin-sha256:EiqPFBPoLKkCzVlK8KoKYGQT/LSo7/0iLg/I7nKt1/0= +Public Key ID: + sha256:122a8f1413e82ca902cd594af0aa0a606413fcb4a8effd222e0fc8ee72add7fd + sha1:4b4510b7a19c88cbce887f5b9d531a6d81d34400 + +-----BEGIN RSA PRIVATE KEY----- +MIIG5AIBAAKCAYEA1fWe/glTz5MRvZtZ6Pk7ac6jCnDbNJhMMBDWjIC9Xc/31joZ +kK5VnW5P/sNZq3S5Glx2Y2Ie+jCeQ7hWYNl1WqCIrV4fNjlgEnuEFUOze2lY243t +4k+OeyQ2YmopDqX2vFiX9q7vzVP6120enUBO1OgyBUnFZpTHmWukQl2ZhzxjoakA +DjYP6sjejhKWXeYjms8KTXpBjl1PaWcvYe4IrMzZuNZq3pveUyl83PcD9uVT0T/j +rZnGv/Ior/TLLdIFmFjOutDX96uMimbgjSxqQcg57EzUBCWIWKjAXNW+v+lqJcCl +YY5y4ElUhuY8j9sQa5OHSevemaIXRiuQMJGFquASVhzPrgpD0jE8UIpwqOQycU+N +NK1nutwzKoq8ZzOoVozlrpz2AifaJ5StVnfzK+0jkuj+7FnkiNeoHUV2DjGLa3J/ +1YwcrLa3J0Gv1tON9BFd81P9mbfCgNc5iwfOP5J/qe0tUKQ7V+dzPDTd89FXTf+5 +VFrmY8bLKP3F08GrAgMBAAECggGAHjiweX+FyBck9VxBKegyXTKj0vC39cjhUhS+ +yV/R37NldWwFems1iqQvRnP/cXluP+v5iPYuG/bMFBKwmMN+kQuF4r8dt4IJMPMj +aAGFE5SAyZpVlJbaMEigKeyG2hvVKyt0Y5K4Ko+HKfCu11VjDS2zCw4thNzVCLWs +oPcpnXGJPSdq65b1TpuK3BSCCsdcFhzSfrkbE2nYsrGxfqqprQbOZg5bUBBCKgr9 +KRT3CWPBIBhfJ4FGEoy49ImmPVWh1GT88tvXnPW+952IXG02pEvqxePqMoFr80e1 +NdXEGrKuEp0Zo+ykr0F+XjSd9by5H6PCMrT8lad6VATi1k4QL2Zoizsg6gXbLnIB +Eed8+HIPYL7xJxmtOm/pcFY6hm5GDeNVMWZ3CYRIuSVLwyZwEsqkX8Y9auXbTWME +uAkHyTCFCJ13QCZg2hDCU9IADZ7Z1XEGMOv79z+CH7Oa800khi6U/Qae3CZo+mTD ++foIxLLsevVVxRC14i3eugQwEFuZAoHBAPvRR52ec/geCSH9iRYFVq+lz1LVzfcm +GNGEOjZlC6LN+biZwMfvAMkvyZIaHT2GWDuxvtSMxhvfuu6HqtEiRxi93gEPDcus +0Eik9JPipsu1t/X1ct3srBPoPWIjVKxS/+6a4X+wrjtBONg5K0DvJYFQsJjb+EAW +bhpBeSKQWJmAwg26tdNU7Cgz5LBY6t5hobcwC53cc2LCB9N1kUhJ3b7PspCVjyls +b/Zoy8/VJKPXN4EbNDuvmkhSr1N89zKiPwKBwQDZg16+CuoL2WZjVjueRKpGbY1s +EIFL3hldLBZ+MHytI5qJU8wY6OhRK3k10Gd9no++6mNeFMBrugJsStoHcJ0U+r4e +QEdQb/Jah562sbhVLLai47AkuuqbVYeLS89ASiW0ic+edsp5SvR0t+7PbI/L4z2e +hjtEt3DsBQxoztbDouzmEdYv94AmqVyquaYzhKkAQ89yB4qRWaKx3nkHa4FnpcJL +/SmKGpZmV2bUN5qYadEZJFOxpFRoHowrtJMZ7ZUCgcEA785mIAFEuTWJRvhWM0VU +PyNtI5p+cW2zVttQQHrLsPfsZ1LslrnRisZadCswS2YD4p0reOiyxNqz/vHtxwmY +oUQ3BdUbMypYk8WbMLY4V2ivTqi3Agaf/Lk+s5Wnzg+gsM6IDnzn/3/mLWuL+GOF +2PdJpdhdOlLh+Vj+jd7esRhANKjo/N8zojmBADs9OBfL1FMJzQSiUZsrrsGYYDoP +1OWgTDZRRoaAvS0hYsO9B9YtgmKwxGI/T76GPsCT/IErAoHAEeRzk7B0Jjtg58T9 +LHy7gQWb/4qwCByh+38X7pNwfhGSsb8558ao7Zxk4R9ek//KFUtUlzWfynzHnD7g +BoKl+UbTAswI0b4Tsoy7ao3d+uutrmKKZ8sUZ2i2uKeoycIPrfU0JfXhm+6lg0Bq +HZfxkDUGKZcjIvjwCgo0Rh7Vncw2LorDErkKSqPd4pFY8Z31BPePBfNG28QC1RzW +2dxnDa6d+ABAPYMIYizIYaadSfJSZ/4MAG3jH5l7sFCvVQ+tAoHBAJCaf28UqLx5 +PyXlYvldKXikeI565Ipiin+crnWV/u4amVNAAXYpfUiFKKIqnw8QjBlqNmvhrKIH +uXJcuaYgu4/L9erdPw6rncFXfnuW+dqwUjw/YpTnXASerGDNTex+aNP7KrQC8A6+ +N7wq+G6NMbU4ZwCeZ59x0Ig2MmlLIHProdm8csJ+ORo2zMFFohQ35srbTQtbaKT/ +t3ux2y9wJ6FsMT/AwyMEsHriDSG6WoBSwaErV3Igtu2x6DuViIGQXQ== +-----END RSA PRIVATE KEY----- diff --git a/test/zdtm.py b/test/zdtm.py index a01947557..000f590b0 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -960,6 +960,7 @@ class criu: self.__lazy_pages_p = None self.__page_server_p = None self.__dump_process = None + self.__tls = self.__tls_options() if opts['tls'] else [] self.__criu_bin = opts['criu_bin'] self.__crit_bin = opts['crit_bin'] @@ -1008,6 +1009,13 @@ class criu: print("Removing %s" % self.__dump_path) shutil.rmtree(self.__dump_path) + def __tls_options(self): + pki_dir = os.path.dirname(os.path.abspath(__file__)) + "/pki" + return ["--tls", "--tls-no-cn-verify", + "--tls-key", pki_dir + "/key.pem", + "--tls-cert", pki_dir + "/cert.pem", + "--tls-cacert", pki_dir + "/cacert.pem"] + def __ddir(self): return os.path.join(self.__dump_path, "%d" % self.__iter) @@ -1141,12 +1149,12 @@ class criu: if self.__page_server: print("Adding page server") - ps_opts = ["--port", "12345"] + ps_opts = ["--port", "12345"] + self.__tls if self.__dedup: ps_opts += ["--auto-dedup"] self.__page_server_p = self.__criu_act("page-server", opts = ps_opts, nowait = True) - a_opts += ["--page-server", "--address", "127.0.0.1", "--port", "12345"] + a_opts += ["--page-server", "--address", "127.0.0.1", "--port", "12345"] + self.__tls a_opts += self.__test.getdopts() @@ -1167,7 +1175,7 @@ class criu: nowait = False if self.__lazy_migrate and action == "dump": - a_opts += ["--lazy-pages", "--port", "12345"] + a_opts += ["--lazy-pages", "--port", "12345"] + self.__tls nowait = True self.__dump_process = self.__criu_act(action, opts = a_opts + opts, nowait = nowait) if self.__mdedup and self.__iter > 1: @@ -1215,10 +1223,12 @@ class criu: if self.__lazy_pages or self.__lazy_migrate: lp_opts = [] if self.__remote_lazy_pages or self.__lazy_migrate: - lp_opts += ['--page-server', "--port", "12345", "--address", "127.0.0.1"] + lp_opts += ["--page-server", "--port", "12345", + "--address", "127.0.0.1"] + self.__tls + if self.__remote_lazy_pages: ps_opts = ["--pidfile", "ps.pid", - "--port", "12345", "--lazy-pages"] + "--port", "12345", "--lazy-pages"] + self.__tls self.__page_server_p = self.__criu_act("page-server", opts = ps_opts, nowait = True) self.__lazy_pages_p = self.__criu_act("lazy-pages", opts = lp_opts, nowait = True) r_opts += ["--lazy-pages"] @@ -1719,7 +1729,7 @@ class Launcher: nd = ('nocr', 'norst', 'pre', 'iters', 'page_server', 'sibling', 'stop', 'empty_ns', 'fault', 'keep_img', 'report', 'snaps', 'sat', 'script', 'rpc', 'lazy_pages', 'join_ns', 'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup', - 'remote_lazy_pages', 'show_stats', 'lazy_migrate', + 'remote_lazy_pages', 'show_stats', 'lazy_migrate', 'tls', 'criu_bin', 'crit_bin') arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd})) @@ -2283,6 +2293,7 @@ rp.add_argument("--ignore-taint", help = "Don't care about a non-zero kernel tai rp.add_argument("--lazy-pages", help = "restore pages on demand", action = 'store_true') rp.add_argument("--lazy-migrate", help = "restore pages on demand", action = 'store_true') rp.add_argument("--remote-lazy-pages", help = "simulate lazy migration", action = 'store_true') +rp.add_argument("--tls", help = "use TLS for migration", action = 'store_true') rp.add_argument("--title", help = "A test suite title", default = "criu") rp.add_argument("--show-stats", help = "Show criu statistics", action = 'store_true') rp.add_argument("--criu-bin", help = "Path to criu binary", default = '../criu/criu') From 73d3ddef3400336e8b36b24ad91c005acddfde87 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 8 May 2019 21:45:39 +0100 Subject: [PATCH 2096/4375] travis: Enable TLS testing Signed-off-by: Radostin Stoyanov --- scripts/build/Dockerfile.alpine | 1 + scripts/build/Dockerfile.centos | 1 + scripts/build/Dockerfile.fedora.tmpl | 1 + scripts/build/Dockerfile.tmpl | 2 ++ scripts/travis/travis-tests | 5 +++-- 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index a91e01637..c71a3901f 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -9,6 +9,7 @@ RUN apk update && apk add \ ccache \ coreutils \ git \ + gnutls-dev \ libaio-dev \ libcap-dev \ libnet-dev \ diff --git a/scripts/build/Dockerfile.centos b/scripts/build/Dockerfile.centos index 2ed3a2db9..2ce40b179 100644 --- a/scripts/build/Dockerfile.centos +++ b/scripts/build/Dockerfile.centos @@ -9,6 +9,7 @@ RUN yum install -y \ findutils \ gcc \ git \ + gnutls-devel \ iproute \ iptables \ libaio-devel \ diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index 22ebaed9c..965309623 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -6,6 +6,7 @@ RUN dnf install -y \ findutils \ gcc \ git \ + gnutls-devel \ iproute \ iptables \ libaio-devel \ diff --git a/scripts/build/Dockerfile.tmpl b/scripts/build/Dockerfile.tmpl index bdfdf713a..4378ba149 100644 --- a/scripts/build/Dockerfile.tmpl +++ b/scripts/build/Dockerfile.tmpl @@ -12,6 +12,8 @@ RUN apt-get update && apt-get install -y \ iptables \ libaio-dev \ libcap-dev \ + libgnutls28-dev \ + libgnutls30 \ libnl-3-dev \ libprotobuf-c0-dev \ libprotobuf-dev \ diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 47ff199cf..664f723e9 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -2,8 +2,8 @@ set -x -e TRAVIS_PKGS="protobuf-c-compiler libprotobuf-c0-dev libaio-dev - libprotobuf-dev protobuf-compiler libcap-dev - libnl-3-dev gcc-multilib gdb bash python-protobuf + libgnutls28-dev libgnutls30 libprotobuf-dev protobuf-compiler + libcap-dev libnl-3-dev gcc-multilib gdb bash python-protobuf libnet-dev util-linux asciidoctor libnl-route-3-dev" travis_prep () { @@ -125,6 +125,7 @@ LAZY_TESTS=.*\(maps0\|uffd-events\|lazy-thp\|futex\|fork\).* ./test/zdtm.py run -p 2 -T $LAZY_TESTS --lazy-pages $LAZY_EXCLUDE $ZDTM_OPTS ./test/zdtm.py run -p 2 -T $LAZY_TESTS --remote-lazy-pages $LAZY_EXCLUDE $ZDTM_OPTS +./test/zdtm.py run -p 2 -T $LAZY_TESTS --remote-lazy-pages --tls $LAZY_EXCLUDE $ZDTM_OPTS bash ./test/jenkins/criu-fault.sh bash ./test/jenkins/criu-fcg.sh From 38d86fa0a2c5197bdaac5ff8c178cb5535d1e297 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 27 Jun 2019 14:18:38 +0300 Subject: [PATCH 2097/4375] lint: Print flake8 version before checking Signed-off-by: Pavel Emelyanov --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 9d83862d1..0b49364fb 100644 --- a/Makefile +++ b/Makefile @@ -380,6 +380,7 @@ help: .PHONY: help lint: + flake8 --version flake8 --config=scripts/flake8.cfg test/zdtm.py flake8 --config=scripts/flake8.cfg test/inhfd/*.py flake8 --config=scripts/flake8.cfg test/others/rpc/config_file.py From 9bd4aee1b464524fb7924f49aeeeab8e993cba1e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Jun 2019 20:16:38 +0300 Subject: [PATCH 2098/4375] flake.cfg: Update to yapf formatting Signed-off-by: Pavel Emelyanov --- scripts/flake8.cfg | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/scripts/flake8.cfg b/scripts/flake8.cfg index 4231e843d..b6a587729 100644 --- a/scripts/flake8.cfg +++ b/scripts/flake8.cfg @@ -1,10 +1,4 @@ [flake8] -# W191 indentation contains tabs -# E128 continuation line under-indented for visual indent # E501 line too long -# E251 unexpected spaces around keyword / parameter equals -# E101 indentation contains mixed spaces and tabs -# E126 continuation line over-indented for hanging indent # W504 line break after binary operator -# E117 over-indented -ignore = W191,E128,E501,E251,E101,E126,W504,E117 +ignore = E501,W504 From c797dae453c74852f16fe9e1f9024f4ed0c08235 Mon Sep 17 00:00:00 2001 From: Harshavardhan Unnibhavi Date: Fri, 8 Mar 2019 15:43:46 +0530 Subject: [PATCH 2099/4375] Documentation: Create man page for libcompel Resolves #349 Signed-off-by: Harshavardhan Unnibhavi --- Documentation/Makefile | 1 + Documentation/compel.txt | 119 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 Documentation/compel.txt diff --git a/Documentation/Makefile b/Documentation/Makefile index aa5d3ebbf..cbc7ff2c8 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -12,6 +12,7 @@ endif FOOTER := footer.txt SRC1 += crit.txt +SRC1 += compel.txt SRC8 += criu.txt SRC := $(SRC1) $(SRC8) XMLS := $(patsubst %.txt,%.xml,$(SRC)) diff --git a/Documentation/compel.txt b/Documentation/compel.txt new file mode 100644 index 000000000..744a3b35d --- /dev/null +++ b/Documentation/compel.txt @@ -0,0 +1,119 @@ +COMPEL(1) +========== +include::footer.txt[] + +NAME +---- +compel - Execute parasitic code within another process. + +SYNOPSIS +-------- +*compel* 'hgen' ['option' ...] + +*compel* 'plugins' ['PLUGIN_NAME' ...] + +*compel* ['--compat'] 'includes' | 'cflags' | 'ldflags' + +*compel* ['--compat'] ['--static'] 'libs' + +DESCRIPTION +------------ +*compel* is a utility to execute arbitrary code, also called parasite code, +in the context of a foreign process. The parasitic code, once compiled with +compel flags and packed, can be executed in the context of other tasks. Currently +there is only one way to load the parasitic blob into victim task using libcompel.a, +called c-header. + +ARGUMENTS +---------- + +Positional Arguments +~~~~~~~~~~~~~~~~~~~~ + +*hgen*:: + create a header from the .po file, which is the parasite binary. + +*plugins*:: + prints the plugins available. + +*ldflags*:: + prints the ldflags available to compel during linking of parasite code. + +*cflags*:: + prints the compel cflags to be used during compilation of parasitic code. + +*includes*:: + prints list of standard include directories. + +*libs*:: + prints list of static or dynamic libraries that compel can link with. + +OPTIONS +-------- +*-f*, *--file* 'FILE':: + Path to the binary file, 'FILE', which *compel* must turn into a header + +*-o*, *--output* 'FILE':: + Path to the header file, 'FILE', where compel must write the resulting header. + +*-p*, *--prefix* 'NAME':: + Specify prefix for var names + +*-l*, *--log-level* 'NUM':: + Default log level of compel. + +*-h*, *--help*:: + Prints usage and exits. + +*-V*, *--version*:: + Prints version number of compel. + +SOURCE EXAMPLES +---------------- + +Parasitic Code +~~~~~~~~~~~~~~ + +*#include * + +*int parasite_trap_cmd(int cmd, void *args);* //gets called by compel_run_in_thread() + +*int parasite_daemon_cmd(int cmd, void *arg);* // gets called by compel_rpc_call() and compel_rpc_call_sync() + +*void parasite_cleanup(void);* //gets called on parasite unload by compel_cure() + +Infecting code +~~~~~~~~~~~~~~ +The parasitic code is compiled and converted to a header using *compel*, and included here. + +*#include * + +*#include "parasite.h"* + +Following steps are perfomed to infect the victim process: + + - stop the task: *int compel_stop_task(int pid);* + - prepare infection handler: *struct parasite_ctl *compel_prepare(int pid);* + - execute system call: *int compel_syscall(ctl, int syscall_nr, long *ret, int arg ...);* + - infect victim: *int compel_infect(ctl, nr_thread, size_of_args_area);* + - cure the victim: *int compel_cure(ctl);* //ctl pointer is freed by this call + - Resume victim: *int compel_resume_task(pid, orig_state, state);* + +*ctl* must be configured with blob information by calling *PREFIX_setup_c_header()*, with ctl as its argument. +*PREFIX* is the argument given to *-p* when calling hgen, else it is deduced from file name. + + +EXAMPLES +--------- +To generate a header file(.h) from a parasite binary file(.po) use: + +---------- + compel hgen -f parasite.po -o parasite.h +---------- + +'parasite.po' file is obtained by compiling the parasite source with compel flags and +linking it with the compel plugins. + +AUTHOR +------ +The CRIU team. From b30b0dcb14be6b2fd38c1146b734e876a6e9a8e4 Mon Sep 17 00:00:00 2001 From: Dengguangxing Date: Wed, 19 Jun 2019 09:13:39 +0000 Subject: [PATCH 2100/4375] fix segmentation fault caused by uninitialized mutex Segmentation fault was raised while trying to restore a process with tty. Coredump file says this is caused by uninitialized tty_mutex: (gdb) where #0 0x00000000004d7270 in atomic_add_return (i=1, v=0x0) at include/common/asm/atomic.h:34 #1 0x00000000004d7398 in mutex_lock (m=0x0) at include/common/lock.h:151 #2 0x00000000004d840c in __pty_open_ptmx_index (index=3, flags=2, cb=0x4dce50 , arg=0x11, path=0x5562e0 "ptmx") at criu/tty.c:603 #3 0x00000000004dced8 in pty_create_ptmx_index (dfd=17, index=3, flags=2) at criu/tty.c:2384 since init_tty_mutex() is reentrantable, just calling it before mutex_lock() Signed-off-by: Deng Guangxing Reviewed-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/tty.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/tty.c b/criu/tty.c index 6fe11530a..e9a28897c 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -600,6 +600,9 @@ static int __pty_open_ptmx_index(int index, int flags, memset(fds, 0xff, sizeof(fds)); + if (init_tty_mutex()) + return -1; + mutex_lock(tty_mutex); for (i = 0; i < ARRAY_SIZE(fds); i++) { From 13b29f8e16d117461f42a4d06aa20973b03e82cb Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 25 Jun 2019 15:16:26 +0300 Subject: [PATCH 2101/4375] tty: Move tty layer shared init into tty_init_restore Instead of using tty_mutex value in atomic context (which is wrong, since it is not atomic) better move tty_mutex allocation into cr_restore_tasks where our all initializers live. Otherwise weird race effect might be observed. Reported-by: Deng Guangxing Signed-off-by: Cyrill Gorcunov --- criu/cr-restore.c | 3 +++ criu/include/tty.h | 1 + criu/tty.c | 15 +-------------- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 23be81140..bf85ab04b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2353,6 +2353,9 @@ int cr_restore_tasks(void) if (vdso_init_restore()) goto err; + if (tty_init_restore()) + goto err; + if (opts.cpu_cap & CPU_CAP_IMAGE) { if (cpu_validate_cpuinfo()) goto err; diff --git a/criu/include/tty.h b/criu/include/tty.h index 95ced8396..8419593e5 100644 --- a/criu/include/tty.h +++ b/criu/include/tty.h @@ -32,6 +32,7 @@ struct mount_info; extern int devpts_restore(struct mount_info *pm); extern int tty_prep_fds(void); +extern int tty_init_restore(void); extern int devpts_check_bindmount(struct mount_info *m); diff --git a/criu/tty.c b/criu/tty.c index e9a28897c..dee8d46bf 100644 --- a/criu/tty.c +++ b/criu/tty.c @@ -349,11 +349,8 @@ static mutex_t *tty_mutex; static bool tty_is_master(struct tty_info *info); -static int init_tty_mutex(void) +int tty_init_restore(void) { - if (tty_mutex) - return 0; - tty_mutex = shmalloc(sizeof(*tty_mutex)); if (!tty_mutex) { pr_err("Can't create ptmx index mutex\n"); @@ -600,9 +597,6 @@ static int __pty_open_ptmx_index(int index, int flags, memset(fds, 0xff, sizeof(fds)); - if (init_tty_mutex()) - return -1; - mutex_lock(tty_mutex); for (i = 0; i < ARRAY_SIZE(fds); i++) { @@ -1792,13 +1786,6 @@ static int tty_info_setup(struct tty_info *info) add_post_prepare_cb_once(&prep_tty_restore); - /* - * Call it explicitly. Post-callbacks will be called after - * namespaces preparation, while the latter needs this mutex. - */ - if (init_tty_mutex()) - return -1; - info->fdstore_id = -1; return file_desc_add(&info->d, info->tfe->id, &tty_desc_ops); } From 60bd698d7ccd37c794d33e874b8cbfb730fb020e Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 14 May 2019 18:12:53 +0000 Subject: [PATCH 2102/4375] sk-inet: fix coverity IDENTICAL_BRANCHES criu-3.12/criu/sk-inet.c:575: identical_branches: The same code is executed when the condition "pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE)" is true or false, because the code in the if-then branch and after the if statement is identical. Should the if statement be removed? Signed-off-by: Adrian Reber --- criu/sk-inet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-inet.c b/criu/sk-inet.c index 90ab492ed..f9c64c7af 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -573,7 +573,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa ie.ip_opts->raw = NULL; if (pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE)) - goto err; + err = -1; err: ip_raw_opts_free(&ipopts_raw); release_skopts(&skopts); From afdde285a15eecdee909749509c6ac0a95a66ea6 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 12:23:56 +0000 Subject: [PATCH 2103/4375] seize: fix coverity RESOURCE_LEAK criu-3.12/criu/seize.c:648: leaked_storage: Variable "threads" going out of scope leaks the storage it points to. Signed-off-by: Adrian Reber --- criu/seize.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/criu/seize.c b/criu/seize.c index b958d4bf9..cce8911b9 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -627,6 +627,7 @@ static int collect_threads(struct pstree_item *item) { struct seccomp_entry *task_seccomp_entry; struct pid *threads = NULL; + struct pid *tmp = NULL; int nr_threads = 0, i = 0, ret, nr_inprogress, nr_stopped = 0; task_seccomp_entry = seccomp_find_entry(item->pid->real); @@ -643,9 +644,11 @@ static int collect_threads(struct pstree_item *item) } /* The number of threads can't be less than already frozen */ - item->threads = xrealloc(item->threads, nr_threads * sizeof(struct pid)); - if (item->threads == NULL) - return -1; + tmp = xrealloc(item->threads, nr_threads * sizeof(struct pid)); + if (tmp == NULL) + goto err; + + item->threads = tmp; if (item->nr_threads == 0) { item->threads[0].real = item->pid->real; From 927382d6fcbbc9fd16876eab9bdf626f28151fc1 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 14:03:19 +0000 Subject: [PATCH 2104/4375] util: fix clang 'null pointer passed' criu-3.12/criu/util.c:879:9: warning: Null pointer passed as an argument to a 'nonnull' parameter criu-3.12/criu/util.c:1171:3: warning: Value stored to 'ret' is never read Signed-off-by: Adrian Reber --- criu/util.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/criu/util.c b/criu/util.c index 0617c97b3..028f604bb 100644 --- a/criu/util.c +++ b/criu/util.c @@ -856,6 +856,12 @@ void split(char *str, char token, char ***out, int *n) cur++; } + if (*n == 0) { + /* This can only happen if str == NULL */ + *out = NULL; + *n = -1; + return; + } *out = xmalloc((*n) * sizeof(char *)); if (!*out) { @@ -1139,7 +1145,7 @@ int run_tcp_server(bool daemon_mode, int *ask, int cfd, int sk) ret = cr_daemon(1, 0, cfd); if (ret == -1) { pr_err("Can't run in the background\n"); - goto out; + goto err; } if (ret > 0) { /* parent task, daemon started */ close_safe(&sk); @@ -1160,10 +1166,11 @@ int run_tcp_server(bool daemon_mode, int *ask, int cfd, int sk) return -1; if (sk >= 0) { - ret = *ask = accept(sk, (struct sockaddr *)&caddr, &clen); - if (*ask < 0) + *ask = accept(sk, (struct sockaddr *)&caddr, &clen); + if (*ask < 0) { pr_perror("Can't accept connection to server"); - else + goto err; + } else pr_info("Accepted connection from %s:%u\n", inet_ntoa(caddr.sin_addr), (int)ntohs(caddr.sin_port)); @@ -1171,7 +1178,7 @@ int run_tcp_server(bool daemon_mode, int *ask, int cfd, int sk) } return 0; -out: +err: close(sk); return -1; } From 04f8fac210da821ed837a7ffb539fe2882726c3d Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 07:37:58 +0000 Subject: [PATCH 2105/4375] files-reg: fix coverity RESOURCE_LEAK criu-3.12/criu/files-reg.c:774: leaked_storage: Variable "img" going out of scope leaks the storage it points to. criu-3.12/criu/files-reg.c:788: leaked_storage: Variable "img" going out of scope leaks the storage it points to. criu-3.12/criu/files-reg.c:797: leaked_storage: Variable "img" going out of scope leaks the storage it points to. Signed-off-by: Adrian Reber --- criu/files-reg.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index ff0ae7d69..2f68bc03f 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -735,6 +735,7 @@ static struct collect_image_info remap_cinfo = { static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_dev) { struct cr_img *img; + int exit_code = -1; GhostFileEntry gfe = GHOST_FILE_ENTRY__INIT; Timeval atim = TIMEVAL__INIT, mtim = TIMEVAL__INIT; @@ -771,7 +772,7 @@ static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_de } if (pb_write_one(img, &gfe, PB_GHOST_FILE)) - return -1; + goto err_out; if (S_ISREG(st->st_mode)) { int fd, ret; @@ -785,7 +786,7 @@ static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_de fd = open(lpath, O_RDONLY); if (fd < 0) { pr_perror("Can't open ghost original file"); - return -1; + goto err_out; } if (gfe.chunks) @@ -794,11 +795,13 @@ static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_de ret = copy_file(fd, img_raw_fd(img), st->st_size); close(fd); if (ret) - return -1; + goto err_out; } + exit_code = 0; +err_out: close_image(img); - return 0; + return exit_code; } struct file_remap *lookup_ghost_remap(u32 dev, u32 ino) From 72da499a27b3211dbedc1e313d41b5edaf000f6e Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 2 Jul 2019 12:51:50 +0300 Subject: [PATCH 2106/4375] dedup: convert noisy warning to debug and improve messages We want to grep warnings from zdtm tests to travis final logs. And I see a lot of these: (00.250989) Warn (criu/pagemap.c:90): Missing 7f84103e3000 in parent pagemap (00.250999) p 0x7f84103f5000 [1] We do a lookup of an intersecting pagemap entry with a memory region we want to dedup, it is expected that sometimes we don't have some subrange in pagemap entries. So these should not be a warning, make it debug message. While on it change the message to save us from been confused with other "Missing..." error messages, and change abstract "parent image" message to the IDs of pages image in all messages in dedup_one_iovec(). v2: print image ids --- criu/pagemap.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/criu/pagemap.c b/criu/pagemap.c index 6bcd0d70e..05f6b82b8 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -86,11 +86,15 @@ int dedup_one_iovec(struct page_read *pr, unsigned long off, unsigned long len) ret = pr->seek_pagemap(pr, off); if (ret == 0) { - pr_warn("Missing %lx in parent pagemap\n", off); - if (off < pr->cvaddr && pr->cvaddr < iov_end) + if (off < pr->cvaddr && pr->cvaddr < iov_end) { + pr_debug("pr%lu-%u:No range %lx-%lx in pagemap\n", + pr->img_id, pr->id, off, pr->cvaddr); off = pr->cvaddr; - else + } else { + pr_debug("pr%lu-%u:No range %lx-%lx in pagemap\n", + pr->img_id, pr->id, off, iov_end); return 0; + } } if (!pr->pe) @@ -105,7 +109,8 @@ int dedup_one_iovec(struct page_read *pr, unsigned long off, unsigned long len) prp = pr->parent; if (prp) { /* recursively */ - pr_debug("Go to next parent level\n"); + pr_debug("pr%lu-%u:Go to next parent level\n", + pr->img_id, pr->id); len = min(piov_end, iov_end) - off; ret = dedup_one_iovec(prp, off, len); if (ret != 0) From facfebee22b4223f406d6cfe09fda862924a7b12 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 2 Jul 2019 13:33:30 +0300 Subject: [PATCH 2107/4375] inventory: skip warning in case of no parent directory We want to grep warnings from zdtm tests to travis final logs. And I see a lot of these: Warn (criu/image.c:137): Failed to open parent directory If there is no parent images directory then there is no previous dump and no pid-reuse problem with pagemaps possible, so it is fine to have no parent inventory image at the same time which is used here to fix the problem. These always hapens on the first iteration of iterative dump. So don't warn here. While on it also fix error message in detect_pid_reuse. v2: add detect_pid_reuse part v3: improve comments --- criu/image.c | 22 +++++++++++++++++++++- criu/mem.c | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/criu/image.c b/criu/image.c index 5239ab474..2eb926929 100644 --- a/criu/image.c +++ b/criu/image.c @@ -125,6 +125,18 @@ int inventory_save_uptime(InventoryEntry *he) return 0; } +/* + * This function is intended to get an inventory image from previous (parent) + * dump iteration. We use dump_uptime from the image in detect_pid_reuse(). + * + * You see that these function never fails by itself, it only prints warnings + * to better understand reasons why we don't found a proper image, failing here + * is too early. We get to detect_pid_reuse() only if we have a parent pagemap + * and that's the proper place to fail: we know that there is a parent pagemap + * but we don't have (can't access, etc) parent inventory => can't detect + * pid-reuse => fail. + */ + InventoryEntry *get_parent_inventory(void) { struct cr_img *img; @@ -133,7 +145,15 @@ InventoryEntry *get_parent_inventory(void) dir = openat(get_service_fd(IMG_FD_OFF), CR_PARENT_LINK, O_RDONLY); if (dir == -1) { - pr_warn("Failed to open parent directory\n"); + /* + * We print the warning below to be notified that we had some + * unexpected problem on open. For instance we have a parent + * directory but have no access. Having no parent inventory + * when also having no parent directory is an expected case of + * first dump iteration. + */ + if (errno != ENOENT) + pr_warn("Failed to open parent directory\n"); return NULL; } diff --git a/criu/mem.c b/criu/mem.c index 6a1a87a1e..d2a39a9db 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -318,7 +318,7 @@ static int detect_pid_reuse(struct pstree_item *item, if (!parent_ie) { pr_err("Pid-reuse detection failed: no parent inventory, " \ - "check warnings in get_parent_stats\n"); + "check warnings in get_parent_inventory\n"); return -1; } From 3ca4c73e478ddb9b525a24164e523c8487658151 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 1 Jul 2019 11:28:43 +0300 Subject: [PATCH 2108/4375] zdtm: make grep_errors also grep warnings It is inspired by the discussion about inotify fix: https://github.com/checkpoint-restore/criu/pull/728#issuecomment-506929427 From one point of view, warnings might be important to understand why we detect some visible change in the environment after c/r-ing the process, and if this change is expected or not. So we should add "Warn" messages to the output. From over point, these warnings if they are expected, can spoil our final logs with a lot of unnecessary details, so add changes in previous patches to silence the most noisy of these warnings. Signed-off-by: Pavel Tikhomirov --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 000f590b0..c64fb2e49 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1915,7 +1915,7 @@ def grep_errors(fname): before.append(l) if len(before) > 5: before.pop(0) - if "Error" in l: + if "Error" in l or "Warn" in l: if first: print_fname(fname, 'log') print_sep("grep Error", "-", 60) From cb6768b62c5347fedef6a88363667280fbce2cff Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 15 Jul 2019 01:04:42 -0700 Subject: [PATCH 2109/4375] test/packet_sock_mmap: parse inode as unsigned long long 7f95a16df000-7f95a16e1000 rw-p 00000000 00:09 2183152397 socket:[2183152397] Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin --- test/zdtm/static/packet_sock_mmap.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/zdtm/static/packet_sock_mmap.c b/test/zdtm/static/packet_sock_mmap.c index 2a82950bc..93d6ebbf2 100644 --- a/test/zdtm/static/packet_sock_mmap.c +++ b/test/zdtm/static/packet_sock_mmap.c @@ -35,16 +35,17 @@ struct tpacket_req3 { static void check_map_is_there(unsigned long addr, int sk) { FILE *f; - char line[64]; + char line[4096]; struct stat ss; fstat(sk, &ss); f = fopen("/proc/self/maps", "r"); while (fgets(line, sizeof(line), f) != NULL) { + unsigned long long ino; unsigned long start; - int maj, min, ino; + int maj, min; - sscanf(line, "%lx-%*x %*s %*s %x:%x %d %*s", &start, &maj, &min, &ino); + sscanf(line, "%lx-%*x %*s %*s %x:%x %llu %*s", &start, &maj, &min, &ino); if ((start == addr) && ss.st_dev == makedev(maj, min) && ss.st_ino == ino) { pass(); fclose(f); From a82275f3d4407f673b9a3d91032f2dea0629574b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 17 Jul 2019 00:42:24 -0700 Subject: [PATCH 2110/4375] zdtm: use a proper page size for the host In zdtm.py, the page size is hardcoded as 4096, but on ppc64le, is is equal to 64K and all test fail with errors like this: ERROR: bad page counts, stats = 13 real = 208(0) Signed-off-by: Andrei Vagin --- test/zdtm.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index c64fb2e49..c52964528 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -23,6 +23,7 @@ import errno import datetime import yaml import struct +import mmap import pycriu as crpc os.chdir(os.path.dirname(os.path.abspath(__file__))) @@ -1130,8 +1131,8 @@ class criu: if f.startswith('pages-'): real_written += os.path.getsize(os.path.join(self.__ddir(), f)) - r_pages = real_written / 4096 - r_off = real_written % 4096 + r_pages = real_written / mmap.PAGESIZE + r_off = real_written % mmap.PAGESIZE if (stats_written != r_pages) or (r_off != 0): print("ERROR: bad page counts, stats = %d real = %d(%d)" % (stats_written, r_pages, r_off)) raise test_fail_exc("page counts mismatch") From b758e4b4762255236048d85ca90dcaf06f75c117 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Wed, 17 Jul 2019 14:30:01 +0200 Subject: [PATCH 2111/4375] Replace libprotobuf-c0-dev with libprotobuf-c-dev The `libprotobuf-c0-dev` virtual package is no longer available in Debian Buster, but is provided by `libprotobuf-c-dev`, which is available. Signed-off-by: Sebastiaan van Stijn --- contrib/debian/dev-packages.lst | 2 +- criu/Makefile.packages | 2 +- scripts/build/Dockerfile.tmpl | 2 +- scripts/travis/travis-tests | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/debian/dev-packages.lst b/contrib/debian/dev-packages.lst index b0b664f72..049bbd82d 100644 --- a/contrib/debian/dev-packages.lst +++ b/contrib/debian/dev-packages.lst @@ -1,7 +1,7 @@ # Required packages for development in Debian build-essential libprotobuf-dev -libprotobuf-c0-dev +libprotobuf-c-dev protobuf-c-compiler protobuf-compiler python-protobuf diff --git a/criu/Makefile.packages b/criu/Makefile.packages index b01b4b044..f380fa2f0 100644 --- a/criu/Makefile.packages +++ b/criu/Makefile.packages @@ -11,7 +11,7 @@ REQ-RPM-PKG-NAMES += $(PYTHON)-future REQ-RPM-PKG-TEST-NAMES += libaio-devel REQ-DEB-PKG-NAMES += libprotobuf-dev -REQ-DEB-PKG-NAMES += libprotobuf-c0-dev +REQ-DEB-PKG-NAMES += libprotobuf-c-dev REQ-DEB-PKG-NAMES += protobuf-c-compiler REQ-DEB-PKG-NAMES += protobuf-compiler REQ-DEB-PKG-NAMES += python-protobuf diff --git a/scripts/build/Dockerfile.tmpl b/scripts/build/Dockerfile.tmpl index 4378ba149..d90a1d229 100644 --- a/scripts/build/Dockerfile.tmpl +++ b/scripts/build/Dockerfile.tmpl @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y \ libgnutls28-dev \ libgnutls30 \ libnl-3-dev \ - libprotobuf-c0-dev \ + libprotobuf-c-dev \ libprotobuf-dev \ libselinux-dev \ pkg-config \ diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 664f723e9..348daca1f 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -1,7 +1,7 @@ #!/bin/sh set -x -e -TRAVIS_PKGS="protobuf-c-compiler libprotobuf-c0-dev libaio-dev +TRAVIS_PKGS="protobuf-c-compiler libprotobuf-c-dev libaio-dev libgnutls28-dev libgnutls30 libprotobuf-dev protobuf-compiler libcap-dev libnl-3-dev gcc-multilib gdb bash python-protobuf libnet-dev util-linux asciidoctor libnl-route-3-dev" From db2777e73c3cf44ddb75aa4ab9f6e5bb88705571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20C=C5=82api=C5=84ski?= Date: Fri, 12 Jul 2019 18:12:42 +0200 Subject: [PATCH 2112/4375] Add support for migrating CHILD_SUBREAPER prctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Checkpoint it via parasite. 2. Restore it after forking. Signed-off-by: Michał Cłapiński Reviewed-by: Pavel Tikhomirov --- criu/cr-dump.c | 8 ++++++-- criu/cr-restore.c | 7 +++++-- criu/include/parasite.h | 1 + criu/include/restorer.h | 1 + criu/pie/parasite.c | 12 +++++++++++- criu/pie/restorer.c | 13 +++++++++++++ images/core.proto | 2 ++ 7 files changed, 39 insertions(+), 5 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 91b8b383a..b12119fa6 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -726,7 +726,8 @@ int dump_thread_core(int pid, CoreEntry *core, const struct parasite_dump_thread static int dump_task_core_all(struct parasite_ctl *ctl, struct pstree_item *item, const struct proc_pid_stat *stat, - const struct cr_imgset *cr_imgset) + const struct cr_imgset *cr_imgset, + const struct parasite_dump_misc *misc) { struct cr_img *img; CoreEntry *core = item->core[0]; @@ -740,6 +741,9 @@ static int dump_task_core_all(struct parasite_ctl *ctl, pr_info("Dumping core (pid: %d)\n", pid); pr_info("----------------------------------------\n"); + core->tc->child_subreaper = misc->child_subreaper; + core->tc->has_child_subreaper = true; + ret = get_task_personality(pid, &core->tc->personality); if (ret < 0) goto err; @@ -1378,7 +1382,7 @@ static int dump_one_task(struct pstree_item *item, InventoryEntry *parent_ie) goto err_cure; } - ret = dump_task_core_all(parasite_ctl, item, &pps_buf, cr_imgset); + ret = dump_task_core_all(parasite_ctl, item, &pps_buf, cr_imgset, &misc); if (ret) { pr_err("Dump core (pid: %d) failed with %d\n", pid, ret); goto err_cure; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index bf85ab04b..2ffd9a86c 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -806,10 +806,13 @@ static int prepare_oom_score_adj(int value) return ret; } -static int prepare_proc_misc(pid_t pid, TaskCoreEntry *tc) +static int prepare_proc_misc(pid_t pid, TaskCoreEntry *tc, struct task_restore_args *args) { int ret; + if (tc->has_child_subreaper) + args->child_subreaper = tc->child_subreaper; + /* loginuid value is critical to restore */ if (kdat.luid == LUID_FULL && tc->has_loginuid && tc->loginuid != INVALID_UID) { @@ -877,7 +880,7 @@ static int restore_one_alive_task(int pid, CoreEntry *core) if (collect_zombie_pids(ta) < 0) return -1; - if (prepare_proc_misc(pid, core->tc)) + if (prepare_proc_misc(pid, core->tc, ta)) return -1; /* diff --git a/criu/include/parasite.h b/criu/include/parasite.h index 0a62f2439..d9570948a 100644 --- a/criu/include/parasite.h +++ b/criu/include/parasite.h @@ -126,6 +126,7 @@ struct parasite_dump_misc { int dumpable; int thp_disabled; + int child_subreaper; }; /* diff --git a/criu/include/restorer.h b/criu/include/restorer.h index effbc3655..f980bfad3 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -217,6 +217,7 @@ struct task_restore_args { unsigned page_size; #endif int lsm_type; + int child_subreaper; } __aligned(64); /* diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index 01bacd311..9a179ef8b 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -39,6 +39,10 @@ static struct parasite_dump_pages_args *mprotect_args = NULL; #define PR_GET_PDEATHSIG 2 #endif +#ifndef PR_GET_CHILD_SUBREAPER +#define PR_GET_CHILD_SUBREAPER 37 +#endif + static int mprotect_vmas(struct parasite_dump_pages_args *args) { struct parasite_vma_entry *vmas, *vma; @@ -202,6 +206,8 @@ out: static int dump_misc(struct parasite_dump_misc *args) { + int ret; + args->brk = sys_brk(0); args->pid = sys_getpid(); @@ -212,7 +218,11 @@ static int dump_misc(struct parasite_dump_misc *args) args->dumpable = sys_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0); args->thp_disabled = sys_prctl(PR_GET_THP_DISABLE, 0, 0, 0, 0); - return 0; + ret = sys_prctl(PR_GET_CHILD_SUBREAPER, (unsigned long)&args->child_subreaper, 0, 0, 0); + if (ret) + pr_err("PR_GET_CHILD_SUBREAPER failed (%d)\n", ret); + + return ret; } static int dump_creds(struct parasite_dump_creds *args) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 513be74e0..324a11e0c 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -52,6 +52,10 @@ #define PR_SET_PDEATHSIG 1 #endif +#ifndef PR_SET_CHILD_SUBREAPER +#define PR_SET_CHILD_SUBREAPER 36 +#endif + #ifndef FALLOC_FL_KEEP_SIZE #define FALLOC_FL_KEEP_SIZE 0x01 #endif @@ -1231,6 +1235,14 @@ static bool vdso_needs_parking(struct task_restore_args *args) return !vdso_unmapped(args); } +static inline int restore_child_subreaper(int child_subreaper) +{ + if (child_subreaper) + return sys_prctl(PR_SET_CHILD_SUBREAPER, child_subreaper, 0, 0, 0); + else + return 0; +} + /* * The main routine to restore task via sigreturn. * This one is very special, we never return there @@ -1731,6 +1743,7 @@ long __export_restore_task(struct task_restore_args *args) args->lsm_type); ret = ret || restore_dumpable_flag(&args->mm); ret = ret || restore_pdeath_sig(args->t); + ret = ret || restore_child_subreaper(args->child_subreaper); futex_set_and_wake(&thread_inprogress, args->nr_threads); diff --git a/images/core.proto b/images/core.proto index 312a983f0..9f3f870c9 100644 --- a/images/core.proto +++ b/images/core.proto @@ -51,6 +51,8 @@ message task_core_entry { // Reserved for tty inheritance //optional int32 tty_nr = 16; //optional int32 tty_pgrp = 17; + + optional int32 child_subreaper = 18; } message task_kobj_ids_entry { From 6606f246c21a8e1ff40b56087a360c1ff6fbe6bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20C=C5=82api=C5=84ski?= Date: Fri, 12 Jul 2019 18:14:41 +0200 Subject: [PATCH 2113/4375] Add ZDTM tests for child subreaper property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Basic check if property is migrated 2. Check that property is restored for existing children 3. Check that child subreaper does not affect reparenting Signed-off-by: Pavel Tikhomirov Signed-off-by: Michał Cłapiński Reviewed-by: Pavel Tikhomirov --- test/zdtm/static/Makefile | 3 + test/zdtm/static/child_subreaper.c | 36 +++++ .../static/child_subreaper_and_reparent.c | 142 ++++++++++++++++++ .../static/child_subreaper_and_reparent.desc | 1 + .../static/child_subreaper_existing_child.c | 138 +++++++++++++++++ 5 files changed, 320 insertions(+) create mode 100644 test/zdtm/static/child_subreaper.c create mode 100644 test/zdtm/static/child_subreaper_and_reparent.c create mode 100644 test/zdtm/static/child_subreaper_and_reparent.desc create mode 100644 test/zdtm/static/child_subreaper_existing_child.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 7799c0b0a..52bd00602 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -214,6 +214,9 @@ TST_NOFILE := \ selinux00 \ selinux01 \ selinux02 \ + child_subreaper \ + child_subreaper_existing_child \ + child_subreaper_and_reparent \ # jobctl00 \ ifneq ($(SRCARCH),arm) diff --git a/test/zdtm/static/child_subreaper.c b/test/zdtm/static/child_subreaper.c new file mode 100644 index 000000000..267795249 --- /dev/null +++ b/test/zdtm/static/child_subreaper.c @@ -0,0 +1,36 @@ +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check that child subreaper attribute is restored"; +const char *test_author = "Michał Cłapiński "; + +int main(int argc, char **argv) +{ + test_init(argc, argv); + + int cs_before = 1; + int ret = prctl(PR_SET_CHILD_SUBREAPER, cs_before, 0, 0, 0); + if (ret) { + pr_perror("Can't set child subreaper attribute, err = %d", ret); + exit(1); + } + + test_daemon(); + test_waitsig(); + + int cs_after; + ret = prctl(PR_GET_CHILD_SUBREAPER, (unsigned long)&cs_after, 0, 0, 0); + if (ret) { + pr_perror("Can't get child subreaper attribute, err = %d", ret); + exit(1); + } + + if (cs_before != cs_after) + fail("%d != %d\n", cs_before, cs_after); + else + pass(); + + return 0; +} diff --git a/test/zdtm/static/child_subreaper_and_reparent.c b/test/zdtm/static/child_subreaper_and_reparent.c new file mode 100644 index 000000000..57943a67b --- /dev/null +++ b/test/zdtm/static/child_subreaper_and_reparent.c @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" +#include "lock.h" + +const char *test_doc = "Check that child subreaper does not affect reparenting"; +const char *test_author = "Pavel Tikhomirov "; + +enum { + TEST_FORK, + TEST_SAVE, + TEST_CRIU, + TEST_CHECK, + TEST_EXIT, +}; + +struct shared { + futex_t fstate; + int parent_before_cr; + int parent_after_cr; +} *sh; + +int orphan() +{ + /* + * Wait until reparented to the pidns init. (By waiting + * for the SUBREAPER to reap our parent.) + */ + futex_wait_until(&sh->fstate, TEST_SAVE); + + sh->parent_before_cr = getppid(); + + /* Return the control back to MAIN worker to do C/R */ + futex_set_and_wake(&sh->fstate, TEST_CRIU); + futex_wait_until(&sh->fstate, TEST_CHECK); + + sh->parent_after_cr = getppid(); + + futex_set_and_wake(&sh->fstate, TEST_EXIT); + return 0; +} + +int helper() +{ + int pid; + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork"); + return 1; + } else if (pid == 0) { + exit(orphan()); + } + return 0; +} + +int subreaper() +{ + int pid, ret, status; + + setsid(); + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork"); + return 1; + } else if (pid == 0) { + exit(helper()); + } + + /* Reap the HELPER */ + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + pr_perror("Wrong exit status for helper: %d", status); + return 1; + } + + ret = prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); + if (ret) { + pr_perror("Can't set child subreaper attribute, err = %d", ret); + return 1; + } + + /* Give control to ORPHAN to save it's parent */ + futex_set_and_wake(&sh->fstate, TEST_SAVE); + futex_wait_until(&sh->fstate, TEST_EXIT); + return 0; +} + +int main(int argc, char **argv) +{ + int pid, status; + + sh = mmap(NULL, sizeof(struct shared), PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (sh == MAP_FAILED) { + pr_perror("Failed to alloc shared region"); + exit(1); + } + + futex_set(&sh->fstate, TEST_FORK); + + test_init(argc, argv); + + setsid(); + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork"); + exit(1); + } else if (pid == 0) { + exit(subreaper()); + } + + /* Wait until ORPHAN is ready to C/R */ + futex_wait_until(&sh->fstate, TEST_CRIU); + + test_daemon(); + test_waitsig(); + + /* Give control to ORPHAN to check it's parent */ + futex_set_and_wake(&sh->fstate, TEST_CHECK); + futex_wait_until(&sh->fstate, TEST_EXIT); + + /* Cleanup */ + while (wait(&status) > 0) { + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + fail("Wrong exit status: %d", status); + return 1; + } + } + + if (sh->parent_before_cr != sh->parent_after_cr) + fail("Parent mismatch before %d after %d", sh->parent_before_cr, sh->parent_after_cr); + else + pass(); + return 0; +} diff --git a/test/zdtm/static/child_subreaper_and_reparent.desc b/test/zdtm/static/child_subreaper_and_reparent.desc new file mode 100644 index 000000000..6c4afe5f0 --- /dev/null +++ b/test/zdtm/static/child_subreaper_and_reparent.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns'} diff --git a/test/zdtm/static/child_subreaper_existing_child.c b/test/zdtm/static/child_subreaper_existing_child.c new file mode 100644 index 000000000..28e9dbb8a --- /dev/null +++ b/test/zdtm/static/child_subreaper_existing_child.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include + +#include "zdtmtst.h" +#include "lock.h" + +const char *test_doc = "Check that property is restored for existing children"; +const char *test_author = "Michał Cłapiński "; + +enum { + TEST_FORK, + TEST_CRIU, + TEST_DIE, + TEST_CHECK, + TEST_EXIT, +}; + +struct shared { + futex_t fstate; + int ppid_after_reparent; +} *sh; + + +int orphan() +{ + /* Return the control back to MAIN worker to do C/R */ + futex_set_and_wake(&sh->fstate, TEST_CRIU); + futex_wait_until(&sh->fstate, TEST_CHECK); + + sh->ppid_after_reparent = getppid(); + + futex_set_and_wake(&sh->fstate, TEST_EXIT); + return 0; +} + +int helper() +{ + int pid; + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork"); + return 1; + } else if (pid == 0) { + exit(orphan()); + } + + futex_wait_until(&sh->fstate, TEST_DIE); + return 0; +} + +int subreaper() +{ + int pid, ret, status; + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork"); + return 1; + } else if (pid == 0) { + exit(helper()); + } + + ret = prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); + if (ret) { + pr_perror("Can't set child subreaper attribute, err = %d", ret); + return 1; + } + + /* Reap the HELPER */ + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + pr_perror("Wrong exit status for HELPER: %d", status); + return 1; + } + + /* Give control to ORPHAN so it can check its parent */ + futex_set_and_wake(&sh->fstate, TEST_CHECK); + futex_wait_until(&sh->fstate, TEST_EXIT); + + /* Cleanup: reap the ORPHAN */ + wait(&status); + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + pr_perror("Wrong exit status for ORPHAN: %d", status); + return 1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + int pid, status; + + sh = mmap(NULL, sizeof(struct shared), PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (sh == MAP_FAILED) { + pr_perror("Failed to alloc shared region"); + exit(1); + } + + futex_set(&sh->fstate, TEST_FORK); + + test_init(argc, argv); + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork"); + exit(1); + } else if (pid == 0) { + exit(subreaper()); + } + + /* Wait until ORPHAN is ready to C/R */ + futex_wait_until(&sh->fstate, TEST_CRIU); + + test_daemon(); + test_waitsig(); + + /* Give control to HELPER so it can die */ + futex_set_and_wake(&sh->fstate, TEST_DIE); + futex_wait_until(&sh->fstate, TEST_EXIT); + + /* Cleanup: reap the SUBREAPER */ + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + fail("Wrong exit status: %d", status); + return 1; + } + + if (sh->ppid_after_reparent != pid) + fail("Orphan was reparented to %d instead of %d", sh->ppid_after_reparent, pid); + else + pass(); + return 0; +} From cb946164367d8ea6cfd9490ee3f8f66ed38b1a4d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:37:56 +0300 Subject: [PATCH 2114/4375] mem/page-pipe: Eliminate redundant pipe_off setup In case if we may use previous pipe the pipe_off get set directly so no need for redundat unconditional assignment. Signed-off-by: Cyrill Gorcunov Acked-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/page-pipe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/page-pipe.c b/criu/page-pipe.c index c32b89332..33741db42 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -104,8 +104,6 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp, return NULL; cnt_add(CNT_PAGE_PIPE_BUFS, 1); - ppb->pipe_off = 0; - if (prev && ppb_resize_pipe(prev) == 0) { /* The previous pipe isn't full and we can continue to use it. */ ppb->p[0] = prev->p[0]; @@ -120,6 +118,7 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp, } cnt_add(CNT_PAGE_PIPES, 1); + ppb->pipe_off = 0; ppb->pipe_size = fcntl(ppb->p[0], F_GETPIPE_SZ, 0) / PAGE_SIZE; pp->nr_pipes++; } From 088b086bfe82621d64b3c52414909f791d6033dd Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:37:57 +0300 Subject: [PATCH 2115/4375] mem/page-pipe: create_page_pipe -- Drop redundant zero assignment We allocate with xzalloc, no need for additional zero assignemtns. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/page-pipe.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/criu/page-pipe.c b/criu/page-pipe.c index 33741db42..32be2f981 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -187,26 +187,18 @@ struct page_pipe *create_page_pipe(unsigned int nr_segs, struct iovec *iovs, uns if (!pp) return NULL; + INIT_LIST_HEAD(&pp->free_bufs); + INIT_LIST_HEAD(&pp->bufs); + pp->nr_iovs = nr_segs; pp->flags = flags; if (!iovs) { iovs = xmalloc(sizeof(*iovs) * nr_segs); if (!iovs) goto err_free_pp; - pp->flags |= PP_OWN_IOVS; } - - pp->nr_pipes = 0; - INIT_LIST_HEAD(&pp->bufs); - INIT_LIST_HEAD(&pp->free_bufs); - pp->nr_iovs = nr_segs; pp->iovs = iovs; - pp->free_iov = 0; - - pp->nr_holes = 0; - pp->free_hole = 0; - pp->holes = NULL; if (page_pipe_grow(pp, 0)) goto err_free_iovs; From 692fdada56456406b72ba62b53f1e6922f640341 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:37:58 +0300 Subject: [PATCH 2116/4375] mem/page-pipe: Align members for readability sake Signed-off-by: Cyrill Gorcunov Reviewed-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/include/page-pipe.h | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h index 80e595871..decd14321 100644 --- a/criu/include/page-pipe.h +++ b/criu/include/page-pipe.h @@ -91,15 +91,15 @@ struct kernel_pipe_buffer { */ struct page_pipe_buf { - int p[2]; /* pipe with pages */ - unsigned int pipe_size; /* how many pages can be fit into pipe */ - unsigned int pipe_off; /* where this buf is started in a pipe */ - unsigned int pages_in; /* how many pages are there */ - unsigned int nr_segs; /* how many iov-s are busy */ + int p[2]; /* pipe with pages */ + unsigned int pipe_size; /* how many pages can be fit into pipe */ + unsigned int pipe_off; /* where this buf is started in a pipe */ + unsigned int pages_in; /* how many pages are there */ + unsigned int nr_segs; /* how many iov-s are busy */ #define PPB_LAZY (1 << 0) - unsigned int flags; - struct iovec *iov; /* vaddr:len map */ - struct list_head l; /* links into page_pipe->bufs */ + unsigned int flags; + struct iovec *iov; /* vaddr:len map */ + struct list_head l; /* links into page_pipe->bufs */ }; /* @@ -114,21 +114,21 @@ struct page_pipe_buf { #define PP_HOLE_PARENT (1 << 0) struct page_pipe { - unsigned int nr_pipes; /* how many page_pipe_bufs in there */ - struct list_head bufs; /* list of bufs */ - struct list_head free_bufs; /* list of bufs */ - struct page_pipe_buf *prev[PP_PIPE_TYPES]; /* last ppb of each type - for pipe sharing */ - unsigned int nr_iovs; /* number of iovs */ - unsigned int free_iov; /* first free iov */ - struct iovec *iovs; /* iovs. They are provided into create_page_pipe - and all bufs have their iov-s in there */ + unsigned int nr_pipes; /* how many page_pipe_bufs in there */ + struct list_head bufs; /* list of bufs */ + struct list_head free_bufs; /* list of bufs */ + struct page_pipe_buf *prev[PP_PIPE_TYPES]; /* last ppb of each type for pipe sharing */ + unsigned int nr_iovs; /* number of iovs */ + unsigned int free_iov; /* first free iov */ - unsigned int nr_holes; /* number of holes allocated */ - unsigned int free_hole; /* number of holes in use */ - struct iovec *holes; /* holes */ - unsigned int *hole_flags; - unsigned flags; /* PP_FOO flags below */ + struct iovec *iovs; /* iovs. They are provided into create_page_pipe + and all bufs have their iov-s in there */ + + unsigned int nr_holes; /* number of holes allocated */ + unsigned int free_hole; /* number of holes in use */ + struct iovec *holes; /* holes */ + unsigned int *hole_flags; + unsigned int flags; /* PP_FOO flags below */ }; #define PP_CHUNK_MODE 0x1 /* Restrict the maximum buffer size of pipes From f3b8371c3095b3eb73476d9b8d8f98c9ad7bd078 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:37:59 +0300 Subject: [PATCH 2117/4375] mem/page-pipe: Use ssize_t for splice/tee results Integer value is too short. Signed-off-by: Cyrill Gorcunov Reviewed-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/page-pipe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/page-pipe.c b/criu/page-pipe.c index 32be2f981..534380b0f 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -389,7 +389,7 @@ int page_pipe_read(struct page_pipe *pp, struct pipe_read_dest *prd, struct page_pipe_buf *ppb; struct iovec *iov = NULL; unsigned long skip = 0, len; - int ret; + ssize_t ret; /* * Get ppb that contains addr and count length of data between @@ -418,13 +418,13 @@ int page_pipe_read(struct page_pipe *pp, struct pipe_read_dest *prd, ret = tee(ppb->p[0], prd->p[1], len, 0); if (ret != len) { - pr_perror("tee: %d", ret); + pr_perror("tee: %zd", ret); return -1; } ret = splice(prd->p[0], NULL, prd->sink_fd, NULL, skip, 0); if (ret != skip) { - pr_perror("splice: %d", ret); + pr_perror("splice: %zd", ret); return -1; } From 6e86b9eb01f6e7f0da04ff255d49bdefe19b7c04 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:38:00 +0300 Subject: [PATCH 2118/4375] mem/vma: Use memset for vm_area_list_init To eliminate side effects, in particular setting nr_aios is already missing here. Signed-off-by: Cyrill Gorcunov Reviewed-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/include/vma.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/criu/include/vma.h b/criu/include/vma.h index c297c0d14..6f5ee19d3 100644 --- a/criu/include/vma.h +++ b/criu/include/vma.h @@ -7,6 +7,7 @@ #include "images/vma.pb-c.h" #include +#include struct vm_area_list { struct list_head h; @@ -21,11 +22,8 @@ struct vm_area_list { static inline void vm_area_list_init(struct vm_area_list *vml) { + memset(vml, 0, sizeof(*vml)); INIT_LIST_HEAD(&vml->h); - vml->nr = 0; - vml->priv_size = 0; - vml->priv_longest = 0; - vml->shared_longest = 0; } struct file_desc; From 32e9f155254e820bed4f2e1582015e7a1a98b0b6 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:38:01 +0300 Subject: [PATCH 2119/4375] mem/vma: Use vm_area_list_init where appropriate Signed-off-by: Cyrill Gorcunov Reviewed-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 9 +++------ criu/proc_parse.c | 7 +------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index b12119fa6..dc151b9a8 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -108,8 +108,7 @@ void free_mappings(struct vm_area_list *vma_area_list) free(vma_area); } - INIT_LIST_HEAD(&vma_area_list->h); - vma_area_list->nr = 0; + vm_area_list_init(vma_area_list); } int collect_mappings(pid_t pid, struct vm_area_list *vma_area_list, @@ -1142,8 +1141,7 @@ static int pre_dump_one_task(struct pstree_item *item, InventoryEntry *parent_ie struct parasite_dump_misc misc; struct mem_dump_ctl mdc; - INIT_LIST_HEAD(&vmas.h); - vmas.nr = 0; + vm_area_list_init(&vmas); pr_info("========================================\n"); pr_info("Pre-dumping task (pid: %d)\n", pid); @@ -1224,8 +1222,7 @@ static int dump_one_task(struct pstree_item *item, InventoryEntry *parent_ie) struct proc_posix_timers_stat proc_args; struct mem_dump_ctl mdc; - INIT_LIST_HEAD(&vmas.h); - vmas.nr = 0; + vm_area_list_init(&vmas); pr_info("========================================\n"); pr_info("Dumping task (pid: %d)\n", pid); diff --git a/criu/proc_parse.c b/criu/proc_parse.c index f6ebb1fd6..4c127f264 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -705,12 +705,7 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, DIR *map_files_dir = NULL; struct bfd f; - vma_area_list->nr = 0; - vma_area_list->nr_aios = 0; - vma_area_list->priv_longest = 0; - vma_area_list->priv_size = 0; - vma_area_list->shared_longest = 0; - INIT_LIST_HEAD(&vma_area_list->h); + vm_area_list_init(vma_area_list); f.fd = open_proc(pid, "smaps"); if (f.fd < 0) From 0ee3d0764ddd5d1ad744586f770601e394a8cd14 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:38:02 +0300 Subject: [PATCH 2120/4375] mem/vma: Drop never used VM_AREA_LIST macro Signed-off-by: Cyrill Gorcunov Reviewed-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/include/vma.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/criu/include/vma.h b/criu/include/vma.h index 6f5ee19d3..3cdd1b319 100644 --- a/criu/include/vma.h +++ b/criu/include/vma.h @@ -18,8 +18,6 @@ struct vm_area_list { unsigned long shared_longest; /* nr of pages in longest shared VMA */ }; -#define VM_AREA_LIST(name) struct vm_area_list name = { .h = LIST_HEAD_INIT(name.h), .nr = 0, } - static inline void vm_area_list_init(struct vm_area_list *vml) { memset(vml, 0, sizeof(*vml)); From 8f9ae895d04b032c227f6adf0ac2d244b6b43e31 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:38:03 +0300 Subject: [PATCH 2121/4375] mem/vma: Sanitize struct vm_area_list - make names more descriptive - add comments - use union for nr_priv_pages and rst_priv_size since former priv_size has been used with different meaning: number of pages during checkpoint time and size in bytes on restore moment Signed-off-by: Cyrill Gorcunov Reviewed-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 2 +- criu/include/vma.h | 15 +++++++++------ criu/mem.c | 20 ++++++++++---------- criu/proc_parse.c | 9 +++++---- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index dc151b9a8..9273fc0a5 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -125,7 +125,7 @@ int collect_mappings(pid_t pid, struct vm_area_list *vma_area_list, goto err; pr_info("Collected, longest area occupies %lu pages\n", - vma_area_list->priv_longest); + vma_area_list->nr_priv_pages_longest); pr_info_vma_list(&vma_area_list->h); pr_info("----------------------------------------\n"); diff --git a/criu/include/vma.h b/criu/include/vma.h index 3cdd1b319..5e3f3527b 100644 --- a/criu/include/vma.h +++ b/criu/include/vma.h @@ -10,12 +10,15 @@ #include struct vm_area_list { - struct list_head h; - unsigned nr; - unsigned int nr_aios; - unsigned long priv_size; /* nr of pages in private VMAs */ - unsigned long priv_longest; /* nr of pages in longest private VMA */ - unsigned long shared_longest; /* nr of pages in longest shared VMA */ + struct list_head h; /* list of VMAs */ + unsigned nr; /* nr of all VMAs in the list */ + unsigned int nr_aios; /* nr of AIOs VMAs in the list */ + union { + unsigned long nr_priv_pages; /* dmp: nr of pages in private VMAs */ + unsigned long rst_priv_size; /* rst: size of private VMAs */ + }; + unsigned long nr_priv_pages_longest; /* nr of pages in longest private VMA */ + unsigned long nr_shared_pages_longest;/* nr of pages in longest shared VMA */ }; static inline void vm_area_list_init(struct vm_area_list *vml) diff --git a/criu/mem.c b/criu/mem.c index d2a39a9db..de66a6210 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -81,7 +81,7 @@ unsigned long dump_pages_args_size(struct vm_area_list *vmas) /* In the worst case I need one iovec for each page */ return sizeof(struct parasite_dump_pages_args) + vmas->nr * sizeof(struct parasite_vma_entry) + - (vmas->priv_size + 1) * sizeof(struct iovec); + (vmas->nr_priv_pages + 1) * sizeof(struct iovec); } static inline bool __page_is_zero(u64 pme) @@ -414,14 +414,14 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, timing_start(TIME_MEMDUMP); pr_debug(" Private vmas %lu/%lu pages\n", - vma_area_list->priv_longest, vma_area_list->priv_size); + vma_area_list->nr_priv_pages_longest, vma_area_list->nr_priv_pages); /* * Step 0 -- prepare */ - pmc_size = max(vma_area_list->priv_longest, - vma_area_list->shared_longest); + pmc_size = max(vma_area_list->nr_priv_pages_longest, + vma_area_list->nr_shared_pages_longest); if (pmc_init(&pmc, item->pid->real, &vma_area_list->h, pmc_size * PAGE_SIZE)) return -1; @@ -433,7 +433,7 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, * use, i.e. on non-lazy non-predump. */ cpp_flags |= PP_CHUNK_MODE; - pp = create_page_pipe(vma_area_list->priv_size, + pp = create_page_pipe(vma_area_list->nr_priv_pages, mdc->lazy ? NULL : pargs_iovs(args), cpp_flags); if (!pp) @@ -612,9 +612,9 @@ int prepare_mm_pid(struct pstree_item *i) list_add_tail(&vma->list, &ri->vmas.h); if (vma_area_is_private(vma, kdat.task_size)) { - ri->vmas.priv_size += vma_area_len(vma); + ri->vmas.rst_priv_size += vma_area_len(vma); if (vma_has_guard_gap_hidden(vma)) - ri->vmas.priv_size += PAGE_SIZE; + ri->vmas.rst_priv_size += PAGE_SIZE; } pr_info("vma 0x%"PRIx64" 0x%"PRIx64"\n", vma->e->start, vma->e->end); @@ -1171,17 +1171,17 @@ int prepare_mappings(struct pstree_item *t) goto out; /* Reserve a place for mapping private vma-s one by one */ - addr = mmap(NULL, vmas->priv_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + addr = mmap(NULL, vmas->rst_priv_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); if (addr == MAP_FAILED) { ret = -1; - pr_perror("Unable to reserve memory (%lu bytes)", vmas->priv_size); + pr_perror("Unable to reserve memory (%lu bytes)", vmas->rst_priv_size); goto out; } old_premmapped_addr = rsti(t)->premmapped_addr; old_premmapped_len = rsti(t)->premmapped_len; rsti(t)->premmapped_addr = addr; - rsti(t)->premmapped_len = vmas->priv_size; + rsti(t)->premmapped_len = vmas->rst_priv_size; ret = open_page_read(vpid(t), &pr, PR_TASK); if (ret <= 0) diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 4c127f264..0e8b6f209 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -660,14 +660,15 @@ static int vma_list_add(struct vma_area *vma_area, unsigned long pages; pages = vma_area_len(vma_area) / PAGE_SIZE; - vma_area_list->priv_size += pages; - vma_area_list->priv_longest = max(vma_area_list->priv_longest, pages); + vma_area_list->nr_priv_pages += pages; + vma_area_list->nr_priv_pages_longest = + max(vma_area_list->nr_priv_pages_longest, pages); } else if (vma_area_is(vma_area, VMA_ANON_SHARED)) { unsigned long pages; pages = vma_area_len(vma_area) / PAGE_SIZE; - vma_area_list->shared_longest = - max(vma_area_list->shared_longest, pages); + vma_area_list->nr_shared_pages_longest = + max(vma_area_list->nr_shared_pages_longest, pages); } *prev_vfi = *vfi; From 43ac528cb946ce8d9c07368c4f2de94684583227 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:38:04 +0300 Subject: [PATCH 2122/4375] mem/page-xfer: Add log prefix Signed-off-by: Cyrill Gorcunov Reviewed-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/page-xfer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/criu/page-xfer.c b/criu/page-xfer.c index f74716100..75e135c66 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -7,6 +7,9 @@ #include #include +#undef LOG_PREFIX +#define LOG_PREFIX "page-xfer: " + #include "types.h" #include "cr_options.h" #include "servicefd.h" From 7eec03bd958d04e96a81069676205fc4c20096d2 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:38:05 +0300 Subject: [PATCH 2123/4375] mem/pmc: Use pr_warn_once if cache is disabled No need to spam on every pmc_init call. Signed-off-by: Cyrill Gorcunov Reviewed-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/pagemap-cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/pagemap-cache.c b/criu/pagemap-cache.c index a1c2d42f4..c80776123 100644 --- a/criu/pagemap-cache.c +++ b/criu/pagemap-cache.c @@ -56,7 +56,7 @@ int pmc_init(pmc_t *pmc, pid_t pid, const struct list_head *vma_head, size_t siz goto err; if (pagemap_cache_disabled) - pr_debug("The pagemap cache is disabled\n"); + pr_warn_once("The pagemap cache is disabled\n"); if (kdat.pmap == PM_DISABLED) { /* From cb7b013dd01b79fb31e6e855ee61b718906dd573 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:38:06 +0300 Subject: [PATCH 2124/4375] mem/pmc: Print pid for debug sake When logs are massive it is convenient for grepping. Signed-off-by: Cyrill Gorcunov Reviewed-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/pagemap-cache.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/criu/pagemap-cache.c b/criu/pagemap-cache.c index c80776123..61ab09387 100644 --- a/criu/pagemap-cache.c +++ b/criu/pagemap-cache.c @@ -105,8 +105,8 @@ static int pmc_fill_cache(pmc_t *pmc, const struct vma_area *vma) pmc->start = vma->e->start; pmc->end = vma->e->end; - pr_debug("filling VMA %lx-%lx (%zuK) [l:%lx h:%lx]\n", - (long)vma->e->start, (long)vma->e->end, len >> 10, low, high); + pr_debug("%d: filling VMA %lx-%lx (%zuK) [l:%lx h:%lx]\n", + pmc->pid, (long)vma->e->start, (long)vma->e->end, len >> 10, low, high); /* * If we meet a small VMA, lets try to fit 2M cache @@ -123,8 +123,8 @@ static int pmc_fill_cache(pmc_t *pmc, const struct vma_area *vma) size_t size_cov = len; size_t nr_vmas = 1; - pr_debug("\t%16lx-%-16lx nr:%-5zu cov:%zu\n", - (long)vma->e->start, (long)vma->e->end, nr_vmas, size_cov); + pr_debug("\t%d: %16lx-%-16lx nr:%-5zu cov:%zu\n", + pmc->pid, (long)vma->e->start, (long)vma->e->end, nr_vmas, size_cov); list_for_each_entry_continue(vma, pmc->vma_head, list) { if (vma->e->start > high || vma->e->end > high) @@ -134,8 +134,8 @@ static int pmc_fill_cache(pmc_t *pmc, const struct vma_area *vma) size_cov += vma_area_len(vma); nr_vmas++; - pr_debug("\t%16lx-%-16lx nr:%-5zu cov:%zu\n", - (long)vma->e->start, (long)vma->e->end, nr_vmas, size_cov); + pr_debug("\t%d: %16lx-%-16lx nr:%-5zu cov:%zu\n", + pmc->pid, (long)vma->e->start, (long)vma->e->end, nr_vmas, size_cov); } if (nr_vmas > 1) { @@ -145,9 +145,9 @@ static int pmc_fill_cache(pmc_t *pmc, const struct vma_area *vma) * allows us to save a couple of code bytes. */ pmc->end = high; - pr_debug("\tcache mode [l:%lx h:%lx]\n", pmc->start, pmc->end); + pr_debug("\t%d: cache mode [l:%lx h:%lx]\n", pmc->pid, pmc->start, pmc->end); } else - pr_debug("\tsimple mode [l:%lx h:%lx]\n", pmc->start, pmc->end); + pr_debug("\t%d: simple mode [l:%lx h:%lx]\n", pmc->pid, pmc->start, pmc->end); } size_map = PAGEMAP_LEN(pmc->end - pmc->start); From 0319d1bf2e273295dea3fa8699519e7ca8579823 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:38:07 +0300 Subject: [PATCH 2125/4375] mem/page-pipe: Use xrealloc_safe in page_pipe_add_hole To shrink code a bit. Signed-off-by: Cyrill Gorcunov Reviewed-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/page-pipe.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/criu/page-pipe.c b/criu/page-pipe.c index 534380b0f..a8216962d 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -298,14 +298,12 @@ int page_pipe_add_hole(struct page_pipe *pp, unsigned long addr, unsigned int flags) { if (pp->free_hole >= pp->nr_holes) { - pp->holes = xrealloc(pp->holes, - (pp->nr_holes + PP_HOLES_BATCH) * sizeof(struct iovec)); - if (!pp->holes) + size_t new_size = (pp->nr_holes + PP_HOLES_BATCH) * sizeof(struct iovec); + if (xrealloc_safe(&pp->holes, new_size)) return -1; - pp->hole_flags = xrealloc(pp->hole_flags, - (pp->nr_holes + PP_HOLES_BATCH) * sizeof(unsigned int)); - if(!pp->hole_flags) + new_size = (pp->nr_holes + PP_HOLES_BATCH) * sizeof(unsigned int); + if (xrealloc_safe(&pp->hole_flags, new_size)) return -1; pp->nr_holes += PP_HOLES_BATCH; From d999a9e07951ceda18b43dd8658924d29179b886 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:38:08 +0300 Subject: [PATCH 2126/4375] mem/shmem: Use xrealloc_safe in expand_shmem Signed-off-by: Cyrill Gorcunov Reviewed-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/shmem.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/shmem.c b/criu/shmem.c index bc9f23bd7..3c2811398 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -197,8 +197,7 @@ static int expand_shmem(struct shmem_info *si, unsigned long new_size) BUG_ON(new_map_size < map_size); - si->pstate_map = xrealloc(si->pstate_map, new_map_size); - if (!si->pstate_map) + if (xrealloc_safe(&si->pstate_map, new_map_size)) return -1; memzero(si->pstate_map + nr_map_items, new_map_size - map_size); return 0; From 67d5dbb995926e4d28b6b3b76e43c342953ed21e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 20:47:10 +0300 Subject: [PATCH 2127/4375] mem/shmem: More elegant entries declaration Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/shmem.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/criu/shmem.c b/criu/shmem.c index 3c2811398..a183460a7 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -179,11 +179,12 @@ static void set_pstate(unsigned long *pstate_map, unsigned long pfn, static int expand_shmem(struct shmem_info *si, unsigned long new_size) { - unsigned long nr_pages, nr_map_items, map_size, - nr_new_map_items, new_map_size, old_size; + unsigned long nr_pages, nr_map_items, map_size; + unsigned long nr_new_map_items, new_map_size, old_size; old_size = si->size; si->size = new_size; + if (!is_shmem_tracking_en()) return 0; From 92717977cd507e21c0aa6f0948cde456da91a6bd Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:38:10 +0300 Subject: [PATCH 2128/4375] mem/shmem: Use xmalloc in collect_sysv_shmem To get error message in log if no memory available. Signed-off-by: Cyrill Gorcunov Reviewed-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/shmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/shmem.c b/criu/shmem.c index a183460a7..cf35873a7 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -234,7 +234,7 @@ int collect_sysv_shmem(unsigned long shmid, unsigned long size) * Tasks will not modify this object, so don't * shmalloc() as we do it for anon shared mem */ - si = malloc(sizeof(*si)); + si = xmalloc(sizeof(*si)); if (!si) return -1; From c01da212da56144b4aa07fdd63ae1e47ca51e3ba Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 5 Jul 2019 18:38:11 +0300 Subject: [PATCH 2129/4375] mem/shmem: Fix typos for_each_shmem macro Since we use _i as a counter in macro declaration we should use it as a reference. This macro simply happen to work now because of being called with variable i declarated in the caller code. Signed-off-by: Cyrill Gorcunov Reviewed-by: Mike Rapoport Signed-off-by: Andrei Vagin --- criu/shmem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/shmem.c b/criu/shmem.c index cf35873a7..cee47dba7 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -43,8 +43,8 @@ #define SHMEM_HASH_SIZE 32 static struct hlist_head shmems_hash[SHMEM_HASH_SIZE]; -#define for_each_shmem(_i, _si) \ - for (i = 0; i < SHMEM_HASH_SIZE; i++) \ +#define for_each_shmem(_i, _si) \ + for (_i = 0; _i < SHMEM_HASH_SIZE; _i++) \ hlist_for_each_entry(_si, &shmems_hash[_i], h) struct shmem_info { From ba454407bf8217d28be97af8888be9e7cac22932 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 10 Jul 2019 18:47:56 +0100 Subject: [PATCH 2130/4375] make: Insert version macros in criu.h Including the version information of CRIU in criu.h is required by projects that use libcriu to preserve backward compatibility. Closes #738 Signed-off-by: Radostin Stoyanov --- lib/Makefile | 2 +- lib/c/criu.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 67c50b95a..f9b66701e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,6 +1,6 @@ CRIU_SO := libcriu.so CRIU_A := libcriu.a -UAPI_HEADERS := lib/c/criu.h images/rpc.proto +UAPI_HEADERS := lib/c/criu.h images/rpc.proto criu/include/version.h # # File to keep track of files installed by setup.py diff --git a/lib/c/criu.h b/lib/c/criu.h index 4462ce082..76f3547fc 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -21,8 +21,10 @@ #include +#include "version.h" + #ifdef __GNUG__ - extern "C" { + extern "C" { #endif enum criu_service_comm { From 104aaf383e884f87174b8cdc068ab1b29c9c1b18 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 17 Jul 2019 13:07:34 -0700 Subject: [PATCH 2131/4375] restorer: print errors if prctl syscalls failed Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 324a11e0c..2a7180d6a 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -328,10 +328,18 @@ static int restore_creds(struct thread_creds_args *args, int procfd, static inline int restore_pdeath_sig(struct thread_restore_args *ta) { - if (ta->pdeath_sig) - return sys_prctl(PR_SET_PDEATHSIG, ta->pdeath_sig, 0, 0, 0); - else + int ret; + + if (!ta->pdeath_sig) return 0; + + ret = sys_prctl(PR_SET_PDEATHSIG, ta->pdeath_sig, 0, 0, 0); + if (ret) { + pr_err("Unable to set PR_SET_PDEATHSIG(%d): %d\n", ta->pdeath_sig, ret); + return -1; + } + + return 0; } static int restore_dumpable_flag(MmEntry *mme) @@ -1237,10 +1245,18 @@ static bool vdso_needs_parking(struct task_restore_args *args) static inline int restore_child_subreaper(int child_subreaper) { - if (child_subreaper) - return sys_prctl(PR_SET_CHILD_SUBREAPER, child_subreaper, 0, 0, 0); - else + int ret; + + if (!child_subreaper) return 0; + + ret = sys_prctl(PR_SET_CHILD_SUBREAPER, child_subreaper, 0, 0, 0); + if (ret) { + pr_err("Unable to set PR_SET_CHILD_SUBREAPER(%d): %d\n", child_subreaper, ret); + return -1; + } + + return 0; } /* @@ -1364,8 +1380,10 @@ long __export_restore_task(struct task_restore_args *args) if (args->uffd > -1) { /* re-enable THP if we disabled it previously */ if (args->has_thp_enabled) { - if (sys_prctl(PR_SET_THP_DISABLE, 0, 0, 0, 0)) { - pr_err("Cannot re-enable THP\n"); + int ret; + ret = sys_prctl(PR_SET_THP_DISABLE, 0, 0, 0, 0); + if (ret) { + pr_err("Cannot re-enable THP: %d\n", ret); goto core_restore_end; } } From 1e2647f12393547f1d1b9c1e403f8ab75eb46ef5 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 17 Jul 2019 13:08:56 -0700 Subject: [PATCH 2132/4375] images: convert type of child_subreaper from int32 to bool Signed-off-by: Andrei Vagin --- images/core.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/core.proto b/images/core.proto index 9f3f870c9..c3dba6f6d 100644 --- a/images/core.proto +++ b/images/core.proto @@ -52,7 +52,7 @@ message task_core_entry { //optional int32 tty_nr = 16; //optional int32 tty_pgrp = 17; - optional int32 child_subreaper = 18; + optional bool child_subreaper = 18; } message task_kobj_ids_entry { From 9fe8960d89f009c8e9a3c6245aeac3b46b0120ca Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 29 Jul 2019 13:25:20 +0000 Subject: [PATCH 2133/4375] scripts: add possibility to override docker with podman To be able to run the test containers in scripts/build with podman this puts the name of the container runtime into $CONTAINER_RUNTIME. Now it can be overridden with make fedora-rawhide CONTAINER_RUNTIME=podman Signed-off-by: Adrian Reber --- scripts/build/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/build/Makefile b/scripts/build/Makefile index f333b214a..bb2e9ca9d 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -2,6 +2,7 @@ QEMU_ARCHES := armv7hf aarch64 ppc64le s390x fedora-rawhide-aarch64 # require qe ARCHES := $(QEMU_ARCHES) x86_64 fedora-asan fedora-rawhide centos TARGETS := $(ARCHES) alpine TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) +CONTAINER_RUNTIME := docker all: $(TARGETS) $(TARGETS_CLANG) .PHONY: all @@ -27,8 +28,8 @@ $(QEMU_ARCHES): qemu-user-static binfmt_misc $(TARGETS): mkdir -p $(HOME)/.ccache mv $(HOME)/.ccache ../../ - docker build -t criu-$@ -f Dockerfile.$@ $(DB_CC) $(DB_ENV) ../.. - docker run criu-$@ tar c -C /tmp .ccache | tar x -C $(HOME) + $(CONTAINER_RUNTIME) build -t criu-$@ -f Dockerfile.$@ $(DB_CC) $(DB_ENV) ../.. + $(CONTAINER_RUNTIME) run criu-$@ tar c -C /tmp .ccache | tar x -C $(HOME) .PHONY: $(TARGETS) # Clang builds add some Docker build env From 229a8ab06b23e651b17b14a04939e8c2c2024ca5 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 29 Jul 2019 13:51:21 +0000 Subject: [PATCH 2134/4375] scripts: remove python2 from Fedora Dockerfiles More and more python2 packages are being removed from future Fedora releases. This removes python2 packages explicitly listed in CRIU's Dockerfiles, which all are not required for the current level of testing. Signed-off-by: Adrian Reber --- scripts/build/Dockerfile.fedora.tmpl | 5 ----- 1 file changed, 5 deletions(-) diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index 965309623..94f112671 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -18,14 +18,9 @@ RUN dnf install -y \ procps-ng \ protobuf-c-devel \ protobuf-devel \ - python2-protobuf \ - python2 \ - # Starting with Fedora 28 this is python2-ipaddress python-ipaddress \ - # Starting with Fedora 28 this is python2-pyyaml python-yaml \ python3-pip \ - python2-future \ python3-PyYAML \ python3-future \ python3-protobuf \ From 77efcde96dd17dff942bf7677f159c9a9369d622 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 29 Jul 2019 15:28:08 +0300 Subject: [PATCH 2135/4375] mount: fix inconsistent return and goto err alternation Signed-off-by: Pavel Tikhomirov --- criu/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/mount.c b/criu/mount.c index c03a435c5..486d01719 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2327,7 +2327,7 @@ out: if (restore_shared_options(mi, private, mi->shared_id && !shared, mi->master_id && !master)) - return -1; + goto err; mi->mounted = true; exit_code = 0; From cd87a628e14c68c3bb30988df56d04e373079435 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 29 Jul 2019 21:34:51 +0100 Subject: [PATCH 2136/4375] scripts: Remove yaml/ipaddress Py2 fedora modules Signed-off-by: Radostin Stoyanov --- scripts/build/Dockerfile.fedora.tmpl | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index 94f112671..15460665a 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -18,8 +18,6 @@ RUN dnf install -y \ procps-ng \ protobuf-c-devel \ protobuf-devel \ - python-ipaddress \ - python-yaml \ python3-pip \ python3-PyYAML \ python3-future \ From 2a683849b9b3619f7f5a619192e309c0993193c3 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 29 Jul 2019 21:42:19 +0100 Subject: [PATCH 2137/4375] scripts: Set PYTHON=python3 in Fedora Dockerfiles Signed-off-by: Radostin Stoyanov --- scripts/build/Dockerfile.fedora.tmpl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index 15460665a..74348f3e6 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -37,6 +37,7 @@ RUN dnf install -y \ RUN dnf install -y --allowerasing coreutils RUN ln -sf python3 /usr/bin/python +ENV PYTHON=python3 COPY . /criu WORKDIR /criu From 5721e6100037b4e51a67548f7eecd7f67432b7af Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 31 Jul 2019 07:02:10 +0100 Subject: [PATCH 2138/4375] scripts: Install flake8 with dnf in Fedora In the Fedora tests we install python3-pip only to install flake8. This is not necessary as there is a Fedora package for flake8. Signed-off-by: Radostin Stoyanov --- scripts/build/Dockerfile.fedora.tmpl | 2 +- scripts/travis/travis-tests | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index 74348f3e6..280ce1cdd 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -18,7 +18,7 @@ RUN dnf install -y \ procps-ng \ protobuf-c-devel \ protobuf-devel \ - python3-pip \ + python3-flake8 \ python3-PyYAML \ python3-future \ python3-protobuf \ diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 348daca1f..c055860fd 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -163,7 +163,9 @@ ip net add test make -C test/others/shell-job -pip install flake8 +if ! [ -x "$(command -v flake8)" ]; then + pip install flake8 +fi make lint # Check that help output fits into 80 columns From b25d1facaedae7a1bd7154fe28f909c7e961a93c Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 31 Jul 2019 07:08:20 +0100 Subject: [PATCH 2139/4375] pb2dict: Disable undefined name 'basestring' The following error is falsely reported by flake8: lib/py/images/pb2dict.py:266:24: F821 undefined name 'basestring' This error occurs because `basestring` is not available in Python 3, however the if condition on the line above ensures that this error will not occur at run time. Signed-off-by: Radostin Stoyanov --- lib/py/images/pb2dict.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index c4ce736e8..6b4a772c7 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -224,7 +224,7 @@ def get_bytes_dec(field): def is_string(value): # Python 3 compatibility if "basestring" in __builtins__: - string_types = basestring + string_types = basestring # noqa: F821 else: string_types = (str, bytes) return isinstance(value, string_types) From d2d6e3f5379ce9a8cfa320bb07113995a8191bfb Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 25 Jul 2019 23:01:07 +0100 Subject: [PATCH 2140/4375] compel/log: Use enum as parameter for std_log_set_loglevel() Doesn't change uapi, but makes it a bit more friendly and documented which loglevel means what for foreign user. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/plugins/include/uapi/std/log.h | 4 +++- compel/plugins/std/log.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compel/plugins/include/uapi/std/log.h b/compel/plugins/include/uapi/std/log.h index fbd1803bb..7b27b1250 100644 --- a/compel/plugins/include/uapi/std/log.h +++ b/compel/plugins/include/uapi/std/log.h @@ -1,10 +1,12 @@ #ifndef COMPEL_PLUGIN_STD_LOG_H__ #define COMPEL_PLUGIN_STD_LOG_H__ +#include "compel/loglevels.h" + #define STD_LOG_SIMPLE_CHUNK 256 extern void std_log_set_fd(int fd); -extern void std_log_set_loglevel(unsigned int level); +extern void std_log_set_loglevel(enum __compel_log_levels level); extern void std_log_set_start(struct timeval *tv); extern int std_vprint_num(char *buf, int blen, int num, char **ps); extern void std_sprintf(char output[STD_LOG_SIMPLE_CHUNK], const char *format, ...) diff --git a/compel/plugins/std/log.c b/compel/plugins/std/log.c index 403ea46f7..06b9894ae 100644 --- a/compel/plugins/std/log.c +++ b/compel/plugins/std/log.c @@ -120,7 +120,7 @@ void std_log_set_fd(int fd) logfd = fd; } -void std_log_set_loglevel(unsigned int level) +void std_log_set_loglevel(enum __compel_log_levels level) { cur_loglevel = level; } From 28949d5fb80d4cf8998fdda69b02800dadf7e544 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 25 Jul 2019 23:01:08 +0100 Subject: [PATCH 2141/4375] compel/std/uapi: Provide setter for gettimeofday() Provide a way to set gettimeofday() function for an infected task. CRIU's parasite & restorer are very voluble as more logs are better than lesser in terms of bug investigations. In all modern kernels there is a way to get time without entering kernel: vdso. So, add a way to reduce the cost of logging without making it less valuable. [I'm not particularly fond of std_log_set_gettimeofday() name, so if someone can come with a better naming - I'm up for a change] Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/plugins/include/uapi/std/log.h | 12 ++++++++++++ compel/plugins/std/log.c | 16 +++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/compel/plugins/include/uapi/std/log.h b/compel/plugins/include/uapi/std/log.h index 7b27b1250..f21b6df0d 100644 --- a/compel/plugins/include/uapi/std/log.h +++ b/compel/plugins/include/uapi/std/log.h @@ -8,6 +8,18 @@ extern void std_log_set_fd(int fd); extern void std_log_set_loglevel(enum __compel_log_levels level); extern void std_log_set_start(struct timeval *tv); + +/* + * Provides a function to get time *in the infected task* for log timings. + * Expected use-case: address on the vdso page to get time. + * If not set or called with NULL - compel will use raw syscall, + * which requires enter in the kernel and as a result affects performance. + */ +typedef int (*gettimeofday_t)(struct timeval *tv, struct timezone *tz); +extern void std_log_set_gettimeofday(gettimeofday_t gtod); +/* std plugin helper to get time (hopefully, efficiently) */ +extern int std_gettimeofday(struct timeval *tv, struct timezone *tz); + extern int std_vprint_num(char *buf, int blen, int num, char **ps); extern void std_sprintf(char output[STD_LOG_SIMPLE_CHUNK], const char *format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); diff --git a/compel/plugins/std/log.c b/compel/plugins/std/log.c index 06b9894ae..f9be432ea 100644 --- a/compel/plugins/std/log.c +++ b/compel/plugins/std/log.c @@ -16,6 +16,7 @@ struct simple_buf { static int logfd = -1; static int cur_loglevel = COMPEL_DEFAULT_LOGLEVEL; static struct timeval start; +static gettimeofday_t __std_gettimeofday; static void sbuf_log_flush(struct simple_buf *b); @@ -54,7 +55,7 @@ static void sbuf_log_init(struct simple_buf *b) if (start.tv_sec != 0) { struct timeval now; - sys_gettimeofday(&now, NULL); + std_gettimeofday(&now, NULL); timediff(&start, &now); /* Seconds */ @@ -130,6 +131,19 @@ void std_log_set_start(struct timeval *s) start = *s; } +void std_log_set_gettimeofday(gettimeofday_t gtod) +{ + __std_gettimeofday = gtod; +} + +int std_gettimeofday(struct timeval *tv, struct timezone *tz) +{ + if (__std_gettimeofday != NULL) + return __std_gettimeofday(tv, tz); + + return sys_gettimeofday(tv, tz); +} + static void print_string(const char *msg, struct simple_buf *b) { while (*msg) { From 2d521f3c9354719cb2bf488ad0a4c308b9f4c376 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 25 Jul 2019 23:01:09 +0100 Subject: [PATCH 2142/4375] vdso/restorer: Try best to preserve vdso during restore vdso will be used in restorer for timings in logs - try to keep it during restore process. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/parasite-vdso.h | 2 +- criu/pie/parasite-vdso.c | 5 ++- criu/pie/restorer.c | 72 +++++++++++++++++++++++++----------- 3 files changed, 55 insertions(+), 24 deletions(-) diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index 3cf67bbb3..cf15d135f 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -84,7 +84,7 @@ static inline bool is_vdso_mark(void *addr) extern int vdso_do_park(struct vdso_maps *rt, unsigned long park_at, unsigned long park_size); extern int vdso_map_compat(unsigned long map_at); -extern int vdso_proxify(struct vdso_symtable *sym_rt, +extern int vdso_proxify(struct vdso_symtable *sym_rt, bool *added_proxy, unsigned long vdso_rt_parked_at, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso, bool force_trampolines); diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 00bc2bffa..c4197d0cf 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -242,7 +242,8 @@ static int add_vdso_proxy(VmaEntry *vma_vdso, VmaEntry *vma_vvar, return 0; } -int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, +int vdso_proxify(struct vdso_symtable *sym_rt, bool *added_proxy, + unsigned long vdso_rt_parked_at, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso, bool force_trampolines) { @@ -289,11 +290,13 @@ int vdso_proxify(struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at, vma_vvar ? (unsigned long)vma_vvar->start : VVAR_BAD_ADDR, vma_vvar ? (unsigned long)vma_vvar->end : VVAR_BAD_ADDR); + *added_proxy = false; if (blobs_matches(vma_vdso, vma_vvar, &s, sym_rt) && !force_trampolines) { return remap_rt_vdso(vma_vdso, vma_vvar, sym_rt, vdso_rt_parked_at); } + *added_proxy = true; return add_vdso_proxy(vma_vdso, vma_vvar, &s, sym_rt, vdso_rt_parked_at, compat_vdso); } diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 2a7180d6a..565ea0167 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1215,34 +1215,39 @@ static int wait_zombies(struct task_restore_args *task_args) return 0; } -static bool vdso_unmapped(struct task_restore_args *args) +static bool can_restore_vdso(struct task_restore_args *args) { + struct vdso_maps *rt = &args->vdso_maps_rt; + bool had_vdso = false, had_vvar = false; unsigned int i; - /* Don't park rt-vdso or rt-vvar if dumpee doesn't have them */ for (i = 0; i < args->vmas_n; i++) { VmaEntry *vma = &args->vmas[i]; - if (vma_entry_is(vma, VMA_AREA_VDSO) || - vma_entry_is(vma, VMA_AREA_VVAR)) - return false; + if (vma_entry_is(vma, VMA_AREA_VDSO)) + had_vdso = true; + if (vma_entry_is(vma, VMA_AREA_VVAR)) + had_vvar = true; } + if (had_vdso && (rt->vdso_start == VDSO_BAD_ADDR)) { + pr_err("Task had vdso, restorer doesn't\n"); + return false; + } + + /* + * There is a use-case for restoring vvar alone: valgrind (see #488). + * On the other side, we expect that vvar is touched by application + * only from vdso. So, we can put a stale page and proceed restore + * if kernel doesn't provide vvar [but provides vdso, if needede. + * Just warn aloud that we don't like it. + */ + if (had_vvar && (rt->vvar_start == VVAR_BAD_ADDR)) + pr_warn("Can't restore vvar - continuing regardless\n"); + return true; } -static bool vdso_needs_parking(struct task_restore_args *args) -{ - /* Compatible vDSO will be mapped, not moved */ - if (args->compatible_mode) - return false; - - if (args->can_map_vdso) - return false; - - return !vdso_unmapped(args); -} - static inline int restore_child_subreaper(int child_subreaper) { int ret; @@ -1279,6 +1284,7 @@ long __export_restore_task(struct task_restore_args *args) k_rtsigset_t to_block; pid_t my_pid = sys_getpid(); rt_sigaction_t act; + bool has_vdso_proxy; bootstrap_start = args->bootstrap_start; bootstrap_len = args->bootstrap_len; @@ -1325,7 +1331,21 @@ long __export_restore_task(struct task_restore_args *args) pr_debug("lazy-pages: uffd %d\n", args->uffd); } - if (vdso_needs_parking(args)) { + /* + * Park vdso/vvar in a safe place if architecture doesn't support + * mapping them with arch_prctl(). + * Always preserve/map rt-vdso pair if it's possible, regardless + * it's presence in original task: vdso will be used for fast + * getttimeofday() in restorer's log timings. + */ + if (!args->can_map_vdso) { + /* It's already checked in kdat, but let's check again */ + if (args->compatible_mode) { + pr_err("Compatible mode without vdso map support\n"); + goto core_restore_end; + } + if (!can_restore_vdso(args)) + goto core_restore_end; if (vdso_do_park(&args->vdso_maps_rt, args->vdso_rt_parked_at, vdso_rt_size)) goto core_restore_end; @@ -1336,9 +1356,12 @@ long __export_restore_task(struct task_restore_args *args) goto core_restore_end; /* Map vdso that wasn't parked */ - if (!vdso_unmapped(args) && args->can_map_vdso) { - if (arch_map_vdso(args->vdso_rt_parked_at, - args->compatible_mode) < 0) { + if (args->can_map_vdso) { + int err = arch_map_vdso(args->vdso_rt_parked_at, + args->compatible_mode); + + if (err < 0) { + pr_err("Failed to map vdso %d\n", err); goto core_restore_end; } } @@ -1473,11 +1496,16 @@ long __export_restore_task(struct task_restore_args *args) /* * Proxify vDSO. */ - if (vdso_proxify(&args->vdso_maps_rt.sym, args->vdso_rt_parked_at, + if (vdso_proxify(&args->vdso_maps_rt.sym, &has_vdso_proxy, + args->vdso_rt_parked_at, args->vmas, args->vmas_n, args->compatible_mode, fault_injected(FI_VDSO_TRAMPOLINES))) goto core_restore_end; + /* unmap rt-vdso with restorer blob after restore's finished */ + if (!has_vdso_proxy) + vdso_rt_size = 0; + /* * Walk though all VMAs again to drop PROT_WRITE * if it was not there. From 53c2fdc955d8966100c2abd9580d5a065710c31a Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 25 Jul 2019 23:01:10 +0100 Subject: [PATCH 2143/4375] vdso/restorer: Always track vdso/vvar positions in vdso_maps_rt For simplicity, make them always valid in restorer. rt->vdso_start will be used to calculate gettimeofday() address. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/parasite-vdso.h | 3 +- criu/pie/parasite-vdso.c | 81 +++++++++++++----------------------- criu/pie/restorer.c | 44 ++++++++++++++------ 3 files changed, 60 insertions(+), 68 deletions(-) diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index cf15d135f..872105133 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -84,8 +84,7 @@ static inline bool is_vdso_mark(void *addr) extern int vdso_do_park(struct vdso_maps *rt, unsigned long park_at, unsigned long park_size); extern int vdso_map_compat(unsigned long map_at); -extern int vdso_proxify(struct vdso_symtable *sym_rt, bool *added_proxy, - unsigned long vdso_rt_parked_at, +extern int vdso_proxify(struct vdso_maps *rt, bool *added_proxy, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso, bool force_trampolines); extern int vdso_redirect_calls(unsigned long base_to, unsigned long base_from, diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index c4197d0cf..848883b42 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -24,19 +24,19 @@ #endif #define LOG_PREFIX "vdso: " - -static int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size) +/* Updates @from on success */ +static int vdso_remap(char *who, unsigned long *from, unsigned long to, size_t size) { unsigned long addr; - pr_debug("Remap %s %lx -> %lx\n", who, from, to); + pr_debug("Remap %s %lx -> %lx\n", who, *from, to); - addr = sys_mremap(from, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, to); + addr = sys_mremap(*from, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, to); if (addr != to) { - pr_err("Unable to remap %lx -> %lx %lx\n", - from, to, addr); + pr_err("Unable to remap %lx -> %lx %lx\n", *from, to, addr); return -1; } + *from = addr; return 0; } @@ -57,7 +57,7 @@ int vdso_do_park(struct vdso_maps *rt, unsigned long park_at, if (rt->vvar_start == VVAR_BAD_ADDR) { BUG_ON(vdso_size < park_size); - return vdso_remap("rt-vdso", rt->vdso_start, + return vdso_remap("rt-vdso", &rt->vdso_start, rt_vdso_park, vdso_size); } @@ -68,8 +68,8 @@ int vdso_do_park(struct vdso_maps *rt, unsigned long park_at, else rt_vdso_park = park_at + vvar_size; - ret = vdso_remap("rt-vdso", rt->vdso_start, rt_vdso_park, vdso_size); - ret |= vdso_remap("rt-vvar", rt->vvar_start, rt_vvar_park, vvar_size); + ret = vdso_remap("rt-vdso", &rt->vdso_start, rt_vdso_park, vdso_size); + ret |= vdso_remap("rt-vvar", &rt->vvar_start, rt_vvar_park, vvar_size); return ret; } @@ -144,10 +144,8 @@ static bool blobs_matches(VmaEntry *vdso_img, VmaEntry *vvar_img, * to dumpee position without generating any proxy. */ static int remap_rt_vdso(VmaEntry *vma_vdso, VmaEntry *vma_vvar, - struct vdso_symtable *sym_rt, unsigned long vdso_rt_parked_at) + struct vdso_maps *rt) { - unsigned long rt_vvar_addr = vdso_rt_parked_at; - unsigned long rt_vdso_addr = vdso_rt_parked_at; void *remap_addr; int ret; @@ -164,8 +162,8 @@ static int remap_rt_vdso(VmaEntry *vma_vdso, VmaEntry *vma_vvar, } if (!vma_vvar) { - return vdso_remap("rt-vdso", rt_vdso_addr, - vma_vdso->start, sym_rt->vdso_size); + return vdso_remap("rt-vdso", &rt->vdso_start, + vma_vdso->start, rt->sym.vdso_size); } remap_addr = (void *)(uintptr_t)vma_vvar->start; @@ -174,15 +172,10 @@ static int remap_rt_vdso(VmaEntry *vma_vdso, VmaEntry *vma_vvar, return -1; } - if (vma_vdso->start < vma_vvar->start) - rt_vvar_addr = vdso_rt_parked_at + sym_rt->vdso_size; - else - rt_vdso_addr = vdso_rt_parked_at + sym_rt->vvar_size; - - ret = vdso_remap("rt-vdso", rt_vdso_addr, - vma_vdso->start, sym_rt->vdso_size); - ret |= vdso_remap("rt-vvar", rt_vvar_addr, - vma_vvar->start, sym_rt->vvar_size); + ret = vdso_remap("rt-vdso", &rt->vdso_start, + vma_vdso->start, rt->sym.vdso_size); + ret |= vdso_remap("rt-vvar", &rt->vvar_start, + vma_vvar->start, rt->sym.vvar_size); return ret; } @@ -193,28 +186,14 @@ static int remap_rt_vdso(VmaEntry *vma_vdso, VmaEntry *vma_vvar, * to operate as proxy vdso. */ static int add_vdso_proxy(VmaEntry *vma_vdso, VmaEntry *vma_vvar, - struct vdso_symtable *sym_img, struct vdso_symtable *sym_rt, - unsigned long vdso_rt_parked_at, bool compat_vdso) + struct vdso_symtable *sym_img, struct vdso_maps *rt, + bool compat_vdso) { - unsigned long rt_vvar_addr = vdso_rt_parked_at; - unsigned long rt_vdso_addr = vdso_rt_parked_at; unsigned long orig_vvar_addr = vma_vvar ? vma_vvar->start : VVAR_BAD_ADDR; pr_info("Runtime vdso mismatches dumpee, generate proxy\n"); - /* - * Don't forget to shift if vvar is before vdso. - */ - if (sym_rt->vvar_size == VVAR_BAD_SIZE) { - rt_vvar_addr = VVAR_BAD_ADDR; - } else { - if (sym_rt->vdso_before_vvar) - rt_vvar_addr += sym_rt->vdso_size; - else - rt_vdso_addr += sym_rt->vvar_size; - } - /* * Note: we assume that after first migration with inserted * rt-vdso and trampoilines on the following migrations @@ -223,8 +202,8 @@ static int add_vdso_proxy(VmaEntry *vma_vdso, VmaEntry *vma_vvar, * jumps, so we can't remove them if on the following migration * found that number of symbols in vdso has decreased. */ - if (vdso_redirect_calls(rt_vdso_addr, vma_vdso->start, - sym_rt, sym_img, compat_vdso)) { + if (vdso_redirect_calls(rt->vdso_start, vma_vdso->start, + &rt->sym, sym_img, compat_vdso)) { pr_err("Failed to proxify dumpee contents\n"); return -1; } @@ -234,16 +213,15 @@ static int add_vdso_proxy(VmaEntry *vma_vdso, VmaEntry *vma_vvar, * routine we could detect this vdso and do not dump it, since * it's auto-generated every new session if proxy required. */ - sys_mprotect((void *)rt_vdso_addr, sym_rt->vdso_size, PROT_WRITE); - vdso_put_mark((void *)rt_vdso_addr, rt_vvar_addr, - vma_vdso->start, orig_vvar_addr); - sys_mprotect((void *)rt_vdso_addr, sym_rt->vdso_size, VDSO_PROT); + sys_mprotect((void *)rt->vdso_start, rt->sym.vdso_size, PROT_WRITE); + vdso_put_mark((void *)rt->vdso_start, rt->vvar_start, + vma_vdso->start, orig_vvar_addr); + sys_mprotect((void *)rt->vdso_start, rt->sym.vdso_size, VDSO_PROT); return 0; } -int vdso_proxify(struct vdso_symtable *sym_rt, bool *added_proxy, - unsigned long vdso_rt_parked_at, +int vdso_proxify(struct vdso_maps *rt, bool *added_proxy, VmaEntry *vmas, size_t nr_vmas, bool compat_vdso, bool force_trampolines) { @@ -291,12 +269,9 @@ int vdso_proxify(struct vdso_symtable *sym_rt, bool *added_proxy, vma_vvar ? (unsigned long)vma_vvar->end : VVAR_BAD_ADDR); *added_proxy = false; - if (blobs_matches(vma_vdso, vma_vvar, &s, sym_rt) && !force_trampolines) { - return remap_rt_vdso(vma_vdso, vma_vvar, - sym_rt, vdso_rt_parked_at); - } + if (blobs_matches(vma_vdso, vma_vvar, &s, &rt->sym) && !force_trampolines) + return remap_rt_vdso(vma_vdso, vma_vvar, rt); *added_proxy = true; - return add_vdso_proxy(vma_vdso, vma_vvar, &s, sym_rt, - vdso_rt_parked_at, compat_vdso); + return add_vdso_proxy(vma_vdso, vma_vvar, &s, rt, compat_vdso); } diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 565ea0167..d60fdbebf 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1264,6 +1264,32 @@ static inline int restore_child_subreaper(int child_subreaper) return 0; } +static int map_vdso(struct task_restore_args *args, bool compatible) +{ + struct vdso_maps *rt = &args->vdso_maps_rt; + int err; + + err = arch_map_vdso(args->vdso_rt_parked_at, compatible); + if (err < 0) { + pr_err("Failed to map vdso %d\n", err); + return err; + } + + if (rt->sym.vdso_before_vvar) { + rt->vdso_start = args->vdso_rt_parked_at; + /* kernel may provide only vdso */ + if (rt->sym.vvar_size != VVAR_BAD_SIZE) + rt->vvar_start = rt->vdso_start + rt->sym.vdso_size; + else + rt->vvar_start = VVAR_BAD_ADDR; + } else { + rt->vvar_start = args->vdso_rt_parked_at; + rt->vdso_start = rt->vvar_start + rt->sym.vvar_size; + } + + return 0; +} + /* * The main routine to restore task via sigreturn. * This one is very special, we never return there @@ -1356,15 +1382,8 @@ long __export_restore_task(struct task_restore_args *args) goto core_restore_end; /* Map vdso that wasn't parked */ - if (args->can_map_vdso) { - int err = arch_map_vdso(args->vdso_rt_parked_at, - args->compatible_mode); - - if (err < 0) { - pr_err("Failed to map vdso %d\n", err); - goto core_restore_end; - } - } + if (args->can_map_vdso && (map_vdso(args, args->compatible_mode) < 0)) + goto core_restore_end; /* Shift private vma-s to the left */ for (i = 0; i < args->vmas_n; i++) { @@ -1496,10 +1515,9 @@ long __export_restore_task(struct task_restore_args *args) /* * Proxify vDSO. */ - if (vdso_proxify(&args->vdso_maps_rt.sym, &has_vdso_proxy, - args->vdso_rt_parked_at, - args->vmas, args->vmas_n, args->compatible_mode, - fault_injected(FI_VDSO_TRAMPOLINES))) + if (vdso_proxify(&args->vdso_maps_rt, &has_vdso_proxy, + args->vmas, args->vmas_n, args->compatible_mode, + fault_injected(FI_VDSO_TRAMPOLINES))) goto core_restore_end; /* unmap rt-vdso with restorer blob after restore's finished */ From 90ecb82202f6e426644b4d8ae88757649abacf45 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 25 Jul 2019 23:01:11 +0100 Subject: [PATCH 2144/4375] restorer/parasite-vdso: Don't move vvar if failed to move vdso Also slight refactor. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/parasite-vdso.c | 51 +++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 848883b42..be90090de 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -25,7 +25,7 @@ #define LOG_PREFIX "vdso: " /* Updates @from on success */ -static int vdso_remap(char *who, unsigned long *from, unsigned long to, size_t size) +static int remap_one(char *who, unsigned long *from, unsigned long to, size_t size) { unsigned long addr; @@ -41,37 +41,38 @@ static int vdso_remap(char *who, unsigned long *from, unsigned long to, size_t s return 0; } +static int park_at(struct vdso_maps *rt, unsigned long vdso, unsigned long vvar) +{ + int ret; + + ret = remap_one("rt-vdso", &rt->vdso_start, vdso, rt->sym.vdso_size); + + if (ret || !vvar) + return ret; + + return remap_one("rt-vvar", &rt->vvar_start, vvar, rt->sym.vvar_size); +} + /* * Park runtime vDSO in some safe place where it can be accessible * from the restorer */ -int vdso_do_park(struct vdso_maps *rt, unsigned long park_at, - unsigned long park_size) +int vdso_do_park(struct vdso_maps *rt, unsigned long addr, unsigned long space) { unsigned long vvar_size = rt->sym.vvar_size; unsigned long vdso_size = rt->sym.vdso_size; - unsigned long rt_vvar_park = park_at; - unsigned long rt_vdso_park = park_at; - int ret; - if (rt->vvar_start == VVAR_BAD_ADDR) { - BUG_ON(vdso_size < park_size); - return vdso_remap("rt-vdso", &rt->vdso_start, - rt_vdso_park, vdso_size); + BUG_ON(vdso_size < space); + return park_at(rt, addr, 0); } - BUG_ON((vdso_size + vvar_size) < park_size); + BUG_ON((vdso_size + vvar_size) < space); if (rt->sym.vdso_before_vvar) - rt_vvar_park = park_at + vdso_size; + return park_at(rt, addr, addr + vvar_size); else - rt_vdso_park = park_at + vvar_size; - - ret = vdso_remap("rt-vdso", &rt->vdso_start, rt_vdso_park, vdso_size); - ret |= vdso_remap("rt-vvar", &rt->vvar_start, rt_vvar_park, vvar_size); - - return ret; + return park_at(rt, addr + vdso_size, addr); } #ifndef CONFIG_COMPAT @@ -147,7 +148,6 @@ static int remap_rt_vdso(VmaEntry *vma_vdso, VmaEntry *vma_vvar, struct vdso_maps *rt) { void *remap_addr; - int ret; pr_info("Runtime vdso/vvar matches dumpee, remap inplace\n"); @@ -161,10 +161,8 @@ static int remap_rt_vdso(VmaEntry *vma_vdso, VmaEntry *vma_vvar, return -1; } - if (!vma_vvar) { - return vdso_remap("rt-vdso", &rt->vdso_start, - vma_vdso->start, rt->sym.vdso_size); - } + if (!vma_vvar) + return park_at(rt, vma_vdso->start, 0); remap_addr = (void *)(uintptr_t)vma_vvar->start; if (sys_munmap(remap_addr, vma_entry_len(vma_vvar))) { @@ -172,12 +170,7 @@ static int remap_rt_vdso(VmaEntry *vma_vdso, VmaEntry *vma_vvar, return -1; } - ret = vdso_remap("rt-vdso", &rt->vdso_start, - vma_vdso->start, rt->sym.vdso_size); - ret |= vdso_remap("rt-vvar", &rt->vvar_start, - vma_vvar->start, rt->sym.vvar_size); - - return ret; + return park_at(rt, vma_vdso->start, vma_vvar->start); } /* From 23960fe60e448ad71b509b49ed03c8a20bae0228 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 25 Jul 2019 23:01:12 +0100 Subject: [PATCH 2145/4375] seccomp/restorer: Disable gtod from vdso in strict mode Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index d60fdbebf..9d49a8313 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -476,6 +476,23 @@ static int restore_seccomp(struct thread_restore_args *args) return 0; break; case SECCOMP_MODE_STRICT: + /* + * Disable gettimeofday() from vdso: it may use TSC + * which is restricted by kernel: + * + * static long seccomp_set_mode_strict(void) + * { + * [..] + * #ifdef TIF_NOTSC + * disable_TSC(); + * #endif + * [..] + * + * XXX: It may need to be fixed in kernel under + * PTRACE_O_SUSPEND_SECCOMP, but for now just get timings + * with a raw syscall instead of vdso. + */ + std_log_set_gettimeofday(NULL); ret = sys_prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, 0, 0, 0); if (ret < 0) { pr_err("seccomp: SECCOMP_MODE_STRICT returned %d on tid %d\n", From 9e5c0634ff2f3333c8be8561b03a66afe77b2e37 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 25 Jul 2019 23:01:13 +0100 Subject: [PATCH 2146/4375] vdso: Add compatible property to vdso_maps We need to differ compatible (ia32) vdso maps from x86_64. That dictates ABI on vdso code. According to that, the decision to (not) use gettimeofday() from vdso in 64-bit restorer. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/include/util-vdso.h | 1 + criu/vdso.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/criu/include/util-vdso.h b/criu/include/util-vdso.h index c74360c87..33b7411de 100644 --- a/criu/include/util-vdso.h +++ b/criu/include/util-vdso.h @@ -38,6 +38,7 @@ struct vdso_maps { unsigned long vdso_start; unsigned long vvar_start; struct vdso_symtable sym; + bool compatible; }; #define VDSO_SYMBOL_INIT { .offset = VDSO_BAD_ADDR, } diff --git a/criu/vdso.c b/criu/vdso.c index 257cbcd92..50b8b8dba 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -597,7 +597,8 @@ int vdso_init_restore(void) vdso_maps.sym = kdat.vdso_sym; #ifdef CONFIG_COMPAT - vdso_maps_compat.sym = kdat.vdso_sym_compat; + vdso_maps_compat.sym = kdat.vdso_sym_compat; + vdso_maps_compat.compatible = true; #endif return 0; @@ -621,7 +622,8 @@ int kerndat_vdso_fill_symtable(void) pr_err("Failed to fill compat vdso symtable\n"); return -1; } - kdat.vdso_sym_compat = vdso_maps_compat.sym; + vdso_maps_compat.compatible = true; + kdat.vdso_sym_compat = vdso_maps_compat.sym; #endif return 0; From 10a831689e160464b628b1d4e3e58da2439cd983 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 25 Jul 2019 23:01:14 +0100 Subject: [PATCH 2147/4375] restorer: Use gettimeofday() from rt-vdso for log timings Omit calling raw syscalls and use vdso for the purpose of logging. That will eliminate as much as one-syscall-per-PIE-message. Getting time without switching to kernel will speed up C/R, keeping logs as informative as they were. Fixes: #346 I haven't enabled vdso timings for ia32 applications as it needs more changes and complexity.. Maybe later. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/arch/aarch64/include/asm/vdso.h | 1 + criu/arch/arm/include/asm/vdso.h | 1 + criu/arch/ppc64/include/asm/vdso.h | 1 + criu/arch/s390/include/asm/vdso.h | 3 +- criu/arch/x86/include/asm/vdso.h | 3 +- criu/include/parasite-vdso.h | 1 + criu/pie/parasite-vdso.c | 59 +++++++++++++++++++++++++--- criu/pie/restorer.c | 2 + 8 files changed, 64 insertions(+), 7 deletions(-) diff --git a/criu/arch/aarch64/include/asm/vdso.h b/criu/arch/aarch64/include/asm/vdso.h index a7802a279..8a65e0947 100644 --- a/criu/arch/aarch64/include/asm/vdso.h +++ b/criu/arch/aarch64/include/asm/vdso.h @@ -10,6 +10,7 @@ * we should support at the moment. */ #define VDSO_SYMBOL_MAX 4 +#define VDSO_SYMBOL_GTOD 2 /* * Workaround for VDSO array symbol table's relocation. diff --git a/criu/arch/arm/include/asm/vdso.h b/criu/arch/arm/include/asm/vdso.h index cf9d500be..f57790ac2 100644 --- a/criu/arch/arm/include/asm/vdso.h +++ b/criu/arch/arm/include/asm/vdso.h @@ -10,6 +10,7 @@ * Poke from kernel file arch/arm/vdso/vdso.lds.S */ #define VDSO_SYMBOL_MAX 2 +#define VDSO_SYMBOL_GTOD 1 #define ARCH_VDSO_SYMBOLS \ "__vdso_clock_gettime", \ "__vdso_gettimeofday" diff --git a/criu/arch/ppc64/include/asm/vdso.h b/criu/arch/ppc64/include/asm/vdso.h index 9546e2460..6c92348d6 100644 --- a/criu/arch/ppc64/include/asm/vdso.h +++ b/criu/arch/ppc64/include/asm/vdso.h @@ -13,6 +13,7 @@ * inside the text page which should not be used as is from user space. */ #define VDSO_SYMBOL_MAX 10 +#define VDSO_SYMBOL_GTOD 5 #define ARCH_VDSO_SYMBOLS \ "__kernel_clock_getres", \ "__kernel_clock_gettime", \ diff --git a/criu/arch/s390/include/asm/vdso.h b/criu/arch/s390/include/asm/vdso.h index 63e7e0464..c54d848ad 100644 --- a/criu/arch/s390/include/asm/vdso.h +++ b/criu/arch/s390/include/asm/vdso.h @@ -8,7 +8,8 @@ * This is a minimal amount of symbols * we should support at the moment. */ -#define VDSO_SYMBOL_MAX 4 +#define VDSO_SYMBOL_MAX 4 +#define VDSO_SYMBOL_GTOD 0 /* * This definition is used in pie/util-vdso.c to initialize the vdso symbol diff --git a/criu/arch/x86/include/asm/vdso.h b/criu/arch/x86/include/asm/vdso.h index 046db2336..28ae2d15a 100644 --- a/criu/arch/x86/include/asm/vdso.h +++ b/criu/arch/x86/include/asm/vdso.h @@ -12,7 +12,8 @@ * This is a minimal amount of symbols * we should support at the moment. */ -#define VDSO_SYMBOL_MAX 6 +#define VDSO_SYMBOL_MAX 6 +#define VDSO_SYMBOL_GTOD 2 /* * XXX: we don't patch __kernel_vsyscall as it's too small: diff --git a/criu/include/parasite-vdso.h b/criu/include/parasite-vdso.h index 872105133..9ee32f2a7 100644 --- a/criu/include/parasite-vdso.h +++ b/criu/include/parasite-vdso.h @@ -81,6 +81,7 @@ static inline bool is_vdso_mark(void *addr) return false; } +extern void vdso_update_gtod_addr(struct vdso_maps *rt); extern int vdso_do_park(struct vdso_maps *rt, unsigned long park_at, unsigned long park_size); extern int vdso_map_compat(unsigned long map_at); diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index be90090de..38da76680 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -12,7 +12,8 @@ #include "int.h" #include "types.h" #include "page.h" -#include +#include "compel/plugins/std/syscall.h" +#include "compel/plugins/std/log.h" #include "image.h" #include "parasite-vdso.h" #include "vma.h" @@ -43,14 +44,62 @@ static int remap_one(char *who, unsigned long *from, unsigned long to, size_t si static int park_at(struct vdso_maps *rt, unsigned long vdso, unsigned long vvar) { + unsigned long vvar_size = rt->sym.vvar_size; + unsigned long vdso_size = rt->sym.vdso_size; int ret; - ret = remap_one("rt-vdso", &rt->vdso_start, vdso, rt->sym.vdso_size); - - if (ret || !vvar) + ret = remap_one("rt-vdso", &rt->vdso_start, vdso, vdso_size); + if (ret) return ret; - return remap_one("rt-vvar", &rt->vvar_start, vvar, rt->sym.vvar_size); + std_log_set_gettimeofday(NULL); /* stop using vdso for timings */ + + if (vvar) + ret = remap_one("rt-vvar", &rt->vvar_start, vvar, vvar_size); + + if (!ret) + vdso_update_gtod_addr(rt); + + return ret; +} + +void vdso_update_gtod_addr(struct vdso_maps *rt) +{ + struct vdso_symbol *gtod_sym; + void *gtod; + + if (rt->vdso_start == VDSO_BAD_ADDR) { + pr_debug("No rt-vdso - no fast gettimeofday()\n"); + return; + } + + if (VDSO_SYMBOL_GTOD < 0) { + pr_debug("Arch doesn't support gettimeofday() from vdso\n"); + return; + } + + /* + * XXX: Don't enable vdso timings for compatible applications. + * We would need to temporary map 64-bit vdso for timings in restorer + * and remap it with compatible at the end of restore. + * And vdso proxification should be done much later. + * Also, restorer should have two sets of vdso_maps in arguments. + */ + if (rt->compatible) { + pr_debug("compat mode: using syscall for gettimeofday()\n"); + return; + } + + gtod_sym = &rt->sym.symbols[VDSO_SYMBOL_GTOD]; + if (gtod_sym->offset == VDSO_BAD_ADDR) { + pr_debug("No gettimeofday() on rt-vdso\n"); + return; + } + + gtod = (void*)(rt->vdso_start + gtod_sym->offset); + pr_info("Using gettimeofday() on vdso at %p\n", gtod); + + std_log_set_gettimeofday(gtod); } /* diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 9d49a8313..4fff2c85d 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1402,6 +1402,8 @@ long __export_restore_task(struct task_restore_args *args) if (args->can_map_vdso && (map_vdso(args, args->compatible_mode) < 0)) goto core_restore_end; + vdso_update_gtod_addr(&args->vdso_maps_rt); + /* Shift private vma-s to the left */ for (i = 0; i < args->vmas_n; i++) { vma_entry = args->vmas + i; From 96992883ca7550387b347fbbcfde1266f078c55a Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 26 Jun 2019 11:55:19 +0300 Subject: [PATCH 2148/4375] inotify: cleanup auxiliary events from queue I've mentioned the problem that after c/r each inotify receives one or more unexpected events. This happens because our algorithm mixes setting up an inotify watch on the file with opening and closing it. We mix inotify creation and watched file open/close because we need to create the inotify watch on the file from another mntns (generally). And we do a trick opening the file so that it can be referenced in current mntns by /proc//fd/ path. Moreover if we have several inotifies on the same file, than queue gets even more events than just one which happens in a simple case. note: For now we don't have a way to c/r events in queue but we need to at least leave the queue clean from events generated by our own. These, still, looks harder to rewrite wd creation without this proc-fd trick than to remove unexpected events from queues. So just cleanup these events for each fdt-restorer process, for each of its inotify fds _after_ restore stage (at CR_STATE_RESTORE_SIGCHLD). These is a closest place where for an _alive_ process we know that all prepare_fds() are done by all processes. These means we need to do the cleanup in PIE code, so need to add sys_ppoll definitions for PIE and divide process in two phases: first collect and transfer fds, second do real cleanup. note: We still do prepare_fds() for zombies. But zombies have no fds in /proc/pid/fd so we will collect no in collect_fds() and therefore we have no in prepare_fds(), thus there is no need to cleanup inotifies for zombies. v2: adopt to multiple unexpected events v3: do not cleanup from fdt-receivers, done from fdt-restorer v4: do without additional fds restore stage v5: replace sys_poll with sys_ppoll and fix minor nits Signed-off-by: Pavel Tikhomirov use ppoll always and remove poll --- .../arch/arm/plugins/std/syscalls/syscall.def | 1 + .../plugins/std/syscalls/syscall-ppc64.tbl | 1 + .../plugins/std/syscalls/syscall-s390.tbl | 1 + .../x86/plugins/std/syscalls/syscall_32.tbl | 1 + .../x86/plugins/std/syscalls/syscall_64.tbl | 1 + .../plugins/include/uapi/std/syscall-types.h | 1 + criu/cr-restore.c | 38 ++++++++++ criu/include/restorer.h | 3 + criu/pie/restorer.c | 70 +++++++++++++++++++ 9 files changed, 117 insertions(+) diff --git a/compel/arch/arm/plugins/std/syscalls/syscall.def b/compel/arch/arm/plugins/std/syscalls/syscall.def index 653a7539b..721ff16dc 100644 --- a/compel/arch/arm/plugins/std/syscalls/syscall.def +++ b/compel/arch/arm/plugins/std/syscalls/syscall.def @@ -111,3 +111,4 @@ preadv_raw 69 361 (int fd, struct iovec *iov, unsigned long nr, unsigned long userfaultfd 282 388 (int flags) fallocate 47 352 (int fd, int mode, loff_t offset, loff_t len) cacheflush ! 983042 (void *start, void *end, int flags) +ppoll 73 336 (struct pollfd *fds, unsigned int nfds, const struct timespec *tmo, const sigset_t *sigmask, size_t sigsetsize) diff --git a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl index 62e0bc1a0..3b3079040 100644 --- a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl +++ b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl @@ -107,3 +107,4 @@ __NR_ipc 117 sys_ipc (unsigned int call, int first, unsigned long second, un __NR_gettimeofday 78 sys_gettimeofday (struct timeval *tv, struct timezone *tz) __NR_preadv 320 sys_preadv_raw (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) __NR_userfaultfd 364 sys_userfaultfd (int flags) +__NR_ppoll 281 sys_ppoll (struct pollfd *fds, unsigned int nfds, const struct timespec *tmo, const sigset_t *sigmask, size_t sigsetsize) diff --git a/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl b/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl index 3521e9150..cc13a63dd 100644 --- a/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl +++ b/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl @@ -107,3 +107,4 @@ __NR_ipc 117 sys_ipc (unsigned int call, int first, unsigned long second, un __NR_userfaultfd 355 sys_userfaultfd (int flags) __NR_preadv 328 sys_preadv_raw (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) __NR_gettimeofday 78 sys_gettimeofday (struct timeval *tv, struct timezone *tz) +__NR_ppoll 302 sys_ppoll (struct pollfd *fds, unsigned int nfds, const struct timespec *tmo, const sigset_t *sigmask, size_t sigsetsize) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl index a6c55b83c..7903ab150 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl @@ -95,3 +95,4 @@ __NR_kcmp 349 sys_kcmp (pid_t pid1, pid_t pid2, int type, unsigned long idx1, __NR_seccomp 354 sys_seccomp (unsigned int op, unsigned int flags, const char *uargs) __NR_memfd_create 356 sys_memfd_create (const char *name, unsigned int flags) __NR_userfaultfd 374 sys_userfaultfd (int flags) +__NR_ppoll 309 sys_ppoll (struct pollfd *fds, unsigned int nfds, const struct timespec *tmo, const sigset_t *sigmask, size_t sigsetsize) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl index 642715147..4ac9164ea 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl @@ -106,3 +106,4 @@ __NR_setns 308 sys_setns (int fd, int nstype) __NR_kcmp 312 sys_kcmp (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) __NR_memfd_create 319 sys_memfd_create (const char *name, unsigned int flags) __NR_userfaultfd 323 sys_userfaultfd (int flags) +__NR_ppoll 271 sys_ppoll (struct pollfd *fds, unsigned int nfds, const struct timespec *tmo, const sigset_t *sigmask, size_t sigsetsize) diff --git a/compel/plugins/include/uapi/std/syscall-types.h b/compel/plugins/include/uapi/std/syscall-types.h index ddb740c82..57865e741 100644 --- a/compel/plugins/include/uapi/std/syscall-types.h +++ b/compel/plugins/include/uapi/std/syscall-types.h @@ -38,6 +38,7 @@ struct siginfo; struct msghdr; struct rusage; struct iocb; +struct pollfd; typedef unsigned long aio_context_t; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 2ffd9a86c..b4530f8e5 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -726,6 +726,40 @@ static int collect_zombie_pids(struct task_restore_args *ta) return collect_child_pids(TASK_DEAD, &ta->zombies_n); } +static int collect_inotify_fds(struct task_restore_args *ta) +{ + struct list_head *list = &rsti(current)->fds; + struct fdt *fdt = rsti(current)->fdt; + struct fdinfo_list_entry *fle; + + /* Check we are an fdt-restorer */ + if (fdt && fdt->pid != vpid(current)) + return 0; + + ta->inotify_fds = (int *)rst_mem_align_cpos(RM_PRIVATE); + + list_for_each_entry(fle, list, ps_list) { + struct file_desc *d = fle->desc; + int *inotify_fd; + + if (d->ops->type != FD_TYPES__INOTIFY) + continue; + + if (fle != file_master(d)) + continue; + + inotify_fd = rst_mem_alloc(sizeof(*inotify_fd), RM_PRIVATE); + if (!inotify_fd) + return -1; + + ta->inotify_fds_n++; + *inotify_fd = fle->fe->fd; + + pr_debug("Collect inotify fd %d to cleanup later\n", *inotify_fd); + } + return 0; +} + static int open_core(int pid, CoreEntry **pcore) { int ret; @@ -880,6 +914,9 @@ static int restore_one_alive_task(int pid, CoreEntry *core) if (collect_zombie_pids(ta) < 0) return -1; + if (collect_inotify_fds(ta) < 0) + return -1; + if (prepare_proc_misc(pid, core->tc, ta)) return -1; @@ -3411,6 +3448,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns RST_MEM_FIXUP_PPTR(task_args->helpers); RST_MEM_FIXUP_PPTR(task_args->zombies); RST_MEM_FIXUP_PPTR(task_args->vma_ios); + RST_MEM_FIXUP_PPTR(task_args->inotify_fds); task_args->compatible_mode = core_is_compat(core); /* diff --git a/criu/include/restorer.h b/criu/include/restorer.h index f980bfad3..b93807f5f 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -177,6 +177,9 @@ struct task_restore_args { pid_t *zombies; unsigned int zombies_n; + int *inotify_fds; /* fds to cleanup inotify events at CR_STATE_RESTORE_SIGCHLD stage */ + unsigned int inotify_fds_n; + /* * * * * * * * * * * * * * * * * * * * */ unsigned long task_size; diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 4fff2c85d..6f8f1ae54 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "linux/userfaultfd.h" @@ -1307,6 +1308,72 @@ static int map_vdso(struct task_restore_args *args, bool compatible) return 0; } +static int fd_poll(int inotify_fd) +{ + struct pollfd pfd = {inotify_fd, POLLIN, 0}; + struct timespec tmo = {0, 0}; + + return sys_ppoll(&pfd, 1, &tmo, NULL, sizeof(sigset_t)); +} + +/* + * note: Actually kernel may want even more space for one event (see + * round_event_name_len), so using buffer of EVENT_BUFF_SIZE size may fail. + * To be on the safe side - take a bigger buffer, and these also allows to + * read more events in one syscall. + */ +#define EVENT_BUFF_SIZE ((sizeof(struct inotify_event) + PATH_MAX)) + +/* + * Read all available events from inotify queue + */ +static int cleanup_inotify_events(int inotify_fd) +{ + char buf[EVENT_BUFF_SIZE * 8]; + int ret; + + while (1) { + ret = fd_poll(inotify_fd); + if (ret < 0) { + pr_err("Failed to poll from inotify fd: %d\n", ret); + return -1; + } else if (ret == 0) { + break; + } + + ret = sys_read(inotify_fd, buf, sizeof(buf)); + if (ret < 0) { + pr_err("Failed to read inotify events\n"); + return -1; + } + } + + return 0; +} + +/* + * When we restore inotifies we can open and close files we create a watch + * for. So wee need to cleanup these auxiliary events which we've generated. + * + * note: For now we don't have a way to c/r events in queue but we need to + * at least leave the queue clean from events generated by our own. + */ +int cleanup_current_inotify_events(struct task_restore_args *task_args) +{ + int i; + + for (i = 0; i < task_args->inotify_fds_n; i++) { + int inotify_fd = task_args->inotify_fds[i]; + + pr_debug("Cleaning inotify events from %d\n", inotify_fd); + + if (cleanup_inotify_events(inotify_fd)) + return -1; + } + + return 0; +} + /* * The main routine to restore task via sigreturn. * This one is very special, we never return there @@ -1767,6 +1834,9 @@ long __export_restore_task(struct task_restore_args *args) restore_finish_stage(task_entries_local, CR_STATE_RESTORE); + if (cleanup_current_inotify_events(args)) + goto core_restore_end; + if (wait_helpers(args) < 0) goto core_restore_end; if (wait_zombies(args) < 0) From e5bdcbbd1d975f088df3e5766f1ddda4a29c3cb1 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 26 Jun 2019 15:47:39 +0300 Subject: [PATCH 2149/4375] zdtm/inotify: add a test that no unexpected events appear after c/r Just create two inotify watches on a testfile, and do nothing except c/r, it is expected that there is no events in queue after these. before "inotify: cleanup auxiliary events from queue": [root@snorch criu]# ./test/zdtm.py run -t zdtm/static/inotify04 === Run 1/1 ================ zdtm/static/inotify04 ======================== Run zdtm/static/inotify04 in h ======================== DEP inotify04.d CC inotify04.o LINK inotify04 Start test ./inotify04 --pidfile=inotify04.pid --outfile=inotify04.out --dirname=inotify04.test Run criu dump Run criu restore Send the 15 signal to 60 Wait for zdtm/static/inotify04(60) to die for 0.100000 =============== Test zdtm/static/inotify04 FAIL at result check ================ Test output: ================================ 18:37:14.279: 60: Event 0x10 18:37:14.280: 60: Event 0x20 18:37:14.280: 60: Event 0x10 18:37:14.280: 60: Read 3 events 18:37:14.280: 60: FAIL: inotify04.c:105: Found 3 unexpected inotify events (errno = 11 (Resource temporarily unavailable)) <<< ================================ v2: make two inotifies on the same file Signed-off-by: Pavel Tikhomirov zdtm: inotify04 add another inotify on the same file --- test/zdtm/static/Makefile | 1 + test/zdtm/static/inotify04.c | 124 +++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 test/zdtm/static/inotify04.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 52bd00602..d8279d6f8 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -311,6 +311,7 @@ TST_DIR = \ inotify00 \ inotify01 \ inotify02 \ + inotify04 \ cgroup00 \ rmdir_open \ cgroup01 \ diff --git a/test/zdtm/static/inotify04.c b/test/zdtm/static/inotify04.c new file mode 100644 index 000000000..fb9293024 --- /dev/null +++ b/test/zdtm/static/inotify04.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check inotify does not have trash in queue after c/r"; +const char *test_author = "Pavel Tikhomirov "; + +char *dirname; +TEST_OPTION(dirname, string, "directory name", 1); + +#define TEST_FILE "inotify-testfile" + +#define BUFF_SIZE ((sizeof(struct inotify_event) + PATH_MAX)) + +static int inotify_read_events(int inotify_fd, unsigned int *n) +{ + struct inotify_event *event; + char buf[BUFF_SIZE * 8]; + int ret, off; + + *n = 0; + + while (1) { + ret = read(inotify_fd, buf, sizeof(buf)); + if (ret < 0) { + if (errno != EAGAIN) { + pr_perror("Can't read inotify queue"); + return -1; + } else { + ret = 0; + break; + } + } else if (ret == 0) + break; + + for (off = 0; off < ret; (*n)++, off += sizeof(*event) + event->len) { + event = (void *)(buf + off); + test_msg("Event %#10x\n", event->mask); + } + } + + test_msg("Read %u events\n", *n); + return ret; +} + +int main (int argc, char *argv[]) +{ + unsigned int mask = IN_ALL_EVENTS; + char test_file_path[PATH_MAX]; + int fd, ifd, ifd2, ret; + unsigned int n; + + test_init(argc, argv); + + if (mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) { + pr_perror("Can't create directory %s", dirname); + return 1; + } + + snprintf(test_file_path, sizeof(test_file_path), "%s/%s", dirname, TEST_FILE); + + fd = open(test_file_path, O_CREAT, 0644); + if (fd < 0) { + pr_perror("Failed to create %s", test_file_path); + return 1; + } + close(fd); + + ifd = inotify_init1(IN_NONBLOCK); + if (ifd < 0) { + pr_perror("Failed inotify_init"); + return 1; + } + + ifd2 = inotify_init1(IN_NONBLOCK); + if (ifd2 < 0) { + pr_perror("Failed inotify_init"); + return 1; + } + + if (inotify_add_watch(ifd, test_file_path, mask) < 0) { + pr_perror("Failed inotify_add_watch"); + return 1; + } + + if (inotify_add_watch(ifd2, test_file_path, mask) < 0) { + pr_perror("Failed inotify_add_watch"); + return 1; + } + + test_daemon(); + test_waitsig(); + + ret = inotify_read_events(ifd, &n); + if (ret < 0) { + fail("Failed to read inotify events"); + return 1; + } else if (n != 0) { + fail("Found %d unexpected inotify events", n); + return 1; + } + + ret = inotify_read_events(ifd, &n); + if (ret < 0) { + fail("Failed to read inotify events"); + return 1; + } else if (n != 0) { + fail("Found %d unexpected inotify events", n); + return 1; + } + + close(ifd); + close(ifd2); + unlink(test_file_path); + pass(); + + return 0; +} From 5f91f920a8756e565d4a93a2542ba13865cc5733 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 8 Aug 2019 11:09:05 -0700 Subject: [PATCH 2150/4375] test: bring the lo interface up in each network namespace This is needed to workaround the problem with "ip route save": (00.113153) Running ip route save Error: ipv4: FIB table does not exist. Signed-off-by: Andrei Vagin --- test/zdtm/static/netns_sub.c | 4 ++++ test/zdtm/static/netns_sub.desc | 6 +++++- test/zdtm/static/netns_sub_veth.c | 2 ++ test/zdtm/static/netns_sub_veth.desc | 2 +- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/test/zdtm/static/netns_sub.c b/test/zdtm/static/netns_sub.c index 6515057d8..9f77bf96b 100644 --- a/test/zdtm/static/netns_sub.c +++ b/test/zdtm/static/netns_sub.c @@ -104,6 +104,8 @@ int main(int argc, char **argv) pr_perror("unshare"); return 1; } + if (system("ip link set up dev lo")) + return 1; sk = create_socket(1); if (sk < 0) return 1; @@ -166,6 +168,8 @@ int main(int argc, char **argv) pr_perror("unshare"); return 1; } + if (system("ip link set up dev lo")) + return 1; sk = create_socket(2); if (sk < 0) return 1; diff --git a/test/zdtm/static/netns_sub.desc b/test/zdtm/static/netns_sub.desc index 7657ba45c..1f12518d2 100644 --- a/test/zdtm/static/netns_sub.desc +++ b/test/zdtm/static/netns_sub.desc @@ -1 +1,5 @@ -{'flavor': 'ns uns', 'flags': 'suid'} +{ + 'deps': ['/bin/sh', '/sbin/ip|/bin/ip'], + 'flavor': 'ns uns', + 'flags': 'suid' +} diff --git a/test/zdtm/static/netns_sub_veth.c b/test/zdtm/static/netns_sub_veth.c index 927827199..eedbb15c3 100644 --- a/test/zdtm/static/netns_sub_veth.c +++ b/test/zdtm/static/netns_sub_veth.c @@ -50,6 +50,8 @@ int main(int argc, char **argv) if (unshare(CLONE_NEWNET)) return 1; + if (system("ip link set up dev lo")) + return 1; task_waiter_complete(&lock, i); test_waitsig(); diff --git a/test/zdtm/static/netns_sub_veth.desc b/test/zdtm/static/netns_sub_veth.desc index ea9e15c8a..18f81a880 100644 --- a/test/zdtm/static/netns_sub_veth.desc +++ b/test/zdtm/static/netns_sub_veth.desc @@ -1,5 +1,5 @@ { - 'deps': ['/sbin/ip', '/bin/sh'], + 'deps': ['/sbin/ip|/bin/ip', '/bin/sh'], 'flags': 'suid', 'flavor': 'ns uns', 'feature': 'link_nsid', From f6ab4620748588d5d8991c858ae6c2a0b52a2b44 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 10 Aug 2019 02:33:29 +0100 Subject: [PATCH 2151/4375] vdso: Correctly track vdso position without vvar If vvar is absent vdso_before_vvar is initialized by "false". Which means that the check that supposed to track vdso/vvar pair went into wrong brackets. In result it broke CRIU on kernels that don't have vvar mapping. Simpilfy the code by moving the check for VVAR_BAD_SIZE outside of conditional for vdso_before_vvar. Reported-by: Cyrill Gorcunov Fixes: 0918c7667647 ("vdso/restorer: Always track vdso/vvar positions in vdso_maps_rt") Signed-off-by: Dmitry Safonov Acked-by: Cyrill Gorcunov Tested-by: Cyrill Gorcunov Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 6f8f1ae54..390c0e1a9 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1293,13 +1293,16 @@ static int map_vdso(struct task_restore_args *args, bool compatible) return err; } + /* kernel may provide only vdso */ + if (rt->sym.vvar_size == VVAR_BAD_SIZE) { + rt->vdso_start = args->vdso_rt_parked_at; + rt->vvar_start = VVAR_BAD_ADDR; + return 0; + } + if (rt->sym.vdso_before_vvar) { rt->vdso_start = args->vdso_rt_parked_at; - /* kernel may provide only vdso */ - if (rt->sym.vvar_size != VVAR_BAD_SIZE) - rt->vvar_start = rt->vdso_start + rt->sym.vdso_size; - else - rt->vvar_start = VVAR_BAD_ADDR; + rt->vvar_start = rt->vdso_start + rt->sym.vdso_size; } else { rt->vvar_start = args->vdso_rt_parked_at; rt->vdso_start = rt->vvar_start + rt->sym.vvar_size; From 25460af822a629ed6e3ce1360ca035016127cd6c Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 10 Aug 2019 23:46:19 +0300 Subject: [PATCH 2152/4375] kerndat: mark functions as static which are used in kerndat.c only Signed-off-by: Andrei Vagin --- criu/include/kerndat.h | 7 ------- criu/kerndat.c | 14 +++++++------- criu/uffd.c | 2 +- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 75e2130b2..c2164fa0a 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -15,10 +15,6 @@ struct stat; */ extern int kerndat_init(void); -extern int kerndat_get_dirty_track(void); -extern int kerndat_fdinfo_has_lock(void); -extern int kerndat_loginuid(void); -extern int kerndat_files_stat(bool early); enum pagemap_func { PM_UNKNOWN, @@ -90,7 +86,4 @@ enum { */ extern int kerndat_fs_virtualized(unsigned int which, u32 kdev); -extern int kerndat_tcp_repair(); -extern int kerndat_uffd(void); - #endif /* __CR_KERNDAT_H__ */ diff --git a/criu/kerndat.c b/criu/kerndat.c index b884f6d15..c158d6760 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -157,7 +157,7 @@ static void kerndat_mmap_min_addr(void) (unsigned long)kdat.mmap_min_addr); } -int kerndat_files_stat(bool early) +static int kerndat_files_stat(bool early) { static const uint32_t NR_OPEN_DEFAULT = 1024 * 1024; static const uint64_t MAX_FILES_DEFAULT = 8192; @@ -348,7 +348,7 @@ int kerndat_fs_virtualized(unsigned int which, u32 kdev) * this functionality under CONFIG_MEM_SOFT_DIRTY option. */ -int kerndat_get_dirty_track(void) +static int kerndat_get_dirty_track(void) { char *map; int pm2; @@ -471,7 +471,7 @@ static int get_task_size(void) return 0; } -int kerndat_fdinfo_has_lock() +static int kerndat_fdinfo_has_lock() { int fd, pfd = -1, exit_code = -1, len; char buf[PAGE_SIZE]; @@ -521,7 +521,7 @@ static int get_ipv6() return 0; } -int kerndat_loginuid(void) +static int kerndat_loginuid(void) { unsigned int saved_loginuid; int ret; @@ -742,7 +742,7 @@ err: return ret; } -int kerndat_has_inotify_setnextwd(void) +static int kerndat_has_inotify_setnextwd(void) { int ret = 0; int fd; @@ -765,7 +765,7 @@ int kerndat_has_inotify_setnextwd(void) return ret; } -int has_kcmp_epoll_tfd(void) +static int has_kcmp_epoll_tfd(void) { kcmp_epoll_slot_t slot = { }; int ret = -1, efd, tfd; @@ -907,7 +907,7 @@ unl: } } -int kerndat_uffd(void) +static int kerndat_uffd(void) { int uffd; diff --git a/criu/uffd.c b/criu/uffd.c index 5c1e32184..c47b35b1f 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1417,7 +1417,7 @@ int cr_lazy_pages(bool daemon) int lazy_sk; int ret; - if (kerndat_uffd() || !kdat.has_uffd) + if (!kdat.has_uffd) return -1; if (prepare_dummy_pstree()) From 4e84d11c1f30e042dcd1f8d98872bc4abb8fa889 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 10 Aug 2019 23:53:40 +0300 Subject: [PATCH 2153/4375] kerndat: remove unused code Signed-off-by: Andrei Vagin --- criu/include/kerndat.h | 1 - criu/kerndat.c | 54 +++++------------------------------------- 2 files changed, 6 insertions(+), 49 deletions(-) diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index c2164fa0a..d93e07813 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -62,7 +62,6 @@ struct kerndat_s { bool has_nsid; bool has_link_nsid; unsigned int sysctl_nr_open; - unsigned long files_stat_max_files; bool x86_has_ptrace_fpu_xsave_bug; bool has_inotify_setnextwd; bool has_kcmp_epoll_tfd; diff --git a/criu/kerndat.c b/criu/kerndat.c index c158d6760..39cacb8fe 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -157,19 +157,12 @@ static void kerndat_mmap_min_addr(void) (unsigned long)kdat.mmap_min_addr); } -static int kerndat_files_stat(bool early) +static int kerndat_files_stat(void) { static const uint32_t NR_OPEN_DEFAULT = 1024 * 1024; - static const uint64_t MAX_FILES_DEFAULT = 8192; - uint64_t max_files; uint32_t nr_open; struct sysctl_req req[] = { - { - .name = "fs/file-max", - .arg = &max_files, - .type = CTL_U64, - }, { .name = "fs/nr_open", .arg = &nr_open, @@ -177,50 +170,15 @@ static int kerndat_files_stat(bool early) }, }; - if (!early) { - if (sysctl_op(req, ARRAY_SIZE(req), CTL_READ, 0)) { - pr_warn("Can't fetch file_stat, using kernel defaults\n"); - nr_open = NR_OPEN_DEFAULT; - max_files = MAX_FILES_DEFAULT; - } - } else { - char buf[64]; - int fd1, fd2; - ssize_t ret; - - fd1 = open("/proc/sys/fs/file-max", O_RDONLY); - fd2 = open("/proc/sys/fs/nr_open", O_RDONLY); - + if (sysctl_op(req, ARRAY_SIZE(req), CTL_READ, 0)) { + pr_warn("Can't fetch file_stat, using kernel defaults\n"); nr_open = NR_OPEN_DEFAULT; - max_files = MAX_FILES_DEFAULT; - - if (fd1 < 0 || fd2 < 0) { - pr_warn("Can't fetch file_stat, using kernel defaults\n"); - } else { - ret = read(fd1, buf, sizeof(buf) - 1); - if (ret > 0) { - buf[ret] = '\0'; - max_files = atol(buf); - } - ret = read(fd2, buf, sizeof(buf) - 1); - if (ret > 0) { - buf[ret] = '\0'; - nr_open = atol(buf); - } - } - - if (fd1 >= 0) - close(fd1); - if (fd2 >= 0) - close(fd2); } kdat.sysctl_nr_open = nr_open; - kdat.files_stat_max_files = max_files; - pr_debug("files stat: %s %lu, %s %u\n", - req[0].name, kdat.files_stat_max_files, - req[1].name, kdat.sysctl_nr_open); + pr_debug("files stat: %s %u\n", + req[0].name, kdat.sysctl_nr_open); return 0; } @@ -1088,7 +1046,7 @@ int kerndat_init(void) kerndat_lsm(); kerndat_mmap_min_addr(); - kerndat_files_stat(false); + kerndat_files_stat(); if (!ret) kerndat_save_cache(); From 1356a1def3fe2ced121ecaa6ed082154cc1060a4 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 13 Aug 2019 12:29:08 +0200 Subject: [PATCH 2154/4375] Replace references to github.com/xemul/criu Signed-off-by: Sebastiaan van Stijn --- Makefile.config | 2 +- criu/pagemap-cache.c | 2 +- criu/pie/parasite.c | 2 +- scripts/crit-setup.py | 2 +- scripts/travis/travis-tests | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile.config b/Makefile.config index 6f7324069..1e4352b9d 100644 --- a/Makefile.config +++ b/Makefile.config @@ -39,7 +39,7 @@ else $(info Note: Building without ia32 C/R, missed ia32 support in gcc) $(info $(info) That may be related to missing gcc-multilib in your) $(info $(info) distribution or you may have Debian with buggy toolchain) - $(info $(info) (issue https://github.com/xemul/criu/issues/315)) + $(info $(info) (issue https://github.com/checkpoint-restore/criu/issues/315)) endif endif diff --git a/criu/pagemap-cache.c b/criu/pagemap-cache.c index 61ab09387..d7915f99c 100644 --- a/criu/pagemap-cache.c +++ b/criu/pagemap-cache.c @@ -25,7 +25,7 @@ /* * It's a workaround for a kernel bug. In the 3.19 kernel when pagemap are read * for a few vma-s for one read call, it returns incorrect data. - * https://github.com/xemul/criu/issues/207 + * https://github.com/checkpoint-restore/criu/issues/207 */ static bool pagemap_cache_disabled; diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index 9a179ef8b..387a976da 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -293,7 +293,7 @@ static int dump_creds(struct parasite_dump_creds *args) args->uids[3] = sys_setfsuid(-1L); /* - * FIXME In https://github.com/xemul/criu/issues/95 it is + * FIXME In https://github.com/checkpoint-restore/criu/issues/95 it is * been reported that only low 16 bits are set upon syscall * on ARMv7. * diff --git a/scripts/crit-setup.py b/scripts/crit-setup.py index 60fef6a07..f40588142 100644 --- a/scripts/crit-setup.py +++ b/scripts/crit-setup.py @@ -5,7 +5,7 @@ setup(name = "crit", description = "CRiu Image Tool", author = "CRIU team", author_email = "criu@openvz.org", - url = "https://github.com/xemul/criu", + url = "https://github.com/checkpoint-restore/criu", package_dir = {'pycriu': 'lib/py'}, packages = ["pycriu", "pycriu.images"], scripts = ["crit/crit"] diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index c055860fd..980d74734 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -100,7 +100,7 @@ umask 0000 export SKIP_PREP=1 # The 3.19 kernel (from Ubuntu 14.04) has a bug. When /proc/PID/pagemap # is read for a few VMAs in one read call, incorrect data is returned. -# See https://github.com/xemul/criu/issues/207 +# See https://github.com/checkpoint-restore/criu/issues/207 # Kernel 4.4 (from Ubuntu 14.04.5 update) fixes this. uname -r | grep -q ^3\.19 && export CRIU_PMC_OFF=1 From 2a76ecc9fd3f01e40f8a28ca5e005c8be7d9e116 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 13 Aug 2019 12:29:53 +0200 Subject: [PATCH 2155/4375] README: fix broken links to github.com/xemul/criu Signed-off-by: Sebastiaan van Stijn --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 95608a9ea..16e8452b5 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,8 @@ Linux kernel supporting checkpoint and restore for all the features it provides. looking for contributors of all kinds -- feedback, bug reports, testing, coding, writing, etc. Here are some useful hints to get involved. -* We have both -- [very simple](https://github.com/xemul/criu/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) and [more sophisticated](https://github.com/xemul/criu/issues?q=is%3Aissue+is%3Aopen+label%3A%22new+feature%22) coding tasks; -* CRIU does need [extensive testing](https://github.com/xemul/criu/issues?q=is%3Aissue+is%3Aopen+label%3Atesting); +* We have both -- [very simple](https://checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) and [more sophisticated](https://checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3A%22new+feature%22) coding tasks; +* CRIU does need [extensive testing](https://checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Atesting); * Documentation is always hard, we have [some information](https://criu.org/Category:Empty_articles) that is to be extracted from people's heads into wiki pages as well as [some texts](https://criu.org/Category:Editor_help_needed) that all need to be converted into useful articles; * Feedback is expected on the github issues page and on the [mailing list](https://lists.openvz.org/mailman/listinfo/criu); * For historical reasons we do not accept PRs, instead [patches are welcome](http://criu.org/How_to_submit_patches); From bbd922ed32ece54830380abe7706c111203f1774 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 29 Jul 2019 14:21:45 +0000 Subject: [PATCH 2156/4375] travis: add podman test case This adds the same tests currently running for docker also for podman. In addition this also tests podman --export/--import (migration) support. Signed-off-by: Adrian Reber --- .travis.yml | 1 + scripts/travis/Makefile | 3 ++ scripts/travis/podman-test.sh | 69 +++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100755 scripts/travis/podman-test.sh diff --git a/.travis.yml b/.travis.yml index 37db39412..82ba9fbc8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,7 @@ env: - TR_ARCH=fedora-rawhide - TR_ARCH=fedora-rawhide-aarch64 - TR_ARCH=centos + - TR_ARCH=podman-test matrix: allow_failures: - env: TR_ARCH=docker-test diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index 77c937432..baddd6eb1 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -38,5 +38,8 @@ fedora-asan: docker-test: ./docker-test.sh +podman-test: + ./podman-test.sh + %: $(MAKE) -C ../build $@$(target-suffix) diff --git a/scripts/travis/podman-test.sh b/scripts/travis/podman-test.sh new file mode 100755 index 000000000..9bd1f3d8b --- /dev/null +++ b/scripts/travis/podman-test.sh @@ -0,0 +1,69 @@ +#!/bin/bash +set -x -e -o pipefail + +add-apt-repository -y ppa:projectatomic/ppa + +apt-get install -qq \ + apt-transport-https \ + ca-certificates \ + curl \ + software-properties-common + +apt-get update -qq + +apt-get install -qqy podman + +export SKIP_TRAVIS_TEST=1 + +./travis-tests + +cd ../../ + +make install + +podman info + +criu --version + +podman run --name cr -d docker.io/library/alpine /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done' + +sleep 1 +for i in `seq 50`; do + echo "Test $i for podman container checkpoint" + podman exec cr ps axf + podman logs cr + [ `podman ps -f name=cr -q | wc -l` -eq "1" ] + podman container checkpoint cr + [ `podman ps -f name=cr -q | wc -l` -eq "0" ] + podman ps -a + podman container restore cr + [ `podman ps -f name=cr -q | wc -l` -eq "1" ] + podman logs cr +done + +for i in `seq 50`; do + echo "Test $i for podman container checkpoint --export" + podman ps -a + podman exec cr ps axf + podman logs cr + [ `podman ps -f name=cr -q | wc -l` -eq "1" ] + podman container checkpoint -l --export /tmp/chkpt.tar.gz + [ `podman ps -f name=cr -q | wc -l` -eq "0" ] + podman ps -a + podman rm -fa + podman ps -a + podman container restore --import /tmp/chkpt.tar.gz + [ `podman ps -f name=cr -q | wc -l` -eq "1" ] + podman container restore --name cr2 --import /tmp/chkpt.tar.gz + [ `podman ps -f name=cr2 -q | wc -l` -eq "1" ] + podman ps -a + podman logs cr + podman logs cr2 + podman ps -a + podman rm -fa + podman ps -a + podman container restore --import /tmp/chkpt.tar.gz + [ `podman ps -f name=cr -q | wc -l` -eq "1" ] + podman ps -a + rm -f /tmp/chkpt.tar.gz +done From 5ff4fcb753c566f1c40a1973e8c68a270c3b515b Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 26 Aug 2019 18:19:23 +0300 Subject: [PATCH 2157/4375] zdtm: make inotify04 require restore After adding the test for fake inotify events cleanup on restore, we've detected that we also have the same problem on dump/predump, criu touches files that are watched and generates fake events: [root@snorch criu]# test/zdtm.py run -t zdtm/static/inotify04 --norst -k always === Run 1/1 ================ zdtm/static/inotify04 ======================== Run zdtm/static/inotify04 in h ======================== Start test ./inotify04 --pidfile=inotify04.pid --outfile=inotify04.out --dirname=inotify04.test Run criu dump =[log]=> dump/zdtm/static/inotify04/36/1/dump.log ------------------------ grep Error ------------------------ (00.004050) fsnotify: openable (inode match) as home/snorch/devel/criu/test/zdtm/static/inotify04.test/inotify-testfile (00.004052) fsnotify: Dumping /home/snorch/devel/criu/test/zdtm/static/inotify04.test/inotify-testfile as path for handle (00.004055) fsnotify: id 0x000007 flags 0x000800 (00.004071) 36 fdinfo 5: pos: 0 flags: 4000/0 (00.004080) Warn (criu/fsnotify.c:336): fsnotify: The 0x000008 inotify events will be dropped ------------------------ ERROR OVER ------------------------ Send the 15 signal to 36 Wait for zdtm/static/inotify04(36) to die for 0.100000 ############### Test zdtm/static/inotify04 FAIL at result check ################ Test output: ================================ 18:20:10.558: 36: Event 0x20 18:20:10.558: 36: Event 0x10 18:20:10.558: 36: Event 0x20 18:20:10.558: 36: Event 0x10 18:20:10.558: 36: Event 0x20 18:20:10.558: 36: Event 0x10 18:20:10.558: 36: Event 0x20 18:20:10.558: 36: Event 0x10 18:20:10.558: 36: Read 8 events 18:20:10.558: 36: FAIL: inotify04.c:105: Found 8 unexpected inotify events (errno = 11 (Resource temporarily unavailable)) <<< ================================ ##################################### FAIL ##################################### To suppress fails in jenkins make the inotify04 test 'reqrst'. Still need to cleanup (or do not create) these events on dump/predump. --- test/zdtm/static/inotify04.desc | 1 + 1 file changed, 1 insertion(+) create mode 100644 test/zdtm/static/inotify04.desc diff --git a/test/zdtm/static/inotify04.desc b/test/zdtm/static/inotify04.desc new file mode 100644 index 000000000..f19b3d438 --- /dev/null +++ b/test/zdtm/static/inotify04.desc @@ -0,0 +1 @@ +{'flags': 'reqrst'} From 5aa72e723707e2bd7e8ed9841c2ad392781d066d Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 7 Sep 2019 15:46:22 +0300 Subject: [PATCH 2158/4375] py: Reformat everything into pep8 style As discussed on the mailing list, current .py files formatting does not conform to the world standard, so we should better reformat it. For this the yapf tool is used. The command I used was yapf -i $(find -name *.py) Signed-off-by: Pavel Emelyanov --- coredump/criu_coredump/coredump.py | 1191 ++++----- coredump/criu_coredump/elf.py | 1015 ++++---- lib/py/cli.py | 552 +++-- lib/py/criu.py | 409 ++-- lib/py/images/images.py | 813 +++--- lib/py/images/pb2dict.py | 576 +++-- scripts/crit-setup.py | 19 +- scripts/magic-gen.py | 88 +- soccr/test/run.py | 20 +- test/check_actions.py | 41 +- test/crit-recode.py | 100 +- test/exhaustive/pipe.py | 384 +-- test/exhaustive/unix.py | 1167 ++++----- test/inhfd/fifo.py | 46 +- test/inhfd/pipe.py | 14 +- test/inhfd/socket.py | 14 +- test/inhfd/tty.py | 35 +- test/others/ext-tty/run.py | 27 +- test/others/mounts/mounts.py | 47 +- test/others/rpc/config_file.py | 247 +- test/others/rpc/errno.py | 182 +- test/others/rpc/ps_test.py | 76 +- test/others/rpc/read.py | 2 +- test/others/rpc/restore-loop.py | 37 +- test/others/rpc/test.py | 75 +- test/others/rpc/version.py | 34 +- test/others/shell-job/run.py | 13 +- test/zdtm.py | 3681 +++++++++++++++------------- 28 files changed, 5738 insertions(+), 5167 deletions(-) diff --git a/coredump/criu_coredump/coredump.py b/coredump/criu_coredump/coredump.py index 2b0c37f1a..9b2c6c60c 100644 --- a/coredump/criu_coredump/coredump.py +++ b/coredump/criu_coredump/coredump.py @@ -36,795 +36,802 @@ from pycriu import images # Some memory-related constants PAGESIZE = 4096 status = { - "VMA_AREA_NONE" : 0 << 0, - "VMA_AREA_REGULAR" : 1 << 0, - "VMA_AREA_STACK" : 1 << 1, - "VMA_AREA_VSYSCALL" : 1 << 2, - "VMA_AREA_VDSO" : 1 << 3, - "VMA_FORCE_READ" : 1 << 4, - "VMA_AREA_HEAP" : 1 << 5, - "VMA_FILE_PRIVATE" : 1 << 6, - "VMA_FILE_SHARED" : 1 << 7, - "VMA_ANON_SHARED" : 1 << 8, - "VMA_ANON_PRIVATE" : 1 << 9, - "VMA_AREA_SYSVIPC" : 1 << 10, - "VMA_AREA_SOCKET" : 1 << 11, - "VMA_AREA_VVAR" : 1 << 12, - "VMA_AREA_AIORING" : 1 << 13, - "VMA_AREA_UNSUPP" : 1 << 31 + "VMA_AREA_NONE": 0 << 0, + "VMA_AREA_REGULAR": 1 << 0, + "VMA_AREA_STACK": 1 << 1, + "VMA_AREA_VSYSCALL": 1 << 2, + "VMA_AREA_VDSO": 1 << 3, + "VMA_FORCE_READ": 1 << 4, + "VMA_AREA_HEAP": 1 << 5, + "VMA_FILE_PRIVATE": 1 << 6, + "VMA_FILE_SHARED": 1 << 7, + "VMA_ANON_SHARED": 1 << 8, + "VMA_ANON_PRIVATE": 1 << 9, + "VMA_AREA_SYSVIPC": 1 << 10, + "VMA_AREA_SOCKET": 1 << 11, + "VMA_AREA_VVAR": 1 << 12, + "VMA_AREA_AIORING": 1 << 13, + "VMA_AREA_UNSUPP": 1 << 31 } -prot = { - "PROT_READ" : 0x1, - "PROT_WRITE" : 0x2, - "PROT_EXEC" : 0x4 -} +prot = {"PROT_READ": 0x1, "PROT_WRITE": 0x2, "PROT_EXEC": 0x4} + class elf_note: - nhdr = None # Elf_Nhdr; - owner = None # i.e. CORE or LINUX; - data = None # Ctypes structure with note data; + nhdr = None # Elf_Nhdr; + owner = None # i.e. CORE or LINUX; + data = None # Ctypes structure with note data; class coredump: - """ + """ A class to keep elf core dump components inside and functions to properly write them to file. """ - ehdr = None # Elf ehdr; - phdrs = [] # Array of Phdrs; - notes = [] # Array of elf_notes; - vmas = [] # Array of BytesIO with memory content; - # FIXME keeping all vmas in memory is a bad idea; + ehdr = None # Elf ehdr; + phdrs = [] # Array of Phdrs; + notes = [] # Array of elf_notes; + vmas = [] # Array of BytesIO with memory content; - def write(self, f): - """ + # FIXME keeping all vmas in memory is a bad idea; + + def write(self, f): + """ Write core dump to file f. """ - buf = io.BytesIO() - buf.write(self.ehdr) + buf = io.BytesIO() + buf.write(self.ehdr) - for phdr in self.phdrs: - buf.write(phdr) + for phdr in self.phdrs: + buf.write(phdr) - for note in self.notes: - buf.write(note.nhdr) - buf.write(note.owner) - buf.write("\0"*(8-len(note.owner))) - buf.write(note.data) + for note in self.notes: + buf.write(note.nhdr) + buf.write(note.owner) + buf.write("\0" * (8 - len(note.owner))) + buf.write(note.data) - offset = ctypes.sizeof(elf.Elf64_Ehdr()) - offset += (len(self.vmas) + 1)*ctypes.sizeof(elf.Elf64_Phdr()) + offset = ctypes.sizeof(elf.Elf64_Ehdr()) + offset += (len(self.vmas) + 1) * ctypes.sizeof(elf.Elf64_Phdr()) - filesz = 0 - for note in self.notes: - filesz += ctypes.sizeof(note.nhdr) + ctypes.sizeof(note.data) + 8 + filesz = 0 + for note in self.notes: + filesz += ctypes.sizeof(note.nhdr) + ctypes.sizeof(note.data) + 8 - note_align = PAGESIZE - ((offset + filesz) % PAGESIZE) + note_align = PAGESIZE - ((offset + filesz) % PAGESIZE) - if note_align == PAGESIZE: - note_align = 0 + if note_align == PAGESIZE: + note_align = 0 - if note_align != 0: - scratch = (ctypes.c_char * note_align)() - ctypes.memset(ctypes.addressof(scratch), 0, ctypes.sizeof(scratch)) - buf.write(scratch) + if note_align != 0: + scratch = (ctypes.c_char * note_align)() + ctypes.memset(ctypes.addressof(scratch), 0, ctypes.sizeof(scratch)) + buf.write(scratch) - for vma in self.vmas: - buf.write(vma.data) + for vma in self.vmas: + buf.write(vma.data) - buf.seek(0) - f.write(buf.read()) + buf.seek(0) + f.write(buf.read()) class coredump_generator: - """ + """ Generate core dump from criu images. """ - coredumps = {} # coredumps by pid; + coredumps = {} # coredumps by pid; - pstree = {} # process info by pid; - cores = {} # cores by pid; - mms = {} # mm by pid; - reg_files = None # reg-files; - pagemaps = {} # pagemap by pid; + pstree = {} # process info by pid; + cores = {} # cores by pid; + mms = {} # mm by pid; + reg_files = None # reg-files; + pagemaps = {} # pagemap by pid; - def _img_open_and_strip(self, name, single = False, pid = None): - """ + def _img_open_and_strip(self, name, single=False, pid=None): + """ Load criu image and strip it from magic and redundant list. """ - path = self._imgs_dir + "/" + name - if pid: - path += "-"+str(pid) - path += ".img" + path = self._imgs_dir + "/" + name + if pid: + path += "-" + str(pid) + path += ".img" - with open(path) as f: - img = images.load(f) + with open(path) as f: + img = images.load(f) - if single: - return img["entries"][0] - else: - return img["entries"] + if single: + return img["entries"][0] + else: + return img["entries"] - - def __call__(self, imgs_dir): - """ + def __call__(self, imgs_dir): + """ Parse criu images stored in directory imgs_dir to fill core dumps. """ - self._imgs_dir = imgs_dir - pstree = self._img_open_and_strip("pstree") + self._imgs_dir = imgs_dir + pstree = self._img_open_and_strip("pstree") - for p in pstree: - pid = p['pid'] + for p in pstree: + pid = p['pid'] - self.pstree[pid] = p - for tid in p['threads']: - self.cores[tid] = self._img_open_and_strip("core", True, tid) - self.mms[pid] = self._img_open_and_strip("mm", True, pid) - self.pagemaps[pid] = self._img_open_and_strip("pagemap", False, pid) + self.pstree[pid] = p + for tid in p['threads']: + self.cores[tid] = self._img_open_and_strip("core", True, tid) + self.mms[pid] = self._img_open_and_strip("mm", True, pid) + self.pagemaps[pid] = self._img_open_and_strip( + "pagemap", False, pid) - files = self._img_open_and_strip("files", False) - self.reg_files = [ x["reg"] for x in files if x["type"]=="REG" ] + files = self._img_open_and_strip("files", False) + self.reg_files = [x["reg"] for x in files if x["type"] == "REG"] - for pid in self.pstree: - self.coredumps[pid] = self._gen_coredump(pid) + for pid in self.pstree: + self.coredumps[pid] = self._gen_coredump(pid) - return self.coredumps + return self.coredumps - - def write(self, coredumps_dir, pid = None): - """ + def write(self, coredumps_dir, pid=None): + """ Write core dumpt to cores_dir directory. Specify pid to choose core dump of only one process. """ - for p in self.coredumps: - if pid and p != pid: - continue - with open(coredumps_dir+"/"+"core."+str(p), 'w+') as f: - self.coredumps[p].write(f) + for p in self.coredumps: + if pid and p != pid: + continue + with open(coredumps_dir + "/" + "core." + str(p), 'w+') as f: + self.coredumps[p].write(f) - def _gen_coredump(self, pid): - """ + def _gen_coredump(self, pid): + """ Generate core dump for pid. """ - cd = coredump() + cd = coredump() - # Generate everything backwards so it is easier to calculate offset. - cd.vmas = self._gen_vmas(pid) - cd.notes = self._gen_notes(pid) - cd.phdrs = self._gen_phdrs(pid, cd.notes, cd.vmas) - cd.ehdr = self._gen_ehdr(pid, cd.phdrs) + # Generate everything backwards so it is easier to calculate offset. + cd.vmas = self._gen_vmas(pid) + cd.notes = self._gen_notes(pid) + cd.phdrs = self._gen_phdrs(pid, cd.notes, cd.vmas) + cd.ehdr = self._gen_ehdr(pid, cd.phdrs) - return cd + return cd - def _gen_ehdr(self, pid, phdrs): - """ + def _gen_ehdr(self, pid, phdrs): + """ Generate elf header for process pid with program headers phdrs. """ - ehdr = elf.Elf64_Ehdr() + ehdr = elf.Elf64_Ehdr() - ctypes.memset(ctypes.addressof(ehdr), 0, ctypes.sizeof(ehdr)) - ehdr.e_ident[elf.EI_MAG0] = elf.ELFMAG0 - ehdr.e_ident[elf.EI_MAG1] = elf.ELFMAG1 - ehdr.e_ident[elf.EI_MAG2] = elf.ELFMAG2 - ehdr.e_ident[elf.EI_MAG3] = elf.ELFMAG3 - ehdr.e_ident[elf.EI_CLASS] = elf.ELFCLASS64 - ehdr.e_ident[elf.EI_DATA] = elf.ELFDATA2LSB - ehdr.e_ident[elf.EI_VERSION] = elf.EV_CURRENT + ctypes.memset(ctypes.addressof(ehdr), 0, ctypes.sizeof(ehdr)) + ehdr.e_ident[elf.EI_MAG0] = elf.ELFMAG0 + ehdr.e_ident[elf.EI_MAG1] = elf.ELFMAG1 + ehdr.e_ident[elf.EI_MAG2] = elf.ELFMAG2 + ehdr.e_ident[elf.EI_MAG3] = elf.ELFMAG3 + ehdr.e_ident[elf.EI_CLASS] = elf.ELFCLASS64 + ehdr.e_ident[elf.EI_DATA] = elf.ELFDATA2LSB + ehdr.e_ident[elf.EI_VERSION] = elf.EV_CURRENT - ehdr.e_type = elf.ET_CORE - ehdr.e_machine = elf.EM_X86_64 - ehdr.e_version = elf.EV_CURRENT - ehdr.e_phoff = ctypes.sizeof(elf.Elf64_Ehdr()) - ehdr.e_ehsize = ctypes.sizeof(elf.Elf64_Ehdr()) - ehdr.e_phentsize = ctypes.sizeof(elf.Elf64_Phdr()) - #FIXME Case len(phdrs) > PN_XNUM should be handled properly. - # See fs/binfmt_elf.c from linux kernel. - ehdr.e_phnum = len(phdrs) + ehdr.e_type = elf.ET_CORE + ehdr.e_machine = elf.EM_X86_64 + ehdr.e_version = elf.EV_CURRENT + ehdr.e_phoff = ctypes.sizeof(elf.Elf64_Ehdr()) + ehdr.e_ehsize = ctypes.sizeof(elf.Elf64_Ehdr()) + ehdr.e_phentsize = ctypes.sizeof(elf.Elf64_Phdr()) + #FIXME Case len(phdrs) > PN_XNUM should be handled properly. + # See fs/binfmt_elf.c from linux kernel. + ehdr.e_phnum = len(phdrs) - return ehdr + return ehdr - def _gen_phdrs(self, pid, notes, vmas): - """ + def _gen_phdrs(self, pid, notes, vmas): + """ Generate program headers for process pid. """ - phdrs = [] + phdrs = [] - offset = ctypes.sizeof(elf.Elf64_Ehdr()) - offset += (len(vmas) + 1)*ctypes.sizeof(elf.Elf64_Phdr()) + offset = ctypes.sizeof(elf.Elf64_Ehdr()) + offset += (len(vmas) + 1) * ctypes.sizeof(elf.Elf64_Phdr()) - filesz = 0 - for note in notes: - filesz += ctypes.sizeof(note.nhdr) + ctypes.sizeof(note.data) + 8 + filesz = 0 + for note in notes: + filesz += ctypes.sizeof(note.nhdr) + ctypes.sizeof(note.data) + 8 - # PT_NOTE - phdr = elf.Elf64_Phdr() - ctypes.memset(ctypes.addressof(phdr), 0, ctypes.sizeof(phdr)) - phdr.p_type = elf.PT_NOTE - phdr.p_offset = offset - phdr.p_filesz = filesz + # PT_NOTE + phdr = elf.Elf64_Phdr() + ctypes.memset(ctypes.addressof(phdr), 0, ctypes.sizeof(phdr)) + phdr.p_type = elf.PT_NOTE + phdr.p_offset = offset + phdr.p_filesz = filesz - phdrs.append(phdr) + phdrs.append(phdr) - note_align = PAGESIZE - ((offset + filesz) % PAGESIZE) + note_align = PAGESIZE - ((offset + filesz) % PAGESIZE) - if note_align == PAGESIZE: - note_align = 0 + if note_align == PAGESIZE: + note_align = 0 - offset += note_align + offset += note_align - # VMA phdrs + # VMA phdrs - for vma in vmas: - offset += filesz - filesz = vma.filesz - phdr = elf.Elf64_Phdr() - ctypes.memset(ctypes.addressof(phdr), 0, ctypes.sizeof(phdr)) - phdr.p_type = elf.PT_LOAD - phdr.p_align = PAGESIZE - phdr.p_paddr = 0 - phdr.p_offset = offset - phdr.p_vaddr = vma.start - phdr.p_memsz = vma.memsz - phdr.p_filesz = vma.filesz - phdr.p_flags = vma.flags + for vma in vmas: + offset += filesz + filesz = vma.filesz + phdr = elf.Elf64_Phdr() + ctypes.memset(ctypes.addressof(phdr), 0, ctypes.sizeof(phdr)) + phdr.p_type = elf.PT_LOAD + phdr.p_align = PAGESIZE + phdr.p_paddr = 0 + phdr.p_offset = offset + phdr.p_vaddr = vma.start + phdr.p_memsz = vma.memsz + phdr.p_filesz = vma.filesz + phdr.p_flags = vma.flags - phdrs.append(phdr) + phdrs.append(phdr) - return phdrs + return phdrs - def _gen_prpsinfo(self, pid): - """ + def _gen_prpsinfo(self, pid): + """ Generate NT_PRPSINFO note for process pid. """ - pstree = self.pstree[pid] - core = self.cores[pid] + pstree = self.pstree[pid] + core = self.cores[pid] - prpsinfo = elf.elf_prpsinfo() - ctypes.memset(ctypes.addressof(prpsinfo), 0, ctypes.sizeof(prpsinfo)) + prpsinfo = elf.elf_prpsinfo() + ctypes.memset(ctypes.addressof(prpsinfo), 0, ctypes.sizeof(prpsinfo)) - # FIXME TASK_ALIVE means that it is either running or sleeping, need to - # teach criu to distinguish them. - TASK_ALIVE = 0x1 - # XXX A bit of confusion here, as in ps "dead" and "zombie" - # state are two separate states, and we use TASK_DEAD for zombies. - TASK_DEAD = 0x2 - TASK_STOPPED = 0x3 - if core["tc"]["task_state"] == TASK_ALIVE: - prpsinfo.pr_state = 0 - if core["tc"]["task_state"] == TASK_DEAD: - prpsinfo.pr_state = 4 - if core["tc"]["task_state"] == TASK_STOPPED: - prpsinfo.pr_state = 3 - # Don't even ask me why it is so, just borrowed from linux - # source and made pr_state match. - prpsinfo.pr_sname = '.' if prpsinfo.pr_state > 5 else "RSDTZW"[prpsinfo.pr_state] - prpsinfo.pr_zomb = 1 if prpsinfo.pr_state == 4 else 0 - prpsinfo.pr_nice = core["thread_core"]["sched_prio"] if "sched_prio" in core["thread_core"] else 0 - prpsinfo.pr_flag = core["tc"]["flags"] - prpsinfo.pr_uid = core["thread_core"]["creds"]["uid"] - prpsinfo.pr_gid = core["thread_core"]["creds"]["gid"] - prpsinfo.pr_pid = pid - prpsinfo.pr_ppid = pstree["ppid"] - prpsinfo.pr_pgrp = pstree["pgid"] - prpsinfo.pr_sid = pstree["sid"] - prpsinfo.pr_fname = core["tc"]["comm"] - prpsinfo.pr_psargs = self._gen_cmdline(pid) + # FIXME TASK_ALIVE means that it is either running or sleeping, need to + # teach criu to distinguish them. + TASK_ALIVE = 0x1 + # XXX A bit of confusion here, as in ps "dead" and "zombie" + # state are two separate states, and we use TASK_DEAD for zombies. + TASK_DEAD = 0x2 + TASK_STOPPED = 0x3 + if core["tc"]["task_state"] == TASK_ALIVE: + prpsinfo.pr_state = 0 + if core["tc"]["task_state"] == TASK_DEAD: + prpsinfo.pr_state = 4 + if core["tc"]["task_state"] == TASK_STOPPED: + prpsinfo.pr_state = 3 + # Don't even ask me why it is so, just borrowed from linux + # source and made pr_state match. + prpsinfo.pr_sname = '.' if prpsinfo.pr_state > 5 else "RSDTZW" [ + prpsinfo.pr_state] + prpsinfo.pr_zomb = 1 if prpsinfo.pr_state == 4 else 0 + prpsinfo.pr_nice = core["thread_core"][ + "sched_prio"] if "sched_prio" in core["thread_core"] else 0 + prpsinfo.pr_flag = core["tc"]["flags"] + prpsinfo.pr_uid = core["thread_core"]["creds"]["uid"] + prpsinfo.pr_gid = core["thread_core"]["creds"]["gid"] + prpsinfo.pr_pid = pid + prpsinfo.pr_ppid = pstree["ppid"] + prpsinfo.pr_pgrp = pstree["pgid"] + prpsinfo.pr_sid = pstree["sid"] + prpsinfo.pr_fname = core["tc"]["comm"] + prpsinfo.pr_psargs = self._gen_cmdline(pid) - nhdr = elf.Elf64_Nhdr() - nhdr.n_namesz = 5 - nhdr.n_descsz = ctypes.sizeof(elf.elf_prpsinfo()) - nhdr.n_type = elf.NT_PRPSINFO + nhdr = elf.Elf64_Nhdr() + nhdr.n_namesz = 5 + nhdr.n_descsz = ctypes.sizeof(elf.elf_prpsinfo()) + nhdr.n_type = elf.NT_PRPSINFO - note = elf_note() - note.data = prpsinfo - note.owner = "CORE" - note.nhdr = nhdr + note = elf_note() + note.data = prpsinfo + note.owner = "CORE" + note.nhdr = nhdr - return note + return note - def _gen_prstatus(self, pid, tid): - """ + def _gen_prstatus(self, pid, tid): + """ Generate NT_PRSTATUS note for thread tid of process pid. """ - core = self.cores[tid] - regs = core["thread_info"]["gpregs"] - pstree = self.pstree[pid] + core = self.cores[tid] + regs = core["thread_info"]["gpregs"] + pstree = self.pstree[pid] - prstatus = elf.elf_prstatus() + prstatus = elf.elf_prstatus() - ctypes.memset(ctypes.addressof(prstatus), 0, ctypes.sizeof(prstatus)) + ctypes.memset(ctypes.addressof(prstatus), 0, ctypes.sizeof(prstatus)) - #FIXME setting only some of the fields for now. Revisit later. - prstatus.pr_pid = tid - prstatus.pr_ppid = pstree["ppid"] - prstatus.pr_pgrp = pstree["pgid"] - prstatus.pr_sid = pstree["sid"] + #FIXME setting only some of the fields for now. Revisit later. + prstatus.pr_pid = tid + prstatus.pr_ppid = pstree["ppid"] + prstatus.pr_pgrp = pstree["pgid"] + prstatus.pr_sid = pstree["sid"] - prstatus.pr_reg.r15 = regs["r15"] - prstatus.pr_reg.r14 = regs["r14"] - prstatus.pr_reg.r13 = regs["r13"] - prstatus.pr_reg.r12 = regs["r12"] - prstatus.pr_reg.rbp = regs["bp"] - prstatus.pr_reg.rbx = regs["bx"] - prstatus.pr_reg.r11 = regs["r11"] - prstatus.pr_reg.r10 = regs["r10"] - prstatus.pr_reg.r9 = regs["r9"] - prstatus.pr_reg.r8 = regs["r8"] - prstatus.pr_reg.rax = regs["ax"] - prstatus.pr_reg.rcx = regs["cx"] - prstatus.pr_reg.rdx = regs["dx"] - prstatus.pr_reg.rsi = regs["si"] - prstatus.pr_reg.rdi = regs["di"] - prstatus.pr_reg.orig_rax = regs["orig_ax"] - prstatus.pr_reg.rip = regs["ip"] - prstatus.pr_reg.cs = regs["cs"] - prstatus.pr_reg.eflags = regs["flags"] - prstatus.pr_reg.rsp = regs["sp"] - prstatus.pr_reg.ss = regs["ss"] - prstatus.pr_reg.fs_base = regs["fs_base"] - prstatus.pr_reg.gs_base = regs["gs_base"] - prstatus.pr_reg.ds = regs["ds"] - prstatus.pr_reg.es = regs["es"] - prstatus.pr_reg.fs = regs["fs"] - prstatus.pr_reg.gs = regs["gs"] + prstatus.pr_reg.r15 = regs["r15"] + prstatus.pr_reg.r14 = regs["r14"] + prstatus.pr_reg.r13 = regs["r13"] + prstatus.pr_reg.r12 = regs["r12"] + prstatus.pr_reg.rbp = regs["bp"] + prstatus.pr_reg.rbx = regs["bx"] + prstatus.pr_reg.r11 = regs["r11"] + prstatus.pr_reg.r10 = regs["r10"] + prstatus.pr_reg.r9 = regs["r9"] + prstatus.pr_reg.r8 = regs["r8"] + prstatus.pr_reg.rax = regs["ax"] + prstatus.pr_reg.rcx = regs["cx"] + prstatus.pr_reg.rdx = regs["dx"] + prstatus.pr_reg.rsi = regs["si"] + prstatus.pr_reg.rdi = regs["di"] + prstatus.pr_reg.orig_rax = regs["orig_ax"] + prstatus.pr_reg.rip = regs["ip"] + prstatus.pr_reg.cs = regs["cs"] + prstatus.pr_reg.eflags = regs["flags"] + prstatus.pr_reg.rsp = regs["sp"] + prstatus.pr_reg.ss = regs["ss"] + prstatus.pr_reg.fs_base = regs["fs_base"] + prstatus.pr_reg.gs_base = regs["gs_base"] + prstatus.pr_reg.ds = regs["ds"] + prstatus.pr_reg.es = regs["es"] + prstatus.pr_reg.fs = regs["fs"] + prstatus.pr_reg.gs = regs["gs"] - nhdr = elf.Elf64_Nhdr() - nhdr.n_namesz = 5 - nhdr.n_descsz = ctypes.sizeof(elf.elf_prstatus()) - nhdr.n_type = elf.NT_PRSTATUS + nhdr = elf.Elf64_Nhdr() + nhdr.n_namesz = 5 + nhdr.n_descsz = ctypes.sizeof(elf.elf_prstatus()) + nhdr.n_type = elf.NT_PRSTATUS - note = elf_note() - note.data = prstatus - note.owner = "CORE" - note.nhdr = nhdr + note = elf_note() + note.data = prstatus + note.owner = "CORE" + note.nhdr = nhdr - return note + return note - def _gen_fpregset(self, pid, tid): - """ + def _gen_fpregset(self, pid, tid): + """ Generate NT_FPREGSET note for thread tid of process pid. """ - core = self.cores[tid] - regs = core["thread_info"]["fpregs"] + core = self.cores[tid] + regs = core["thread_info"]["fpregs"] - fpregset = elf.elf_fpregset_t() - ctypes.memset(ctypes.addressof(fpregset), 0, ctypes.sizeof(fpregset)) + fpregset = elf.elf_fpregset_t() + ctypes.memset(ctypes.addressof(fpregset), 0, ctypes.sizeof(fpregset)) - fpregset.cwd = regs["cwd"] - fpregset.swd = regs["swd"] - fpregset.ftw = regs["twd"] - fpregset.fop = regs["fop"] - fpregset.rip = regs["rip"] - fpregset.rdp = regs["rdp"] - fpregset.mxcsr = regs["mxcsr"] - fpregset.mxcr_mask = regs["mxcsr_mask"] - fpregset.st_space = (ctypes.c_uint * len(regs["st_space"]))(*regs["st_space"]) - fpregset.xmm_space = (ctypes.c_uint * len(regs["xmm_space"]))(*regs["xmm_space"]) - #fpregset.padding = regs["padding"] unused + fpregset.cwd = regs["cwd"] + fpregset.swd = regs["swd"] + fpregset.ftw = regs["twd"] + fpregset.fop = regs["fop"] + fpregset.rip = regs["rip"] + fpregset.rdp = regs["rdp"] + fpregset.mxcsr = regs["mxcsr"] + fpregset.mxcr_mask = regs["mxcsr_mask"] + fpregset.st_space = (ctypes.c_uint * len(regs["st_space"]))( + *regs["st_space"]) + fpregset.xmm_space = (ctypes.c_uint * len(regs["xmm_space"]))( + *regs["xmm_space"]) + #fpregset.padding = regs["padding"] unused - nhdr = elf.Elf64_Nhdr() - nhdr.n_namesz = 5 - nhdr.n_descsz = ctypes.sizeof(elf.elf_fpregset_t()) - nhdr.n_type = elf.NT_FPREGSET + nhdr = elf.Elf64_Nhdr() + nhdr.n_namesz = 5 + nhdr.n_descsz = ctypes.sizeof(elf.elf_fpregset_t()) + nhdr.n_type = elf.NT_FPREGSET - note = elf_note() - note.data = fpregset - note.owner = "CORE" - note.nhdr = nhdr + note = elf_note() + note.data = fpregset + note.owner = "CORE" + note.nhdr = nhdr - return note + return note - def _gen_x86_xstate(self, pid, tid): - """ + def _gen_x86_xstate(self, pid, tid): + """ Generate NT_X86_XSTATE note for thread tid of process pid. """ - core = self.cores[tid] - fpregs = core["thread_info"]["fpregs"] + core = self.cores[tid] + fpregs = core["thread_info"]["fpregs"] - data = elf.elf_xsave_struct() - ctypes.memset(ctypes.addressof(data), 0, ctypes.sizeof(data)) + data = elf.elf_xsave_struct() + ctypes.memset(ctypes.addressof(data), 0, ctypes.sizeof(data)) - data.i387.cwd = fpregs["cwd"] - data.i387.swd = fpregs["swd"] - data.i387.twd = fpregs["twd"] - data.i387.fop = fpregs["fop"] - data.i387.rip = fpregs["rip"] - data.i387.rdp = fpregs["rdp"] - data.i387.mxcsr = fpregs["mxcsr"] - data.i387.mxcsr_mask = fpregs["mxcsr_mask"] - data.i387.st_space = (ctypes.c_uint * len(fpregs["st_space"]))(*fpregs["st_space"]) - data.i387.xmm_space = (ctypes.c_uint * len(fpregs["xmm_space"]))(*fpregs["xmm_space"]) + data.i387.cwd = fpregs["cwd"] + data.i387.swd = fpregs["swd"] + data.i387.twd = fpregs["twd"] + data.i387.fop = fpregs["fop"] + data.i387.rip = fpregs["rip"] + data.i387.rdp = fpregs["rdp"] + data.i387.mxcsr = fpregs["mxcsr"] + data.i387.mxcsr_mask = fpregs["mxcsr_mask"] + data.i387.st_space = (ctypes.c_uint * len(fpregs["st_space"]))( + *fpregs["st_space"]) + data.i387.xmm_space = (ctypes.c_uint * len(fpregs["xmm_space"]))( + *fpregs["xmm_space"]) - if "xsave" in fpregs: - data.xsave_hdr.xstate_bv = fpregs["xsave"]["xstate_bv"] - data.ymmh.ymmh_space = (ctypes.c_uint * len(fpregs["xsave"]["ymmh_space"]))(*fpregs["xsave"]["ymmh_space"]) + if "xsave" in fpregs: + data.xsave_hdr.xstate_bv = fpregs["xsave"]["xstate_bv"] + data.ymmh.ymmh_space = (ctypes.c_uint * + len(fpregs["xsave"]["ymmh_space"]))( + *fpregs["xsave"]["ymmh_space"]) - nhdr = elf.Elf64_Nhdr() - nhdr.n_namesz = 6 - nhdr.n_descsz = ctypes.sizeof(data) - nhdr.n_type = elf.NT_X86_XSTATE + nhdr = elf.Elf64_Nhdr() + nhdr.n_namesz = 6 + nhdr.n_descsz = ctypes.sizeof(data) + nhdr.n_type = elf.NT_X86_XSTATE - note = elf_note() - note.data = data - note.owner = "LINUX" - note.nhdr = nhdr + note = elf_note() + note.data = data + note.owner = "LINUX" + note.nhdr = nhdr - return note + return note - def _gen_siginfo(self, pid, tid): - """ + def _gen_siginfo(self, pid, tid): + """ Generate NT_SIGINFO note for thread tid of process pid. """ - siginfo = elf.siginfo_t() - # FIXME zeroify everything for now - ctypes.memset(ctypes.addressof(siginfo), 0, ctypes.sizeof(siginfo)) + siginfo = elf.siginfo_t() + # FIXME zeroify everything for now + ctypes.memset(ctypes.addressof(siginfo), 0, ctypes.sizeof(siginfo)) - nhdr = elf.Elf64_Nhdr() - nhdr.n_namesz = 5 - nhdr.n_descsz = ctypes.sizeof(elf.siginfo_t()) - nhdr.n_type = elf.NT_SIGINFO + nhdr = elf.Elf64_Nhdr() + nhdr.n_namesz = 5 + nhdr.n_descsz = ctypes.sizeof(elf.siginfo_t()) + nhdr.n_type = elf.NT_SIGINFO - note = elf_note() - note.data = siginfo - note.owner = "CORE" - note.nhdr = nhdr + note = elf_note() + note.data = siginfo + note.owner = "CORE" + note.nhdr = nhdr - return note + return note - def _gen_auxv(self, pid): - """ + def _gen_auxv(self, pid): + """ Generate NT_AUXV note for thread tid of process pid. """ - mm = self.mms[pid] - num_auxv = len(mm["mm_saved_auxv"])/2 + mm = self.mms[pid] + num_auxv = len(mm["mm_saved_auxv"]) / 2 - class elf_auxv(ctypes.Structure): - _fields_ = [("auxv", elf.Elf64_auxv_t*num_auxv)] + class elf_auxv(ctypes.Structure): + _fields_ = [("auxv", elf.Elf64_auxv_t * num_auxv)] - auxv = elf_auxv() - for i in range(num_auxv): - auxv.auxv[i].a_type = mm["mm_saved_auxv"][i] - auxv.auxv[i].a_val = mm["mm_saved_auxv"][i+1] + auxv = elf_auxv() + for i in range(num_auxv): + auxv.auxv[i].a_type = mm["mm_saved_auxv"][i] + auxv.auxv[i].a_val = mm["mm_saved_auxv"][i + 1] - nhdr = elf.Elf64_Nhdr() - nhdr.n_namesz = 5 - nhdr.n_descsz = ctypes.sizeof(elf_auxv()) - nhdr.n_type = elf.NT_AUXV + nhdr = elf.Elf64_Nhdr() + nhdr.n_namesz = 5 + nhdr.n_descsz = ctypes.sizeof(elf_auxv()) + nhdr.n_type = elf.NT_AUXV - note = elf_note() - note.data = auxv - note.owner = "CORE" - note.nhdr = nhdr + note = elf_note() + note.data = auxv + note.owner = "CORE" + note.nhdr = nhdr - return note + return note - def _gen_files(self, pid): - """ + def _gen_files(self, pid): + """ Generate NT_FILE note for process pid. """ - mm = self.mms[pid] + mm = self.mms[pid] - class mmaped_file_info: - start = None - end = None - file_ofs = None - name = None + class mmaped_file_info: + start = None + end = None + file_ofs = None + name = None - infos = [] - for vma in mm["vmas"]: - if vma["shmid"] == 0: - # shmid == 0 means that it is not a file - continue + infos = [] + for vma in mm["vmas"]: + if vma["shmid"] == 0: + # shmid == 0 means that it is not a file + continue - shmid = vma["shmid"] - size = vma["end"] - vma["start"] - off = vma["pgoff"]/PAGESIZE + shmid = vma["shmid"] + size = vma["end"] - vma["start"] + off = vma["pgoff"] / PAGESIZE - files = self.reg_files - fname = filter(lambda x: x["id"] == shmid, files)[0]["name"] + files = self.reg_files + fname = filter(lambda x: x["id"] == shmid, files)[0]["name"] - info = mmaped_file_info() - info.start = vma["start"] - info.end = vma["end"] - info.file_ofs = off - info.name = fname + info = mmaped_file_info() + info.start = vma["start"] + info.end = vma["end"] + info.file_ofs = off + info.name = fname - infos.append(info) + infos.append(info) - # /* - # * Format of NT_FILE note: - # * - # * long count -- how many files are mapped - # * long page_size -- units for file_ofs - # * array of [COUNT] elements of - # * long start - # * long end - # * long file_ofs - # * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL... - # */ - fields = [] - fields.append(("count", ctypes.c_long)) - fields.append(("page_size", ctypes.c_long)) - for i in range(len(infos)): - fields.append(("start"+str(i), ctypes.c_long)) - fields.append(("end"+str(i), ctypes.c_long)) - fields.append(("file_ofs"+str(i), ctypes.c_long)) - for i in range(len(infos)): - fields.append(("name"+str(i), ctypes.c_char*(len(infos[i].name)+1))) + # /* + # * Format of NT_FILE note: + # * + # * long count -- how many files are mapped + # * long page_size -- units for file_ofs + # * array of [COUNT] elements of + # * long start + # * long end + # * long file_ofs + # * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL... + # */ + fields = [] + fields.append(("count", ctypes.c_long)) + fields.append(("page_size", ctypes.c_long)) + for i in range(len(infos)): + fields.append(("start" + str(i), ctypes.c_long)) + fields.append(("end" + str(i), ctypes.c_long)) + fields.append(("file_ofs" + str(i), ctypes.c_long)) + for i in range(len(infos)): + fields.append( + ("name" + str(i), ctypes.c_char * (len(infos[i].name) + 1))) - class elf_files(ctypes.Structure): - _fields_ = fields + class elf_files(ctypes.Structure): + _fields_ = fields - data = elf_files() - data.count = len(infos) - data.page_size = PAGESIZE - for i in range(len(infos)): - info = infos[i] - setattr(data, "start"+str(i), info.start) - setattr(data, "end"+str(i), info.end) - setattr(data, "file_ofs"+str(i), info.file_ofs) - setattr(data, "name"+str(i), info.name) + data = elf_files() + data.count = len(infos) + data.page_size = PAGESIZE + for i in range(len(infos)): + info = infos[i] + setattr(data, "start" + str(i), info.start) + setattr(data, "end" + str(i), info.end) + setattr(data, "file_ofs" + str(i), info.file_ofs) + setattr(data, "name" + str(i), info.name) - nhdr = elf.Elf64_Nhdr() + nhdr = elf.Elf64_Nhdr() - nhdr.n_namesz = 5#XXX strlen + 1 - nhdr.n_descsz = ctypes.sizeof(elf_files()) - nhdr.n_type = elf.NT_FILE + nhdr.n_namesz = 5 #XXX strlen + 1 + nhdr.n_descsz = ctypes.sizeof(elf_files()) + nhdr.n_type = elf.NT_FILE - note = elf_note() - note.nhdr = nhdr - note.owner = "CORE" - note.data = data + note = elf_note() + note.nhdr = nhdr + note.owner = "CORE" + note.data = data - return note + return note - def _gen_thread_notes(self, pid, tid): - notes = [] + def _gen_thread_notes(self, pid, tid): + notes = [] - notes.append(self._gen_prstatus(pid, tid)) - notes.append(self._gen_fpregset(pid, tid)) - notes.append(self._gen_x86_xstate(pid, tid)) - notes.append(self._gen_siginfo(pid, tid)) + notes.append(self._gen_prstatus(pid, tid)) + notes.append(self._gen_fpregset(pid, tid)) + notes.append(self._gen_x86_xstate(pid, tid)) + notes.append(self._gen_siginfo(pid, tid)) - return notes + return notes - def _gen_notes(self, pid): - """ + def _gen_notes(self, pid): + """ Generate notes for core dump of process pid. """ - notes = [] + notes = [] - notes.append(self._gen_prpsinfo(pid)) + notes.append(self._gen_prpsinfo(pid)) - threads = self.pstree[pid]["threads"] + threads = self.pstree[pid]["threads"] - # Main thread first - notes += self._gen_thread_notes(pid, pid) + # Main thread first + notes += self._gen_thread_notes(pid, pid) - # Then other threads - for tid in threads: - if tid == pid: - continue + # Then other threads + for tid in threads: + if tid == pid: + continue - notes += self._gen_thread_notes(pid, tid) + notes += self._gen_thread_notes(pid, tid) - notes.append(self._gen_auxv(pid)) - notes.append(self._gen_files(pid)) + notes.append(self._gen_auxv(pid)) + notes.append(self._gen_files(pid)) - return notes + return notes - def _get_page(self, pid, page_no): - """ + def _get_page(self, pid, page_no): + """ Try to find memory page page_no in pages.img image for process pid. """ - pagemap = self.pagemaps[pid] + pagemap = self.pagemaps[pid] - # First entry is pagemap_head, we will need it later to open - # proper pages.img. - pages_id = pagemap[0]["pages_id"] - off = 0# in pages - for m in pagemap[1:]: - found = False - for i in range(m["nr_pages"]): - if m["vaddr"] + i*PAGESIZE == page_no*PAGESIZE: - found = True - break - off += 1 + # First entry is pagemap_head, we will need it later to open + # proper pages.img. + pages_id = pagemap[0]["pages_id"] + off = 0 # in pages + for m in pagemap[1:]: + found = False + for i in range(m["nr_pages"]): + if m["vaddr"] + i * PAGESIZE == page_no * PAGESIZE: + found = True + break + off += 1 - if not found: - continue + if not found: + continue - if "in_parent" in m and m["in_parent"] == True: - ppid = self.pstree[pid]["ppid"] - return self._get_page(ppid, page_no) - else: - with open(self._imgs_dir+"/"+"pages-"+str(pages_id)+".img") as f: - f.seek(off*PAGESIZE) - return f.read(PAGESIZE) + if "in_parent" in m and m["in_parent"] == True: + ppid = self.pstree[pid]["ppid"] + return self._get_page(ppid, page_no) + else: + with open(self._imgs_dir + "/" + "pages-" + str(pages_id) + + ".img") as f: + f.seek(off * PAGESIZE) + return f.read(PAGESIZE) - return None + return None - def _gen_mem_chunk(self, pid, vma, size): - """ + def _gen_mem_chunk(self, pid, vma, size): + """ Obtain vma contents for process pid. """ - f = None + f = None - if size == 0: - return "" + if size == 0: + return "" - if vma["status"] & status["VMA_AREA_VVAR"]: - #FIXME this is what gdb does, as vvar vma - # is not readable from userspace? - return "\0"*size - elif vma["status"] & status["VMA_AREA_VSYSCALL"]: - #FIXME need to dump it with criu or read from - # current process. - return "\0"*size + if vma["status"] & status["VMA_AREA_VVAR"]: + #FIXME this is what gdb does, as vvar vma + # is not readable from userspace? + return "\0" * size + elif vma["status"] & status["VMA_AREA_VSYSCALL"]: + #FIXME need to dump it with criu or read from + # current process. + return "\0" * size - if vma["status"] & status["VMA_FILE_SHARED"] or \ - vma["status"] & status["VMA_FILE_PRIVATE"]: - # Open file before iterating vma pages - shmid = vma["shmid"] - off = vma["pgoff"] + if vma["status"] & status["VMA_FILE_SHARED"] or \ + vma["status"] & status["VMA_FILE_PRIVATE"]: + # Open file before iterating vma pages + shmid = vma["shmid"] + off = vma["pgoff"] - files = self.reg_files - fname = filter(lambda x: x["id"] == shmid, files)[0]["name"] + files = self.reg_files + fname = filter(lambda x: x["id"] == shmid, files)[0]["name"] - f = open(fname) - f.seek(off) + f = open(fname) + f.seek(off) - start = vma["start"] - end = vma["start"] + size + start = vma["start"] + end = vma["start"] + size - # Split requested memory chunk into pages, so it could be - # pictured as: - # - # "----" -- part of page with memory outside of our vma; - # "XXXX" -- memory from our vma; - # - # Start page Pages in the middle End page - # [-----XXXXX]...[XXXXXXXXXX][XXXXXXXXXX]...[XXX-------] - # - # Each page could be found in pages.img or in a standalone - # file described by shmid field in vma entry and - # corresponding entry in reg-files.img. - # For VMA_FILE_PRIVATE vma, unchanged pages are taken from - # a file, and changed ones -- from pages.img. - # Finally, if no page is found neither in pages.img nor - # in file, hole in inserted -- a page filled with zeroes. - start_page = start/PAGESIZE - end_page = end/PAGESIZE + # Split requested memory chunk into pages, so it could be + # pictured as: + # + # "----" -- part of page with memory outside of our vma; + # "XXXX" -- memory from our vma; + # + # Start page Pages in the middle End page + # [-----XXXXX]...[XXXXXXXXXX][XXXXXXXXXX]...[XXX-------] + # + # Each page could be found in pages.img or in a standalone + # file described by shmid field in vma entry and + # corresponding entry in reg-files.img. + # For VMA_FILE_PRIVATE vma, unchanged pages are taken from + # a file, and changed ones -- from pages.img. + # Finally, if no page is found neither in pages.img nor + # in file, hole in inserted -- a page filled with zeroes. + start_page = start / PAGESIZE + end_page = end / PAGESIZE - buf = "" - for page_no in range(start_page, end_page+1): - page = None + buf = "" + for page_no in range(start_page, end_page + 1): + page = None - # Search for needed page in pages.img and reg-files.img - # and choose appropriate. - page_mem = self._get_page(pid, page_no) + # Search for needed page in pages.img and reg-files.img + # and choose appropriate. + page_mem = self._get_page(pid, page_no) - if f != None: - page = f.read(PAGESIZE) + if f != None: + page = f.read(PAGESIZE) - if page_mem != None: - # Page from pages.img has higher priority - # than one from maped file on disk. - page = page_mem + if page_mem != None: + # Page from pages.img has higher priority + # than one from maped file on disk. + page = page_mem - if page == None: - # Hole - page = PAGESIZE*"\0" + if page == None: + # Hole + page = PAGESIZE * "\0" - # If it is a start or end page, we need to read - # only part of it. - if page_no == start_page: - n_skip = start - page_no*PAGESIZE - if start_page == end_page: - n_read = size - else: - n_read = PAGESIZE - n_skip - elif page_no == end_page: - n_skip = 0 - n_read = end - page_no*PAGESIZE - else: - n_skip = 0 - n_read = PAGESIZE + # If it is a start or end page, we need to read + # only part of it. + if page_no == start_page: + n_skip = start - page_no * PAGESIZE + if start_page == end_page: + n_read = size + else: + n_read = PAGESIZE - n_skip + elif page_no == end_page: + n_skip = 0 + n_read = end - page_no * PAGESIZE + else: + n_skip = 0 + n_read = PAGESIZE - buf += page[n_skip : n_skip + n_read] + buf += page[n_skip:n_skip + n_read] - # Don't forget to close file. - if f != None: - f.close() + # Don't forget to close file. + if f != None: + f.close() - return buf + return buf - def _gen_cmdline(self, pid): - """ + def _gen_cmdline(self, pid): + """ Generate full command with arguments. """ - mm = self.mms[pid] + mm = self.mms[pid] - vma = {} - vma["start"] = mm["mm_arg_start"] - vma["end"] = mm["mm_arg_end"] - # Dummy flags and status. - vma["flags"] = 0 - vma["status"] = 0 - size = vma["end"] - vma["start"] + vma = {} + vma["start"] = mm["mm_arg_start"] + vma["end"] = mm["mm_arg_end"] + # Dummy flags and status. + vma["flags"] = 0 + vma["status"] = 0 + size = vma["end"] - vma["start"] - chunk = self._gen_mem_chunk(pid, vma, size) + chunk = self._gen_mem_chunk(pid, vma, size) - # Replace all '\0's with spaces. - return chunk.replace('\0', ' ') + # Replace all '\0's with spaces. + return chunk.replace('\0', ' ') - def _get_vma_dump_size(self, vma): - """ + def _get_vma_dump_size(self, vma): + """ Calculate amount of vma to put into core dump. """ - if vma["status"] & status["VMA_AREA_VVAR"] or \ - vma["status"] & status["VMA_AREA_VSYSCALL"] or \ - vma["status"] & status["VMA_AREA_VDSO"]: - size = vma["end"] - vma["start"] - elif vma["prot"] == 0: - size = 0 - elif vma["prot"] & prot["PROT_READ"] and \ - vma["prot"] & prot["PROT_EXEC"]: - size = PAGESIZE - elif vma["status"] & status["VMA_ANON_SHARED"] or \ - vma["status"] & status["VMA_FILE_SHARED"] or \ - vma["status"] & status["VMA_ANON_PRIVATE"] or \ - vma["status"] & status["VMA_FILE_PRIVATE"]: - size = vma["end"] - vma["start"] - else: - size = 0 + if vma["status"] & status["VMA_AREA_VVAR"] or \ + vma["status"] & status["VMA_AREA_VSYSCALL"] or \ + vma["status"] & status["VMA_AREA_VDSO"]: + size = vma["end"] - vma["start"] + elif vma["prot"] == 0: + size = 0 + elif vma["prot"] & prot["PROT_READ"] and \ + vma["prot"] & prot["PROT_EXEC"]: + size = PAGESIZE + elif vma["status"] & status["VMA_ANON_SHARED"] or \ + vma["status"] & status["VMA_FILE_SHARED"] or \ + vma["status"] & status["VMA_ANON_PRIVATE"] or \ + vma["status"] & status["VMA_FILE_PRIVATE"]: + size = vma["end"] - vma["start"] + else: + size = 0 - return size + return size - def _get_vma_flags(self, vma): - """ + def _get_vma_flags(self, vma): + """ Convert vma flags int elf flags. """ - flags = 0 + flags = 0 - if vma['prot'] & prot["PROT_READ"]: - flags = flags | elf.PF_R + if vma['prot'] & prot["PROT_READ"]: + flags = flags | elf.PF_R - if vma['prot'] & prot["PROT_WRITE"]: - flags = flags | elf.PF_W + if vma['prot'] & prot["PROT_WRITE"]: + flags = flags | elf.PF_W - if vma['prot'] & prot["PROT_EXEC"]: - flags = flags | elf.PF_X + if vma['prot'] & prot["PROT_EXEC"]: + flags = flags | elf.PF_X - return flags + return flags - def _gen_vmas(self, pid): - """ + def _gen_vmas(self, pid): + """ Generate vma contents for core dump for process pid. """ - mm = self.mms[pid] + mm = self.mms[pid] - class vma_class: - data = None - filesz = None - memsz = None - flags = None - start = None + class vma_class: + data = None + filesz = None + memsz = None + flags = None + start = None - vmas = [] - for vma in mm["vmas"]: - size = self._get_vma_dump_size(vma) + vmas = [] + for vma in mm["vmas"]: + size = self._get_vma_dump_size(vma) - chunk = self._gen_mem_chunk(pid, vma, size) + chunk = self._gen_mem_chunk(pid, vma, size) - v = vma_class() - v.filesz = self._get_vma_dump_size(vma) - v.data = self._gen_mem_chunk(pid, vma, v.filesz) - v.memsz = vma["end"] - vma["start"] - v.start = vma["start"] - v.flags = self._get_vma_flags(vma) + v = vma_class() + v.filesz = self._get_vma_dump_size(vma) + v.data = self._gen_mem_chunk(pid, vma, v.filesz) + v.memsz = vma["end"] - vma["start"] + v.start = vma["start"] + v.flags = self._get_vma_flags(vma) - vmas.append(v) + vmas.append(v) - return vmas + return vmas diff --git a/coredump/criu_coredump/elf.py b/coredump/criu_coredump/elf.py index 1da06a6fd..65da583c3 100644 --- a/coredump/criu_coredump/elf.py +++ b/coredump/criu_coredump/elf.py @@ -1,526 +1,685 @@ # Define structures and constants for generating elf file. import ctypes -Elf64_Half = ctypes.c_uint16 # typedef uint16_t Elf64_Half; -Elf64_Word = ctypes.c_uint32 # typedef uint32_t Elf64_Word; -Elf64_Addr = ctypes.c_uint64 # typedef uint64_t Elf64_Addr; -Elf64_Off = ctypes.c_uint64 # typedef uint64_t Elf64_Off; -Elf64_Xword = ctypes.c_uint64 # typedef uint64_t Elf64_Xword; +Elf64_Half = ctypes.c_uint16 # typedef uint16_t Elf64_Half; +Elf64_Word = ctypes.c_uint32 # typedef uint32_t Elf64_Word; +Elf64_Addr = ctypes.c_uint64 # typedef uint64_t Elf64_Addr; +Elf64_Off = ctypes.c_uint64 # typedef uint64_t Elf64_Off; +Elf64_Xword = ctypes.c_uint64 # typedef uint64_t Elf64_Xword; # Elf64_Ehdr related constants. # e_ident size. -EI_NIDENT = 16 # #define EI_NIDENT (16) +EI_NIDENT = 16 # #define EI_NIDENT (16) -EI_MAG0 = 0 # #define EI_MAG0 0 /* File identification byte 0 index */ -ELFMAG0 = 0x7f # #define ELFMAG0 0x7f /* Magic number byte 0 */ +EI_MAG0 = 0 # #define EI_MAG0 0 /* File identification byte 0 index */ +ELFMAG0 = 0x7f # #define ELFMAG0 0x7f /* Magic number byte 0 */ -EI_MAG1 = 1 # #define EI_MAG1 1 /* File identification byte 1 index */ -ELFMAG1 = ord('E') # #define ELFMAG1 'E' /* Magic number byte 1 */ +EI_MAG1 = 1 # #define EI_MAG1 1 /* File identification byte 1 index */ +ELFMAG1 = ord( + 'E') # #define ELFMAG1 'E' /* Magic number byte 1 */ -EI_MAG2 = 2 # #define EI_MAG2 2 /* File identification byte 2 index */ -ELFMAG2 = ord('L') # #define ELFMAG2 'L' /* Magic number byte 2 */ +EI_MAG2 = 2 # #define EI_MAG2 2 /* File identification byte 2 index */ +ELFMAG2 = ord( + 'L') # #define ELFMAG2 'L' /* Magic number byte 2 */ -EI_MAG3 = 3 # #define EI_MAG3 3 /* File identification byte 3 index */ -ELFMAG3 = ord('F') # #define ELFMAG3 'F' /* Magic number byte 3 */ +EI_MAG3 = 3 # #define EI_MAG3 3 /* File identification byte 3 index */ +ELFMAG3 = ord( + 'F') # #define ELFMAG3 'F' /* Magic number byte 3 */ -EI_CLASS = 4 # #define EI_CLASS 4 /* File class byte index */ +EI_CLASS = 4 # #define EI_CLASS 4 /* File class byte index */ -EI_DATA = 5 # #define EI_DATA 5 /* Data encoding byte index */ +EI_DATA = 5 # #define EI_DATA 5 /* Data encoding byte index */ -EI_VERSION = 6 # #define EI_VERSION 6 /* File version byte index */ +EI_VERSION = 6 # #define EI_VERSION 6 /* File version byte index */ -ELFDATA2LSB = 1 # #define ELFDATA2LSB 1 /* 2's complement, little endian */ +ELFDATA2LSB = 1 # #define ELFDATA2LSB 1 /* 2's complement, little endian */ -ELFCLASS64 = 2 # #define ELFCLASS64 2 /* 64-bit objects */ +ELFCLASS64 = 2 # #define ELFCLASS64 2 /* 64-bit objects */ # Legal values for e_type (object file type). -ET_CORE = 4 # #define ET_CORE 4 /* Core file */ +ET_CORE = 4 # #define ET_CORE 4 /* Core file */ # Legal values for e_machine (architecture). -EM_X86_64 = 62 # #define EM_X86_64 62 /* AMD x86-64 architecture */ +EM_X86_64 = 62 # #define EM_X86_64 62 /* AMD x86-64 architecture */ # Legal values for e_version (version). -EV_CURRENT = 1 # #define EV_CURRENT 1 /* Current version */ +EV_CURRENT = 1 # #define EV_CURRENT 1 /* Current version */ -class Elf64_Ehdr(ctypes.Structure): # typedef struct - _fields_ = [ # { - ("e_ident", ctypes.c_ubyte*EI_NIDENT), # unsigned char e_ident[EI_NIDENT]; - ("e_type", Elf64_Half), # Elf64_Half e_type; - ("e_machine", Elf64_Half), # Elf64_Half e_machine; - ("e_version", Elf64_Word), # Elf64_Word e_version; - ("e_entry", Elf64_Addr), # Elf64_Addr e_entry; - ("e_phoff", Elf64_Off), # Elf64_Off e_phoff; - ("e_shoff", Elf64_Off), # Elf64_Off e_shoff; - ("e_flags", Elf64_Word), # Elf64_Word e_flags; - ("e_ehsize", Elf64_Half), # Elf64_Half e_ehsize; - ("e_phentsize", Elf64_Half), # Elf64_Half e_phentsize; - ("e_phnum", Elf64_Half), # Elf64_Half e_phnum; - ("e_shentsize", Elf64_Half), # Elf64_Half e_shentsize; - ("e_shnum", Elf64_Half), # Elf64_Half e_shnum; - ("e_shstrndx", Elf64_Half) # Elf64_Half e_shstrndx; - ] # } Elf64_Ehdr; + +class Elf64_Ehdr(ctypes.Structure): # typedef struct + _fields_ = [ # { + ("e_ident", + ctypes.c_ubyte * EI_NIDENT), # unsigned char e_ident[EI_NIDENT]; + ("e_type", Elf64_Half), # Elf64_Half e_type; + ("e_machine", Elf64_Half), # Elf64_Half e_machine; + ("e_version", Elf64_Word), # Elf64_Word e_version; + ("e_entry", Elf64_Addr), # Elf64_Addr e_entry; + ("e_phoff", Elf64_Off), # Elf64_Off e_phoff; + ("e_shoff", Elf64_Off), # Elf64_Off e_shoff; + ("e_flags", Elf64_Word), # Elf64_Word e_flags; + ("e_ehsize", Elf64_Half), # Elf64_Half e_ehsize; + ("e_phentsize", Elf64_Half), # Elf64_Half e_phentsize; + ("e_phnum", Elf64_Half), # Elf64_Half e_phnum; + ("e_shentsize", Elf64_Half), # Elf64_Half e_shentsize; + ("e_shnum", Elf64_Half), # Elf64_Half e_shnum; + ("e_shstrndx", Elf64_Half) # Elf64_Half e_shstrndx; + ] # } Elf64_Ehdr; # Elf64_Phdr related constants. # Legal values for p_type (segment type). -PT_LOAD = 1 # #define PT_LOAD 1 /* Loadable program segment */ -PT_NOTE = 4 # #define PT_NOTE 4 /* Auxiliary information */ +PT_LOAD = 1 # #define PT_LOAD 1 /* Loadable program segment */ +PT_NOTE = 4 # #define PT_NOTE 4 /* Auxiliary information */ # Legal values for p_flags (segment flags). -PF_X = 1 # #define PF_X (1 << 0) /* Segment is executable */ -PF_W = 1 << 1 # #define PF_W (1 << 1) /* Segment is writable */ -PF_R = 1 << 2 # #define PF_R (1 << 2) /* Segment is readable */ +PF_X = 1 # #define PF_X (1 << 0) /* Segment is executable */ +PF_W = 1 << 1 # #define PF_W (1 << 1) /* Segment is writable */ +PF_R = 1 << 2 # #define PF_R (1 << 2) /* Segment is readable */ -class Elf64_Phdr(ctypes.Structure): # typedef struct - _fields_ = [ # { - ("p_type", Elf64_Word), # Elf64_Word p_type; - ("p_flags", Elf64_Word), # Elf64_Word p_flags; - ("p_offset", Elf64_Off), # Elf64_Off p_offset; - ("p_vaddr", Elf64_Addr), # Elf64_Addr p_vaddr; - ("p_paddr", Elf64_Addr), # Elf64_Addr p_paddr; - ("p_filesz", Elf64_Xword), # Elf64_Xword p_filesz; - ("p_memsz", Elf64_Xword), # Elf64_Xword p_memsz; - ("p_align", Elf64_Xword), # Elf64_Xword p_align; - ] # } Elf64_Phdr; + +class Elf64_Phdr(ctypes.Structure): # typedef struct + _fields_ = [ # { + ("p_type", Elf64_Word), # Elf64_Word p_type; + ("p_flags", Elf64_Word), # Elf64_Word p_flags; + ("p_offset", Elf64_Off), # Elf64_Off p_offset; + ("p_vaddr", Elf64_Addr), # Elf64_Addr p_vaddr; + ("p_paddr", Elf64_Addr), # Elf64_Addr p_paddr; + ("p_filesz", Elf64_Xword), # Elf64_Xword p_filesz; + ("p_memsz", Elf64_Xword), # Elf64_Xword p_memsz; + ("p_align", Elf64_Xword), # Elf64_Xword p_align; + ] # } Elf64_Phdr; # Elf64_auxv_t related constants. -class _Elf64_auxv_t_U(ctypes.Union): - _fields_ = [ - ("a_val", ctypes.c_uint64) - ] -class Elf64_auxv_t(ctypes.Structure): # typedef struct - _fields_ = [ # { - ("a_type", ctypes.c_uint64), # uint64_t a_type; /* Entry type */ - ("a_un", _Elf64_auxv_t_U) # union - # { - # uint64_t a_val; /* Integer value */ - # /* We use to have pointer elements added here. We cannot do that, - # though, since it does not work when using 32-bit definitions - # on 64-bit platforms and vice versa. */ - # } a_un; - ] # } Elf64_auxv_t; +class _Elf64_auxv_t_U(ctypes.Union): + _fields_ = [("a_val", ctypes.c_uint64)] + + +class Elf64_auxv_t(ctypes.Structure): # typedef struct + _fields_ = [ # { + ("a_type", + ctypes.c_uint64), # uint64_t a_type; /* Entry type */ + ("a_un", _Elf64_auxv_t_U) # union + # { + # uint64_t a_val; /* Integer value */ + # /* We use to have pointer elements added here. We cannot do that, + # though, since it does not work when using 32-bit definitions + # on 64-bit platforms and vice versa. */ + # } a_un; + ] # } Elf64_auxv_t; # Elf64_Nhdr related constants. -NT_PRSTATUS = 1 # #define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ -NT_FPREGSET = 2 # #define NT_FPREGSET 2 /* Contains copy of fpregset struct */ -NT_PRPSINFO = 3 # #define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ -NT_AUXV = 6 # #define NT_AUXV 6 /* Contains copy of auxv array */ -NT_SIGINFO = 0x53494749 # #define NT_SIGINFO 0x53494749 /* Contains copy of siginfo_t, +NT_PRSTATUS = 1 # #define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +NT_FPREGSET = 2 # #define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +NT_PRPSINFO = 3 # #define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ +NT_AUXV = 6 # #define NT_AUXV 6 /* Contains copy of auxv array */ +NT_SIGINFO = 0x53494749 # #define NT_SIGINFO 0x53494749 /* Contains copy of siginfo_t, # size might increase */ -NT_FILE = 0x46494c45 # #define NT_FILE 0x46494c45 /* Contains information about mapped +NT_FILE = 0x46494c45 # #define NT_FILE 0x46494c45 /* Contains information about mapped # files */ -NT_X86_XSTATE = 0x202 # #define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ +NT_X86_XSTATE = 0x202 # #define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ -class Elf64_Nhdr(ctypes.Structure): # typedef struct - _fields_ = [ # { - ("n_namesz", Elf64_Word), # Elf64_Word n_namesz; /* Length of the note's name. */ - ("n_descsz", Elf64_Word), # Elf64_Word n_descsz; /* Length of the note's descriptor. */ - ("n_type", Elf64_Word), # Elf64_Word n_type; /* Type of the note. */ - ] # } Elf64_Nhdr; + +class Elf64_Nhdr(ctypes.Structure): # typedef struct + _fields_ = [ # { + ( + "n_namesz", Elf64_Word + ), # Elf64_Word n_namesz; /* Length of the note's name. */ + ( + "n_descsz", Elf64_Word + ), # Elf64_Word n_descsz; /* Length of the note's descriptor. */ + ("n_type", Elf64_Word + ), # Elf64_Word n_type; /* Type of the note. */ + ] # } Elf64_Nhdr; # Elf64_Shdr related constants. -class Elf64_Shdr(ctypes.Structure): # typedef struct - _fields_ = [ # { - ("sh_name", Elf64_Word), # Elf64_Word sh_name; /* Section name (string tbl index) */ - ("sh_type", Elf64_Word), # Elf64_Word sh_type; /* Section type */ - ("sh_flags", Elf64_Xword), # Elf64_Xword sh_flags; /* Section flags */ - ("sh_addr", Elf64_Addr), # Elf64_Addr sh_addr; /* Section virtual addr at execution */ - ("sh_offset", Elf64_Off), # Elf64_Off sh_offset; /* Section file offset */ - ("sh_size", Elf64_Xword), # Elf64_Xword sh_size; /* Section size in bytes */ - ("sh_link", Elf64_Word), # Elf64_Word sh_link; /* Link to another section */ - ("sh_info", Elf64_Word), # Elf64_Word sh_info; /* Additional section information */ - ("sh_addralign",Elf64_Xword), # Elf64_Xword sh_addralign; /* Section alignment */ - ("sh_entsize", Elf64_Xword) # Elf64_Xword sh_entsize; /* Entry size if section holds table */ - ] # } Elf64_Shdr; + +class Elf64_Shdr(ctypes.Structure): # typedef struct + _fields_ = [ # { + ( + "sh_name", Elf64_Word + ), # Elf64_Word sh_name; /* Section name (string tbl index) */ + ("sh_type", Elf64_Word + ), # Elf64_Word sh_type; /* Section type */ + ("sh_flags", Elf64_Xword + ), # Elf64_Xword sh_flags; /* Section flags */ + ( + "sh_addr", Elf64_Addr + ), # Elf64_Addr sh_addr; /* Section virtual addr at execution */ + ( + "sh_offset", Elf64_Off + ), # Elf64_Off sh_offset; /* Section file offset */ + ( + "sh_size", Elf64_Xword + ), # Elf64_Xword sh_size; /* Section size in bytes */ + ( + "sh_link", Elf64_Word + ), # Elf64_Word sh_link; /* Link to another section */ + ( + "sh_info", Elf64_Word + ), # Elf64_Word sh_info; /* Additional section information */ + ("sh_addralign", Elf64_Xword + ), # Elf64_Xword sh_addralign; /* Section alignment */ + ( + "sh_entsize", Elf64_Xword + ) # Elf64_Xword sh_entsize; /* Entry size if section holds table */ + ] # } Elf64_Shdr; # elf_prstatus related constants. + # Signal info. -class elf_siginfo(ctypes.Structure): # struct elf_siginfo - _fields_ = [ # { - ("si_signo", ctypes.c_int), # int si_signo; /* Signal number. */ - ("si_code", ctypes.c_int), # int si_code; /* Extra code. */ - ("si_errno", ctypes.c_int) # int si_errno; /* Errno. */ - ] # }; +class elf_siginfo(ctypes.Structure): # struct elf_siginfo + _fields_ = [ # { + ("si_signo", ctypes.c_int + ), # int si_signo; /* Signal number. */ + ("si_code", ctypes.c_int + ), # int si_code; /* Extra code. */ + ("si_errno", ctypes.c_int + ) # int si_errno; /* Errno. */ + ] # }; + # A time value that is accurate to the nearest # microsecond but also has a range of years. -class timeval(ctypes.Structure): # struct timeval - _fields_ = [ # { - ("tv_sec", ctypes.c_long), # __time_t tv_sec; /* Seconds. */ - ("tv_usec", ctypes.c_long) # __suseconds_t tv_usec; /* Microseconds. */ - ] # }; +class timeval(ctypes.Structure): # struct timeval + _fields_ = [ # { + ("tv_sec", + ctypes.c_long), # __time_t tv_sec; /* Seconds. */ + ("tv_usec", ctypes.c_long + ) # __suseconds_t tv_usec; /* Microseconds. */ + ] # }; + + +class user_regs_struct(ctypes.Structure): # struct user_regs_struct + _fields_ = [ # { + ("r15", + ctypes.c_ulonglong), # __extension__ unsigned long long int r15; + ("r14", + ctypes.c_ulonglong), # __extension__ unsigned long long int r14; + ("r13", + ctypes.c_ulonglong), # __extension__ unsigned long long int r13; + ("r12", + ctypes.c_ulonglong), # __extension__ unsigned long long int r12; + ("rbp", + ctypes.c_ulonglong), # __extension__ unsigned long long int rbp; + ("rbx", + ctypes.c_ulonglong), # __extension__ unsigned long long int rbx; + ("r11", + ctypes.c_ulonglong), # __extension__ unsigned long long int r11; + ("r10", + ctypes.c_ulonglong), # __extension__ unsigned long long int r10; + ("r9", + ctypes.c_ulonglong), # __extension__ unsigned long long int r9; + ("r8", + ctypes.c_ulonglong), # __extension__ unsigned long long int r8; + ("rax", + ctypes.c_ulonglong), # __extension__ unsigned long long int rax; + ("rcx", + ctypes.c_ulonglong), # __extension__ unsigned long long int rcx; + ("rdx", + ctypes.c_ulonglong), # __extension__ unsigned long long int rdx; + ("rsi", + ctypes.c_ulonglong), # __extension__ unsigned long long int rsi; + ("rdi", + ctypes.c_ulonglong), # __extension__ unsigned long long int rdi; + ("orig_rax", ctypes.c_ulonglong + ), # __extension__ unsigned long long int orig_rax; + ("rip", + ctypes.c_ulonglong), # __extension__ unsigned long long int rip; + ("cs", + ctypes.c_ulonglong), # __extension__ unsigned long long int cs; + ("eflags", + ctypes.c_ulonglong), # __extension__ unsigned long long int eflags; + ("rsp", + ctypes.c_ulonglong), # __extension__ unsigned long long int rsp; + ("ss", + ctypes.c_ulonglong), # __extension__ unsigned long long int ss; + ("fs_base", ctypes.c_ulonglong + ), # __extension__ unsigned long long int fs_base; + ("gs_base", ctypes.c_ulonglong + ), # __extension__ unsigned long long int gs_base; + ("ds", + ctypes.c_ulonglong), # __extension__ unsigned long long int ds; + ("es", + ctypes.c_ulonglong), # __extension__ unsigned long long int es; + ("fs", + ctypes.c_ulonglong), # __extension__ unsigned long long int fs; + ("gs", ctypes.c_ulonglong + ) # __extension__ unsigned long long int gs; + ] # }; -class user_regs_struct(ctypes.Structure): # struct user_regs_struct - _fields_ = [ # { - ("r15", ctypes.c_ulonglong), # __extension__ unsigned long long int r15; - ("r14", ctypes.c_ulonglong), # __extension__ unsigned long long int r14; - ("r13", ctypes.c_ulonglong), # __extension__ unsigned long long int r13; - ("r12", ctypes.c_ulonglong), # __extension__ unsigned long long int r12; - ("rbp", ctypes.c_ulonglong), # __extension__ unsigned long long int rbp; - ("rbx", ctypes.c_ulonglong), # __extension__ unsigned long long int rbx; - ("r11", ctypes.c_ulonglong), # __extension__ unsigned long long int r11; - ("r10", ctypes.c_ulonglong), # __extension__ unsigned long long int r10; - ("r9", ctypes.c_ulonglong), # __extension__ unsigned long long int r9; - ("r8", ctypes.c_ulonglong), # __extension__ unsigned long long int r8; - ("rax", ctypes.c_ulonglong), # __extension__ unsigned long long int rax; - ("rcx", ctypes.c_ulonglong), # __extension__ unsigned long long int rcx; - ("rdx", ctypes.c_ulonglong), # __extension__ unsigned long long int rdx; - ("rsi", ctypes.c_ulonglong), # __extension__ unsigned long long int rsi; - ("rdi", ctypes.c_ulonglong), # __extension__ unsigned long long int rdi; - ("orig_rax", ctypes.c_ulonglong), # __extension__ unsigned long long int orig_rax; - ("rip", ctypes.c_ulonglong), # __extension__ unsigned long long int rip; - ("cs", ctypes.c_ulonglong), # __extension__ unsigned long long int cs; - ("eflags", ctypes.c_ulonglong), # __extension__ unsigned long long int eflags; - ("rsp", ctypes.c_ulonglong), # __extension__ unsigned long long int rsp; - ("ss", ctypes.c_ulonglong), # __extension__ unsigned long long int ss; - ("fs_base", ctypes.c_ulonglong), # __extension__ unsigned long long int fs_base; - ("gs_base", ctypes.c_ulonglong), # __extension__ unsigned long long int gs_base; - ("ds", ctypes.c_ulonglong), # __extension__ unsigned long long int ds; - ("es", ctypes.c_ulonglong), # __extension__ unsigned long long int es; - ("fs", ctypes.c_ulonglong), # __extension__ unsigned long long int fs; - ("gs", ctypes.c_ulonglong) # __extension__ unsigned long long int gs; - ] # }; #elf_greg_t = ctypes.c_ulonglong #ELF_NGREG = ctypes.sizeof(user_regs_struct)/ctypes.sizeof(elf_greg_t) #elf_gregset_t = elf_greg_t*ELF_NGREG elf_gregset_t = user_regs_struct -class elf_prstatus(ctypes.Structure): # struct elf_prstatus - _fields_ = [ # { - ("pr_info", elf_siginfo), # struct elf_siginfo pr_info; /* Info associated with signal. */ - ("pr_cursig", ctypes.c_short), # short int pr_cursig; /* Current signal. */ - ("pr_sigpend", ctypes.c_ulong), # unsigned long int pr_sigpend; /* Set of pending signals. */ - ("pr_sighold", ctypes.c_ulong), # unsigned long int pr_sighold; /* Set of held signals. */ - ("pr_pid", ctypes.c_int), # __pid_t pr_pid; - ("pr_ppid", ctypes.c_int), # __pid_t pr_ppid; - ("pr_pgrp", ctypes.c_int), # __pid_t pr_pgrp; - ("pr_sid", ctypes.c_int), # __pid_t pr_sid; - ("pr_utime", timeval), # struct timeval pr_utime; /* User time. */ - ("pr_stime", timeval), # struct timeval pr_stime; /* System time. */ - ("pr_cutime", timeval), # struct timeval pr_cutime; /* Cumulative user time. */ - ("pr_cstime", timeval), # struct timeval pr_cstime; /* Cumulative system time. */ - ("pr_reg", elf_gregset_t), # elf_gregset_t pr_reg; /* GP registers. */ - ("pr_fpvalid", ctypes.c_int) # int pr_fpvalid; /* True if math copro being used. */ - ] # }; + +class elf_prstatus(ctypes.Structure): # struct elf_prstatus + _fields_ = [ # { + ( + "pr_info", elf_siginfo + ), # struct elf_siginfo pr_info; /* Info associated with signal. */ + ("pr_cursig", ctypes.c_short + ), # short int pr_cursig; /* Current signal. */ + ( + "pr_sigpend", ctypes.c_ulong + ), # unsigned long int pr_sigpend; /* Set of pending signals. */ + ( + "pr_sighold", ctypes.c_ulong + ), # unsigned long int pr_sighold; /* Set of held signals. */ + ("pr_pid", ctypes.c_int), # __pid_t pr_pid; + ("pr_ppid", ctypes.c_int), # __pid_t pr_ppid; + ("pr_pgrp", ctypes.c_int), # __pid_t pr_pgrp; + ("pr_sid", ctypes.c_int), # __pid_t pr_sid; + ("pr_utime", + timeval), # struct timeval pr_utime; /* User time. */ + ("pr_stime", timeval + ), # struct timeval pr_stime; /* System time. */ + ( + "pr_cutime", timeval + ), # struct timeval pr_cutime; /* Cumulative user time. */ + ( + "pr_cstime", timeval + ), # struct timeval pr_cstime; /* Cumulative system time. */ + ("pr_reg", elf_gregset_t + ), # elf_gregset_t pr_reg; /* GP registers. */ + ( + "pr_fpvalid", ctypes.c_int + ) # int pr_fpvalid; /* True if math copro being used. */ + ] # }; # elf_prpsinfo related constants. -ELF_PRARGSZ = 80 # #define ELF_PRARGSZ (80) /* Number of chars for args. */ - -class elf_prpsinfo(ctypes.Structure): # struct elf_prpsinfo - _fields_ = [ # { - ("pr_state", ctypes.c_byte), # char pr_state; /* Numeric process state. */ - ("pr_sname", ctypes.c_char), # char pr_sname; /* Char for pr_state. */ - ("pr_zomb", ctypes.c_byte), # char pr_zomb; /* Zombie. */ - ("pr_nice", ctypes.c_byte), # char pr_nice; /* Nice val. */ - ("pr_flag", ctypes.c_ulong), # unsigned long int pr_flag; /* Flags. */ - # #if __WORDSIZE == 32 - # unsigned short int pr_uid; - # unsigned short int pr_gid; - # #else - ("pr_uid", ctypes.c_uint), # unsigned int pr_uid; - ("pr_gid", ctypes.c_uint), # unsigned int pr_gid; - # #endif - ("pr_pid", ctypes.c_int), # int pr_pid, pr_ppid, pr_pgrp, pr_sid; - ("pr_ppid", ctypes.c_int), - ("pr_pgrp", ctypes.c_int), - ("pr_sid", ctypes.c_int), - # /* Lots missing */ - ("pr_fname", ctypes.c_char*16), # char pr_fname[16]; /* Filename of executable. */ - ("pr_psargs", ctypes.c_char*ELF_PRARGSZ) # char pr_psargs[ELF_PRARGSZ]; /* Initial part of arg list. */ - ] # }; +ELF_PRARGSZ = 80 # #define ELF_PRARGSZ (80) /* Number of chars for args. */ -class user_fpregs_struct(ctypes.Structure): # struct user_fpregs_struct - _fields_ = [ # { - ("cwd", ctypes.c_ushort), # unsigned short int cwd; - ("swd", ctypes.c_ushort), # unsigned short int swd; - ("ftw", ctypes.c_ushort), # unsigned short int ftw; - ("fop", ctypes.c_ushort), # unsigned short int fop; - ("rip", ctypes.c_ulonglong), # __extension__ unsigned long long int rip; - ("rdp", ctypes.c_ulonglong), # __extension__ unsigned long long int rdp; - ("mxcsr", ctypes.c_uint), # unsigned int mxcsr; - ("mxcr_mask", ctypes.c_uint), # unsigned int mxcr_mask; - ("st_space", ctypes.c_uint*32), # unsigned int st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ - ("xmm_space", ctypes.c_uint*64), # unsigned int xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */ - ("padding", ctypes.c_uint*24), # unsigned int padding[24]; - ] # }; +class elf_prpsinfo(ctypes.Structure): # struct elf_prpsinfo + _fields_ = [ # { + ( + "pr_state", ctypes.c_byte + ), # char pr_state; /* Numeric process state. */ + ( + "pr_sname", ctypes.c_char + ), # char pr_sname; /* Char for pr_state. */ + ("pr_zomb", ctypes.c_byte + ), # char pr_zomb; /* Zombie. */ + ("pr_nice", ctypes.c_byte + ), # char pr_nice; /* Nice val. */ + ("pr_flag", ctypes.c_ulong + ), # unsigned long int pr_flag; /* Flags. */ + # #if __WORDSIZE == 32 + # unsigned short int pr_uid; + # unsigned short int pr_gid; + # #else + ("pr_uid", ctypes.c_uint), # unsigned int pr_uid; + ("pr_gid", ctypes.c_uint), # unsigned int pr_gid; + # #endif + ("pr_pid", ctypes.c_int), # int pr_pid, pr_ppid, pr_pgrp, pr_sid; + ("pr_ppid", ctypes.c_int), + ("pr_pgrp", ctypes.c_int), + ("pr_sid", ctypes.c_int), + # /* Lots missing */ + ( + "pr_fname", ctypes.c_char * 16 + ), # char pr_fname[16]; /* Filename of executable. */ + ( + "pr_psargs", ctypes.c_char * ELF_PRARGSZ + ) # char pr_psargs[ELF_PRARGSZ]; /* Initial part of arg list. */ + ] # }; + + +class user_fpregs_struct(ctypes.Structure): # struct user_fpregs_struct + _fields_ = [ # { + ("cwd", ctypes.c_ushort), # unsigned short int cwd; + ("swd", ctypes.c_ushort), # unsigned short int swd; + ("ftw", ctypes.c_ushort), # unsigned short int ftw; + ("fop", ctypes.c_ushort), # unsigned short int fop; + ("rip", + ctypes.c_ulonglong), # __extension__ unsigned long long int rip; + ("rdp", + ctypes.c_ulonglong), # __extension__ unsigned long long int rdp; + ("mxcsr", ctypes.c_uint), # unsigned int mxcsr; + ("mxcr_mask", ctypes.c_uint), # unsigned int mxcr_mask; + ( + "st_space", ctypes.c_uint * 32 + ), # unsigned int st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ + ( + "xmm_space", ctypes.c_uint * 64 + ), # unsigned int xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */ + ("padding", + ctypes.c_uint * 24), # unsigned int padding[24]; + ] # }; elf_fpregset_t = user_fpregs_struct - # siginfo_t related constants. -_SI_MAX_SIZE = 128 -_SI_PAD_SIZE = (_SI_MAX_SIZE/ctypes.sizeof(ctypes.c_int)) - 4 +_SI_MAX_SIZE = 128 +_SI_PAD_SIZE = (_SI_MAX_SIZE / ctypes.sizeof(ctypes.c_int)) - 4 - # /* kill(). */ -class _siginfo_t_U_kill(ctypes.Structure): # struct - _fields_ = [ # { - ("si_pid", ctypes.c_int), # __pid_t si_pid; /* Sending process ID. */ - ("si_uid", ctypes.c_uint) # __uid_t si_uid; /* Real user ID of sending process. */ - ] # } _kill; +# /* kill(). */ +class _siginfo_t_U_kill(ctypes.Structure): # struct + _fields_ = [ # { + ("si_pid", ctypes.c_int + ), # __pid_t si_pid; /* Sending process ID. */ + ( + "si_uid", ctypes.c_uint + ) # __uid_t si_uid; /* Real user ID of sending process. */ + ] # } _kill; # Type for data associated with a signal. -class sigval_t(ctypes.Union): # typedef union sigval - _fields_ = [ # { - ("sival_int", ctypes.c_int), # int sival_int; - ("sical_ptr", ctypes.c_void_p), # void *sival_ptr; - ] # } sigval_t; - - # /* POSIX.1b timers. */ -class _siginfo_t_U_timer(ctypes.Structure): # struct - _fields_ = [ # { - ("si_tid", ctypes.c_int), # int si_tid; /* Timer ID. */ - ("si_overrun", ctypes.c_int), # int si_overrun; /* Overrun count. */ - ("si_sigval", sigval_t) # sigval_t si_sigval; /* Signal value. */ - ] # } _timer; +class sigval_t(ctypes.Union): # typedef union sigval + _fields_ = [ # { + ("sival_int", ctypes.c_int), # int sival_int; + ("sical_ptr", ctypes.c_void_p), # void *sival_ptr; + ] # } sigval_t; - # /* POSIX.1b signals. */ -class _siginfo_t_U_rt(ctypes.Structure): # struct - _fields_ = [ # { - ("si_pid", ctypes.c_int), # __pid_t si_pid; /* Sending process ID. */ - ("si_uid", ctypes.c_uint), # __uid_t si_uid; /* Real user ID of sending process. */ - ("si_sigval", sigval_t) # sigval_t si_sigval; /* Signal value. */ - ] # } _rt; + # /* POSIX.1b timers. */ +class _siginfo_t_U_timer(ctypes.Structure): # struct + _fields_ = [ # { + ("si_tid", + ctypes.c_int), # int si_tid; /* Timer ID. */ + ("si_overrun", ctypes.c_int + ), # int si_overrun; /* Overrun count. */ + ("si_sigval", sigval_t + ) # sigval_t si_sigval; /* Signal value. */ + ] # } _timer; - # /* SIGCHLD. */ -class _siginfo_t_U_sigchld(ctypes.Structure): # struct - _fields_ = [ # { - ("si_pid", ctypes.c_int), # __pid_t si_pid; /* Which child. */ - ("si_uid", ctypes.c_uint), # __uid_t si_uid; /* Real user ID of sending process. */ - ("si_status", ctypes.c_int), # int si_status; /* Exit value or signal. */ - ("si_utime", ctypes.c_long), # __sigchld_clock_t si_utime; - ("si_stime", ctypes.c_long) # __sigchld_clock_t si_stime; - ] # } _sigchld; - - # /* SIGILL, SIGFPE, SIGSEGV, SIGBUS. */ -class _siginfo_t_U_sigfault(ctypes.Structure): # struct - _fields_ = [ # { - ("si_addr", ctypes.c_void_p), # void *si_addr; /* Faulting insn/memory ref. */ - ("si_addr_lsb", ctypes.c_short) # short int si_addr_lsb; /* Valid LSB of the reported address. */ - ] # } _sigfault; - - # /* SIGPOLL. */ -class _siginfo_t_U_sigpoll(ctypes.Structure): # struct - _fields_ = [ # { - ("si_band", ctypes.c_long), # long int si_band; /* Band event for SIGPOLL. */ - ("si_fd", ctypes.c_int) # int si_fd; - ] # } _sigpoll; + # /* POSIX.1b signals. */ +class _siginfo_t_U_rt(ctypes.Structure): # struct + _fields_ = [ # { + ("si_pid", ctypes.c_int + ), # __pid_t si_pid; /* Sending process ID. */ + ( + "si_uid", ctypes.c_uint + ), # __uid_t si_uid; /* Real user ID of sending process. */ + ("si_sigval", sigval_t + ) # sigval_t si_sigval; /* Signal value. */ + ] # } _rt; - # /* SIGSYS. */ -class _siginfo_t_U_sigsys(ctypes.Structure): # struct - _fields_ = [ # { - ("_call_addr", ctypes.c_void_p), # void *_call_addr; /* Calling user insn. */ - ("_syscall", ctypes.c_int), # int _syscall; /* Triggering system call number. */ - ("_arch", ctypes.c_uint) # unsigned int _arch; /* AUDIT_ARCH_* of syscall. */ - ] # } _sigsys; + # /* SIGCHLD. */ +class _siginfo_t_U_sigchld(ctypes.Structure): # struct + _fields_ = [ # { + ("si_pid", + ctypes.c_int), # __pid_t si_pid; /* Which child. */ + ( + "si_uid", ctypes.c_uint + ), # __uid_t si_uid; /* Real user ID of sending process. */ + ("si_status", ctypes.c_int + ), # int si_status; /* Exit value or signal. */ + ("si_utime", ctypes.c_long), # __sigchld_clock_t si_utime; + ("si_stime", ctypes.c_long) # __sigchld_clock_t si_stime; + ] # } _sigchld; -class _siginfo_t_U(ctypes.Union): # union - _fields_ = [ # { - ("_pad", ctypes.c_int*_SI_PAD_SIZE), # int _pad[__SI_PAD_SIZE]; - # - # /* kill(). */ - ("_kill", _siginfo_t_U_kill), # struct - # { - # __pid_t si_pid; /* Sending process ID. */ - # __uid_t si_uid; /* Real user ID of sending process. */ - # } _kill; - # - # /* POSIX.1b timers. */ - ("_timer", _siginfo_t_U_timer), # struct - # { - # int si_tid; /* Timer ID. */ - # int si_overrun; /* Overrun count. */ - # sigval_t si_sigval; /* Signal value. */ - # } _timer; - # - # /* POSIX.1b signals. */ - ("_rt", _siginfo_t_U_rt), # struct - # { - # __pid_t si_pid; /* Sending process ID. */ - # __uid_t si_uid; /* Real user ID of sending process. */ - # sigval_t si_sigval; /* Signal value. */ - # } _rt; - # - # /* SIGCHLD. */ - ("_sigchld", _siginfo_t_U_sigchld), # struct - # { - # __pid_t si_pid; /* Which child. */ - # __uid_t si_uid; /* Real user ID of sending process. */ - # int si_status; /* Exit value or signal. */ - # __sigchld_clock_t si_utime; - # __sigchld_clock_t si_stime; - # } _sigchld; - # - # /* SIGILL, SIGFPE, SIGSEGV, SIGBUS. */ - ("_sigfault", _siginfo_t_U_sigfault), # struct - # { - # void *si_addr; /* Faulting insn/memory ref. */ - # short int si_addr_lsb; /* Valid LSB of the reported address. */ - # } _sigfault; - # - # /* SIGPOLL. */ - ("_sigpoll", _siginfo_t_U_sigpoll), # struct - # { - # long int si_band; /* Band event for SIGPOLL. */ - # int si_fd; - # } _sigpoll; - # - # /* SIGSYS. */ - ("_sigsys", _siginfo_t_U_sigpoll) # struct - # { - # void *_call_addr; /* Calling user insn. */ - # int _syscall; /* Triggering system call number. */ - # unsigned int _arch; /* AUDIT_ARCH_* of syscall. */ - # } _sigsys; - ] # } _sifields; + # /* SIGILL, SIGFPE, SIGSEGV, SIGBUS. */ +class _siginfo_t_U_sigfault(ctypes.Structure): # struct + _fields_ = [ # { + ("si_addr", ctypes.c_void_p + ), # void *si_addr; /* Faulting insn/memory ref. */ + ( + "si_addr_lsb", ctypes.c_short + ) # short int si_addr_lsb; /* Valid LSB of the reported address. */ + ] # } _sigfault; -class siginfo_t(ctypes.Structure): # typedef struct - _fields_ = [ # { - ("si_signo", ctypes.c_int), # int si_signo; /* Signal number. */ - ("si_errno", ctypes.c_int), # int si_errno; /* If non-zero, an errno value associated with - # this signal, as defined in . */ - ("si_code", ctypes.c_int), # int si_code; /* Signal code. */ - # - ("_sifields", _siginfo_t_U) # union - # { - # int _pad[__SI_PAD_SIZE]; - # - # /* kill(). */ - # struct - # { - # __pid_t si_pid; /* Sending process ID. */ - # __uid_t si_uid; /* Real user ID of sending process. */ - # } _kill; - # - # /* POSIX.1b timers. */ - # struct - # { - # int si_tid; /* Timer ID. */ - # int si_overrun; /* Overrun count. */ - # sigval_t si_sigval; /* Signal value. */ - # } _timer; - # - # /* POSIX.1b signals. */ - # struct - # { - # __pid_t si_pid; /* Sending process ID. */ - # __uid_t si_uid; /* Real user ID of sending process. */ - # sigval_t si_sigval; /* Signal value. */ - # } _rt; - # - # /* SIGCHLD. */ - # struct - # { - # __pid_t si_pid; /* Which child. */ - # __uid_t si_uid; /* Real user ID of sending process. */ - # int si_status; /* Exit value or signal. */ - # __sigchld_clock_t si_utime; - # __sigchld_clock_t si_stime; - # } _sigchld; - # - # /* SIGILL, SIGFPE, SIGSEGV, SIGBUS. */ - # struct - # { - # void *si_addr; /* Faulting insn/memory ref. */ - # short int si_addr_lsb; /* Valid LSB of the reported address. */ - # } _sigfault; - # - # /* SIGPOLL. */ - # struct - # { - # long int si_band; /* Band event for SIGPOLL. */ - # int si_fd; - # } _sigpoll; - # - # /* SIGSYS. */ - # struct - # { - # void *_call_addr; /* Calling user insn. */ - # int _syscall; /* Triggering system call number. */ - # unsigned int _arch; /* AUDIT_ARCH_* of syscall. */ - # } _sigsys; - # } _sifields; - ] # } siginfo_t __SI_ALIGNMENT; + + # /* SIGPOLL. */ +class _siginfo_t_U_sigpoll(ctypes.Structure): # struct + _fields_ = [ # { + ("si_band", ctypes.c_long + ), # long int si_band; /* Band event for SIGPOLL. */ + ("si_fd", ctypes.c_int) # int si_fd; + ] # } _sigpoll; + + + # /* SIGSYS. */ +class _siginfo_t_U_sigsys(ctypes.Structure): # struct + _fields_ = [ # { + ("_call_addr", ctypes.c_void_p + ), # void *_call_addr; /* Calling user insn. */ + ( + "_syscall", ctypes.c_int + ), # int _syscall; /* Triggering system call number. */ + ("_arch", ctypes.c_uint + ) # unsigned int _arch; /* AUDIT_ARCH_* of syscall. */ + ] # } _sigsys; + + +class _siginfo_t_U(ctypes.Union): # union + _fields_ = [ # { + ("_pad", + ctypes.c_int * _SI_PAD_SIZE), # int _pad[__SI_PAD_SIZE]; + # + # /* kill(). */ + ("_kill", _siginfo_t_U_kill), # struct + # { + # __pid_t si_pid; /* Sending process ID. */ + # __uid_t si_uid; /* Real user ID of sending process. */ + # } _kill; + # + # /* POSIX.1b timers. */ + ("_timer", _siginfo_t_U_timer), # struct + # { + # int si_tid; /* Timer ID. */ + # int si_overrun; /* Overrun count. */ + # sigval_t si_sigval; /* Signal value. */ + # } _timer; + # + # /* POSIX.1b signals. */ + ("_rt", _siginfo_t_U_rt), # struct + # { + # __pid_t si_pid; /* Sending process ID. */ + # __uid_t si_uid; /* Real user ID of sending process. */ + # sigval_t si_sigval; /* Signal value. */ + # } _rt; + # + # /* SIGCHLD. */ + ("_sigchld", _siginfo_t_U_sigchld), # struct + # { + # __pid_t si_pid; /* Which child. */ + # __uid_t si_uid; /* Real user ID of sending process. */ + # int si_status; /* Exit value or signal. */ + # __sigchld_clock_t si_utime; + # __sigchld_clock_t si_stime; + # } _sigchld; + # + # /* SIGILL, SIGFPE, SIGSEGV, SIGBUS. */ + ("_sigfault", _siginfo_t_U_sigfault), # struct + # { + # void *si_addr; /* Faulting insn/memory ref. */ + # short int si_addr_lsb; /* Valid LSB of the reported address. */ + # } _sigfault; + # + # /* SIGPOLL. */ + ("_sigpoll", _siginfo_t_U_sigpoll), # struct + # { + # long int si_band; /* Band event for SIGPOLL. */ + # int si_fd; + # } _sigpoll; + # + # /* SIGSYS. */ + ("_sigsys", _siginfo_t_U_sigpoll) # struct + # { + # void *_call_addr; /* Calling user insn. */ + # int _syscall; /* Triggering system call number. */ + # unsigned int _arch; /* AUDIT_ARCH_* of syscall. */ + # } _sigsys; + ] # } _sifields; + + +class siginfo_t(ctypes.Structure): # typedef struct + _fields_ = [ # { + ("si_signo", ctypes.c_int + ), # int si_signo; /* Signal number. */ + ( + "si_errno", ctypes.c_int + ), # int si_errno; /* If non-zero, an errno value associated with + # this signal, as defined in . */ + ("si_code", ctypes.c_int + ), # int si_code; /* Signal code. */ + # + ("_sifields", _siginfo_t_U) # union + # { + # int _pad[__SI_PAD_SIZE]; + # + # /* kill(). */ + # struct + # { + # __pid_t si_pid; /* Sending process ID. */ + # __uid_t si_uid; /* Real user ID of sending process. */ + # } _kill; + # + # /* POSIX.1b timers. */ + # struct + # { + # int si_tid; /* Timer ID. */ + # int si_overrun; /* Overrun count. */ + # sigval_t si_sigval; /* Signal value. */ + # } _timer; + # + # /* POSIX.1b signals. */ + # struct + # { + # __pid_t si_pid; /* Sending process ID. */ + # __uid_t si_uid; /* Real user ID of sending process. */ + # sigval_t si_sigval; /* Signal value. */ + # } _rt; + # + # /* SIGCHLD. */ + # struct + # { + # __pid_t si_pid; /* Which child. */ + # __uid_t si_uid; /* Real user ID of sending process. */ + # int si_status; /* Exit value or signal. */ + # __sigchld_clock_t si_utime; + # __sigchld_clock_t si_stime; + # } _sigchld; + # + # /* SIGILL, SIGFPE, SIGSEGV, SIGBUS. */ + # struct + # { + # void *si_addr; /* Faulting insn/memory ref. */ + # short int si_addr_lsb; /* Valid LSB of the reported address. */ + # } _sigfault; + # + # /* SIGPOLL. */ + # struct + # { + # long int si_band; /* Band event for SIGPOLL. */ + # int si_fd; + # } _sigpoll; + # + # /* SIGSYS. */ + # struct + # { + # void *_call_addr; /* Calling user insn. */ + # int _syscall; /* Triggering system call number. */ + # unsigned int _arch; /* AUDIT_ARCH_* of syscall. */ + # } _sigsys; + # } _sifields; + ] # } siginfo_t __SI_ALIGNMENT; # xsave related. -class ymmh_struct(ctypes.Structure): # struct ymmh_struct { - _fields_ = [ - ("ymmh_space", 64*ctypes.c_uint) # u32 ymmh_space[64]; - ] # } __packed; + +class ymmh_struct(ctypes.Structure): # struct ymmh_struct { + _fields_ = [("ymmh_space", 64 * ctypes.c_uint + ) # u32 ymmh_space[64]; + ] # } __packed; -class xsave_hdr_struct(ctypes.Structure): # struct xsave_hdr_struct { - _fields_ = [ - ("xstate_bv", ctypes.c_ulonglong), # u64 xstate_bv; - ("reserved1", ctypes.c_ulonglong*2), # u64 reserved1[2]; - ("reserved2", ctypes.c_ulonglong*5) # u64 reserved2[5]; - ] # } __packed; +class xsave_hdr_struct(ctypes.Structure): # struct xsave_hdr_struct { + _fields_ = [ + ("xstate_bv", ctypes.c_ulonglong + ), # u64 xstate_bv; + ("reserved1", ctypes.c_ulonglong * + 2), # u64 reserved1[2]; + ("reserved2", ctypes.c_ulonglong * 5 + ) # u64 reserved2[5]; + ] # } __packed; -class i387_fxsave_struct(ctypes.Structure): # struct i387_fxsave_struct { - _fields_ = [ - ("cwd", ctypes.c_ushort), # u16 cwd; /* Control Word */ - ("swd", ctypes.c_ushort), # u16 swd; /* Status Word */ - ("twd", ctypes.c_ushort), # u16 twd; /* Tag Word */ - ("fop", ctypes.c_ushort), # u16 fop; /* Last Instruction Opcode */ - # union { - # struct { - ("rip", ctypes.c_ulonglong), # u64 rip; /* Instruction Pointer */ - ("rdp", ctypes.c_ulonglong), # u64 rdp; /* Data Pointer */ - # }; - # struct { - # u32 fip; /* FPU IP Offset */ - # u32 fcs; /* FPU IP Selector */ - # u32 foo; /* FPU Operand Offset */ - # u32 fos; /* FPU Operand Selector */ - # }; - # }; - ("mxcsr", ctypes.c_uint), # u32 mxcsr; /* MXCSR Register State */ - ("mxcsr_mask", ctypes.c_uint), # u32 mxcsr_mask; /* MXCSR Mask */ - # - # /* 8*16 bytes for each FP-reg = 128 bytes */ - ("st_space", ctypes.c_uint*32), # u32 st_space[32]; -# - # /* 16*16 bytes for each XMM-reg = 256 bytes */ - ("xmm_space", ctypes.c_uint*64), # u32 xmm_space[64]; - # - ("padding", ctypes.c_uint*12), # u32 padding[12]; - # - # union { - ("padding1", ctypes.c_uint*12) # u32 padding1[12]; - # u32 sw_reserved[12]; - # }; - # - ] # } __aligned(16); +class i387_fxsave_struct(ctypes.Structure): # struct i387_fxsave_struct { + _fields_ = [ + ( + "cwd", ctypes.c_ushort + ), # u16 cwd; /* Control Word */ + ( + "swd", ctypes.c_ushort + ), # u16 swd; /* Status Word */ + ( + "twd", ctypes.c_ushort + ), # u16 twd; /* Tag Word */ + ( + "fop", ctypes.c_ushort + ), # u16 fop; /* Last Instruction Opcode */ + # union { + # struct { + ( + "rip", ctypes.c_ulonglong + ), # u64 rip; /* Instruction Pointer */ + ( + "rdp", ctypes.c_ulonglong + ), # u64 rdp; /* Data Pointer */ + # }; + # struct { + # u32 fip; /* FPU IP Offset */ + # u32 fcs; /* FPU IP Selector */ + # u32 foo; /* FPU Operand Offset */ + # u32 fos; /* FPU Operand Selector */ + # }; + # }; + ( + "mxcsr", ctypes.c_uint + ), # u32 mxcsr; /* MXCSR Register State */ + ( + "mxcsr_mask", ctypes.c_uint + ), # u32 mxcsr_mask; /* MXCSR Mask */ + # + # /* 8*16 bytes for each FP-reg = 128 bytes */ + ("st_space", ctypes.c_uint * 32 + ), # u32 st_space[32]; + # + # /* 16*16 bytes for each XMM-reg = 256 bytes */ + ("xmm_space", ctypes.c_uint * 64 + ), # u32 xmm_space[64]; + # + ("padding", ctypes.c_uint * 12 + ), # u32 padding[12]; + # + # union { + ("padding1", ctypes.c_uint * 12 + ) # u32 padding1[12]; + # u32 sw_reserved[12]; + # }; + # + ] # } __aligned(16); -class elf_xsave_struct(ctypes.Structure): # struct xsave_struct { - _fields_ = [ - ("i387", i387_fxsave_struct), # struct i387_fxsave_struct i387; - ("xsave_hdr", xsave_hdr_struct), # struct xsave_hdr_struct xsave_hdr; - ("ymmh", ymmh_struct) # struct ymmh_struct ymmh; - ] # } __aligned(FP_MIN_ALIGN_BYTES) __packed; +class elf_xsave_struct(ctypes.Structure): # struct xsave_struct { + _fields_ = [ + ("i387", + i387_fxsave_struct), # struct i387_fxsave_struct i387; + ("xsave_hdr", xsave_hdr_struct + ), # struct xsave_hdr_struct xsave_hdr; + ("ymmh", ymmh_struct) # struct ymmh_struct ymmh; + ] # } __aligned(FP_MIN_ALIGN_BYTES) __packed; diff --git a/lib/py/cli.py b/lib/py/cli.py index abaf0720c..da343022e 100755 --- a/lib/py/cli.py +++ b/lib/py/cli.py @@ -6,337 +6,409 @@ import os import pycriu + def inf(opts): - if opts['in']: - return open(opts['in'], 'rb') - else: - return sys.stdin + if opts['in']: + return open(opts['in'], 'rb') + else: + return sys.stdin + def outf(opts): - if opts['out']: - return open(opts['out'], 'w+') - else: - return sys.stdout + if opts['out']: + return open(opts['out'], 'w+') + else: + return sys.stdout + def dinf(opts, name): - return open(os.path.join(opts['dir'], name)) + return open(os.path.join(opts['dir'], name)) + def decode(opts): - indent = None + indent = None - try: - img = pycriu.images.load(inf(opts), opts['pretty'], opts['nopl']) - except pycriu.images.MagicException as exc: - print("Unknown magic %#x.\n"\ - "Maybe you are feeding me an image with "\ - "raw data(i.e. pages.img)?" % exc.magic, file=sys.stderr) - sys.exit(1) + try: + img = pycriu.images.load(inf(opts), opts['pretty'], opts['nopl']) + except pycriu.images.MagicException as exc: + print("Unknown magic %#x.\n"\ + "Maybe you are feeding me an image with "\ + "raw data(i.e. pages.img)?" % exc.magic, file=sys.stderr) + sys.exit(1) - if opts['pretty']: - indent = 4 + if opts['pretty']: + indent = 4 + + f = outf(opts) + json.dump(img, f, indent=indent) + if f == sys.stdout: + f.write("\n") - f = outf(opts) - json.dump(img, f, indent=indent) - if f == sys.stdout: - f.write("\n") def encode(opts): - img = json.load(inf(opts)) - pycriu.images.dump(img, outf(opts)) + img = json.load(inf(opts)) + pycriu.images.dump(img, outf(opts)) + def info(opts): - infs = pycriu.images.info(inf(opts)) - json.dump(infs, sys.stdout, indent = 4) - print() + infs = pycriu.images.info(inf(opts)) + json.dump(infs, sys.stdout, indent=4) + print() + def get_task_id(p, val): - return p[val] if val in p else p['ns_' + val][0] + return p[val] if val in p else p['ns_' + val][0] + + # # Explorers # -class ps_item: - def __init__(self, p, core): - self.pid = get_task_id(p, 'pid') - self.ppid = p['ppid'] - self.p = p - self.core = core - self.kids = [] -def show_ps(p, opts, depth = 0): - print("%7d%7d%7d %s%s" % (p.pid, get_task_id(p.p, 'pgid'), get_task_id(p.p, 'sid'), - ' ' * (4 * depth), p.core['tc']['comm'])) - for kid in p.kids: - show_ps(kid, opts, depth + 1) +class ps_item: + def __init__(self, p, core): + self.pid = get_task_id(p, 'pid') + self.ppid = p['ppid'] + self.p = p + self.core = core + self.kids = [] + + +def show_ps(p, opts, depth=0): + print("%7d%7d%7d %s%s" % + (p.pid, get_task_id(p.p, 'pgid'), get_task_id(p.p, 'sid'), ' ' * + (4 * depth), p.core['tc']['comm'])) + for kid in p.kids: + show_ps(kid, opts, depth + 1) + def explore_ps(opts): - pss = { } - ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) - for p in ps_img['entries']: - core = pycriu.images.load(dinf(opts, 'core-%d.img' % get_task_id(p, 'pid'))) - ps = ps_item(p, core['entries'][0]) - pss[ps.pid] = ps + pss = {} + ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) + for p in ps_img['entries']: + core = pycriu.images.load( + dinf(opts, 'core-%d.img' % get_task_id(p, 'pid'))) + ps = ps_item(p, core['entries'][0]) + pss[ps.pid] = ps - # Build tree - psr = None - for pid in pss: - p = pss[pid] - if p.ppid == 0: - psr = p - continue + # Build tree + psr = None + for pid in pss: + p = pss[pid] + if p.ppid == 0: + psr = p + continue - pp = pss[p.ppid] - pp.kids.append(p) + pp = pss[p.ppid] + pp.kids.append(p) + + print("%7s%7s%7s %s" % ('PID', 'PGID', 'SID', 'COMM')) + show_ps(psr, opts) - print("%7s%7s%7s %s" % ('PID', 'PGID', 'SID', 'COMM')) - show_ps(psr, opts) files_img = None + def ftype_find_in_files(opts, ft, fid): - global files_img + global files_img - if files_img is None: - try: - files_img = pycriu.images.load(dinf(opts, "files.img"))['entries'] - except: - files_img = [] + if files_img is None: + try: + files_img = pycriu.images.load(dinf(opts, "files.img"))['entries'] + except: + files_img = [] - if len(files_img) == 0: - return None + if len(files_img) == 0: + return None - for f in files_img: - if f['id'] == fid: - return f + for f in files_img: + if f['id'] == fid: + return f - return None + return None def ftype_find_in_image(opts, ft, fid, img): - f = ftype_find_in_files(opts, ft, fid) - if f: - return f[ft['field']] + f = ftype_find_in_files(opts, ft, fid) + if f: + return f[ft['field']] + + if ft['img'] == None: + ft['img'] = pycriu.images.load(dinf(opts, img))['entries'] + for f in ft['img']: + if f['id'] == fid: + return f + return None - if ft['img'] == None: - ft['img'] = pycriu.images.load(dinf(opts, img))['entries'] - for f in ft['img']: - if f['id'] == fid: - return f - return None def ftype_reg(opts, ft, fid): - rf = ftype_find_in_image(opts, ft, fid, 'reg-files.img') - return rf and rf['name'] or 'unknown path' + rf = ftype_find_in_image(opts, ft, fid, 'reg-files.img') + return rf and rf['name'] or 'unknown path' + def ftype_pipe(opts, ft, fid): - p = ftype_find_in_image(opts, ft, fid, 'pipes.img') - return p and 'pipe[%d]' % p['pipe_id'] or 'pipe[?]' + p = ftype_find_in_image(opts, ft, fid, 'pipes.img') + return p and 'pipe[%d]' % p['pipe_id'] or 'pipe[?]' + def ftype_unix(opts, ft, fid): - ux = ftype_find_in_image(opts, ft, fid, 'unixsk.img') - if not ux: - return 'unix[?]' + ux = ftype_find_in_image(opts, ft, fid, 'unixsk.img') + if not ux: + return 'unix[?]' + + n = ux['name'] and ' %s' % ux['name'] or '' + return 'unix[%d (%d)%s]' % (ux['ino'], ux['peer'], n) - n = ux['name'] and ' %s' % ux['name'] or '' - return 'unix[%d (%d)%s]' % (ux['ino'], ux['peer'], n) file_types = { - 'REG': {'get': ftype_reg, 'img': None, 'field': 'reg'}, - 'PIPE': {'get': ftype_pipe, 'img': None, 'field': 'pipe'}, - 'UNIXSK': {'get': ftype_unix, 'img': None, 'field': 'usk'}, + 'REG': { + 'get': ftype_reg, + 'img': None, + 'field': 'reg' + }, + 'PIPE': { + 'get': ftype_pipe, + 'img': None, + 'field': 'pipe' + }, + 'UNIXSK': { + 'get': ftype_unix, + 'img': None, + 'field': 'usk' + }, } -def ftype_gen(opts, ft, fid): - return '%s.%d' % (ft['typ'], fid) -files_cache = { } +def ftype_gen(opts, ft, fid): + return '%s.%d' % (ft['typ'], fid) + + +files_cache = {} + def get_file_str(opts, fd): - key = (fd['type'], fd['id']) - f = files_cache.get(key, None) - if not f: - ft = file_types.get(fd['type'], {'get': ftype_gen, 'typ': fd['type']}) - f = ft['get'](opts, ft, fd['id']) - files_cache[key] = f + key = (fd['type'], fd['id']) + f = files_cache.get(key, None) + if not f: + ft = file_types.get(fd['type'], {'get': ftype_gen, 'typ': fd['type']}) + f = ft['get'](opts, ft, fd['id']) + files_cache[key] = f + + return f - return f def explore_fds(opts): - ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) - for p in ps_img['entries']: - pid = get_task_id(p, 'pid') - idi = pycriu.images.load(dinf(opts, 'ids-%s.img' % pid)) - fdt = idi['entries'][0]['files_id'] - fdi = pycriu.images.load(dinf(opts, 'fdinfo-%d.img' % fdt)) + ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) + for p in ps_img['entries']: + pid = get_task_id(p, 'pid') + idi = pycriu.images.load(dinf(opts, 'ids-%s.img' % pid)) + fdt = idi['entries'][0]['files_id'] + fdi = pycriu.images.load(dinf(opts, 'fdinfo-%d.img' % fdt)) - print("%d" % pid) - for fd in fdi['entries']: - print("\t%7d: %s" % (fd['fd'], get_file_str(opts, fd))) + print("%d" % pid) + for fd in fdi['entries']: + print("\t%7d: %s" % (fd['fd'], get_file_str(opts, fd))) - fdi = pycriu.images.load(dinf(opts, 'fs-%d.img' % pid))['entries'][0] - print("\t%7s: %s" % ('cwd', get_file_str(opts, {'type': 'REG', 'id': fdi['cwd_id']}))) - print("\t%7s: %s" % ('root', get_file_str(opts, {'type': 'REG', 'id': fdi['root_id']}))) + fdi = pycriu.images.load(dinf(opts, 'fs-%d.img' % pid))['entries'][0] + print("\t%7s: %s" % + ('cwd', get_file_str(opts, { + 'type': 'REG', + 'id': fdi['cwd_id'] + }))) + print("\t%7s: %s" % + ('root', get_file_str(opts, { + 'type': 'REG', + 'id': fdi['root_id'] + }))) class vma_id: - def __init__(self): - self.__ids = {} - self.__last = 1 + def __init__(self): + self.__ids = {} + self.__last = 1 - def get(self, iid): - ret = self.__ids.get(iid, None) - if not ret: - ret = self.__last - self.__last += 1 - self.__ids[iid] = ret + def get(self, iid): + ret = self.__ids.get(iid, None) + if not ret: + ret = self.__last + self.__last += 1 + self.__ids[iid] = ret + + return ret - return ret def explore_mems(opts): - ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) - vids = vma_id() - for p in ps_img['entries']: - pid = get_task_id(p, 'pid') - mmi = pycriu.images.load(dinf(opts, 'mm-%d.img' % pid))['entries'][0] + ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) + vids = vma_id() + for p in ps_img['entries']: + pid = get_task_id(p, 'pid') + mmi = pycriu.images.load(dinf(opts, 'mm-%d.img' % pid))['entries'][0] - print("%d" % pid) - print("\t%-36s %s" % ('exe', get_file_str(opts, {'type': 'REG', 'id': mmi['exe_file_id']}))) + print("%d" % pid) + print("\t%-36s %s" % ('exe', + get_file_str(opts, { + 'type': 'REG', + 'id': mmi['exe_file_id'] + }))) - for vma in mmi['vmas']: - st = vma['status'] - if st & (1 << 10): - fn = ' ' + 'ips[%lx]' % vids.get(vma['shmid']) - elif st & (1 << 8): - fn = ' ' + 'shmem[%lx]' % vids.get(vma['shmid']) - elif st & (1 << 11): - fn = ' ' + 'packet[%lx]' % vids.get(vma['shmid']) - elif st & ((1 << 6) | (1 << 7)): - fn = ' ' + get_file_str(opts, {'type': 'REG', 'id': vma['shmid']}) - if vma['pgoff']: - fn += ' + %#lx' % vma['pgoff'] - if st & (1 << 7): - fn += ' (s)' - elif st & (1 << 1): - fn = ' [stack]' - elif st & (1 << 2): - fn = ' [vsyscall]' - elif st & (1 << 3): - fn = ' [vdso]' - elif vma['flags'] & 0x0100: # growsdown - fn = ' [stack?]' - else: - fn = '' + for vma in mmi['vmas']: + st = vma['status'] + if st & (1 << 10): + fn = ' ' + 'ips[%lx]' % vids.get(vma['shmid']) + elif st & (1 << 8): + fn = ' ' + 'shmem[%lx]' % vids.get(vma['shmid']) + elif st & (1 << 11): + fn = ' ' + 'packet[%lx]' % vids.get(vma['shmid']) + elif st & ((1 << 6) | (1 << 7)): + fn = ' ' + get_file_str(opts, { + 'type': 'REG', + 'id': vma['shmid'] + }) + if vma['pgoff']: + fn += ' + %#lx' % vma['pgoff'] + if st & (1 << 7): + fn += ' (s)' + elif st & (1 << 1): + fn = ' [stack]' + elif st & (1 << 2): + fn = ' [vsyscall]' + elif st & (1 << 3): + fn = ' [vdso]' + elif vma['flags'] & 0x0100: # growsdown + fn = ' [stack?]' + else: + fn = '' - if not st & (1 << 0): - fn += ' *' + if not st & (1 << 0): + fn += ' *' - prot = vma['prot'] & 0x1 and 'r' or '-' - prot += vma['prot'] & 0x2 and 'w' or '-' - prot += vma['prot'] & 0x4 and 'x' or '-' + prot = vma['prot'] & 0x1 and 'r' or '-' + prot += vma['prot'] & 0x2 and 'w' or '-' + prot += vma['prot'] & 0x4 and 'x' or '-' - astr = '%08lx-%08lx' % (vma['start'], vma['end']) - print("\t%-36s%s%s" % (astr, prot, fn)) + astr = '%08lx-%08lx' % (vma['start'], vma['end']) + print("\t%-36s%s%s" % (astr, prot, fn)) def explore_rss(opts): - ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) - for p in ps_img['entries']: - pid = get_task_id(p, 'pid') - vmas = pycriu.images.load(dinf(opts, 'mm-%d.img' % pid))['entries'][0]['vmas'] - pms = pycriu.images.load(dinf(opts, 'pagemap-%d.img' % pid))['entries'] + ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) + for p in ps_img['entries']: + pid = get_task_id(p, 'pid') + vmas = pycriu.images.load(dinf(opts, 'mm-%d.img' % + pid))['entries'][0]['vmas'] + pms = pycriu.images.load(dinf(opts, 'pagemap-%d.img' % pid))['entries'] - print("%d" % pid) - vmi = 0 - pvmi = -1 - for pm in pms[1:]: - pstr = '\t%lx / %-8d' % (pm['vaddr'], pm['nr_pages']) - while vmas[vmi]['end'] <= pm['vaddr']: - vmi += 1 + print("%d" % pid) + vmi = 0 + pvmi = -1 + for pm in pms[1:]: + pstr = '\t%lx / %-8d' % (pm['vaddr'], pm['nr_pages']) + while vmas[vmi]['end'] <= pm['vaddr']: + vmi += 1 - pme = pm['vaddr'] + (pm['nr_pages'] << 12) - vstr = '' - while vmas[vmi]['start'] < pme: - vma = vmas[vmi] - if vmi == pvmi: - vstr += ' ~' - else: - vstr += ' %08lx / %-8d' % (vma['start'], (vma['end'] - vma['start'])>>12) - if vma['status'] & ((1 << 6) | (1 << 7)): - vstr += ' ' + get_file_str(opts, {'type': 'REG', 'id': vma['shmid']}) - pvmi = vmi - vstr += '\n\t%23s' % '' - vmi += 1 + pme = pm['vaddr'] + (pm['nr_pages'] << 12) + vstr = '' + while vmas[vmi]['start'] < pme: + vma = vmas[vmi] + if vmi == pvmi: + vstr += ' ~' + else: + vstr += ' %08lx / %-8d' % ( + vma['start'], (vma['end'] - vma['start']) >> 12) + if vma['status'] & ((1 << 6) | (1 << 7)): + vstr += ' ' + get_file_str(opts, { + 'type': 'REG', + 'id': vma['shmid'] + }) + pvmi = vmi + vstr += '\n\t%23s' % '' + vmi += 1 - vmi -= 1 + vmi -= 1 - print('%-24s%s' % (pstr, vstr)) + print('%-24s%s' % (pstr, vstr)) +explorers = { + 'ps': explore_ps, + 'fds': explore_fds, + 'mems': explore_mems, + 'rss': explore_rss +} -explorers = { 'ps': explore_ps, 'fds': explore_fds, 'mems': explore_mems, 'rss': explore_rss } def explore(opts): - explorers[opts['what']](opts) + explorers[opts['what']](opts) + def main(): - desc = 'CRiu Image Tool' - parser = argparse.ArgumentParser(description=desc, - formatter_class=argparse.RawTextHelpFormatter) + desc = 'CRiu Image Tool' + parser = argparse.ArgumentParser( + description=desc, formatter_class=argparse.RawTextHelpFormatter) - subparsers = parser.add_subparsers(help='Use crit CMD --help for command-specific help') + subparsers = parser.add_subparsers( + help='Use crit CMD --help for command-specific help') - # Decode - decode_parser = subparsers.add_parser('decode', - help = 'convert criu image from binary type to json') - decode_parser.add_argument('--pretty', - help = 'Multiline with indents and some numerical fields in field-specific format', - action = 'store_true') - decode_parser.add_argument('-i', - '--in', - help = 'criu image in binary format to be decoded (stdin by default)') - decode_parser.add_argument('-o', - '--out', - help = 'where to put criu image in json format (stdout by default)') - decode_parser.set_defaults(func=decode, nopl=False) + # Decode + decode_parser = subparsers.add_parser( + 'decode', help='convert criu image from binary type to json') + decode_parser.add_argument( + '--pretty', + help= + 'Multiline with indents and some numerical fields in field-specific format', + action='store_true') + decode_parser.add_argument( + '-i', + '--in', + help='criu image in binary format to be decoded (stdin by default)') + decode_parser.add_argument( + '-o', + '--out', + help='where to put criu image in json format (stdout by default)') + decode_parser.set_defaults(func=decode, nopl=False) - # Encode - encode_parser = subparsers.add_parser('encode', - help = 'convert criu image from json type to binary') - encode_parser.add_argument('-i', - '--in', - help = 'criu image in json format to be encoded (stdin by default)') - encode_parser.add_argument('-o', - '--out', - help = 'where to put criu image in binary format (stdout by default)') - encode_parser.set_defaults(func=encode) + # Encode + encode_parser = subparsers.add_parser( + 'encode', help='convert criu image from json type to binary') + encode_parser.add_argument( + '-i', + '--in', + help='criu image in json format to be encoded (stdin by default)') + encode_parser.add_argument( + '-o', + '--out', + help='where to put criu image in binary format (stdout by default)') + encode_parser.set_defaults(func=encode) - # Info - info_parser = subparsers.add_parser('info', - help = 'show info about image') - info_parser.add_argument("in") - info_parser.set_defaults(func=info) + # Info + info_parser = subparsers.add_parser('info', help='show info about image') + info_parser.add_argument("in") + info_parser.set_defaults(func=info) - # Explore - x_parser = subparsers.add_parser('x', help = 'explore image dir') - x_parser.add_argument('dir') - x_parser.add_argument('what', choices = [ 'ps', 'fds', 'mems', 'rss']) - x_parser.set_defaults(func=explore) + # Explore + x_parser = subparsers.add_parser('x', help='explore image dir') + x_parser.add_argument('dir') + x_parser.add_argument('what', choices=['ps', 'fds', 'mems', 'rss']) + x_parser.set_defaults(func=explore) - # Show - show_parser = subparsers.add_parser('show', - help = "convert criu image from binary to human-readable json") - show_parser.add_argument("in") - show_parser.add_argument('--nopl', help = 'do not show entry payload (if exists)', action = 'store_true') - show_parser.set_defaults(func=decode, pretty=True, out=None) + # Show + show_parser = subparsers.add_parser( + 'show', help="convert criu image from binary to human-readable json") + show_parser.add_argument("in") + show_parser.add_argument('--nopl', + help='do not show entry payload (if exists)', + action='store_true') + show_parser.set_defaults(func=decode, pretty=True, out=None) - opts = vars(parser.parse_args()) + opts = vars(parser.parse_args()) - if not opts: - sys.stderr.write(parser.format_usage()) - sys.stderr.write("crit: error: too few arguments\n") - sys.exit(1) + if not opts: + sys.stderr.write(parser.format_usage()) + sys.stderr.write("crit: error: too few arguments\n") + sys.exit(1) + + opts["func"](opts) - opts["func"](opts) if __name__ == '__main__': - main() + main() diff --git a/lib/py/criu.py b/lib/py/criu.py index de1a214a3..d94fea9e1 100644 --- a/lib/py/criu.py +++ b/lib/py/criu.py @@ -8,325 +8,336 @@ import struct import pycriu.rpc_pb2 as rpc + class _criu_comm: - """ + """ Base class for communication classes. """ - COMM_SK = 0 - COMM_FD = 1 - COMM_BIN = 2 - comm_type = None - comm = None - sk = None + COMM_SK = 0 + COMM_FD = 1 + COMM_BIN = 2 + comm_type = None + comm = None + sk = None - def connect(self, daemon): - """ + def connect(self, daemon): + """ Connect to criu and return socket object. daemon -- is for whether or not criu should daemonize if executing criu from binary(comm_bin). """ - pass + pass - def disconnect(self): - """ + def disconnect(self): + """ Disconnect from criu. """ - pass + pass class _criu_comm_sk(_criu_comm): - """ + """ Communication class for unix socket. """ - def __init__(self, sk_path): - self.comm_type = self.COMM_SK - self.comm = sk_path - def connect(self, daemon): - self.sk = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) - self.sk.connect(self.comm) + def __init__(self, sk_path): + self.comm_type = self.COMM_SK + self.comm = sk_path - return self.sk + def connect(self, daemon): + self.sk = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) + self.sk.connect(self.comm) - def disconnect(self): - self.sk.close() + return self.sk + + def disconnect(self): + self.sk.close() class _criu_comm_fd(_criu_comm): - """ + """ Communication class for file descriptor. """ - def __init__(self, fd): - self.comm_type = self.COMM_FD - self.comm = fd - def connect(self, daemon): - self.sk = socket.fromfd(self.comm, socket.AF_UNIX, socket.SOCK_SEQPACKET) + def __init__(self, fd): + self.comm_type = self.COMM_FD + self.comm = fd - return self.sk + def connect(self, daemon): + self.sk = socket.fromfd(self.comm, socket.AF_UNIX, + socket.SOCK_SEQPACKET) + + return self.sk + + def disconnect(self): + self.sk.close() - def disconnect(self): - self.sk.close() class _criu_comm_bin(_criu_comm): - """ + """ Communication class for binary. """ - def __init__(self, bin_path): - self.comm_type = self.COMM_BIN - self.comm = bin_path - self.swrk = None - self.daemon = None - def connect(self, daemon): - # Kind of the same thing we do in libcriu - css = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) - flags = fcntl.fcntl(css[1], fcntl.F_GETFD) - fcntl.fcntl(css[1], fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC) - flags = fcntl.fcntl(css[0], fcntl.F_GETFD) - fcntl.fcntl(css[0], fcntl.F_SETFD, flags & ~fcntl.FD_CLOEXEC) + def __init__(self, bin_path): + self.comm_type = self.COMM_BIN + self.comm = bin_path + self.swrk = None + self.daemon = None - self.daemon = daemon + def connect(self, daemon): + # Kind of the same thing we do in libcriu + css = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) + flags = fcntl.fcntl(css[1], fcntl.F_GETFD) + fcntl.fcntl(css[1], fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC) + flags = fcntl.fcntl(css[0], fcntl.F_GETFD) + fcntl.fcntl(css[0], fcntl.F_SETFD, flags & ~fcntl.FD_CLOEXEC) - p = os.fork() + self.daemon = daemon - if p == 0: - def exec_criu(): - os.close(0) - os.close(1) - os.close(2) + p = os.fork() - css[0].send(struct.pack('i', os.getpid())) - os.execv(self.comm, [self.comm, 'swrk', "%d" % css[0].fileno()]) - os._exit(1) + if p == 0: - if daemon: - # Python has no daemon(3) alternative, - # so we need to mimic it ourself. - p = os.fork() + def exec_criu(): + os.close(0) + os.close(1) + os.close(2) - if p == 0: - os.setsid() + css[0].send(struct.pack('i', os.getpid())) + os.execv(self.comm, + [self.comm, 'swrk', + "%d" % css[0].fileno()]) + os._exit(1) - exec_criu() - else: - os._exit(0) - else: - exec_criu() - else: - if daemon: - os.waitpid(p, 0) + if daemon: + # Python has no daemon(3) alternative, + # so we need to mimic it ourself. + p = os.fork() - css[0].close() - self.swrk = struct.unpack('i', css[1].recv(4))[0] - self.sk = css[1] + if p == 0: + os.setsid() - return self.sk + exec_criu() + else: + os._exit(0) + else: + exec_criu() + else: + if daemon: + os.waitpid(p, 0) - def disconnect(self): - self.sk.close() - if not self.daemon: - os.waitpid(self.swrk, 0) + css[0].close() + self.swrk = struct.unpack('i', css[1].recv(4))[0] + self.sk = css[1] + + return self.sk + + def disconnect(self): + self.sk.close() + if not self.daemon: + os.waitpid(self.swrk, 0) class CRIUException(Exception): - """ + """ Exception class for handling and storing criu errors. """ - typ = None - _str = None + typ = None + _str = None - def __str__(self): - return self._str + def __str__(self): + return self._str class CRIUExceptionInternal(CRIUException): - """ + """ Exception class for handling and storing internal errors. """ - def __init__(self, typ, s): - self.typ = typ - self._str = "%s failed with internal error: %s" % (rpc.criu_req_type.Name(self.typ), s) + + def __init__(self, typ, s): + self.typ = typ + self._str = "%s failed with internal error: %s" % ( + rpc.criu_req_type.Name(self.typ), s) class CRIUExceptionExternal(CRIUException): - """ + """ Exception class for handling and storing criu RPC errors. """ - def __init__(self, req_typ, resp_typ, errno): - self.typ = req_typ - self.resp_typ = resp_typ - self.errno = errno - self._str = self._gen_error_str() + def __init__(self, req_typ, resp_typ, errno): + self.typ = req_typ + self.resp_typ = resp_typ + self.errno = errno + self._str = self._gen_error_str() - def _gen_error_str(self): - s = "%s failed: " % (rpc.criu_req_type.Name(self.typ), ) + def _gen_error_str(self): + s = "%s failed: " % (rpc.criu_req_type.Name(self.typ), ) - if self.typ != self.resp_typ: - s += "Unexpected response type %d: " % (self.resp_typ, ) + if self.typ != self.resp_typ: + s += "Unexpected response type %d: " % (self.resp_typ, ) - s += "Error(%d): " % (self.errno, ) + s += "Error(%d): " % (self.errno, ) - if self.errno == errno.EBADRQC: - s += "Bad options" + if self.errno == errno.EBADRQC: + s += "Bad options" - if self.typ == rpc.DUMP: - if self.errno == errno.ESRCH: - s += "No process with such pid" + if self.typ == rpc.DUMP: + if self.errno == errno.ESRCH: + s += "No process with such pid" - if self.typ == rpc.RESTORE: - if self.errno == errno.EEXIST: - s += "Process with requested pid already exists" + if self.typ == rpc.RESTORE: + if self.errno == errno.EEXIST: + s += "Process with requested pid already exists" - s += "Unknown" + s += "Unknown" - return s + return s class criu: - """ + """ Call criu through RPC. """ - opts = None #CRIU options in pb format + opts = None #CRIU options in pb format - _comm = None #Communication method + _comm = None #Communication method - def __init__(self): - self.use_binary('criu') - self.opts = rpc.criu_opts() - self.sk = None + def __init__(self): + self.use_binary('criu') + self.opts = rpc.criu_opts() + self.sk = None - def use_sk(self, sk_name): - """ + def use_sk(self, sk_name): + """ Access criu using unix socket which that belongs to criu service daemon. """ - self._comm = _criu_comm_sk(sk_name) + self._comm = _criu_comm_sk(sk_name) - def use_fd(self, fd): - """ + def use_fd(self, fd): + """ Access criu using provided fd. """ - self._comm = _criu_comm_fd(fd) + self._comm = _criu_comm_fd(fd) - def use_binary(self, bin_name): - """ + def use_binary(self, bin_name): + """ Access criu by execing it using provided path to criu binary. """ - self._comm = _criu_comm_bin(bin_name) + self._comm = _criu_comm_bin(bin_name) - def _send_req_and_recv_resp(self, req): - """ + def _send_req_and_recv_resp(self, req): + """ As simple as send request and receive response. """ - # In case of self-dump we need to spawn criu swrk detached - # from our current process, as criu has a hard time separating - # process resources from its own if criu is located in a same - # process tree it is trying to dump. - daemon = False - if req.type == rpc.DUMP and not req.opts.HasField('pid'): - daemon = True + # In case of self-dump we need to spawn criu swrk detached + # from our current process, as criu has a hard time separating + # process resources from its own if criu is located in a same + # process tree it is trying to dump. + daemon = False + if req.type == rpc.DUMP and not req.opts.HasField('pid'): + daemon = True - try: - if not self.sk: - s = self._comm.connect(daemon) - else: - s = self.sk + try: + if not self.sk: + s = self._comm.connect(daemon) + else: + s = self.sk - if req.keep_open: - self.sk = s + if req.keep_open: + self.sk = s - s.send(req.SerializeToString()) + s.send(req.SerializeToString()) - buf = s.recv(len(s.recv(1, socket.MSG_TRUNC | socket.MSG_PEEK))) + buf = s.recv(len(s.recv(1, socket.MSG_TRUNC | socket.MSG_PEEK))) - if not req.keep_open: - self._comm.disconnect() + if not req.keep_open: + self._comm.disconnect() - resp = rpc.criu_resp() - resp.ParseFromString(buf) - except Exception as e: - raise CRIUExceptionInternal(req.type, str(e)) + resp = rpc.criu_resp() + resp.ParseFromString(buf) + except Exception as e: + raise CRIUExceptionInternal(req.type, str(e)) - return resp + return resp - def check(self): - """ + def check(self): + """ Checks whether the kernel support is up-to-date. """ - req = rpc.criu_req() - req.type = rpc.CHECK + req = rpc.criu_req() + req.type = rpc.CHECK - resp = self._send_req_and_recv_resp(req) + resp = self._send_req_and_recv_resp(req) - if not resp.success: - raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) + if not resp.success: + raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) - def dump(self): - """ + def dump(self): + """ Checkpoint a process/tree identified by opts.pid. """ - req = rpc.criu_req() - req.type = rpc.DUMP - req.opts.MergeFrom(self.opts) + req = rpc.criu_req() + req.type = rpc.DUMP + req.opts.MergeFrom(self.opts) - resp = self._send_req_and_recv_resp(req) + resp = self._send_req_and_recv_resp(req) - if not resp.success: - raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) + if not resp.success: + raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) - return resp.dump + return resp.dump - def pre_dump(self): - """ + def pre_dump(self): + """ Checkpoint a process/tree identified by opts.pid. """ - req = rpc.criu_req() - req.type = rpc.PRE_DUMP - req.opts.MergeFrom(self.opts) + req = rpc.criu_req() + req.type = rpc.PRE_DUMP + req.opts.MergeFrom(self.opts) - resp = self._send_req_and_recv_resp(req) + resp = self._send_req_and_recv_resp(req) - if not resp.success: - raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) + if not resp.success: + raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) - return resp.dump + return resp.dump - def restore(self): - """ + def restore(self): + """ Restore a process/tree. """ - req = rpc.criu_req() - req.type = rpc.RESTORE - req.opts.MergeFrom(self.opts) + req = rpc.criu_req() + req.type = rpc.RESTORE + req.opts.MergeFrom(self.opts) - resp = self._send_req_and_recv_resp(req) + resp = self._send_req_and_recv_resp(req) - if not resp.success: - raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) + if not resp.success: + raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) - return resp.restore + return resp.restore - def page_server_chld(self): - req = rpc.criu_req() - req.type = rpc.PAGE_SERVER_CHLD - req.opts.MergeFrom(self.opts) - req.keep_open = True + def page_server_chld(self): + req = rpc.criu_req() + req.type = rpc.PAGE_SERVER_CHLD + req.opts.MergeFrom(self.opts) + req.keep_open = True - resp = self._send_req_and_recv_resp(req) + resp = self._send_req_and_recv_resp(req) - if not resp.success: - raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) + if not resp.success: + raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) - return resp.ps + return resp.ps - def wait_pid(self, pid): - req = rpc.criu_req() - req.type = rpc.WAIT_PID - req.pid = pid + def wait_pid(self, pid): + req = rpc.criu_req() + req.type = rpc.WAIT_PID + req.pid = pid - resp = self._send_req_and_recv_resp(req) + resp = self._send_req_and_recv_resp(req) - if not resp.success: - raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) + if not resp.success: + raise CRIUExceptionExternal(req.type, resp.type, resp.cr_errno) - return resp.status + return resp.status diff --git a/lib/py/images/images.py b/lib/py/images/images.py index 7a9b9da6e..28c6d9e1f 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -48,8 +48,8 @@ from . import pb from . import pb2dict if "encodebytes" not in dir(base64): - base64.encodebytes = base64.encodestring - base64.decodebytes = base64.decodestring + base64.encodebytes = base64.encodestring + base64.decodebytes = base64.decodestring # # Predefined hardcoded constants @@ -57,233 +57,241 @@ sizeof_u16 = 2 sizeof_u32 = 4 sizeof_u64 = 8 + # A helper for rounding -def round_up(x,y): - return (((x - 1) | (y - 1)) + 1) +def round_up(x, y): + return (((x - 1) | (y - 1)) + 1) + class MagicException(Exception): - def __init__(self, magic): - self.magic = magic + def __init__(self, magic): + self.magic = magic + # Generic class to handle loading/dumping criu images entries from/to bin # format to/from dict(json). class entry_handler: - """ + """ Generic class to handle loading/dumping criu images entries from/to bin format to/from dict(json). """ - def __init__(self, payload, extra_handler=None): - """ + + def __init__(self, payload, extra_handler=None): + """ Sets payload class and extra handler class. """ - self.payload = payload - self.extra_handler = extra_handler + self.payload = payload + self.extra_handler = extra_handler - def load(self, f, pretty = False, no_payload = False): - """ + def load(self, f, pretty=False, no_payload=False): + """ Convert criu image entries from binary format to dict(json). Takes a file-like object and returnes a list with entries in dict(json) format. """ - entries = [] + entries = [] - while True: - entry = {} + while True: + entry = {} - # Read payload - pbuff = self.payload() - buf = f.read(4) - if buf == b'': - break - size, = struct.unpack('i', buf) - pbuff.ParseFromString(f.read(size)) - entry = pb2dict.pb2dict(pbuff, pretty) + # Read payload + pbuff = self.payload() + buf = f.read(4) + if buf == b'': + break + size, = struct.unpack('i', buf) + pbuff.ParseFromString(f.read(size)) + entry = pb2dict.pb2dict(pbuff, pretty) - # Read extra - if self.extra_handler: - if no_payload: - def human_readable(num): - for unit in ['','K','M','G','T','P','E','Z']: - if num < 1024.0: - if int(num) == num: - return "%d%sB" % (num, unit) - else: - return "%.1f%sB" % (num, unit) - num /= 1024.0 - return "%.1fYB" % num + # Read extra + if self.extra_handler: + if no_payload: - pl_size = self.extra_handler.skip(f, pbuff) - entry['extra'] = '... <%s>' % human_readable(pl_size) - else: - entry['extra'] = self.extra_handler.load(f, pbuff) + def human_readable(num): + for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']: + if num < 1024.0: + if int(num) == num: + return "%d%sB" % (num, unit) + else: + return "%.1f%sB" % (num, unit) + num /= 1024.0 + return "%.1fYB" % num - entries.append(entry) + pl_size = self.extra_handler.skip(f, pbuff) + entry['extra'] = '... <%s>' % human_readable(pl_size) + else: + entry['extra'] = self.extra_handler.load(f, pbuff) - return entries + entries.append(entry) - def loads(self, s, pretty = False): - """ + return entries + + def loads(self, s, pretty=False): + """ Same as load(), but takes a string as an argument. """ - f = io.BytesIO(s) - return self.load(f, pretty) + f = io.BytesIO(s) + return self.load(f, pretty) - def dump(self, entries, f): - """ + def dump(self, entries, f): + """ Convert criu image entries from dict(json) format to binary. Takes a list of entries and a file-like object to write entries in binary format to. """ - for entry in entries: - extra = entry.pop('extra', None) + for entry in entries: + extra = entry.pop('extra', None) - # Write payload - pbuff = self.payload() - pb2dict.dict2pb(entry, pbuff) - pb_str = pbuff.SerializeToString() - size = len(pb_str) - f.write(struct.pack('i', size)) - f.write(pb_str) + # Write payload + pbuff = self.payload() + pb2dict.dict2pb(entry, pbuff) + pb_str = pbuff.SerializeToString() + size = len(pb_str) + f.write(struct.pack('i', size)) + f.write(pb_str) - # Write extra - if self.extra_handler and extra: - self.extra_handler.dump(extra, f, pbuff) + # Write extra + if self.extra_handler and extra: + self.extra_handler.dump(extra, f, pbuff) - def dumps(self, entries): - """ + def dumps(self, entries): + """ Same as dump(), but doesn't take file-like object and just returns a string. """ - f = io.BytesIO('') - self.dump(entries, f) - return f.read() + f = io.BytesIO('') + self.dump(entries, f) + return f.read() - def count(self, f): - """ + def count(self, f): + """ Counts the number of top-level object in the image file """ - entries = 0 + entries = 0 - while True: - buf = f.read(4) - if buf == '': - break - size, = struct.unpack('i', buf) - f.seek(size, 1) - entries += 1 + while True: + buf = f.read(4) + if buf == '': + break + size, = struct.unpack('i', buf) + f.seek(size, 1) + entries += 1 + + return entries - return entries # Special handler for pagemap.img class pagemap_handler: - """ + """ Special entry handler for pagemap.img, which is unique in a way that it has a header of pagemap_head type followed by entries of pagemap_entry type. """ - def load(self, f, pretty = False, no_payload = False): - entries = [] - pbuff = pb.pagemap_head() - while True: - buf = f.read(4) - if buf == b'': - break - size, = struct.unpack('i', buf) - pbuff.ParseFromString(f.read(size)) - entries.append(pb2dict.pb2dict(pbuff, pretty)) + def load(self, f, pretty=False, no_payload=False): + entries = [] - pbuff = pb.pagemap_entry() + pbuff = pb.pagemap_head() + while True: + buf = f.read(4) + if buf == b'': + break + size, = struct.unpack('i', buf) + pbuff.ParseFromString(f.read(size)) + entries.append(pb2dict.pb2dict(pbuff, pretty)) - return entries + pbuff = pb.pagemap_entry() - def loads(self, s, pretty = False): - f = io.BytesIO(s) - return self.load(f, pretty) + return entries - def dump(self, entries, f): - pbuff = pb.pagemap_head() - for item in entries: - pb2dict.dict2pb(item, pbuff) - pb_str = pbuff.SerializeToString() - size = len(pb_str) - f.write(struct.pack('i', size)) - f.write(pb_str) + def loads(self, s, pretty=False): + f = io.BytesIO(s) + return self.load(f, pretty) - pbuff = pb.pagemap_entry() + def dump(self, entries, f): + pbuff = pb.pagemap_head() + for item in entries: + pb2dict.dict2pb(item, pbuff) + pb_str = pbuff.SerializeToString() + size = len(pb_str) + f.write(struct.pack('i', size)) + f.write(pb_str) - def dumps(self, entries): - f = io.BytesIO('') - self.dump(entries, f) - return f.read() + pbuff = pb.pagemap_entry() + + def dumps(self, entries): + f = io.BytesIO('') + self.dump(entries, f) + return f.read() + + def count(self, f): + return entry_handler(None).count(f) - 1 - def count(self, f): - return entry_handler(None).count(f) - 1 # Special handler for ghost-file.img class ghost_file_handler: - def load(self, f, pretty = False, no_payload = False): - entries = [] + def load(self, f, pretty=False, no_payload=False): + entries = [] - gf = pb.ghost_file_entry() - buf = f.read(4) - size, = struct.unpack('i', buf) - gf.ParseFromString(f.read(size)) - g_entry = pb2dict.pb2dict(gf, pretty) + gf = pb.ghost_file_entry() + buf = f.read(4) + size, = struct.unpack('i', buf) + gf.ParseFromString(f.read(size)) + g_entry = pb2dict.pb2dict(gf, pretty) - if gf.chunks: - entries.append(g_entry) - while True: - gc = pb.ghost_chunk_entry() - buf = f.read(4) - if buf == '': - break - size, = struct.unpack('i', buf) - gc.ParseFromString(f.read(size)) - entry = pb2dict.pb2dict(gc, pretty) - if no_payload: - f.seek(gc.len, os.SEEK_CUR) - else: - entry['extra'] = base64.encodebytes(f.read(gc.len)) - entries.append(entry) - else: - if no_payload: - f.seek(0, os.SEEK_END) - else: - g_entry['extra'] = base64.encodebytes(f.read()) - entries.append(g_entry) + if gf.chunks: + entries.append(g_entry) + while True: + gc = pb.ghost_chunk_entry() + buf = f.read(4) + if buf == '': + break + size, = struct.unpack('i', buf) + gc.ParseFromString(f.read(size)) + entry = pb2dict.pb2dict(gc, pretty) + if no_payload: + f.seek(gc.len, os.SEEK_CUR) + else: + entry['extra'] = base64.encodebytes(f.read(gc.len)) + entries.append(entry) + else: + if no_payload: + f.seek(0, os.SEEK_END) + else: + g_entry['extra'] = base64.encodebytes(f.read()) + entries.append(g_entry) - return entries + return entries - def loads(self, s, pretty = False): - f = io.BytesIO(s) - return self.load(f, pretty) + def loads(self, s, pretty=False): + f = io.BytesIO(s) + return self.load(f, pretty) - def dump(self, entries, f): - pbuff = pb.ghost_file_entry() - item = entries.pop(0) - pb2dict.dict2pb(item, pbuff) - pb_str = pbuff.SerializeToString() - size = len(pb_str) - f.write(struct.pack('i', size)) - f.write(pb_str) + def dump(self, entries, f): + pbuff = pb.ghost_file_entry() + item = entries.pop(0) + pb2dict.dict2pb(item, pbuff) + pb_str = pbuff.SerializeToString() + size = len(pb_str) + f.write(struct.pack('i', size)) + f.write(pb_str) - if pbuff.chunks: - for item in entries: - pbuff = pb.ghost_chunk_entry() - pb2dict.dict2pb(item, pbuff) - pb_str = pbuff.SerializeToString() - size = len(pb_str) - f.write(struct.pack('i', size)) - f.write(pb_str) - f.write(base64.decodebytes(item['extra'])) - else: - f.write(base64.decodebytes(item['extra'])) + if pbuff.chunks: + for item in entries: + pbuff = pb.ghost_chunk_entry() + pb2dict.dict2pb(item, pbuff) + pb_str = pbuff.SerializeToString() + size = len(pb_str) + f.write(struct.pack('i', size)) + f.write(pb_str) + f.write(base64.decodebytes(item['extra'])) + else: + f.write(base64.decodebytes(item['extra'])) - def dumps(self, entries): - f = io.BytesIO('') - self.dump(entries, f) - return f.read() + def dumps(self, entries): + f = io.BytesIO('') + self.dump(entries, f) + return f.read() # In following extra handlers we use base64 encoding @@ -293,304 +301,317 @@ class ghost_file_handler: # do not store big amounts of binary data. They # are negligible comparing to pages size. class pipes_data_extra_handler: - def load(self, f, pload): - size = pload.bytes - data = f.read(size) - return base64.encodebytes(data) + def load(self, f, pload): + size = pload.bytes + data = f.read(size) + return base64.encodebytes(data) - def dump(self, extra, f, pload): - data = base64.decodebytes(extra) - f.write(data) + def dump(self, extra, f, pload): + data = base64.decodebytes(extra) + f.write(data) + + def skip(self, f, pload): + f.seek(pload.bytes, os.SEEK_CUR) + return pload.bytes - def skip(self, f, pload): - f.seek(pload.bytes, os.SEEK_CUR) - return pload.bytes class sk_queues_extra_handler: - def load(self, f, pload): - size = pload.length - data = f.read(size) - return base64.encodebytes(data) + def load(self, f, pload): + size = pload.length + data = f.read(size) + return base64.encodebytes(data) - def dump(self, extra, f, _unused): - data = base64.decodebytes(extra) - f.write(data) + def dump(self, extra, f, _unused): + data = base64.decodebytes(extra) + f.write(data) - def skip(self, f, pload): - f.seek(pload.length, os.SEEK_CUR) - return pload.length + def skip(self, f, pload): + f.seek(pload.length, os.SEEK_CUR) + return pload.length class tcp_stream_extra_handler: - def load(self, f, pbuff): - d = {} + def load(self, f, pbuff): + d = {} - inq = f.read(pbuff.inq_len) - outq = f.read(pbuff.outq_len) + inq = f.read(pbuff.inq_len) + outq = f.read(pbuff.outq_len) - d['inq'] = base64.encodebytes(inq) - d['outq'] = base64.encodebytes(outq) + d['inq'] = base64.encodebytes(inq) + d['outq'] = base64.encodebytes(outq) - return d + return d - def dump(self, extra, f, _unused): - inq = base64.decodebytes(extra['inq']) - outq = base64.decodebytes(extra['outq']) + def dump(self, extra, f, _unused): + inq = base64.decodebytes(extra['inq']) + outq = base64.decodebytes(extra['outq']) - f.write(inq) - f.write(outq) + f.write(inq) + f.write(outq) + + def skip(self, f, pbuff): + f.seek(0, os.SEEK_END) + return pbuff.inq_len + pbuff.outq_len - def skip(self, f, pbuff): - f.seek(0, os.SEEK_END) - return pbuff.inq_len + pbuff.outq_len class ipc_sem_set_handler: - def load(self, f, pbuff): - entry = pb2dict.pb2dict(pbuff) - size = sizeof_u16 * entry['nsems'] - rounded = round_up(size, sizeof_u64) - s = array.array('H') - if s.itemsize != sizeof_u16: - raise Exception("Array size mismatch") - s.fromstring(f.read(size)) - f.seek(rounded - size, 1) - return s.tolist() + def load(self, f, pbuff): + entry = pb2dict.pb2dict(pbuff) + size = sizeof_u16 * entry['nsems'] + rounded = round_up(size, sizeof_u64) + s = array.array('H') + if s.itemsize != sizeof_u16: + raise Exception("Array size mismatch") + s.fromstring(f.read(size)) + f.seek(rounded - size, 1) + return s.tolist() - def dump(self, extra, f, pbuff): - entry = pb2dict.pb2dict(pbuff) - size = sizeof_u16 * entry['nsems'] - rounded = round_up(size, sizeof_u64) - s = array.array('H') - if s.itemsize != sizeof_u16: - raise Exception("Array size mismatch") - s.fromlist(extra) - if len(s) != entry['nsems']: - raise Exception("Number of semaphores mismatch") - f.write(s.tostring()) - f.write('\0' * (rounded - size)) + def dump(self, extra, f, pbuff): + entry = pb2dict.pb2dict(pbuff) + size = sizeof_u16 * entry['nsems'] + rounded = round_up(size, sizeof_u64) + s = array.array('H') + if s.itemsize != sizeof_u16: + raise Exception("Array size mismatch") + s.fromlist(extra) + if len(s) != entry['nsems']: + raise Exception("Number of semaphores mismatch") + f.write(s.tostring()) + f.write('\0' * (rounded - size)) + + def skip(self, f, pbuff): + entry = pb2dict.pb2dict(pbuff) + size = sizeof_u16 * entry['nsems'] + f.seek(round_up(size, sizeof_u64), os.SEEK_CUR) + return size - def skip(self, f, pbuff): - entry = pb2dict.pb2dict(pbuff) - size = sizeof_u16 * entry['nsems'] - f.seek(round_up(size, sizeof_u64), os.SEEK_CUR) - return size class ipc_msg_queue_handler: - def load(self, f, pbuff): - entry = pb2dict.pb2dict(pbuff) - messages = [] - for x in range (0, entry['qnum']): - buf = f.read(4) - if buf == '': - break - size, = struct.unpack('i', buf) - msg = pb.ipc_msg() - msg.ParseFromString(f.read(size)) - rounded = round_up(msg.msize, sizeof_u64) - data = f.read(msg.msize) - f.seek(rounded - msg.msize, 1) - messages.append(pb2dict.pb2dict(msg)) - messages.append(base64.encodebytes(data)) - return messages + def load(self, f, pbuff): + entry = pb2dict.pb2dict(pbuff) + messages = [] + for x in range(0, entry['qnum']): + buf = f.read(4) + if buf == '': + break + size, = struct.unpack('i', buf) + msg = pb.ipc_msg() + msg.ParseFromString(f.read(size)) + rounded = round_up(msg.msize, sizeof_u64) + data = f.read(msg.msize) + f.seek(rounded - msg.msize, 1) + messages.append(pb2dict.pb2dict(msg)) + messages.append(base64.encodebytes(data)) + return messages - def dump(self, extra, f, pbuff): - entry = pb2dict.pb2dict(pbuff) - for i in range (0, len(extra), 2): - msg = pb.ipc_msg() - pb2dict.dict2pb(extra[i], msg) - msg_str = msg.SerializeToString() - size = len(msg_str) - f.write(struct.pack('i', size)) - f.write(msg_str) - rounded = round_up(msg.msize, sizeof_u64) - data = base64.decodebytes(extra[i + 1]) - f.write(data[:msg.msize]) - f.write('\0' * (rounded - msg.msize)) + def dump(self, extra, f, pbuff): + entry = pb2dict.pb2dict(pbuff) + for i in range(0, len(extra), 2): + msg = pb.ipc_msg() + pb2dict.dict2pb(extra[i], msg) + msg_str = msg.SerializeToString() + size = len(msg_str) + f.write(struct.pack('i', size)) + f.write(msg_str) + rounded = round_up(msg.msize, sizeof_u64) + data = base64.decodebytes(extra[i + 1]) + f.write(data[:msg.msize]) + f.write('\0' * (rounded - msg.msize)) - def skip(self, f, pbuff): - entry = pb2dict.pb2dict(pbuff) - pl_len = 0 - for x in range (0, entry['qnum']): - buf = f.read(4) - if buf == '': - break - size, = struct.unpack('i', buf) - msg = pb.ipc_msg() - msg.ParseFromString(f.read(size)) - rounded = round_up(msg.msize, sizeof_u64) - f.seek(rounded, os.SEEK_CUR) - pl_len += size + msg.msize + def skip(self, f, pbuff): + entry = pb2dict.pb2dict(pbuff) + pl_len = 0 + for x in range(0, entry['qnum']): + buf = f.read(4) + if buf == '': + break + size, = struct.unpack('i', buf) + msg = pb.ipc_msg() + msg.ParseFromString(f.read(size)) + rounded = round_up(msg.msize, sizeof_u64) + f.seek(rounded, os.SEEK_CUR) + pl_len += size + msg.msize + + return pl_len - return pl_len class ipc_shm_handler: - def load(self, f, pbuff): - entry = pb2dict.pb2dict(pbuff) - size = entry['size'] - data = f.read(size) - rounded = round_up(size, sizeof_u32) - f.seek(rounded - size, 1) - return base64.encodebytes(data) + def load(self, f, pbuff): + entry = pb2dict.pb2dict(pbuff) + size = entry['size'] + data = f.read(size) + rounded = round_up(size, sizeof_u32) + f.seek(rounded - size, 1) + return base64.encodebytes(data) - def dump(self, extra, f, pbuff): - entry = pb2dict.pb2dict(pbuff) - size = entry['size'] - data = base64.decodebytes(extra) - rounded = round_up(size, sizeof_u32) - f.write(data[:size]) - f.write('\0' * (rounded - size)) + def dump(self, extra, f, pbuff): + entry = pb2dict.pb2dict(pbuff) + size = entry['size'] + data = base64.decodebytes(extra) + rounded = round_up(size, sizeof_u32) + f.write(data[:size]) + f.write('\0' * (rounded - size)) - def skip(self, f, pbuff): - entry = pb2dict.pb2dict(pbuff) - size = entry['size'] - rounded = round_up(size, sizeof_u32) - f.seek(rounded, os.SEEK_CUR) - return size + def skip(self, f, pbuff): + entry = pb2dict.pb2dict(pbuff) + size = entry['size'] + rounded = round_up(size, sizeof_u32) + f.seek(rounded, os.SEEK_CUR) + return size handlers = { - 'INVENTORY' : entry_handler(pb.inventory_entry), - 'CORE' : entry_handler(pb.core_entry), - 'IDS' : entry_handler(pb.task_kobj_ids_entry), - 'CREDS' : entry_handler(pb.creds_entry), - 'UTSNS' : entry_handler(pb.utsns_entry), - 'IPC_VAR' : entry_handler(pb.ipc_var_entry), - 'FS' : entry_handler(pb.fs_entry), - 'GHOST_FILE' : ghost_file_handler(), - 'MM' : entry_handler(pb.mm_entry), - 'CGROUP' : entry_handler(pb.cgroup_entry), - 'TCP_STREAM' : entry_handler(pb.tcp_stream_entry, tcp_stream_extra_handler()), - 'STATS' : entry_handler(pb.stats_entry), - 'PAGEMAP' : pagemap_handler(), # Special one - 'PSTREE' : entry_handler(pb.pstree_entry), - 'REG_FILES' : entry_handler(pb.reg_file_entry), - 'NS_FILES' : entry_handler(pb.ns_file_entry), - 'EVENTFD_FILE' : entry_handler(pb.eventfd_file_entry), - 'EVENTPOLL_FILE' : entry_handler(pb.eventpoll_file_entry), - 'EVENTPOLL_TFD' : entry_handler(pb.eventpoll_tfd_entry), - 'SIGNALFD' : entry_handler(pb.signalfd_entry), - 'TIMERFD' : entry_handler(pb.timerfd_entry), - 'INOTIFY_FILE' : entry_handler(pb.inotify_file_entry), - 'INOTIFY_WD' : entry_handler(pb.inotify_wd_entry), - 'FANOTIFY_FILE' : entry_handler(pb.fanotify_file_entry), - 'FANOTIFY_MARK' : entry_handler(pb.fanotify_mark_entry), - 'VMAS' : entry_handler(pb.vma_entry), - 'PIPES' : entry_handler(pb.pipe_entry), - 'FIFO' : entry_handler(pb.fifo_entry), - 'SIGACT' : entry_handler(pb.sa_entry), - 'NETLINK_SK' : entry_handler(pb.netlink_sk_entry), - 'REMAP_FPATH' : entry_handler(pb.remap_file_path_entry), - 'MNTS' : entry_handler(pb.mnt_entry), - 'TTY_FILES' : entry_handler(pb.tty_file_entry), - 'TTY_INFO' : entry_handler(pb.tty_info_entry), - 'TTY_DATA' : entry_handler(pb.tty_data_entry), - 'RLIMIT' : entry_handler(pb.rlimit_entry), - 'TUNFILE' : entry_handler(pb.tunfile_entry), - 'EXT_FILES' : entry_handler(pb.ext_file_entry), - 'IRMAP_CACHE' : entry_handler(pb.irmap_cache_entry), - 'FILE_LOCKS' : entry_handler(pb.file_lock_entry), - 'FDINFO' : entry_handler(pb.fdinfo_entry), - 'UNIXSK' : entry_handler(pb.unix_sk_entry), - 'INETSK' : entry_handler(pb.inet_sk_entry), - 'PACKETSK' : entry_handler(pb.packet_sock_entry), - 'ITIMERS' : entry_handler(pb.itimer_entry), - 'POSIX_TIMERS' : entry_handler(pb.posix_timer_entry), - 'NETDEV' : entry_handler(pb.net_device_entry), - 'PIPES_DATA' : entry_handler(pb.pipe_data_entry, pipes_data_extra_handler()), - 'FIFO_DATA' : entry_handler(pb.pipe_data_entry, pipes_data_extra_handler()), - 'SK_QUEUES' : entry_handler(pb.sk_packet_entry, sk_queues_extra_handler()), - 'IPCNS_SHM' : entry_handler(pb.ipc_shm_entry, ipc_shm_handler()), - 'IPCNS_SEM' : entry_handler(pb.ipc_sem_entry, ipc_sem_set_handler()), - 'IPCNS_MSG' : entry_handler(pb.ipc_msg_entry, ipc_msg_queue_handler()), - 'NETNS' : entry_handler(pb.netns_entry), - 'USERNS' : entry_handler(pb.userns_entry), - 'SECCOMP' : entry_handler(pb.seccomp_entry), - 'AUTOFS' : entry_handler(pb.autofs_entry), - 'FILES' : entry_handler(pb.file_entry), - 'CPUINFO' : entry_handler(pb.cpuinfo_entry), - } + 'INVENTORY': entry_handler(pb.inventory_entry), + 'CORE': entry_handler(pb.core_entry), + 'IDS': entry_handler(pb.task_kobj_ids_entry), + 'CREDS': entry_handler(pb.creds_entry), + 'UTSNS': entry_handler(pb.utsns_entry), + 'IPC_VAR': entry_handler(pb.ipc_var_entry), + 'FS': entry_handler(pb.fs_entry), + 'GHOST_FILE': ghost_file_handler(), + 'MM': entry_handler(pb.mm_entry), + 'CGROUP': entry_handler(pb.cgroup_entry), + 'TCP_STREAM': entry_handler(pb.tcp_stream_entry, + tcp_stream_extra_handler()), + 'STATS': entry_handler(pb.stats_entry), + 'PAGEMAP': pagemap_handler(), # Special one + 'PSTREE': entry_handler(pb.pstree_entry), + 'REG_FILES': entry_handler(pb.reg_file_entry), + 'NS_FILES': entry_handler(pb.ns_file_entry), + 'EVENTFD_FILE': entry_handler(pb.eventfd_file_entry), + 'EVENTPOLL_FILE': entry_handler(pb.eventpoll_file_entry), + 'EVENTPOLL_TFD': entry_handler(pb.eventpoll_tfd_entry), + 'SIGNALFD': entry_handler(pb.signalfd_entry), + 'TIMERFD': entry_handler(pb.timerfd_entry), + 'INOTIFY_FILE': entry_handler(pb.inotify_file_entry), + 'INOTIFY_WD': entry_handler(pb.inotify_wd_entry), + 'FANOTIFY_FILE': entry_handler(pb.fanotify_file_entry), + 'FANOTIFY_MARK': entry_handler(pb.fanotify_mark_entry), + 'VMAS': entry_handler(pb.vma_entry), + 'PIPES': entry_handler(pb.pipe_entry), + 'FIFO': entry_handler(pb.fifo_entry), + 'SIGACT': entry_handler(pb.sa_entry), + 'NETLINK_SK': entry_handler(pb.netlink_sk_entry), + 'REMAP_FPATH': entry_handler(pb.remap_file_path_entry), + 'MNTS': entry_handler(pb.mnt_entry), + 'TTY_FILES': entry_handler(pb.tty_file_entry), + 'TTY_INFO': entry_handler(pb.tty_info_entry), + 'TTY_DATA': entry_handler(pb.tty_data_entry), + 'RLIMIT': entry_handler(pb.rlimit_entry), + 'TUNFILE': entry_handler(pb.tunfile_entry), + 'EXT_FILES': entry_handler(pb.ext_file_entry), + 'IRMAP_CACHE': entry_handler(pb.irmap_cache_entry), + 'FILE_LOCKS': entry_handler(pb.file_lock_entry), + 'FDINFO': entry_handler(pb.fdinfo_entry), + 'UNIXSK': entry_handler(pb.unix_sk_entry), + 'INETSK': entry_handler(pb.inet_sk_entry), + 'PACKETSK': entry_handler(pb.packet_sock_entry), + 'ITIMERS': entry_handler(pb.itimer_entry), + 'POSIX_TIMERS': entry_handler(pb.posix_timer_entry), + 'NETDEV': entry_handler(pb.net_device_entry), + 'PIPES_DATA': entry_handler(pb.pipe_data_entry, + pipes_data_extra_handler()), + 'FIFO_DATA': entry_handler(pb.pipe_data_entry, pipes_data_extra_handler()), + 'SK_QUEUES': entry_handler(pb.sk_packet_entry, sk_queues_extra_handler()), + 'IPCNS_SHM': entry_handler(pb.ipc_shm_entry, ipc_shm_handler()), + 'IPCNS_SEM': entry_handler(pb.ipc_sem_entry, ipc_sem_set_handler()), + 'IPCNS_MSG': entry_handler(pb.ipc_msg_entry, ipc_msg_queue_handler()), + 'NETNS': entry_handler(pb.netns_entry), + 'USERNS': entry_handler(pb.userns_entry), + 'SECCOMP': entry_handler(pb.seccomp_entry), + 'AUTOFS': entry_handler(pb.autofs_entry), + 'FILES': entry_handler(pb.file_entry), + 'CPUINFO': entry_handler(pb.cpuinfo_entry), +} + def __rhandler(f): - # Images v1.1 NOTE: First read "first" magic. - img_magic, = struct.unpack('i', f.read(4)) - if img_magic in (magic.by_name['IMG_COMMON'], magic.by_name['IMG_SERVICE']): - img_magic, = struct.unpack('i', f.read(4)) + # Images v1.1 NOTE: First read "first" magic. + img_magic, = struct.unpack('i', f.read(4)) + if img_magic in (magic.by_name['IMG_COMMON'], + magic.by_name['IMG_SERVICE']): + img_magic, = struct.unpack('i', f.read(4)) - try: - m = magic.by_val[img_magic] - except: - raise MagicException(img_magic) + try: + m = magic.by_val[img_magic] + except: + raise MagicException(img_magic) - try: - handler = handlers[m] - except: - raise Exception("No handler found for image with magic " + m) + try: + handler = handlers[m] + except: + raise Exception("No handler found for image with magic " + m) - return m, handler + return m, handler -def load(f, pretty = False, no_payload = False): - """ + +def load(f, pretty=False, no_payload=False): + """ Convert criu image from binary format to dict(json). Takes a file-like object to read criu image from. Returns criu image in dict(json) format. """ - image = {} + image = {} - m, handler = __rhandler(f) + m, handler = __rhandler(f) - image['magic'] = m - image['entries'] = handler.load(f, pretty, no_payload) + image['magic'] = m + image['entries'] = handler.load(f, pretty, no_payload) + + return image - return image def info(f): - res = {} + res = {} - m, handler = __rhandler(f) + m, handler = __rhandler(f) - res['magic'] = m - res['count'] = handler.count(f) + res['magic'] = m + res['count'] = handler.count(f) - return res + return res -def loads(s, pretty = False): - """ + +def loads(s, pretty=False): + """ Same as load(), but takes a string. """ - f = io.BytesIO(s) - return load(f, pretty) + f = io.BytesIO(s) + return load(f, pretty) + def dump(img, f): - """ + """ Convert criu image from dict(json) format to binary. Takes an image in dict(json) format and file-like object to write to. """ - m = img['magic'] - magic_val = magic.by_name[img['magic']] + m = img['magic'] + magic_val = magic.by_name[img['magic']] - # Images v1.1 NOTE: use "second" magic to identify what "first" - # should be written. - if m != 'INVENTORY': - if m in ('STATS', 'IRMAP_CACHE'): - f.write(struct.pack('i', magic.by_name['IMG_SERVICE'])) - else: - f.write(struct.pack('i', magic.by_name['IMG_COMMON'])) + # Images v1.1 NOTE: use "second" magic to identify what "first" + # should be written. + if m != 'INVENTORY': + if m in ('STATS', 'IRMAP_CACHE'): + f.write(struct.pack('i', magic.by_name['IMG_SERVICE'])) + else: + f.write(struct.pack('i', magic.by_name['IMG_COMMON'])) - f.write(struct.pack('i', magic_val)) + f.write(struct.pack('i', magic_val)) - try: - handler = handlers[m] - except: - raise Exception("No handler found for image with such magic") + try: + handler = handlers[m] + except: + raise Exception("No handler found for image with such magic") + + handler.dump(img['entries'], f) - handler.dump(img['entries'], f) def dumps(img): - """ + """ Same as dump(), but takes only an image and returns a string. """ - f = io.BytesIO(b'') - dump(img, f) - return f.getvalue() + f = io.BytesIO(b'') + dump(img, f) + return f.getvalue() diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index 6b4a772c7..daaa7297e 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -9,8 +9,8 @@ import base64 import quopri if "encodebytes" not in dir(base64): - base64.encodebytes = base64.encodestring - base64.decodebytes = base64.decodestring + base64.encodebytes = base64.encodestring + base64.decodebytes = base64.decodestring # pb2dict and dict2pb are methods to convert pb to/from dict. # Inspired by: @@ -29,350 +29,396 @@ if "encodebytes" not in dir(base64): # enums to string value too. (i.e. "march : x86_64" is better then # "march : 1"). - _basic_cast = { - FD.TYPE_FIXED64 : int, - FD.TYPE_FIXED32 : int, - FD.TYPE_SFIXED64 : int, - FD.TYPE_SFIXED32 : int, - - FD.TYPE_INT64 : int, - FD.TYPE_UINT64 : int, - FD.TYPE_SINT64 : int, - - FD.TYPE_INT32 : int, - FD.TYPE_UINT32 : int, - FD.TYPE_SINT32 : int, - - FD.TYPE_BOOL : bool, - - FD.TYPE_STRING : str + FD.TYPE_FIXED64: int, + FD.TYPE_FIXED32: int, + FD.TYPE_SFIXED64: int, + FD.TYPE_SFIXED32: int, + FD.TYPE_INT64: int, + FD.TYPE_UINT64: int, + FD.TYPE_SINT64: int, + FD.TYPE_INT32: int, + FD.TYPE_UINT32: int, + FD.TYPE_SINT32: int, + FD.TYPE_BOOL: bool, + FD.TYPE_STRING: str } + def _marked_as_hex(field): - return field.GetOptions().Extensions[opts_pb2.criu].hex + return field.GetOptions().Extensions[opts_pb2.criu].hex + def _marked_as_ip(field): - return field.GetOptions().Extensions[opts_pb2.criu].ipadd + return field.GetOptions().Extensions[opts_pb2.criu].ipadd + def _marked_as_flags(field): - return field.GetOptions().Extensions[opts_pb2.criu].flags + return field.GetOptions().Extensions[opts_pb2.criu].flags + def _marked_as_dev(field): - return field.GetOptions().Extensions[opts_pb2.criu].dev + return field.GetOptions().Extensions[opts_pb2.criu].dev + def _marked_as_odev(field): - return field.GetOptions().Extensions[opts_pb2.criu].odev + return field.GetOptions().Extensions[opts_pb2.criu].odev + def _marked_as_dict(field): - return field.GetOptions().Extensions[opts_pb2.criu].dict + return field.GetOptions().Extensions[opts_pb2.criu].dict + def _custom_conv(field): - return field.GetOptions().Extensions[opts_pb2.criu].conv + return field.GetOptions().Extensions[opts_pb2.criu].conv + mmap_prot_map = [ - ('PROT_READ', 0x1), - ('PROT_WRITE', 0x2), - ('PROT_EXEC', 0x4), + ('PROT_READ', 0x1), + ('PROT_WRITE', 0x2), + ('PROT_EXEC', 0x4), ] mmap_flags_map = [ - ('MAP_SHARED', 0x1), - ('MAP_PRIVATE', 0x2), - ('MAP_ANON', 0x20), - ('MAP_GROWSDOWN', 0x0100), + ('MAP_SHARED', 0x1), + ('MAP_PRIVATE', 0x2), + ('MAP_ANON', 0x20), + ('MAP_GROWSDOWN', 0x0100), ] mmap_status_map = [ - ('VMA_AREA_NONE', 0 << 0), - ('VMA_AREA_REGULAR', 1 << 0), - ('VMA_AREA_STACK', 1 << 1), - ('VMA_AREA_VSYSCALL', 1 << 2), - ('VMA_AREA_VDSO', 1 << 3), - ('VMA_AREA_HEAP', 1 << 5), - - ('VMA_FILE_PRIVATE', 1 << 6), - ('VMA_FILE_SHARED', 1 << 7), - ('VMA_ANON_SHARED', 1 << 8), - ('VMA_ANON_PRIVATE', 1 << 9), - - ('VMA_AREA_SYSVIPC', 1 << 10), - ('VMA_AREA_SOCKET', 1 << 11), - ('VMA_AREA_VVAR', 1 << 12), - ('VMA_AREA_AIORING', 1 << 13), - - ('VMA_UNSUPP', 1 << 31), + ('VMA_AREA_NONE', 0 << 0), + ('VMA_AREA_REGULAR', 1 << 0), + ('VMA_AREA_STACK', 1 << 1), + ('VMA_AREA_VSYSCALL', 1 << 2), + ('VMA_AREA_VDSO', 1 << 3), + ('VMA_AREA_HEAP', 1 << 5), + ('VMA_FILE_PRIVATE', 1 << 6), + ('VMA_FILE_SHARED', 1 << 7), + ('VMA_ANON_SHARED', 1 << 8), + ('VMA_ANON_PRIVATE', 1 << 9), + ('VMA_AREA_SYSVIPC', 1 << 10), + ('VMA_AREA_SOCKET', 1 << 11), + ('VMA_AREA_VVAR', 1 << 12), + ('VMA_AREA_AIORING', 1 << 13), + ('VMA_UNSUPP', 1 << 31), ] rfile_flags_map = [ - ('O_WRONLY', 0o1), - ('O_RDWR', 0o2), - ('O_APPEND', 0o2000), - ('O_DIRECT', 0o40000), - ('O_LARGEFILE', 0o100000), + ('O_WRONLY', 0o1), + ('O_RDWR', 0o2), + ('O_APPEND', 0o2000), + ('O_DIRECT', 0o40000), + ('O_LARGEFILE', 0o100000), ] pmap_flags_map = [ - ('PE_PARENT', 1 << 0), - ('PE_LAZY', 1 << 1), - ('PE_PRESENT', 1 << 2), + ('PE_PARENT', 1 << 0), + ('PE_LAZY', 1 << 1), + ('PE_PRESENT', 1 << 2), ] flags_maps = { - 'mmap.prot' : mmap_prot_map, - 'mmap.flags' : mmap_flags_map, - 'mmap.status' : mmap_status_map, - 'rfile.flags' : rfile_flags_map, - 'pmap.flags' : pmap_flags_map, + 'mmap.prot': mmap_prot_map, + 'mmap.flags': mmap_flags_map, + 'mmap.status': mmap_status_map, + 'rfile.flags': rfile_flags_map, + 'pmap.flags': pmap_flags_map, } gen_maps = { - 'task_state' : { 1: 'Alive', 3: 'Zombie', 6: 'Stopped' }, + 'task_state': { + 1: 'Alive', + 3: 'Zombie', + 6: 'Stopped' + }, } sk_maps = { - 'family' : { 1: 'UNIX', - 2: 'INET', - 10: 'INET6', - 16: 'NETLINK', - 17: 'PACKET' }, - 'type' : { 1: 'STREAM', - 2: 'DGRAM', - 3: 'RAW', - 5: 'SEQPACKET', - 10: 'PACKET' }, - 'state' : { 1: 'ESTABLISHED', - 2: 'SYN_SENT', - 3: 'SYN_RECV', - 4: 'FIN_WAIT1', - 5: 'FIN_WAIT2', - 6: 'TIME_WAIT', - 7: 'CLOSE', - 8: 'CLOSE_WAIT', - 9: 'LAST_ACK', - 10: 'LISTEN' }, - 'proto' : { 0: 'IP', - 6: 'TCP', - 17: 'UDP', - 136: 'UDPLITE' }, + 'family': { + 1: 'UNIX', + 2: 'INET', + 10: 'INET6', + 16: 'NETLINK', + 17: 'PACKET' + }, + 'type': { + 1: 'STREAM', + 2: 'DGRAM', + 3: 'RAW', + 5: 'SEQPACKET', + 10: 'PACKET' + }, + 'state': { + 1: 'ESTABLISHED', + 2: 'SYN_SENT', + 3: 'SYN_RECV', + 4: 'FIN_WAIT1', + 5: 'FIN_WAIT2', + 6: 'TIME_WAIT', + 7: 'CLOSE', + 8: 'CLOSE_WAIT', + 9: 'LAST_ACK', + 10: 'LISTEN' + }, + 'proto': { + 0: 'IP', + 6: 'TCP', + 17: 'UDP', + 136: 'UDPLITE' + }, } -gen_rmaps = { k: {v2:k2 for k2,v2 in list(v.items())} for k,v in list(gen_maps.items()) } -sk_rmaps = { k: {v2:k2 for k2,v2 in list(v.items())} for k,v in list(sk_maps.items()) } +gen_rmaps = { + k: {v2: k2 + for k2, v2 in list(v.items())} + for k, v in list(gen_maps.items()) +} +sk_rmaps = { + k: {v2: k2 + for k2, v2 in list(v.items())} + for k, v in list(sk_maps.items()) +} dict_maps = { - 'gen' : ( gen_maps, gen_rmaps ), - 'sk' : ( sk_maps, sk_rmaps ), + 'gen': (gen_maps, gen_rmaps), + 'sk': (sk_maps, sk_rmaps), } + def map_flags(value, flags_map): - bs = [x[0] for x in [x for x in flags_map if value & x[1]]] - value &= ~sum([x[1] for x in flags_map]) - if value: - bs.append("0x%x" % value) - return " | ".join(bs) + bs = [x[0] for x in [x for x in flags_map if value & x[1]]] + value &= ~sum([x[1] for x in flags_map]) + if value: + bs.append("0x%x" % value) + return " | ".join(bs) + def unmap_flags(value, flags_map): - if value == '': - return 0 + if value == '': + return 0 - bd = dict(flags_map) - return sum([int(str(bd.get(x, x)), 0) for x in [x.strip() for x in value.split('|')]]) + bd = dict(flags_map) + return sum([ + int(str(bd.get(x, x)), 0) + for x in [x.strip() for x in value.split('|')] + ]) + + +kern_minorbits = 20 # This is how kernel encodes dev_t in new format -kern_minorbits = 20 # This is how kernel encodes dev_t in new format def decode_dev(field, value): - if _marked_as_odev(field): - return "%d:%d" % (os.major(value), os.minor(value)) - else: - return "%d:%d" % (value >> kern_minorbits, value & ((1 << kern_minorbits) - 1)) + if _marked_as_odev(field): + return "%d:%d" % (os.major(value), os.minor(value)) + else: + return "%d:%d" % (value >> kern_minorbits, + value & ((1 << kern_minorbits) - 1)) + def encode_dev(field, value): - dev = [int(x) for x in value.split(':')] - if _marked_as_odev(field): - return os.makedev(dev[0], dev[1]) - else: - return dev[0] << kern_minorbits | dev[1] + dev = [int(x) for x in value.split(':')] + if _marked_as_odev(field): + return os.makedev(dev[0], dev[1]) + else: + return dev[0] << kern_minorbits | dev[1] + def encode_base64(value): - return base64.encodebytes(value) + return base64.encodebytes(value) + + def decode_base64(value): - return base64.decodebytes(value) + return base64.decodebytes(value) + def encode_unix(value): - return quopri.encodestring(value) -def decode_unix(value): - return quopri.decodestring(value) + return quopri.encodestring(value) + + +def decode_unix(value): + return quopri.decodestring(value) + + +encode = {'unix_name': encode_unix} +decode = {'unix_name': decode_unix} -encode = { 'unix_name': encode_unix } -decode = { 'unix_name': decode_unix } def get_bytes_enc(field): - c = _custom_conv(field) - if c: - return encode[c] - else: - return encode_base64 + c = _custom_conv(field) + if c: + return encode[c] + else: + return encode_base64 + def get_bytes_dec(field): - c = _custom_conv(field) - if c: - return decode[c] - else: - return decode_base64 + c = _custom_conv(field) + if c: + return decode[c] + else: + return decode_base64 + def is_string(value): - # Python 3 compatibility - if "basestring" in __builtins__: - string_types = basestring # noqa: F821 - else: - string_types = (str, bytes) - return isinstance(value, string_types) + # Python 3 compatibility + if "basestring" in __builtins__: + string_types = basestring # noqa: F821 + else: + string_types = (str, bytes) + return isinstance(value, string_types) -def _pb2dict_cast(field, value, pretty = False, is_hex = False): - if not is_hex: - is_hex = _marked_as_hex(field) - if field.type == FD.TYPE_MESSAGE: - return pb2dict(value, pretty, is_hex) - elif field.type == FD.TYPE_BYTES: - return get_bytes_enc(field)(value) - elif field.type == FD.TYPE_ENUM: - return field.enum_type.values_by_number.get(value, None).name - elif field.type in _basic_cast: - cast = _basic_cast[field.type] - if pretty and (cast == int): - if is_hex: - # Fields that have (criu).hex = true option set - # should be stored in hex string format. - return "0x%x" % value +def _pb2dict_cast(field, value, pretty=False, is_hex=False): + if not is_hex: + is_hex = _marked_as_hex(field) - if _marked_as_dev(field): - return decode_dev(field, value) + if field.type == FD.TYPE_MESSAGE: + return pb2dict(value, pretty, is_hex) + elif field.type == FD.TYPE_BYTES: + return get_bytes_enc(field)(value) + elif field.type == FD.TYPE_ENUM: + return field.enum_type.values_by_number.get(value, None).name + elif field.type in _basic_cast: + cast = _basic_cast[field.type] + if pretty and (cast == int): + if is_hex: + # Fields that have (criu).hex = true option set + # should be stored in hex string format. + return "0x%x" % value - flags = _marked_as_flags(field) - if flags: - try: - flags_map = flags_maps[flags] - except: - return "0x%x" % value # flags are better seen as hex anyway - else: - return map_flags(value, flags_map) + if _marked_as_dev(field): + return decode_dev(field, value) - dct = _marked_as_dict(field) - if dct: - return dict_maps[dct][0][field.name].get(value, cast(value)) + flags = _marked_as_flags(field) + if flags: + try: + flags_map = flags_maps[flags] + except Exception: + return "0x%x" % value # flags are better seen as hex anyway + else: + return map_flags(value, flags_map) - return cast(value) - else: - raise Exception("Field(%s) has unsupported type %d" % (field.name, field.type)) + dct = _marked_as_dict(field) + if dct: + return dict_maps[dct][0][field.name].get(value, cast(value)) -def pb2dict(pb, pretty = False, is_hex = False): - """ - Convert protobuf msg to dictionary. - Takes a protobuf message and returns a dict. - """ - d = collections.OrderedDict() if pretty else {} - for field, value in pb.ListFields(): - if field.label == FD.LABEL_REPEATED: - d_val = [] - if pretty and _marked_as_ip(field): - if len(value) == 1: - v = socket.ntohl(value[0]) - addr = IPv4Address(v) - else: - v = 0 + (socket.ntohl(value[0]) << (32 * 3)) + \ - (socket.ntohl(value[1]) << (32 * 2)) + \ - (socket.ntohl(value[2]) << (32 * 1)) + \ - (socket.ntohl(value[3])) - addr = IPv6Address(v) + return cast(value) + else: + raise Exception("Field(%s) has unsupported type %d" % + (field.name, field.type)) - d_val.append(addr.compressed) - else: - for v in value: - d_val.append(_pb2dict_cast(field, v, pretty, is_hex)) - else: - d_val = _pb2dict_cast(field, value, pretty, is_hex) - d[field.name] = d_val - return d +def pb2dict(pb, pretty=False, is_hex=False): + """ + Convert protobuf msg to dictionary. + Takes a protobuf message and returns a dict. + """ + d = collections.OrderedDict() if pretty else {} + for field, value in pb.ListFields(): + if field.label == FD.LABEL_REPEATED: + d_val = [] + if pretty and _marked_as_ip(field): + if len(value) == 1: + v = socket.ntohl(value[0]) + addr = IPv4Address(v) + else: + v = 0 + (socket.ntohl(value[0]) << (32 * 3)) + \ + (socket.ntohl(value[1]) << (32 * 2)) + \ + (socket.ntohl(value[2]) << (32 * 1)) + \ + (socket.ntohl(value[3])) + addr = IPv6Address(v) + + d_val.append(addr.compressed) + else: + for v in value: + d_val.append(_pb2dict_cast(field, v, pretty, is_hex)) + else: + d_val = _pb2dict_cast(field, value, pretty, is_hex) + + d[field.name] = d_val + return d + def _dict2pb_cast(field, value): - # Not considering TYPE_MESSAGE here, as repeated - # and non-repeated messages need special treatment - # in this case, and are hadled separately. - if field.type == FD.TYPE_BYTES: - return get_bytes_dec(field)(value) - elif field.type == FD.TYPE_ENUM: - return field.enum_type.values_by_name.get(value, None).number - elif field.type in _basic_cast: - cast = _basic_cast[field.type] - if (cast == int) and is_string(value): - if _marked_as_dev(field): - return encode_dev(field, value) + # Not considering TYPE_MESSAGE here, as repeated + # and non-repeated messages need special treatment + # in this case, and are hadled separately. + if field.type == FD.TYPE_BYTES: + return get_bytes_dec(field)(value) + elif field.type == FD.TYPE_ENUM: + return field.enum_type.values_by_name.get(value, None).number + elif field.type in _basic_cast: + cast = _basic_cast[field.type] + if (cast == int) and is_string(value): + if _marked_as_dev(field): + return encode_dev(field, value) - flags = _marked_as_flags(field) - if flags: - try: - flags_map = flags_maps[flags] - except: - pass # Try to use plain string cast - else: - return unmap_flags(value, flags_map) + flags = _marked_as_flags(field) + if flags: + try: + flags_map = flags_maps[flags] + except Exception: + pass # Try to use plain string cast + else: + return unmap_flags(value, flags_map) - dct = _marked_as_dict(field) - if dct: - ret = dict_maps[dct][1][field.name].get(value, None) - if ret == None: - ret = cast(value, 0) - return ret + dct = _marked_as_dict(field) + if dct: + ret = dict_maps[dct][1][field.name].get(value, None) + if ret is None: + ret = cast(value, 0) + return ret + + # Some int or long fields might be stored as hex + # strings. See _pb2dict_cast. + return cast(value, 0) + else: + return cast(value) + else: + raise Exception("Field(%s) has unsupported type %d" % + (field.name, field.type)) - # Some int or long fields might be stored as hex - # strings. See _pb2dict_cast. - return cast(value, 0) - else: - return cast(value) - else: - raise Exception("Field(%s) has unsupported type %d" % (field.name, field.type)) def dict2pb(d, pb): - """ - Convert dictionary to protobuf msg. - Takes dict and protobuf message to be merged into. - """ - for field in pb.DESCRIPTOR.fields: - if field.name not in d: - continue - value = d[field.name] - if field.label == FD.LABEL_REPEATED: - pb_val = getattr(pb, field.name, None) - if is_string(value[0]) and _marked_as_ip(field): - val = ip_address(value[0]) - if val.version == 4: - pb_val.append(socket.htonl(int(val))) - elif val.version == 6: - ival = int(val) - pb_val.append(socket.htonl((ival >> (32 * 3)) & 0xFFFFFFFF)) - pb_val.append(socket.htonl((ival >> (32 * 2)) & 0xFFFFFFFF)) - pb_val.append(socket.htonl((ival >> (32 * 1)) & 0xFFFFFFFF)) - pb_val.append(socket.htonl((ival >> (32 * 0)) & 0xFFFFFFFF)) - else: - raise Exception("Unknown IP address version %d" % val.version) - continue + """ + Convert dictionary to protobuf msg. + Takes dict and protobuf message to be merged into. + """ + for field in pb.DESCRIPTOR.fields: + if field.name not in d: + continue + value = d[field.name] + if field.label == FD.LABEL_REPEATED: + pb_val = getattr(pb, field.name, None) + if is_string(value[0]) and _marked_as_ip(field): + val = ip_address(value[0]) + if val.version == 4: + pb_val.append(socket.htonl(int(val))) + elif val.version == 6: + ival = int(val) + pb_val.append(socket.htonl((ival >> (32 * 3)) & 0xFFFFFFFF)) + pb_val.append(socket.htonl((ival >> (32 * 2)) & 0xFFFFFFFF)) + pb_val.append(socket.htonl((ival >> (32 * 1)) & 0xFFFFFFFF)) + pb_val.append(socket.htonl((ival >> (32 * 0)) & 0xFFFFFFFF)) + else: + raise Exception("Unknown IP address version %d" % + val.version) + continue - for v in value: - if field.type == FD.TYPE_MESSAGE: - dict2pb(v, pb_val.add()) - else: - pb_val.append(_dict2pb_cast(field, v)) - else: - if field.type == FD.TYPE_MESSAGE: - # SetInParent method acts just like has_* = true in C, - # and helps to properly treat cases when we have optional - # field with empty repeated inside. - getattr(pb, field.name).SetInParent() + for v in value: + if field.type == FD.TYPE_MESSAGE: + dict2pb(v, pb_val.add()) + else: + pb_val.append(_dict2pb_cast(field, v)) + else: + if field.type == FD.TYPE_MESSAGE: + # SetInParent method acts just like has_* = true in C, + # and helps to properly treat cases when we have optional + # field with empty repeated inside. + getattr(pb, field.name).SetInParent() - dict2pb(value, getattr(pb, field.name, None)) - else: - setattr(pb, field.name, _dict2pb_cast(field, value)) - return pb + dict2pb(value, getattr(pb, field.name, None)) + else: + setattr(pb, field.name, _dict2pb_cast(field, value)) + return pb diff --git a/scripts/crit-setup.py b/scripts/crit-setup.py index f40588142..871e55921 100644 --- a/scripts/crit-setup.py +++ b/scripts/crit-setup.py @@ -1,12 +1,11 @@ from distutils.core import setup -setup(name = "crit", - version = "0.0.1", - description = "CRiu Image Tool", - author = "CRIU team", - author_email = "criu@openvz.org", - url = "https://github.com/checkpoint-restore/criu", - package_dir = {'pycriu': 'lib/py'}, - packages = ["pycriu", "pycriu.images"], - scripts = ["crit/crit"] - ) +setup(name="crit", + version="0.0.1", + description="CRiu Image Tool", + author="CRIU team", + author_email="criu@openvz.org", + url="https://github.com/checkpoint-restore/criu", + package_dir={'pycriu': 'lib/py'}, + packages=["pycriu", "pycriu.images"], + scripts=["crit/crit"]) diff --git a/scripts/magic-gen.py b/scripts/magic-gen.py index 7088f634d..3d9777735 100755 --- a/scripts/magic-gen.py +++ b/scripts/magic-gen.py @@ -1,61 +1,63 @@ #!/bin/env python2 import sys + # This program parses criu magic.h file and produces # magic.py with all *_MAGIC constants except RAW and V1. def main(argv): - if len(argv) != 3: - print("Usage: magic-gen.py path/to/image.h path/to/magic.py") - exit(1) + if len(argv) != 3: + print("Usage: magic-gen.py path/to/image.h path/to/magic.py") + exit(1) - magic_c_header = argv[1] - magic_py = argv[2] + magic_c_header = argv[1] + magic_py = argv[2] - out = open(magic_py, 'w+') + out = open(magic_py, 'w+') - # all_magic is used to parse constructions like: - # #define PAGEMAP_MAGIC 0x56084025 - # #define SHMEM_PAGEMAP_MAGIC PAGEMAP_MAGIC - all_magic = {} - # and magic is used to store only unique magic. - magic = {} + # all_magic is used to parse constructions like: + # #define PAGEMAP_MAGIC 0x56084025 + # #define SHMEM_PAGEMAP_MAGIC PAGEMAP_MAGIC + all_magic = {} + # and magic is used to store only unique magic. + magic = {} - f = open(magic_c_header, 'r') - for line in f: - split = line.split() + f = open(magic_c_header, 'r') + for line in f: + split = line.split() - if len(split) < 3: - continue + if len(split) < 3: + continue - if not '#define' in split[0]: - continue + if not '#define' in split[0]: + continue - key = split[1] - value = split[2] + key = split[1] + value = split[2] - if value in all_magic: - value = all_magic[value] - else: - magic[key] = value + if value in all_magic: + value = all_magic[value] + else: + magic[key] = value - all_magic[key] = value + all_magic[key] = value + + out.write('#Autogenerated. Do not edit!\n') + out.write('by_name = {}\n') + out.write('by_val = {}\n') + for k, v in list(magic.items()): + # We don't need RAW or V1 magic, because + # they can't be used to identify images. + if v == '0x0' or v == '1' or k == '0x0' or v == '1': + continue + if k.endswith("_MAGIC"): + # Just cutting _MAGIC suffix + k = k[:-6] + v = int(v, 16) + out.write("by_name['" + k + "'] = " + str(v) + "\n") + out.write("by_val[" + str(v) + "] = '" + k + "'\n") + f.close() + out.close() - out.write('#Autogenerated. Do not edit!\n') - out.write('by_name = {}\n') - out.write('by_val = {}\n') - for k,v in list(magic.items()): - # We don't need RAW or V1 magic, because - # they can't be used to identify images. - if v == '0x0' or v == '1' or k == '0x0' or v == '1': - continue - if k.endswith("_MAGIC"): - # Just cutting _MAGIC suffix - k = k[:-6] - v = int(v, 16) - out.write("by_name['"+ k +"'] = "+ str(v) +"\n") - out.write("by_val["+ str(v) +"] = '"+ k +"'\n") - f.close() - out.close() if __name__ == "__main__": - main(sys.argv) + main(sys.argv) diff --git a/soccr/test/run.py b/soccr/test/run.py index a25c29263..446584a71 100644 --- a/soccr/test/run.py +++ b/soccr/test/run.py @@ -13,17 +13,17 @@ sport = os.getenv("TCP_SPORT", "12345") dport = os.getenv("TCP_DPORT", "54321") print(sys.argv[1]) -args = [sys.argv[1], - "--addr", src, "--port", sport, "--seq", "555", - "--next", - "--addr", dst, "--port", dport, "--seq", "666", - "--reverse", "--", "./tcp-test.py"] +args = [ + sys.argv[1], "--addr", src, "--port", sport, "--seq", "555", "--next", + "--addr", dst, "--port", dport, "--seq", "666", "--reverse", "--", + "./tcp-test.py" +] -p1 = Popen(args + ["dst"], stdout = PIPE, stdin = PIPE) +p1 = Popen(args + ["dst"], stdout=PIPE, stdin=PIPE) -args.remove("--reverse"); +args.remove("--reverse") -p2 = Popen(args + ["src"], stdout = PIPE, stdin = PIPE) +p2 = Popen(args + ["src"], stdout=PIPE, stdin=PIPE) p1.stdout.read(5) p2.stdout.read(5) @@ -42,7 +42,7 @@ str2 = m.hexdigest() if str2 != eval(s): print("FAIL", repr(str2), repr(s)) - sys.exit(5); + sys.exit(5) s = p1.stdout.read() m = hashlib.md5() @@ -52,7 +52,7 @@ str1 = m.hexdigest() s = p2.stdout.read() if str1 != eval(s): print("FAIL", repr(str1), s) - sys.exit(5); + sys.exit(5) if p1.wait(): sys.exit(1) diff --git a/test/check_actions.py b/test/check_actions.py index 0e3daf178..ae909e668 100755 --- a/test/check_actions.py +++ b/test/check_actions.py @@ -4,37 +4,38 @@ import sys import os actions = set(['pre-dump', 'pre-restore', 'post-dump', 'setup-namespaces', \ - 'post-setup-namespaces', 'post-restore', 'post-resume', \ - 'network-lock', 'network-unlock' ]) + 'post-setup-namespaces', 'post-restore', 'post-resume', \ + 'network-lock', 'network-unlock' ]) errors = [] af = os.path.dirname(os.path.abspath(__file__)) + '/actions_called.txt' for act in open(af): - act = act.strip().split() - act.append('EMPTY') - act.append('EMPTY') + act = act.strip().split() + act.append('EMPTY') + act.append('EMPTY') - if act[0] == 'EMPTY': - raise Exception("Error in test, bogus actions line") + if act[0] == 'EMPTY': + raise Exception("Error in test, bogus actions line") - if act[1] == 'EMPTY': - errors.append('Action %s misses CRTOOLS_IMAGE_DIR' % act[0]) + if act[1] == 'EMPTY': + errors.append('Action %s misses CRTOOLS_IMAGE_DIR' % act[0]) - if act[0] in ('post-dump', 'setup-namespaces', 'post-setup-namespaces', \ - 'post-restore', 'post-resume', 'network-lock', 'network-unlock'): - if act[2] == 'EMPTY': - errors.append('Action %s misses CRTOOLS_INIT_PID' % act[0]) - elif not act[2].isdigit() or int(act[2]) == 0: - errors.append('Action %s PID is not number (%s)' % (act[0], act[2])) + if act[0] in ('post-dump', 'setup-namespaces', 'post-setup-namespaces', \ + 'post-restore', 'post-resume', 'network-lock', 'network-unlock'): + if act[2] == 'EMPTY': + errors.append('Action %s misses CRTOOLS_INIT_PID' % act[0]) + elif not act[2].isdigit() or int(act[2]) == 0: + errors.append('Action %s PID is not number (%s)' % + (act[0], act[2])) - actions -= set([act[0]]) + actions -= set([act[0]]) if actions: - errors.append('Not all actions called: %r' % actions) + errors.append('Not all actions called: %r' % actions) if errors: - for x in errors: - print(x) - sys.exit(1) + for x in errors: + print(x) + sys.exit(1) print('PASS') diff --git a/test/crit-recode.py b/test/crit-recode.py index 441f7757e..a7dcc7272 100755 --- a/test/crit-recode.py +++ b/test/crit-recode.py @@ -6,70 +6,72 @@ import sys import os import subprocess -find = subprocess.Popen(['find', 'test/dump/', '-size', '+0', '-name', '*.img'], - stdout = subprocess.PIPE) +find = subprocess.Popen( + ['find', 'test/dump/', '-size', '+0', '-name', '*.img'], + stdout=subprocess.PIPE) test_pass = True + def recode_and_check(imgf, o_img, pretty): - try: - pb = pycriu.images.loads(o_img, pretty) - except pycriu.images.MagicException as me: - print("%s magic %x error" % (imgf, me.magic)) - return False - except Exception as e: - print("%s %sdecode fails: %s" % (imgf, pretty and 'pretty ' or '', e)) - return False + try: + pb = pycriu.images.loads(o_img, pretty) + except pycriu.images.MagicException as me: + print("%s magic %x error" % (imgf, me.magic)) + return False + except Exception as e: + print("%s %sdecode fails: %s" % (imgf, pretty and 'pretty ' or '', e)) + return False - try: - r_img = pycriu.images.dumps(pb) - except Exception as e: - r_img = pycriu.images.dumps(pb) - print("%s %s encode fails: %s" % (imgf, pretty and 'pretty ' or '', e)) - return False + try: + r_img = pycriu.images.dumps(pb) + except Exception as e: + r_img = pycriu.images.dumps(pb) + print("%s %s encode fails: %s" % (imgf, pretty and 'pretty ' or '', e)) + return False - if o_img != r_img: - print("%s %s recode mismatch" % (imgf, pretty and 'pretty ' or '')) - return False + if o_img != r_img: + print("%s %s recode mismatch" % (imgf, pretty and 'pretty ' or '')) + return False - return True + return True for imgf in find.stdout.readlines(): - imgf = imgf.strip() - imgf_b = os.path.basename(imgf) + imgf = imgf.strip() + imgf_b = os.path.basename(imgf) - if imgf_b.startswith(b'pages-'): - continue - if imgf_b.startswith(b'iptables-'): - continue - if imgf_b.startswith(b'ip6tables-'): - continue - if imgf_b.startswith(b'route-'): - continue - if imgf_b.startswith(b'route6-'): - continue - if imgf_b.startswith(b'ifaddr-'): - continue - if imgf_b.startswith(b'tmpfs-'): - continue - if imgf_b.startswith(b'netns-ct-'): - continue - if imgf_b.startswith(b'netns-exp-'): - continue - if imgf_b.startswith(b'rule-'): - continue + if imgf_b.startswith(b'pages-'): + continue + if imgf_b.startswith(b'iptables-'): + continue + if imgf_b.startswith(b'ip6tables-'): + continue + if imgf_b.startswith(b'route-'): + continue + if imgf_b.startswith(b'route6-'): + continue + if imgf_b.startswith(b'ifaddr-'): + continue + if imgf_b.startswith(b'tmpfs-'): + continue + if imgf_b.startswith(b'netns-ct-'): + continue + if imgf_b.startswith(b'netns-exp-'): + continue + if imgf_b.startswith(b'rule-'): + continue - o_img = open(imgf.decode(), "rb").read() - if not recode_and_check(imgf, o_img, False): - test_pass = False - if not recode_and_check(imgf, o_img, True): - test_pass = False + o_img = open(imgf.decode(), "rb").read() + if not recode_and_check(imgf, o_img, False): + test_pass = False + if not recode_and_check(imgf, o_img, True): + test_pass = False find.wait() if not test_pass: - print("FAIL") - sys.exit(1) + print("FAIL") + sys.exit(1) print("PASS") diff --git a/test/exhaustive/pipe.py b/test/exhaustive/pipe.py index 17e065800..fdadc480c 100755 --- a/test/exhaustive/pipe.py +++ b/test/exhaustive/pipe.py @@ -8,125 +8,127 @@ import time import sys import subprocess -criu_bin='../../criu/criu' +criu_bin = '../../criu/criu' + def mix(nr_tasks, nr_pipes): - # Returned is the list of combinations. - # Each combination is the lists of pipe descriptors. - # Each pipe descriptor is a 2-elemtn tuple, that contains values - # for R and W ends of pipes, each being a bit-field denoting in - # which tasks the respective end should be opened or not. + # Returned is the list of combinations. + # Each combination is the lists of pipe descriptors. + # Each pipe descriptor is a 2-elemtn tuple, that contains values + # for R and W ends of pipes, each being a bit-field denoting in + # which tasks the respective end should be opened or not. - # First -- make a full set of combinations for a single pipe. - max_idx = 1 << nr_tasks - pipe_mix = [[(r, w)] for r in range(0, max_idx) for w in range(0, max_idx)] + # First -- make a full set of combinations for a single pipe. + max_idx = 1 << nr_tasks + pipe_mix = [[(r, w)] for r in range(0, max_idx) for w in range(0, max_idx)] - # Now, for every pipe throw another one into the game making - # all possible combinations of what was seen before with the - # newbie. - pipes_mix = pipe_mix - for t in range(1, nr_pipes): - pipes_mix = [ o + n for o in pipes_mix for n in pipe_mix ] + # Now, for every pipe throw another one into the game making + # all possible combinations of what was seen before with the + # newbie. + pipes_mix = pipe_mix + for t in range(1, nr_pipes): + pipes_mix = [o + n for o in pipes_mix for n in pipe_mix] - return pipes_mix + return pipes_mix # Called by a test sub-process. It just closes the not needed ends # of pipes and sleeps waiting for death. def make_pipes(task_nr, nr_pipes, pipes, comb, status_pipe): - print('\t\tMake pipes for %d' % task_nr) - # We need to make sure that pipes have their - # ends according to comb for task_nr + print('\t\tMake pipes for %d' % task_nr) + # We need to make sure that pipes have their + # ends according to comb for task_nr - for i in range(0, nr_pipes): - # Read end - if not (comb[i][0] & (1 << task_nr)): - os.close(pipes[i][0]) - # Write end - if not (comb[i][1] & (1 << task_nr)): - os.close(pipes[i][1]) + for i in range(0, nr_pipes): + # Read end + if not (comb[i][0] & (1 << task_nr)): + os.close(pipes[i][0]) + # Write end + if not (comb[i][1] & (1 << task_nr)): + os.close(pipes[i][1]) - os.write(status_pipe, '0') - os.close(status_pipe) - while True: - time.sleep(100) + os.write(status_pipe, '0') + os.close(status_pipe) + while True: + time.sleep(100) def get_pipe_ino(pid, fd): - try: - return os.stat('/proc/%d/fd/%d' % (pid, fd)).st_ino - except: - return None + try: + return os.stat('/proc/%d/fd/%d' % (pid, fd)).st_ino + except: + return None def get_pipe_rw(pid, fd): - for l in open('/proc/%d/fdinfo/%d' % (pid, fd)): - if l.startswith('flags:'): - f = l.split(None, 1)[1][-2] - if f == '0': - return 0 # Read - elif f == '1': - return 1 # Write - break + for l in open('/proc/%d/fdinfo/%d' % (pid, fd)): + if l.startswith('flags:'): + f = l.split(None, 1)[1][-2] + if f == '0': + return 0 # Read + elif f == '1': + return 1 # Write + break - raise Exception('Unexpected fdinfo contents') + raise Exception('Unexpected fdinfo contents') def check_pipe_y(pid, fd, rw, inos): - ino = get_pipe_ino(pid, fd) - if ino == None: - return 'missing ' - if not inos.has_key(fd): - inos[fd] = ino - elif inos[fd] != ino: - return 'wrong ' - mod = get_pipe_rw(pid, fd) - if mod != rw: - return 'badmode ' - return None + ino = get_pipe_ino(pid, fd) + if ino == None: + return 'missing ' + if not inos.has_key(fd): + inos[fd] = ino + elif inos[fd] != ino: + return 'wrong ' + mod = get_pipe_rw(pid, fd) + if mod != rw: + return 'badmode ' + return None def check_pipe_n(pid, fd): - ino = get_pipe_ino(pid, fd) - if ino == None: - return None - else: - return 'present ' + ino = get_pipe_ino(pid, fd) + if ino == None: + return None + else: + return 'present ' def check_pipe_end(kids, fd, comb, rw, inos): - t_nr = 0 - for t_pid in kids: - if comb & (1 << t_nr): - res = check_pipe_y(t_pid, fd, rw, inos) - else: - res = check_pipe_n(t_pid, fd) - if res != None: - return res + 'kid(%d)' % t_nr - t_nr += 1 - return None + t_nr = 0 + for t_pid in kids: + if comb & (1 << t_nr): + res = check_pipe_y(t_pid, fd, rw, inos) + else: + res = check_pipe_n(t_pid, fd) + if res != None: + return res + 'kid(%d)' % t_nr + t_nr += 1 + return None def check_pipe(kids, fds, comb, inos): - for e in (0, 1): # 0 == R, 1 == W, see get_pipe_rw() - res = check_pipe_end(kids, fds[e], comb[e], e, inos) - if res != None: - return res + 'end(%d)' % e - return None + for e in (0, 1): # 0 == R, 1 == W, see get_pipe_rw() + res = check_pipe_end(kids, fds[e], comb[e], e, inos) + if res != None: + return res + 'end(%d)' % e + return None + def check_pipes(kids, pipes, comb): - # Kids contain pids - # Pipes contain pipe FDs - # Comb contain list of pairs of bits for RW ends - p_nr = 0 - p_inos = {} - for p_fds in pipes: - res = check_pipe(kids, p_fds, comb[p_nr], p_inos) - if res != None: - return res + 'pipe(%d)' % p_nr - p_nr += 1 + # Kids contain pids + # Pipes contain pipe FDs + # Comb contain list of pairs of bits for RW ends + p_nr = 0 + p_inos = {} + for p_fds in pipes: + res = check_pipe(kids, p_fds, comb[p_nr], p_inos) + if res != None: + return res + 'pipe(%d)' % p_nr + p_nr += 1 - return None + return None # Run by test main process. It opens pipes, then forks kids that @@ -134,128 +136,134 @@ def check_pipes(kids, pipes, comb): # and waits for a signal (unix socket message) to start checking # the kids' FD tables. def make_comb(comb, opts, status_pipe): - print('\tMake pipes') - # 1st -- make needed pipes - pipes = [] - for p in range(0, opts.pipes): - pipes.append(os.pipe()) + print('\tMake pipes') + # 1st -- make needed pipes + pipes = [] + for p in range(0, opts.pipes): + pipes.append(os.pipe()) - # Fork the kids that'll make pipes - kc_pipe = os.pipe() - kids = [] - for t in range(0, opts.tasks): - pid = os.fork() - if pid == 0: - os.close(status_pipe) - os.close(kc_pipe[0]) - make_pipes(t, opts.pipes, pipes, comb, kc_pipe[1]) - sys.exit(1) - kids.append(pid) + # Fork the kids that'll make pipes + kc_pipe = os.pipe() + kids = [] + for t in range(0, opts.tasks): + pid = os.fork() + if pid == 0: + os.close(status_pipe) + os.close(kc_pipe[0]) + make_pipes(t, opts.pipes, pipes, comb, kc_pipe[1]) + sys.exit(1) + kids.append(pid) - os.close(kc_pipe[1]) - for p in pipes: - os.close(p[0]) - os.close(p[1]) + os.close(kc_pipe[1]) + for p in pipes: + os.close(p[0]) + os.close(p[1]) - # Wait for kids to get ready - k_res = '' - while True: - v = os.read(kc_pipe[0], 16) - if v == '': - break - k_res += v - os.close(kc_pipe[0]) + # Wait for kids to get ready + k_res = '' + while True: + v = os.read(kc_pipe[0], 16) + if v == '': + break + k_res += v + os.close(kc_pipe[0]) - ex_code = 1 - if k_res == '0' * opts.tasks: - print('\tWait for C/R') - cmd_sk = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) - cmd_sk.bind('\0CRIUPCSK') + ex_code = 1 + if k_res == '0' * opts.tasks: + print('\tWait for C/R') + cmd_sk = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) + cmd_sk.bind('\0CRIUPCSK') - # Kids are ready, so is socket for kicking us. Notify the - # parent task that we are good to go. - os.write(status_pipe, '0') - os.close(status_pipe) - v = cmd_sk.recv(16) - if v == '0': - print('\tCheck pipes') - res = check_pipes(kids, pipes, comb) - if res == None: - ex_code = 0 - else: - print('\tFAIL %s' % res) + # Kids are ready, so is socket for kicking us. Notify the + # parent task that we are good to go. + os.write(status_pipe, '0') + os.close(status_pipe) + v = cmd_sk.recv(16) + if v == '0': + print('\tCheck pipes') + res = check_pipes(kids, pipes, comb) + if res == None: + ex_code = 0 + else: + print('\tFAIL %s' % res) - # Just kill kids, all checks are done by us, we don't need'em any more - for t in kids: - os.kill(t, signal.SIGKILL) - os.waitpid(t, 0) + # Just kill kids, all checks are done by us, we don't need'em any more + for t in kids: + os.kill(t, signal.SIGKILL) + os.waitpid(t, 0) - return ex_code + return ex_code def cr_test(pid): - print('C/R test') - img_dir = 'pimg_%d' % pid - try: - os.mkdir(img_dir) - subprocess.check_call([criu_bin, 'dump', '-t', '%d' % pid, '-D', img_dir, '-o', 'dump.log', '-v4', '-j']) - except: - print('`- dump fail') - return False + print('C/R test') + img_dir = 'pimg_%d' % pid + try: + os.mkdir(img_dir) + subprocess.check_call([ + criu_bin, 'dump', '-t', + '%d' % pid, '-D', img_dir, '-o', 'dump.log', '-v4', '-j' + ]) + except: + print('`- dump fail') + return False - try: - os.waitpid(pid, 0) - subprocess.check_call([criu_bin, 'restore', '-D', img_dir, '-o', 'rst.log', '-v4', '-j', '-d', '-S']) - except: - print('`- restore fail') - return False + try: + os.waitpid(pid, 0) + subprocess.check_call([ + criu_bin, 'restore', '-D', img_dir, '-o', 'rst.log', '-v4', '-j', + '-d', '-S' + ]) + except: + print('`- restore fail') + return False - return True + return True def run(comb, opts): - print('Checking %r' % comb) - cpipe = os.pipe() - pid = os.fork() - if pid == 0: - os.close(cpipe[0]) - ret = make_comb(comb, opts, cpipe[1]) - sys.exit(ret) + print('Checking %r' % comb) + cpipe = os.pipe() + pid = os.fork() + if pid == 0: + os.close(cpipe[0]) + ret = make_comb(comb, opts, cpipe[1]) + sys.exit(ret) - # Wait for the main process to get ready - os.close(cpipe[1]) - res = os.read(cpipe[0], 16) - os.close(cpipe[0]) + # Wait for the main process to get ready + os.close(cpipe[1]) + res = os.read(cpipe[0], 16) + os.close(cpipe[0]) - if res == '0': - res = cr_test(pid) + if res == '0': + res = cr_test(pid) - print('Wake up test') - s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) - if res: - res = '0' - else: - res = 'X' - try: - # Kick the test to check its state - s.sendto(res, '\0CRIUPCSK') - except: - # Restore might have failed or smth else happened - os.kill(pid, signal.SIGKILL) - s.close() + print('Wake up test') + s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) + if res: + res = '0' + else: + res = 'X' + try: + # Kick the test to check its state + s.sendto(res, '\0CRIUPCSK') + except: + # Restore might have failed or smth else happened + os.kill(pid, signal.SIGKILL) + s.close() - # Wait for the guy to exit and get the result (PASS/FAIL) - p, st = os.waitpid(pid, 0) - if os.WIFEXITED(st): - st = os.WEXITSTATUS(st) + # Wait for the guy to exit and get the result (PASS/FAIL) + p, st = os.waitpid(pid, 0) + if os.WIFEXITED(st): + st = os.WEXITSTATUS(st) - print('Done (%d, pid == %d)' % (st, pid)) - return st == 0 + print('Done (%d, pid == %d)' % (st, pid)) + return st == 0 p = argparse.ArgumentParser("CRIU test suite") -p.add_argument("--tasks", help = "Number of tasks", default = '2') -p.add_argument("--pipes", help = "Number of pipes", default = '2') +p.add_argument("--tasks", help="Number of tasks", default='2') +p.add_argument("--pipes", help="Number of pipes", default='2') opts = p.parse_args() opts.tasks = int(opts.tasks) opts.pipes = int(opts.pipes) @@ -263,8 +271,8 @@ opts.pipes = int(opts.pipes) pipe_combs = mix(opts.tasks, opts.pipes) for comb in pipe_combs: - if not run(comb, opts): - print('FAIL') - break + if not run(comb, opts): + print('FAIL') + break else: - print('PASS') + print('PASS') diff --git a/test/exhaustive/unix.py b/test/exhaustive/unix.py index 41053bd0d..98dbbb7b0 100755 --- a/test/exhaustive/unix.py +++ b/test/exhaustive/unix.py @@ -9,11 +9,11 @@ import signal import fcntl import stat -criu_bin='../../criu/criu' +criu_bin = '../../criu/criu' sk_type_s = { - socket.SOCK_STREAM: "S", - socket.SOCK_DGRAM: "D", + socket.SOCK_STREAM: "S", + socket.SOCK_DGRAM: "D", } # Actions that can be done by test. Actions are not only syscall @@ -25,721 +25,739 @@ sk_type_s = { # - do() method, that actually does what's required # - show() method to return the string description of what's done + def mk_socket(st, typ): - st.sk_id += 1 - sk = sock(st.sk_id, typ) - st.add_socket(sk) - return sk + st.sk_id += 1 + sk = sock(st.sk_id, typ) + st.add_socket(sk) + return sk + class act_socket: - def __init__(self, typ): - self.typ = typ + def __init__(self, typ): + self.typ = typ - def act(self, st): - sk = mk_socket(st, self.typ) - self.sk_id = sk.sk_id + def act(self, st): + sk = mk_socket(st, self.typ) + self.sk_id = sk.sk_id - def do(self, st): - sk = socket.socket(socket.AF_UNIX, self.typ, 0) - st.real_sockets[self.sk_id] = sk + def do(self, st): + sk = socket.socket(socket.AF_UNIX, self.typ, 0) + st.real_sockets[self.sk_id] = sk - def show(self): - return 'socket(%s) = %d' % (sk_type_s[self.typ], self.sk_id) + def show(self): + return 'socket(%s) = %d' % (sk_type_s[self.typ], self.sk_id) class act_close: - def __init__(self, sk_id): - self.sk_id = sk_id + def __init__(self, sk_id): + self.sk_id = sk_id - def act(self, st): - sk = st.get_socket(self.sk_id) - st.del_socket(sk) - for ic in sk.icons: - sk = st.get_socket(ic) - st.del_socket(sk) + def act(self, st): + sk = st.get_socket(self.sk_id) + st.del_socket(sk) + for ic in sk.icons: + sk = st.get_socket(ic) + st.del_socket(sk) - def do(self, st): - sk = st.real_sockets.pop(self.sk_id) - sk.close() + def do(self, st): + sk = st.real_sockets.pop(self.sk_id) + sk.close() - def show(self): - return 'close(%d)' % self.sk_id + def show(self): + return 'close(%d)' % self.sk_id class act_listen: - def __init__(self, sk_id): - self.sk_id = sk_id + def __init__(self, sk_id): + self.sk_id = sk_id - def act(self, st): - sk = st.get_socket(self.sk_id) - sk.listen = True + def act(self, st): + sk = st.get_socket(self.sk_id) + sk.listen = True - def do(self, st): - sk = st.real_sockets[self.sk_id] - sk.listen(10) + def do(self, st): + sk = st.real_sockets[self.sk_id] + sk.listen(10) - def show(self): - return 'listen(%d)' % self.sk_id + def show(self): + return 'listen(%d)' % self.sk_id class act_bind: - def __init__(self, sk_id, name_id): - self.sk_id = sk_id - self.name_id = name_id + def __init__(self, sk_id, name_id): + self.sk_id = sk_id + self.name_id = name_id - def act(self, st): - sk = st.get_socket(self.sk_id) - sk.name = self.name_id + def act(self, st): + sk = st.get_socket(self.sk_id) + sk.name = self.name_id - def do(self, st): - sk = st.real_sockets[self.sk_id] - sk.bind(sock.real_name_for(self.name_id)) + def do(self, st): + sk = st.real_sockets[self.sk_id] + sk.bind(sock.real_name_for(self.name_id)) - def show(self): - return 'bind(%d, $name-%d)' % (self.sk_id, self.name_id) + def show(self): + return 'bind(%d, $name-%d)' % (self.sk_id, self.name_id) class act_connect: - def __init__(self, sk_id, listen_sk_id): - self.sk_id = sk_id - self.lsk_id = listen_sk_id + def __init__(self, sk_id, listen_sk_id): + self.sk_id = sk_id + self.lsk_id = listen_sk_id - def act(self, st): - sk = st.get_socket(self.sk_id) - if st.sk_type == socket.SOCK_STREAM: - lsk = st.get_socket(self.lsk_id) - psk = mk_socket(st, socket.SOCK_STREAM) - psk.visible = False - sk.peer = psk.sk_id - psk.peer = sk.sk_id - psk.name = lsk.name - lsk.icons.append(psk.sk_id) - lsk.icons_seq += 1 - else: - sk.peer = self.lsk_id - psk = st.get_socket(self.lsk_id) - psk.icons_seq += 1 + def act(self, st): + sk = st.get_socket(self.sk_id) + if st.sk_type == socket.SOCK_STREAM: + lsk = st.get_socket(self.lsk_id) + psk = mk_socket(st, socket.SOCK_STREAM) + psk.visible = False + sk.peer = psk.sk_id + psk.peer = sk.sk_id + psk.name = lsk.name + lsk.icons.append(psk.sk_id) + lsk.icons_seq += 1 + else: + sk.peer = self.lsk_id + psk = st.get_socket(self.lsk_id) + psk.icons_seq += 1 - def do(self, st): - sk = st.real_sockets[self.sk_id] - sk.connect(sock.real_name_for(self.lsk_id)) + def do(self, st): + sk = st.real_sockets[self.sk_id] + sk.connect(sock.real_name_for(self.lsk_id)) - def show(self): - return 'connect(%d, $name-%d)' % (self.sk_id, self.lsk_id) + def show(self): + return 'connect(%d, $name-%d)' % (self.sk_id, self.lsk_id) class act_accept: - def __init__(self, sk_id): - self.sk_id = sk_id + def __init__(self, sk_id): + self.sk_id = sk_id - def act(self, st): - lsk = st.get_socket(self.sk_id) - iid = lsk.icons.pop(0) - nsk = st.get_socket(iid) - nsk.visible = True - self.nsk_id = nsk.sk_id + def act(self, st): + lsk = st.get_socket(self.sk_id) + iid = lsk.icons.pop(0) + nsk = st.get_socket(iid) + nsk.visible = True + self.nsk_id = nsk.sk_id - def do(self, st): - sk = st.real_sockets[self.sk_id] - nsk, ai = sk.accept() - if self.nsk_id in st.real_sockets: - raise Exception("SK ID conflict") - st.real_sockets[self.nsk_id] = nsk + def do(self, st): + sk = st.real_sockets[self.sk_id] + nsk, ai = sk.accept() + if self.nsk_id in st.real_sockets: + raise Exception("SK ID conflict") + st.real_sockets[self.nsk_id] = nsk - def show(self): - return 'accept(%d) = %d' % (self.sk_id, self.nsk_id) + def show(self): + return 'accept(%d) = %d' % (self.sk_id, self.nsk_id) class act_sendmsg: - def __init__(self, sk_id, to_id): - self.sk_id = sk_id - self.to_id = to_id - self.direct_send = None + def __init__(self, sk_id, to_id): + self.sk_id = sk_id + self.to_id = to_id + self.direct_send = None - def act(self, st): - sk = st.get_socket(self.sk_id) - msg = (sk.sk_id, sk.outseq) - self.msg_id = sk.outseq - sk.outseq += 1 - psk = st.get_socket(self.to_id) - psk.inqueue.append(msg) - self.direct_send = (sk.peer == psk.sk_id) + def act(self, st): + sk = st.get_socket(self.sk_id) + msg = (sk.sk_id, sk.outseq) + self.msg_id = sk.outseq + sk.outseq += 1 + psk = st.get_socket(self.to_id) + psk.inqueue.append(msg) + self.direct_send = (sk.peer == psk.sk_id) - def do(self, st): - sk = st.real_sockets[self.sk_id] - msgv = act_sendmsg.msgval(self.msg_id) - if self.direct_send: - sk.send(msgv) - else: - sk.sendto(msgv, sock.real_name_for(self.to_id)) + def do(self, st): + sk = st.real_sockets[self.sk_id] + msgv = act_sendmsg.msgval(self.msg_id) + if self.direct_send: + sk.send(msgv) + else: + sk.sendto(msgv, sock.real_name_for(self.to_id)) - def show(self): - return 'send(%d, %d, $message-%d)' % (self.sk_id, self.to_id, self.msg_id) + def show(self): + return 'send(%d, %d, $message-%d)' % (self.sk_id, self.to_id, + self.msg_id) + + @staticmethod + def msgval(msgid, pref=''): + return '%sMSG%d' % (pref, msgid) - @staticmethod - def msgval(msgid, pref = ''): - return '%sMSG%d' % (pref, msgid) # # Description of a socket # class sock: - def __init__(self, sk_id, sock_type): - # ID of a socket. Since states and sockets are cloned - # while we scan the tree of states the only valid way - # to address a socket is to find one by ID. - self.sk_id = sk_id - # The socket.SOCK_FOO value - self.sk_type = sock_type - # Sockets that haven't yet been accept()-ed are in the - # state, but user cannot operate on them. Also this - # invisibility contributes to state description since - # connection to not accepted socket is not the same - # as connection to accepted one. - self.visible = True - # The listen() was called. - self.listen = False - # The bind() was called. Also set by accept(), the name - # inherits from listener. - self.name = None - # The connect() was called. Set on two sockets when the - # connect() is called. - self.peer = None - # Progress on accepting connections. Used to check when - # it's OK to close the socket (see comment below). - self.icons_seq = 0 - # List of IDs of sockets that can be accept()-ed - self.icons = [] - # Number to generate message contents. - self.outseq = 0 - # Incoming queue of messages. - self.inqueue = [] + def __init__(self, sk_id, sock_type): + # ID of a socket. Since states and sockets are cloned + # while we scan the tree of states the only valid way + # to address a socket is to find one by ID. + self.sk_id = sk_id + # The socket.SOCK_FOO value + self.sk_type = sock_type + # Sockets that haven't yet been accept()-ed are in the + # state, but user cannot operate on them. Also this + # invisibility contributes to state description since + # connection to not accepted socket is not the same + # as connection to accepted one. + self.visible = True + # The listen() was called. + self.listen = False + # The bind() was called. Also set by accept(), the name + # inherits from listener. + self.name = None + # The connect() was called. Set on two sockets when the + # connect() is called. + self.peer = None + # Progress on accepting connections. Used to check when + # it's OK to close the socket (see comment below). + self.icons_seq = 0 + # List of IDs of sockets that can be accept()-ed + self.icons = [] + # Number to generate message contents. + self.outseq = 0 + # Incoming queue of messages. + self.inqueue = [] - def clone(self): - sk = sock(self.sk_id, self.sk_type) - sk.visible = self.visible - sk.listen = self.listen - sk.name = self.name - sk.peer = self.peer - sk.icons_seq = self.icons_seq - sk.icons = list(self.icons) - sk.outseq = self.outseq - sk.inqueue = list(self.inqueue) - return sk + def clone(self): + sk = sock(self.sk_id, self.sk_type) + sk.visible = self.visible + sk.listen = self.listen + sk.name = self.name + sk.peer = self.peer + sk.icons_seq = self.icons_seq + sk.icons = list(self.icons) + sk.outseq = self.outseq + sk.inqueue = list(self.inqueue) + return sk - def get_actions(self, st): - if not self.visible: - return [] + def get_actions(self, st): + if not self.visible: + return [] - if st.sk_type == socket.SOCK_STREAM: - return self.get_stream_actions(st) - else: - return self.get_dgram_actions(st) + if st.sk_type == socket.SOCK_STREAM: + return self.get_stream_actions(st) + else: + return self.get_dgram_actions(st) - def get_send_action(self, to, st): - # However, if peer has a message from us at - # the queue tail, sending a new one doesn't - # really make sense - want_msg = True - if len(to.inqueue) != 0: - lmsg = to.inqueue[-1] - if lmsg[0] == self.sk_id: - want_msg = False - if want_msg: - return [ act_sendmsg(self.sk_id, to.sk_id) ] - else: - return [ ] + def get_send_action(self, to, st): + # However, if peer has a message from us at + # the queue tail, sending a new one doesn't + # really make sense + want_msg = True + if len(to.inqueue) != 0: + lmsg = to.inqueue[-1] + if lmsg[0] == self.sk_id: + want_msg = False + if want_msg: + return [act_sendmsg(self.sk_id, to.sk_id)] + else: + return [] - def get_stream_actions(self, st): - act_list = [] + def get_stream_actions(self, st): + act_list = [] - # Any socket can be closed, but closing a socket - # that hasn't contributed to some new states is - # just waste of time, so we close only connected - # sockets or listeners that has at least one - # incoming connection pendig or served + # Any socket can be closed, but closing a socket + # that hasn't contributed to some new states is + # just waste of time, so we close only connected + # sockets or listeners that has at least one + # incoming connection pendig or served - if self.listen: - if self.icons: - act_list.append(act_accept(self.sk_id)) - if self.icons_seq: - act_list.append(act_close(self.sk_id)) - elif self.peer: - act_list.append(act_close(self.sk_id)) - # Connected sockets can send and receive messages - # But receiving seem not to produce any new states, - # so only sending - # Also sending to a closed socket doesn't work - psk = st.get_socket(self.peer, True) - if psk: - act_list += self.get_send_action(psk, st) - else: - for psk in st.sockets: - if psk.listen and psk.name: - act_list.append(act_connect(self.sk_id, psk.sk_id)) + if self.listen: + if self.icons: + act_list.append(act_accept(self.sk_id)) + if self.icons_seq: + act_list.append(act_close(self.sk_id)) + elif self.peer: + act_list.append(act_close(self.sk_id)) + # Connected sockets can send and receive messages + # But receiving seem not to produce any new states, + # so only sending + # Also sending to a closed socket doesn't work + psk = st.get_socket(self.peer, True) + if psk: + act_list += self.get_send_action(psk, st) + else: + for psk in st.sockets: + if psk.listen and psk.name: + act_list.append(act_connect(self.sk_id, psk.sk_id)) - # Listen on not-bound socket is prohibited as - # well as binding a listening socket - if not self.name: - # TODO: support for file paths (see real_name_for) - # TODO: these names can overlap each other - act_list.append(act_bind(self.sk_id, self.sk_id)) - else: - act_list.append(act_listen(self.sk_id)) + # Listen on not-bound socket is prohibited as + # well as binding a listening socket + if not self.name: + # TODO: support for file paths (see real_name_for) + # TODO: these names can overlap each other + act_list.append(act_bind(self.sk_id, self.sk_id)) + else: + act_list.append(act_listen(self.sk_id)) - return act_list + return act_list - def get_dgram_actions(self, st): - act_list = [] + def get_dgram_actions(self, st): + act_list = [] - # Dgram socket can bind at any time - if not self.name: - act_list.append(act_bind(self.sk_id, self.sk_id)) + # Dgram socket can bind at any time + if not self.name: + act_list.append(act_bind(self.sk_id, self.sk_id)) - # Can connect to peer-less sockets - for psk in st.sockets: - if psk == self: - continue - if psk.peer != None and psk.peer != self.sk_id: - # Peer by someone else, can do nothing - continue + # Can connect to peer-less sockets + for psk in st.sockets: + if psk == self: + continue + if psk.peer != None and psk.peer != self.sk_id: + # Peer by someone else, can do nothing + continue - # Peer-less psk or having us as peer - # We can connect to or send messages - if psk.name and self.peer != psk.sk_id: - act_list.append(act_connect(self.sk_id, psk.sk_id)) + # Peer-less psk or having us as peer + # We can connect to or send messages + if psk.name and self.peer != psk.sk_id: + act_list.append(act_connect(self.sk_id, psk.sk_id)) - if psk.name or self.peer == psk.sk_id: - act_list += self.get_send_action(psk, st) + if psk.name or self.peer == psk.sk_id: + act_list += self.get_send_action(psk, st) - if self.outseq != 0 or self.icons_seq != 0: - act_list.append(act_close(self.sk_id)) + if self.outseq != 0 or self.icons_seq != 0: + act_list.append(act_close(self.sk_id)) - return act_list + return act_list - @staticmethod - def name_of(sk): - if not sk: - return 'X' - elif not sk.visible: - return 'H' - elif sk.name: - return 'B' - else: - return 'A' + @staticmethod + def name_of(sk): + if not sk: + return 'X' + elif not sk.visible: + return 'H' + elif sk.name: + return 'B' + else: + return 'A' - @staticmethod - def real_name_for(sk_id): - return "\0" + "CRSK%d" % sk_id + @staticmethod + def real_name_for(sk_id): + return "\0" + "CRSK%d" % sk_id - # The describe() generates a string that represents - # a state of a socket. Called by state.describe(), see - # comment there about what description is. - def describe(self, st): - dsc = '%s' % sk_type_s[self.sk_type] - dsc += sock.name_of(self) + # The describe() generates a string that represents + # a state of a socket. Called by state.describe(), see + # comment there about what description is. + def describe(self, st): + dsc = '%s' % sk_type_s[self.sk_type] + dsc += sock.name_of(self) - if self.listen: - dsc += 'L' - if self.peer: - psk = st.get_socket(self.peer, True) - dsc += '-C%s' % sock.name_of(psk) - if self.icons: - i_dsc = '' - for c in self.icons: - psk = st.get_socket(c) - psk = st.get_socket(psk.peer, True) - i_dsc += sock.name_of(psk) - dsc += '-I%s' % i_dsc - if self.inqueue: - froms = set() - for m in self.inqueue: - froms.add(m[0]) - q_dsc = '' - for f in froms: - fsk = st.get_socket(f, True) - q_dsc += sock.name_of(fsk) - dsc += '-M%s' % q_dsc - return dsc + if self.listen: + dsc += 'L' + if self.peer: + psk = st.get_socket(self.peer, True) + dsc += '-C%s' % sock.name_of(psk) + if self.icons: + i_dsc = '' + for c in self.icons: + psk = st.get_socket(c) + psk = st.get_socket(psk.peer, True) + i_dsc += sock.name_of(psk) + dsc += '-I%s' % i_dsc + if self.inqueue: + froms = set() + for m in self.inqueue: + froms.add(m[0]) + q_dsc = '' + for f in froms: + fsk = st.get_socket(f, True) + q_dsc += sock.name_of(fsk) + dsc += '-M%s' % q_dsc + return dsc class state: - def __init__(self, max_sockets, sk_type): - self.sockets = [] - self.sk_id = 0 - self.steps = [] - self.real_sockets = {} - self.sockets_left = max_sockets - self.sk_type = sk_type + def __init__(self, max_sockets, sk_type): + self.sockets = [] + self.sk_id = 0 + self.steps = [] + self.real_sockets = {} + self.sockets_left = max_sockets + self.sk_type = sk_type - def add_socket(self, sk): - self.sockets.append(sk) + def add_socket(self, sk): + self.sockets.append(sk) - def del_socket(self, sk): - self.sockets.remove(sk) + def del_socket(self, sk): + self.sockets.remove(sk) - def get_socket(self, sk_id, can_be_null = False): - for sk in self.sockets: - if sk.sk_id == sk_id: - return sk + def get_socket(self, sk_id, can_be_null=False): + for sk in self.sockets: + if sk.sk_id == sk_id: + return sk - if not can_be_null: - raise Exception("%d socket not in list" % sk_id) + if not can_be_null: + raise Exception("%d socket not in list" % sk_id) - return None + return None - def get_actions(self): - act_list = [] + def get_actions(self): + act_list = [] - # Any socket in the state we can change it - for sk in self.sockets: - act_list += sk.get_actions(self) + # Any socket in the state we can change it + for sk in self.sockets: + act_list += sk.get_actions(self) - if self.sockets_left > 0: - act_list.append(act_socket(self.sk_type)) - self.sockets_left -= 1 + if self.sockets_left > 0: + act_list.append(act_socket(self.sk_type)) + self.sockets_left -= 1 - return act_list + return act_list - def clone(self): - nst = state(self.sockets_left, self.sk_type) - for sk in self.sockets: - nst.sockets.append(sk.clone()) - nst.sk_id = self.sk_id - nst.steps = list(self.steps) - return nst + def clone(self): + nst = state(self.sockets_left, self.sk_type) + for sk in self.sockets: + nst.sockets.append(sk.clone()) + nst.sk_id = self.sk_id + nst.steps = list(self.steps) + return nst - # Generates textual description of a state. Different states - # may have same descriptions, e.g. if we have two sockets and - # only one of them is in listen state, we don't care which - # one in which. At the same time really different states - # shouldn't map to the same string. - def describe(self): - sks = [x.describe(self) for x in self.sockets] - sks = sorted(sks) - return '_'.join(sks) + # Generates textual description of a state. Different states + # may have same descriptions, e.g. if we have two sockets and + # only one of them is in listen state, we don't care which + # one in which. At the same time really different states + # shouldn't map to the same string. + def describe(self): + sks = [x.describe(self) for x in self.sockets] + sks = sorted(sks) + return '_'.join(sks) def set_nonblock(sk): - fd = sk.fileno() - flags = fcntl.fcntl(fd, fcntl.F_GETFL) - fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) + fd = sk.fileno() + flags = fcntl.fcntl(fd, fcntl.F_GETFL) + fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) -CHK_FAIL_UNKNOWN = 10 -CHK_FAIL_SOCKET = 11 -CHK_FAIL_STAT = 12 -CHK_FAIL_LISTEN = 13 -CHK_FAIL_NAME = 14 -CHK_FAIL_ACCEPT = 15 -CHK_FAIL_RECV_0 = 16 -CHK_FAIL_RECV_MIX = 17 -CHK_FAIL_CONNECT = 18 -CHK_FAIL_CONNECT2 = 19 -CHK_FAIL_KILLED = 20 -CHK_FAIL_DUMP = 21 -CHK_FAIL_RESTORE = 22 -CHK_PASS = 42 +CHK_FAIL_UNKNOWN = 10 +CHK_FAIL_SOCKET = 11 +CHK_FAIL_STAT = 12 +CHK_FAIL_LISTEN = 13 +CHK_FAIL_NAME = 14 +CHK_FAIL_ACCEPT = 15 +CHK_FAIL_RECV_0 = 16 +CHK_FAIL_RECV_MIX = 17 +CHK_FAIL_CONNECT = 18 +CHK_FAIL_CONNECT2 = 19 +CHK_FAIL_KILLED = 20 +CHK_FAIL_DUMP = 21 +CHK_FAIL_RESTORE = 22 + +CHK_PASS = 42 fail_desc = { - CHK_FAIL_UNKNOWN: 'Aliens invaded the test', - CHK_FAIL_LISTEN: 'Listen state lost on restore', - CHK_FAIL_NAME: 'Name lost on restore', - CHK_FAIL_ACCEPT: 'Incoming connection lost on restore', - CHK_FAIL_RECV_0: 'Message lost on restore', - CHK_FAIL_RECV_MIX: 'Message misorder on restore', - CHK_FAIL_CONNECT: 'Connectivity broken on restore', - CHK_FAIL_CONNECT2: 'Connectivity broken the hard way on restore', - CHK_FAIL_KILLED: 'Test process died unexpectedly', - CHK_FAIL_DUMP: 'Cannot dump', - CHK_FAIL_RESTORE: 'Cannot restore', + CHK_FAIL_UNKNOWN: 'Aliens invaded the test', + CHK_FAIL_LISTEN: 'Listen state lost on restore', + CHK_FAIL_NAME: 'Name lost on restore', + CHK_FAIL_ACCEPT: 'Incoming connection lost on restore', + CHK_FAIL_RECV_0: 'Message lost on restore', + CHK_FAIL_RECV_MIX: 'Message misorder on restore', + CHK_FAIL_CONNECT: 'Connectivity broken on restore', + CHK_FAIL_CONNECT2: 'Connectivity broken the hard way on restore', + CHK_FAIL_KILLED: 'Test process died unexpectedly', + CHK_FAIL_DUMP: 'Cannot dump', + CHK_FAIL_RESTORE: 'Cannot restore', } + def chk_real_state(st): - # Before enything else -- check that we still have - # all the sockets at hands - for sk in st.sockets: - if not sk.visible: - continue + # Before enything else -- check that we still have + # all the sockets at hands + for sk in st.sockets: + if not sk.visible: + continue - # In theory we can have key-not-found exception here, - # but this has nothing to do with sockets restore, - # since it's just bytes in memory, so ... we assume - # that we have object here and just check for it in - # the fdtable - rsk = st.real_sockets[sk.sk_id] - try: - s_st = os.fstat(rsk.fileno()) - except: - print('FAIL: Socket %d lost' % sk.sk_id) - return CHK_FAIL_SOCKET - if not stat.S_ISSOCK(s_st.st_mode): - print('FAIL: Not a socket %d at %d' % (sk.sk_id, rsk.fileno())) - return CHK_FAIL_STAT + # In theory we can have key-not-found exception here, + # but this has nothing to do with sockets restore, + # since it's just bytes in memory, so ... we assume + # that we have object here and just check for it in + # the fdtable + rsk = st.real_sockets[sk.sk_id] + try: + s_st = os.fstat(rsk.fileno()) + except: + print('FAIL: Socket %d lost' % sk.sk_id) + return CHK_FAIL_SOCKET + if not stat.S_ISSOCK(s_st.st_mode): + print('FAIL: Not a socket %d at %d' % (sk.sk_id, rsk.fileno())) + return CHK_FAIL_STAT - # First -- check the listen states and names - for sk in st.sockets: - if not sk.visible: - continue + # First -- check the listen states and names + for sk in st.sockets: + if not sk.visible: + continue - rsk = st.real_sockets[sk.sk_id] - r_listen = rsk.getsockopt(socket.SOL_SOCKET, socket.SO_ACCEPTCONN) - if (sk.listen and r_listen == 0) or (not sk.listen and r_listen == 1): - print("FAIL: Socket %d listen %d, expected %d" - % (sk.sk_id, r_listen, sk.listen and 1 or 0)) - return CHK_FAIL_LISTEN + rsk = st.real_sockets[sk.sk_id] + r_listen = rsk.getsockopt(socket.SOL_SOCKET, socket.SO_ACCEPTCONN) + if (sk.listen and r_listen == 0) or (not sk.listen and r_listen == 1): + print("FAIL: Socket %d listen %d, expected %d" % + (sk.sk_id, r_listen, sk.listen and 1 or 0)) + return CHK_FAIL_LISTEN - if sk.name: - r_name = rsk.getsockname() - w_name = sock.real_name_for(sk.name) - if r_name != w_name: - print('FAIL: Socket %d name mismatch [%s], want [%s]' - % (sk.sk_id, r_name, w_name)) - return CHK_FAIL_NAME + if sk.name: + r_name = rsk.getsockname() + w_name = sock.real_name_for(sk.name) + if r_name != w_name: + print('FAIL: Socket %d name mismatch [%s], want [%s]' % + (sk.sk_id, r_name, w_name)) + return CHK_FAIL_NAME - # Second -- check (accept) pending connections - for sk in st.sockets: - if not sk.listen: - continue + # Second -- check (accept) pending connections + for sk in st.sockets: + if not sk.listen: + continue - rsk = st.real_sockets[sk.sk_id] - set_nonblock(rsk) + rsk = st.real_sockets[sk.sk_id] + set_nonblock(rsk) - while sk.icons: - # Do act_accept to change the state properly - # and not write the code twice - acc = act_accept(sk.sk_id) - acc.act(st) - try: - acc.do(st) - except: - print('FAIL: Cannot accept pending connection for %d' % sk.sk_id) - return CHK_FAIL_ACCEPT + while sk.icons: + # Do act_accept to change the state properly + # and not write the code twice + acc = act_accept(sk.sk_id) + acc.act(st) + try: + acc.do(st) + except: + print('FAIL: Cannot accept pending connection for %d' % + sk.sk_id) + return CHK_FAIL_ACCEPT - print(' `- did %s' % acc.show()) + print(' `- did %s' % acc.show()) - # Third -- check inqueues - for sk in st.sockets: - if not sk.inqueue: - continue + # Third -- check inqueues + for sk in st.sockets: + if not sk.inqueue: + continue - rsk = st.real_sockets[sk.sk_id] - set_nonblock(rsk) + rsk = st.real_sockets[sk.sk_id] + set_nonblock(rsk) - while sk.inqueue: - msg = sk.inqueue.pop(0) - try: - r_msg, m_from = rsk.recvfrom(128) - except: - print('FAIL: No message in queue for %d' % sk.sk_id) - return CHK_FAIL_RECV_0 + while sk.inqueue: + msg = sk.inqueue.pop(0) + try: + r_msg, m_from = rsk.recvfrom(128) + except: + print('FAIL: No message in queue for %d' % sk.sk_id) + return CHK_FAIL_RECV_0 - w_msg = act_sendmsg.msgval(msg[1]) - if r_msg != w_msg: - print('FAIL: Message misorder: %s want %s (from %d)' - %(r_msg, w_msg, msg[0])) - return CHK_FAIL_RECV_MIX + w_msg = act_sendmsg.msgval(msg[1]) + if r_msg != w_msg: + print('FAIL: Message misorder: %s want %s (from %d)' % + (r_msg, w_msg, msg[0])) + return CHK_FAIL_RECV_MIX - # TODO -- check sender - print(' `- recvd %d.%d msg %s -> %d' - % (msg[0], msg[1], m_from, sk.sk_id)) + # TODO -- check sender + print(' `- recvd %d.%d msg %s -> %d' % + (msg[0], msg[1], m_from, sk.sk_id)) - # Finally, after all sockets are visible and all inqueues are - # drained -- check the sockets connectivity - for sk in st.sockets: - if not sk.peer: - continue + # Finally, after all sockets are visible and all inqueues are + # drained -- check the sockets connectivity + for sk in st.sockets: + if not sk.peer: + continue - # Closed connection with one peer alive. Cannot check. - if not sk.peer in st.real_sockets: - continue + # Closed connection with one peer alive. Cannot check. + if not sk.peer in st.real_sockets: + continue - rsk = st.real_sockets[sk.sk_id] - psk = st.real_sockets[sk.peer] - set_nonblock(psk) - msgv = act_sendmsg.msgval(3 * sk.sk_id + 5 * sk.peer, 'C') # just random + rsk = st.real_sockets[sk.sk_id] + psk = st.real_sockets[sk.peer] + set_nonblock(psk) + msgv = act_sendmsg.msgval(3 * sk.sk_id + 5 * sk.peer, + 'C') # just random - try: - rsk.send(msgv) - rmsg = psk.recv(128) - except: - print('FAIL: Connectivity %d -> %d lost' % (sk.sk_id, sk.peer)) - return CHK_FAIL_CONNECT + try: + rsk.send(msgv) + rmsg = psk.recv(128) + except: + print('FAIL: Connectivity %d -> %d lost' % (sk.sk_id, sk.peer)) + return CHK_FAIL_CONNECT - # If sockets are not connected the recv above - # would generate exception and the check would - # fail. But just in case we've screwed the queues - # the hard way -- also check for the message being - # delivered for real - if rmsg != msgv: - print('FAIL: Connectivity %d -> %d not verified' - % (sk.sk_id, sk.peer)) - return CHK_FAIL_CONNECT2 + # If sockets are not connected the recv above + # would generate exception and the check would + # fail. But just in case we've screwed the queues + # the hard way -- also check for the message being + # delivered for real + if rmsg != msgv: + print('FAIL: Connectivity %d -> %d not verified' % + (sk.sk_id, sk.peer)) + return CHK_FAIL_CONNECT2 - print(' `- checked %d -> %d with %s' % (sk.sk_id, sk.peer, msgv)) + print(' `- checked %d -> %d with %s' % (sk.sk_id, sk.peer, msgv)) - return CHK_PASS + return CHK_PASS def chk_state(st, opts): - print("Will check state") + print("Will check state") - sigsk_name = "\0" + "CRSIGSKC" - signal_sk = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) - signal_sk.bind(sigsk_name) + sigsk_name = "\0" + "CRSIGSKC" + signal_sk = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) + signal_sk.bind(sigsk_name) - # FIXME Ideally call to criu should be performed by the run_state's - # pid!=0 branch, but for simplicity we fork the kid which has the - # same set of sockets we do, then dump it. Then restore and notify - # via dgram socket to check its state. Current task still has all - # the same sockets :) so we close them not to produce bind() name - # conflicts on restore + # FIXME Ideally call to criu should be performed by the run_state's + # pid!=0 branch, but for simplicity we fork the kid which has the + # same set of sockets we do, then dump it. Then restore and notify + # via dgram socket to check its state. Current task still has all + # the same sockets :) so we close them not to produce bind() name + # conflicts on restore - pid = os.fork() - if pid == 0: - msg = signal_sk.recv(64) - ret = chk_real_state(st) - sys.exit(ret) + pid = os.fork() + if pid == 0: + msg = signal_sk.recv(64) + ret = chk_real_state(st) + sys.exit(ret) - signal_sk.close() - for rsk in st.real_sockets.values(): - rsk.close() + signal_sk.close() + for rsk in st.real_sockets.values(): + rsk.close() - print("`- dump") - img_path = "sti_" + st.describe() - try: - os.mkdir(img_path) - subprocess.check_call([criu_bin, "dump", "-t", "%d" % pid, "-D", img_path, "-v4", "-o", "dump.log", "-j"]) - except: - print("Dump failed") - os.kill(pid, signal.SIGKILL) - return CHK_FAIL_DUMP + print("`- dump") + img_path = "sti_" + st.describe() + try: + os.mkdir(img_path) + subprocess.check_call([ + criu_bin, "dump", "-t", + "%d" % pid, "-D", img_path, "-v4", "-o", "dump.log", "-j" + ]) + except: + print("Dump failed") + os.kill(pid, signal.SIGKILL) + return CHK_FAIL_DUMP - print("`- restore") - try: - os.waitpid(pid, 0) - subprocess.check_call([criu_bin, "restore", "-D", img_path, "-v4", "-o", "rst.log", "-j", "-d", "-S"]) - except: - print("Restore failed") - return CHK_FAIL_RESTORE + print("`- restore") + try: + os.waitpid(pid, 0) + subprocess.check_call([ + criu_bin, "restore", "-D", img_path, "-v4", "-o", "rst.log", "-j", + "-d", "-S" + ]) + except: + print("Restore failed") + return CHK_FAIL_RESTORE - print("`- check") - signal_sk = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) - try: - signal_sk.sendto('check', sigsk_name) - except: - # Probably the peer has died before us or smth else went wrong - os.kill(pid, signal.SIGKILL) + print("`- check") + signal_sk = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) + try: + signal_sk.sendto('check', sigsk_name) + except: + # Probably the peer has died before us or smth else went wrong + os.kill(pid, signal.SIGKILL) - wp, status = os.waitpid(pid, 0) - if os.WIFEXITED(status): - status = os.WEXITSTATUS(status) - if status != CHK_PASS: - print("`- exited with %d" % status) - return status - elif os.WIFSIGNALED(status): - status = os.WTERMSIG(status) - print("`- killed with %d" % status) - return CHK_FAIL_KILLED - else: - return CHK_FAIL_UNKNOWN + wp, status = os.waitpid(pid, 0) + if os.WIFEXITED(status): + status = os.WEXITSTATUS(status) + if status != CHK_PASS: + print("`- exited with %d" % status) + return status + elif os.WIFSIGNALED(status): + status = os.WTERMSIG(status) + print("`- killed with %d" % status) + return CHK_FAIL_KILLED + else: + return CHK_FAIL_UNKNOWN - return CHK_PASS + return CHK_PASS def run_state(st, opts): - print("Will run state") - pid = os.fork() - if pid != 0: - wpid, status = os.wait() - if os.WIFEXITED(status): - status = os.WEXITSTATUS(status) - elif os.WIFSIGNALED(status): - status = CHK_FAIL_KILLED - else: - status = CHK_FAIL_UNKNOWN - return status + print("Will run state") + pid = os.fork() + if pid != 0: + wpid, status = os.wait() + if os.WIFEXITED(status): + status = os.WEXITSTATUS(status) + elif os.WIFSIGNALED(status): + status = CHK_FAIL_KILLED + else: + status = CHK_FAIL_UNKNOWN + return status - # Try the states in subprocess so that once - # it exits the created sockets are removed - for step in st.steps: - step.do(st) + # Try the states in subprocess so that once + # it exits the created sockets are removed + for step in st.steps: + step.do(st) - if not opts.run: - ret = chk_state(st, opts) - else: - ret = chk_real_state(st) + if not opts.run: + ret = chk_state(st, opts) + else: + ret = chk_real_state(st) - sys.exit(ret) + sys.exit(ret) -def proceed(st, seen, failed, opts, depth = 0): - desc = st.describe() - if not desc: - pass - elif not desc in seen: - # When scanning the tree we run and try only states that - # differ, but don't stop tree traversal on them. This is - # because sometimes we can get into the already seen state - # using less steps and it's better to proceed as we have - # depth to move forward and generate more states. - seen[desc] = len(st.steps) - print('%s' % desc) - for s in st.steps: - print('\t%s' % s.show()) +def proceed(st, seen, failed, opts, depth=0): + desc = st.describe() + if not desc: + pass + elif not desc in seen: + # When scanning the tree we run and try only states that + # differ, but don't stop tree traversal on them. This is + # because sometimes we can get into the already seen state + # using less steps and it's better to proceed as we have + # depth to move forward and generate more states. + seen[desc] = len(st.steps) + print('%s' % desc) + for s in st.steps: + print('\t%s' % s.show()) - if not opts.gen: - ret = run_state(st, opts) - if ret != CHK_PASS: - failed.add((desc, ret)) - if not opts.keep: - return False - else: - # Don't even proceed with this state if we've already - # seen one but get there with less steps - seen_score = seen[desc] - if len(st.steps) > seen_score: - return True - else: - seen[desc] = len(st.steps) + if not opts.gen: + ret = run_state(st, opts) + if ret != CHK_PASS: + failed.add((desc, ret)) + if not opts.keep: + return False + else: + # Don't even proceed with this state if we've already + # seen one but get there with less steps + seen_score = seen[desc] + if len(st.steps) > seen_score: + return True + else: + seen[desc] = len(st.steps) - if depth >= opts.depth: - return True + if depth >= opts.depth: + return True - actions = st.get_actions() - for act in actions: - nst = st.clone() - act.act(nst) - nst.steps.append(act) - if not proceed(nst, seen, failed, opts, depth + 1): - return False + actions = st.get_actions() + for act in actions: + nst = st.clone() + act.act(nst) + nst.steps.append(act) + if not proceed(nst, seen, failed, opts, depth + 1): + return False - return True + return True p = argparse.ArgumentParser("CRIU test suite") -p.add_argument("--depth", help = "Depth of generated tree", default = '8') -p.add_argument("--sockets", help = "Maximum number of sockets", default = '1') -p.add_argument("--dgram", help = "Use SOCK_DGRAM sockets", action = 'store_true') -p.add_argument("--stream", help = "Use SOCK_STREAM sockets", action = 'store_true') -p.add_argument("--gen", help = "Only generate and show states", action = 'store_true') -p.add_argument("--run", help = "Run the states, but don't C/R", action = 'store_true') -p.add_argument("--keep", help = "Don't stop on error", action = 'store_true') +p.add_argument("--depth", help="Depth of generated tree", default='8') +p.add_argument("--sockets", help="Maximum number of sockets", default='1') +p.add_argument("--dgram", help="Use SOCK_DGRAM sockets", action='store_true') +p.add_argument("--stream", help="Use SOCK_STREAM sockets", action='store_true') +p.add_argument("--gen", + help="Only generate and show states", + action='store_true') +p.add_argument("--run", + help="Run the states, but don't C/R", + action='store_true') +p.add_argument("--keep", help="Don't stop on error", action='store_true') opts = p.parse_args() opts.depth = int(opts.depth) # XXX: does it make any sense to mix two types in one go? if opts.stream and opts.dgram: - print('Choose only one type') - sys.exit(1) + print('Choose only one type') + sys.exit(1) if opts.stream: - sk_type = socket.SOCK_STREAM + sk_type = socket.SOCK_STREAM elif opts.dgram: - sk_type = socket.SOCK_DGRAM + sk_type = socket.SOCK_DGRAM else: - print('Choose some type') - sys.exit(1) + print('Choose some type') + sys.exit(1) st = state(int(opts.sockets), sk_type) seen = {} @@ -747,8 +765,9 @@ failed = set() proceed(st, seen, failed, opts) if len(failed) == 0: - print('PASS (%d states)' % len(seen)) + print('PASS (%d states)' % len(seen)) else: - print('FAIL %d/%d' % (len(failed), len(seen))) - for f in failed: - print("\t%-50s: %s" % (f[0], fail_desc.get(f[1], 'unknown reason %d' % f[1]))) + print('FAIL %d/%d' % (len(failed), len(seen))) + for f in failed: + print("\t%-50s: %s" % + (f[0], fail_desc.get(f[1], 'unknown reason %d' % f[1]))) diff --git a/test/inhfd/fifo.py b/test/inhfd/fifo.py index 64e5f8f13..2d20e4dbf 100755 --- a/test/inhfd/fifo.py +++ b/test/inhfd/fifo.py @@ -5,35 +5,35 @@ id_str = "" def create_fds(): - tdir = tempfile.mkdtemp("zdtm.inhfd.XXXXXX") - if os.system("mount -t tmpfs zdtm.inhfd %s" % tdir) != 0: - raise Exception("Unable to mount tmpfs") - tfifo = os.path.join(tdir, "test_fifo") - os.mkfifo(tfifo) - fd2 = open(tfifo, "w+b", buffering=0) - fd1 = open(tfifo, "rb") - os.system("umount -l %s" % tdir) - os.rmdir(tdir) + tdir = tempfile.mkdtemp("zdtm.inhfd.XXXXXX") + if os.system("mount -t tmpfs zdtm.inhfd %s" % tdir) != 0: + raise Exception("Unable to mount tmpfs") + tfifo = os.path.join(tdir, "test_fifo") + os.mkfifo(tfifo) + fd2 = open(tfifo, "w+b", buffering=0) + fd1 = open(tfifo, "rb") + os.system("umount -l %s" % tdir) + os.rmdir(tdir) - mnt_id = -1 - with open("/proc/self/fdinfo/%d" % fd1.fileno()) as f: - for line in f: - line = line.split() - if line[0] == "mnt_id:": - mnt_id = int(line[1]) - break - else: - raise Exception("Unable to find mnt_id") + mnt_id = -1 + with open("/proc/self/fdinfo/%d" % fd1.fileno()) as f: + for line in f: + line = line.split() + if line[0] == "mnt_id:": + mnt_id = int(line[1]) + break + else: + raise Exception("Unable to find mnt_id") - global id_str - id_str = "file[%x:%x]" % (mnt_id, os.fstat(fd1.fileno()).st_ino) + global id_str + id_str = "file[%x:%x]" % (mnt_id, os.fstat(fd1.fileno()).st_ino) - return [(fd2, fd1)] + return [(fd2, fd1)] def filename(pipef): - return id_str + return id_str def dump_opts(sockf): - return ["--external", id_str] + return ["--external", id_str] diff --git a/test/inhfd/pipe.py b/test/inhfd/pipe.py index 318dc862d..8d8318d5b 100755 --- a/test/inhfd/pipe.py +++ b/test/inhfd/pipe.py @@ -2,16 +2,16 @@ import os def create_fds(): - pipes = [] - for i in range(10): - (fd1, fd2) = os.pipe() - pipes.append((os.fdopen(fd2, "wb"), os.fdopen(fd1, "rb"))) - return pipes + pipes = [] + for i in range(10): + (fd1, fd2) = os.pipe() + pipes.append((os.fdopen(fd2, "wb"), os.fdopen(fd1, "rb"))) + return pipes def filename(pipef): - return 'pipe:[%d]' % os.fstat(pipef.fileno()).st_ino + return 'pipe:[%d]' % os.fstat(pipef.fileno()).st_ino def dump_opts(sockf): - return [] + return [] diff --git a/test/inhfd/socket.py b/test/inhfd/socket.py index feba0e0c6..9cea16ffb 100755 --- a/test/inhfd/socket.py +++ b/test/inhfd/socket.py @@ -3,19 +3,19 @@ import os def create_fds(): - (sk1, sk2) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM) - (sk3, sk4) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM) - return [(sk1.makefile("wb"), sk2.makefile("rb")), - (sk3.makefile("wb"), sk4.makefile("rb"))] + (sk1, sk2) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM) + (sk3, sk4) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM) + return [(sk1.makefile("wb"), sk2.makefile("rb")), + (sk3.makefile("wb"), sk4.makefile("rb"))] def __sock_ino(sockf): - return os.fstat(sockf.fileno()).st_ino + return os.fstat(sockf.fileno()).st_ino def filename(sockf): - return 'socket:[%d]' % __sock_ino(sockf) + return 'socket:[%d]' % __sock_ino(sockf) def dump_opts(sockf): - return ['--external', 'unix[%d]' % __sock_ino(sockf)] + return ['--external', 'unix[%d]' % __sock_ino(sockf)] diff --git a/test/inhfd/tty.py b/test/inhfd/tty.py index ae76a96d4..c11a57117 100755 --- a/test/inhfd/tty.py +++ b/test/inhfd/tty.py @@ -4,34 +4,33 @@ import os import pty import termios - ctl = False def child_prep(fd): - global ctl - if ctl: - return - ctl = True - fcntl.ioctl(fd.fileno(), termios.TIOCSCTTY, 1) + global ctl + if ctl: + return + ctl = True + fcntl.ioctl(fd.fileno(), termios.TIOCSCTTY, 1) def create_fds(): - ttys = [] - for i in range(10): - (fd1, fd2) = pty.openpty() - newattr = termios.tcgetattr(fd1) - newattr[3] &= ~termios.ICANON & ~termios.ECHO - termios.tcsetattr(fd1, termios.TCSADRAIN, newattr) - ttys.append((os.fdopen(fd1, "wb"), os.fdopen(fd2, "rb"))) - return ttys + ttys = [] + for i in range(10): + (fd1, fd2) = pty.openpty() + newattr = termios.tcgetattr(fd1) + newattr[3] &= ~termios.ICANON & ~termios.ECHO + termios.tcsetattr(fd1, termios.TCSADRAIN, newattr) + ttys.append((os.fdopen(fd1, "wb"), os.fdopen(fd2, "rb"))) + return ttys def filename(pipef): - st = os.fstat(pipef.fileno()) - return 'tty[%x:%x]' % (st.st_rdev, st.st_dev) + st = os.fstat(pipef.fileno()) + return 'tty[%x:%x]' % (st.st_rdev, st.st_dev) def dump_opts(sockf): - st = os.fstat(sockf.fileno()) - return "--external", 'tty[%x:%x]' % (st.st_rdev, st.st_dev) + st = os.fstat(sockf.fileno()) + return "--external", 'tty[%x:%x]' % (st.st_rdev, st.st_dev) diff --git a/test/others/ext-tty/run.py b/test/others/ext-tty/run.py index f44b1d946..b1dcb4a5a 100755 --- a/test/others/ext-tty/run.py +++ b/test/others/ext-tty/run.py @@ -5,32 +5,41 @@ import os, sys, time, signal, pty master, slave = pty.openpty() p = subprocess.Popen(["setsid", "--ctty", "sleep", "10000"], - stdin = slave, stdout = slave, stderr = slave, close_fds = True) + stdin=slave, + stdout=slave, + stderr=slave, + close_fds=True) st = os.stat("/proc/self/fd/%d" % slave) ttyid = "tty[%x:%x]" % (st.st_rdev, st.st_dev) os.close(slave) time.sleep(1) -ret = subprocess.Popen(["../../../criu/criu", "dump", "-t", str(p.pid), "-v4", "--external", ttyid]).wait() +ret = subprocess.Popen([ + "../../../criu/criu", "dump", "-t", + str(p.pid), "-v4", "--external", ttyid +]).wait() if ret: - sys.exit(ret) + sys.exit(ret) p.wait() -new_master, slave = pty.openpty() # get another pty pair +new_master, slave = pty.openpty() # get another pty pair os.close(master) ttyid = "fd[%d]:tty[%x:%x]" % (slave, st.st_rdev, st.st_dev) -ret = subprocess.Popen(["../../../criu/criu", "restore", "-v4", "--inherit-fd", ttyid, "--restore-sibling", "--restore-detach"]).wait() +ret = subprocess.Popen([ + "../../../criu/criu", "restore", "-v4", "--inherit-fd", ttyid, + "--restore-sibling", "--restore-detach" +]).wait() if ret: - sys.exit(ret) + sys.exit(ret) os.close(slave) -os.waitpid(-1, os.WNOHANG) # is the process alive +os.waitpid(-1, os.WNOHANG) # is the process alive os.close(new_master) _, status = os.wait() if not os.WIFSIGNALED(status) or os.WTERMSIG(status) != signal.SIGHUP: - print(status) - sys.exit(1) + print(status) + sys.exit(1) print("PASS") diff --git a/test/others/mounts/mounts.py b/test/others/mounts/mounts.py index dc65ba45c..70b0be5fa 100755 --- a/test/others/mounts/mounts.py +++ b/test/others/mounts/mounts.py @@ -1,31 +1,36 @@ import os import tempfile, random + def mount(src, dst, shared, private, slave): - cmd = "mount" - if shared: - cmd += " --make-shared" - if private: - cmd += " --make-private" - if slave: - cmd += " --make-slave" - if src: - cmd += " --bind '%s' '%s'" % (src, dst) - else: - cmd += " -t tmpfs none '%s'" % (dst) + cmd = "mount" + if shared: + cmd += " --make-shared" + if private: + cmd += " --make-private" + if slave: + cmd += " --make-slave" + if src: + cmd += " --bind '%s' '%s'" % (src, dst) + else: + cmd += " -t tmpfs none '%s'" % (dst) - print(cmd) - ret = os.system(cmd) - if ret: - print("failed") + print(cmd) + ret = os.system(cmd) + if ret: + print("failed") -root = tempfile.mkdtemp(prefix = "root.mount", dir = "/tmp") + +root = tempfile.mkdtemp(prefix="root.mount", dir="/tmp") mount(None, root, 1, 0, 0) mounts = [root] for i in range(10): - dstdir = random.choice(mounts) - dst = tempfile.mkdtemp(prefix = "mount", dir = dstdir) - src = random.choice(mounts + [None]) - mount(src, dst, random.randint(0,100) > 50, random.randint(0,100) > 90, random.randint(0,100) > 50) - mounts.append(dst) + dstdir = random.choice(mounts) + dst = tempfile.mkdtemp(prefix="mount", dir=dstdir) + src = random.choice(mounts + [None]) + mount(src, dst, + random.randint(0, 100) > 50, + random.randint(0, 100) > 90, + random.randint(0, 100) > 50) + mounts.append(dst) diff --git a/test/others/rpc/config_file.py b/test/others/rpc/config_file.py index 23a06615f..3579ac76f 100755 --- a/test/others/rpc/config_file.py +++ b/test/others/rpc/config_file.py @@ -14,169 +14,174 @@ does_not_exist = 'does-not.exist' def setup_swrk(): - print('Connecting to CRIU in swrk mode.') - css = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) - swrk = subprocess.Popen(['./criu', "swrk", "%d" % css[0].fileno()]) - css[0].close() - return swrk, css[1] + print('Connecting to CRIU in swrk mode.') + css = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) + swrk = subprocess.Popen(['./criu', "swrk", "%d" % css[0].fileno()]) + css[0].close() + return swrk, css[1] def setup_config_file(content): - # Creating a temporary file which will be used as configuration file. - fd, path = mkstemp() + # Creating a temporary file which will be used as configuration file. + fd, path = mkstemp() - with os.fdopen(fd, 'w') as f: - f.write(content) + with os.fdopen(fd, 'w') as f: + f.write(content) - os.environ['CRIU_CONFIG_FILE'] = path + os.environ['CRIU_CONFIG_FILE'] = path - return path + return path def cleanup_config_file(path): - if os.environ.get('CRIU_CONFIG_FILE', None) is not None: - del os.environ['CRIU_CONFIG_FILE'] - os.unlink(path) + if os.environ.get('CRIU_CONFIG_FILE', None) is not None: + del os.environ['CRIU_CONFIG_FILE'] + os.unlink(path) def cleanup_output(path): - for f in (does_not_exist, log_file): - f = os.path.join(path, f) - if os.access(f, os.F_OK): - os.unlink(f) + for f in (does_not_exist, log_file): + f = os.path.join(path, f) + if os.access(f, os.F_OK): + os.unlink(f) def setup_criu_dump_request(): - # Create criu msg, set it's type to dump request - # and set dump options. Checkout more options in protobuf/rpc.proto - req = rpc.criu_req() - req.type = rpc.DUMP - req.opts.leave_running = True - req.opts.log_level = 4 - req.opts.log_file = log_file - req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY) - # Not necessary, just for testing - req.opts.tcp_established = True - req.opts.shell_job = True - return req + # Create criu msg, set it's type to dump request + # and set dump options. Checkout more options in protobuf/rpc.proto + req = rpc.criu_req() + req.type = rpc.DUMP + req.opts.leave_running = True + req.opts.log_level = 4 + req.opts.log_file = log_file + req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY) + # Not necessary, just for testing + req.opts.tcp_established = True + req.opts.shell_job = True + return req def do_rpc(s, req): - # Send request - s.send(req.SerializeToString()) + # Send request + s.send(req.SerializeToString()) - # Recv response - resp = rpc.criu_resp() - MAX_MSG_SIZE = 1024 - resp.ParseFromString(s.recv(MAX_MSG_SIZE)) + # Recv response + resp = rpc.criu_resp() + MAX_MSG_SIZE = 1024 + resp.ParseFromString(s.recv(MAX_MSG_SIZE)) - s.close() - return resp + s.close() + return resp def test_broken_configuration_file(): - # Testing RPC configuration file mode with a broken configuration file. - # This should fail - content = 'hopefully-this-option-will-never=exist' - path = setup_config_file(content) - swrk, s = setup_swrk() - s.close() - # This test is only about detecting wrong configuration files. - # If we do not sleep it might happen that we kill CRIU before - # it parses the configuration file. A short sleep makes sure - # that the configuration file has been parsed. Hopefully. - # (I am sure this will fail horribly at some point) - time.sleep(0.3) - swrk.kill() - return_code = swrk.wait() - # delete temporary file again - cleanup_config_file(path) - if return_code != 1: - print('FAIL: CRIU should have returned 1 instead of %d' % return_code) - sys.exit(-1) + # Testing RPC configuration file mode with a broken configuration file. + # This should fail + content = 'hopefully-this-option-will-never=exist' + path = setup_config_file(content) + swrk, s = setup_swrk() + s.close() + # This test is only about detecting wrong configuration files. + # If we do not sleep it might happen that we kill CRIU before + # it parses the configuration file. A short sleep makes sure + # that the configuration file has been parsed. Hopefully. + # (I am sure this will fail horribly at some point) + time.sleep(0.3) + swrk.kill() + return_code = swrk.wait() + # delete temporary file again + cleanup_config_file(path) + if return_code != 1: + print('FAIL: CRIU should have returned 1 instead of %d' % return_code) + sys.exit(-1) def search_in_log_file(log, message): - with open(os.path.join(args['dir'], log)) as f: - if message not in f.read(): - print('FAIL: Missing the expected error message (%s) in the log file' % message) - sys.exit(-1) + with open(os.path.join(args['dir'], log)) as f: + if message not in f.read(): + print( + 'FAIL: Missing the expected error message (%s) in the log file' + % message) + sys.exit(-1) def check_results(resp, log): - # Check if the specified log file exists - if not os.path.isfile(os.path.join(args['dir'], log)): - print('FAIL: Expected log file %s does not exist' % log) - sys.exit(-1) - # Dump should have failed with: 'The criu itself is within dumped tree' - if resp.type != rpc.DUMP: - print('FAIL: Unexpected msg type %r' % resp.type) - sys.exit(-1) - if 'The criu itself is within dumped tree' not in resp.cr_errmsg: - print('FAIL: Missing the expected error message in RPC response') - sys.exit(-1) - # Look into the log file for the same message - search_in_log_file(log, 'The criu itself is within dumped tree') + # Check if the specified log file exists + if not os.path.isfile(os.path.join(args['dir'], log)): + print('FAIL: Expected log file %s does not exist' % log) + sys.exit(-1) + # Dump should have failed with: 'The criu itself is within dumped tree' + if resp.type != rpc.DUMP: + print('FAIL: Unexpected msg type %r' % resp.type) + sys.exit(-1) + if 'The criu itself is within dumped tree' not in resp.cr_errmsg: + print('FAIL: Missing the expected error message in RPC response') + sys.exit(-1) + # Look into the log file for the same message + search_in_log_file(log, 'The criu itself is within dumped tree') def test_rpc_without_configuration_file(): - # Testing without configuration file - # Just doing a dump and checking for the logfile - req = setup_criu_dump_request() - _, s = setup_swrk() - resp = do_rpc(s, req) - s.close() - check_results(resp, log_file) + # Testing without configuration file + # Just doing a dump and checking for the logfile + req = setup_criu_dump_request() + _, s = setup_swrk() + resp = do_rpc(s, req) + s.close() + check_results(resp, log_file) def test_rpc_with_configuration_file(): - # Testing with configuration file - # Just doing a dump and checking for the logfile + # Testing with configuration file + # Just doing a dump and checking for the logfile - # Setting a different log file via configuration file - # This should not work as RPC settings overwrite configuration - # file settings in the default configuration. - log = does_not_exist - content = 'log-file ' + log + '\n' - content += 'no-tcp-established\nno-shell-job' - path = setup_config_file(content) - req = setup_criu_dump_request() - _, s = setup_swrk() - do_rpc(s, req) - s.close() - cleanup_config_file(path) - # Check if the specified log file exists - # It should not as configuration files do not overwrite RPC values. - if os.path.isfile(os.path.join(args['dir'], log)): - print('FAIL: log file %s should not exist' % log) - sys.exit(-1) + # Setting a different log file via configuration file + # This should not work as RPC settings overwrite configuration + # file settings in the default configuration. + log = does_not_exist + content = 'log-file ' + log + '\n' + content += 'no-tcp-established\nno-shell-job' + path = setup_config_file(content) + req = setup_criu_dump_request() + _, s = setup_swrk() + do_rpc(s, req) + s.close() + cleanup_config_file(path) + # Check if the specified log file exists + # It should not as configuration files do not overwrite RPC values. + if os.path.isfile(os.path.join(args['dir'], log)): + print('FAIL: log file %s should not exist' % log) + sys.exit(-1) def test_rpc_with_configuration_file_overwriting_rpc(): - # Testing with configuration file - # Just doing a dump and checking for the logfile + # Testing with configuration file + # Just doing a dump and checking for the logfile - # Setting a different log file via configuration file - # This should not work as RPC settings overwrite configuration - # file settings in the default configuration. - log = does_not_exist - content = 'log-file ' + log + '\n' - content += 'no-tcp-established\nno-shell-job' - path = setup_config_file(content) - # Only set the configuration file via RPC; - # not via environment variable - del os.environ['CRIU_CONFIG_FILE'] - req = setup_criu_dump_request() - req.opts.config_file = path - _, s = setup_swrk() - resp = do_rpc(s, req) - s.close() - cleanup_config_file(path) - check_results(resp, log) + # Setting a different log file via configuration file + # This should not work as RPC settings overwrite configuration + # file settings in the default configuration. + log = does_not_exist + content = 'log-file ' + log + '\n' + content += 'no-tcp-established\nno-shell-job' + path = setup_config_file(content) + # Only set the configuration file via RPC; + # not via environment variable + del os.environ['CRIU_CONFIG_FILE'] + req = setup_criu_dump_request() + req.opts.config_file = path + _, s = setup_swrk() + resp = do_rpc(s, req) + s.close() + cleanup_config_file(path) + check_results(resp, log) -parser = argparse.ArgumentParser(description="Test config files using CRIU RPC") -parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed") +parser = argparse.ArgumentParser( + description="Test config files using CRIU RPC") +parser.add_argument('dir', + type=str, + help="Directory where CRIU images should be placed") args = vars(parser.parse_args()) diff --git a/test/others/rpc/errno.py b/test/others/rpc/errno.py index ee9e90d8c..49cb622de 100755 --- a/test/others/rpc/errno.py +++ b/test/others/rpc/errno.py @@ -6,130 +6,136 @@ import rpc_pb2 as rpc import argparse parser = argparse.ArgumentParser(description="Test errno reported by CRIU RPC") -parser.add_argument('socket', type = str, help = "CRIU service socket") -parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed") +parser.add_argument('socket', type=str, help="CRIU service socket") +parser.add_argument('dir', + type=str, + help="Directory where CRIU images should be placed") args = vars(parser.parse_args()) + # Prepare dir for images class test: - def __init__(self): - self.imgs_fd = os.open(args['dir'], os.O_DIRECTORY) - self.s = -1 - self._MAX_MSG_SIZE = 1024 + def __init__(self): + self.imgs_fd = os.open(args['dir'], os.O_DIRECTORY) + self.s = -1 + self._MAX_MSG_SIZE = 1024 - def connect(self): - self.s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) - self.s.connect(args['socket']) + def connect(self): + self.s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) + self.s.connect(args['socket']) - def get_base_req(self): - req = rpc.criu_req() - req.opts.log_level = 4 - req.opts.images_dir_fd = self.imgs_fd - return req + def get_base_req(self): + req = rpc.criu_req() + req.opts.log_level = 4 + req.opts.images_dir_fd = self.imgs_fd + return req - def send_req(self, req): - self.connect() - self.s.send(req.SerializeToString()) + def send_req(self, req): + self.connect() + self.s.send(req.SerializeToString()) - def recv_resp(self): - resp = rpc.criu_resp() - resp.ParseFromString(self.s.recv(self._MAX_MSG_SIZE)) - return resp + def recv_resp(self): + resp = rpc.criu_resp() + resp.ParseFromString(self.s.recv(self._MAX_MSG_SIZE)) + return resp - def check_resp(self, resp, typ, err): - if resp.type != typ: - raise Exception('Unexpected responce type ' + str(resp.type)) + def check_resp(self, resp, typ, err): + if resp.type != typ: + raise Exception('Unexpected responce type ' + str(resp.type)) - if resp.success: - raise Exception('Unexpected success = True') + if resp.success: + raise Exception('Unexpected success = True') - if err and resp.cr_errno != err: - raise Exception('Unexpected cr_errno ' + str(resp.cr_errno)) + if err and resp.cr_errno != err: + raise Exception('Unexpected cr_errno ' + str(resp.cr_errno)) - def no_process(self): - print('Try to dump unexisting process') - # Get pid of non-existing process. - # Suppose max_pid is not taken by any process. - with open("/proc/sys/kernel/pid_max", "r") as f: - pid = int(f.readline()) - try: - os.kill(pid, 0) - except OSError: - pass - else: - raise Exception('max pid is taken') + def no_process(self): + print('Try to dump unexisting process') + # Get pid of non-existing process. + # Suppose max_pid is not taken by any process. + with open("/proc/sys/kernel/pid_max", "r") as f: + pid = int(f.readline()) + try: + os.kill(pid, 0) + except OSError: + pass + else: + raise Exception('max pid is taken') - # Ask criu to dump non-existing process. - req = self.get_base_req() - req.type = rpc.DUMP - req.opts.pid = pid + # Ask criu to dump non-existing process. + req = self.get_base_req() + req.type = rpc.DUMP + req.opts.pid = pid - self.send_req(req) - resp = self.recv_resp() + self.send_req(req) + resp = self.recv_resp() - self.check_resp(resp, rpc.DUMP, errno.ESRCH) + self.check_resp(resp, rpc.DUMP, errno.ESRCH) - print('Success') + print('Success') - def process_exists(self): - print('Try to restore process which pid is already taken by other process') + def process_exists(self): + print( + 'Try to restore process which pid is already taken by other process' + ) - # Perform self-dump - req = self.get_base_req() - req.type = rpc.DUMP - req.opts.leave_running = True + # Perform self-dump + req = self.get_base_req() + req.type = rpc.DUMP + req.opts.leave_running = True - self.send_req(req) - resp = self.recv_resp() + self.send_req(req) + resp = self.recv_resp() - if resp.success != True: - raise Exception('Self-dump failed') + if resp.success != True: + raise Exception('Self-dump failed') - # Ask to restore process from images of ourselves - req = self.get_base_req() - req.type = rpc.RESTORE + # Ask to restore process from images of ourselves + req = self.get_base_req() + req.type = rpc.RESTORE - self.send_req(req) - resp = self.recv_resp() + self.send_req(req) + resp = self.recv_resp() - self.check_resp(resp, rpc.RESTORE, errno.EEXIST) + self.check_resp(resp, rpc.RESTORE, errno.EEXIST) - print('Success') + print('Success') - def bad_options(self): - print('Try to send criu invalid opts') + def bad_options(self): + print('Try to send criu invalid opts') - # Subdirs are not allowed in log_file - req = self.get_base_req() - req.type = rpc.DUMP - req.opts.log_file = "../file.log" + # Subdirs are not allowed in log_file + req = self.get_base_req() + req.type = rpc.DUMP + req.opts.log_file = "../file.log" - self.send_req(req) - resp = self.recv_resp() + self.send_req(req) + resp = self.recv_resp() - self.check_resp(resp, rpc.DUMP, errno.EBADRQC) + self.check_resp(resp, rpc.DUMP, errno.EBADRQC) - print('Success') + print('Success') - def bad_request(self): - print('Try to send criu invalid request type') + def bad_request(self): + print('Try to send criu invalid request type') - req = self.get_base_req() - req.type = rpc.NOTIFY + req = self.get_base_req() + req.type = rpc.NOTIFY - self.send_req(req) - resp = self.recv_resp() + self.send_req(req) + resp = self.recv_resp() - self.check_resp(resp, rpc.EMPTY, None) + self.check_resp(resp, rpc.EMPTY, None) - print('Success') + print('Success') + + def run(self): + self.no_process() + self.process_exists() + self.bad_options() + self.bad_request() - def run(self): - self.no_process() - self.process_exists() - self.bad_options() - self.bad_request() t = test() t.run() diff --git a/test/others/rpc/ps_test.py b/test/others/rpc/ps_test.py index 1872120fc..d16efd3f6 100755 --- a/test/others/rpc/ps_test.py +++ b/test/others/rpc/ps_test.py @@ -5,8 +5,10 @@ import rpc_pb2 as rpc import argparse parser = argparse.ArgumentParser(description="Test page-server using CRIU RPC") -parser.add_argument('socket', type = str, help = "CRIU service socket") -parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed") +parser.add_argument('socket', type=str, help="CRIU service socket") +parser.add_argument('dir', + type=str, + help="Directory where CRIU images should be placed") args = vars(parser.parse_args()) @@ -16,45 +18,45 @@ s.connect(args['socket']) # Start page-server print('Starting page-server') -req = rpc.criu_req() -req.type = rpc.PAGE_SERVER -req.opts.log_file = 'page-server.log' -req.opts.log_level = 4 -req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY) +req = rpc.criu_req() +req.type = rpc.PAGE_SERVER +req.opts.log_file = 'page-server.log' +req.opts.log_level = 4 +req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY) s.send(req.SerializeToString()) -resp = rpc.criu_resp() +resp = rpc.criu_resp() MAX_MSG_SIZE = 1024 resp.ParseFromString(s.recv(MAX_MSG_SIZE)) if resp.type != rpc.PAGE_SERVER: - print('Unexpected msg type') - sys.exit(1) + print('Unexpected msg type') + sys.exit(1) else: - if resp.success: - # check if pid even exists - try: - os.kill(resp.ps.pid, 0) - except OSError as err: - if err.errno == errno.ESRCH: - print('No process with page-server pid %d' %(resp.ps.pid)) - else: - print('Can\'t check that process %d exists' %(resp.ps.pid)) - sys.exit(1) - print('Success, page-server pid %d started on port %u' %(resp.ps.pid, resp.ps.port)) - else: - print('Failed to start page-server') - sys.exit(1) - + if resp.success: + # check if pid even exists + try: + os.kill(resp.ps.pid, 0) + except OSError as err: + if err.errno == errno.ESRCH: + print('No process with page-server pid %d' % (resp.ps.pid)) + else: + print('Can\'t check that process %d exists' % (resp.ps.pid)) + sys.exit(1) + print('Success, page-server pid %d started on port %u' % + (resp.ps.pid, resp.ps.port)) + else: + print('Failed to start page-server') + sys.exit(1) # Perform self-dump print('Dumping myself using page-server') -req.type = rpc.DUMP -req.opts.ps.port = resp.ps.port -req.opts.ps.address = "127.0.0.1" -req.opts.log_file = 'dump.log' -req.opts.leave_running = True +req.type = rpc.DUMP +req.opts.ps.port = resp.ps.port +req.opts.ps.address = "127.0.0.1" +req.opts.log_file = 'dump.log' +req.opts.leave_running = True s.close() s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) @@ -64,11 +66,11 @@ s.send(req.SerializeToString()) resp.ParseFromString(s.recv(MAX_MSG_SIZE)) if resp.type != rpc.DUMP: - print('Unexpected msg type') - sys.exit(1) + print('Unexpected msg type') + sys.exit(1) else: - if resp.success: - print('Success') - else: - print('Fail') - sys.exit(1) + if resp.success: + print('Success') + else: + print('Fail') + sys.exit(1) diff --git a/test/others/rpc/read.py b/test/others/rpc/read.py index bbf69b6cb..ff7e5c1a0 100644 --- a/test/others/rpc/read.py +++ b/test/others/rpc/read.py @@ -12,6 +12,6 @@ r = f.read(1) f.close() if r == '\0': - sys.exit(0) + sys.exit(0) sys.exit(-1) diff --git a/test/others/rpc/restore-loop.py b/test/others/rpc/restore-loop.py index ce5786a56..c81567426 100755 --- a/test/others/rpc/restore-loop.py +++ b/test/others/rpc/restore-loop.py @@ -4,9 +4,12 @@ import socket, os, sys import rpc_pb2 as rpc import argparse -parser = argparse.ArgumentParser(description="Test ability to restore a process from images using CRIU RPC") -parser.add_argument('socket', type = str, help = "CRIU service socket") -parser.add_argument('dir', type = str, help = "Directory where CRIU images could be found") +parser = argparse.ArgumentParser( + description="Test ability to restore a process from images using CRIU RPC") +parser.add_argument('socket', type=str, help="CRIU service socket") +parser.add_argument('dir', + type=str, + help="Directory where CRIU images could be found") args = vars(parser.parse_args()) @@ -16,30 +19,30 @@ s.connect(args['socket']) # Create criu msg, set it's type to dump request # and set dump options. Checkout more options in protobuf/rpc.proto -req = rpc.criu_req() -req.type = rpc.RESTORE -req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY) +req = rpc.criu_req() +req.type = rpc.RESTORE +req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY) # As the dumped process is running with setsid this should not # be necessary. There seems to be a problem for this testcase # in combination with alpine's setsid. # The dump is now done with -j and the restore also. -req.opts.shell_job = True +req.opts.shell_job = True # Send request s.send(req.SerializeToString()) # Recv response -resp = rpc.criu_resp() -MAX_MSG_SIZE = 1024 +resp = rpc.criu_resp() +MAX_MSG_SIZE = 1024 resp.ParseFromString(s.recv(MAX_MSG_SIZE)) if resp.type != rpc.RESTORE: - print('Unexpected msg type') - sys.exit(-1) + print('Unexpected msg type') + sys.exit(-1) else: - if resp.success: - print('Restore success') - else: - print('Restore fail') - sys.exit(-1) - print("PID of the restored program is %d\n" %(resp.restore.pid)) + if resp.success: + print('Restore success') + else: + print('Restore fail') + sys.exit(-1) + print("PID of the restored program is %d\n" % (resp.restore.pid)) diff --git a/test/others/rpc/test.py b/test/others/rpc/test.py index 0addbaedc..9a35e0e97 100755 --- a/test/others/rpc/test.py +++ b/test/others/rpc/test.py @@ -4,9 +4,12 @@ import socket, os, sys import rpc_pb2 as rpc import argparse -parser = argparse.ArgumentParser(description="Test dump/restore using CRIU RPC") -parser.add_argument('socket', type = str, help = "CRIU service socket") -parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed") +parser = argparse.ArgumentParser( + description="Test dump/restore using CRIU RPC") +parser.add_argument('socket', type=str, help="CRIU service socket") +parser.add_argument('dir', + type=str, + help="Directory where CRIU images should be placed") args = vars(parser.parse_args()) @@ -16,32 +19,32 @@ s.connect(args['socket']) # Create criu msg, set it's type to dump request # and set dump options. Checkout more options in protobuf/rpc.proto -req = rpc.criu_req() -req.type = rpc.DUMP -req.opts.leave_running = True -req.opts.log_level = 4 -req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY) +req = rpc.criu_req() +req.type = rpc.DUMP +req.opts.leave_running = True +req.opts.log_level = 4 +req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY) # Send request s.send(req.SerializeToString()) # Recv response -resp = rpc.criu_resp() -MAX_MSG_SIZE = 1024 +resp = rpc.criu_resp() +MAX_MSG_SIZE = 1024 resp.ParseFromString(s.recv(MAX_MSG_SIZE)) if resp.type != rpc.DUMP: - print('Unexpected msg type') - sys.exit(-1) + print('Unexpected msg type') + sys.exit(-1) else: - if resp.success: - print('Success') - else: - print('Fail') - sys.exit(-1) + if resp.success: + print('Success') + else: + print('Fail') + sys.exit(-1) - if resp.dump.restored: - print('Restored') + if resp.dump.restored: + print('Restored') # Connect to service socket s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) @@ -61,21 +64,21 @@ MAX_MSG_SIZE = 1024 resp.ParseFromString(s.recv(MAX_MSG_SIZE)) if resp.type != rpc.VERSION: - print('RPC: Unexpected msg type') - sys.exit(-1) + print('RPC: Unexpected msg type') + sys.exit(-1) else: - if resp.success: - print('RPC: Success') - print('CRIU major %d' % resp.version.major_number) - print('CRIU minor %d' % resp.version.minor_number) - if resp.version.HasField('gitid'): - print('CRIU gitid %s' % resp.version.gitid) - if resp.version.HasField('sublevel'): - print('CRIU sublevel %s' % resp.version.sublevel) - if resp.version.HasField('extra'): - print('CRIU extra %s' % resp.version.extra) - if resp.version.HasField('name'): - print('CRIU name %s' % resp.version.name) - else: - print('Fail') - sys.exit(-1) + if resp.success: + print('RPC: Success') + print('CRIU major %d' % resp.version.major_number) + print('CRIU minor %d' % resp.version.minor_number) + if resp.version.HasField('gitid'): + print('CRIU gitid %s' % resp.version.gitid) + if resp.version.HasField('sublevel'): + print('CRIU sublevel %s' % resp.version.sublevel) + if resp.version.HasField('extra'): + print('CRIU extra %s' % resp.version.extra) + if resp.version.HasField('name'): + print('CRIU name %s' % resp.version.name) + else: + print('Fail') + sys.exit(-1) diff --git a/test/others/rpc/version.py b/test/others/rpc/version.py index 247bc466d..f978c6c37 100755 --- a/test/others/rpc/version.py +++ b/test/others/rpc/version.py @@ -27,21 +27,21 @@ MAX_MSG_SIZE = 1024 resp.ParseFromString(s.recv(MAX_MSG_SIZE)) if resp.type != rpc.VERSION: - print('RPC: Unexpected msg type') - sys.exit(-1) + print('RPC: Unexpected msg type') + sys.exit(-1) else: - if resp.success: - print('RPC: Success') - print('CRIU major %d' % resp.version.major_number) - print('CRIU minor %d' % resp.version.minor_number) - if resp.version.HasField('gitid'): - print('CRIU gitid %s' % resp.version.gitid) - if resp.version.HasField('sublevel'): - print('CRIU sublevel %s' % resp.version.sublevel) - if resp.version.HasField('extra'): - print('CRIU extra %s' % resp.version.extra) - if resp.version.HasField('name'): - print('CRIU name %s' % resp.version.name) - else: - print('Fail') - sys.exit(-1) + if resp.success: + print('RPC: Success') + print('CRIU major %d' % resp.version.major_number) + print('CRIU minor %d' % resp.version.minor_number) + if resp.version.HasField('gitid'): + print('CRIU gitid %s' % resp.version.gitid) + if resp.version.HasField('sublevel'): + print('CRIU sublevel %s' % resp.version.sublevel) + if resp.version.HasField('extra'): + print('CRIU extra %s' % resp.version.extra) + if resp.version.HasField('name'): + print('CRIU name %s' % resp.version.name) + else: + print('Fail') + sys.exit(-1) diff --git a/test/others/shell-job/run.py b/test/others/shell-job/run.py index 4f4dfadef..bd5c42509 100755 --- a/test/others/shell-job/run.py +++ b/test/others/shell-job/run.py @@ -6,15 +6,17 @@ cr_bin = "../../../criu/criu" os.chdir(os.getcwd()) + def create_pty(): - (fd1, fd2) = pty.openpty() - return (os.fdopen(fd1, "w+"), os.fdopen(fd2, "w+")) + (fd1, fd2) = pty.openpty() + return (os.fdopen(fd1, "w+"), os.fdopen(fd2, "w+")) + if not os.access("work", os.X_OK): os.mkdir("work", 0755) open("running", "w").close() -m,s = create_pty() +m, s = create_pty() p = os.pipe() pr = os.fdopen(p[0], "r") pw = os.fdopen(p[1], "w") @@ -46,14 +48,15 @@ if ret != 0: os.wait() os.unlink("running") -m,s = create_pty() +m, s = create_pty() cpid = os.fork() if cpid == 0: os.setsid() fcntl.ioctl(m.fileno(), termios.TIOCSCTTY, 1) cmd = [cr_bin, "restore", "-j", "-D", "work", "-v"] print("Run: %s" % " ".join(cmd)) - ret = subprocess.Popen([cr_bin, "restore", "-j", "-D", "work", "-v"]).wait() + ret = subprocess.Popen([cr_bin, "restore", "-j", "-D", "work", + "-v"]).wait() if ret != 0: sys.exit(1) sys.exit(0) diff --git a/test/zdtm.py b/test/zdtm.py index c52964528..0153c6058 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -32,26 +32,26 @@ prev_line = None def alarm(*args): - print("==== ALARM ====") + print("==== ALARM ====") signal.signal(signal.SIGALRM, alarm) def traceit(f, e, a): - if e == "line": - lineno = f.f_lineno - fil = f.f_globals["__file__"] - if fil.endswith("zdtm.py"): - global prev_line - line = linecache.getline(fil, lineno) - if line == prev_line: - print(" ...") - else: - prev_line = line - print("+%4d: %s" % (lineno, line.rstrip())) + if e == "line": + lineno = f.f_lineno + fil = f.f_globals["__file__"] + if fil.endswith("zdtm.py"): + global prev_line + line = linecache.getline(fil, lineno) + if line == prev_line: + print(" ...") + else: + prev_line = line + print("+%4d: %s" % (lineno, line.rstrip())) - return traceit + return traceit # Root dir for ns and uns flavors. All tests @@ -60,17 +60,17 @@ tests_root = None def clean_tests_root(): - global tests_root - if tests_root and tests_root[0] == os.getpid(): - os.rmdir(tests_root[1]) + global tests_root + if tests_root and tests_root[0] == os.getpid(): + os.rmdir(tests_root[1]) def make_tests_root(): - global tests_root - if not tests_root: - tests_root = (os.getpid(), tempfile.mkdtemp("", "criu-root-", "/tmp")) - atexit.register(clean_tests_root) - return tests_root[1] + global tests_root + if not tests_root: + tests_root = (os.getpid(), tempfile.mkdtemp("", "criu-root-", "/tmp")) + atexit.register(clean_tests_root) + return tests_root[1] # Report generation @@ -79,60 +79,61 @@ report_dir = None def init_report(path): - global report_dir - report_dir = path - if not os.access(report_dir, os.F_OK): - os.makedirs(report_dir) + global report_dir + report_dir = path + if not os.access(report_dir, os.F_OK): + os.makedirs(report_dir) def add_to_report(path, tgt_name): - global report_dir - if report_dir: - tgt_path = os.path.join(report_dir, tgt_name) - att = 0 - while os.access(tgt_path, os.F_OK): - tgt_path = os.path.join(report_dir, tgt_name + ".%d" % att) - att += 1 + global report_dir + if report_dir: + tgt_path = os.path.join(report_dir, tgt_name) + att = 0 + while os.access(tgt_path, os.F_OK): + tgt_path = os.path.join(report_dir, tgt_name + ".%d" % att) + att += 1 - ignore = shutil.ignore_patterns('*.socket') - if os.path.isdir(path): - shutil.copytree(path, tgt_path, ignore = ignore) - else: - if not os.path.exists(os.path.dirname(tgt_path)): - os.mkdir(os.path.dirname(tgt_path)) - shutil.copy2(path, tgt_path) + ignore = shutil.ignore_patterns('*.socket') + if os.path.isdir(path): + shutil.copytree(path, tgt_path, ignore=ignore) + else: + if not os.path.exists(os.path.dirname(tgt_path)): + os.mkdir(os.path.dirname(tgt_path)) + shutil.copy2(path, tgt_path) def add_to_output(path): - global report_dir - if not report_dir: - return + global report_dir + if not report_dir: + return - output_path = os.path.join(report_dir, "output") - with open(path, "r") as fdi, open(output_path, "a") as fdo: - for line in fdi: - fdo.write(line) + output_path = os.path.join(report_dir, "output") + with open(path, "r") as fdi, open(output_path, "a") as fdo: + for line in fdi: + fdo.write(line) prev_crash_reports = set(glob.glob("/tmp/zdtm-core-*.txt")) def check_core_files(): - reports = set(glob.glob("/tmp/zdtm-core-*.txt")) - prev_crash_reports - if not reports: - return False + reports = set(glob.glob("/tmp/zdtm-core-*.txt")) - prev_crash_reports + if not reports: + return False - while subprocess.Popen(r"ps axf | grep 'abrt\.sh'", shell = True).wait() == 0: - time.sleep(1) + while subprocess.Popen(r"ps axf | grep 'abrt\.sh'", + shell=True).wait() == 0: + time.sleep(1) - for i in reports: - add_to_report(i, os.path.basename(i)) - print_sep(i) - with open(i, "r") as report: - print(report.read()) - print_sep(i) + for i in reports: + add_to_report(i, os.path.basename(i)) + print_sep(i) + with open(i, "r") as report: + print(report.read()) + print_sep(i) - return True + return True # Arch we run on @@ -147,148 +148,161 @@ arch = os.uname()[4] class host_flavor: - def __init__(self, opts): - self.name = "host" - self.ns = False - self.root = None + def __init__(self, opts): + self.name = "host" + self.ns = False + self.root = None - def init(self, l_bins, x_bins): - pass + def init(self, l_bins, x_bins): + pass - def fini(self): - pass + def fini(self): + pass - @staticmethod - def clean(): - pass + @staticmethod + def clean(): + pass class ns_flavor: - __root_dirs = ["/bin", "/sbin", "/etc", "/lib", "/lib64", "/dev", "/dev/pts", "/dev/net", "/tmp", "/usr", "/proc", "/run"] + __root_dirs = [ + "/bin", "/sbin", "/etc", "/lib", "/lib64", "/dev", "/dev/pts", + "/dev/net", "/tmp", "/usr", "/proc", "/run" + ] - def __init__(self, opts): - self.name = "ns" - self.ns = True - self.uns = False - self.root = make_tests_root() - self.root_mounted = False + def __init__(self, opts): + self.name = "ns" + self.ns = True + self.uns = False + self.root = make_tests_root() + self.root_mounted = False - def __copy_one(self, fname): - tfname = self.root + fname - if not os.access(tfname, os.F_OK): - # Copying should be atomic as tests can be - # run in parallel - try: - os.makedirs(self.root + os.path.dirname(fname)) - except OSError as e: - if e.errno != errno.EEXIST: - raise - dst = tempfile.mktemp(".tso", "", self.root + os.path.dirname(fname)) - shutil.copy2(fname, dst) - os.rename(dst, tfname) + def __copy_one(self, fname): + tfname = self.root + fname + if not os.access(tfname, os.F_OK): + # Copying should be atomic as tests can be + # run in parallel + try: + os.makedirs(self.root + os.path.dirname(fname)) + except OSError as e: + if e.errno != errno.EEXIST: + raise + dst = tempfile.mktemp(".tso", "", + self.root + os.path.dirname(fname)) + shutil.copy2(fname, dst) + os.rename(dst, tfname) - def __copy_libs(self, binary): - ldd = subprocess.Popen(["ldd", binary], stdout = subprocess.PIPE) - xl = re.compile(r'^(linux-gate.so|linux-vdso(64)?.so|not a dynamic|.*\s*ldd\s)') + def __copy_libs(self, binary): + ldd = subprocess.Popen(["ldd", binary], stdout=subprocess.PIPE) + xl = re.compile( + r'^(linux-gate.so|linux-vdso(64)?.so|not a dynamic|.*\s*ldd\s)') - # This Mayakovsky-style code gets list of libraries a binary - # needs minus vdso and gate .so-s - libs = map(lambda x: x[1] == '=>' and x[2] or x[0], - map(lambda x: str(x).split(), - filter(lambda x: not xl.match(x), - map(lambda x: str(x).strip(), - filter(lambda x: str(x).startswith('\t'), ldd.stdout.read().decode('ascii').splitlines()))))) + # This Mayakovsky-style code gets list of libraries a binary + # needs minus vdso and gate .so-s + libs = map( + lambda x: x[1] == '=>' and x[2] or x[0], + map( + lambda x: str(x).split(), + filter( + lambda x: not xl.match(x), + map( + lambda x: str(x).strip(), + filter(lambda x: str(x).startswith('\t'), + ldd.stdout.read().decode( + 'ascii').splitlines()))))) - ldd.wait() + ldd.wait() - for lib in libs: - if not os.access(lib, os.F_OK): - raise test_fail_exc("Can't find lib %s required by %s" % (lib, binary)) - self.__copy_one(lib) + for lib in libs: + if not os.access(lib, os.F_OK): + raise test_fail_exc("Can't find lib %s required by %s" % + (lib, binary)) + self.__copy_one(lib) - def __mknod(self, name, rdev = None): - name = "/dev/" + name - if not rdev: - if not os.access(name, os.F_OK): - print("Skipping %s at root" % name) - return - else: - rdev = os.stat(name).st_rdev + def __mknod(self, name, rdev=None): + name = "/dev/" + name + if not rdev: + if not os.access(name, os.F_OK): + print("Skipping %s at root" % name) + return + else: + rdev = os.stat(name).st_rdev - name = self.root + name - os.mknod(name, stat.S_IFCHR, rdev) - os.chmod(name, 0o666) + name = self.root + name + os.mknod(name, stat.S_IFCHR, rdev) + os.chmod(name, 0o666) - def __construct_root(self): - for dir in self.__root_dirs: - os.mkdir(self.root + dir) - os.chmod(self.root + dir, 0o777) + def __construct_root(self): + for dir in self.__root_dirs: + os.mkdir(self.root + dir) + os.chmod(self.root + dir, 0o777) - for ldir in ["/bin", "/sbin", "/lib", "/lib64"]: - os.symlink(".." + ldir, self.root + "/usr" + ldir) + for ldir in ["/bin", "/sbin", "/lib", "/lib64"]: + os.symlink(".." + ldir, self.root + "/usr" + ldir) - self.__mknod("tty", os.makedev(5, 0)) - self.__mknod("null", os.makedev(1, 3)) - self.__mknod("net/tun") - self.__mknod("rtc") - self.__mknod("autofs", os.makedev(10, 235)) + self.__mknod("tty", os.makedev(5, 0)) + self.__mknod("null", os.makedev(1, 3)) + self.__mknod("net/tun") + self.__mknod("rtc") + self.__mknod("autofs", os.makedev(10, 235)) - def __copy_deps(self, deps): - for d in deps.split('|'): - if os.access(d, os.F_OK): - self.__copy_one(d) - self.__copy_libs(d) - return - raise test_fail_exc("Deps check %s failed" % deps) + def __copy_deps(self, deps): + for d in deps.split('|'): + if os.access(d, os.F_OK): + self.__copy_one(d) + self.__copy_libs(d) + return + raise test_fail_exc("Deps check %s failed" % deps) - def init(self, l_bins, x_bins): - subprocess.check_call(["mount", "--make-slave", "--bind", ".", self.root]) - self.root_mounted = True + def init(self, l_bins, x_bins): + subprocess.check_call( + ["mount", "--make-slave", "--bind", ".", self.root]) + self.root_mounted = True - if not os.access(self.root + "/.constructed", os.F_OK): - with open(os.path.abspath(__file__)) as o: - fcntl.flock(o, fcntl.LOCK_EX) - if not os.access(self.root + "/.constructed", os.F_OK): - print("Construct root for %s" % l_bins[0]) - self.__construct_root() - os.mknod(self.root + "/.constructed", stat.S_IFREG | 0o600) + if not os.access(self.root + "/.constructed", os.F_OK): + with open(os.path.abspath(__file__)) as o: + fcntl.flock(o, fcntl.LOCK_EX) + if not os.access(self.root + "/.constructed", os.F_OK): + print("Construct root for %s" % l_bins[0]) + self.__construct_root() + os.mknod(self.root + "/.constructed", stat.S_IFREG | 0o600) - for b in l_bins: - self.__copy_libs(b) - for b in x_bins: - self.__copy_deps(b) + for b in l_bins: + self.__copy_libs(b) + for b in x_bins: + self.__copy_deps(b) - def fini(self): - if self.root_mounted: - subprocess.check_call(["./umount2", self.root]) - self.root_mounted = False + def fini(self): + if self.root_mounted: + subprocess.check_call(["./umount2", self.root]) + self.root_mounted = False - @staticmethod - def clean(): - for d in ns_flavor.__root_dirs: - p = './' + d - print('Remove %s' % p) - if os.access(p, os.F_OK): - shutil.rmtree('./' + d) + @staticmethod + def clean(): + for d in ns_flavor.__root_dirs: + p = './' + d + print('Remove %s' % p) + if os.access(p, os.F_OK): + shutil.rmtree('./' + d) - if os.access('./.constructed', os.F_OK): - os.unlink('./.constructed') + if os.access('./.constructed', os.F_OK): + os.unlink('./.constructed') class userns_flavor(ns_flavor): - def __init__(self, opts): - ns_flavor.__init__(self, opts) - self.name = "userns" - self.uns = True + def __init__(self, opts): + ns_flavor.__init__(self, opts) + self.name = "userns" + self.uns = True - def init(self, l_bins, x_bins): - # To be able to create roots_yard in CRIU - os.chmod(".", os.stat(".").st_mode | 0o077) - ns_flavor.init(self, l_bins, x_bins) + def init(self, l_bins, x_bins): + # To be able to create roots_yard in CRIU + os.chmod(".", os.stat(".").st_mode | 0o077) + ns_flavor.init(self, l_bins, x_bins) - @staticmethod - def clean(): - pass + @staticmethod + def clean(): + pass flavors = {'h': host_flavor, 'ns': ns_flavor, 'uns': userns_flavor} @@ -300,47 +314,47 @@ flavors_codes = dict(zip(range(len(flavors)), sorted(flavors.keys()))) def encode_flav(f): - return sorted(flavors.keys()).index(f) + 128 + return sorted(flavors.keys()).index(f) + 128 def decode_flav(i): - return flavors_codes.get(i - 128, "unknown") + return flavors_codes.get(i - 128, "unknown") def tail(path): - p = subprocess.Popen(['tail', '-n1', path], - stdout = subprocess.PIPE) - out = p.stdout.readline() - p.wait() - return out.decode() + p = subprocess.Popen(['tail', '-n1', path], stdout=subprocess.PIPE) + out = p.stdout.readline() + p.wait() + return out.decode() def rpidfile(path): - with open(path) as fd: - return fd.readline().strip() + with open(path) as fd: + return fd.readline().strip() -def wait_pid_die(pid, who, tmo = 30): - stime = 0.1 - while stime < tmo: - try: - os.kill(int(pid), 0) - except OSError as e: - if e.errno != errno.ESRCH: - print(e) - break +def wait_pid_die(pid, who, tmo=30): + stime = 0.1 + while stime < tmo: + try: + os.kill(int(pid), 0) + except OSError as e: + if e.errno != errno.ESRCH: + print(e) + break - print("Wait for %s(%d) to die for %f" % (who, pid, stime)) - time.sleep(stime) - stime *= 2 - else: - subprocess.Popen(["ps", "-p", str(pid)]).wait() - subprocess.Popen(["ps", "axf", str(pid)]).wait() - raise test_fail_exc("%s die" % who) + print("Wait for %s(%d) to die for %f" % (who, pid, stime)) + time.sleep(stime) + stime *= 2 + else: + subprocess.Popen(["ps", "-p", str(pid)]).wait() + subprocess.Popen(["ps", "axf", str(pid)]).wait() + raise test_fail_exc("%s die" % who) def test_flag(tdesc, flag): - return flag in tdesc.get('flags', '').split() + return flag in tdesc.get('flags', '').split() + # # Exception thrown when something inside the test goes wrong, @@ -350,16 +364,17 @@ def test_flag(tdesc, flag): class test_fail_exc(Exception): - def __init__(self, step): - self.step = step + def __init__(self, step): + self.step = step - def __str__(self): - return str(self.step) + def __str__(self): + return str(self.step) class test_fail_expected_exc(Exception): - def __init__(self, cr_action): - self.cr_action = cr_action + def __init__(self, cr_action): + self.cr_action = cr_action + # # A test from zdtm/ directory. @@ -367,418 +382,440 @@ class test_fail_expected_exc(Exception): class zdtm_test: - def __init__(self, name, desc, flavor, freezer): - self.__name = name - self.__desc = desc - self.__freezer = None - self.__make_action('cleanout') - self.__pid = 0 - self.__flavor = flavor - self.__freezer = freezer - self._bins = [name] - self._env = {} - self._deps = desc.get('deps', []) - self.auto_reap = True - self.__timeout = int(self.__desc.get('timeout') or 30) + def __init__(self, name, desc, flavor, freezer): + self.__name = name + self.__desc = desc + self.__freezer = None + self.__make_action('cleanout') + self.__pid = 0 + self.__flavor = flavor + self.__freezer = freezer + self._bins = [name] + self._env = {} + self._deps = desc.get('deps', []) + self.auto_reap = True + self.__timeout = int(self.__desc.get('timeout') or 30) - def __make_action(self, act, env = None, root = None): - sys.stdout.flush() # Not to let make's messages appear before ours - tpath = self.__name + '.' + act - s_args = ['make', '--no-print-directory', - '-C', os.path.dirname(tpath), - os.path.basename(tpath)] + def __make_action(self, act, env=None, root=None): + sys.stdout.flush() # Not to let make's messages appear before ours + tpath = self.__name + '.' + act + s_args = [ + 'make', '--no-print-directory', '-C', + os.path.dirname(tpath), + os.path.basename(tpath) + ] - if env: - env = dict(os.environ, **env) + if env: + env = dict(os.environ, **env) - s = subprocess.Popen(s_args, env = env, cwd = root, close_fds = True, - preexec_fn = self.__freezer and self.__freezer.attach or None) - if act == "pid": - try_run_hook(self, ["--post-start"]) - if s.wait(): - raise test_fail_exc(str(s_args)) + s = subprocess.Popen( + s_args, + env=env, + cwd=root, + close_fds=True, + preexec_fn=self.__freezer and self.__freezer.attach or None) + if act == "pid": + try_run_hook(self, ["--post-start"]) + if s.wait(): + raise test_fail_exc(str(s_args)) - if self.__freezer: - self.__freezer.freeze() + if self.__freezer: + self.__freezer.freeze() - def __pidfile(self): - return self.__name + '.pid' + def __pidfile(self): + return self.__name + '.pid' - def __wait_task_die(self): - wait_pid_die(int(self.__pid), self.__name, self.__timeout) + def __wait_task_die(self): + wait_pid_die(int(self.__pid), self.__name, self.__timeout) - def __add_wperms(self): - # Add write perms for .out and .pid files - for b in self._bins: - p = os.path.dirname(b) - os.chmod(p, os.stat(p).st_mode | 0o222) + def __add_wperms(self): + # Add write perms for .out and .pid files + for b in self._bins: + p = os.path.dirname(b) + os.chmod(p, os.stat(p).st_mode | 0o222) - def start(self): - self.__flavor.init(self._bins, self._deps) + def start(self): + self.__flavor.init(self._bins, self._deps) - print("Start test") + print("Start test") - env = self._env - if not self.__freezer.kernel: - env['ZDTM_THREAD_BOMB'] = "5" + env = self._env + if not self.__freezer.kernel: + env['ZDTM_THREAD_BOMB'] = "5" - if test_flag(self.__desc, 'pre-dump-notify'): - env['ZDTM_NOTIFY_FDIN'] = "100" - env['ZDTM_NOTIFY_FDOUT'] = "101" + if test_flag(self.__desc, 'pre-dump-notify'): + env['ZDTM_NOTIFY_FDIN'] = "100" + env['ZDTM_NOTIFY_FDOUT'] = "101" - if not test_flag(self.__desc, 'suid'): - # Numbers should match those in criu - env['ZDTM_UID'] = "18943" - env['ZDTM_GID'] = "58467" - env['ZDTM_GROUPS'] = "27495 48244" - self.__add_wperms() - else: - print("Test is SUID") + if not test_flag(self.__desc, 'suid'): + # Numbers should match those in criu + env['ZDTM_UID'] = "18943" + env['ZDTM_GID'] = "58467" + env['ZDTM_GROUPS'] = "27495 48244" + self.__add_wperms() + else: + print("Test is SUID") - if self.__flavor.ns: - env['ZDTM_NEWNS'] = "1" - env['ZDTM_ROOT'] = self.__flavor.root - env['PATH'] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + if self.__flavor.ns: + env['ZDTM_NEWNS'] = "1" + env['ZDTM_ROOT'] = self.__flavor.root + env['PATH'] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - if self.__flavor.uns: - env['ZDTM_USERNS'] = "1" - self.__add_wperms() - if os.getenv("GCOV"): - criu_dir = os.path.dirname(os.getcwd()) - criu_dir_r = "%s%s" % (self.__flavor.root, criu_dir) + if self.__flavor.uns: + env['ZDTM_USERNS'] = "1" + self.__add_wperms() + if os.getenv("GCOV"): + criu_dir = os.path.dirname(os.getcwd()) + criu_dir_r = "%s%s" % (self.__flavor.root, criu_dir) - env['ZDTM_CRIU'] = os.path.dirname(os.getcwd()) - subprocess.check_call(["mkdir", "-p", criu_dir_r]) + env['ZDTM_CRIU'] = os.path.dirname(os.getcwd()) + subprocess.check_call(["mkdir", "-p", criu_dir_r]) - self.__make_action('pid', env, self.__flavor.root) + self.__make_action('pid', env, self.__flavor.root) - try: - os.kill(int(self.getpid()), 0) - except Exception as e: - raise test_fail_exc("start: %s" % e) + try: + os.kill(int(self.getpid()), 0) + except Exception as e: + raise test_fail_exc("start: %s" % e) - if not self.static(): - # Wait less than a second to give the test chance to - # move into some semi-random state - time.sleep(random.random()) + if not self.static(): + # Wait less than a second to give the test chance to + # move into some semi-random state + time.sleep(random.random()) - def kill(self, sig = signal.SIGKILL): - self.__freezer.thaw() - if self.__pid: - print("Send the %d signal to %s" % (sig, self.__pid)) - os.kill(int(self.__pid), sig) - self.gone(sig == signal.SIGKILL) + def kill(self, sig=signal.SIGKILL): + self.__freezer.thaw() + if self.__pid: + print("Send the %d signal to %s" % (sig, self.__pid)) + os.kill(int(self.__pid), sig) + self.gone(sig == signal.SIGKILL) - self.__flavor.fini() + self.__flavor.fini() - def pre_dump_notify(self): - env = self._env + def pre_dump_notify(self): + env = self._env - if 'ZDTM_NOTIFY_FDIN' not in env: - return + if 'ZDTM_NOTIFY_FDIN' not in env: + return - if self.__pid == 0: - self.getpid() + if self.__pid == 0: + self.getpid() - notify_fdout_path = "/proc/%s/fd/%s" % (self.__pid, env['ZDTM_NOTIFY_FDOUT']) - notify_fdin_path = "/proc/%s/fd/%s" % (self.__pid, env['ZDTM_NOTIFY_FDIN']) + notify_fdout_path = "/proc/%s/fd/%s" % (self.__pid, + env['ZDTM_NOTIFY_FDOUT']) + notify_fdin_path = "/proc/%s/fd/%s" % (self.__pid, + env['ZDTM_NOTIFY_FDIN']) - print("Send pre-dump notify to %s" % (self.__pid)) - with open(notify_fdout_path, "rb") as fdout: - with open(notify_fdin_path, "wb") as fdin: - fdin.write(struct.pack("i", 0)) - fdin.flush() - print("Wait pre-dump notify reply") - ret = struct.unpack('i', fdout.read(4)) - print("Completed pre-dump notify with %d" % (ret)) + print("Send pre-dump notify to %s" % (self.__pid)) + with open(notify_fdout_path, "rb") as fdout: + with open(notify_fdin_path, "wb") as fdin: + fdin.write(struct.pack("i", 0)) + fdin.flush() + print("Wait pre-dump notify reply") + ret = struct.unpack('i', fdout.read(4)) + print("Completed pre-dump notify with %d" % (ret)) - def stop(self): - self.__freezer.thaw() - self.getpid() # Read the pid from pidfile back - self.kill(signal.SIGTERM) + def stop(self): + self.__freezer.thaw() + self.getpid() # Read the pid from pidfile back + self.kill(signal.SIGTERM) - res = tail(self.__name + '.out') - if 'PASS' not in list(map(lambda s: s.strip(), res.split())): - if os.access(self.__name + '.out.inprogress', os.F_OK): - print_sep(self.__name + '.out.inprogress') - with open(self.__name + '.out.inprogress') as fd: - print(fd.read()) - print_sep(self.__name + '.out.inprogress') - raise test_fail_exc("result check") + res = tail(self.__name + '.out') + if 'PASS' not in list(map(lambda s: s.strip(), res.split())): + if os.access(self.__name + '.out.inprogress', os.F_OK): + print_sep(self.__name + '.out.inprogress') + with open(self.__name + '.out.inprogress') as fd: + print(fd.read()) + print_sep(self.__name + '.out.inprogress') + raise test_fail_exc("result check") - def getpid(self): - if self.__pid == 0: - self.__pid = rpidfile(self.__pidfile()) + def getpid(self): + if self.__pid == 0: + self.__pid = rpidfile(self.__pidfile()) - return self.__pid + return self.__pid - def getname(self): - return self.__name + def getname(self): + return self.__name - def __getcropts(self): - opts = self.__desc.get('opts', '').split() + ["--pidfile", os.path.realpath(self.__pidfile())] - if self.__flavor.ns: - opts += ["--root", self.__flavor.root] - if test_flag(self.__desc, 'crlib'): - opts += ["-L", os.path.dirname(os.path.realpath(self.__name)) + '/lib'] - return opts + def __getcropts(self): + opts = self.__desc.get('opts', '').split() + [ + "--pidfile", os.path.realpath(self.__pidfile()) + ] + if self.__flavor.ns: + opts += ["--root", self.__flavor.root] + if test_flag(self.__desc, 'crlib'): + opts += [ + "-L", + os.path.dirname(os.path.realpath(self.__name)) + '/lib' + ] + return opts - def getdopts(self): - return self.__getcropts() + self.__freezer.getdopts() + self.__desc.get('dopts', '').split() + def getdopts(self): + return self.__getcropts() + self.__freezer.getdopts( + ) + self.__desc.get('dopts', '').split() - def getropts(self): - return self.__getcropts() + self.__freezer.getropts() + self.__desc.get('ropts', '').split() + def getropts(self): + return self.__getcropts() + self.__freezer.getropts( + ) + self.__desc.get('ropts', '').split() - def unlink_pidfile(self): - self.__pid = 0 - os.unlink(self.__pidfile()) + def unlink_pidfile(self): + self.__pid = 0 + os.unlink(self.__pidfile()) - def gone(self, force = True): - if not self.auto_reap: - pid, status = os.waitpid(int(self.__pid), 0) - if pid != int(self.__pid): - raise test_fail_exc("kill pid mess") + def gone(self, force=True): + if not self.auto_reap: + pid, status = os.waitpid(int(self.__pid), 0) + if pid != int(self.__pid): + raise test_fail_exc("kill pid mess") - self.__wait_task_die() - self.__pid = 0 - if force: - os.unlink(self.__pidfile()) + self.__wait_task_die() + self.__pid = 0 + if force: + os.unlink(self.__pidfile()) - def print_output(self): - if os.access(self.__name + '.out', os.R_OK): - print("Test output: " + "=" * 32) - with open(self.__name + '.out') as output: - print(output.read()) - print(" <<< " + "=" * 32) + def print_output(self): + if os.access(self.__name + '.out', os.R_OK): + print("Test output: " + "=" * 32) + with open(self.__name + '.out') as output: + print(output.read()) + print(" <<< " + "=" * 32) - def static(self): - return self.__name.split('/')[1] == 'static' + def static(self): + return self.__name.split('/')[1] == 'static' - def ns(self): - return self.__flavor.ns + def ns(self): + return self.__flavor.ns - def blocking(self): - return test_flag(self.__desc, 'crfail') + def blocking(self): + return test_flag(self.__desc, 'crfail') - @staticmethod - def available(): - if not os.access("umount2", os.X_OK): - subprocess.check_call(["make", "umount2"]) - if not os.access("zdtm_ct", os.X_OK): - subprocess.check_call(["make", "zdtm_ct"]) - if not os.access("zdtm/lib/libzdtmtst.a", os.F_OK): - subprocess.check_call(["make", "-C", "zdtm/"]) - subprocess.check_call(["flock", "zdtm_mount_cgroups.lock", "./zdtm_mount_cgroups"]) + @staticmethod + def available(): + if not os.access("umount2", os.X_OK): + subprocess.check_call(["make", "umount2"]) + if not os.access("zdtm_ct", os.X_OK): + subprocess.check_call(["make", "zdtm_ct"]) + if not os.access("zdtm/lib/libzdtmtst.a", os.F_OK): + subprocess.check_call(["make", "-C", "zdtm/"]) + subprocess.check_call( + ["flock", "zdtm_mount_cgroups.lock", "./zdtm_mount_cgroups"]) - @staticmethod - def cleanup(): - subprocess.check_call(["flock", "zdtm_mount_cgroups.lock", "./zdtm_umount_cgroups"]) + @staticmethod + def cleanup(): + subprocess.check_call( + ["flock", "zdtm_mount_cgroups.lock", "./zdtm_umount_cgroups"]) def load_module_from_file(name, path): - if sys.version_info[0] == 3 and sys.version_info[1] >= 5: - import importlib.util - spec = importlib.util.spec_from_file_location(name, path) - mod = importlib.util.module_from_spec(spec) - spec.loader.exec_module(mod) - else: - import imp - mod = imp.load_source(name, path) - return mod + if sys.version_info[0] == 3 and sys.version_info[1] >= 5: + import importlib.util + spec = importlib.util.spec_from_file_location(name, path) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + else: + import imp + mod = imp.load_source(name, path) + return mod class inhfd_test: - def __init__(self, name, desc, flavor, freezer): - self.__name = os.path.basename(name) - print("Load %s" % name) - self.__fdtyp = load_module_from_file(self.__name, name) - self.__peer_pid = 0 - self.__files = None - self.__peer_file_names = [] - self.__dump_opts = [] - self.__messages = {} + def __init__(self, name, desc, flavor, freezer): + self.__name = os.path.basename(name) + print("Load %s" % name) + self.__fdtyp = load_module_from_file(self.__name, name) + self.__peer_pid = 0 + self.__files = None + self.__peer_file_names = [] + self.__dump_opts = [] + self.__messages = {} - def __get_message(self, i): - m = self.__messages.get(i, None) - if not m: - m = b"".join([random.choice(string.ascii_letters).encode() for _ in range(10)]) + b"%06d" % i - self.__messages[i] = m - return m + def __get_message(self, i): + m = self.__messages.get(i, None) + if not m: + m = b"".join([ + random.choice(string.ascii_letters).encode() for _ in range(10) + ]) + b"%06d" % i + self.__messages[i] = m + return m - def start(self): - self.__files = self.__fdtyp.create_fds() + def start(self): + self.__files = self.__fdtyp.create_fds() - # Check FDs returned for inter-connection - i = 0 - for my_file, peer_file in self.__files: - msg = self.__get_message(i) - my_file.write(msg) - my_file.flush() - data = peer_file.read(len(msg)) - if data != msg: - raise test_fail_exc("FDs screwup: %r %r" % (msg, data)) - i += 1 + # Check FDs returned for inter-connection + i = 0 + for my_file, peer_file in self.__files: + msg = self.__get_message(i) + my_file.write(msg) + my_file.flush() + data = peer_file.read(len(msg)) + if data != msg: + raise test_fail_exc("FDs screwup: %r %r" % (msg, data)) + i += 1 - start_pipe = os.pipe() - self.__peer_pid = os.fork() - if self.__peer_pid == 0: - os.setsid() + start_pipe = os.pipe() + self.__peer_pid = os.fork() + if self.__peer_pid == 0: + os.setsid() - for _, peer_file in self.__files: - getattr(self.__fdtyp, "child_prep", lambda fd: None)(peer_file) + for _, peer_file in self.__files: + getattr(self.__fdtyp, "child_prep", lambda fd: None)(peer_file) - try: - os.unlink(self.__name + ".out") - except Exception as e: - print(e) - fd = os.open(self.__name + ".out", os.O_WRONLY | os.O_APPEND | os.O_CREAT) - os.dup2(fd, 1) - os.dup2(fd, 2) - os.close(fd) - fd = os.open("/dev/null", os.O_RDONLY) - os.dup2(fd, 0) - for my_file, _ in self.__files: - my_file.close() - os.close(start_pipe[0]) - os.close(start_pipe[1]) - i = 0 - for _, peer_file in self.__files: - msg = self.__get_message(i) - my_file.close() - try: - data = peer_file.read(16) - except Exception as e: - print("Unable to read a peer file: %s" % e) - sys.exit(1) + try: + os.unlink(self.__name + ".out") + except Exception as e: + print(e) + fd = os.open(self.__name + ".out", + os.O_WRONLY | os.O_APPEND | os.O_CREAT) + os.dup2(fd, 1) + os.dup2(fd, 2) + os.close(fd) + fd = os.open("/dev/null", os.O_RDONLY) + os.dup2(fd, 0) + for my_file, _ in self.__files: + my_file.close() + os.close(start_pipe[0]) + os.close(start_pipe[1]) + i = 0 + for _, peer_file in self.__files: + msg = self.__get_message(i) + my_file.close() + try: + data = peer_file.read(16) + except Exception as e: + print("Unable to read a peer file: %s" % e) + sys.exit(1) - if data != msg: - print("%r %r" % (data, msg)) - i += 1 - sys.exit(data == msg and 42 or 2) + if data != msg: + print("%r %r" % (data, msg)) + i += 1 + sys.exit(data == msg and 42 or 2) - os.close(start_pipe[1]) - os.read(start_pipe[0], 12) - os.close(start_pipe[0]) + os.close(start_pipe[1]) + os.read(start_pipe[0], 12) + os.close(start_pipe[0]) - for _, peer_file in self.__files: - self.__peer_file_names.append(self.__fdtyp.filename(peer_file)) - self.__dump_opts += self.__fdtyp.dump_opts(peer_file) + for _, peer_file in self.__files: + self.__peer_file_names.append(self.__fdtyp.filename(peer_file)) + self.__dump_opts += self.__fdtyp.dump_opts(peer_file) - self.__fds = set(os.listdir("/proc/%s/fd" % self.__peer_pid)) + self.__fds = set(os.listdir("/proc/%s/fd" % self.__peer_pid)) - def stop(self): - fds = set(os.listdir("/proc/%s/fd" % self.__peer_pid)) - if fds != self.__fds: - raise test_fail_exc("File descriptors mismatch: %s %s" % (fds, self.__fds)) - i = 0 - for my_file, _ in self.__files: - msg = self.__get_message(i) - my_file.write(msg) - my_file.flush() - i += 1 - pid, status = os.waitpid(self.__peer_pid, 0) - with open(self.__name + ".out") as output: - print(output.read()) - self.__peer_pid = 0 - if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 42: - raise test_fail_exc("test failed with %d" % status) + def stop(self): + fds = set(os.listdir("/proc/%s/fd" % self.__peer_pid)) + if fds != self.__fds: + raise test_fail_exc("File descriptors mismatch: %s %s" % + (fds, self.__fds)) + i = 0 + for my_file, _ in self.__files: + msg = self.__get_message(i) + my_file.write(msg) + my_file.flush() + i += 1 + pid, status = os.waitpid(self.__peer_pid, 0) + with open(self.__name + ".out") as output: + print(output.read()) + self.__peer_pid = 0 + if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 42: + raise test_fail_exc("test failed with %d" % status) - def kill(self): - if self.__peer_pid: - os.kill(self.__peer_pid, signal.SIGKILL) + def kill(self): + if self.__peer_pid: + os.kill(self.__peer_pid, signal.SIGKILL) - def getname(self): - return self.__name + def getname(self): + return self.__name - def getpid(self): - return "%s" % self.__peer_pid + def getpid(self): + return "%s" % self.__peer_pid - def gone(self, force = True): - os.waitpid(self.__peer_pid, 0) - wait_pid_die(self.__peer_pid, self.__name) - self.__files = None + def gone(self, force=True): + os.waitpid(self.__peer_pid, 0) + wait_pid_die(self.__peer_pid, self.__name) + self.__files = None - def getdopts(self): - return self.__dump_opts + def getdopts(self): + return self.__dump_opts - def getropts(self): - self.__files = self.__fdtyp.create_fds() - ropts = ["--restore-sibling"] - for i in range(len(self.__files)): - my_file, peer_file = self.__files[i] - fd = peer_file.fileno() - fdflags = fcntl.fcntl(fd, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC - fcntl.fcntl(fd, fcntl.F_SETFD, fdflags) - peer_file_name = self.__peer_file_names[i] - ropts.extend(["--inherit-fd", "fd[%d]:%s" % (fd, peer_file_name)]) - return ropts + def getropts(self): + self.__files = self.__fdtyp.create_fds() + ropts = ["--restore-sibling"] + for i in range(len(self.__files)): + my_file, peer_file = self.__files[i] + fd = peer_file.fileno() + fdflags = fcntl.fcntl(fd, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC + fcntl.fcntl(fd, fcntl.F_SETFD, fdflags) + peer_file_name = self.__peer_file_names[i] + ropts.extend(["--inherit-fd", "fd[%d]:%s" % (fd, peer_file_name)]) + return ropts - def print_output(self): - pass + def print_output(self): + pass - def static(self): - return True + def static(self): + return True - def blocking(self): - return False + def blocking(self): + return False - @staticmethod - def available(): - pass + @staticmethod + def available(): + pass - @staticmethod - def cleanup(): - pass + @staticmethod + def cleanup(): + pass class groups_test(zdtm_test): - def __init__(self, name, desc, flavor, freezer): - zdtm_test.__init__(self, 'zdtm/lib/groups', desc, flavor, freezer) - if flavor.ns: - self.__real_name = name - with open(name) as fd: - self.__subs = map(lambda x: x.strip(), fd.readlines()) - print("Subs:\n%s" % '\n'.join(self.__subs)) - else: - self.__real_name = '' - self.__subs = [] + def __init__(self, name, desc, flavor, freezer): + zdtm_test.__init__(self, 'zdtm/lib/groups', desc, flavor, freezer) + if flavor.ns: + self.__real_name = name + with open(name) as fd: + self.__subs = map(lambda x: x.strip(), fd.readlines()) + print("Subs:\n%s" % '\n'.join(self.__subs)) + else: + self.__real_name = '' + self.__subs = [] - self._bins += self.__subs - self._deps += get_test_desc('zdtm/lib/groups')['deps'] - self._env = {'ZDTM_TESTS': self.__real_name} + self._bins += self.__subs + self._deps += get_test_desc('zdtm/lib/groups')['deps'] + self._env = {'ZDTM_TESTS': self.__real_name} - def __get_start_cmd(self, name): - tdir = os.path.dirname(name) - tname = os.path.basename(name) + def __get_start_cmd(self, name): + tdir = os.path.dirname(name) + tname = os.path.basename(name) - s_args = ['make', '--no-print-directory', '-C', tdir] - subprocess.check_call(s_args + [tname + '.cleanout']) - s = subprocess.Popen(s_args + ['--dry-run', tname + '.pid'], stdout = subprocess.PIPE) - cmd = s.stdout.readlines().pop().strip() - s.wait() + s_args = ['make', '--no-print-directory', '-C', tdir] + subprocess.check_call(s_args + [tname + '.cleanout']) + s = subprocess.Popen(s_args + ['--dry-run', tname + '.pid'], + stdout=subprocess.PIPE) + cmd = s.stdout.readlines().pop().strip() + s.wait() - return 'cd /' + tdir + ' && ' + cmd + return 'cd /' + tdir + ' && ' + cmd - def start(self): - if (self.__subs): - with open(self.__real_name + '.start', 'w') as f: - for test in self.__subs: - cmd = self.__get_start_cmd(test) - f.write(cmd + '\n') + def start(self): + if (self.__subs): + with open(self.__real_name + '.start', 'w') as f: + for test in self.__subs: + cmd = self.__get_start_cmd(test) + f.write(cmd + '\n') - with open(self.__real_name + '.stop', 'w') as f: - for test in self.__subs: - f.write('kill -TERM `cat /%s.pid`\n' % test) + with open(self.__real_name + '.stop', 'w') as f: + for test in self.__subs: + f.write('kill -TERM `cat /%s.pid`\n' % test) - zdtm_test.start(self) + zdtm_test.start(self) - def stop(self): - zdtm_test.stop(self) + def stop(self): + zdtm_test.stop(self) - for test in self.__subs: - res = tail(test + '.out') - if 'PASS' not in res.split(): - raise test_fail_exc("sub %s result check" % test) + for test in self.__subs: + res = tail(test + '.out') + if 'PASS' not in res.split(): + raise test_fail_exc("sub %s result check" % test) test_classes = {'zdtm': zdtm_test, 'inhfd': inhfd_test, 'groups': groups_test} @@ -791,495 +828,543 @@ join_ns_file = '/run/netns/zdtm_netns' class criu_cli: - @staticmethod - def run(action, args, criu_bin, fault = None, strace = [], preexec = None, nowait = False): - env = dict(os.environ, ASAN_OPTIONS = "log_path=asan.log:disable_coredump=0:detect_leaks=0") + @staticmethod + def run(action, + args, + criu_bin, + fault=None, + strace=[], + preexec=None, + nowait=False): + env = dict( + os.environ, + ASAN_OPTIONS="log_path=asan.log:disable_coredump=0:detect_leaks=0") - if fault: - print("Forcing %s fault" % fault) - env['CRIU_FAULT'] = fault + if fault: + print("Forcing %s fault" % fault) + env['CRIU_FAULT'] = fault - cr = subprocess.Popen(strace + [criu_bin, action, "--no-default-config"] + args, - env = env, close_fds = False, preexec_fn = preexec) - if nowait: - return cr - return cr.wait() + cr = subprocess.Popen(strace + + [criu_bin, action, "--no-default-config"] + args, + env=env, + close_fds=False, + preexec_fn=preexec) + if nowait: + return cr + return cr.wait() class criu_rpc_process: - def wait(self): - return self.criu.wait_pid(self.pid) + def wait(self): + return self.criu.wait_pid(self.pid) - def terminate(self): - os.kill(self.pid, signal.SIGTERM) + def terminate(self): + os.kill(self.pid, signal.SIGTERM) class criu_rpc: - @staticmethod - def __set_opts(criu, args, ctx): - while len(args) != 0: - arg = args.pop(0) - if arg == '-v4': - criu.opts.log_level = 4 - continue - if arg == '-o': - criu.opts.log_file = args.pop(0) - continue - if arg == '-D': - criu.opts.images_dir_fd = os.open(args.pop(0), os.O_DIRECTORY) - ctx['imgd'] = criu.opts.images_dir_fd - continue - if arg == '-t': - criu.opts.pid = int(args.pop(0)) - continue - if arg == '--pidfile': - ctx['pidf'] = args.pop(0) - continue - if arg == '--timeout': - criu.opts.timeout = int(args.pop(0)) - continue - if arg == '--restore-detached': - # Set by service by default - ctx['rd'] = True - continue - if arg == '--root': - criu.opts.root = args.pop(0) - continue - if arg == '--external': - criu.opts.external.append(args.pop(0)) - continue - if arg == '--status-fd': - fd = int(args.pop(0)) - os.write(fd, b"\0") - fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC) - continue - if arg == '--port': - criu.opts.ps.port = int(args.pop(0)) - continue - if arg == '--address': - criu.opts.ps.address = args.pop(0) - continue - if arg == '--page-server': - continue - if arg == '--prev-images-dir': - criu.opts.parent_img = args.pop(0) - continue - if arg == '--track-mem': - criu.opts.track_mem = True - continue - if arg == '--tcp-established': - criu.opts.tcp_established = True - continue - if arg == '--restore-sibling': - criu.opts.rst_sibling = True - continue - if arg == "--inherit-fd": - inhfd = criu.opts.inherit_fd.add() - key = args.pop(0) - fd, key = key.split(":", 1) - inhfd.fd = int(fd[3:-1]) - inhfd.key = key - continue + @staticmethod + def __set_opts(criu, args, ctx): + while len(args) != 0: + arg = args.pop(0) + if arg == '-v4': + criu.opts.log_level = 4 + continue + if arg == '-o': + criu.opts.log_file = args.pop(0) + continue + if arg == '-D': + criu.opts.images_dir_fd = os.open(args.pop(0), os.O_DIRECTORY) + ctx['imgd'] = criu.opts.images_dir_fd + continue + if arg == '-t': + criu.opts.pid = int(args.pop(0)) + continue + if arg == '--pidfile': + ctx['pidf'] = args.pop(0) + continue + if arg == '--timeout': + criu.opts.timeout = int(args.pop(0)) + continue + if arg == '--restore-detached': + # Set by service by default + ctx['rd'] = True + continue + if arg == '--root': + criu.opts.root = args.pop(0) + continue + if arg == '--external': + criu.opts.external.append(args.pop(0)) + continue + if arg == '--status-fd': + fd = int(args.pop(0)) + os.write(fd, b"\0") + fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC) + continue + if arg == '--port': + criu.opts.ps.port = int(args.pop(0)) + continue + if arg == '--address': + criu.opts.ps.address = args.pop(0) + continue + if arg == '--page-server': + continue + if arg == '--prev-images-dir': + criu.opts.parent_img = args.pop(0) + continue + if arg == '--track-mem': + criu.opts.track_mem = True + continue + if arg == '--tcp-established': + criu.opts.tcp_established = True + continue + if arg == '--restore-sibling': + criu.opts.rst_sibling = True + continue + if arg == "--inherit-fd": + inhfd = criu.opts.inherit_fd.add() + key = args.pop(0) + fd, key = key.split(":", 1) + inhfd.fd = int(fd[3:-1]) + inhfd.key = key + continue - raise test_fail_exc('RPC for %s required' % arg) + raise test_fail_exc('RPC for %s required' % arg) - @staticmethod - def run(action, args, criu_bin, fault = None, strace = [], preexec = None, nowait = False): - if fault: - raise test_fail_exc('RPC and FAULT not supported') - if strace: - raise test_fail_exc('RPC and SAT not supported') - if preexec: - raise test_fail_exc('RPC and PREEXEC not supported') + @staticmethod + def run(action, + args, + criu_bin, + fault=None, + strace=[], + preexec=None, + nowait=False): + if fault: + raise test_fail_exc('RPC and FAULT not supported') + if strace: + raise test_fail_exc('RPC and SAT not supported') + if preexec: + raise test_fail_exc('RPC and PREEXEC not supported') - ctx = {} # Object used to keep info untill action is done - criu = crpc.criu() - criu.use_binary(criu_bin) - criu_rpc.__set_opts(criu, args, ctx) - p = None + ctx = {} # Object used to keep info untill action is done + criu = crpc.criu() + criu.use_binary(criu_bin) + criu_rpc.__set_opts(criu, args, ctx) + p = None - try: - if action == 'dump': - criu.dump() - elif action == 'pre-dump': - criu.pre_dump() - elif action == 'restore': - if 'rd' not in ctx: - raise test_fail_exc('RPC Non-detached restore is impossible') + try: + if action == 'dump': + criu.dump() + elif action == 'pre-dump': + criu.pre_dump() + elif action == 'restore': + if 'rd' not in ctx: + raise test_fail_exc( + 'RPC Non-detached restore is impossible') - res = criu.restore() - pidf = ctx.get('pidf') - if pidf: - with open(pidf, 'w') as fd: - fd.write('%d\n' % res.pid) - elif action == "page-server": - res = criu.page_server_chld() - p = criu_rpc_process() - p.pid = res.pid - p.criu = criu - else: - raise test_fail_exc('RPC for %s required' % action) - except crpc.CRIUExceptionExternal as e: - print("Fail", e) - ret = -1 - else: - ret = 0 + res = criu.restore() + pidf = ctx.get('pidf') + if pidf: + with open(pidf, 'w') as fd: + fd.write('%d\n' % res.pid) + elif action == "page-server": + res = criu.page_server_chld() + p = criu_rpc_process() + p.pid = res.pid + p.criu = criu + else: + raise test_fail_exc('RPC for %s required' % action) + except crpc.CRIUExceptionExternal as e: + print("Fail", e) + ret = -1 + else: + ret = 0 - imgd = ctx.get('imgd') - if imgd: - os.close(imgd) + imgd = ctx.get('imgd') + if imgd: + os.close(imgd) - if nowait and ret == 0: - return p + if nowait and ret == 0: + return p - return ret + return ret class criu: - def __init__(self, opts): - self.__test = None - self.__dump_path = None - self.__iter = 0 - self.__prev_dump_iter = None - self.__page_server = bool(opts['page_server']) - self.__remote_lazy_pages = bool(opts['remote_lazy_pages']) - self.__lazy_pages = (self.__remote_lazy_pages or - bool(opts['lazy_pages'])) - self.__lazy_migrate = bool(opts['lazy_migrate']) - self.__restore_sibling = bool(opts['sibling']) - self.__join_ns = bool(opts['join_ns']) - self.__empty_ns = bool(opts['empty_ns']) - self.__fault = opts['fault'] - self.__script = opts['script'] - self.__sat = bool(opts['sat']) - self.__dedup = bool(opts['dedup']) - self.__mdedup = bool(opts['noauto_dedup']) - self.__user = bool(opts['user']) - self.__leave_stopped = bool(opts['stop']) - self.__criu = (opts['rpc'] and criu_rpc or criu_cli) - self.__show_stats = bool(opts['show_stats']) - self.__lazy_pages_p = None - self.__page_server_p = None - self.__dump_process = None - self.__tls = self.__tls_options() if opts['tls'] else [] - self.__criu_bin = opts['criu_bin'] - self.__crit_bin = opts['crit_bin'] + def __init__(self, opts): + self.__test = None + self.__dump_path = None + self.__iter = 0 + self.__prev_dump_iter = None + self.__page_server = bool(opts['page_server']) + self.__remote_lazy_pages = bool(opts['remote_lazy_pages']) + self.__lazy_pages = (self.__remote_lazy_pages or + bool(opts['lazy_pages'])) + self.__lazy_migrate = bool(opts['lazy_migrate']) + self.__restore_sibling = bool(opts['sibling']) + self.__join_ns = bool(opts['join_ns']) + self.__empty_ns = bool(opts['empty_ns']) + self.__fault = opts['fault'] + self.__script = opts['script'] + self.__sat = bool(opts['sat']) + self.__dedup = bool(opts['dedup']) + self.__mdedup = bool(opts['noauto_dedup']) + self.__user = bool(opts['user']) + self.__leave_stopped = bool(opts['stop']) + self.__criu = (opts['rpc'] and criu_rpc or criu_cli) + self.__show_stats = bool(opts['show_stats']) + self.__lazy_pages_p = None + self.__page_server_p = None + self.__dump_process = None + self.__tls = self.__tls_options() if opts['tls'] else [] + self.__criu_bin = opts['criu_bin'] + self.__crit_bin = opts['crit_bin'] - def fini(self): - if self.__lazy_migrate: - ret = self.__dump_process.wait() - if self.__lazy_pages_p: - ret = self.__lazy_pages_p.wait() - grep_errors(os.path.join(self.__ddir(), "lazy-pages.log")) - self.__lazy_pages_p = None - if ret: - raise test_fail_exc("criu lazy-pages exited with %s" % ret) - if self.__page_server_p: - ret = self.__page_server_p.wait() - grep_errors(os.path.join(self.__ddir(), "page-server.log")) - self.__page_server_p = None - if ret: - raise test_fail_exc("criu page-server exited with %s" % ret) - if self.__dump_process: - ret = self.__dump_process.wait() - grep_errors(os.path.join(self.__ddir(), "dump.log")) - self.__dump_process = None - if ret: - raise test_fail_exc("criu dump exited with %s" % ret) - return + def fini(self): + if self.__lazy_migrate: + ret = self.__dump_process.wait() + if self.__lazy_pages_p: + ret = self.__lazy_pages_p.wait() + grep_errors(os.path.join(self.__ddir(), "lazy-pages.log")) + self.__lazy_pages_p = None + if ret: + raise test_fail_exc("criu lazy-pages exited with %s" % ret) + if self.__page_server_p: + ret = self.__page_server_p.wait() + grep_errors(os.path.join(self.__ddir(), "page-server.log")) + self.__page_server_p = None + if ret: + raise test_fail_exc("criu page-server exited with %s" % ret) + if self.__dump_process: + ret = self.__dump_process.wait() + grep_errors(os.path.join(self.__ddir(), "dump.log")) + self.__dump_process = None + if ret: + raise test_fail_exc("criu dump exited with %s" % ret) + return - def logs(self): - return self.__dump_path + def logs(self): + return self.__dump_path - def set_test(self, test): - self.__test = test - self.__dump_path = "dump/" + test.getname() + "/" + test.getpid() - if os.path.exists(self.__dump_path): - for i in range(100): - newpath = self.__dump_path + "." + str(i) - if not os.path.exists(newpath): - os.rename(self.__dump_path, newpath) - break - else: - raise test_fail_exc("couldn't find dump dir %s" % self.__dump_path) + def set_test(self, test): + self.__test = test + self.__dump_path = "dump/" + test.getname() + "/" + test.getpid() + if os.path.exists(self.__dump_path): + for i in range(100): + newpath = self.__dump_path + "." + str(i) + if not os.path.exists(newpath): + os.rename(self.__dump_path, newpath) + break + else: + raise test_fail_exc("couldn't find dump dir %s" % + self.__dump_path) - os.makedirs(self.__dump_path) + os.makedirs(self.__dump_path) - def cleanup(self): - if self.__dump_path: - print("Removing %s" % self.__dump_path) - shutil.rmtree(self.__dump_path) + def cleanup(self): + if self.__dump_path: + print("Removing %s" % self.__dump_path) + shutil.rmtree(self.__dump_path) - def __tls_options(self): - pki_dir = os.path.dirname(os.path.abspath(__file__)) + "/pki" - return ["--tls", "--tls-no-cn-verify", - "--tls-key", pki_dir + "/key.pem", - "--tls-cert", pki_dir + "/cert.pem", - "--tls-cacert", pki_dir + "/cacert.pem"] + def __tls_options(self): + pki_dir = os.path.dirname(os.path.abspath(__file__)) + "/pki" + return [ + "--tls", "--tls-no-cn-verify", "--tls-key", pki_dir + "/key.pem", + "--tls-cert", pki_dir + "/cert.pem", "--tls-cacert", + pki_dir + "/cacert.pem" + ] - def __ddir(self): - return os.path.join(self.__dump_path, "%d" % self.__iter) + def __ddir(self): + return os.path.join(self.__dump_path, "%d" % self.__iter) - def set_user_id(self): - # Numbers should match those in zdtm_test - os.setresgid(58467, 58467, 58467) - os.setresuid(18943, 18943, 18943) + def set_user_id(self): + # Numbers should match those in zdtm_test + os.setresgid(58467, 58467, 58467) + os.setresuid(18943, 18943, 18943) - def __criu_act(self, action, opts = [], log = None, nowait = False): - if not log: - log = action + ".log" + def __criu_act(self, action, opts=[], log=None, nowait=False): + if not log: + log = action + ".log" - s_args = ["-o", log, "-D", self.__ddir(), "-v4"] + opts + s_args = ["-o", log, "-D", self.__ddir(), "-v4"] + opts - with open(os.path.join(self.__ddir(), action + '.cropt'), 'w') as f: - f.write(' '.join(s_args) + '\n') + with open(os.path.join(self.__ddir(), action + '.cropt'), 'w') as f: + f.write(' '.join(s_args) + '\n') - print("Run criu " + action) + print("Run criu " + action) - strace = [] - if self.__sat: - fname = os.path.join(self.__ddir(), action + '.strace') - print_fname(fname, 'strace') - strace = ["strace", "-o", fname, '-T'] - if action == 'restore': - strace += ['-f'] - s_args += ['--action-script', os.getcwd() + '/../scripts/fake-restore.sh'] + strace = [] + if self.__sat: + fname = os.path.join(self.__ddir(), action + '.strace') + print_fname(fname, 'strace') + strace = ["strace", "-o", fname, '-T'] + if action == 'restore': + strace += ['-f'] + s_args += [ + '--action-script', + os.getcwd() + '/../scripts/fake-restore.sh' + ] - if self.__script: - s_args += ['--action-script', self.__script] + if self.__script: + s_args += ['--action-script', self.__script] - if action == "restore": - preexec = None - else: - preexec = self.__user and self.set_user_id or None + if action == "restore": + preexec = None + else: + preexec = self.__user and self.set_user_id or None - __ddir = self.__ddir() + __ddir = self.__ddir() - status_fds = None - if nowait: - status_fds = os.pipe() - fd = status_fds[1] - fdflags = fcntl.fcntl(fd, fcntl.F_GETFD) - fcntl.fcntl(fd, fcntl.F_SETFD, fdflags & ~fcntl.FD_CLOEXEC) - s_args += ["--status-fd", str(fd)] + status_fds = None + if nowait: + status_fds = os.pipe() + fd = status_fds[1] + fdflags = fcntl.fcntl(fd, fcntl.F_GETFD) + fcntl.fcntl(fd, fcntl.F_SETFD, fdflags & ~fcntl.FD_CLOEXEC) + s_args += ["--status-fd", str(fd)] - with open("/proc/sys/kernel/ns_last_pid") as ns_last_pid_fd: - ns_last_pid = ns_last_pid_fd.read() + with open("/proc/sys/kernel/ns_last_pid") as ns_last_pid_fd: + ns_last_pid = ns_last_pid_fd.read() - ret = self.__criu.run(action, s_args, self.__criu_bin, self.__fault, strace, preexec, nowait) + ret = self.__criu.run(action, s_args, self.__criu_bin, self.__fault, + strace, preexec, nowait) - if nowait: - os.close(status_fds[1]) - if os.read(status_fds[0], 1) != b'\0': - ret = ret.wait() - if self.__test.blocking(): - raise test_fail_expected_exc(action) - else: - raise test_fail_exc("criu %s exited with %s" % (action, ret)) - os.close(status_fds[0]) - return ret + if nowait: + os.close(status_fds[1]) + if os.read(status_fds[0], 1) != b'\0': + ret = ret.wait() + if self.__test.blocking(): + raise test_fail_expected_exc(action) + else: + raise test_fail_exc("criu %s exited with %s" % + (action, ret)) + os.close(status_fds[0]) + return ret - grep_errors(os.path.join(__ddir, log)) - if ret != 0: - if self.__fault and int(self.__fault) < 128: - try_run_hook(self.__test, ["--fault", action]) - if action == "dump": - # create a clean directory for images - os.rename(__ddir, __ddir + ".fail") - os.mkdir(__ddir) - os.chmod(__ddir, 0o777) - else: - # on restore we move only a log file, because we need images - os.rename(os.path.join(__ddir, log), os.path.join(__ddir, log + ".fail")) - # restore ns_last_pid to avoid a case when criu gets - # PID of one of restored processes. - with open("/proc/sys/kernel/ns_last_pid", "w+") as fd: - fd.write(ns_last_pid) - # try again without faults - print("Run criu " + action) - ret = self.__criu.run(action, s_args, self.__criu_bin, False, strace, preexec) - grep_errors(os.path.join(__ddir, log)) - if ret == 0: - return - rst_succeeded = os.access(os.path.join(__ddir, "restore-succeeded"), os.F_OK) - if self.__test.blocking() or (self.__sat and action == 'restore' and rst_succeeded): - raise test_fail_expected_exc(action) - else: - raise test_fail_exc("CRIU %s" % action) + grep_errors(os.path.join(__ddir, log)) + if ret != 0: + if self.__fault and int(self.__fault) < 128: + try_run_hook(self.__test, ["--fault", action]) + if action == "dump": + # create a clean directory for images + os.rename(__ddir, __ddir + ".fail") + os.mkdir(__ddir) + os.chmod(__ddir, 0o777) + else: + # on restore we move only a log file, because we need images + os.rename(os.path.join(__ddir, log), + os.path.join(__ddir, log + ".fail")) + # restore ns_last_pid to avoid a case when criu gets + # PID of one of restored processes. + with open("/proc/sys/kernel/ns_last_pid", "w+") as fd: + fd.write(ns_last_pid) + # try again without faults + print("Run criu " + action) + ret = self.__criu.run(action, s_args, self.__criu_bin, False, + strace, preexec) + grep_errors(os.path.join(__ddir, log)) + if ret == 0: + return + rst_succeeded = os.access( + os.path.join(__ddir, "restore-succeeded"), os.F_OK) + if self.__test.blocking() or (self.__sat and action == 'restore' and + rst_succeeded): + raise test_fail_expected_exc(action) + else: + raise test_fail_exc("CRIU %s" % action) - def __stats_file(self, action): - return os.path.join(self.__ddir(), "stats-%s" % action) + def __stats_file(self, action): + return os.path.join(self.__ddir(), "stats-%s" % action) - def show_stats(self, action): - if not self.__show_stats: - return + def show_stats(self, action): + if not self.__show_stats: + return - subprocess.Popen([self.__crit_bin, "show", self.__stats_file(action)]).wait() + subprocess.Popen([self.__crit_bin, "show", + self.__stats_file(action)]).wait() - def check_pages_counts(self): - if not os.access(self.__stats_file("dump"), os.R_OK): - return + def check_pages_counts(self): + if not os.access(self.__stats_file("dump"), os.R_OK): + return - stats_written = -1 - with open(self.__stats_file("dump"), 'rb') as stfile: - stats = crpc.images.load(stfile) - stent = stats['entries'][0]['dump'] - stats_written = int(stent['shpages_written']) + int(stent['pages_written']) + stats_written = -1 + with open(self.__stats_file("dump"), 'rb') as stfile: + stats = crpc.images.load(stfile) + stent = stats['entries'][0]['dump'] + stats_written = int(stent['shpages_written']) + int( + stent['pages_written']) - real_written = 0 - for f in os.listdir(self.__ddir()): - if f.startswith('pages-'): - real_written += os.path.getsize(os.path.join(self.__ddir(), f)) + real_written = 0 + for f in os.listdir(self.__ddir()): + if f.startswith('pages-'): + real_written += os.path.getsize(os.path.join(self.__ddir(), f)) - r_pages = real_written / mmap.PAGESIZE - r_off = real_written % mmap.PAGESIZE - if (stats_written != r_pages) or (r_off != 0): - print("ERROR: bad page counts, stats = %d real = %d(%d)" % (stats_written, r_pages, r_off)) - raise test_fail_exc("page counts mismatch") + r_pages = real_written / mmap.PAGESIZE + r_off = real_written % mmap.PAGESIZE + if (stats_written != r_pages) or (r_off != 0): + print("ERROR: bad page counts, stats = %d real = %d(%d)" % + (stats_written, r_pages, r_off)) + raise test_fail_exc("page counts mismatch") - def dump(self, action, opts = []): - self.__iter += 1 - os.mkdir(self.__ddir()) - os.chmod(self.__ddir(), 0o777) + def dump(self, action, opts=[]): + self.__iter += 1 + os.mkdir(self.__ddir()) + os.chmod(self.__ddir(), 0o777) - a_opts = ["-t", self.__test.getpid()] - if self.__prev_dump_iter: - a_opts += ["--prev-images-dir", "../%d" % self.__prev_dump_iter, "--track-mem"] - self.__prev_dump_iter = self.__iter + a_opts = ["-t", self.__test.getpid()] + if self.__prev_dump_iter: + a_opts += [ + "--prev-images-dir", + "../%d" % self.__prev_dump_iter, "--track-mem" + ] + self.__prev_dump_iter = self.__iter - if self.__page_server: - print("Adding page server") + if self.__page_server: + print("Adding page server") - ps_opts = ["--port", "12345"] + self.__tls - if self.__dedup: - ps_opts += ["--auto-dedup"] + ps_opts = ["--port", "12345"] + self.__tls + if self.__dedup: + ps_opts += ["--auto-dedup"] - self.__page_server_p = self.__criu_act("page-server", opts = ps_opts, nowait = True) - a_opts += ["--page-server", "--address", "127.0.0.1", "--port", "12345"] + self.__tls + self.__page_server_p = self.__criu_act("page-server", + opts=ps_opts, + nowait=True) + a_opts += [ + "--page-server", "--address", "127.0.0.1", "--port", "12345" + ] + self.__tls - a_opts += self.__test.getdopts() + a_opts += self.__test.getdopts() - if self.__dedup: - a_opts += ["--auto-dedup"] + if self.__dedup: + a_opts += ["--auto-dedup"] - a_opts += ["--timeout", "10"] + a_opts += ["--timeout", "10"] - criu_dir = os.path.dirname(os.getcwd()) - if os.getenv("GCOV"): - a_opts.append('--external') - a_opts.append('mnt[%s]:zdtm' % criu_dir) + criu_dir = os.path.dirname(os.getcwd()) + if os.getenv("GCOV"): + a_opts.append('--external') + a_opts.append('mnt[%s]:zdtm' % criu_dir) - if self.__leave_stopped: - a_opts += ['--leave-stopped'] - if self.__empty_ns: - a_opts += ['--empty-ns', 'net'] + if self.__leave_stopped: + a_opts += ['--leave-stopped'] + if self.__empty_ns: + a_opts += ['--empty-ns', 'net'] - nowait = False - if self.__lazy_migrate and action == "dump": - a_opts += ["--lazy-pages", "--port", "12345"] + self.__tls - nowait = True - self.__dump_process = self.__criu_act(action, opts = a_opts + opts, nowait = nowait) - if self.__mdedup and self.__iter > 1: - self.__criu_act("dedup", opts = []) + nowait = False + if self.__lazy_migrate and action == "dump": + a_opts += ["--lazy-pages", "--port", "12345"] + self.__tls + nowait = True + self.__dump_process = self.__criu_act(action, + opts=a_opts + opts, + nowait=nowait) + if self.__mdedup and self.__iter > 1: + self.__criu_act("dedup", opts=[]) - self.show_stats("dump") - self.check_pages_counts() + self.show_stats("dump") + self.check_pages_counts() - if self.__leave_stopped: - pstree_check_stopped(self.__test.getpid()) - pstree_signal(self.__test.getpid(), signal.SIGKILL) + if self.__leave_stopped: + pstree_check_stopped(self.__test.getpid()) + pstree_signal(self.__test.getpid(), signal.SIGKILL) - if self.__page_server_p: - ret = self.__page_server_p.wait() - grep_errors(os.path.join(self.__ddir(), "page-server.log")) - self.__page_server_p = None - if ret: - raise test_fail_exc("criu page-server exited with %d" % ret) + if self.__page_server_p: + ret = self.__page_server_p.wait() + grep_errors(os.path.join(self.__ddir(), "page-server.log")) + self.__page_server_p = None + if ret: + raise test_fail_exc("criu page-server exited with %d" % ret) - def restore(self): - r_opts = [] - if self.__restore_sibling: - r_opts = ["--restore-sibling"] - self.__test.auto_reap = False - r_opts += self.__test.getropts() - if self.__join_ns: - r_opts.append("--join-ns") - r_opts.append("net:%s" % join_ns_file) - if self.__empty_ns: - r_opts += ['--empty-ns', 'net'] - r_opts += ['--action-script', os.getcwd() + '/empty-netns-prep.sh'] + def restore(self): + r_opts = [] + if self.__restore_sibling: + r_opts = ["--restore-sibling"] + self.__test.auto_reap = False + r_opts += self.__test.getropts() + if self.__join_ns: + r_opts.append("--join-ns") + r_opts.append("net:%s" % join_ns_file) + if self.__empty_ns: + r_opts += ['--empty-ns', 'net'] + r_opts += ['--action-script', os.getcwd() + '/empty-netns-prep.sh'] - if self.__dedup: - r_opts += ["--auto-dedup"] + if self.__dedup: + r_opts += ["--auto-dedup"] - if self.__dedup: - r_opts += ["--auto-dedup"] + self.__prev_dump_iter = None + criu_dir = os.path.dirname(os.getcwd()) + if os.getenv("GCOV"): + r_opts.append('--external') + r_opts.append('mnt[zdtm]:%s' % criu_dir) - self.__prev_dump_iter = None - criu_dir = os.path.dirname(os.getcwd()) - if os.getenv("GCOV"): - r_opts.append('--external') - r_opts.append('mnt[zdtm]:%s' % criu_dir) + if self.__lazy_pages or self.__lazy_migrate: + lp_opts = [] + if self.__remote_lazy_pages or self.__lazy_migrate: + lp_opts += [ + "--page-server", "--port", "12345", "--address", + "127.0.0.1" + ] + self.__tls - if self.__lazy_pages or self.__lazy_migrate: - lp_opts = [] - if self.__remote_lazy_pages or self.__lazy_migrate: - lp_opts += ["--page-server", "--port", "12345", - "--address", "127.0.0.1"] + self.__tls + if self.__remote_lazy_pages: + ps_opts = [ + "--pidfile", "ps.pid", "--port", "12345", "--lazy-pages" + ] + self.__tls + self.__page_server_p = self.__criu_act("page-server", + opts=ps_opts, + nowait=True) + self.__lazy_pages_p = self.__criu_act("lazy-pages", + opts=lp_opts, + nowait=True) + r_opts += ["--lazy-pages"] - if self.__remote_lazy_pages: - ps_opts = ["--pidfile", "ps.pid", - "--port", "12345", "--lazy-pages"] + self.__tls - self.__page_server_p = self.__criu_act("page-server", opts = ps_opts, nowait = True) - self.__lazy_pages_p = self.__criu_act("lazy-pages", opts = lp_opts, nowait = True) - r_opts += ["--lazy-pages"] + if self.__leave_stopped: + r_opts += ['--leave-stopped'] - if self.__leave_stopped: - r_opts += ['--leave-stopped'] + self.__criu_act("restore", opts=r_opts + ["--restore-detached"]) + self.show_stats("restore") - self.__criu_act("restore", opts = r_opts + ["--restore-detached"]) - self.show_stats("restore") + if self.__leave_stopped: + pstree_check_stopped(self.__test.getpid()) + pstree_signal(self.__test.getpid(), signal.SIGCONT) - if self.__leave_stopped: - pstree_check_stopped(self.__test.getpid()) - pstree_signal(self.__test.getpid(), signal.SIGCONT) + @staticmethod + def check(feature): + return criu_cli.run( + "check", ["--no-default-config", "-v0", "--feature", feature], + opts['criu_bin']) == 0 - @staticmethod - def check(feature): - return criu_cli.run("check", ["--no-default-config", "-v0", - "--feature", feature], opts['criu_bin']) == 0 + @staticmethod + def available(): + if not os.access(opts['criu_bin'], os.X_OK): + print("CRIU binary not found at %s" % opts['criu_bin']) + sys.exit(1) - @staticmethod - def available(): - if not os.access(opts['criu_bin'], os.X_OK): - print("CRIU binary not found at %s" % opts['criu_bin']) - sys.exit(1) - - def kill(self): - if self.__lazy_pages_p: - self.__lazy_pages_p.terminate() - print("criu lazy-pages exited with %s" % self.__lazy_pages_p.wait()) - grep_errors(os.path.join(self.__ddir(), "lazy-pages.log")) - self.__lazy_pages_p = None - if self.__page_server_p: - self.__page_server_p.terminate() - print("criu page-server exited with %s" % self.__page_server_p.wait()) - grep_errors(os.path.join(self.__ddir(), "page-server.log")) - self.__page_server_p = None - if self.__dump_process: - self.__dump_process.terminate() - print("criu dump exited with %s" % self.__dump_process.wait()) - grep_errors(os.path.join(self.__ddir(), "dump.log")) - self.__dump_process = None + def kill(self): + if self.__lazy_pages_p: + self.__lazy_pages_p.terminate() + print("criu lazy-pages exited with %s" % + self.__lazy_pages_p.wait()) + grep_errors(os.path.join(self.__ddir(), "lazy-pages.log")) + self.__lazy_pages_p = None + if self.__page_server_p: + self.__page_server_p.terminate() + print("criu page-server exited with %s" % + self.__page_server_p.wait()) + grep_errors(os.path.join(self.__ddir(), "page-server.log")) + self.__page_server_p = None + if self.__dump_process: + self.__dump_process.terminate() + print("criu dump exited with %s" % self.__dump_process.wait()) + grep_errors(os.path.join(self.__ddir(), "dump.log")) + self.__dump_process = None def try_run_hook(test, args): - hname = test.getname() + '.hook' - if os.access(hname, os.X_OK): - print("Running %s(%s)" % (hname, ', '.join(args))) - hook = subprocess.Popen([hname] + args) - if hook.wait() != 0: - raise test_fail_exc("hook " + " ".join(args)) + hname = test.getname() + '.hook' + if os.access(hname, os.X_OK): + print("Running %s(%s)" % (hname, ', '.join(args))) + hook = subprocess.Popen([hname] + args) + if hook.wait() != 0: + raise test_fail_exc("hook " + " ".join(args)) # @@ -1290,583 +1375,615 @@ do_sbs = False def init_sbs(): - if sys.stdout.isatty(): - global do_sbs - do_sbs = True - else: - print("Can't do step-by-step in this runtime") + if sys.stdout.isatty(): + global do_sbs + do_sbs = True + else: + print("Can't do step-by-step in this runtime") def sbs(what): - if do_sbs: - input("Pause at %s. Press Enter to continue." % what) + if do_sbs: + input("Pause at %s. Press Enter to continue." % what) # # Main testing entity -- dump (probably with pre-dumps) and restore # def iter_parm(opt, dflt): - x = ((opt or str(dflt)) + ":0").split(':') - return (range(0, int(x[0])), float(x[1])) + x = ((opt or str(dflt)) + ":0").split(':') + return (range(0, int(x[0])), float(x[1])) def cr(cr_api, test, opts): - if opts['nocr']: - return + if opts['nocr']: + return - cr_api.set_test(test) + cr_api.set_test(test) - iters = iter_parm(opts['iters'], 1) - for i in iters[0]: - pres = iter_parm(opts['pre'], 0) - for p in pres[0]: - if opts['snaps']: - cr_api.dump("dump", opts = ["--leave-running", "--track-mem"]) - else: - cr_api.dump("pre-dump") - try_run_hook(test, ["--post-pre-dump"]) - test.pre_dump_notify() - time.sleep(pres[1]) + iters = iter_parm(opts['iters'], 1) + for i in iters[0]: + pres = iter_parm(opts['pre'], 0) + for p in pres[0]: + if opts['snaps']: + cr_api.dump("dump", opts=["--leave-running", "--track-mem"]) + else: + cr_api.dump("pre-dump") + try_run_hook(test, ["--post-pre-dump"]) + test.pre_dump_notify() + time.sleep(pres[1]) - sbs('pre-dump') + sbs('pre-dump') - os.environ["ZDTM_TEST_PID"] = str(test.getpid()) - if opts['norst']: - try_run_hook(test, ["--pre-dump"]) - cr_api.dump("dump", opts = ["--leave-running"]) - else: - try_run_hook(test, ["--pre-dump"]) - cr_api.dump("dump") - if not opts['lazy_migrate']: - test.gone() - else: - test.unlink_pidfile() - sbs('pre-restore') - try_run_hook(test, ["--pre-restore"]) - cr_api.restore() - os.environ["ZDTM_TEST_PID"] = str(test.getpid()) - os.environ["ZDTM_IMG_DIR"] = cr_api.logs() - try_run_hook(test, ["--post-restore"]) - sbs('post-restore') + os.environ["ZDTM_TEST_PID"] = str(test.getpid()) + if opts['norst']: + try_run_hook(test, ["--pre-dump"]) + cr_api.dump("dump", opts=["--leave-running"]) + else: + try_run_hook(test, ["--pre-dump"]) + cr_api.dump("dump") + if not opts['lazy_migrate']: + test.gone() + else: + test.unlink_pidfile() + sbs('pre-restore') + try_run_hook(test, ["--pre-restore"]) + cr_api.restore() + os.environ["ZDTM_TEST_PID"] = str(test.getpid()) + os.environ["ZDTM_IMG_DIR"] = cr_api.logs() + try_run_hook(test, ["--post-restore"]) + sbs('post-restore') - time.sleep(iters[1]) + time.sleep(iters[1]) # Additional checks that can be done outside of test process + def get_visible_state(test): - maps = {} - files = {} - mounts = {} + maps = {} + files = {} + mounts = {} - if not getattr(test, "static", lambda: False)() or \ - not getattr(test, "ns", lambda: False)(): - return ({}, {}, {}) + if not getattr(test, "static", lambda: False)() or \ + not getattr(test, "ns", lambda: False)(): + return ({}, {}, {}) - r = re.compile('^[0-9]+$') - pids = filter(lambda p: r.match(p), os.listdir("/proc/%s/root/proc/" % test.getpid())) - for pid in pids: - files[pid] = set(os.listdir("/proc/%s/root/proc/%s/fd" % (test.getpid(), pid))) + r = re.compile('^[0-9]+$') + pids = filter(lambda p: r.match(p), + os.listdir("/proc/%s/root/proc/" % test.getpid())) + for pid in pids: + files[pid] = set( + os.listdir("/proc/%s/root/proc/%s/fd" % (test.getpid(), pid))) - cmaps = [[0, 0, ""]] - last = 0 - mapsfd = open("/proc/%s/root/proc/%s/maps" % (test.getpid(), pid)) - for mp in mapsfd: - m = list(map(lambda x: int('0x' + x, 0), mp.split()[0].split('-'))) + cmaps = [[0, 0, ""]] + last = 0 + mapsfd = open("/proc/%s/root/proc/%s/maps" % (test.getpid(), pid)) + for mp in mapsfd: + m = list(map(lambda x: int('0x' + x, 0), mp.split()[0].split('-'))) - m.append(mp.split()[1]) + m.append(mp.split()[1]) - f = "/proc/%s/root/proc/%s/map_files/%s" % (test.getpid(), pid, mp.split()[0]) - if os.access(f, os.F_OK): - st = os.lstat(f) - m.append(oct(st.st_mode)) + f = "/proc/%s/root/proc/%s/map_files/%s" % (test.getpid(), pid, + mp.split()[0]) + if os.access(f, os.F_OK): + st = os.lstat(f) + m.append(oct(st.st_mode)) - if cmaps[last][1] == m[0] and cmaps[last][2] == m[2]: - cmaps[last][1] = m[1] - else: - cmaps.append(m) - last += 1 - mapsfd.close() + if cmaps[last][1] == m[0] and cmaps[last][2] == m[2]: + cmaps[last][1] = m[1] + else: + cmaps.append(m) + last += 1 + mapsfd.close() - maps[pid] = set(map(lambda x: '%x-%x %s' % (x[0], x[1], " ".join(x[2:])), cmaps)) + maps[pid] = set( + map(lambda x: '%x-%x %s' % (x[0], x[1], " ".join(x[2:])), cmaps)) - cmounts = [] - try: - r = re.compile(r"^\S+\s\S+\s\S+\s(\S+)\s(\S+)\s(\S+)\s[^-]*?(shared)?[^-]*?(master)?[^-]*?-") - with open("/proc/%s/root/proc/%s/mountinfo" % (test.getpid(), pid)) as mountinfo: - for m in mountinfo: - cmounts.append(r.match(m).groups()) - except IOError as e: - if e.errno != errno.EINVAL: - raise e - mounts[pid] = cmounts - return files, maps, mounts + cmounts = [] + try: + r = re.compile( + r"^\S+\s\S+\s\S+\s(\S+)\s(\S+)\s(\S+)\s[^-]*?(shared)?[^-]*?(master)?[^-]*?-" + ) + with open("/proc/%s/root/proc/%s/mountinfo" % + (test.getpid(), pid)) as mountinfo: + for m in mountinfo: + cmounts.append(r.match(m).groups()) + except IOError as e: + if e.errno != errno.EINVAL: + raise e + mounts[pid] = cmounts + return files, maps, mounts def check_visible_state(test, state, opts): - new = get_visible_state(test) + new = get_visible_state(test) - for pid in state[0].keys(): - fnew = new[0][pid] - fold = state[0][pid] - if fnew != fold: - print("%s: Old files lost: %s" % (pid, fold - fnew)) - print("%s: New files appeared: %s" % (pid, fnew - fold)) - raise test_fail_exc("fds compare") + for pid in state[0].keys(): + fnew = new[0][pid] + fold = state[0][pid] + if fnew != fold: + print("%s: Old files lost: %s" % (pid, fold - fnew)) + print("%s: New files appeared: %s" % (pid, fnew - fold)) + raise test_fail_exc("fds compare") - old_maps = state[1][pid] - new_maps = new[1][pid] - if os.getenv("COMPAT_TEST"): - # the vsyscall vma isn't unmapped from x32 processes - vsyscall = u"ffffffffff600000-ffffffffff601000 r-xp" - if vsyscall in new_maps and vsyscall not in old_maps: - new_maps.remove(vsyscall) - if old_maps != new_maps: - print("%s: Old maps lost: %s" % (pid, old_maps - new_maps)) - print("%s: New maps appeared: %s" % (pid, new_maps - old_maps)) - if not opts['fault']: # skip parasite blob - raise test_fail_exc("maps compare") + old_maps = state[1][pid] + new_maps = new[1][pid] + if os.getenv("COMPAT_TEST"): + # the vsyscall vma isn't unmapped from x32 processes + vsyscall = u"ffffffffff600000-ffffffffff601000 r-xp" + if vsyscall in new_maps and vsyscall not in old_maps: + new_maps.remove(vsyscall) + if old_maps != new_maps: + print("%s: Old maps lost: %s" % (pid, old_maps - new_maps)) + print("%s: New maps appeared: %s" % (pid, new_maps - old_maps)) + if not opts['fault']: # skip parasite blob + raise test_fail_exc("maps compare") - old_mounts = state[2][pid] - new_mounts = new[2][pid] - for i in range(len(old_mounts)): - m = old_mounts.pop(0) - if m in new_mounts: - new_mounts.remove(m) - else: - old_mounts.append(m) - if old_mounts or new_mounts: - print("%s: Old mounts lost: %s" % (pid, old_mounts)) - print("%s: New mounts appeared: %s" % (pid, new_mounts)) - raise test_fail_exc("mounts compare") + old_mounts = state[2][pid] + new_mounts = new[2][pid] + for i in range(len(old_mounts)): + m = old_mounts.pop(0) + if m in new_mounts: + new_mounts.remove(m) + else: + old_mounts.append(m) + if old_mounts or new_mounts: + print("%s: Old mounts lost: %s" % (pid, old_mounts)) + print("%s: New mounts appeared: %s" % (pid, new_mounts)) + raise test_fail_exc("mounts compare") - if '--link-remap' in test.getdopts(): - import glob - link_remap_list = glob.glob(os.path.dirname(test.getname()) + '/link_remap*') - if link_remap_list: - print("%s: link-remap files left: %s" % (test.getname(), link_remap_list)) - raise test_fail_exc("link remaps left") + if '--link-remap' in test.getdopts(): + import glob + link_remap_list = glob.glob( + os.path.dirname(test.getname()) + '/link_remap*') + if link_remap_list: + print("%s: link-remap files left: %s" % + (test.getname(), link_remap_list)) + raise test_fail_exc("link remaps left") class noop_freezer: - def __init__(self): - self.kernel = False + def __init__(self): + self.kernel = False - def attach(self): - pass + def attach(self): + pass - def freeze(self): - pass + def freeze(self): + pass - def thaw(self): - pass + def thaw(self): + pass - def getdopts(self): - return [] + def getdopts(self): + return [] - def getropts(self): - return [] + def getropts(self): + return [] class cg_freezer: - def __init__(self, path, state): - self.__path = '/sys/fs/cgroup/freezer/' + path - self.__state = state - self.kernel = True + def __init__(self, path, state): + self.__path = '/sys/fs/cgroup/freezer/' + path + self.__state = state + self.kernel = True - def attach(self): - if not os.access(self.__path, os.F_OK): - os.makedirs(self.__path) - with open(self.__path + '/tasks', 'w') as f: - f.write('0') + def attach(self): + if not os.access(self.__path, os.F_OK): + os.makedirs(self.__path) + with open(self.__path + '/tasks', 'w') as f: + f.write('0') - def __set_state(self, state): - with open(self.__path + '/freezer.state', 'w') as f: - f.write(state) + def __set_state(self, state): + with open(self.__path + '/freezer.state', 'w') as f: + f.write(state) - def freeze(self): - if self.__state.startswith('f'): - self.__set_state('FROZEN') + def freeze(self): + if self.__state.startswith('f'): + self.__set_state('FROZEN') - def thaw(self): - if self.__state.startswith('f'): - self.__set_state('THAWED') + def thaw(self): + if self.__state.startswith('f'): + self.__set_state('THAWED') - def getdopts(self): - return ['--freeze-cgroup', self.__path, '--manage-cgroups'] + def getdopts(self): + return ['--freeze-cgroup', self.__path, '--manage-cgroups'] - def getropts(self): - return ['--manage-cgroups'] + def getropts(self): + return ['--manage-cgroups'] def get_freezer(desc): - if not desc: - return noop_freezer() + if not desc: + return noop_freezer() - fd = desc.split(':') - fr = cg_freezer(path = fd[0], state = fd[1]) - return fr + fd = desc.split(':') + fr = cg_freezer(path=fd[0], state=fd[1]) + return fr def cmp_ns(ns1, match, ns2, msg): - ns1_ino = os.stat(ns1).st_ino - ns2_ino = os.stat(ns2).st_ino - if eval("%r %s %r" % (ns1_ino, match, ns2_ino)): - print("%s match (%r %s %r) fail" % (msg, ns1_ino, match, ns2_ino)) - raise test_fail_exc("%s compare" % msg) + ns1_ino = os.stat(ns1).st_ino + ns2_ino = os.stat(ns2).st_ino + if eval("%r %s %r" % (ns1_ino, match, ns2_ino)): + print("%s match (%r %s %r) fail" % (msg, ns1_ino, match, ns2_ino)) + raise test_fail_exc("%s compare" % msg) def check_joinns_state(t): - cmp_ns("/proc/%s/ns/net" % t.getpid(), "!=", join_ns_file, "join-ns") + cmp_ns("/proc/%s/ns/net" % t.getpid(), "!=", join_ns_file, "join-ns") def pstree_each_pid(root_pid): - f_children_path = "/proc/{0}/task/{0}/children".format(root_pid) - child_pids = [] - try: - with open(f_children_path, "r") as f_children: - pid_line = f_children.readline().strip(" \n") - if pid_line: - child_pids += pid_line.split(" ") - except Exception as e: - print("Unable to read /proc/*/children: %s" % e) - return # process is dead + f_children_path = "/proc/{0}/task/{0}/children".format(root_pid) + child_pids = [] + try: + with open(f_children_path, "r") as f_children: + pid_line = f_children.readline().strip(" \n") + if pid_line: + child_pids += pid_line.split(" ") + except Exception as e: + print("Unable to read /proc/*/children: %s" % e) + return # process is dead - yield root_pid - for child_pid in child_pids: - for pid in pstree_each_pid(child_pid): - yield pid + yield root_pid + for child_pid in child_pids: + for pid in pstree_each_pid(child_pid): + yield pid def is_proc_stopped(pid): - def get_thread_status(thread_dir): - try: - with open(os.path.join(thread_dir, "status")) as f_status: - for line in f_status.readlines(): - if line.startswith("State:"): - return line.split(":", 1)[1].strip().split(" ")[0] - except Exception as e: - print("Unable to read a thread status: %s" % e) - pass # process is dead - return None + def get_thread_status(thread_dir): + try: + with open(os.path.join(thread_dir, "status")) as f_status: + for line in f_status.readlines(): + if line.startswith("State:"): + return line.split(":", 1)[1].strip().split(" ")[0] + except Exception as e: + print("Unable to read a thread status: %s" % e) + pass # process is dead + return None - def is_thread_stopped(status): - return (status is None) or (status == "T") or (status == "Z") + def is_thread_stopped(status): + return (status is None) or (status == "T") or (status == "Z") - tasks_dir = "/proc/%s/task" % pid - thread_dirs = [] - try: - thread_dirs = os.listdir(tasks_dir) - except Exception as e: - print("Unable to read threads: %s" % e) - pass # process is dead + tasks_dir = "/proc/%s/task" % pid + thread_dirs = [] + try: + thread_dirs = os.listdir(tasks_dir) + except Exception as e: + print("Unable to read threads: %s" % e) + pass # process is dead - for thread_dir in thread_dirs: - thread_status = get_thread_status(os.path.join(tasks_dir, thread_dir)) - if not is_thread_stopped(thread_status): - return False + for thread_dir in thread_dirs: + thread_status = get_thread_status(os.path.join(tasks_dir, thread_dir)) + if not is_thread_stopped(thread_status): + return False - if not is_thread_stopped(get_thread_status("/proc/%s" % pid)): - return False + if not is_thread_stopped(get_thread_status("/proc/%s" % pid)): + return False - return True + return True def pstree_check_stopped(root_pid): - for pid in pstree_each_pid(root_pid): - if not is_proc_stopped(pid): - raise test_fail_exc("CRIU --leave-stopped %s" % pid) + for pid in pstree_each_pid(root_pid): + if not is_proc_stopped(pid): + raise test_fail_exc("CRIU --leave-stopped %s" % pid) def pstree_signal(root_pid, signal): - for pid in pstree_each_pid(root_pid): - try: - os.kill(int(pid), signal) - except Exception as e: - print("Unable to kill %d: %s" % (pid, e)) - pass # process is dead + for pid in pstree_each_pid(root_pid): + try: + os.kill(int(pid), signal) + except Exception as e: + print("Unable to kill %d: %s" % (pid, e)) + pass # process is dead def do_run_test(tname, tdesc, flavs, opts): - tcname = tname.split('/')[0] - tclass = test_classes.get(tcname, None) - if not tclass: - print("Unknown test class %s" % tcname) - return + tcname = tname.split('/')[0] + tclass = test_classes.get(tcname, None) + if not tclass: + print("Unknown test class %s" % tcname) + return - if opts['report']: - init_report(opts['report']) - if opts['sbs']: - init_sbs() + if opts['report']: + init_report(opts['report']) + if opts['sbs']: + init_sbs() - fcg = get_freezer(opts['freezecg']) + fcg = get_freezer(opts['freezecg']) - for f in flavs: - print_sep("Run %s in %s" % (tname, f)) - if opts['dry_run']: - continue - flav = flavors[f](opts) - t = tclass(tname, tdesc, flav, fcg) - cr_api = criu(opts) + for f in flavs: + print_sep("Run %s in %s" % (tname, f)) + if opts['dry_run']: + continue + flav = flavors[f](opts) + t = tclass(tname, tdesc, flav, fcg) + cr_api = criu(opts) - try: - t.start() - s = get_visible_state(t) - try: - cr(cr_api, t, opts) - except test_fail_expected_exc as e: - if e.cr_action == "dump": - t.stop() - else: - check_visible_state(t, s, opts) - if opts['join_ns']: - check_joinns_state(t) - t.stop() - cr_api.fini() - try_run_hook(t, ["--clean"]) - except test_fail_exc as e: - print_sep("Test %s FAIL at %s" % (tname, e.step), '#') - t.print_output() - t.kill() - cr_api.kill() - try_run_hook(t, ["--clean"]) - if cr_api.logs(): - add_to_report(cr_api.logs(), tname.replace('/', '_') + "_" + f + "/images") - if opts['keep_img'] == 'never': - cr_api.cleanup() - # When option --keep-going not specified this exit - # does two things: exits from subprocess and aborts the - # main script execution on the 1st error met - sys.exit(encode_flav(f)) - else: - if opts['keep_img'] != 'always': - cr_api.cleanup() - print_sep("Test %s PASS" % tname) + try: + t.start() + s = get_visible_state(t) + try: + cr(cr_api, t, opts) + except test_fail_expected_exc as e: + if e.cr_action == "dump": + t.stop() + else: + check_visible_state(t, s, opts) + if opts['join_ns']: + check_joinns_state(t) + t.stop() + cr_api.fini() + try_run_hook(t, ["--clean"]) + except test_fail_exc as e: + print_sep("Test %s FAIL at %s" % (tname, e.step), '#') + t.print_output() + t.kill() + cr_api.kill() + try_run_hook(t, ["--clean"]) + if cr_api.logs(): + add_to_report(cr_api.logs(), + tname.replace('/', '_') + "_" + f + "/images") + if opts['keep_img'] == 'never': + cr_api.cleanup() + # When option --keep-going not specified this exit + # does two things: exits from subprocess and aborts the + # main script execution on the 1st error met + sys.exit(encode_flav(f)) + else: + if opts['keep_img'] != 'always': + cr_api.cleanup() + print_sep("Test %s PASS" % tname) class Launcher: - def __init__(self, opts, nr_tests): - self.__opts = opts - self.__total = nr_tests - self.__runtest = 0 - self.__nr = 0 - self.__max = int(opts['parallel'] or 1) - self.__subs = {} - self.__fail = False - self.__file_report = None - self.__junit_file = None - self.__junit_test_cases = None - self.__failed = [] - self.__nr_skip = 0 - if self.__max > 1 and self.__total > 1: - self.__use_log = True - elif opts['report']: - self.__use_log = True - else: - self.__use_log = False + def __init__(self, opts, nr_tests): + self.__opts = opts + self.__total = nr_tests + self.__runtest = 0 + self.__nr = 0 + self.__max = int(opts['parallel'] or 1) + self.__subs = {} + self.__fail = False + self.__file_report = None + self.__junit_file = None + self.__junit_test_cases = None + self.__failed = [] + self.__nr_skip = 0 + if self.__max > 1 and self.__total > 1: + self.__use_log = True + elif opts['report']: + self.__use_log = True + else: + self.__use_log = False - if opts['report'] and (opts['keep_going'] or self.__total == 1): - global TestSuite, TestCase - from junit_xml import TestSuite, TestCase - now = datetime.datetime.now() - att = 0 - reportname = os.path.join(report_dir, "criu-testreport.tap") - junitreport = os.path.join(report_dir, "criu-testreport.xml") - while os.access(reportname, os.F_OK) or os.access(junitreport, os.F_OK): - reportname = os.path.join(report_dir, "criu-testreport" + ".%d.tap" % att) - junitreport = os.path.join(report_dir, "criu-testreport" + ".%d.xml" % att) - att += 1 + if opts['report'] and (opts['keep_going'] or self.__total == 1): + global TestSuite, TestCase + from junit_xml import TestSuite, TestCase + now = datetime.datetime.now() + att = 0 + reportname = os.path.join(report_dir, "criu-testreport.tap") + junitreport = os.path.join(report_dir, "criu-testreport.xml") + while os.access(reportname, os.F_OK) or os.access( + junitreport, os.F_OK): + reportname = os.path.join(report_dir, + "criu-testreport" + ".%d.tap" % att) + junitreport = os.path.join(report_dir, + "criu-testreport" + ".%d.xml" % att) + att += 1 - self.__junit_file = open(junitreport, 'a') - self.__junit_test_cases = [] + self.__junit_file = open(junitreport, 'a') + self.__junit_test_cases = [] - self.__file_report = open(reportname, 'a') - print(u"TAP version 13", file=self.__file_report) - print(u"# Hardware architecture: " + arch, file=self.__file_report) - print(u"# Timestamp: " + now.strftime("%Y-%m-%d %H:%M") + " (GMT+1)", file=self.__file_report) - print(u"# ", file=self.__file_report) - print(u"1.." + str(nr_tests), file=self.__file_report) - with open("/proc/sys/kernel/tainted") as taintfd: - self.__taint = taintfd.read() - if int(self.__taint, 0) != 0: - print("The kernel is tainted: %r" % self.__taint) - if not opts["ignore_taint"]: - raise Exception("The kernel is tainted: %r" % self.__taint) + self.__file_report = open(reportname, 'a') + print(u"TAP version 13", file=self.__file_report) + print(u"# Hardware architecture: " + arch, file=self.__file_report) + print(u"# Timestamp: " + now.strftime("%Y-%m-%d %H:%M") + + " (GMT+1)", + file=self.__file_report) + print(u"# ", file=self.__file_report) + print(u"1.." + str(nr_tests), file=self.__file_report) + with open("/proc/sys/kernel/tainted") as taintfd: + self.__taint = taintfd.read() + if int(self.__taint, 0) != 0: + print("The kernel is tainted: %r" % self.__taint) + if not opts["ignore_taint"]: + raise Exception("The kernel is tainted: %r" % self.__taint) - def __show_progress(self, msg): - perc = int(self.__nr * 16 / self.__total) - print("=== Run %d/%d %s %s" % (self.__nr, self.__total, '=' * perc + '-' * (16 - perc), msg)) + def __show_progress(self, msg): + perc = int(self.__nr * 16 / self.__total) + print("=== Run %d/%d %s %s" % + (self.__nr, self.__total, '=' * perc + '-' * (16 - perc), msg)) - def skip(self, name, reason): - print("Skipping %s (%s)" % (name, reason)) - self.__nr += 1 - self.__runtest += 1 - self.__nr_skip += 1 + def skip(self, name, reason): + print("Skipping %s (%s)" % (name, reason)) + self.__nr += 1 + self.__runtest += 1 + self.__nr_skip += 1 - if self.__junit_test_cases is not None: - tc = TestCase(name) - tc.add_skipped_info(reason) - self.__junit_test_cases.append(tc) - if self.__file_report: - testline = u"ok %d - %s # SKIP %s" % (self.__runtest, name, reason) - print(testline, file=self.__file_report) + if self.__junit_test_cases is not None: + tc = TestCase(name) + tc.add_skipped_info(reason) + self.__junit_test_cases.append(tc) + if self.__file_report: + testline = u"ok %d - %s # SKIP %s" % (self.__runtest, name, reason) + print(testline, file=self.__file_report) - def run_test(self, name, desc, flavor): + def run_test(self, name, desc, flavor): - if len(self.__subs) >= self.__max: - self.wait() + if len(self.__subs) >= self.__max: + self.wait() - with open("/proc/sys/kernel/tainted") as taintfd: - taint = taintfd.read() - if self.__taint != taint: - raise Exception("The kernel is tainted: %r (%r)" % (taint, self.__taint)) + with open("/proc/sys/kernel/tainted") as taintfd: + taint = taintfd.read() + if self.__taint != taint: + raise Exception("The kernel is tainted: %r (%r)" % + (taint, self.__taint)) - if test_flag(desc, 'excl'): - self.wait_all() + if test_flag(desc, 'excl'): + self.wait_all() - self.__nr += 1 - self.__show_progress(name) + self.__nr += 1 + self.__show_progress(name) - nd = ('nocr', 'norst', 'pre', 'iters', 'page_server', 'sibling', 'stop', 'empty_ns', - 'fault', 'keep_img', 'report', 'snaps', 'sat', 'script', 'rpc', 'lazy_pages', - 'join_ns', 'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup', - 'remote_lazy_pages', 'show_stats', 'lazy_migrate', 'tls', - 'criu_bin', 'crit_bin') - arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd})) + nd = ('nocr', 'norst', 'pre', 'iters', 'page_server', 'sibling', + 'stop', 'empty_ns', 'fault', 'keep_img', 'report', 'snaps', + 'sat', 'script', 'rpc', 'lazy_pages', 'join_ns', 'dedup', 'sbs', + 'freezecg', 'user', 'dry_run', 'noauto_dedup', + 'remote_lazy_pages', 'show_stats', 'lazy_migrate', + 'tls', 'criu_bin', 'crit_bin') + arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd})) - if self.__use_log: - logf = name.replace('/', '_') + ".log" - log = open(logf, "w") - else: - logf = None - log = None + if self.__use_log: + logf = name.replace('/', '_') + ".log" + log = open(logf, "w") + else: + logf = None + log = None - sub = subprocess.Popen(["./zdtm_ct", "zdtm.py"], - env = dict(os.environ, CR_CT_TEST_INFO = arg), - stdout = log, stderr = subprocess.STDOUT, close_fds = True) - self.__subs[sub.pid] = {'sub': sub, 'log': logf, 'name': name, "start": time.time()} + sub = subprocess.Popen(["./zdtm_ct", "zdtm.py"], + env=dict(os.environ, CR_CT_TEST_INFO=arg), + stdout=log, + stderr=subprocess.STDOUT, + close_fds=True) + self.__subs[sub.pid] = { + 'sub': sub, + 'log': logf, + 'name': name, + "start": time.time() + } - if test_flag(desc, 'excl'): - self.wait() + if test_flag(desc, 'excl'): + self.wait() - def __wait_one(self, flags): - pid = -1 - status = -1 - signal.alarm(10) - while True: - try: - pid, status = os.waitpid(0, flags) - except OSError as e: - if e.errno == errno.EINTR: - subprocess.Popen(["ps", "axf"]).wait() - continue - signal.alarm(0) - raise e - else: - break - signal.alarm(0) + def __wait_one(self, flags): + pid = -1 + status = -1 + signal.alarm(10) + while True: + try: + pid, status = os.waitpid(0, flags) + except OSError as e: + if e.errno == errno.EINTR: + subprocess.Popen(["ps", "axf"]).wait() + continue + signal.alarm(0) + raise e + else: + break + signal.alarm(0) - self.__runtest += 1 - if pid != 0: - sub = self.__subs.pop(pid) - tc = None - if self.__junit_test_cases is not None: - tc = TestCase(sub['name'], elapsed_sec=time.time() - sub['start']) - self.__junit_test_cases.append(tc) - if status != 0: - self.__fail = True - failed_flavor = decode_flav(os.WEXITSTATUS(status)) - self.__failed.append([sub['name'], failed_flavor]) - if self.__file_report: - testline = u"not ok %d - %s # flavor %s" % (self.__runtest, sub['name'], failed_flavor) - with open(sub['log']) as sublog: - output = sublog.read() - details = {'output': output} - tc.add_error_info(output = output) - print(testline, file=self.__file_report) - print("%s" % yaml.safe_dump(details, explicit_start=True, - explicit_end=True, default_style='|'), file=self.__file_report) - if sub['log']: - add_to_output(sub['log']) - else: - if self.__file_report: - testline = u"ok %d - %s" % (self.__runtest, sub['name']) - print(testline, file=self.__file_report) + self.__runtest += 1 + if pid != 0: + sub = self.__subs.pop(pid) + tc = None + if self.__junit_test_cases is not None: + tc = TestCase(sub['name'], + elapsed_sec=time.time() - sub['start']) + self.__junit_test_cases.append(tc) + if status != 0: + self.__fail = True + failed_flavor = decode_flav(os.WEXITSTATUS(status)) + self.__failed.append([sub['name'], failed_flavor]) + if self.__file_report: + testline = u"not ok %d - %s # flavor %s" % ( + self.__runtest, sub['name'], failed_flavor) + with open(sub['log']) as sublog: + output = sublog.read() + details = {'output': output} + tc.add_error_info(output=output) + print(testline, file=self.__file_report) + print("%s" % yaml.safe_dump(details, + explicit_start=True, + explicit_end=True, + default_style='|'), + file=self.__file_report) + if sub['log']: + add_to_output(sub['log']) + else: + if self.__file_report: + testline = u"ok %d - %s" % (self.__runtest, sub['name']) + print(testline, file=self.__file_report) - if sub['log']: - with open(sub['log']) as sublog: - print("%s" % sublog.read().encode('ascii', 'ignore').decode('utf-8')) - os.unlink(sub['log']) + if sub['log']: + with open(sub['log']) as sublog: + print("%s" % sublog.read().encode( + 'ascii', 'ignore').decode('utf-8')) + os.unlink(sub['log']) - return True + return True - return False + return False - def __wait_all(self): - while self.__subs: - self.__wait_one(0) + def __wait_all(self): + while self.__subs: + self.__wait_one(0) - def wait(self): - self.__wait_one(0) - while self.__subs: - if not self.__wait_one(os.WNOHANG): - break - if self.__fail and not opts['keep_going']: - raise test_fail_exc('') + def wait(self): + self.__wait_one(0) + while self.__subs: + if not self.__wait_one(os.WNOHANG): + break + if self.__fail and not opts['keep_going']: + raise test_fail_exc('') - def wait_all(self): - self.__wait_all() - if self.__fail and not opts['keep_going']: - raise test_fail_exc('') + def wait_all(self): + self.__wait_all() + if self.__fail and not opts['keep_going']: + raise test_fail_exc('') - def finish(self): - self.__wait_all() - if not opts['fault'] and check_core_files(): - self.__fail = True - if self.__file_report: - ts = TestSuite(opts['title'], self.__junit_test_cases, os.getenv("NODE_NAME")) - self.__junit_file.write(TestSuite.to_xml_string([ts])) - self.__junit_file.close() - self.__file_report.close() + def finish(self): + self.__wait_all() + if not opts['fault'] and check_core_files(): + self.__fail = True + if self.__file_report: + ts = TestSuite(opts['title'], self.__junit_test_cases, + os.getenv("NODE_NAME")) + self.__junit_file.write(TestSuite.to_xml_string([ts])) + self.__junit_file.close() + self.__file_report.close() - if opts['keep_going']: - if self.__fail: - print_sep("%d TEST(S) FAILED (TOTAL %d/SKIPPED %d)" - % (len(self.__failed), self.__total, self.__nr_skip), "#") - for failed in self.__failed: - print(" * %s(%s)" % (failed[0], failed[1])) - else: - print_sep("ALL TEST(S) PASSED (TOTAL %d/SKIPPED %d)" - % (self.__total, self.__nr_skip), "#") + if opts['keep_going']: + if self.__fail: + print_sep( + "%d TEST(S) FAILED (TOTAL %d/SKIPPED %d)" % + (len(self.__failed), self.__total, self.__nr_skip), "#") + for failed in self.__failed: + print(" * %s(%s)" % (failed[0], failed[1])) + else: + print_sep( + "ALL TEST(S) PASSED (TOTAL %d/SKIPPED %d)" % + (self.__total, self.__nr_skip), "#") - if self.__fail: - print_sep("FAIL", "#") - sys.exit(1) + if self.__fail: + print_sep("FAIL", "#") + sys.exit(1) def all_tests(opts): - with open(opts['set'] + '.desc') as fd: - desc = eval(fd.read()) + with open(opts['set'] + '.desc') as fd: + desc = eval(fd.read()) - files = [] - mask = stat.S_IFREG | stat.S_IXUSR - for d in os.walk(desc['dir']): - for f in d[2]: - fp = os.path.join(d[0], f) - st = os.lstat(fp) - if (st.st_mode & mask) != mask: - continue - if stat.S_IFMT(st.st_mode) in [stat.S_IFLNK, stat.S_IFSOCK]: - continue - files.append(fp) - excl = list(map(lambda x: os.path.join(desc['dir'], x), desc['exclude'])) - tlist = filter(lambda x: - not x.endswith('.checkskip') and - not x.endswith('.hook') and - x not in excl, - map(lambda x: x.strip(), files) - ) - return tlist + files = [] + mask = stat.S_IFREG | stat.S_IXUSR + for d in os.walk(desc['dir']): + for f in d[2]: + fp = os.path.join(d[0], f) + st = os.lstat(fp) + if (st.st_mode & mask) != mask: + continue + if stat.S_IFMT(st.st_mode) in [stat.S_IFLNK, stat.S_IFSOCK]: + continue + files.append(fp) + excl = list(map(lambda x: os.path.join(desc['dir'], x), desc['exclude'])) + tlist = filter( + lambda x: not x.endswith('.checkskip') and not x.endswith('.hook') and + x not in excl, map(lambda x: x.strip(), files)) + return tlist # Descriptor for abstract test not in list @@ -1874,355 +1991,363 @@ default_test = {} def get_test_desc(tname): - d_path = tname + '.desc' - if os.access(d_path, os.F_OK) and os.path.getsize(d_path) > 0: - with open(d_path) as fd: - return eval(fd.read()) + d_path = tname + '.desc' + if os.access(d_path, os.F_OK) and os.path.getsize(d_path) > 0: + with open(d_path) as fd: + return eval(fd.read()) - return default_test + return default_test def self_checkskip(tname): - chs = tname + '.checkskip' - if os.access(chs, os.X_OK): - ch = subprocess.Popen([chs]) - return not ch.wait() == 0 + chs = tname + '.checkskip' + if os.access(chs, os.X_OK): + ch = subprocess.Popen([chs]) + return not ch.wait() == 0 - return False + return False def print_fname(fname, typ): - print("=[%s]=> %s" % (typ, fname)) + print("=[%s]=> %s" % (typ, fname)) -def print_sep(title, sep = "=", width = 80): - print((" " + title + " ").center(width, sep)) +def print_sep(title, sep="=", width=80): + print((" " + title + " ").center(width, sep)) def print_error(line): - line = line.rstrip() - print(line) - if line.endswith('>'): # combine pie output - return True - return False + line = line.rstrip() + print(line) + if line.endswith('>'): # combine pie output + return True + return False def grep_errors(fname): - first = True - print_next = False - before = [] - with open(fname) as fd: - for l in fd: - before.append(l) - if len(before) > 5: - before.pop(0) - if "Error" in l or "Warn" in l: - if first: - print_fname(fname, 'log') - print_sep("grep Error", "-", 60) - first = False - for i in before: - print_next = print_error(i) - before = [] - else: - if print_next: - print_next = print_error(l) - before = [] - if not first: - print_sep("ERROR OVER", "-", 60) + first = True + print_next = False + before = [] + with open(fname) as fd: + for l in fd: + before.append(l) + if len(before) > 5: + before.pop(0) + if "Error" in l or "Warn" in l: + if first: + print_fname(fname, 'log') + print_sep("grep Error", "-", 60) + first = False + for i in before: + print_next = print_error(i) + before = [] + else: + if print_next: + print_next = print_error(l) + before = [] + if not first: + print_sep("ERROR OVER", "-", 60) def run_tests(opts): - excl = None - features = {} + excl = None + features = {} - if opts['pre'] or opts['snaps']: - if not criu.check("mem_dirty_track"): - print("Tracking memory is not available") - return + if opts['pre'] or opts['snaps']: + if not criu.check("mem_dirty_track"): + print("Tracking memory is not available") + return - if opts['all']: - torun = all_tests(opts) - run_all = True - elif opts['tests']: - r = re.compile(opts['tests']) - torun = filter(lambda x: r.match(x), all_tests(opts)) - run_all = True - elif opts['test']: - torun = opts['test'] - run_all = False - elif opts['from']: - if not os.access(opts['from'], os.R_OK): - print("No such file") - return + if opts['all']: + torun = all_tests(opts) + run_all = True + elif opts['tests']: + r = re.compile(opts['tests']) + torun = filter(lambda x: r.match(x), all_tests(opts)) + run_all = True + elif opts['test']: + torun = opts['test'] + run_all = False + elif opts['from']: + if not os.access(opts['from'], os.R_OK): + print("No such file") + return - with open(opts['from']) as fd: - torun = map(lambda x: x.strip(), fd) - opts['keep_going'] = False - run_all = True - else: - print("Specify test with -t or -a") - return + with open(opts['from']) as fd: + torun = map(lambda x: x.strip(), fd) + opts['keep_going'] = False + run_all = True + else: + print("Specify test with -t or -a") + return - torun = list(torun) - if opts['keep_going'] and len(torun) < 2: - print("[WARNING] Option --keep-going is more useful when running multiple tests") - opts['keep_going'] = False + torun = list(torun) + if opts['keep_going'] and len(torun) < 2: + print( + "[WARNING] Option --keep-going is more useful when running multiple tests" + ) + opts['keep_going'] = False - if opts['exclude']: - excl = re.compile(".*(" + "|".join(opts['exclude']) + ")") - print("Compiled exclusion list") + if opts['exclude']: + excl = re.compile(".*(" + "|".join(opts['exclude']) + ")") + print("Compiled exclusion list") - if opts['report']: - init_report(opts['report']) + if opts['report']: + init_report(opts['report']) - if opts['parallel'] and opts['freezecg']: - print("Parallel launch with freezer not supported") - opts['parallel'] = None + if opts['parallel'] and opts['freezecg']: + print("Parallel launch with freezer not supported") + opts['parallel'] = None - if opts['join_ns']: - if subprocess.Popen(["ip", "netns", "add", "zdtm_netns"]).wait(): - raise Exception("Unable to create a network namespace") - if subprocess.Popen(["ip", "netns", "exec", "zdtm_netns", "ip", "link", "set", "up", "dev", "lo"]).wait(): - raise Exception("ip link set up dev lo") + if opts['join_ns']: + if subprocess.Popen(["ip", "netns", "add", "zdtm_netns"]).wait(): + raise Exception("Unable to create a network namespace") + if subprocess.Popen([ + "ip", "netns", "exec", "zdtm_netns", "ip", "link", "set", "up", + "dev", "lo" + ]).wait(): + raise Exception("ip link set up dev lo") - if opts['lazy_pages'] or opts['remote_lazy_pages'] or opts['lazy_migrate']: - uffd = criu.check("uffd") - uffd_noncoop = criu.check("uffd-noncoop") - if not uffd: - raise Exception("UFFD is not supported, cannot run with --lazy-pages") - if not uffd_noncoop: - # Most tests will work with 4.3 - 4.11 - print("[WARNING] Non-cooperative UFFD is missing, some tests might spuriously fail") + if opts['lazy_pages'] or opts['remote_lazy_pages'] or opts['lazy_migrate']: + uffd = criu.check("uffd") + uffd_noncoop = criu.check("uffd-noncoop") + if not uffd: + raise Exception( + "UFFD is not supported, cannot run with --lazy-pages") + if not uffd_noncoop: + # Most tests will work with 4.3 - 4.11 + print( + "[WARNING] Non-cooperative UFFD is missing, some tests might spuriously fail" + ) - launcher = Launcher(opts, len(torun)) - try: - for t in torun: - global arch + launcher = Launcher(opts, len(torun)) + try: + for t in torun: + global arch - if excl and excl.match(t): - launcher.skip(t, "exclude") - continue + if excl and excl.match(t): + launcher.skip(t, "exclude") + continue - tdesc = get_test_desc(t) - if tdesc.get('arch', arch) != arch: - launcher.skip(t, "arch %s" % tdesc['arch']) - continue + tdesc = get_test_desc(t) + if tdesc.get('arch', arch) != arch: + launcher.skip(t, "arch %s" % tdesc['arch']) + continue - if test_flag(tdesc, 'reqrst') and opts['norst']: - launcher.skip(t, "restore stage is required") - continue + if test_flag(tdesc, 'reqrst') and opts['norst']: + launcher.skip(t, "restore stage is required") + continue - if run_all and test_flag(tdesc, 'noauto'): - launcher.skip(t, "manual run only") - continue + if run_all and test_flag(tdesc, 'noauto'): + launcher.skip(t, "manual run only") + continue - feat_list = tdesc.get('feature', "") - for feat in feat_list.split(): - if feat not in features: - print("Checking feature %s" % feat) - features[feat] = criu.check(feat) + feat_list = tdesc.get('feature', "") + for feat in feat_list.split(): + if feat not in features: + print("Checking feature %s" % feat) + features[feat] = criu.check(feat) - if not features[feat]: - launcher.skip(t, "no %s feature" % feat) - feat_list = None - break - if feat_list is None: - continue + if not features[feat]: + launcher.skip(t, "no %s feature" % feat) + feat_list = None + break + if feat_list is None: + continue - if self_checkskip(t): - launcher.skip(t, "checkskip failed") - continue + if self_checkskip(t): + launcher.skip(t, "checkskip failed") + continue - if opts['user']: - if test_flag(tdesc, 'suid'): - launcher.skip(t, "suid test in user mode") - continue - if test_flag(tdesc, 'nouser'): - launcher.skip(t, "criu root prio needed") - continue + if opts['user']: + if test_flag(tdesc, 'suid'): + launcher.skip(t, "suid test in user mode") + continue + if test_flag(tdesc, 'nouser'): + launcher.skip(t, "criu root prio needed") + continue - if opts['join_ns']: - if test_flag(tdesc, 'samens'): - launcher.skip(t, "samens test in the same namespace") - continue + if opts['join_ns']: + if test_flag(tdesc, 'samens'): + launcher.skip(t, "samens test in the same namespace") + continue - if opts['lazy_pages'] or opts['remote_lazy_pages'] or opts['lazy_migrate']: - if test_flag(tdesc, 'nolazy'): - launcher.skip(t, "lazy pages are not supported") - continue + if opts['lazy_pages'] or opts['remote_lazy_pages'] or opts[ + 'lazy_migrate']: + if test_flag(tdesc, 'nolazy'): + launcher.skip(t, "lazy pages are not supported") + continue - if opts['remote_lazy_pages']: - if test_flag(tdesc, 'noremotelazy'): - launcher.skip(t, "remote lazy pages are not supported") - continue + if opts['remote_lazy_pages']: + if test_flag(tdesc, 'noremotelazy'): + launcher.skip(t, "remote lazy pages are not supported") + continue - test_flavs = tdesc.get('flavor', 'h ns uns').split() - opts_flavs = (opts['flavor'] or 'h,ns,uns').split(',') - if opts_flavs != ['best']: - run_flavs = set(test_flavs) & set(opts_flavs) - else: - run_flavs = set([test_flavs.pop()]) - if not criu.check("userns"): - run_flavs -= set(['uns']) - if opts['user']: - # FIXME -- probably uns will make sense - run_flavs -= set(['ns', 'uns']) + test_flavs = tdesc.get('flavor', 'h ns uns').split() + opts_flavs = (opts['flavor'] or 'h,ns,uns').split(',') + if opts_flavs != ['best']: + run_flavs = set(test_flavs) & set(opts_flavs) + else: + run_flavs = set([test_flavs.pop()]) + if not criu.check("userns"): + run_flavs -= set(['uns']) + if opts['user']: + # FIXME -- probably uns will make sense + run_flavs -= set(['ns', 'uns']) - # remove ns and uns flavor in join_ns - if opts['join_ns']: - run_flavs -= set(['ns', 'uns']) - if opts['empty_ns']: - run_flavs -= set(['h']) + # remove ns and uns flavor in join_ns + if opts['join_ns']: + run_flavs -= set(['ns', 'uns']) + if opts['empty_ns']: + run_flavs -= set(['h']) - if run_flavs: - launcher.run_test(t, tdesc, run_flavs) - else: - launcher.skip(t, "no flavors") - finally: - launcher.finish() - if opts['join_ns']: - subprocess.Popen(["ip", "netns", "delete", "zdtm_netns"]).wait() + if run_flavs: + launcher.run_test(t, tdesc, run_flavs) + else: + launcher.skip(t, "no flavors") + finally: + launcher.finish() + if opts['join_ns']: + subprocess.Popen(["ip", "netns", "delete", "zdtm_netns"]).wait() sti_fmt = "%-40s%-10s%s" def show_test_info(t): - tdesc = get_test_desc(t) - flavs = tdesc.get('flavor', '') - return sti_fmt % (t, flavs, tdesc.get('flags', '')) + tdesc = get_test_desc(t) + flavs = tdesc.get('flavor', '') + return sti_fmt % (t, flavs, tdesc.get('flags', '')) def list_tests(opts): - tlist = all_tests(opts) - if opts['info']: - print(sti_fmt % ('Name', 'Flavors', 'Flags')) - tlist = map(lambda x: show_test_info(x), tlist) - print('\n'.join(tlist)) + tlist = all_tests(opts) + if opts['info']: + print(sti_fmt % ('Name', 'Flavors', 'Flags')) + tlist = map(lambda x: show_test_info(x), tlist) + print('\n'.join(tlist)) class group: - def __init__(self, tname, tdesc): - self.__tests = [tname] - self.__desc = tdesc - self.__deps = set() + def __init__(self, tname, tdesc): + self.__tests = [tname] + self.__desc = tdesc + self.__deps = set() - def __is_mergeable_desc(self, desc): - # For now make it full match - if self.__desc.get('flags') != desc.get('flags'): - return False - if self.__desc.get('flavor') != desc.get('flavor'): - return False - if self.__desc.get('arch') != desc.get('arch'): - return False - if self.__desc.get('opts') != desc.get('opts'): - return False - if self.__desc.get('feature') != desc.get('feature'): - return False - return True + def __is_mergeable_desc(self, desc): + # For now make it full match + if self.__desc.get('flags') != desc.get('flags'): + return False + if self.__desc.get('flavor') != desc.get('flavor'): + return False + if self.__desc.get('arch') != desc.get('arch'): + return False + if self.__desc.get('opts') != desc.get('opts'): + return False + if self.__desc.get('feature') != desc.get('feature'): + return False + return True - def merge(self, tname, tdesc): - if not self.__is_mergeable_desc(tdesc): - return False + def merge(self, tname, tdesc): + if not self.__is_mergeable_desc(tdesc): + return False - self.__deps |= set(tdesc.get('deps', [])) - self.__tests.append(tname) - return True + self.__deps |= set(tdesc.get('deps', [])) + self.__tests.append(tname) + return True - def size(self): - return len(self.__tests) + def size(self): + return len(self.__tests) - # common method to write a "meta" auxiliary script (hook/checkskip) - # which will call all tests' scripts in turn - def __dump_meta(self, fname, ext): - scripts = filter(lambda names: os.access(names[1], os.X_OK), - map(lambda test: (test, test + ext), - self.__tests)) - if scripts: - f = open(fname + ext, "w") - f.write("#!/bin/sh -e\n") + # common method to write a "meta" auxiliary script (hook/checkskip) + # which will call all tests' scripts in turn + def __dump_meta(self, fname, ext): + scripts = filter(lambda names: os.access(names[1], os.X_OK), + map(lambda test: (test, test + ext), self.__tests)) + if scripts: + f = open(fname + ext, "w") + f.write("#!/bin/sh -e\n") - for test, script in scripts: - f.write("echo 'Running %s for %s'\n" % (ext, test)) - f.write('%s "$@"\n' % script) + for test, script in scripts: + f.write("echo 'Running %s for %s'\n" % (ext, test)) + f.write('%s "$@"\n' % script) - f.write("echo 'All %s scripts OK'\n" % ext) - f.close() - os.chmod(fname + ext, 0o700) + f.write("echo 'All %s scripts OK'\n" % ext) + f.close() + os.chmod(fname + ext, 0o700) - def dump(self, fname): - f = open(fname, "w") - for t in self.__tests: - f.write(t + '\n') - f.close() - os.chmod(fname, 0o700) + def dump(self, fname): + f = open(fname, "w") + for t in self.__tests: + f.write(t + '\n') + f.close() + os.chmod(fname, 0o700) - if len(self.__desc) or len(self.__deps): - f = open(fname + '.desc', "w") - if len(self.__deps): - self.__desc['deps'] = list(self.__deps) - f.write(repr(self.__desc)) - f.close() + if len(self.__desc) or len(self.__deps): + f = open(fname + '.desc', "w") + if len(self.__deps): + self.__desc['deps'] = list(self.__deps) + f.write(repr(self.__desc)) + f.close() - # write "meta" .checkskip and .hook scripts - self.__dump_meta(fname, '.checkskip') - self.__dump_meta(fname, '.hook') + # write "meta" .checkskip and .hook scripts + self.__dump_meta(fname, '.checkskip') + self.__dump_meta(fname, '.hook') def group_tests(opts): - excl = None - groups = [] - pend_groups = [] - maxs = int(opts['max_size']) + excl = None + groups = [] + pend_groups = [] + maxs = int(opts['max_size']) - if not os.access("groups", os.F_OK): - os.mkdir("groups") + if not os.access("groups", os.F_OK): + os.mkdir("groups") - tlist = all_tests(opts) - random.shuffle(tlist) - if opts['exclude']: - excl = re.compile(".*(" + "|".join(opts['exclude']) + ")") - print("Compiled exclusion list") + tlist = all_tests(opts) + random.shuffle(tlist) + if opts['exclude']: + excl = re.compile(".*(" + "|".join(opts['exclude']) + ")") + print("Compiled exclusion list") - for t in tlist: - if excl and excl.match(t): - continue + for t in tlist: + if excl and excl.match(t): + continue - td = get_test_desc(t) + td = get_test_desc(t) - for g in pend_groups: - if g.merge(t, td): - if g.size() == maxs: - pend_groups.remove(g) - groups.append(g) - break - else: - g = group(t, td) - pend_groups.append(g) + for g in pend_groups: + if g.merge(t, td): + if g.size() == maxs: + pend_groups.remove(g) + groups.append(g) + break + else: + g = group(t, td) + pend_groups.append(g) - groups += pend_groups + groups += pend_groups - nr = 0 - suf = opts['name'] or 'group' + nr = 0 + suf = opts['name'] or 'group' - for g in groups: - if maxs > 1 and g.size() == 1: # Not much point in group test for this - continue + for g in groups: + if maxs > 1 and g.size() == 1: # Not much point in group test for this + continue - fn = os.path.join("groups", "%s.%d" % (suf, nr)) - g.dump(fn) - nr += 1 + fn = os.path.join("groups", "%s.%d" % (suf, nr)) + g.dump(fn) + nr += 1 - print("Generated %d group(s)" % nr) + print("Generated %d group(s)" % nr) def clean_stuff(opts): - print("Cleaning %s" % opts['what']) - if opts['what'] == 'nsroot': - for f in flavors: - f = flavors[f] - f.clean() + print("Cleaning %s" % opts['what']) + if opts['what'] == 'nsroot': + for f in flavors: + f = flavors[f] + f.clean() # @@ -2230,103 +2355,167 @@ def clean_stuff(opts): # if 'CR_CT_TEST_INFO' in os.environ: - # Fork here, since we're new pidns init and are supposed to - # collect this namespace's zombies - status = 0 - pid = os.fork() - if pid == 0: - tinfo = eval(os.environ['CR_CT_TEST_INFO']) - do_run_test(tinfo[0], tinfo[1], tinfo[2], tinfo[3]) - else: - while True: - wpid, status = os.wait() - if wpid == pid: - if os.WIFEXITED(status): - status = os.WEXITSTATUS(status) - else: - status = 1 - break + # Fork here, since we're new pidns init and are supposed to + # collect this namespace's zombies + status = 0 + pid = os.fork() + if pid == 0: + tinfo = eval(os.environ['CR_CT_TEST_INFO']) + do_run_test(tinfo[0], tinfo[1], tinfo[2], tinfo[3]) + else: + while True: + wpid, status = os.wait() + if wpid == pid: + if os.WIFEXITED(status): + status = os.WEXITSTATUS(status) + else: + status = 1 + break - sys.exit(status) + sys.exit(status) p = argparse.ArgumentParser("CRIU test suite") -p.add_argument("--debug", help = "Print what's being executed", action = 'store_true') -p.add_argument("--set", help = "Which set of tests to use", default = 'zdtm') +p.add_argument("--debug", + help="Print what's being executed", + action='store_true') +p.add_argument("--set", help="Which set of tests to use", default='zdtm') -sp = p.add_subparsers(help = "Use --help for list of actions") +sp = p.add_subparsers(help="Use --help for list of actions") -rp = sp.add_parser("run", help = "Run test(s)") -rp.set_defaults(action = run_tests) -rp.add_argument("-a", "--all", action = 'store_true') -rp.add_argument("-t", "--test", help = "Test name", action = 'append') -rp.add_argument("-T", "--tests", help = "Regexp") -rp.add_argument("-F", "--from", help = "From file") -rp.add_argument("-f", "--flavor", help = "Flavor to run") -rp.add_argument("-x", "--exclude", help = "Exclude tests from --all run", action = 'append') +rp = sp.add_parser("run", help="Run test(s)") +rp.set_defaults(action=run_tests) +rp.add_argument("-a", "--all", action='store_true') +rp.add_argument("-t", "--test", help="Test name", action='append') +rp.add_argument("-T", "--tests", help="Regexp") +rp.add_argument("-F", "--from", help="From file") +rp.add_argument("-f", "--flavor", help="Flavor to run") +rp.add_argument("-x", + "--exclude", + help="Exclude tests from --all run", + action='append') -rp.add_argument("--sibling", help = "Restore tests as siblings", action = 'store_true') -rp.add_argument("--join-ns", help = "Restore tests and join existing namespace", action = 'store_true') -rp.add_argument("--empty-ns", help = "Restore tests in empty net namespace", action = 'store_true') -rp.add_argument("--pre", help = "Do some pre-dumps before dump (n[:pause])") -rp.add_argument("--snaps", help = "Instead of pre-dumps do full dumps", action = 'store_true') -rp.add_argument("--dedup", help = "Auto-deduplicate images on iterations", action = 'store_true') -rp.add_argument("--noauto-dedup", help = "Manual deduplicate images on iterations", action = 'store_true') -rp.add_argument("--nocr", help = "Do not CR anything, just check test works", action = 'store_true') -rp.add_argument("--norst", help = "Don't restore tasks, leave them running after dump", action = 'store_true') -rp.add_argument("--stop", help = "Check that --leave-stopped option stops ps tree.", action = 'store_true') -rp.add_argument("--iters", help = "Do CR cycle several times before check (n[:pause])") -rp.add_argument("--fault", help = "Test fault injection") -rp.add_argument("--sat", help = "Generate criu strace-s for sat tool (restore is fake, images are kept)", action = 'store_true') -rp.add_argument("--sbs", help = "Do step-by-step execution, asking user for keypress to continue", action = 'store_true') -rp.add_argument("--freezecg", help = "Use freeze cgroup (path:state)") -rp.add_argument("--user", help = "Run CRIU as regular user", action = 'store_true') -rp.add_argument("--rpc", help = "Run CRIU via RPC rather than CLI", action = 'store_true') +rp.add_argument("--sibling", + help="Restore tests as siblings", + action='store_true') +rp.add_argument("--join-ns", + help="Restore tests and join existing namespace", + action='store_true') +rp.add_argument("--empty-ns", + help="Restore tests in empty net namespace", + action='store_true') +rp.add_argument("--pre", help="Do some pre-dumps before dump (n[:pause])") +rp.add_argument("--snaps", + help="Instead of pre-dumps do full dumps", + action='store_true') +rp.add_argument("--dedup", + help="Auto-deduplicate images on iterations", + action='store_true') +rp.add_argument("--noauto-dedup", + help="Manual deduplicate images on iterations", + action='store_true') +rp.add_argument("--nocr", + help="Do not CR anything, just check test works", + action='store_true') +rp.add_argument("--norst", + help="Don't restore tasks, leave them running after dump", + action='store_true') +rp.add_argument("--stop", + help="Check that --leave-stopped option stops ps tree.", + action='store_true') +rp.add_argument("--iters", + help="Do CR cycle several times before check (n[:pause])") +rp.add_argument("--fault", help="Test fault injection") +rp.add_argument( + "--sat", + help="Generate criu strace-s for sat tool (restore is fake, images are kept)", + action='store_true') +rp.add_argument( + "--sbs", + help="Do step-by-step execution, asking user for keypress to continue", + action='store_true') +rp.add_argument("--freezecg", help="Use freeze cgroup (path:state)") +rp.add_argument("--user", help="Run CRIU as regular user", action='store_true') +rp.add_argument("--rpc", + help="Run CRIU via RPC rather than CLI", + action='store_true') -rp.add_argument("--page-server", help = "Use page server dump", action = 'store_true') -rp.add_argument("-p", "--parallel", help = "Run test in parallel") -rp.add_argument("--dry-run", help="Don't run tests, just pretend to", action='store_true') +rp.add_argument("--page-server", + help="Use page server dump", + action='store_true') +rp.add_argument("--remote", + help="Use remote option for diskless C/R", + action='store_true') +rp.add_argument("-p", "--parallel", help="Run test in parallel") +rp.add_argument("--dry-run", + help="Don't run tests, just pretend to", + action='store_true') rp.add_argument("--script", help="Add script to get notified by criu") -rp.add_argument("-k", "--keep-img", help = "Whether or not to keep images after test", - choices = ['always', 'never', 'failed'], default = 'failed') -rp.add_argument("--report", help = "Generate summary report in directory") -rp.add_argument("--keep-going", help = "Keep running tests in spite of failures", action = 'store_true') -rp.add_argument("--ignore-taint", help = "Don't care about a non-zero kernel taint flag", action = 'store_true') -rp.add_argument("--lazy-pages", help = "restore pages on demand", action = 'store_true') -rp.add_argument("--lazy-migrate", help = "restore pages on demand", action = 'store_true') -rp.add_argument("--remote-lazy-pages", help = "simulate lazy migration", action = 'store_true') -rp.add_argument("--tls", help = "use TLS for migration", action = 'store_true') -rp.add_argument("--title", help = "A test suite title", default = "criu") -rp.add_argument("--show-stats", help = "Show criu statistics", action = 'store_true') -rp.add_argument("--criu-bin", help = "Path to criu binary", default = '../criu/criu') -rp.add_argument("--crit-bin", help = "Path to crit binary", default = '../crit/crit') +rp.add_argument("-k", + "--keep-img", + help="Whether or not to keep images after test", + choices=['always', 'never', 'failed'], + default='failed') +rp.add_argument("--report", help="Generate summary report in directory") +rp.add_argument("--keep-going", + help="Keep running tests in spite of failures", + action='store_true') +rp.add_argument("--ignore-taint", + help="Don't care about a non-zero kernel taint flag", + action='store_true') +rp.add_argument("--lazy-pages", + help="restore pages on demand", + action='store_true') +rp.add_argument("--lazy-migrate", + help="restore pages on demand", + action='store_true') +rp.add_argument("--remote-lazy-pages", + help="simulate lazy migration", + action='store_true') +rp.add_argument("--tls", help="use TLS for migration", action='store_true') +rp.add_argument("--title", help="A test suite title", default="criu") +rp.add_argument("--show-stats", + help="Show criu statistics", + action='store_true') +rp.add_argument("--criu-bin", + help="Path to criu binary", + default='../criu/criu') +rp.add_argument("--crit-bin", + help="Path to crit binary", + default='../crit/crit') -lp = sp.add_parser("list", help = "List tests") -lp.set_defaults(action = list_tests) -lp.add_argument('-i', '--info', help = "Show more info about tests", action = 'store_true') +lp = sp.add_parser("list", help="List tests") +lp.set_defaults(action=list_tests) +lp.add_argument('-i', + '--info', + help="Show more info about tests", + action='store_true') -gp = sp.add_parser("group", help = "Generate groups") -gp.set_defaults(action = group_tests) -gp.add_argument("-m", "--max-size", help = "Maximum number of tests in group") -gp.add_argument("-n", "--name", help = "Common name for group tests") -gp.add_argument("-x", "--exclude", help = "Exclude tests from --all run", action = 'append') +gp = sp.add_parser("group", help="Generate groups") +gp.set_defaults(action=group_tests) +gp.add_argument("-m", "--max-size", help="Maximum number of tests in group") +gp.add_argument("-n", "--name", help="Common name for group tests") +gp.add_argument("-x", + "--exclude", + help="Exclude tests from --all run", + action='append') -cp = sp.add_parser("clean", help = "Clean something") -cp.set_defaults(action = clean_stuff) -cp.add_argument("what", choices = ['nsroot']) +cp = sp.add_parser("clean", help="Clean something") +cp.set_defaults(action=clean_stuff) +cp.add_argument("what", choices=['nsroot']) opts = vars(p.parse_args()) if opts.get('sat', False): - opts['keep_img'] = 'always' + opts['keep_img'] = 'always' if opts['debug']: - sys.settrace(traceit) + sys.settrace(traceit) if opts['action'] == 'run': - criu.available() + criu.available() for tst in test_classes.values(): - tst.available() + tst.available() opts['action'](opts) for tst in test_classes.values(): - tst.cleanup() + tst.cleanup() From 4c1ee3e227045fc1dc07b10ac7a538a68299693b Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 29 Jul 2019 22:07:10 +0100 Subject: [PATCH 2159/4375] test/other: Resolve Py3 compatibility issues When Python 2 is not installed we assume that /usr/bin/python refers to version 3 of Python and the executable /usr/bin/python2 does not exist. This commit also resolves a compatibility issue with Popen where in Py2 file descriptors will be inherited by the child process and in Py3 they will be closed by default. Signed-off-by: Radostin Stoyanov --- soccr/test/run.py | 2 +- test/check_actions.py | 2 +- test/others/ext-tty/run.py | 2 +- test/others/mounts/mounts.sh | 2 +- test/others/rpc/config_file.py | 15 ++++++++++----- test/others/rpc/errno.py | 2 +- test/others/rpc/ps_test.py | 2 +- test/others/rpc/restore-loop.py | 2 +- test/others/rpc/test.py | 2 +- test/others/rpc/version.py | 17 ++++++++++------- test/others/shell-job/run.py | 6 +++--- 11 files changed, 31 insertions(+), 23 deletions(-) diff --git a/soccr/test/run.py b/soccr/test/run.py index 446584a71..1ffe58a58 100644 --- a/soccr/test/run.py +++ b/soccr/test/run.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python import sys, os import hashlib diff --git a/test/check_actions.py b/test/check_actions.py index ae909e668..4973e3938 100755 --- a/test/check_actions.py +++ b/test/check_actions.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python import sys import os diff --git a/test/others/ext-tty/run.py b/test/others/ext-tty/run.py index b1dcb4a5a..2c0bacc84 100755 --- a/test/others/ext-tty/run.py +++ b/test/others/ext-tty/run.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python import subprocess import os, sys, time, signal, pty diff --git a/test/others/mounts/mounts.sh b/test/others/mounts/mounts.sh index a9a1cc80c..19116d0cf 100755 --- a/test/others/mounts/mounts.sh +++ b/test/others/mounts/mounts.sh @@ -20,7 +20,7 @@ for i in `cat /proc/self/mounts | awk '{ print $2 }'`; do umount -l $i done -python2 mounts.py +python mounts.py kill $INMNTNS_PID while :; do sleep 10 diff --git a/test/others/rpc/config_file.py b/test/others/rpc/config_file.py index 3579ac76f..e4b395e31 100755 --- a/test/others/rpc/config_file.py +++ b/test/others/rpc/config_file.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python import os import socket @@ -15,10 +15,15 @@ does_not_exist = 'does-not.exist' def setup_swrk(): print('Connecting to CRIU in swrk mode.') - css = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) - swrk = subprocess.Popen(['./criu', "swrk", "%d" % css[0].fileno()]) - css[0].close() - return swrk, css[1] + s1, s2 = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) + + kwargs = {} + if sys.version_info.major == 3: + kwargs["pass_fds"] = [s1.fileno()] + + swrk = subprocess.Popen(['./criu', "swrk", "%d" % s1.fileno()], **kwargs) + s1.close() + return swrk, s2 def setup_config_file(content): diff --git a/test/others/rpc/errno.py b/test/others/rpc/errno.py index 49cb622de..01a6eee7b 100755 --- a/test/others/rpc/errno.py +++ b/test/others/rpc/errno.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python # Test criu errno import socket, os, errno diff --git a/test/others/rpc/ps_test.py b/test/others/rpc/ps_test.py index d16efd3f6..b51357d42 100755 --- a/test/others/rpc/ps_test.py +++ b/test/others/rpc/ps_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python import socket, os, sys, errno import rpc_pb2 as rpc diff --git a/test/others/rpc/restore-loop.py b/test/others/rpc/restore-loop.py index c81567426..84a2ce56d 100755 --- a/test/others/rpc/restore-loop.py +++ b/test/others/rpc/restore-loop.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python import socket, os, sys import rpc_pb2 as rpc diff --git a/test/others/rpc/test.py b/test/others/rpc/test.py index 9a35e0e97..80f6338f4 100755 --- a/test/others/rpc/test.py +++ b/test/others/rpc/test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python import socket, os, sys import rpc_pb2 as rpc diff --git a/test/others/rpc/version.py b/test/others/rpc/version.py index f978c6c37..3b8f1b961 100755 --- a/test/others/rpc/version.py +++ b/test/others/rpc/version.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python import socket import sys @@ -7,11 +7,14 @@ import subprocess print('Connecting to CRIU in swrk mode to check the version:') -css = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) -swrk = subprocess.Popen(['./criu', "swrk", "%d" % css[0].fileno()]) -css[0].close() +s1, s2 = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) -s = css[1] +kwargs = {} +if sys.version_info.major == 3: + kwargs["pass_fds"] = [s2.fileno()] + +swrk = subprocess.Popen(['./criu', "swrk", "%d" % s2.fileno()], **kwargs) +s2.close() # Create criu msg, set it's type to dump request # and set dump options. Checkout more options in protobuf/rpc.proto @@ -19,12 +22,12 @@ req = rpc.criu_req() req.type = rpc.VERSION # Send request -s.send(req.SerializeToString()) +s1.send(req.SerializeToString()) # Recv response resp = rpc.criu_resp() MAX_MSG_SIZE = 1024 -resp.ParseFromString(s.recv(MAX_MSG_SIZE)) +resp.ParseFromString(s1.recv(MAX_MSG_SIZE)) if resp.type != rpc.VERSION: print('RPC: Unexpected msg type') diff --git a/test/others/shell-job/run.py b/test/others/shell-job/run.py index bd5c42509..a59945d6a 100755 --- a/test/others/shell-job/run.py +++ b/test/others/shell-job/run.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python import os, pty, sys, subprocess import termios, fcntl, time @@ -9,11 +9,11 @@ os.chdir(os.getcwd()) def create_pty(): (fd1, fd2) = pty.openpty() - return (os.fdopen(fd1, "w+"), os.fdopen(fd2, "w+")) + return (os.fdopen(fd1, "wb"), os.fdopen(fd2, "wb")) if not os.access("work", os.X_OK): - os.mkdir("work", 0755) + os.mkdir("work", 0o755) open("running", "w").close() m, s = create_pty() From 6b615ca15277fc14b52a09b4eb18314b7c6cbe75 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 31 Jul 2019 09:46:18 +0100 Subject: [PATCH 2160/4375] test/others: Reuse setup_swrk() Reduce code duplication by taking setup_swrk() function into a separate module that can be reused in multiple places. Signed-off-by: Radostin Stoyanov --- test/others/rpc/config_file.py | 17 ++--------------- test/others/rpc/setup_swrk.py | 16 ++++++++++++++++ test/others/rpc/version.py | 13 +++---------- 3 files changed, 21 insertions(+), 25 deletions(-) create mode 100644 test/others/rpc/setup_swrk.py diff --git a/test/others/rpc/config_file.py b/test/others/rpc/config_file.py index e4b395e31..7b07bc145 100755 --- a/test/others/rpc/config_file.py +++ b/test/others/rpc/config_file.py @@ -1,31 +1,18 @@ #!/usr/bin/python import os -import socket import sys import rpc_pb2 as rpc import argparse -import subprocess from tempfile import mkstemp import time +from setup_swrk import setup_swrk + log_file = 'config_file_test.log' does_not_exist = 'does-not.exist' -def setup_swrk(): - print('Connecting to CRIU in swrk mode.') - s1, s2 = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) - - kwargs = {} - if sys.version_info.major == 3: - kwargs["pass_fds"] = [s1.fileno()] - - swrk = subprocess.Popen(['./criu', "swrk", "%d" % s1.fileno()], **kwargs) - s1.close() - return swrk, s2 - - def setup_config_file(content): # Creating a temporary file which will be used as configuration file. fd, path = mkstemp() diff --git a/test/others/rpc/setup_swrk.py b/test/others/rpc/setup_swrk.py new file mode 100644 index 000000000..c7f84f952 --- /dev/null +++ b/test/others/rpc/setup_swrk.py @@ -0,0 +1,16 @@ +import sys +import socket +import subprocess + +def setup_swrk(): + print('Connecting to CRIU in swrk mode.') + s1, s2 = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) + + kwargs = {} + if sys.version_info.major == 3: + kwargs["pass_fds"] = [s1.fileno()] + + swrk = subprocess.Popen(['./criu', "swrk", "%d" % s1.fileno()], **kwargs) + s1.close() + return swrk, s2 + diff --git a/test/others/rpc/version.py b/test/others/rpc/version.py index 3b8f1b961..9d7fa745b 100755 --- a/test/others/rpc/version.py +++ b/test/others/rpc/version.py @@ -1,20 +1,13 @@ #!/usr/bin/python -import socket import sys import rpc_pb2 as rpc -import subprocess + +from setup_swrk import setup_swrk print('Connecting to CRIU in swrk mode to check the version:') -s1, s2 = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) - -kwargs = {} -if sys.version_info.major == 3: - kwargs["pass_fds"] = [s2.fileno()] - -swrk = subprocess.Popen(['./criu', "swrk", "%d" % s2.fileno()], **kwargs) -s2.close() +swrk, s1 = setup_swrk() # Create criu msg, set it's type to dump request # and set dump options. Checkout more options in protobuf/rpc.proto From 34dbf67b240f6fb97f576a81c96ea6ce46a8e288 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 1 Jul 2019 17:43:56 +0300 Subject: [PATCH 2161/4375] pyimages: Add pb2dict.py to checked and fix warnings/errors Signed-off-by: Pavel Emelyanov --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 0b49364fb..0140330e1 100644 --- a/Makefile +++ b/Makefile @@ -384,6 +384,7 @@ lint: flake8 --config=scripts/flake8.cfg test/zdtm.py flake8 --config=scripts/flake8.cfg test/inhfd/*.py flake8 --config=scripts/flake8.cfg test/others/rpc/config_file.py + flake8 --config=scripts/flake8.cfg lib/py/images/pb2dict.py include Makefile.install From 72402c6e7a4a9a70eefd534f91bcbe068736276d Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 28 Jun 2019 20:17:35 +0300 Subject: [PATCH 2162/4375] py: Fix tabs in code comments These were left by yapf formatter Signed-off-by: Pavel Emelyanov --- coredump/criu_coredump/coredump.py | 130 ++++++++++++++--------------- coredump/criu_coredump/elf.py | 12 +-- lib/py/criu.py | 74 ++++++++-------- lib/py/images/images.py | 92 ++++++++++---------- scripts/magic-gen.py | 4 +- 5 files changed, 156 insertions(+), 156 deletions(-) diff --git a/coredump/criu_coredump/coredump.py b/coredump/criu_coredump/coredump.py index 9b2c6c60c..bc53a7705 100644 --- a/coredump/criu_coredump/coredump.py +++ b/coredump/criu_coredump/coredump.py @@ -9,24 +9,24 @@ # # On my x86_64 systems with fresh kernel ~3.17 core dump looks like: # -# 1) Elf file header; -# 2) PT_NOTE program header describing notes section; -# 3) PT_LOAD program headers for (almost?) each vma; -# 4) NT_PRPSINFO note with elf_prpsinfo inside; -# 5) An array of notes for each thread of the process: -# NT_PRSTATUS note with elf_prstatus inside; -# NT_FPREGSET note with elf_fpregset inside; -# NT_X86_XSTATE note with x86 extended state using xsave; -# NT_SIGINFO note with siginfo_t inside; -# 6) NT_AUXV note with auxv; -# 7) NT_FILE note with mapped files; -# 8) VMAs themselves; +# 1) Elf file header; +# 2) PT_NOTE program header describing notes section; +# 3) PT_LOAD program headers for (almost?) each vma; +# 4) NT_PRPSINFO note with elf_prpsinfo inside; +# 5) An array of notes for each thread of the process: +# NT_PRSTATUS note with elf_prstatus inside; +# NT_FPREGSET note with elf_fpregset inside; +# NT_X86_XSTATE note with x86 extended state using xsave; +# NT_SIGINFO note with siginfo_t inside; +# 6) NT_AUXV note with auxv; +# 7) NT_FILE note with mapped files; +# 8) VMAs themselves; # # Or, you can represent it in less details as: -# 1) Elf file header; -# 2) Program table; -# 3) Notes; -# 4) VMAs contents; +# 1) Elf file header; +# 2) Program table; +# 3) Notes; +# 4) VMAs contents; # import io import elf @@ -65,9 +65,9 @@ class elf_note: class coredump: """ - A class to keep elf core dump components inside and - functions to properly write them to file. - """ + A class to keep elf core dump components inside and + functions to properly write them to file. + """ ehdr = None # Elf ehdr; phdrs = [] # Array of Phdrs; notes = [] # Array of elf_notes; @@ -77,8 +77,8 @@ class coredump: def write(self, f): """ - Write core dump to file f. - """ + Write core dump to file f. + """ buf = io.BytesIO() buf.write(self.ehdr) @@ -117,8 +117,8 @@ class coredump: class coredump_generator: """ - Generate core dump from criu images. - """ + Generate core dump from criu images. + """ coredumps = {} # coredumps by pid; pstree = {} # process info by pid; @@ -129,8 +129,8 @@ class coredump_generator: def _img_open_and_strip(self, name, single=False, pid=None): """ - Load criu image and strip it from magic and redundant list. - """ + Load criu image and strip it from magic and redundant list. + """ path = self._imgs_dir + "/" + name if pid: path += "-" + str(pid) @@ -146,8 +146,8 @@ class coredump_generator: def __call__(self, imgs_dir): """ - Parse criu images stored in directory imgs_dir to fill core dumps. - """ + Parse criu images stored in directory imgs_dir to fill core dumps. + """ self._imgs_dir = imgs_dir pstree = self._img_open_and_strip("pstree") @@ -171,9 +171,9 @@ class coredump_generator: def write(self, coredumps_dir, pid=None): """ - Write core dumpt to cores_dir directory. Specify pid to choose - core dump of only one process. - """ + Write core dumpt to cores_dir directory. Specify pid to choose + core dump of only one process. + """ for p in self.coredumps: if pid and p != pid: continue @@ -182,8 +182,8 @@ class coredump_generator: def _gen_coredump(self, pid): """ - Generate core dump for pid. - """ + Generate core dump for pid. + """ cd = coredump() # Generate everything backwards so it is easier to calculate offset. @@ -196,8 +196,8 @@ class coredump_generator: def _gen_ehdr(self, pid, phdrs): """ - Generate elf header for process pid with program headers phdrs. - """ + Generate elf header for process pid with program headers phdrs. + """ ehdr = elf.Elf64_Ehdr() ctypes.memset(ctypes.addressof(ehdr), 0, ctypes.sizeof(ehdr)) @@ -223,8 +223,8 @@ class coredump_generator: def _gen_phdrs(self, pid, notes, vmas): """ - Generate program headers for process pid. - """ + Generate program headers for process pid. + """ phdrs = [] offset = ctypes.sizeof(elf.Elf64_Ehdr()) @@ -272,8 +272,8 @@ class coredump_generator: def _gen_prpsinfo(self, pid): """ - Generate NT_PRPSINFO note for process pid. - """ + Generate NT_PRPSINFO note for process pid. + """ pstree = self.pstree[pid] core = self.cores[pid] @@ -324,8 +324,8 @@ class coredump_generator: def _gen_prstatus(self, pid, tid): """ - Generate NT_PRSTATUS note for thread tid of process pid. - """ + Generate NT_PRSTATUS note for thread tid of process pid. + """ core = self.cores[tid] regs = core["thread_info"]["gpregs"] pstree = self.pstree[pid] @@ -382,8 +382,8 @@ class coredump_generator: def _gen_fpregset(self, pid, tid): """ - Generate NT_FPREGSET note for thread tid of process pid. - """ + Generate NT_FPREGSET note for thread tid of process pid. + """ core = self.cores[tid] regs = core["thread_info"]["fpregs"] @@ -402,7 +402,7 @@ class coredump_generator: *regs["st_space"]) fpregset.xmm_space = (ctypes.c_uint * len(regs["xmm_space"]))( *regs["xmm_space"]) - #fpregset.padding = regs["padding"] unused + #fpregset.padding = regs["padding"] unused nhdr = elf.Elf64_Nhdr() nhdr.n_namesz = 5 @@ -418,8 +418,8 @@ class coredump_generator: def _gen_x86_xstate(self, pid, tid): """ - Generate NT_X86_XSTATE note for thread tid of process pid. - """ + Generate NT_X86_XSTATE note for thread tid of process pid. + """ core = self.cores[tid] fpregs = core["thread_info"]["fpregs"] @@ -459,8 +459,8 @@ class coredump_generator: def _gen_siginfo(self, pid, tid): """ - Generate NT_SIGINFO note for thread tid of process pid. - """ + Generate NT_SIGINFO note for thread tid of process pid. + """ siginfo = elf.siginfo_t() # FIXME zeroify everything for now ctypes.memset(ctypes.addressof(siginfo), 0, ctypes.sizeof(siginfo)) @@ -479,8 +479,8 @@ class coredump_generator: def _gen_auxv(self, pid): """ - Generate NT_AUXV note for thread tid of process pid. - """ + Generate NT_AUXV note for thread tid of process pid. + """ mm = self.mms[pid] num_auxv = len(mm["mm_saved_auxv"]) / 2 @@ -506,8 +506,8 @@ class coredump_generator: def _gen_files(self, pid): """ - Generate NT_FILE note for process pid. - """ + Generate NT_FILE note for process pid. + """ mm = self.mms[pid] class mmaped_file_info: @@ -597,8 +597,8 @@ class coredump_generator: def _gen_notes(self, pid): """ - Generate notes for core dump of process pid. - """ + Generate notes for core dump of process pid. + """ notes = [] notes.append(self._gen_prpsinfo(pid)) @@ -622,8 +622,8 @@ class coredump_generator: def _get_page(self, pid, page_no): """ - Try to find memory page page_no in pages.img image for process pid. - """ + Try to find memory page page_no in pages.img image for process pid. + """ pagemap = self.pagemaps[pid] # First entry is pagemap_head, we will need it later to open @@ -654,8 +654,8 @@ class coredump_generator: def _gen_mem_chunk(self, pid, vma, size): """ - Obtain vma contents for process pid. - """ + Obtain vma contents for process pid. + """ f = None if size == 0: @@ -749,8 +749,8 @@ class coredump_generator: def _gen_cmdline(self, pid): """ - Generate full command with arguments. - """ + Generate full command with arguments. + """ mm = self.mms[pid] vma = {} @@ -768,8 +768,8 @@ class coredump_generator: def _get_vma_dump_size(self, vma): """ - Calculate amount of vma to put into core dump. - """ + Calculate amount of vma to put into core dump. + """ if vma["status"] & status["VMA_AREA_VVAR"] or \ vma["status"] & status["VMA_AREA_VSYSCALL"] or \ vma["status"] & status["VMA_AREA_VDSO"]: @@ -791,8 +791,8 @@ class coredump_generator: def _get_vma_flags(self, vma): """ - Convert vma flags int elf flags. - """ + Convert vma flags int elf flags. + """ flags = 0 if vma['prot'] & prot["PROT_READ"]: @@ -808,8 +808,8 @@ class coredump_generator: def _gen_vmas(self, pid): """ - Generate vma contents for core dump for process pid. - """ + Generate vma contents for core dump for process pid. + """ mm = self.mms[pid] class vma_class: diff --git a/coredump/criu_coredump/elf.py b/coredump/criu_coredump/elf.py index 65da583c3..e65919e6b 100644 --- a/coredump/criu_coredump/elf.py +++ b/coredump/criu_coredump/elf.py @@ -120,9 +120,9 @@ NT_FPREGSET = 2 # #define NT_FPREGSET 2 /* Contains copy of f NT_PRPSINFO = 3 # #define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ NT_AUXV = 6 # #define NT_AUXV 6 /* Contains copy of auxv array */ NT_SIGINFO = 0x53494749 # #define NT_SIGINFO 0x53494749 /* Contains copy of siginfo_t, -# size might increase */ +# size might increase */ NT_FILE = 0x46494c45 # #define NT_FILE 0x46494c45 /* Contains information about mapped -# files */ +# files */ NT_X86_XSTATE = 0x202 # #define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ @@ -259,7 +259,7 @@ class user_regs_struct(ctypes.Structure): # struct user_regs_struct ] # }; -#elf_greg_t = ctypes.c_ulonglong +#elf_greg_t = ctypes.c_ulonglong #ELF_NGREG = ctypes.sizeof(user_regs_struct)/ctypes.sizeof(elf_greg_t) #elf_gregset_t = elf_greg_t*ELF_NGREG elf_gregset_t = user_regs_struct @@ -450,7 +450,7 @@ class _siginfo_t_U_sigpoll(ctypes.Structure): # struct ] # } _sigpoll; - # /* SIGSYS. */ + # /* SIGSYS. */ class _siginfo_t_U_sigsys(ctypes.Structure): # struct _fields_ = [ # { ("_call_addr", ctypes.c_void_p @@ -515,7 +515,7 @@ class _siginfo_t_U(ctypes.Union): # union # int si_fd; # } _sigpoll; # - # /* SIGSYS. */ + # /* SIGSYS. */ ("_sigsys", _siginfo_t_U_sigpoll) # struct # { # void *_call_addr; /* Calling user insn. */ @@ -587,7 +587,7 @@ class siginfo_t(ctypes.Structure): # typedef struct # int si_fd; # } _sigpoll; # - # /* SIGSYS. */ + # /* SIGSYS. */ # struct # { # void *_call_addr; /* Calling user insn. */ diff --git a/lib/py/criu.py b/lib/py/criu.py index d94fea9e1..f3e018095 100644 --- a/lib/py/criu.py +++ b/lib/py/criu.py @@ -11,8 +11,8 @@ import pycriu.rpc_pb2 as rpc class _criu_comm: """ - Base class for communication classes. - """ + Base class for communication classes. + """ COMM_SK = 0 COMM_FD = 1 COMM_BIN = 2 @@ -22,22 +22,22 @@ class _criu_comm: def connect(self, daemon): """ - Connect to criu and return socket object. - daemon -- is for whether or not criu should daemonize if executing criu from binary(comm_bin). - """ + Connect to criu and return socket object. + daemon -- is for whether or not criu should daemonize if executing criu from binary(comm_bin). + """ pass def disconnect(self): """ - Disconnect from criu. - """ + Disconnect from criu. + """ pass class _criu_comm_sk(_criu_comm): """ - Communication class for unix socket. - """ + Communication class for unix socket. + """ def __init__(self, sk_path): self.comm_type = self.COMM_SK @@ -55,8 +55,8 @@ class _criu_comm_sk(_criu_comm): class _criu_comm_fd(_criu_comm): """ - Communication class for file descriptor. - """ + Communication class for file descriptor. + """ def __init__(self, fd): self.comm_type = self.COMM_FD @@ -74,8 +74,8 @@ class _criu_comm_fd(_criu_comm): class _criu_comm_bin(_criu_comm): """ - Communication class for binary. - """ + Communication class for binary. + """ def __init__(self, bin_path): self.comm_type = self.COMM_BIN @@ -139,8 +139,8 @@ class _criu_comm_bin(_criu_comm): class CRIUException(Exception): """ - Exception class for handling and storing criu errors. - """ + Exception class for handling and storing criu errors. + """ typ = None _str = None @@ -150,8 +150,8 @@ class CRIUException(Exception): class CRIUExceptionInternal(CRIUException): """ - Exception class for handling and storing internal errors. - """ + Exception class for handling and storing internal errors. + """ def __init__(self, typ, s): self.typ = typ @@ -161,8 +161,8 @@ class CRIUExceptionInternal(CRIUException): class CRIUExceptionExternal(CRIUException): """ - Exception class for handling and storing criu RPC errors. - """ + Exception class for handling and storing criu RPC errors. + """ def __init__(self, req_typ, resp_typ, errno): self.typ = req_typ @@ -196,8 +196,8 @@ class CRIUExceptionExternal(CRIUException): class criu: """ - Call criu through RPC. - """ + Call criu through RPC. + """ opts = None #CRIU options in pb format _comm = None #Communication method @@ -209,26 +209,26 @@ class criu: def use_sk(self, sk_name): """ - Access criu using unix socket which that belongs to criu service daemon. - """ + Access criu using unix socket which that belongs to criu service daemon. + """ self._comm = _criu_comm_sk(sk_name) def use_fd(self, fd): """ - Access criu using provided fd. - """ + Access criu using provided fd. + """ self._comm = _criu_comm_fd(fd) def use_binary(self, bin_name): """ - Access criu by execing it using provided path to criu binary. - """ + Access criu by execing it using provided path to criu binary. + """ self._comm = _criu_comm_bin(bin_name) def _send_req_and_recv_resp(self, req): """ - As simple as send request and receive response. - """ + As simple as send request and receive response. + """ # In case of self-dump we need to spawn criu swrk detached # from our current process, as criu has a hard time separating # process resources from its own if criu is located in a same @@ -262,8 +262,8 @@ class criu: def check(self): """ - Checks whether the kernel support is up-to-date. - """ + Checks whether the kernel support is up-to-date. + """ req = rpc.criu_req() req.type = rpc.CHECK @@ -274,8 +274,8 @@ class criu: def dump(self): """ - Checkpoint a process/tree identified by opts.pid. - """ + Checkpoint a process/tree identified by opts.pid. + """ req = rpc.criu_req() req.type = rpc.DUMP req.opts.MergeFrom(self.opts) @@ -289,8 +289,8 @@ class criu: def pre_dump(self): """ - Checkpoint a process/tree identified by opts.pid. - """ + Checkpoint a process/tree identified by opts.pid. + """ req = rpc.criu_req() req.type = rpc.PRE_DUMP req.opts.MergeFrom(self.opts) @@ -304,8 +304,8 @@ class criu: def restore(self): """ - Restore a process/tree. - """ + Restore a process/tree. + """ req = rpc.criu_req() req.type = rpc.RESTORE req.opts.MergeFrom(self.opts) diff --git a/lib/py/images/images.py b/lib/py/images/images.py index 28c6d9e1f..f4517d845 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -12,8 +12,8 @@ # SIZE ::= "32 bit integer, equals the PAYLOAD length" # # Images v1.1 NOTE: MAGIC now consist of 2 32 bit integers, first one is -# MAGIC_COMMON or MAGIC_SERVICE and the second one is same as MAGIC -# in images V1.0. We don't keep "first" magic in json images. +# MAGIC_COMMON or MAGIC_SERVICE and the second one is same as MAGIC +# in images V1.0. We don't keep "first" magic in json images. # # In order to convert images to human-readable format, we use dict(json). # Using json not only allows us to easily read\write images, but also @@ -23,18 +23,18 @@ # Using dict(json) format, criu images can be described like: # # { -# 'magic' : 'FOO', -# 'entries' : [ -# entry, -# ... -# ] +# 'magic' : 'FOO', +# 'entries' : [ +# entry, +# ... +# ] # } # # Entry, in its turn, could be described as: # # { -# pb_msg, -# 'extra' : extra_msg +# pb_msg, +# 'extra' : extra_msg # } # import io @@ -72,23 +72,23 @@ class MagicException(Exception): # format to/from dict(json). class entry_handler: """ - Generic class to handle loading/dumping criu images - entries from/to bin format to/from dict(json). - """ + Generic class to handle loading/dumping criu images + entries from/to bin format to/from dict(json). + """ def __init__(self, payload, extra_handler=None): """ - Sets payload class and extra handler class. - """ + Sets payload class and extra handler class. + """ self.payload = payload self.extra_handler = extra_handler def load(self, f, pretty=False, no_payload=False): """ - Convert criu image entries from binary format to dict(json). - Takes a file-like object and returnes a list with entries in - dict(json) format. - """ + Convert criu image entries from binary format to dict(json). + Takes a file-like object and returnes a list with entries in + dict(json) format. + """ entries = [] while True: @@ -128,17 +128,17 @@ class entry_handler: def loads(self, s, pretty=False): """ - Same as load(), but takes a string as an argument. - """ + Same as load(), but takes a string as an argument. + """ f = io.BytesIO(s) return self.load(f, pretty) def dump(self, entries, f): """ - Convert criu image entries from dict(json) format to binary. - Takes a list of entries and a file-like object to write entries - in binary format to. - """ + Convert criu image entries from dict(json) format to binary. + Takes a list of entries and a file-like object to write entries + in binary format to. + """ for entry in entries: extra = entry.pop('extra', None) @@ -156,17 +156,17 @@ class entry_handler: def dumps(self, entries): """ - Same as dump(), but doesn't take file-like object and just - returns a string. - """ + Same as dump(), but doesn't take file-like object and just + returns a string. + """ f = io.BytesIO('') self.dump(entries, f) return f.read() def count(self, f): """ - Counts the number of top-level object in the image file - """ + Counts the number of top-level object in the image file + """ entries = 0 while True: @@ -183,10 +183,10 @@ class entry_handler: # Special handler for pagemap.img class pagemap_handler: """ - Special entry handler for pagemap.img, which is unique in a way - that it has a header of pagemap_head type followed by entries - of pagemap_entry type. - """ + Special entry handler for pagemap.img, which is unique in a way + that it has a header of pagemap_head type followed by entries + of pagemap_entry type. + """ def load(self, f, pretty=False, no_payload=False): entries = [] @@ -547,10 +547,10 @@ def __rhandler(f): def load(f, pretty=False, no_payload=False): """ - Convert criu image from binary format to dict(json). - Takes a file-like object to read criu image from. - Returns criu image in dict(json) format. - """ + Convert criu image from binary format to dict(json). + Takes a file-like object to read criu image from. + Returns criu image in dict(json) format. + """ image = {} m, handler = __rhandler(f) @@ -574,18 +574,18 @@ def info(f): def loads(s, pretty=False): """ - Same as load(), but takes a string. - """ + Same as load(), but takes a string. + """ f = io.BytesIO(s) return load(f, pretty) def dump(img, f): """ - Convert criu image from dict(json) format to binary. - Takes an image in dict(json) format and file-like - object to write to. - """ + Convert criu image from dict(json) format to binary. + Takes an image in dict(json) format and file-like + object to write to. + """ m = img['magic'] magic_val = magic.by_name[img['magic']] @@ -609,9 +609,9 @@ def dump(img, f): def dumps(img): """ - Same as dump(), but takes only an image and returns - a string. - """ + Same as dump(), but takes only an image and returns + a string. + """ f = io.BytesIO(b'') dump(img, f) return f.getvalue() diff --git a/scripts/magic-gen.py b/scripts/magic-gen.py index 3d9777735..3b1f29fb5 100755 --- a/scripts/magic-gen.py +++ b/scripts/magic-gen.py @@ -15,8 +15,8 @@ def main(argv): out = open(magic_py, 'w+') # all_magic is used to parse constructions like: - # #define PAGEMAP_MAGIC 0x56084025 - # #define SHMEM_PAGEMAP_MAGIC PAGEMAP_MAGIC + # #define PAGEMAP_MAGIC 0x56084025 + # #define SHMEM_PAGEMAP_MAGIC PAGEMAP_MAGIC all_magic = {} # and magic is used to store only unique magic. magic = {} From c703e3fd8404e506cc6156719b953ea0580d59a4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 11 Sep 2019 11:29:31 +0300 Subject: [PATCH 2163/4375] criu: Version 3.13 Here we have some bugfixes, huuuge *.py patch for coding style and nice set of new features like 32bit for ARM, TLS for page server and new mode for CGroups. Signed-off-by: Pavel Emelyanov --- Makefile.versions | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index a7820b3b3..f3adcb0a6 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 12 -CRIU_VERSION_SUBLEVEL := 1 +CRIU_VERSION_MINOR := 13 +CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Ice Penguin +CRIU_VERSION_NAME := Silicon Willet CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From 08f3b57ab324aea55e7a92ecbe961be60df4983d Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 1 Jul 2019 17:40:44 +0300 Subject: [PATCH 2164/4375] py: Manual fixlets of code formatting Signed-off-by: Pavel Emelyanov --- coredump/criu_coredump/coredump.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/coredump/criu_coredump/coredump.py b/coredump/criu_coredump/coredump.py index bc53a7705..68dc16bf2 100644 --- a/coredump/criu_coredump/coredump.py +++ b/coredump/criu_coredump/coredump.py @@ -645,8 +645,7 @@ class coredump_generator: ppid = self.pstree[pid]["ppid"] return self._get_page(ppid, page_no) else: - with open(self._imgs_dir + "/" + "pages-" + str(pages_id) + - ".img") as f: + with open(self._imgs_dir + "/pages-%s.img" % pages_id) as f: f.seek(off * PAGESIZE) return f.read(PAGESIZE) From 3eed47223b255c092f3aba31b68a9acefa9be523 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 1 Sep 2019 12:23:39 +0100 Subject: [PATCH 2165/4375] files-reg: Drop clear_ghost_files() prototype The function clear_ghost_files() has been removed in commit b11eeea "restore: auto-unlink for ghost files (v2)". Signed-off-by: Radostin Stoyanov --- criu/include/files-reg.h | 1 - 1 file changed, 1 deletion(-) diff --git a/criu/include/files-reg.h b/criu/include/files-reg.h index 7a22d4d82..016d76a9f 100644 --- a/criu/include/files-reg.h +++ b/criu/include/files-reg.h @@ -30,7 +30,6 @@ extern int open_reg_by_id(u32 id); extern int open_reg_fd(struct file_desc *); extern int open_path(struct file_desc *, int (*open_cb)(int ns_root_fd, struct reg_file_info *, void *), void *arg); -extern void clear_ghost_files(void); extern const struct fdtype_ops regfile_dump_ops; extern int do_open_reg_noseek_flags(int ns_root_fd, struct reg_file_info *rfi, void *arg); From 8ea953f18b8534be883de3638369e4804771d086 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 13 Aug 2019 22:11:04 +0100 Subject: [PATCH 2166/4375] cr-dump: Remove redundant if-statement Signed-off-by: Radostin Stoyanov --- criu/cr-dump.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 9273fc0a5..fcbe816e8 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -782,8 +782,6 @@ static int dump_task_core_all(struct parasite_ctl *ctl, img = img_from_set(cr_imgset, CR_FD_CORE); ret = pb_write_one(img, core, PB_CORE); - if (ret < 0) - goto err; err: pr_info("----------------------------------------\n"); From 0d8e2477e928a1301c0611de233aed6879fdc13b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 10 Sep 2019 06:50:58 -0700 Subject: [PATCH 2167/4375] arch/x86: push correct eip on the stack before lretq Right now we use pushq, but it pushes sign-extended value, so if the parasite code is placed higher that 2Gb, we will see something like this: 0xf7efd5b0: pushq $0x23 0xf7efd5b2: pushq $0xfffffffff7efd5b9 => 0xf7efd5b7: lretq Actually we want to push 0xf7efd5b9 instead of 0xfffffffff7efd5b9. Fixes: #398 Cc: Dmitry Safonov Cc: Cyrill Gorcunov Signed-off-by: Andrei Vagin Acked-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/include/uapi/asm/sigframe.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h index 51ca023f7..486c0c8e0 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/sigframe.h @@ -194,7 +194,9 @@ void rt_sigframe_erase_sigset(struct rt_sigframe *sigframe) #define ARCH_RT_SIGRETURN_COMPAT(new_sp) \ asm volatile( \ "pushq $"__stringify(USER32_CS)" \n" \ - "pushq $1f \n" \ + "xor %%rax, %%rax \n" \ + "movl $1f, %%eax \n" \ + "pushq %%rax \n" \ "lretq \n" \ "1: \n" \ ".code32 \n" \ From 3e9dc1c7f5537a860a7332b93e056e7058162578 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 11 Sep 2019 11:13:51 +0100 Subject: [PATCH 2168/4375] compel/x86: Don't use pushq for a label `pushq` sign-extends the value. Which is a bummer as the label's address may be higher that 2Gb, which means that the sign-bit will be set. As it long-jumps with ia32 selector, %r11 can be scratched. Use %r11 register as a temporary to push the 32-bit address. Complements: a9a760278c1a ("arch/x86: push correct eip on the stack before lretq") Cc: Cyrill Gorcunov Reported-by: Andrei Vagin Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/x86/plugins/std/parasite-head.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compel/arch/x86/plugins/std/parasite-head.S b/compel/arch/x86/plugins/std/parasite-head.S index a988de9d4..465cd887b 100644 --- a/compel/arch/x86/plugins/std/parasite-head.S +++ b/compel/arch/x86/plugins/std/parasite-head.S @@ -25,7 +25,9 @@ ENTRY(__export_parasite_head_start_compat) .code64 PARASITE_ENTRY 0 pushq $__USER32_CS - pushq $2f + xor %r11, %r11 + movl $2f, %r11d + pushq %r11 lretq 2: .code32 From ad7e82a30f813b8b902026467434cc2e7421452e Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 9 Sep 2019 21:57:33 +0100 Subject: [PATCH 2169/4375] scripts: Drop Fedora 28/rawhide fix This change was introduced with c75cb2b and it is no longer necessary. Signed-off-by: Radostin Stoyanov --- scripts/build/Dockerfile.fedora.tmpl | 6 ------ 1 file changed, 6 deletions(-) diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index 280ce1cdd..b1127c9b2 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -30,12 +30,6 @@ RUN dnf install -y \ rubygem-asciidoctor \ kmod -# Replace coreutils-single with "traditional" coreutils -# to fix the following error on Fedora 28/rawhide while -# running under QEMU: -# > sh: /usr/bin/sort: /usr/bin/coreutils: bad interpreter: No such file or directory -RUN dnf install -y --allowerasing coreutils - RUN ln -sf python3 /usr/bin/python ENV PYTHON=python3 From 2f337652ad5c40f7a420fdd9a7c57767af4ba8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20C=C5=82api=C5=84ski?= Date: Thu, 8 Aug 2019 18:49:13 +0200 Subject: [PATCH 2170/4375] Add new command line option: --cgroup-yard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of creating cgroup yard in CRIU, now we can create it externally and pass it to CRIU. Useful if somebody doesn't want to grant CAP_SYS_ADMIN to CRIU. Signed-off-by: Michał Cłapiński --- Documentation/criu.txt | 36 ++++++++++++-- criu/cgroup.c | 101 +++++++++++++++++++++++++------------- criu/config.c | 4 ++ criu/cr-service.c | 3 ++ criu/crtools.c | 4 ++ criu/image.c | 2 +- criu/include/cr_options.h | 1 + images/rpc.proto | 1 + lib/c/criu.c | 13 +++++ lib/c/criu.h | 1 + 10 files changed, 126 insertions(+), 40 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 94fc5428a..28913a7fb 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -266,10 +266,33 @@ For example, the command line for the above example should look like this: discovered automatically (usually via */proc*). This option is useful when one needs *criu* to skip some controllers. -*--cgroup-props-ignore-default*:: - When combined with *--cgroup-props*, makes *criu* substitute - a predefined controller property with the new one shipped. If the option - is not used, the predefined properties are merged with the provided ones. +*--cgroup-yard* 'path':: + Instead of trying to mount cgroups in CRIU, provide a path to a directory + with already created cgroup yard. Useful if you don't want to grant + CAP_SYS_ADMIN to CRIU. For every cgroup mount there should be exactly one + directory. If there is only one controller in this mount, the dir's name + should be just the name of the controller. If there are multiple controllers + comounted, the directory name should have them be separated by a comma. ++ +For example, if */proc/cgroups* looks like this: ++ +---------- +#subsys_name hierarchy num_cgroups enabled +cpu 1 1 1 +devices 2 2 1 +freezer 2 2 1 +---------- ++ +then you can create the cgroup yard by the following commands: ++ +---------- +mkdir private_yard +cd private_yard +mkdir cpu +mount -t cgroup -o cpu none cpu +mkdir devices,freezer +mount -t cgroup -o devices,freezer none devices,freezer +---------- *--tcp-established*:: Checkpoint established TCP connections. @@ -442,6 +465,11 @@ The 'mode' may be one of the following: *ignore*::: Don't deal with cgroups and pretend that they don't exist. +*--cgroup-yard* 'path':: + Instead of trying to mount cgroups in CRIU, provide a path to a directory + with already created cgroup yard. For more information look in the *dump* + section. + *--cgroup-root* ['controller'*:*]/'newroot':: Change the root cgroup the controller will be installed into. No controller means that root is the default for all controllers not specified. diff --git a/criu/cgroup.c b/criu/cgroup.c index 332c79fb9..9f3aef10d 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -549,8 +549,9 @@ static int collect_cgroups(struct list_head *ctls) int fd = -1; list_for_each_entry(cc, ctls, l) { - char path[PATH_MAX], mopts[1024], *root; + char path[PATH_MAX], *root; char prefix[] = ".criu.cgmounts.XXXXXX"; + const char namestr[] = "name="; struct cg_controller *cg; struct cg_root_opt *o; @@ -568,7 +569,7 @@ static int collect_cgroups(struct list_head *ctls) if (!current_controller) { /* only allow "fake" controllers to be created this way */ - if (!strstartswith(cc->name, "name=")) { + if (!strstartswith(cc->name, namestr)) { pr_err("controller %s not found\n", cc->name); return -1; } else { @@ -586,26 +587,45 @@ static int collect_cgroups(struct list_head *ctls) if (!opts.manage_cgroups) continue; - if (strstartswith(cc->name, "name=")) - snprintf(mopts, sizeof(mopts), "none,%s", cc->name); - else - snprintf(mopts, sizeof(mopts), "%s", cc->name); + if (opts.cgroup_yard) { + char dir_path[PATH_MAX]; + int off; + + off = snprintf(dir_path, PATH_MAX, "%s/", opts.cgroup_yard); + if (strstartswith(cc->name, namestr)) + snprintf(dir_path + off, PATH_MAX, "%s", cc->name + strlen(namestr)); + else + snprintf(dir_path + off, PATH_MAX, "%s", cc->name); - if (mkdtemp(prefix) == NULL) { - pr_perror("can't make dir for cg mounts"); - return -1; + fd = open(dir_path, O_RDONLY | O_DIRECTORY, 0); + if (fd < 0) { + pr_perror("couldn't open %s", dir_path); + return -1; + } + } else { + char mopts[1024]; + + if (strstartswith(cc->name, namestr)) + snprintf(mopts, sizeof(mopts), "none,%s", cc->name); + else + snprintf(mopts, sizeof(mopts), "%s", cc->name); + + if (mkdtemp(prefix) == NULL) { + pr_perror("can't make dir for cg mounts"); + return -1; + } + + if (mount("none", prefix, "cgroup", 0, mopts) < 0) { + pr_perror("couldn't mount %s", mopts); + rmdir(prefix); + return -1; + } + + fd = open_detach_mount(prefix); + if (fd < 0) + return -1; } - if (mount("none", prefix, "cgroup", 0, mopts) < 0) { - pr_perror("couldn't mount %s", mopts); - rmdir(prefix); - return -1; - } - - fd = open_detach_mount(prefix); - if (fd < 0) - return -1; - path_pref_len = snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd); root = cc->path; @@ -620,6 +640,7 @@ static int collect_cgroups(struct list_head *ctls) snprintf(path + path_pref_len, PATH_MAX - path_pref_len, "%s", root); ret = ftw(path, add_cgroup, 4); + if (ret < 0) pr_perror("failed walking %s for empty cgroups", path); @@ -1167,10 +1188,12 @@ void fini_cgroup(void) return; close_service_fd(CGROUP_YARD); - if (umount2(cg_yard, MNT_DETACH)) - pr_perror("Unable to umount %s", cg_yard); - if (rmdir(cg_yard)) - pr_perror("Unable to remove %s", cg_yard); + if (!opts.cgroup_yard) { + if (umount2(cg_yard, MNT_DETACH)) + pr_perror("Unable to umount %s", cg_yard); + if (rmdir(cg_yard)) + pr_perror("Unable to remove %s", cg_yard); + } xfree(cg_yard); cg_yard = NULL; } @@ -1652,20 +1675,28 @@ static int prepare_cgroup_sfd(CgroupEntry *ce) pr_info("Preparing cgroups yard (cgroups restore mode %#x)\n", opts.manage_cgroups); - off = sprintf(paux, ".criu.cgyard.XXXXXX"); - if (mkdtemp(paux) == NULL) { - pr_perror("Can't make temp cgyard dir"); - return -1; - } + if (opts.cgroup_yard) { + off = sprintf(paux, "%s", opts.cgroup_yard); - cg_yard = xstrdup(paux); - if (!cg_yard) { - rmdir(paux); - return -1; - } + cg_yard = xstrdup(paux); + if (!cg_yard) + return -1; + } else { + off = sprintf(paux, ".criu.cgyard.XXXXXX"); + if (mkdtemp(paux) == NULL) { + pr_perror("Can't make temp cgyard dir"); + return -1; + } - if (make_yard(cg_yard)) - goto err; + cg_yard = xstrdup(paux); + if (!cg_yard) { + rmdir(paux); + return -1; + } + + if (make_yard(cg_yard)) + goto err; + } pr_debug("Opening %s as cg yard\n", cg_yard); i = open(cg_yard, O_DIRECTORY); diff --git a/criu/config.c b/criu/config.c index 39aa071c9..cdea91f02 100644 --- a/criu/config.c +++ b/criu/config.c @@ -516,6 +516,7 @@ int parse_options(int argc, char **argv, bool *usage_error, { "tls-key", required_argument, 0, 1095}, BOOL_OPT("tls", &opts.tls), {"tls-no-cn-verify", no_argument, &opts.tls_no_cn_verify, true}, + { "cgroup-yard", required_argument, 0, 1096 }, { }, }; @@ -814,6 +815,9 @@ int parse_options(int argc, char **argv, bool *usage_error, case 1095: SET_CHAR_OPTS(tls_key, optarg); break; + case 1096: + SET_CHAR_OPTS(cgroup_yard, optarg); + break; case 'V': pr_msg("Version: %s\n", CRIU_VERSION); if (strcmp(CRIU_GITID, "0")) diff --git a/criu/cr-service.c b/criu/cr-service.c index 0938db02b..95ba2e5ce 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -608,6 +608,9 @@ static int setup_opts_from_req(int sk, CriuOpts *req) goto err; } + if (req->cgroup_yard) + SET_CHAR_OPTS(cgroup_yard, req->cgroup_yard); + if (req->tls_cacert) SET_CHAR_OPTS(tls_cacert, req->tls_cacert); if (req->tls_cacrl) diff --git a/criu/crtools.c b/criu/crtools.c index a94875684..0799a564c 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -366,6 +366,10 @@ usage: " --cgroup-dump-controller NAME\n" " define cgroup controller to be dumped\n" " and skip anything else present in system\n" +" --cgroup-yard PATH\n" +" instead of trying to mount cgroups in CRIU, provide\n" +" a path to a directory with already created cgroup yard.\n" +" Useful if you don't want to grant CAP_SYS_ADMIN to CRIU\n" " --lsm-profile TYPE:NAME\n" " Specify an LSM profile to be used during restore.\n" " The type can be either 'apparmor' or 'selinux'.\n" diff --git a/criu/image.c b/criu/image.c index 2eb926929..0225788b0 100644 --- a/criu/image.c +++ b/criu/image.c @@ -190,7 +190,7 @@ int prepare_inventory(InventoryEntry *he) struct dmp_info d; } crt = { .i.pid = &pid }; - pr_info("Perparing image inventory (version %u)\n", CRTOOLS_IMAGES_V1); + pr_info("Preparing image inventory (version %u)\n", CRTOOLS_IMAGES_V1); he->img_version = CRTOOLS_IMAGES_V1_1; he->fdinfo_per_id = true; diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index 82f76ad94..da7c10d69 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -106,6 +106,7 @@ struct cr_options { char *cgroup_props; char *cgroup_props_file; struct list_head new_cgroup_roots; + char *cgroup_yard; bool autodetect_ext_mounts; int enable_external_sharing; int enable_external_masters; diff --git a/images/rpc.proto b/images/rpc.proto index 15e677a77..c402259ac 100644 --- a/images/rpc.proto +++ b/images/rpc.proto @@ -120,6 +120,7 @@ message criu_opts { optional string tls_key = 57; optional bool tls = 58; optional bool tls_no_cn_verify = 59; + optional string cgroup_yard = 60; /* optional bool check_mounts = 128; */ } diff --git a/lib/c/criu.c b/lib/c/criu.c index 17d5c3983..14ddff26d 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -987,6 +987,19 @@ int criu_local_add_cg_dump_controller(criu_opts *opts, const char *name) return 0; } +int criu_local_add_cg_yard(criu_opts *opts, const char *path) +{ + char *new; + + new = strdup(path); + if (!new) + return -ENOMEM; + + free(opts->rpc->cgroup_yard); + opts->rpc->cgroup_yard = new; + return 0; +} + int criu_add_skip_mnt(const char *mnt) { return criu_local_add_skip_mnt(global_opts, mnt); diff --git a/lib/c/criu.h b/lib/c/criu.h index 76f3547fc..cb37c5291 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -207,6 +207,7 @@ int criu_local_add_irmap_path(criu_opts *opts, const char *path); int criu_local_add_cg_props(criu_opts *opts, const char *stream); int criu_local_add_cg_props_file(criu_opts *opts, const char *path); int criu_local_add_cg_dump_controller(criu_opts *opts, const char *name); +int criu_local_add_cg_yard(criu_opts *opts, const char *path); int criu_local_add_inherit_fd(criu_opts *opts, int fd, const char *key); int criu_local_add_external(criu_opts *opts, const char *key); int criu_local_set_page_server_address_port(criu_opts *opts, const char *address, int port); From cf0080505ac3b3194f664d77edccccfa47bf450a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20C=C5=82api=C5=84ski?= Date: Wed, 14 Aug 2019 21:13:34 +0200 Subject: [PATCH 2171/4375] test: implement test for new --cgroup-yard option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Cłapiński --- test/zdtm.py | 4 +- test/zdtm/static/Makefile | 3 +- test/zdtm/static/cgroup_yard.c | 1 + test/zdtm/static/cgroup_yard.desc | 7 ++++ test/zdtm/static/cgroup_yard.hook | 70 +++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 3 deletions(-) create mode 120000 test/zdtm/static/cgroup_yard.c create mode 100644 test/zdtm/static/cgroup_yard.desc create mode 100755 test/zdtm/static/cgroup_yard.hook diff --git a/test/zdtm.py b/test/zdtm.py index 0153c6058..f0a102413 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -2018,7 +2018,7 @@ def print_sep(title, sep="=", width=80): def print_error(line): line = line.rstrip() - print(line) + print(line.encode('utf-8')) if line.endswith('>'): # combine pie output return True return False @@ -2028,7 +2028,7 @@ def grep_errors(fname): first = True print_next = False before = [] - with open(fname) as fd: + with open(fname, errors='replace') as fd: for l in fd: before.append(l) if len(before) > 5: diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index d8279d6f8..a38482f44 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -319,7 +319,8 @@ TST_DIR = \ cgroup03 \ cgroup04 \ cgroup_ifpriomap \ - cgroup_stray \ + cgroup_stray \ + cgroup_yard \ unlink_fstat04 \ unlink_fstat041 \ mntns_remap \ diff --git a/test/zdtm/static/cgroup_yard.c b/test/zdtm/static/cgroup_yard.c new file mode 120000 index 000000000..f3683c2b4 --- /dev/null +++ b/test/zdtm/static/cgroup_yard.c @@ -0,0 +1 @@ +cgroup00.c \ No newline at end of file diff --git a/test/zdtm/static/cgroup_yard.desc b/test/zdtm/static/cgroup_yard.desc new file mode 100644 index 000000000..8736d6780 --- /dev/null +++ b/test/zdtm/static/cgroup_yard.desc @@ -0,0 +1,7 @@ +{ +'flavor': 'h', +'flags': 'suid', +# We create the external cgroup yard in working directory during --pre-dump +# hook. We have to go up a few directories to find the yard. +'opts': '--manage-cgroups --cgroup-yard ../../../../../../external_yard' +} diff --git a/test/zdtm/static/cgroup_yard.hook b/test/zdtm/static/cgroup_yard.hook new file mode 100755 index 000000000..7ae53342c --- /dev/null +++ b/test/zdtm/static/cgroup_yard.hook @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +import sys +import os +import subprocess +import tempfile + +yard = "external_yard" + +if sys.argv[1] == "--pre-dump": + ''' + Create external cgroup yard to be passed to CRIU via --cgroup-yard + ''' + os.mkdir(yard) + with open("/proc/self/cgroup") as f: + for line in f: + cgr = line.split(":")[1] + + if cgr == "": + continue + + if cgr.startswith("name="): + ctrl = cgr[len("name="):] + opts = "none," + cgr + else: + ctrl = cgr + opts = cgr + + os.mkdir(yard + "/" + ctrl) + subprocess.check_call(["mount", "-t", "cgroup", "none", yard + "/" + ctrl, "-o", opts]) + +if sys.argv[1] == "--post-restore": + ''' + Clean up the cgroup yard created during `--pre-dump` + ''' + with open("/proc/self/cgroup") as f: + for line in f: + cgr = line.split(":")[1] + + if cgr == "": + continue + + if cgr.startswith("name="): + ctrl = cgr[len("name="):] + else: + ctrl = cgr + + subprocess.check_call(["umount", yard + "/" + ctrl]) + os.rmdir(yard + "/" + ctrl) + os.rmdir(yard) + +if sys.argv[1] in ["--pre-restore", "--clean"]: + ''' + Clean up the leftover cgroups created by the test + ''' + tname = tempfile.mkdtemp() + subprocess.call(["mount", "-t", "cgroup", "none", tname, "-o", "none,name=zdtmtst"]) + + try: + os.rmdir(os.path.join(tname, "subcg00", "subsubcg")) + except: + pass + + try: + os.rmdir(os.path.join(tname, "subcg00")) + except: + pass + + subprocess.call(["umount", tname]) + os.rmdir(tname) From 4f24786b36058ab82e669fd5686cc9f5cfc573db Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sat, 14 Sep 2019 13:47:06 +0100 Subject: [PATCH 2172/4375] travis: Install missing diffutils dependency The following tests fail in Fedora rawhide because /usr/bin/diff is missing. * zdtm/static/bridge(ns) * zdtm/static/cr_veth(uns) * zdtm/static/macvlan(ns) * zdtm/static/netns(uns) * zdtm/static/netns-nf(ns) * zdtm/static/sit(ns) Signed-off-by: Radostin Stoyanov --- scripts/build/Dockerfile.fedora.tmpl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index b1127c9b2..0500a8fc5 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -3,6 +3,7 @@ ARG ENV1=FOOBAR RUN dnf install -y \ ccache \ + diffutils \ findutils \ gcc \ git \ From 8bdc60d50e5b990aa8debd06785175da3e0ba34a Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 14 Sep 2019 10:26:22 +0300 Subject: [PATCH 2173/4375] arch/x86: fpu_state->fpu_state_ia32.xsave hast to be 64-byte aligned Before the 5.2 kernel, only fpu_state->fpu_state_64.xsave has to be 64-byte aligned. But staring with the 5.2 kernel, the same is required for pu_state->fpu_state_ia32.xsave. The behavior was changed in: c2ff9e9a3d9d ("x86/fpu: Merge the two code paths in __fpu__restore_sig()") Signed-off-by: Andrei Vagin --- compel/arch/x86/src/lib/include/uapi/asm/fpu.h | 8 ++++++-- criu/arch/x86/sigframe.c | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h index 509f4488b..4ff531fb9 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h @@ -263,7 +263,7 @@ struct xsave_struct_ia32 { struct ymmh_struct ymmh; uint8_t extended_state_area[EXTENDED_STATE_AREA_SIZE]; }; -} __aligned(FXSAVE_ALIGN_BYTES); +}; typedef struct { /* @@ -309,7 +309,11 @@ typedef struct { typedef struct { union { fpu_state_64_t fpu_state_64; - fpu_state_ia32_t fpu_state_ia32; + struct { + /* fpu_state_ia32->xsave has to be 64-byte aligned. */ + uint32_t __pad[2]; + fpu_state_ia32_t fpu_state_ia32; + }; }; uint8_t has_fpu; diff --git a/criu/arch/x86/sigframe.c b/criu/arch/x86/sigframe.c index 11b0d640d..33ba14387 100644 --- a/criu/arch/x86/sigframe.c +++ b/criu/arch/x86/sigframe.c @@ -28,8 +28,14 @@ int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, sigframe->native.uc.uc_mcontext.fpstate = (uint64_t)addr; } else if (!sigframe->is_native) { + unsigned long addr = (unsigned long)(void *)&fpu_state->fpu_state_ia32.xsave; sigframe->compat.uc.uc_mcontext.fpstate = (uint32_t)(unsigned long)(void *)&fpu_state->fpu_state_ia32; + if ((addr % 64ul)) { + pr_err("Unaligned address passed: %lx (native %d)\n", + addr, sigframe->is_native); + return -1; + } } return 0; From a9f974b4951a261063187f0536c01c7f84e5fe56 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 15 Sep 2019 06:58:15 +0100 Subject: [PATCH 2174/4375] Introduce flush_early_log_to_stderr destructor Prior log initialisation CRIU preserves all (early) log messages in a buffer. In case of error the content of the content of this buffer needs to be printed out (flushed). Suggested-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Radostin Stoyanov --- criu/crtools.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index 0799a564c..4625446ad 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -47,6 +47,13 @@ #include "setproctitle.h" #include "sysctl.h" +void flush_early_log_to_stderr() __attribute__((destructor)); + +void flush_early_log_to_stderr(void) +{ + flush_early_log_buffer(STDERR_FILENO); +} + int main(int argc, char *argv[], char *envp[]) { int ret = -1; @@ -95,10 +102,8 @@ int main(int argc, char *argv[], char *envp[]) return cr_service_work(atoi(argv[2])); } - if (check_options()) { - flush_early_log_buffer(STDERR_FILENO); + if (check_options()) return 1; - } if (opts.imgs_dir == NULL) SET_CHAR_OPTS(imgs_dir, "."); From 813bfbeb4f26611f8fd431c6fd65104cbad789d1 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 15 Sep 2019 07:03:57 +0100 Subject: [PATCH 2175/4375] Convert pr_msg() error messages to pr_err() Print error messages to stderr (instead of stdout). Suggested-by: Andrei Vagin Signed-off-by: Radostin Stoyanov --- criu/config.c | 4 ++-- criu/cr-check.c | 2 +- criu/crtools.c | 22 +++++++++++----------- criu/proc_parse.c | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/criu/config.c b/criu/config.c index cdea91f02..2ad2fd43c 100644 --- a/criu/config.c +++ b/criu/config.c @@ -835,10 +835,10 @@ int parse_options(int argc, char **argv, bool *usage_error, bad_arg: if (idx < 0) /* short option */ - pr_msg("Error: invalid argument for -%c: %s\n", + pr_err("invalid argument for -%c: %s\n", opt, optarg); else /* long option */ - pr_msg("Error: invalid argument for --%s: %s\n", + pr_err("invalid argument for --%s: %s\n", long_opts[idx].name, optarg); return 1; } diff --git a/criu/cr-check.c b/criu/cr-check.c index 75a665cfb..729b2dc38 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -62,7 +62,7 @@ static int check_tty(void) int ret = -1; if (ARRAY_SIZE(t.c_cc) < TERMIOS_NCC) { - pr_msg("struct termios has %d @c_cc while " + pr_err("struct termios has %d @c_cc while " "at least %d expected.\n", (int)ARRAY_SIZE(t.c_cc), TERMIOS_NCC); diff --git a/criu/crtools.c b/criu/crtools.c index 4625446ad..5740b806d 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -112,7 +112,7 @@ int main(int argc, char *argv[], char *envp[]) SET_CHAR_OPTS(work_dir, opts.imgs_dir); if (optind >= argc) { - pr_msg("Error: command is required\n"); + pr_err("command is required\n"); goto usage; } @@ -120,17 +120,17 @@ int main(int argc, char *argv[], char *envp[]) if (has_exec_cmd) { if (!has_sub_command) { - pr_msg("Error: --exec-cmd requires a command\n"); + pr_err("--exec-cmd requires a command\n"); goto usage; } if (strcmp(argv[optind], "restore")) { - pr_msg("Error: --exec-cmd is available for the restore command only\n"); + pr_err("--exec-cmd is available for the restore command only\n"); goto usage; } if (opts.restore_detach) { - pr_msg("Error: --restore-detached and --exec-cmd cannot be used together\n"); + pr_err("--restore-detached and --exec-cmd cannot be used together\n"); goto usage; } @@ -142,7 +142,7 @@ int main(int argc, char *argv[], char *envp[]) } else { /* No subcommands except for cpuinfo and restore --exec-cmd */ if (strcmp(argv[optind], "cpuinfo") && has_sub_command) { - pr_msg("Error: excessive parameter%s for command %s\n", + pr_err("excessive parameter%s for command %s\n", (argc - optind) > 2 ? "s" : "", argv[optind]); goto usage; } @@ -241,7 +241,7 @@ int main(int argc, char *argv[], char *envp[]) if (!strcmp(argv[optind], "cpuinfo")) { if (!argv[optind + 1]) { - pr_msg("Error: cpuinfo requires an action: dump or check\n"); + pr_err("cpuinfo requires an action: dump or check\n"); goto usage; } if (!strcmp(argv[optind + 1], "dump")) @@ -251,17 +251,17 @@ int main(int argc, char *argv[], char *envp[]) } if (!strcmp(argv[optind], "exec")) { - pr_msg("The \"exec\" action is deprecated by the Compel library.\n"); + pr_err("The \"exec\" action is deprecated by the Compel library.\n"); return -1; } if (!strcmp(argv[optind], "show")) { - pr_msg("The \"show\" action is deprecated by the CRIT utility.\n"); - pr_msg("To view an image use the \"crit decode -i $name --pretty\" command.\n"); + pr_err("The \"show\" action is deprecated by the CRIT utility.\n"); + pr_err("To view an image use the \"crit decode -i $name --pretty\" command.\n"); return -1; } - pr_msg("Error: unknown command: %s\n", argv[optind]); + pr_err("unknown command: %s\n", argv[optind]); usage: pr_msg("\n" "Usage:\n" @@ -455,6 +455,6 @@ usage: return 0; opt_pid_missing: - pr_msg("Error: pid not specified\n"); + pr_err("pid not specified\n"); return 1; } diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 0e8b6f209..97f82ee01 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -932,7 +932,7 @@ int prepare_loginuid(unsigned int value, unsigned int loglevel) if (write(fd, buf, 11) < 0) { print_on_level(loglevel, - "Write %s to /proc/self/loginuid failed: %s", + "Write %s to /proc/self/loginuid failed: %s\n", buf, strerror(errno)); ret = -1; } From db40ef5be671dbd78f42bd868a5377e62707c3de Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 15 Sep 2019 11:49:27 -0700 Subject: [PATCH 2176/4375] test/cgroup_yard: always clean up a test cgroup yard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now it is cleaned up from a post-restore hook, but zdtm.py can be executed with the norst option: $ zdtm.py run -t zdtm/static/cgroup_yard --norst ... OSError: [Errno 17] File exists: 'external_yard' Cc: Michał Cłapiński Signed-off-by: Andrei Vagin --- test/zdtm/static/cgroup_yard.hook | 39 ++++++++----------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/test/zdtm/static/cgroup_yard.hook b/test/zdtm/static/cgroup_yard.hook index 7ae53342c..cc3971707 100755 --- a/test/zdtm/static/cgroup_yard.hook +++ b/test/zdtm/static/cgroup_yard.hook @@ -12,6 +12,7 @@ if sys.argv[1] == "--pre-dump": Create external cgroup yard to be passed to CRIU via --cgroup-yard ''' os.mkdir(yard) + subprocess.check_call(["mount", "-t", "tmpfs", "zdtm_yard", yard]) with open("/proc/self/cgroup") as f: for line in f: cgr = line.split(":")[1] @@ -29,26 +30,6 @@ if sys.argv[1] == "--pre-dump": os.mkdir(yard + "/" + ctrl) subprocess.check_call(["mount", "-t", "cgroup", "none", yard + "/" + ctrl, "-o", opts]) -if sys.argv[1] == "--post-restore": - ''' - Clean up the cgroup yard created during `--pre-dump` - ''' - with open("/proc/self/cgroup") as f: - for line in f: - cgr = line.split(":")[1] - - if cgr == "": - continue - - if cgr.startswith("name="): - ctrl = cgr[len("name="):] - else: - ctrl = cgr - - subprocess.check_call(["umount", yard + "/" + ctrl]) - os.rmdir(yard + "/" + ctrl) - os.rmdir(yard) - if sys.argv[1] in ["--pre-restore", "--clean"]: ''' Clean up the leftover cgroups created by the test @@ -56,15 +37,15 @@ if sys.argv[1] in ["--pre-restore", "--clean"]: tname = tempfile.mkdtemp() subprocess.call(["mount", "-t", "cgroup", "none", tname, "-o", "none,name=zdtmtst"]) - try: - os.rmdir(os.path.join(tname, "subcg00", "subsubcg")) - except: - pass - - try: - os.rmdir(os.path.join(tname, "subcg00")) - except: - pass + for cg in [os.path.join(tname, "subcg00", "subsubcg"), + os.path.join(tname, "subcg00")]: + if os.access(cg, os.F_OK): + os.rmdir(cg) subprocess.call(["umount", tname]) os.rmdir(tname) + +if sys.argv[1] == "--clean": + if os.access(yard, os.F_OK): + subprocess.call(["umount", "-l", yard]) + os.rmdir(yard) From f44939317f60288874bdc7b8544442a59db0d024 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 19 Sep 2019 23:37:57 +0300 Subject: [PATCH 2177/4375] zdtm/cgroup_yard: create a test cgroup yard from the post-start hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now, it is created from the pre-dump hook, but if the --snap option is set, the test fails: $ python test/zdtm.py run -t zdtm/static/cgroup_yard -f h --snap --iter 3 ... Running zdtm/static/cgroup_yard.hook(--pre-dump) Traceback (most recent call last): File zdtm/static/cgroup_yard.hook, line 14, in os.mkdir(yard) OSError: [Errno 17] File exists: 'external_yard' Cc: Michał Cłapiński Signed-off-by: Andrei Vagin --- test/zdtm/static/cgroup_yard.hook | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/cgroup_yard.hook b/test/zdtm/static/cgroup_yard.hook index cc3971707..072b9d38d 100755 --- a/test/zdtm/static/cgroup_yard.hook +++ b/test/zdtm/static/cgroup_yard.hook @@ -7,7 +7,7 @@ import tempfile yard = "external_yard" -if sys.argv[1] == "--pre-dump": +if sys.argv[1] == "--post-start": ''' Create external cgroup yard to be passed to CRIU via --cgroup-yard ''' From b47ef26eac1777396ede638af0d6951a3fc52a1e Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Sat, 21 Sep 2019 13:35:18 +0300 Subject: [PATCH 2178/4375] cgroup: fixup nits 1) s/\s*$// 2) fix snprintf out of bound access Signed-off-by: Pavel Tikhomirov --- criu/cgroup.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index 9f3aef10d..1be8be234 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -590,12 +590,12 @@ static int collect_cgroups(struct list_head *ctls) if (opts.cgroup_yard) { char dir_path[PATH_MAX]; int off; - + off = snprintf(dir_path, PATH_MAX, "%s/", opts.cgroup_yard); if (strstartswith(cc->name, namestr)) - snprintf(dir_path + off, PATH_MAX, "%s", cc->name + strlen(namestr)); + snprintf(dir_path + off, PATH_MAX - off, "%s", cc->name + strlen(namestr)); else - snprintf(dir_path + off, PATH_MAX, "%s", cc->name); + snprintf(dir_path + off, PATH_MAX - off, "%s", cc->name); fd = open(dir_path, O_RDONLY | O_DIRECTORY, 0); if (fd < 0) { From 3f1c4a17ad18fca3f95c0f51c5c42fedbb403b89 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 24 Sep 2019 23:36:29 +0300 Subject: [PATCH 2179/4375] pipe: print pipe_id as unsigned to generate an external pipe name Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin --- criu/pipes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/pipes.c b/criu/pipes.c index fd1a7e6bb..cb5da71de 100644 --- a/criu/pipes.c +++ b/criu/pipes.c @@ -282,8 +282,8 @@ static char *pipe_d_name(struct file_desc *d, char *buf, size_t s) struct pipe_info *pi; pi = container_of(d, struct pipe_info, d); - if (snprintf(buf, s, "pipe:[%d]", pi->pe->pipe_id) >= s) { - pr_err("Not enough room for pipe %d identifier string\n", + if (snprintf(buf, s, "pipe:[%u]", pi->pe->pipe_id) >= s) { + pr_err("Not enough room for pipe %u identifier string\n", pi->pe->pipe_id); return NULL; } From b84f481b55442433f46b5ea4b91a32dd8cffc502 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 24 Sep 2019 23:48:15 +0300 Subject: [PATCH 2180/4375] unix: print inode numbers as unsigned int Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin --- criu/sk-unix.c | 60 +++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index f0620e676..f43aa2124 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -130,7 +130,7 @@ static struct unix_sk_listen_icon *lookup_unix_listen_icons(unsigned int peer_in static void show_one_unix(char *act, const struct unix_sk_desc *sk) { - pr_debug("\t%s: ino %d peer_ino %d family %4d type %4d state %2d name %s\n", + pr_debug("\t%s: ino %u peer_ino %u family %4d type %4d state %2d name %s\n", act, sk->sd.ino, sk->peer_ino, sk->sd.family, sk->type, sk->state, sk->name); if (sk->nr_icons) { @@ -143,7 +143,7 @@ static void show_one_unix(char *act, const struct unix_sk_desc *sk) static void show_one_unix_img(const char *act, const UnixSkEntry *e) { - pr_info("\t%s: id %#x ino %d peer %d type %d state %d name %d bytes\n", + pr_info("\t%s: id %#x ino %u peer %u type %d state %d name %d bytes\n", act, e->id, e->ino, e->peer, e->type, e->state, (int)e->name.len); } @@ -426,7 +426,7 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) if (ue->peer) { peer = (struct unix_sk_desc *)lookup_socket(ue->peer, PF_UNIX, 0); if (IS_ERR_OR_NULL(peer)) { - pr_err("Unix socket %d without peer %d\n", + pr_err("Unix socket %u without peer %u\n", ue->ino, ue->peer); goto err; } @@ -437,7 +437,7 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) */ if (peer->peer_ino != ue->ino) { if (!peer->name) { - pr_err("Unix socket %d with unreachable peer %d (%d)\n", + pr_err("Unix socket %u with unreachable peer %u (%u)\n", ue->ino, ue->peer, peer->peer_ino); goto err; } @@ -513,7 +513,7 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p) ue->peer = e->sk_desc->sd.ino; - pr_debug("\t\tFixed inflight socket %d peer %d)\n", + pr_debug("\t\tFixed inflight socket %u peer %u)\n", ue->ino, ue->peer); } dump: @@ -1383,7 +1383,7 @@ static int keep_deleted(struct unix_sk_info *ui) { int fd = open(ui->name, O_PATH); if (fd < 0) { - pr_perror("ghost: Can't open id %#x ino %d addr %s", + pr_perror("ghost: Can't open id %#x ino %u addr %s", ui->ue->id, ui->ue->ino, ui->name); return -1; } @@ -1409,7 +1409,7 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) int ret; if (ui->ue->name.len >= UNIX_PATH_MAX) { - pr_err("ghost: Too long name for socket id %#x ino %d name %s\n", + pr_err("ghost: Too long name for socket id %#x ino %u name %s\n", ui->ue->id, ui->ue->ino, ui->name); return -ENOSPC; } @@ -1424,14 +1424,14 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) ret = access(path, R_OK | W_OK | X_OK); if (ret == 0) { ui->ghost_dir_pos = pos - path; - pr_debug("ghost: socket id %#x ino %d name %s detected F_OK %s\n", + pr_debug("ghost: socket id %#x ino %u name %s detected F_OK %s\n", ui->ue->id, ui->ue->ino, ui->name, path); break; } if (errno != ENOENT) { ret = -errno; - pr_perror("ghost: Can't access %s for socket id %#x ino %d name %s", + pr_perror("ghost: Can't access %s for socket id %#x ino %u name %s", path, ui->ue->id, ui->ue->ino, ui->name); return ret; } @@ -1441,7 +1441,7 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) path[ui->ue->name.len] = '\0'; pos = dirname(path); - pr_debug("ghost: socket id %#x ino %d name %s creating %s\n", + pr_debug("ghost: socket id %#x ino %u name %s creating %s\n", ui->ue->id, ui->ue->ino, ui->name, pos); ret = mkdirpat(AT_FDCWD, pos, 0755); if (ret) { @@ -1471,15 +1471,15 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) * clean it up. */ if (unlinkat(AT_FDCWD, path_parked, 0) == 0) - pr_debug("ghost: Unlinked stale socket id %#x ino %d name %s\n", + pr_debug("ghost: Unlinked stale socket id %#x ino %u name %s\n", ui->ue->id, ui->ue->ino, path_parked); if (rename(ui->name, path_parked)) { ret = -errno; - pr_perror("ghost: Can't rename id %#x ino %d addr %s -> %s", + pr_perror("ghost: Can't rename id %#x ino %u addr %s -> %s", ui->ue->id, ui->ue->ino, ui->name, path_parked); return ret; } - pr_debug("ghost: id %#x ino %d renamed %s -> %s\n", + pr_debug("ghost: id %#x ino %u renamed %s -> %s\n", ui->ue->id, ui->ue->ino, ui->name, path_parked); renamed = true; ret = bind(sk, (struct sockaddr *)&addr, @@ -1487,7 +1487,7 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) } if (ret < 0) { ret = -errno; - pr_perror("ghost: Can't bind on socket id %#x ino %d addr %s", + pr_perror("ghost: Can't bind on socket id %#x ino %u addr %s", ui->ue->id, ui->ue->ino, ui->name); return ret; } @@ -1499,7 +1499,7 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) ret = keep_deleted(ui); if (ret < 0) { - pr_err("ghost: Can't save socket %#x ino %d addr %s into fdstore\n", + pr_err("ghost: Can't save socket %#x ino %u addr %s into fdstore\n", ui->ue->id, ui->ue->ino, ui->name); return -EIO; } @@ -1511,7 +1511,7 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) ret = unlinkat(AT_FDCWD, ui->name, 0); if (ret < 0) { ret = -errno; - pr_perror("ghost: Can't unlink socket %#x ino %d addr %s", + pr_perror("ghost: Can't unlink socket %#x ino %u addr %s", ui->ue->id, ui->ue->ino, ui->name); return ret; } @@ -1519,12 +1519,12 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) if (renamed) { if (rename(path_parked, ui->name)) { ret = -errno; - pr_perror("ghost: Can't rename id %#x ino %d addr %s -> %s", + pr_perror("ghost: Can't rename id %#x ino %u addr %s -> %s", ui->ue->id, ui->ue->ino, path_parked, ui->name); return ret; } - pr_debug("ghost: id %#x ino %d renamed %s -> %s\n", + pr_debug("ghost: id %#x ino %u renamed %s -> %s\n", ui->ue->id, ui->ue->ino, path_parked, ui->name); } @@ -1542,11 +1542,11 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) pos = strrchr(path, '/')) { *pos = '\0'; if (rmdir(path)) { - pr_perror("ghost: Can't remove directory %s on id %#x ino %d", + pr_perror("ghost: Can't remove directory %s on id %#x ino %u", path, ui->ue->id, ui->ue->ino); return -1; } - pr_debug("ghost: Removed %s on id %#x ino %d\n", + pr_debug("ghost: Removed %s on id %#x ino %u\n", path, ui->ue->id, ui->ue->ino); } } @@ -1594,13 +1594,13 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) mutex_lock(mutex_ghost); if (ui->flags & USK_GHOST_FDSTORE) { - pr_debug("ghost: bind id %#x ino %d addr %s\n", + pr_debug("ghost: bind id %#x ino %u addr %s\n", ui->ue->id, ui->ue->ino, ui->name); ret = bind_on_deleted(sk, ui); if (ret) errno = -ret; } else { - pr_debug("bind id %#x ino %d addr %s\n", + pr_debug("bind id %#x ino %u addr %s\n", ui->ue->id, ui->ue->ino, ui->name); ret = bind(sk, (struct sockaddr *)&addr, sizeof(addr.sun_family) + ui->ue->name.len); @@ -1608,7 +1608,7 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui) goto done; } if (ret < 0) { - pr_perror("Can't bind id %#x ino %d addr %s", + pr_perror("Can't bind id %#x ino %u addr %s", ui->ue->id, ui->ue->ino, ui->name); goto done; } @@ -1654,7 +1654,7 @@ static int post_open_interconnected_master(struct unix_sk_info *ui) static void pr_info_opening(const char *prefix, struct unix_sk_info *ui, struct fdinfo_list_entry *fle) { - pr_info("Opening %s (stage %d id %#x ino %d peer %d)\n", + pr_info("Opening %s (stage %d id %#x ino %u peer %u)\n", prefix, fle->stage, ui->ue->id, ui->ue->ino, ui->ue->peer); } @@ -1950,7 +1950,7 @@ static char *socket_d_name(struct file_desc *d, char *buf, size_t s) ui = container_of(d, struct unix_sk_info, d); - if (snprintf(buf, s, "socket:[%d]", ui->ue->ino) >= s) { + if (snprintf(buf, s, "socket:[%u]", ui->ue->ino) >= s) { pr_err("Not enough room for unixsk %d identifier string\n", ui->ue->ino); return NULL; @@ -1981,14 +1981,14 @@ static int unlink_sk(struct unix_sk_info *ui) ret = unlinkat(AT_FDCWD, ui->name, 0) ? -1 : 0; if (ret < 0 && errno != ENOENT) { - pr_warn("Can't unlink socket %d peer %d (name %s dir %s)\n", + pr_warn("Can't unlink socket %u peer %u (name %s dir %s)\n", ui->ue->ino, ui->ue->peer, ui->name ? (ui->name[0] ? ui->name : &ui->name[1]) : "-", ui->name_dir ? ui->name_dir : "-"); ret = -errno; goto out; } else if (ret == 0) { - pr_debug("Unlinked socket %d peer %d (name %s dir %s)\n", + pr_debug("Unlinked socket %u peer %u (name %s dir %s)\n", ui->ue->ino, ui->ue->peer, ui->name ? (ui->name[0] ? ui->name : &ui->name[1]) : "-", ui->name_dir ? ui->name_dir : "-"); @@ -2065,7 +2065,7 @@ int unix_prepare_root_shared(void) char tp_name[32]; char st_name[32]; - pr_debug("ghost: id %#x type %s state %s ino %d peer %d address %s\n", + pr_debug("ghost: id %#x type %s state %s ino %u peer %u address %s\n", ui->ue->id, __socket_type_name(ui->ue->type, tp_name), __tcp_state_name(ui->ue->state, st_name), ui->ue->ino, ui->peer ? ui->peer->ue->ino : 0, @@ -2113,7 +2113,7 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) uname = "-"; } - pr_info(" `- Got id %#x ino %d type %s state %s peer %d (name %s%.*s dir %s)\n", + pr_info(" `- Got id %#x ino %u type %s state %s peer %u (name %s%.*s dir %s)\n", ui->ue->id, ui->ue->ino, ___socket_type_name(ui->ue->type), ___tcp_state_name(ui->ue->state), ui->ue->peer, prefix, ulen, uname, ui->name_dir ? ui->name_dir : "-"); @@ -2128,7 +2128,7 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) if (ui->ue->deleted) { if (!ui->name || !ui->ue->name.len || !ui->name[0]) { - pr_err("No name present, ino %d\n", ui->ue->ino); + pr_err("No name present, ino %u\n", ui->ue->ino); return -1; } From 578597299a82f0aea0ef7a3063e6dc6ea6fccb33 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 30 Sep 2019 20:57:08 +0000 Subject: [PATCH 2181/4375] Cleanup do_full_int80() 1) Instead of tampering with the nr argument, do_full_int80() returns the value of the system call. It also avoids copying all registers back into the syscall_args32 argument after the syscall. 2) Additionally, the registers r12-r15 were added in the list of clobbers as kernels older than v4.4 do not preserve these. 3) Further, GCC uses a 128-byte red-zone as defined in the x86_64 ABI optimizing away the correct position of the %rsp register in leaf-functions. We now avoid tampering with the red-zone, fixing a SIGSEGV when running mmap_bug_test() in debug mode (DEBUG=1). Signed-off-by: Nicolas Viennot Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Signed-off-by: Andrei Vagin --- criu/arch/x86/crtools.c | 6 ++-- criu/arch/x86/include/asm/compat.h | 51 ++++++++++++++++++++---------- criu/arch/x86/kerndat.c | 4 +-- criu/arch/x86/restorer.c | 3 +- criu/arch/x86/sigaction_compat.c | 6 +--- 5 files changed, 40 insertions(+), 30 deletions(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index efc23e5fe..e4073c27b 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -590,8 +590,7 @@ static int get_robust_list32(pid_t pid, uintptr_t head, uintptr_t len) .arg2 = (uint32_t)len, }; - do_full_int80(&s); - return (int)s.nr; + return do_full_int80(&s); } static int set_robust_list32(uint32_t head, uint32_t len) @@ -602,8 +601,7 @@ static int set_robust_list32(uint32_t head, uint32_t len) .arg1 = len, }; - do_full_int80(&s); - return (int)s.nr; + return do_full_int80(&s); } int get_task_futex_robust_list_compat(pid_t pid, ThreadCoreEntry *info) diff --git a/criu/arch/x86/include/asm/compat.h b/criu/arch/x86/include/asm/compat.h index cd1ae472d..acd552fb3 100644 --- a/criu/arch/x86/include/asm/compat.h +++ b/criu/arch/x86/include/asm/compat.h @@ -38,26 +38,45 @@ struct syscall_args32 { uint32_t nr, arg0, arg1, arg2, arg3, arg4, arg5; }; -static inline void do_full_int80(struct syscall_args32 *args) +static inline uint32_t do_full_int80(struct syscall_args32 *args) { /* - * r8-r11 registers are cleared during returning to userspace - * from syscall - that's x86_64 ABI to avoid leaking kernel - * pointers. + * Kernel older than v4.4 do not preserve r8-r15 registers when + * invoking int80, so we need to preserve them. * - * Other than that - we can't use %rbp in clobbers as GCC's inline - * assembly doesn't allow to do so. So, here is explicitly saving - * %rbp before syscall and restoring it's value afterward. + * Additionally, %rbp is used as the 6th syscall argument, and we need + * to preserve its value when returning from the syscall to avoid + * upsetting GCC. However, we can't use %rbp in the GCC asm clobbers + * due to a GCC limitation. Instead, we explicitly save %rbp on the + * stack before invoking the syscall and restore its value afterward. + * + * Further, GCC may not adjust the %rsp pointer when allocating the + * args and ret variables because 1) do_full_int80() is a leaf + * function, and 2) the local variables (args and ret) are in the + * 128-byte red-zone as defined in the x86_64 ABI. To use the stack + * when preserving %rbp, we must either tell GCC to a) mark the + * function as non-leaf, or b) move away from the red-zone when using + * the stack. It seems that there is no easy way to do a), so we'll go + * with b). + * Note 1: Another workaround would have been to add %rsp in the list + * of clobbers, but this was deprecated in GCC 9. + * Note 2: This red-zone bug only manifests when compiling CRIU with + * DEBUG=1. */ - asm volatile ("pushq %%rbp\n\t" - "mov %6, %%ebp\n\t" - "int $0x80\n\t" - "mov %%ebp, %6\n\t" - "popq %%rbp\n\t" - : "+a" (args->nr), - "+b" (args->arg0), "+c" (args->arg1), "+d" (args->arg2), - "+S" (args->arg3), "+D" (args->arg4), "+g" (args->arg5) - : : "r8", "r9", "r10", "r11"); + uint32_t ret; + + asm volatile ("sub $128, %%rsp\n\t" + "pushq %%rbp\n\t" + "mov %7, %%ebp\n\t" + "int $0x80\n\t" + "popq %%rbp\n\t" + "add $128, %%rsp\n\t" + : "=a" (ret) + : "a" (args->nr), + "b" (args->arg0), "c" (args->arg1), "d" (args->arg2), + "S" (args->arg3), "D" (args->arg4), "g" (args->arg5) + : "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"); + return ret; } #ifndef CR_NOGLIBC diff --git a/criu/arch/x86/kerndat.c b/criu/arch/x86/kerndat.c index f7593251b..94c954e1e 100644 --- a/criu/arch/x86/kerndat.c +++ b/criu/arch/x86/kerndat.c @@ -75,9 +75,7 @@ void *mmap_ia32(void *addr, size_t len, int prot, s.arg4 = fildes; s.arg5 = (uint32_t)off; - do_full_int80(&s); - - return (void *)(uintptr_t)s.nr; + return (void *)(uintptr_t)do_full_int80(&s); } /* diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c index 2d335d5e1..b2c3b3668 100644 --- a/criu/arch/x86/restorer.c +++ b/criu/arch/x86/restorer.c @@ -54,8 +54,7 @@ int set_compat_robust_list(uint32_t head_ptr, uint32_t len) .arg1 = len, }; - do_full_int80(&s); - return (int)s.nr; + return do_full_int80(&s); } static int prepare_stack32(void **stack32) diff --git a/criu/arch/x86/sigaction_compat.c b/criu/arch/x86/sigaction_compat.c index b38ba8011..f467da490 100644 --- a/criu/arch/x86/sigaction_compat.c +++ b/criu/arch/x86/sigaction_compat.c @@ -28,7 +28,6 @@ extern char restore_rt_sigaction; */ int arch_compat_rt_sigaction(void *stack32, int sig, rt_sigaction_t_compat *act) { - int ret; struct syscall_args32 arg = {}; unsigned long act_stack = (unsigned long)stack32; @@ -49,8 +48,5 @@ int arch_compat_rt_sigaction(void *stack32, int sig, rt_sigaction_t_compat *act) arg.arg2 = 0; /* oldact */ arg.arg3 = (uint32_t)sizeof(act->rt_sa_mask); /* sigsetsize */ - do_full_int80(&arg); - asm volatile ("\t movl %%eax,%0\n" : "=r"(ret)); - return ret; + return do_full_int80(&arg); } - From 576a99f492b1f55050d4fde8560efe454ab887bc Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 4 Oct 2019 16:32:48 +0100 Subject: [PATCH 2182/4375] restorer/inotify: Don't overflow PIE stack PATH_MAX == 4096; PATH_MAX*8 == 32k; RESTORE_STACK_SIZE == 32k. Fixes: a3cdf948699c6 ("inotify: cleanup auxiliary events from queue") Cc: Pavel Tikhomirov Cc: Andrei Vagin Co-debugged-with: Andrei Vagin Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/pie/restorer.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 390c0e1a9..dab58add6 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1320,21 +1320,23 @@ static int fd_poll(int inotify_fd) } /* - * note: Actually kernel may want even more space for one event (see - * round_event_name_len), so using buffer of EVENT_BUFF_SIZE size may fail. - * To be on the safe side - take a bigger buffer, and these also allows to - * read more events in one syscall. + * In the worst case buf size should be: + * sizeof(struct inotify_event) * 2 + PATH_MAX + * See round_event_name_len() in kernel. */ -#define EVENT_BUFF_SIZE ((sizeof(struct inotify_event) + PATH_MAX)) +#define EVENT_BUFF_SIZE ((sizeof(struct inotify_event) * 2 + PATH_MAX)) /* * Read all available events from inotify queue */ static int cleanup_inotify_events(int inotify_fd) { - char buf[EVENT_BUFF_SIZE * 8]; + char buf[EVENT_BUFF_SIZE * 3]; int ret; + /* Limit buf to be lesser than half of restorer's stack */ + BUILD_BUG_ON(ARRAY_SIZE(buf) >= RESTORE_STACK_SIZE/2); + while (1) { ret = fd_poll(inotify_fd); if (ret < 0) { From 20d4920a8bf74d1eceebc076bcc00889ba40e9f7 Mon Sep 17 00:00:00 2001 From: Abhishek Dubey Date: Thu, 3 Oct 2019 19:39:18 +0530 Subject: [PATCH 2183/4375] Adding --pre-dump-mode option Two modes of pre-dump algorithm: 1) splicing memory by parasite --pre-dump-mode=splice (default) 2) using process_vm_readv syscall --pre-dump-mode=read Signed-off-by: Abhishek Dubey Signed-off-by: Andrei Vagin --- Documentation/criu.txt | 6 ++++++ criu/config.c | 10 ++++++++++ criu/cr-service.c | 13 +++++++++++++ criu/crtools.c | 2 ++ criu/include/cr_options.h | 7 +++++++ criu/mem.c | 13 ++++++++++++- images/rpc.proto | 6 ++++++ lib/c/criu.c | 15 +++++++++++++++ lib/c/criu.h | 7 +++++++ test/zdtm.py | 9 ++++++++- 10 files changed, 86 insertions(+), 2 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 28913a7fb..2729bc95a 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -156,6 +156,12 @@ In addition, *page-server* options may be specified. Turn on memory changes tracker in the kernel. If the option is not passed the memory tracker get turned on implicitly. +*--pre-dump-mode*='mode':: + There are two 'mode' to operate pre-dump algorithm. The 'splice' mode + is parasite based, whereas 'read' mode is based on process_vm_readv + syscall. The 'read' mode incurs reduced frozen time and reduced + memory pressure as compared to 'splice' mode. Default is 'splice' mode. + *dump* ~~~~~~ Performs a checkpoint procedure. diff --git a/criu/config.c b/criu/config.c index 2ad2fd43c..e5d42efe4 100644 --- a/criu/config.c +++ b/criu/config.c @@ -276,6 +276,7 @@ void init_opts(void) opts.empty_ns = 0; opts.status_fd = -1; opts.log_level = DEFAULT_LOGLEVEL; + opts.pre_dump_mode = PRE_DUMP_SPLICE; } bool deprecated_ok(char *what) @@ -517,6 +518,7 @@ int parse_options(int argc, char **argv, bool *usage_error, BOOL_OPT("tls", &opts.tls), {"tls-no-cn-verify", no_argument, &opts.tls_no_cn_verify, true}, { "cgroup-yard", required_argument, 0, 1096 }, + { "pre-dump-mode", required_argument, 0, 1097}, { }, }; @@ -818,6 +820,14 @@ int parse_options(int argc, char **argv, bool *usage_error, case 1096: SET_CHAR_OPTS(cgroup_yard, optarg); break; + case 1097: + if (!strcmp("read", optarg)) { + opts.pre_dump_mode = PRE_DUMP_READ; + } else if (strcmp("splice", optarg)) { + pr_err("Unable to parse value of --pre-dump-mode\n"); + return 1; + } + break; case 'V': pr_msg("Version: %s\n", CRIU_VERSION); if (strcmp(CRIU_GITID, "0")) diff --git a/criu/cr-service.c b/criu/cr-service.c index 95ba2e5ce..392e9ac50 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -473,6 +473,19 @@ static int setup_opts_from_req(int sk, CriuOpts *req) opts.lazy_pages = req->lazy_pages; } + if (req->has_pre_dump_mode) { + switch (req->pre_dump_mode) { + case CRIU_PRE_DUMP_MODE__SPLICE: + opts.pre_dump_mode = PRE_DUMP_SPLICE; + break; + case CRIU_PRE_DUMP_MODE__READ: + opts.pre_dump_mode = PRE_DUMP_READ; + break; + default: + goto err; + } + } + if (req->ps) { opts.port = (short)req->ps->port; diff --git a/criu/crtools.c b/criu/crtools.c index 5740b806d..700fad994 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -428,6 +428,8 @@ usage: " pages images of previous dump\n" " when used on restore, as soon as page is restored, it\n" " will be punched from the image\n" +" --pre-dump-mode splice - parasite based pre-dumping (default)\n" +" read - process_vm_readv syscall based pre-dumping\n" "\n" "Page/Service server options:\n" " --address ADDR address of server or service\n" diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index da7c10d69..2c1451e86 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -38,6 +38,12 @@ struct cg_root_opt { char *newroot; }; +/* + * Pre-dump variants + */ +#define PRE_DUMP_SPLICE 1 /* Pre-dump using parasite */ +#define PRE_DUMP_READ 2 /* Pre-dump using process_vm_readv syscall */ + /* * Cgroup management options. */ @@ -81,6 +87,7 @@ struct cr_options { int evasive_devices; int link_remap_ok; int log_file_per_pid; + int pre_dump_mode; bool swrk_restore; char *output; char *root; diff --git a/criu/mem.c b/criu/mem.c index de66a6210..911b9d21c 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -482,7 +482,18 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, if (mdc->lazy) memcpy(pargs_iovs(args), pp->iovs, sizeof(struct iovec) * pp->nr_iovs); - ret = drain_pages(pp, ctl, args); + + /* + * Faking drain_pages for pre-dump here. Actual drain_pages for pre-dump + * will happen after task unfreezing in cr_pre_dump_finish(). This is + * actual optimization which reduces time for which process was frozen + * during pre-dump. + */ + if (mdc->pre_dump && opts.pre_dump_mode == PRE_DUMP_READ) + ret = 0; + else + ret = drain_pages(pp, ctl, args); + if (!ret && !mdc->pre_dump) ret = xfer_pages(pp, &xfer); if (ret) diff --git a/images/rpc.proto b/images/rpc.proto index c402259ac..fc2f1bce2 100644 --- a/images/rpc.proto +++ b/images/rpc.proto @@ -47,6 +47,11 @@ enum criu_cg_mode { DEFAULT = 6; }; +enum criu_pre_dump_mode { + SPLICE = 1; + READ = 2; +}; + message criu_opts { required int32 images_dir_fd = 1; optional int32 pid = 2; /* if not set on dump, will dump requesting process */ @@ -121,6 +126,7 @@ message criu_opts { optional bool tls = 58; optional bool tls_no_cn_verify = 59; optional string cgroup_yard = 60; + optional criu_pre_dump_mode pre_dump_mode = 61 [default = SPLICE]; /* optional bool check_mounts = 128; */ } diff --git a/lib/c/criu.c b/lib/c/criu.c index 14ddff26d..fffb9fd9c 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -336,6 +336,21 @@ int criu_set_parent_images(const char *path) return criu_local_set_parent_images(global_opts, path); } +int criu_local_set_pre_dump_mode(criu_opts *opts, enum criu_pre_dump_mode mode) +{ + opts->rpc->has_pre_dump_mode = true; + if (mode == CRIU_PRE_DUMP_SPLICE || mode == CRIU_PRE_DUMP_READ) { + opts->rpc->pre_dump_mode = mode; + return 0; + } + return -1; +} + +int criu_set_pre_dump_mode(enum criu_pre_dump_mode mode) +{ + return criu_local_set_pre_dump_mode(global_opts, mode); +} + void criu_local_set_track_mem(criu_opts *opts, bool track_mem) { opts->rpc->has_track_mem = true; diff --git a/lib/c/criu.h b/lib/c/criu.h index cb37c5291..22db0fdcf 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -43,6 +43,11 @@ enum criu_cg_mode { CRIU_CG_MODE_DEFAULT, }; +enum criu_pre_dump_mode { + CRIU_PRE_DUMP_SPLICE = 1, + CRIU_PRE_DUMP_READ = 2 +}; + int criu_set_service_address(const char *path); void criu_set_service_fd(int fd); int criu_set_service_binary(const char *path); @@ -95,6 +100,7 @@ int criu_add_irmap_path(const char *path); int criu_add_inherit_fd(int fd, const char *key); int criu_add_external(const char *key); int criu_set_page_server_address_port(const char *address, int port); +int criu_set_pre_dump_mode(enum criu_pre_dump_mode mode); /* * The criu_notify_arg_t na argument is an opaque @@ -211,6 +217,7 @@ int criu_local_add_cg_yard(criu_opts *opts, const char *path); int criu_local_add_inherit_fd(criu_opts *opts, int fd, const char *key); int criu_local_add_external(criu_opts *opts, const char *key); int criu_local_set_page_server_address_port(criu_opts *opts, const char *address, int port); +int criu_local_set_pre_dump_mode(criu_opts *opts, enum criu_pre_dump_mode mode); void criu_local_set_notify_cb(criu_opts *opts, int (*cb)(char *action, criu_notify_arg_t na)); diff --git a/test/zdtm.py b/test/zdtm.py index f0a102413..3c0cee667 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1019,6 +1019,7 @@ class criu: self.__tls = self.__tls_options() if opts['tls'] else [] self.__criu_bin = opts['criu_bin'] self.__crit_bin = opts['crit_bin'] + self.__pre_dump_mode = opts['pre_dump_mode'] def fini(self): if self.__lazy_migrate: @@ -1249,6 +1250,8 @@ class criu: a_opts += ['--leave-stopped'] if self.__empty_ns: a_opts += ['--empty-ns', 'net'] + if self.__pre_dump_mode: + a_opts += ["--pre-dump-mode", "%s" % self.__pre_dump_mode] nowait = False if self.__lazy_migrate and action == "dump": @@ -1835,7 +1838,7 @@ class Launcher: 'sat', 'script', 'rpc', 'lazy_pages', 'join_ns', 'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup', 'remote_lazy_pages', 'show_stats', 'lazy_migrate', - 'tls', 'criu_bin', 'crit_bin') + 'tls', 'criu_bin', 'crit_bin', 'pre_dump_mode') arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd})) if self.__use_log: @@ -2482,6 +2485,10 @@ rp.add_argument("--criu-bin", rp.add_argument("--crit-bin", help="Path to crit binary", default='../crit/crit') +rp.add_argument("--pre-dump-mode", + help="Use splice or read mode of pre-dumping", + choices=['splice', 'read'], + default='splice') lp = sp.add_parser("list", help="List tests") lp.set_defaults(action=list_tests) From e0ea21ad5ecafadad653f46a0ed8cbef69c7b883 Mon Sep 17 00:00:00 2001 From: Abhishek Dubey Date: Thu, 3 Oct 2019 19:39:19 +0530 Subject: [PATCH 2184/4375] Handling iov generation for non-PROT_READ regions Skip iov-generation for regions not having PROT_READ, since process_vm_readv syscall can't process them during "read" pre-dump. Handle random order of "read" & "splice" pre-dumps. Signed-off-by: Abhishek Dubey Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 5 ++++ criu/mem.c | 56 ++++++++++++++++++++++++++++++++++++++++-- images/inventory.proto | 1 + 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index fcbe816e8..dd5b62dd0 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1485,6 +1485,9 @@ static int cr_pre_dump_finish(int status) if (ret) goto err; + he.has_pre_dump_mode = true; + he.pre_dump_mode = opts.pre_dump_mode; + pstree_switch_state(root_item, TASK_ALIVE); timing_stop(TIME_FROZEN); @@ -1914,6 +1917,8 @@ int cr_dump_tasks(pid_t pid) if (ret) goto err; + he.has_pre_dump_mode = false; + ret = write_img_inventory(&he); if (ret) goto err; diff --git a/criu/mem.c b/criu/mem.c index 911b9d21c..a5de23755 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -351,7 +351,8 @@ static int generate_vma_iovs(struct pstree_item *item, struct vma_area *vma, struct page_pipe *pp, struct page_xfer *xfer, struct parasite_dump_pages_args *args, struct parasite_ctl *ctl, pmc_t *pmc, - bool has_parent, bool pre_dump) + bool has_parent, bool pre_dump, + int parent_predump_mode) { u64 off = 0; u64 *map; @@ -361,6 +362,52 @@ static int generate_vma_iovs(struct pstree_item *item, struct vma_area *vma, !vma_area_is(vma, VMA_ANON_SHARED)) return 0; + /* + * To facilitate any combination of pre-dump modes to run after + * one another, we need to take extra care as discussed below. + * + * The SPLICE mode pre-dump, processes all type of memory regions, + * whereas READ mode pre-dump skips processing those memory regions + * which lacks PROT_READ flag. + * + * Now on mixing pre-dump modes: + * If SPLICE mode follows SPLICE mode : no issue + * -> everything dumped both the times + * + * If READ mode follows READ mode : no issue + * -> non-PROT_READ skipped both the time + * + * If READ mode follows SPLICE mode : no issue + * -> everything dumped at first, + * the non-PROT_READ skipped later + * + * If SPLICE mode follows READ mode : Need special care + * + * If READ pre-dump happens first, then it has skipped processing + * non-PROT_READ regions. Following SPLICE pre-dump expects pagemap + * entries for all mappings in parent pagemap, but last READ mode + * pre-dump cycle has skipped processing & pagemap generation for + * non-PROT_READ regions. So SPLICE mode throws error of missing + * pagemap entry for encountered non-PROT_READ mapping. + * + * To resolve this, the pre-dump-mode is stored in current pre-dump's + * inventoy file. This pre-dump mode is read back from this file + * (present in parent pre-dump dir) as parent-pre-dump-mode during + * next pre-dump. + * + * If parent-pre-dump-mode and next-pre-dump-mode are in READ-mode -> + * SPLICE-mode order, then SPLICE mode doesn't expect mappings for + * non-PROT_READ regions in parent-image and marks "has_parent=false". + */ + + if (!(vma->e->prot & PROT_READ)) { + if (opts.pre_dump_mode == PRE_DUMP_READ && pre_dump) + return 0; + if ((parent_predump_mode == PRE_DUMP_READ && + opts.pre_dump_mode == PRE_DUMP_SPLICE) || !pre_dump) + has_parent = false; + } + if (vma_entry_is(vma->e, VMA_AREA_AIORING)) { if (pre_dump) return 0; @@ -406,6 +453,7 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, unsigned long pmc_size; int possible_pid_reuse = 0; bool has_parent; + int parent_predump_mode = -1; pr_info("\n"); pr_info("Dumping pages (type: %d pid: %d)\n", CR_FD_PAGES, item->pid->real); @@ -472,9 +520,13 @@ static int __parasite_dump_pages_seized(struct pstree_item *item, */ args->off = 0; has_parent = !!xfer.parent && !possible_pid_reuse; + if(mdc->parent_ie) + parent_predump_mode = mdc->parent_ie->pre_dump_mode; + list_for_each_entry(vma_area, &vma_area_list->h, list) { ret = generate_vma_iovs(item, vma_area, pp, &xfer, args, ctl, - &pmc, has_parent, mdc->pre_dump); + &pmc, has_parent, mdc->pre_dump, + parent_predump_mode); if (ret < 0) goto out_xfer; } diff --git a/images/inventory.proto b/images/inventory.proto index 7bc2b0c02..d1438e8c8 100644 --- a/images/inventory.proto +++ b/images/inventory.proto @@ -16,4 +16,5 @@ message inventory_entry { optional uint32 root_cg_set = 5; optional lsmtype lsmtype = 6; optional uint64 dump_uptime = 8; + optional uint32 pre_dump_mode = 9; } From 29b63e9a720ec3e996de3bdbeccde5d7c0cb46e3 Mon Sep 17 00:00:00 2001 From: Abhishek Dubey Date: Thu, 3 Oct 2019 19:39:20 +0530 Subject: [PATCH 2185/4375] Skip adding PROT_READ to non-PROT_READ mappings "read" mode pre-dump may fail even after adding PROT_READ flag. Adding PROT_READ works when dumping statically. See added comment for details. Signed-off-by: Abhishek Dubey Signed-off-by: Andrei Vagin --- criu/mem.c | 54 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/criu/mem.c b/criu/mem.c index a5de23755..4e110c9e9 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -591,13 +591,47 @@ int parasite_dump_pages_seized(struct pstree_item *item, * able to read the memory contents. * * Afterwards -- reprotect memory back. + * + * This step is required for "splice" mode pre-dump and dump. + * Skip this step for "read" mode pre-dump. + * "read" mode pre-dump delegates processing of non-PROT_READ + * regions to dump stage. Adding PROT_READ works fine for + * static processing (target process frozen during pre-dump) + * and fails for dynamic as explained below. + * + * Consider following sequence of instances to reason, why + * not to add PROT_READ in "read" mode pre-dump ? + * + * CRIU- "read" pre-dump Target Process + * + * 1. Creates mapping M + * without PROT_READ + * 2. CRIU freezes target + * process + * 3. Collect the mappings + * 4. Add PROT_READ to M + * (non-PROT_READ region) + * 5. CRIU unfreezes target + * process + * 6. Add flag PROT_READ + * to mapping M + * 7. Revoke flag PROT_READ + * from mapping M + * 8. process_vm_readv tries + * to copy mapping M + * (believing M have + * PROT_READ flag) + * 9. syscall fails to copy + * data from M */ - pargs->add_prot = PROT_READ; - ret = compel_rpc_call_sync(PARASITE_CMD_MPROTECT_VMAS, ctl); - if (ret) { - pr_err("Can't dump unprotect vmas with parasite\n"); - return ret; + if (!mdc->pre_dump || opts.pre_dump_mode == PRE_DUMP_SPLICE) { + pargs->add_prot = PROT_READ; + ret = compel_rpc_call_sync(PARASITE_CMD_MPROTECT_VMAS, ctl); + if (ret) { + pr_err("Can't dump unprotect vmas with parasite\n"); + return ret; + } } if (fault_injected(FI_DUMP_PAGES)) { @@ -612,10 +646,12 @@ int parasite_dump_pages_seized(struct pstree_item *item, return ret; } - pargs->add_prot = 0; - if (compel_rpc_call_sync(PARASITE_CMD_MPROTECT_VMAS, ctl)) { - pr_err("Can't rollback unprotected vmas with parasite\n"); - ret = -1; + if (!mdc->pre_dump || opts.pre_dump_mode == PRE_DUMP_SPLICE) { + pargs->add_prot = 0; + if (compel_rpc_call_sync(PARASITE_CMD_MPROTECT_VMAS, ctl)) { + pr_err("Can't rollback unprotected vmas with parasite\n"); + ret = -1; + } } return ret; From 4c774afc18e8af458eeb03ea021ba52d0af4b32c Mon Sep 17 00:00:00 2001 From: Abhishek Dubey Date: Thu, 3 Oct 2019 19:39:21 +0530 Subject: [PATCH 2186/4375] Adding cnt_sub for stats manipulation adding cnt_sub function (complement of cnt_add). cnt_sub is utilized to decrement stats counter according to skipped page count during "read" mode pre-dump. Signed-off-by: Abhishek Dubey Signed-off-by: Andrei Vagin --- criu/include/stats.h | 1 + criu/stats.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/criu/include/stats.h b/criu/include/stats.h index bab9a0507..5d408b7b1 100644 --- a/criu/include/stats.h +++ b/criu/include/stats.h @@ -45,6 +45,7 @@ enum { }; extern void cnt_add(int c, unsigned long val); +extern void cnt_sub(int c, unsigned long val); #define DUMP_STATS 1 #define RESTORE_STATS 2 diff --git a/criu/stats.c b/criu/stats.c index 7410b5ced..cb528011a 100644 --- a/criu/stats.c +++ b/criu/stats.c @@ -41,6 +41,18 @@ void cnt_add(int c, unsigned long val) BUG(); } +void cnt_sub(int c, unsigned long val) +{ + if (dstats != NULL) { + BUG_ON(c >= DUMP_CNT_NR_STATS); + dstats->counts[c] -= val; + } else if (rstats != NULL) { + BUG_ON(c >= RESTORE_CNT_NR_STATS); + atomic_sub(val, &rstats->counts[c]); + } else + BUG(); +} + static void timeval_accumulate(const struct timeval *from, const struct timeval *to, struct timeval *res) { From 98608b90de0f853b1c8a6e15b312320e1441c359 Mon Sep 17 00:00:00 2001 From: Abhishek Dubey Date: Thu, 3 Oct 2019 19:39:22 +0530 Subject: [PATCH 2187/4375] read mode pre-dump implementation Pre-dump using the process_vm_readv syscall. During frozen state, only iovecs will be generated and draining of memory happens after the task is unfrozen. Pre-dumping of shared memory remains unmodified. Signed-off-by: Abhishek Dubey Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 7 +- criu/include/page-xfer.h | 4 + criu/page-xfer.c | 389 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 399 insertions(+), 1 deletion(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index dd5b62dd0..ff05e38d7 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1513,7 +1513,12 @@ static int cr_pre_dump_finish(int status) goto err; mem_pp = dmpi(item)->mem_pp; - ret = page_xfer_dump_pages(&xfer, mem_pp); + + if (opts.pre_dump_mode == PRE_DUMP_READ) + ret = page_xfer_predump_pages(item->pid->real, + &xfer, mem_pp); + else + ret = page_xfer_dump_pages(&xfer, mem_pp); xfer.close(&xfer); diff --git a/criu/include/page-xfer.h b/criu/include/page-xfer.h index fa72273ea..98061e2d3 100644 --- a/criu/include/page-xfer.h +++ b/criu/include/page-xfer.h @@ -9,6 +9,9 @@ struct ps_info { extern int cr_page_server(bool daemon_mode, bool lazy_dump, int cfd); +/* User buffer for read-mode pre-dump*/ +#define BUFFER_SIZE (PIPE_MAX_SIZE << PAGE_SHIFT) + /* * page_xfer -- transfer pages into image file. * Two images backends are implemented -- local image file @@ -48,6 +51,7 @@ struct page_xfer { extern int open_page_xfer(struct page_xfer *xfer, int fd_type, unsigned long id); struct page_pipe; extern int page_xfer_dump_pages(struct page_xfer *, struct page_pipe *); +extern int page_xfer_predump_pages(int pid, struct page_xfer *, struct page_pipe *); extern int connect_to_page_server_to_send(void); extern int connect_to_page_server_to_recv(int epfd); extern int disconnect_from_page_server(void); diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 75e135c66..8709df745 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -6,6 +6,7 @@ #include #include #include +#include #undef LOG_PREFIX #define LOG_PREFIX "page-xfer: " @@ -480,6 +481,394 @@ static inline u32 ppb_xfer_flags(struct page_xfer *xfer, struct page_pipe_buf *p return PE_PRESENT; } +/* + * Optimized pre-dump algorithm + * ============================== + * + * Note: Please refer man(2) page of process_vm_readv syscall. + * + * The following discussion covers the possibly faulty-iov + * locations in an iovec, which hinders process_vm_readv from + * dumping the entire iovec in a single invocation. + * + * Memory layout of target process: + * + * Pages: A B C + * +--------+--------+--------+--------+--------+--------+ + * ||||||||||||||||||||||||||||||||||||||||||||||||||||||| + * +--------+--------+--------+--------+--------+--------+ + * + * Single "iov" representation: {starting_address, length_in_bytes} + * An iovec is array of iov-s. + * + * NOTE: For easy representation and discussion purpose, we carry + * out further discussion at "page granularity". + * length_in_bytes will represent page count in iov instead + * of byte count. Same assumption applies for the syscall's + * return value. Instead of returning the number of bytes + * read, it returns a page count. + * + * For above memory mapping, generated iovec: {A,1}{B,1}{C,4} + * + * This iovec remains unmodified once generated. At the same + * time some of memory regions listed in iovec may get modified + * (unmap/change protection) by the target process while syscall + * is trying to dump iovec regions. + * + * Case 1: + * A is unmapped, {A,1} become faulty iov + * + * A B C + * +--------+--------+--------+--------+--------+--------+ + * | |||||||||||||||||||||||||||||||||||||||||||||| + * +--------+--------+--------+--------+--------+--------+ + * ^ ^ + * | | + * start | + * (1) | + * start + * (2) + * + * process_vm_readv will return -1. Increment start pointer(2), + * syscall will process {B,1}{C,4} in one go and copy 5 pages + * to userbuf from iov-B and iov-C. + * + * Case 2: + * B is unmapped, {B,1} become faulty iov + * + * A B C + * +--------+--------+--------+--------+--------+--------+ + * ||||||||| ||||||||||||||||||||||||||||||||||||| + * +--------+--------+--------+--------+--------+--------+ + * ^ ^ + * | | + * start | + * (1) | + * start + * (2) + * + * process_vm_readv will return 1, i.e. page A copied to + * userbuf successfully and syscall stopped, since B got + * unmapped. + * + * Increment the start pointer to C(2) and invoke syscall. + * Userbuf contains 5 pages overall from iov-A and iov-C. + * + * Case 3: + * This case deals with partial unmapping of iov representing + * more than one pagesize region. + * + * Syscall can't process such faulty iov as whole. So we + * process such regions part-by-part and form new sub-iovs + * in aux_iov from successfully processed pages. + * + * + * Part 3.1: + * First page of C is unmapped + * + * A B C + * +--------+--------+--------+--------+--------+--------+ + * |||||||||||||||||| |||||||||||||||||||||||||||| + * +--------+--------+--------+--------+--------+--------+ + * ^ ^ + * | | + * start | + * (1) | + * dummy + * (2) + * + * process_vm_readv will return 2, i.e. pages A and B copied. + * We identify length of iov-C is more than 1 page, that is + * where this case differs from Case 2. + * + * dummy-iov is introduced(2) as: {C+1,3}. dummy-iov can be + * directly placed at next page to failing page. This will copy + * remaining 3 pages from iov-C to userbuf. Finally create + * modified iov entry in aux_iov. Complete aux_iov look like: + * + * aux_iov: {A,1}{B,1}{C+1,3}* + * + * + * Part 3.2: + * In between page of C is unmapped, let's say third + * + * A B C + * +--------+--------+--------+--------+--------+--------+ + * |||||||||||||||||||||||||||||||||||| |||||||||| + * +--------+--------+--------+--------+--------+--------+ + * ^ ^ + * | |-----------------| | + * start partial_read_bytes | + * (1) | + * dummy + * (2) + * + * process_vm_readv will return 4, i.e. pages A and B copied + * completely and first two pages of C are also copied. + * + * Since, iov-C is not processed completely, we need to find + * "partial_read_byte" count to place out dummy-iov for + * remainig processing of iov-C. This function is performed by + * analyze_iov function. + * + * dummy-iov will be(2): {C+3,1}. dummy-iov will be placed + * next to first failing address to process remaining iov-C. + * New entries in aux_iov will look like: + * + * aux_iov: {A,1}{B,1}{C,2}*{C+3,1}* + */ + +unsigned long handle_faulty_iov(int pid, struct iovec* riov, + unsigned long faulty_index, + struct iovec *bufvec, struct iovec* aux_iov, + unsigned long* aux_len, + unsigned long partial_read_bytes) +{ + /* Handling Case 2*/ + if (riov[faulty_index].iov_len == PAGE_SIZE) { + cnt_sub(CNT_PAGES_WRITTEN, 1); + return 0; + } + + struct iovec dummy; + ssize_t bytes_read; + unsigned long offset = 0; + unsigned long final_read_cnt = 0; + + /* Handling Case 3-Part 3.2*/ + offset = (partial_read_bytes)? partial_read_bytes : PAGE_SIZE; + + dummy.iov_base = riov[faulty_index].iov_base + offset; + dummy.iov_len = riov[faulty_index].iov_len - offset; + + if (!partial_read_bytes) + cnt_sub(CNT_PAGES_WRITTEN, 1); + + while (dummy.iov_len) { + + bytes_read = process_vm_readv(pid, bufvec, 1, &dummy, 1, 0); + + if(bytes_read == -1) { + /* Handling faulty page read in faulty iov */ + cnt_sub(CNT_PAGES_WRITTEN, 1); + dummy.iov_base += PAGE_SIZE; + dummy.iov_len -= PAGE_SIZE; + continue; + } + + /* If aux-iov can merge and expand or new entry required */ + if (aux_iov[(*aux_len)-1].iov_base + + aux_iov[(*aux_len)-1].iov_len == dummy.iov_base) + aux_iov[(*aux_len)-1].iov_len += bytes_read; + else { + aux_iov[*aux_len].iov_base = dummy.iov_base; + aux_iov[*aux_len].iov_len = bytes_read; + (*aux_len) += 1; + } + + dummy.iov_base += bytes_read; + dummy.iov_len -= bytes_read; + bufvec->iov_base += bytes_read; + bufvec->iov_len -= bytes_read; + final_read_cnt += bytes_read; + } + + return final_read_cnt; +} + +/* + * This function will position start pointer to the latest + * successfully read iov in iovec. In case of partial read it + * returns partial_read_bytes, otherwise 0. + */ +static unsigned long analyze_iov(ssize_t bytes_read, struct iovec* riov, + unsigned long *index, struct iovec *aux_iov, + unsigned long *aux_len) +{ + ssize_t processed_bytes = 0; + unsigned long partial_read_bytes = 0; + + /* correlating iovs with read bytes */ + while (processed_bytes < bytes_read) { + + processed_bytes += riov[*index].iov_len; + aux_iov[*aux_len].iov_base = riov[*index].iov_base; + aux_iov[*aux_len].iov_len = riov[*index].iov_len; + + (*aux_len) += 1; + (*index) += 1; + } + + /* handling partially processed faulty iov*/ + if (processed_bytes - bytes_read) { + + (*index) -= 1; + + partial_read_bytes = riov[*index].iov_len + - (processed_bytes - bytes_read); + aux_iov[*aux_len-1].iov_len = partial_read_bytes; + } + + return partial_read_bytes; +} + +/* + * This function iterates over complete ppb->iov entries and pass + * them to process_vm_readv syscall. + * + * Since process_vm_readv returns count of successfully read bytes. + * It does not point to iovec entry associated to last successful + * byte read. The correlation between bytes read and corresponding + * iovec is setup through analyze_iov function. + * + * If all iovecs are not processed in one go, it means there exists + * some faulty iov entry(memory mapping modified after it was grabbed) + * in iovec. process_vm_readv syscall stops at such faulty iov and + * skip processing further any entry in iovec. This is handled by + * handle_faulty_iov function. + */ +static long fill_userbuf(int pid, struct page_pipe_buf *ppb, + struct iovec *bufvec, + struct iovec* aux_iov, + unsigned long *aux_len) +{ + struct iovec *riov = ppb->iov; + ssize_t bytes_read; + unsigned long total_read = 0; + unsigned long start = 0; + unsigned long partial_read_bytes = 0; + + while (start < ppb->nr_segs) { + + bytes_read = process_vm_readv(pid, bufvec, 1, &riov[start], + ppb->nr_segs - start, 0); + + if (bytes_read == -1) { + /* Handling Case 1*/ + if (riov[start].iov_len == PAGE_SIZE) { + cnt_sub(CNT_PAGES_WRITTEN, 1); + start += 1; + continue; + } else if (errno == ESRCH) { + pr_debug("Target process PID:%d not found\n", pid); + return ESRCH; + } + } + + partial_read_bytes = 0; + + if (bytes_read > 0) { + partial_read_bytes = analyze_iov(bytes_read, riov, + &start, aux_iov, + aux_len); + bufvec->iov_base += bytes_read; + bufvec->iov_len -= bytes_read; + total_read += bytes_read; + } + + /* + * If all iovs not processed in one go, + * it means some iov in between has failed. + */ + if (start < ppb->nr_segs) + total_read += handle_faulty_iov(pid, riov, start, bufvec, + aux_iov, aux_len, + partial_read_bytes); + + start += 1; + } + + return total_read; +} + +/* + * This function is similar to page_xfer_dump_pages, instead it uses + * auxiliary_iov array for pagemap generation. + * + * The entries of ppb->iov may mismatch with actual process mappings + * present at time of pre-dump. Such entries need to be adjusted as per + * the pages read by process_vm_readv syscall. These adjusted entries + * along with unmodified entries are present in aux_iov array. + */ + +int page_xfer_predump_pages(int pid, struct page_xfer *xfer, + struct page_pipe *pp) +{ + struct page_pipe_buf *ppb; + unsigned int cur_hole = 0, i; + unsigned long ret, bytes_read; + struct iovec bufvec; + + struct iovec aux_iov[PIPE_MAX_SIZE]; + unsigned long aux_len; + + char *userbuf = mmap(NULL, BUFFER_SIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + + if (userbuf == MAP_FAILED) { + pr_perror("Unable to mmap a buffer"); + return -1; + } + + list_for_each_entry(ppb, &pp->bufs, l) { + + aux_len = 0; + bufvec.iov_len = BUFFER_SIZE; + bufvec.iov_base = userbuf; + + bytes_read = fill_userbuf(pid, ppb, &bufvec, aux_iov, &aux_len); + + if (bytes_read == ESRCH) { + munmap(userbuf, BUFFER_SIZE); + return -1; + } + + bufvec.iov_base = userbuf; + bufvec.iov_len = bytes_read; + ret = vmsplice(ppb->p[1], &bufvec, 1, SPLICE_F_NONBLOCK); + + if (ret == -1 || ret != bytes_read) { + pr_err("vmsplice: Failed to splice user buffer to pipe %ld\n", ret); + munmap(userbuf, BUFFER_SIZE); + return -1; + } + + /* generating pagemap */ + for (i = 0; i < aux_len; i++) { + + struct iovec iov = aux_iov[i]; + u32 flags; + + ret = dump_holes(xfer, pp, &cur_hole, iov.iov_base); + if (ret) { + munmap(userbuf, BUFFER_SIZE); + return ret; + } + + BUG_ON(iov.iov_base < (void *)xfer->offset); + iov.iov_base -= xfer->offset; + pr_debug("\t p %p [%u]\n", iov.iov_base, + (unsigned int)(iov.iov_len / PAGE_SIZE)); + + flags = ppb_xfer_flags(xfer, ppb); + + if (xfer->write_pagemap(xfer, &iov, flags)) { + munmap(userbuf, BUFFER_SIZE); + return -1; + } + + if (xfer->write_pages(xfer, ppb->p[0], iov.iov_len)) { + munmap(userbuf, BUFFER_SIZE); + return -1; + } + } + + } + + munmap(userbuf, BUFFER_SIZE); + return dump_holes(xfer, pp, &cur_hole, NULL); +} + int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp) { struct page_pipe_buf *ppb; From befbbd9bba013533a05547c9b3702a256904190c Mon Sep 17 00:00:00 2001 From: Abhishek Dubey Date: Thu, 3 Oct 2019 19:39:23 +0530 Subject: [PATCH 2188/4375] Refactor time accounting macros refactoring time macros as per read mode pre-dump design. Signed-off-by: Abhishek Dubey Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 7 +++++-- criu/page-xfer.c | 8 ++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index ff05e38d7..f72373d22 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1514,11 +1514,14 @@ static int cr_pre_dump_finish(int status) mem_pp = dmpi(item)->mem_pp; - if (opts.pre_dump_mode == PRE_DUMP_READ) + if (opts.pre_dump_mode == PRE_DUMP_READ) { + timing_stop(TIME_MEMWRITE); ret = page_xfer_predump_pages(item->pid->real, &xfer, mem_pp); - else + } + else { ret = page_xfer_dump_pages(&xfer, mem_pp); + } xfer.close(&xfer); diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 8709df745..4d2d046ef 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -812,6 +812,8 @@ int page_xfer_predump_pages(int pid, struct page_xfer *xfer, list_for_each_entry(ppb, &pp->bufs, l) { + timing_start(TIME_MEMDUMP); + aux_len = 0; bufvec.iov_len = BUFFER_SIZE; bufvec.iov_base = userbuf; @@ -833,6 +835,9 @@ int page_xfer_predump_pages(int pid, struct page_xfer *xfer, return -1; } + timing_stop(TIME_MEMDUMP); + timing_start(TIME_MEMWRITE); + /* generating pagemap */ for (i = 0; i < aux_len; i++) { @@ -863,9 +868,12 @@ int page_xfer_predump_pages(int pid, struct page_xfer *xfer, } } + timing_stop(TIME_MEMWRITE); } munmap(userbuf, BUFFER_SIZE); + timing_start(TIME_MEMWRITE); + return dump_holes(xfer, pp, &cur_hole, NULL); } From d30557699616d27bed6e2e1fd6bbdf45a8c99d7f Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 4 Oct 2019 19:36:37 +0300 Subject: [PATCH 2189/4375] zdtm: handle --pre-dump-mode in the rpc mode Signed-off-by: Andrei Vagin --- test/zdtm.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 3c0cee667..571962241 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -912,6 +912,13 @@ class criu_rpc: if arg == '--prev-images-dir': criu.opts.parent_img = args.pop(0) continue + if arg == '--pre-dump-mode': + key = args.pop(0) + mode = crpc.rpc.READ + if key == "splice": + mode = crpc.rpc.SPLICE + criu.opts.pre_dump_mode = mode + continue if arg == '--track-mem': criu.opts.track_mem = True continue @@ -929,7 +936,7 @@ class criu_rpc: inhfd.key = key continue - raise test_fail_exc('RPC for %s required' % arg) + raise test_fail_exc('RPC for %s(%s) required' % (arg, args.pop(0))) @staticmethod def run(action, From 7c97cc7eb26c7232ca286e5ad4322c3be2bdcfca Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 4 Oct 2019 20:02:07 +0300 Subject: [PATCH 2190/4375] lib/c: fix a compile time error lib/c/criu.c:343:30: error: implicit conversion from enumeration type 'enum criu_pre_dump_mode' to different enumeration type 'CriuPreDumpMode' (aka 'enum _CriuPreDumpMode') [-Werror,-Wenum-conversion opts->rpc->pre_dump_mode = mode; ~ ^~~~ Signed-off-by: Andrei Vagin --- lib/c/criu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/c/criu.c b/lib/c/criu.c index fffb9fd9c..1d0a235f4 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -340,7 +340,7 @@ int criu_local_set_pre_dump_mode(criu_opts *opts, enum criu_pre_dump_mode mode) { opts->rpc->has_pre_dump_mode = true; if (mode == CRIU_PRE_DUMP_SPLICE || mode == CRIU_PRE_DUMP_READ) { - opts->rpc->pre_dump_mode = mode; + opts->rpc->pre_dump_mode = (CriuPreDumpMode)mode; return 0; } return -1; From 6b264f591f42e0ee3e1ceee103d5c557184829d5 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 5 Oct 2019 22:46:02 +0300 Subject: [PATCH 2191/4375] criu: use atomic_add instead of atomic_sub atomic_sub isn't defined for all platforms. Reported-by: Mr Jenkins Cc: Abhishek Dubey Signed-off-by: Andrei Vagin --- criu/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/stats.c b/criu/stats.c index cb528011a..891c37800 100644 --- a/criu/stats.c +++ b/criu/stats.c @@ -48,7 +48,7 @@ void cnt_sub(int c, unsigned long val) dstats->counts[c] -= val; } else if (rstats != NULL) { BUG_ON(c >= RESTORE_CNT_NR_STATS); - atomic_sub(val, &rstats->counts[c]); + atomic_add(-val, &rstats->counts[c]); } else BUG(); } From 3efe44382fef816ea274ed1833adc1abfa4b4f06 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 6 Oct 2019 01:01:50 +0300 Subject: [PATCH 2192/4375] image: avoid name conflicts in image files Conflict register for file "sk-opts.proto": READ is already defined in file "rpc.proto". Please fix the conflict by adding package name on the proto file, or use different name for the duplication. Note: enum values appear as siblings of the enum type instead of children of it. https://github.com/checkpoint-restore/criu/issues/815 Signed-off-by: Andrei Vagin --- criu/cr-service.c | 2 +- images/rpc.proto | 2 +- test/zdtm.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 392e9ac50..a70f99d71 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -478,7 +478,7 @@ static int setup_opts_from_req(int sk, CriuOpts *req) case CRIU_PRE_DUMP_MODE__SPLICE: opts.pre_dump_mode = PRE_DUMP_SPLICE; break; - case CRIU_PRE_DUMP_MODE__READ: + case CRIU_PRE_DUMP_MODE__VM_READ: opts.pre_dump_mode = PRE_DUMP_READ; break; default: diff --git a/images/rpc.proto b/images/rpc.proto index fc2f1bce2..df1b5aed2 100644 --- a/images/rpc.proto +++ b/images/rpc.proto @@ -49,7 +49,7 @@ enum criu_cg_mode { enum criu_pre_dump_mode { SPLICE = 1; - READ = 2; + VM_READ = 2; }; message criu_opts { diff --git a/test/zdtm.py b/test/zdtm.py index 571962241..6d3fddfad 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -914,7 +914,7 @@ class criu_rpc: continue if arg == '--pre-dump-mode': key = args.pop(0) - mode = crpc.rpc.READ + mode = crpc.rpc.VM_READ if key == "splice": mode = crpc.rpc.SPLICE criu.opts.pre_dump_mode = mode From 71c2a9dc73f679df93f2c749fed39088616a7b16 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 1 Oct 2019 20:56:26 +0000 Subject: [PATCH 2193/4375] Guard against empty file lock status The lock status string may be empty. This can happen when the owner of the lock is invisible from our PID namespace. This unfortunate behavior is fixed in kernels v4.19 and up (see commit 1cf8e5de40) Signed-off-by: Nicolas Viennot Signed-off-by: Andrei Vagin --- criu/proc_parse.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 97f82ee01..d67392a12 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1669,17 +1669,27 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, void *arg) if (fdinfo_field(str, "lock")) { struct file_lock *fl; struct fdinfo_common *fdinfo = arg; + char *flock_status = str+sizeof("lock:\t")-1; if (type != FD_TYPES__UND) continue; + /* + * The lock status can be empty when the owner of the + * lock is invisible from our PID namespace. + * This unfortunate behavior is fixed in kernels v4.19 + * and up (see commit 1cf8e5de40). + */ + if (flock_status[0] == '\0') + continue; + fl = alloc_file_lock(); if (!fl) { pr_perror("Alloc file lock failed!"); goto out; } - if (parse_file_lock_buf(str + 6, fl, 0)) { + if (parse_file_lock_buf(flock_status, fl, 0)) { xfree(fl); goto parse_err; } From 5a92f100b88e25981d7d51b3f4db374297fcff3c Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sat, 28 Sep 2019 06:59:45 +0100 Subject: [PATCH 2194/4375] page-pipe: Resize up to PIPE_MAX_SIZE When performing pre-dump we continuously increase the page-pipe size to fit the max amount memory pages in the pipe's buffer. However, we never actually set the pipe's buffer size to max. By doing so, we can reduce the number of pipe-s necessary for pre-dump and improve the performance as shown in the example below. For example, let's consider the following process: #include #include #include void main(void) { int i = 0; void *cache = calloc(1, 1024 * 1024 * 1024); while(1) { printf("%d\n", i++); sleep(1); } } stats-dump before this change: frozen_time: 123538 memdump_time: 95344 memwrite_time: 11980078 pages_scanned: 262721 pages_written: 262169 page_pipes: 513 page_pipe_bufs: 519 stats-dump after this change: frozen_time: 83287 memdump_time: 54587 memwrite_time: 12547466 pages_scanned: 262721 pages_written: 262169 page_pipes: 257 page_pipe_bufs: 263 Signed-off-by: Radostin Stoyanov --- criu/page-pipe.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/criu/page-pipe.c b/criu/page-pipe.c index a8216962d..439c180e4 100644 --- a/criu/page-pipe.c +++ b/criu/page-pipe.c @@ -54,8 +54,12 @@ static inline int ppb_resize_pipe(struct page_pipe_buf *ppb) if (ppb->pages_in + ppb->pipe_off < ppb->pipe_size) return 0; - if (new_size > PIPE_MAX_SIZE) - return 1; + if (new_size > PIPE_MAX_SIZE) { + if (ppb->pipe_size < PIPE_MAX_SIZE) + ppb->pipe_size = PIPE_MAX_SIZE; + else + return 1; + } ret = __ppb_resize_pipe(ppb, new_size); if (ret < 0) From f65b17e976633ad4d4a10dae96e3279157d8e77f Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 30 Apr 2019 11:35:26 +0300 Subject: [PATCH 2195/4375] cgroup: fix cg_yard leak on error path in prepare_cgroup_sfd Signed-off-by: Pavel Tikhomirov --- criu/cgroup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index 1be8be234..a66fc960e 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -1730,11 +1730,11 @@ static int prepare_cgroup_sfd(CgroupEntry *ce) pr_debug("\tMaking controller dir %s (%s)\n", paux, opt); if (mkdir(paux, 0700)) { pr_perror("\tCan't make controller dir %s", paux); - return -1; + goto err; } if (mount("none", paux, "cgroup", 0, opt) < 0) { pr_perror("\tCan't mount controller dir %s", paux); - return -1; + goto err; } } From e56401ed3c187150c8b95cb5fd69e0d637c5515c Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sat, 14 Sep 2019 12:47:14 +0100 Subject: [PATCH 2196/4375] image-desc: Remove CR_FD_FILE_LOCKS_PID The support for per-pid images with locks has been dropped with commit d040219 ("locks: Drop support for per-pid images with locks") and CR_FD_FILE_LOCKS_PID is not used. Signed-off-by: Radostin Stoyanov --- criu/image-desc.c | 5 ----- criu/include/image-desc.h | 1 - 2 files changed, 6 deletions(-) diff --git a/criu/image-desc.c b/criu/image-desc.c index 053e7af21..81cd07484 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -112,9 +112,4 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { .magic = IRMAP_CACHE_MAGIC, .oflags = O_SERVICE | O_FORCE_LOCAL, }, - - [CR_FD_FILE_LOCKS_PID] = { - .fmt = "filelocks-%u.img", - .magic = FILE_LOCKS_MAGIC, - }, }; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 3135f56b4..fea80a719 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -79,7 +79,6 @@ enum { CR_FD_RLIMIT, CR_FD_ITIMERS, CR_FD_POSIX_TIMERS, - CR_FD_FILE_LOCKS_PID, CR_FD_IRMAP_CACHE, CR_FD_CPUINFO, From 477c3a4b0b7a246808afb2f12d0553db14dd74a6 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 8 Oct 2019 21:37:22 +0100 Subject: [PATCH 2197/4375] service: Use space on stack for msg buffer RPC messages are have fairly small size and using space on the stack might be a better option. This change follows the pattern used with do_pb_read_one() and pb_write_one(). Signed-off-by: Radostin Stoyanov --- criu/cr-service.c | 56 +++++++++++++++++++++++------------------ criu/include/protobuf.h | 7 ++++++ criu/protobuf.c | 7 ------ 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index a70f99d71..549b3368b 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -27,6 +27,7 @@ #include "cr-service.h" #include "cr-service-const.h" #include "page-xfer.h" +#include "protobuf.h" #include "net.h" #include "mount.h" #include "filesystems.h" @@ -49,18 +50,21 @@ unsigned int service_sk_ino = -1; static int recv_criu_msg(int socket_fd, CriuReq **req) { - unsigned char *buf; - int len; + u8 local[PB_PKOBJ_LOCAL_SIZE]; + void *buf = (void *)&local; + int len, exit_code = -1; len = recv(socket_fd, NULL, 0, MSG_TRUNC | MSG_PEEK); if (len == -1) { pr_perror("Can't read request"); - return -1; + goto err; } - buf = xmalloc(len); - if (!buf) - return -ENOMEM; + if (len > sizeof(local)) { + buf = xmalloc(len); + if (!buf) + return -ENOMEM; + } len = recv(socket_fd, buf, len, MSG_TRUNC); if (len == -1) { @@ -80,43 +84,47 @@ static int recv_criu_msg(int socket_fd, CriuReq **req) goto err; } - xfree(buf); - return 0; + exit_code = 0; err: - xfree(buf); - return -1; + if (buf != (void *)&local) + xfree(buf); + return exit_code; } static int send_criu_msg_with_fd(int socket_fd, CriuResp *msg, int fd) { - unsigned char *buf; - int len, ret; + u8 local[PB_PKOBJ_LOCAL_SIZE]; + void *buf = (void *)&local; + int len, exit_code = -1; len = criu_resp__get_packed_size(msg); - buf = xmalloc(len); - if (!buf) - return -ENOMEM; + if (len > sizeof(local)) { + buf = xmalloc(len); + if (!buf) + return -ENOMEM; + } if (criu_resp__pack(msg, buf) != len) { pr_perror("Failed packing response"); goto err; } - if (fd >= 0) { - ret = send_fds(socket_fd, NULL, 0, &fd, 1, buf, len); - } else - ret = write(socket_fd, buf, len); - if (ret < 0) { + if (fd >= 0) + exit_code = send_fds(socket_fd, NULL, 0, &fd, 1, buf, len); + else + exit_code = write(socket_fd, buf, len); + + if (exit_code < 0) { pr_perror("Can't send response"); goto err; } - xfree(buf); - return 0; + exit_code = 0; err: - xfree(buf); - return -1; + if (buf != (void *)&local) + xfree(buf); + return exit_code; } static int send_criu_msg(int socket_fd, CriuResp *msg) diff --git a/criu/include/protobuf.h b/criu/include/protobuf.h index fb7489e9d..0b6d8c150 100644 --- a/criu/include/protobuf.h +++ b/criu/include/protobuf.h @@ -52,4 +52,11 @@ static inline int collect_images(struct collect_image_info **array, unsigned siz return 0; } +/* + * To speed up reading of packed objects + * by providing space on stack, this should + * be more than enough for most objects. + */ +#define PB_PKOBJ_LOCAL_SIZE 1024 + #endif /* __CR_PROTOBUF_H__ */ diff --git a/criu/protobuf.c b/criu/protobuf.c index 8eb73e019..e68d42b5c 100644 --- a/criu/protobuf.c +++ b/criu/protobuf.c @@ -20,13 +20,6 @@ #include "protobuf.h" #include "util.h" -/* - * To speed up reading of packed objects - * by providing space on stack, this should - * be more than enough for most objects. - */ -#define PB_PKOBJ_LOCAL_SIZE 1024 - static char *image_name(struct cr_img *img) { int fd = img->_x.fd; From f8125b8bef7bf5a7bbaea5e6e1d29578c45bf53d Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Fri, 13 Sep 2019 18:47:33 +0000 Subject: [PATCH 2198/4375] Couple of fixes to build and run libcriu tests libcriu tests are currently broken. This patch fixes couple of issues to allow the building and running libcriu tests. 1. lib/c/criu.h got updated to include version.h which is present at "criu/include", but the command to compile libcriu tests is not specifying "criu/include" in the path to be searched for header files. This resulted in compilation error. This can be fixed by adding "-I ../../../../../criu/criu/include" however it causes more problems as "criu/include/fcntl.h" would now hide system defined fcntl.h Solution is to use "-iquote ../../../../../criu/criu/include" which applies only to the quote form of include directive. 2. Secondly, libcriu.so major version got updated to 2 but libcriu/run.sh still assumes verion 1. Instead of just updating the version in libcriu/run.sh to 2, this patch updates the libcriu/Makefile to use "CRIU_SO_VERSION_MAJOR" so that future changes to major version of libcriu won't cause same problem again. Signed-off-by: Ashutosh Mehra --- test/others/libcriu/Makefile | 14 ++++++++++++-- test/others/libcriu/run.sh | 5 ++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/test/others/libcriu/Makefile b/test/others/libcriu/Makefile index 5289ed15a..226396e6a 100644 --- a/test/others/libcriu/Makefile +++ b/test/others/libcriu/Makefile @@ -1,3 +1,5 @@ +include ../../../../criu/Makefile.versions + TESTS += test_sub TESTS += test_self TESTS += test_notify @@ -19,8 +21,16 @@ endef $(foreach t, $(TESTS), $(eval $(call genb, $(t)))) %.o: %.c - gcc -c $^ -I../../../../criu/lib/c/ -I../../../../criu/images/ -o $@ -Werror + gcc -c $^ -iquote ../../../../criu/criu/include -I../../../../criu/lib/c/ -I../../../../criu/images/ -o $@ -Werror -clean: +clean: libcriu_clean rm -rf $(TESTS) $(TESTS:%=%.o) lib.o .PHONY: clean + +libcriu_clean: + rm -f libcriu.so.${CRIU_SO_VERSION_MAJOR} +.PHONY: libcriu_clean + +libcriu: + ln -s ../../../../criu/lib/c/libcriu.so libcriu.so.${CRIU_SO_VERSION_MAJOR} +.PHONY: libcriu diff --git a/test/others/libcriu/run.sh b/test/others/libcriu/run.sh index a99b91e52..5f692db31 100755 --- a/test/others/libcriu/run.sh +++ b/test/others/libcriu/run.sh @@ -5,14 +5,13 @@ source ../env.sh || exit 1 echo "== Clean" make clean +make libcriu rm -rf wdir -rm -f ./libcriu.so.1 echo "== Prepare" mkdir -p wdir/i/ echo "== Run tests" -ln -s ../../../../criu/lib/c/libcriu.so libcriu.so.1 export LD_LIBRARY_PATH=. export PATH="`dirname ${BASH_SOURCE[0]}`/../../:$PATH" @@ -40,6 +39,6 @@ run_test test_iters run_test test_errno echo "== Tests done" -unlink libcriu.so.1 +make libcriu_clean [ $RESULT -eq 0 ] && echo "Success" || echo "FAIL" exit $RESULT From 321f82662129f516573cedba10b4fbbfc12f9f5a Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Mon, 16 Sep 2019 06:49:07 +0000 Subject: [PATCH 2199/4375] Enable libcriu testing in travis jobs Updated scripts/travis/travis-tests to run libcriu test. Signed-off-by: Ashutosh Mehra --- scripts/travis/travis-tests | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 980d74734..b2ebe969b 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -161,6 +161,9 @@ ip net add test ./test/zdtm.py run -t zdtm/static/env00 -k always ./test/crit-recode.py +# libcriu testing +make -C test/others/libcriu run + make -C test/others/shell-job if ! [ -x "$(command -v flake8)" ]; then From 00ce121fd55e5947d477be4601169e8676a2bbbf Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Mon, 23 Sep 2019 08:36:12 +0000 Subject: [PATCH 2200/4375] Add `criu` to PATH env variable in libcriu tests PATH is pointing to incorrect location for `criu` executable causing libcriu tests to fail when running in travis. Also added statements to display log file contents on failure to help in debugging. Signed-off-by: Ashutosh Mehra --- test/others/libcriu/run.sh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test/others/libcriu/run.sh b/test/others/libcriu/run.sh index 5f692db31..bd92f8544 100755 --- a/test/others/libcriu/run.sh +++ b/test/others/libcriu/run.sh @@ -13,7 +13,7 @@ mkdir -p wdir/i/ echo "== Run tests" export LD_LIBRARY_PATH=. -export PATH="`dirname ${BASH_SOURCE[0]}`/../../:$PATH" +export PATH="`dirname ${BASH_SOURCE[0]}`/../../../criu:$PATH" RESULT=0 @@ -21,6 +21,19 @@ function run_test { echo "== Build $1" if ! make $1; then echo "FAIL build $1" + echo "** Output of $1/test.log" + cat wdir/i/$1/test.log + echo "---------------" + if [ -f wdir/i/$1/dump.log ]; then + echo "** Contents of dump.log" + cat wdir/i/$1/dump.log + echo "---------------" + fi + if [ -f wdir/i/$1/restore.log ]; then + echo "** Contents of restore.log" + cat wdir/i/$1/restore.log + echo "---------------" + fi RESULT=1; else echo "== Test $1" From 19a24df53c2dba3b2e2457c99965edf43819818d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 1 Oct 2019 00:29:14 +0100 Subject: [PATCH 2201/4375] early-log: Print warnings only if the buffer is full I don't see many issues with early-log, so we probably don't need the warning when it was used. Note that after commit 74731d9 ("zdtm: make grep_errors also grep warnings") also warnings are grepped by zdtm.py (and I believe that was an improvement) which prints some bothering lines: > =[log]=> dump/zdtm/static/inotify00/38/1/dump.log > ------------------------ grep Error ------------------------ > (00.000000) Will allow link remaps on FS > (00.000034) Warn (criu/log.c:203): The early log isn't empty > ------------------------ ERROR OVER ------------------------ Instead of decreasing loglevel of the message, improve it by reporting a real issue. Cc: Adrian Reber Cc: Pavel Tikhomirov Cc: Radostin Stoyanov Signed-off-by: Dmitry Safonov --- criu/log.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/log.c b/criu/log.c index 8bdf83534..0ee113b91 100644 --- a/criu/log.c +++ b/criu/log.c @@ -199,8 +199,8 @@ void flush_early_log_buffer(int fd) } pos += hdr->len; } - if (early_log_buf_off) - pr_warn("The early log isn't empty\n"); + if (early_log_buf_off == EARLY_LOG_BUF_LEN) + pr_warn("The early log buffer is full, some messages may have been lost\n"); early_log_buf_off = 0; } From 1a28dee52b63eca5adc48c1d6f1dda8d532a0e8e Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 24 Oct 2019 19:39:39 +0000 Subject: [PATCH 2202/4375] Action scripts should be invoked with normal signal behavior Signal masks propagate through execve, so we need to clear them before invoking the action scripts as it may want to handle SIGCHLD, or SIGSEGV. Signed-off-by: Nicolas Viennot --- criu/util.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/criu/util.c b/criu/util.c index 028f604bb..e47e109ae 100644 --- a/criu/util.c +++ b/criu/util.c @@ -536,7 +536,7 @@ int cr_system_userns(int in, int out, int err, char *cmd, sigemptyset(&blockmask); sigaddset(&blockmask, SIGCHLD); if (sigprocmask(SIG_BLOCK, &blockmask, &oldmask) == -1) { - pr_perror("Can not set mask of blocked signals"); + pr_perror("Cannot set mask of blocked signals"); return -1; } @@ -545,6 +545,12 @@ int cr_system_userns(int in, int out, int err, char *cmd, pr_perror("fork() failed"); goto out; } else if (pid == 0) { + sigemptyset(&blockmask); + if (sigprocmask(SIG_SETMASK, &blockmask, NULL) == -1) { + pr_perror("Cannot clear blocked signals"); + goto out_chld; + } + if (userns_pid > 0) { if (switch_ns(userns_pid, &user_ns_desc, NULL)) goto out_chld; From 3861b334b252ff65acf2c827b5d85cab21de086a Mon Sep 17 00:00:00 2001 From: Sergey Bronnikov Date: Sun, 3 Nov 2019 13:08:09 +0300 Subject: [PATCH 2203/4375] Fix broken web-links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 16e8452b5..558e87160 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,8 @@ Linux kernel supporting checkpoint and restore for all the features it provides. looking for contributors of all kinds -- feedback, bug reports, testing, coding, writing, etc. Here are some useful hints to get involved. -* We have both -- [very simple](https://checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) and [more sophisticated](https://checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3A%22new+feature%22) coding tasks; -* CRIU does need [extensive testing](https://checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Atesting); +* We have both -- [very simple](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) and [more sophisticated](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3A%22new+feature%22) coding tasks; +* CRIU does need [extensive testing](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Atesting); * Documentation is always hard, we have [some information](https://criu.org/Category:Empty_articles) that is to be extracted from people's heads into wiki pages as well as [some texts](https://criu.org/Category:Editor_help_needed) that all need to be converted into useful articles; * Feedback is expected on the github issues page and on the [mailing list](https://lists.openvz.org/mailman/listinfo/criu); * For historical reasons we do not accept PRs, instead [patches are welcome](http://criu.org/How_to_submit_patches); From a7c625938eb1d472341770699469ca6ddb4d91b1 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 29 Oct 2019 15:17:40 +0100 Subject: [PATCH 2204/4375] travis: start to use aarch64 hardware With the newly introduced aarch64 at Travis it is possible for the CRIU test-cases to switch to aarch64. Travis uses unprivileged LXD containers on aarch64 which blocks many of the kernel interfaces CRIU needs. So for now this only tests building CRIU natively on aarch64 instead of using the Docker+QEMU combination. All tests based on Docker are not working on aarch64 is there currently seems to be a problem with Docker on aarch64. Maybe because of the nesting of Docker in LXD. Signed-off-by: Adrian Reber --- .travis.yml | 11 ++++-- scripts/build/Dockerfile.alpine | 2 +- scripts/build/Dockerfile.centos | 1 + scripts/build/Makefile | 4 +-- scripts/travis/travis-tests | 63 +++++++++++++++++++++------------ 5 files changed, 54 insertions(+), 27 deletions(-) diff --git a/.travis.yml b/.travis.yml index 82ba9fbc8..4cde9c4fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,11 +14,9 @@ env: - TR_ARCH=x86_64 - TR_ARCH=x86_64 CLANG=1 - TR_ARCH=armv7hf - - TR_ARCH=aarch64 - TR_ARCH=ppc64le - TR_ARCH=s390x - TR_ARCH=armv7hf CLANG=1 - - TR_ARCH=aarch64 CLANG=1 - TR_ARCH=ppc64le CLANG=1 - TR_ARCH=alpine CLANG=1 - TR_ARCH=docker-test @@ -27,6 +25,15 @@ env: - TR_ARCH=centos - TR_ARCH=podman-test matrix: + include: + - os: linux + arch: arm64 + env: TR_ARCH=local + dist: bionic + - os: linux + arch: arm64 + env: TR_ARCH=local CLANG=1 + dist: bionic allow_failures: - env: TR_ARCH=docker-test - env: TR_ARCH=fedora-rawhide diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index c71a3901f..70fdf480a 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -42,5 +42,5 @@ RUN apk add \ # The rpc test cases are running as user #1000, let's add the user RUN adduser -u 1000 -D test -RUN pip install protobuf ipaddress junit_xml +RUN pip install protobuf ipaddress junit_xml flake8 RUN make -C test/zdtm diff --git a/scripts/build/Dockerfile.centos b/scripts/build/Dockerfile.centos index 2ce40b179..213be694f 100644 --- a/scripts/build/Dockerfile.centos +++ b/scripts/build/Dockerfile.centos @@ -23,6 +23,7 @@ RUN yum install -y \ protobuf-devel \ protobuf-python \ python \ + python-flake8 \ python-ipaddress \ python2-future \ python2-junit_xml \ diff --git a/scripts/build/Makefile b/scripts/build/Makefile index bb2e9ca9d..3d4d91cd5 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -1,5 +1,5 @@ -QEMU_ARCHES := armv7hf aarch64 ppc64le s390x fedora-rawhide-aarch64 # require qemu -ARCHES := $(QEMU_ARCHES) x86_64 fedora-asan fedora-rawhide centos +QEMU_ARCHES := armv7hf ppc64le s390x fedora-rawhide-aarch64 # require qemu +ARCHES := $(QEMU_ARCHES) aarch64 x86_64 fedora-asan fedora-rawhide centos TARGETS := $(ARCHES) alpine TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) CONTAINER_RUNTIME := docker diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index b2ebe969b..1f6b19130 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -1,17 +1,31 @@ #!/bin/sh set -x -e -TRAVIS_PKGS="protobuf-c-compiler libprotobuf-c-dev libaio-dev +TRAVIS_PKGS="protobuf-c-compiler libprotobuf-c-dev libaio-dev python-future libgnutls28-dev libgnutls30 libprotobuf-dev protobuf-compiler - libcap-dev libnl-3-dev gcc-multilib gdb bash python-protobuf - libnet-dev util-linux asciidoctor libnl-route-3-dev" + libcap-dev libnl-3-dev gdb bash python-protobuf python-yaml + libnet-dev util-linux asciidoctor libnl-route-3-dev + python-junit.xml python-ipaddress time ccache flake8 + libbsd-dev" + +X86_64_PKGS="gcc-multilib" + +UNAME_M=`uname -m` + +if [ "$UNAME_M" != "x86_64" ]; then + # For Travis only x86_64 seems to be baremetal. Other + # architectures are running in unprivileged LXD containers. + # That seems to block most of CRIU's interfaces. + SKIP_TRAVIS_TEST=1 +fi travis_prep () { [ -n "$SKIP_TRAVIS_PREP" ] && return cd ../../ - service apport stop + # This can fail on aarch64 travis + service apport stop || : CC=gcc # clang support @@ -43,24 +57,41 @@ travis_prep () { sed -i '/security/ d' /etc/apt/sources.list fi + + # Do not install x86_64 specific packages on other architectures + if [ "$UNAME_M" = "x86_64" ]; then + TRAVIS_PKGS="$TRAVIS_PKGS $X86_64_PKGS" + fi + apt-get update -qq apt-get install -qq --no-install-recommends $TRAVIS_PKGS - # travis is based on 14.04 and that does not have python - # packages for future and ipaddress (16.04 has those packages) - pip install junit-xml future ipaddress chmod a+x $HOME } travis_prep -ulimit -c unlimited -echo "|`pwd`/test/abrt.sh %P %p %s %e" > /proc/sys/kernel/core_pattern - export GCOV +$CC --version time make CC="$CC" -j4 +./criu/criu -v4 cpuinfo dump || : +./criu/criu -v4 cpuinfo check || : + +make lint + +# Check that help output fits into 80 columns +WIDTH=$(./criu/criu --help | wc --max-line-length) +if [ "$WIDTH" -gt 80 ]; then + echo "criu --help output does not obey 80 characters line width!" + exit 1 +fi + [ -n "$SKIP_TRAVIS_TEST" ] && return +ulimit -c unlimited + +echo "|`pwd`/test/abrt.sh %P %p %s %e" > /proc/sys/kernel/core_pattern + if [ "${COMPAT_TEST}x" = "yx" ] ; then # Dirty hack to keep both ia32 & x86_64 shared libs on a machine: # headers are probably not compatible, so apt-get doesn't allow @@ -165,15 +196,3 @@ ip net add test make -C test/others/libcriu run make -C test/others/shell-job - -if ! [ -x "$(command -v flake8)" ]; then - pip install flake8 -fi -make lint - -# Check that help output fits into 80 columns -WIDTH=$(./criu/criu --help | wc --max-line-length) -if [ "$WIDTH" -gt 80 ]; then - echo "criu --help output does not obey 80 characters line width!" - exit 1 -fi From c4006c0034ef2162693d9dd619d025c240affc78 Mon Sep 17 00:00:00 2001 From: Vitaly Ostrosablin Date: Fri, 1 Nov 2019 09:00:23 +0000 Subject: [PATCH 2205/4375] test/static:conntracks: Support nftables Update test to support both iptables and nft to create conntrack rules. Signed-off-by: Vitaly Ostrosablin Signed-off-by: Andrei Vagin --- test/zdtm/static/conntracks | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/test/zdtm/static/conntracks b/test/zdtm/static/conntracks index a30e0e268..26220f97c 100755 --- a/test/zdtm/static/conntracks +++ b/test/zdtm/static/conntracks @@ -23,7 +23,7 @@ do_or_fail() fail "$failmsg: $output" } -do_start() +do_start_ipt() { [ -f "$statefile" ] && die "state file $statefile aleady exists" @@ -35,7 +35,7 @@ do_start() iptables -L \> "$statefile" } -do_stop() +do_stop_ipt() { do_or_fail "can't compare the iptables" \ iptables -L \| diff -u "$statefile" - @@ -45,6 +45,38 @@ do_stop() echo "PASS" > $outfile } +do_start_nft() +{ + [ -f "$statefile" ] && die "state file $statefile aleady exists" + + do_or_fail "can't install a state match" \ + nft add rule filter INPUT \ + ct state related,established accept + + do_or_fail "can't list the loaded nftables" \ + nft list ruleset \> "$statefile" +} + +do_stop_nft() +{ + do_or_fail "can't compare the nftables" \ + nft list ruleset \| diff -u "$statefile" - + + rm -f "$statefile" + + echo "PASS" > $outfile +} + +do_start() +{ + [ -x "$(command -v nft)" ] && do_start_nft || do_start_ipt +} + +do_stop() +{ + [ -x "$(command -v nft)" ] && do_stop_nft || do_stop_ipt +} + tmpargs="$(../lib/parseargs.sh --name=$0 \ --flags-req=statefile,outfile \ --flags-opt="start,stop" -- "$@")" || From 389bcfef3e8f4be35464da9f94681e6573d6d1d9 Mon Sep 17 00:00:00 2001 From: Nidhi Gupta Date: Fri, 18 Oct 2019 20:09:15 +0530 Subject: [PATCH 2206/4375] test/java: Add FileRead Tests Signed-off-by: Nidhi Gupta --- test/javaTests/README.md | 33 ++ test/javaTests/pom.xml | 47 ++ .../criu/java/tests/CheckpointRestore.java | 450 ++++++++++++++++++ .../src/org/criu/java/tests/FileRead.java | 175 +++++++ .../src/org/criu/java/tests/Helper.java | 99 ++++ .../src/org/criu/java/tests/ImgFilter.java | 11 + test/javaTests/test.xml | 13 + 7 files changed, 828 insertions(+) create mode 100644 test/javaTests/README.md create mode 100644 test/javaTests/pom.xml create mode 100644 test/javaTests/src/org/criu/java/tests/CheckpointRestore.java create mode 100644 test/javaTests/src/org/criu/java/tests/FileRead.java create mode 100644 test/javaTests/src/org/criu/java/tests/Helper.java create mode 100644 test/javaTests/src/org/criu/java/tests/ImgFilter.java create mode 100644 test/javaTests/test.xml diff --git a/test/javaTests/README.md b/test/javaTests/README.md new file mode 100644 index 000000000..cb779285e --- /dev/null +++ b/test/javaTests/README.md @@ -0,0 +1,33 @@ +# JavaTests + +Java Functional tests checks the Java File based APIs and Memory mapping APIs by placing the process in various states before checkpointing and validates if these resources are still accessible after restore. It also validates if the file contents are in expected states. + +Tests are to be run by a user having following capabilities: +CAP_DAC_OVERRIDE +CAP_CHOWN +CAP_SETPCAP +CAP_SETGID +CAP_AUDIT_CONTROL +CAP_DAC_READ_SEARCH +CAP_NET_ADMIN +CAP_SYS_ADMIN +CAP_SYS_CHROOT +CAP_SYS_PTRACE +CAP_FOWNER +CAP_KILL +CAP_FSETID +CAP_SYS_RESOURCE +CAP_SETUID + +## File-based Java APIs + +Here we test the File-Based Java APIs by checkpointing the application in the following scenarios and verifying the contents of the file after restore: +- Reading and writing in the same file. (FileRead.java) + +### Prerequisites for running the tests: +- Maven + +### To run the tests: +- In the javaTests folder run the command ```sudo mvn test``` +- To keep the img files and logs from previous failures, between different runs of the test, use the ```-DneverCleanFailures=true ``` option in the maven command +as ```sudo mvn -DneverCleanFailures=true test``` diff --git a/test/javaTests/pom.xml b/test/javaTests/pom.xml new file mode 100644 index 000000000..faae44d1b --- /dev/null +++ b/test/javaTests/pom.xml @@ -0,0 +1,47 @@ + + 4.0.0 + criu + criu-javaTests + 1 + criu-javaTests + + + src + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.14.1 + + + + test.xml + + + + + + maven-compiler-plugin + 3.1 + + 1.7 + 1.7 + + + + + + + + org.testng + testng + 6.3.1 + + + + UTF-8 + + diff --git a/test/javaTests/src/org/criu/java/tests/CheckpointRestore.java b/test/javaTests/src/org/criu/java/tests/CheckpointRestore.java new file mode 100644 index 000000000..968488191 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/CheckpointRestore.java @@ -0,0 +1,450 @@ +package org.criu.java.tests; + +import org.testng.Assert; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import java.io.*; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class CheckpointRestore { + private MappedByteBuffer mappedByteBuffer = null; + private String testName = ""; + private String logFolder = Helper.LOG_FOLDER + "/"; + private String outputFolder = Helper.OUTPUT_FOLDER_NAME + "/"; + + /** + * Create CRlog and output directory if they don't exist. + * Delete directories containing .img files from failed Checkpoint-Restore if 'neverCleanFailures' property is not set to true. + * + * @throws IOException + */ + @BeforeSuite + void suiteSetup() throws IOException { + System.out.println("Tests are to be run as a privileged user having capabilities mentioned in ReadMe"); + boolean neverCleanFailures = Boolean.getBoolean("neverCleanFailures"); + Path logDir = Paths.get(logFolder); + Path outputDir = Paths.get(outputFolder); + if (!Files.exists(logDir)) { + System.out.println("Logs directory does not exist, creating it"); + Files.createDirectory(logDir); + } + if (!Files.exists(outputDir)) { + System.out.println("Output directory does not exist, creating it"); + Files.createDirectory(outputDir); + } + /* + * Delete the directories containing the img files from failed Checkpoint-Restore. + */ + if (!neverCleanFailures) { + File output = new File(outputFolder); + String[] name = output.list(); + for (int i = 0; null != name && i < name.length; i++) { + File testFolder = new File(outputFolder + name[i]); + if (testFolder.isDirectory()) { + String[] list = testFolder.list(); + File file; + if (null != list) { + for (int j = 0; j < list.length; j++) { + file = new File(outputFolder + name[i] + "/" + list[j]); + if (!file.isDirectory()) { + Files.delete(file.toPath()); + } + } + } + } + Files.delete(testFolder.toPath()); + } + } + } + + /** + * Create the output folder for the test in case it does not exist + * + * @param testName Name of the java test + * @throws IOException + */ + private void testSetup(String testName) throws IOException { + Path testFolderPath = Paths.get(outputFolder + testName + "/"); + if (!Files.exists(testFolderPath)) { + System.out.println("Test Folder does not exist creating it"); + Files.createDirectory(testFolderPath); + } + } + + /** + * Read the pid of process from the pid file of test + * + * @param name Name of the java test + * @return pid Process id of the java test process + * @throws IOException + */ + private String getPid(String name) throws IOException { + name = outputFolder + testName + "/" + name + Helper.PID_APPEND; + File pidfile = new File(name); + BufferedReader pidReader = new BufferedReader(new FileReader(pidfile)); + String pid = pidReader.readLine(); + pidReader.close(); + return pid; + } + + /** + * @param testName Name of the java test + * @param checkpointOpt Additional options for checkpoint + * @param restoreOpt Additional options for restore + * @throws Exception + */ + @Test + @Parameters({"testname", "checkpointOpt", "restoreOpt"}) + public void runtest(String testName, String checkpointOpt, String restoreOpt) throws Exception { + this.testName = testName; + String name = Helper.PACKAGE_NAME + "." + testName; + String pid; + int exitCode; + + System.out.println("======= Testing " + testName + " ========"); + + testSetup(testName); + + File f = new File(Helper.MEMORY_MAPPED_FILE_NAME); + if (f.exists()) { + f.delete(); + } + + /* + * Create a new file that will be mapped to memory and used to communicate between + * this process and the java test process. + */ + boolean newFile = f.createNewFile(); + Assert.assertTrue(newFile, "Unable to create a new file to be mapped"); + + /* + * MappedByteBuffer communicates between this process and java process called. + */ + FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + mappedByteBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + mappedByteBuffer.clear(); + channel.close(); + + /* + * Put MappedByteBuffer in Init state + */ + mappedByteBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_INIT); + + /* + * Run the test as a separate process + */ + System.out.println("Starting the java Test"); + ProcessBuilder builder = new ProcessBuilder("java", "-cp", "target/classes", name); + Process process = builder.start(); + + char currentState = mappedByteBuffer.getChar(Helper.MAPPED_INDEX); + /* + * Loop until the test process changes the state of MappedByteBuffer from init state + */ + while (Helper.STATE_INIT == currentState) { + currentState = mappedByteBuffer.getChar(Helper.MAPPED_INDEX); + } + + /* + * If Mapped Buffer is in Helper.STATE_FAIL state before checkpointing then an exception must + * have occurred in the test. + */ + while (Helper.STATE_FAIL == currentState) { + try { + /* + * We exit the test process with exit code 5 in case of an exception + */ + exitCode = process.exitValue(); + /* + * Reaching here implies that .exitValue() has not thrown an exception, so the process has + * exited, We now check the exitCode. + */ + if (5 == exitCode) { + Assert.fail(testName + ": Exception occurred while running the test: check the log file for details."); + } else { + Assert.fail(testName + ": ERROR: Unexpected value of exit code: " + exitCode + ", expected: 5"); + } + } catch (IllegalThreadStateException e) { + /* + * Do nothing, as an Exception is expected if the process has not exited + * and we try to get its exitValue. + */ + } + + currentState = mappedByteBuffer.getChar(Helper.MAPPED_INDEX); + } + + /* + * Mapped Buffer state should be Helper.STATE_CHECKPOINT for checkpointing or Helper.STATE_END if some error occurs in test + */ + if (Helper.STATE_END != currentState) { + Assert.assertEquals(currentState, Helper.STATE_CHECKPOINT, testName + ": ERROR: Error occurred while running the test: test is not in the excepted 'waiting to be checkpointed state': " + currentState); + } else { + Assert.fail(testName + ": ERROR: Error took place in the test check the log file for more details"); + } + /* + * Reaching here implies that MappedByteBuffer is in To Be Checkpointed state. + * Get the pid of the test process + */ + + pid = getPid(testName); + try { + /* + * Checkpoint the process + */ + checkpoint(pid, checkpointOpt); + + } catch (Exception e) { + /* + * If exception occurs put the MappedByteBuffer to Helper.STATE_TERMINATE-Terminate state. + * On reading the terminate state, the test process terminates, else it + * may go on looping. + */ + mappedByteBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_TERMINATE); + Assert.fail(testName + ": Exception occurred while during checkpointing" + e, e); + } + + /* + * The process has been checkpointed successfully, now restoring the process. + */ + try { + /* + * Restore the process + */ + restore(restoreOpt); + } catch (Exception e) { + mappedByteBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_TERMINATE); + Assert.fail(testName + ": Exception occurred while restoring the test" + e, e); + } + + /* + * Wait for test process to finish + */ + currentState = mappedByteBuffer.getChar(Helper.MAPPED_INDEX); + while (Helper.STATE_RESTORE == currentState) { + currentState = mappedByteBuffer.getChar(Helper.MAPPED_INDEX); + } + + /* + * If a test passes it puts the MappedByteBuffer to Helper.STATE_PASS-Pass state, + * On failing to Helper.STATE_FAIL-Fail state, and if our Buffer is in Helper.STATE_TERMINATE state + * its because the checkpoint-restore of test process failed. + */ + + Assert.assertNotEquals(currentState, Helper.STATE_TERMINATE, testName + ": ERROR: Checkpoint-Restore failed"); + Assert.assertNotEquals(currentState, Helper.STATE_FAIL, testName + ": ERROR: Test Failed, Check Log for details"); + Assert.assertEquals(currentState, Helper.STATE_PASS, testName + " ERROR: Unexpected State of Mapped Buffer"); + System.out.println("-----" + "PASS" + "-----"); + + } + + /** + * Remove .img files, dump.log, restore.log, stats-dump and stats-restore files from Log Directory + * + * @throws IOException + */ + @AfterTest + void cleanup() throws IOException { + int i; + String currentPath = System.getProperty("user.dir"); + currentPath = currentPath + "/" + logFolder; + File deleteFile; + File dir = new File(currentPath); + String[] imgFiles = dir.list(new ImgFilter()); + if (null != imgFiles) { + for (i = 0; i < imgFiles.length; i++) { + deleteFile = new File(currentPath + imgFiles[i]); + Files.delete(deleteFile.toPath()); + } + } + + boolean exists = Files.exists(Paths.get(currentPath + "dump.log")); + if (exists) { + Files.delete(Paths.get(currentPath + "dump.log")); + } + + exists = Files.exists(Paths.get(currentPath + "restore.log")); + if (exists) { + Files.delete(Paths.get(currentPath + "restore.log")); + } + + exists = Files.exists(Paths.get(currentPath + "stats-dump")); + if (exists) { + Files.delete(Paths.get(currentPath + "stats-dump")); + } + + exists = Files.exists(Paths.get(currentPath + "stats-restore")); + if (exists) { + Files.delete(Paths.get(currentPath + "stats-restore")); + } + } + + /** + * Copy .img files, dump.log, restore.log, stats-dump and stats-restore files from Log Directory if they exist + * to another folder. + * + * @throws IOException + */ + String copyFiles() throws IOException { + String currentPath = System.getProperty("user.dir"); + String folderSuffix = new SimpleDateFormat("yyMMddHHmmss").format(new Date()); + String fromPath = currentPath + "/" + logFolder; + File fromDir = new File(fromPath); + Path fromFile, toFile; + boolean exists; + String toPath = currentPath + "/" + outputFolder + testName + folderSuffix + "/"; + Path dirPath = Paths.get(toPath); + Files.createDirectory(dirPath); + + String[] imgFiles = fromDir.list(new ImgFilter()); + if (null != imgFiles) { + for (int i = 0; i < imgFiles.length; i++) { + fromFile = Paths.get(fromPath + imgFiles[i]); + toFile = Paths.get(toPath + imgFiles[i]); + Files.copy(fromFile, toFile); + } + } + + fromFile = Paths.get(fromPath + "dump.log"); + exists = Files.exists(fromFile); + if (exists) { + toFile = Paths.get(toPath + "dump.log"); + Files.copy(fromFile, toFile); + } + + fromFile = Paths.get(fromPath + "restore.log"); + exists = Files.exists(fromFile); + if (exists) { + toFile = Paths.get(toPath + "restore.log"); + Files.copy(fromFile, toFile); + } + + fromFile = Paths.get(fromPath + "stats-dump"); + exists = Files.exists(fromFile); + if (exists) { + toFile = Paths.get(toPath + "stats-dump"); + Files.copy(fromFile, toFile); + } + + fromFile = Paths.get(fromPath + "stats-restore"); + exists = Files.exists(fromFile); + if (exists) { + toFile = Paths.get(toPath + "stats-restore"); + Files.copy(fromFile, toFile); + } + + return folderSuffix; + } + + /** + * Checkpoint the process, if process has not been checkpointed correctly + * copy the .img, log and stats files, puts MappedBuffer to 'terminate' state and mark + * test as failed + * + * @param pid Pid of process to be checkpointed + * @param checkpointOpt Additional options for checkpoint + * @throws IOException + * @throws InterruptedException + */ + private void checkpoint(String pid, String checkpointOpt) throws IOException, InterruptedException { + ProcessBuilder builder; + System.out.println("Checkpointing process " + pid); + String command = "../../criu/criu dump --shell-job -t " + pid + " -vvv -D " + logFolder + " -o dump.log"; + if (0 == checkpointOpt.length()) { + String[] cmd = command.split(" "); + builder = new ProcessBuilder(cmd); + } else { + command = command + " " + checkpointOpt; + String[] cmd = command.split(" "); + builder = new ProcessBuilder(cmd); + } + Process process = builder.start(); + BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream())); + int exitCode = process.waitFor(); + + if (0 != exitCode) { + /* + * Print the error stream + */ + String line = stdError.readLine(); + while (null != line) { + System.out.println(line); + line = stdError.readLine(); + } + + mappedByteBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_TERMINATE); + /* + * If checkpoint fails copy the img files, dump.log, stats-dump, stats-restore + */ + String folderSuffix = copyFiles(); + + Assert.fail(testName + ": ERROR: Error during checkpoint: exitCode of checkpoint process was not zero.\nFor more details check dump.log in " + outputFolder + testName + folderSuffix); + return; + } + + System.out.println("Checkpoint success"); + process.destroy(); + + } + + /** + * Restore the process, if process has been restored correctly put Mapped Buffer to + * 'restored' state, else copy the .img, log and stats files and put MappedBuffer to 'terminate' + * state and mark test as failed + * + * @param restoreOpt Additional options for restore + * @throws IOException + * @throws InterruptedException + */ + private void restore(String restoreOpt) throws IOException, InterruptedException { + ProcessBuilder builder; + System.out.println("Restoring process"); + String command = "../../criu/criu restore -d -vvv --shell-job -D " + logFolder + " -o restore.log"; + if (0 == restoreOpt.length()) { + String[] cmd = command.split(" "); + builder = new ProcessBuilder(cmd); + } else { + command = command + " " + restoreOpt; + String[] cmd = command.split(" "); + builder = new ProcessBuilder(cmd); + } + + Process process = builder.start(); + BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream())); + int exitCode = process.waitFor(); + + if (0 != exitCode) { + /* + * Print the error stream + */ + String line = stdError.readLine(); + while (null != line) { + System.out.println(line); + line = stdError.readLine(); + } + mappedByteBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_TERMINATE); + /* + * If restore fails copy img files, dump.log, restore.log, stats-dump, stats-restore + */ + String folderSuffix = copyFiles(); + Assert.fail(testName + ": ERROR: Error during restore: exitCode of restore process was not zero.\nFor more details check restore.log in " + outputFolder + testName + folderSuffix); + + return; + } else { + System.out.println("Restore success"); + mappedByteBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_RESTORE); + } + process.destroy(); + } +} diff --git a/test/javaTests/src/org/criu/java/tests/FileRead.java b/test/javaTests/src/org/criu/java/tests/FileRead.java new file mode 100644 index 000000000..d94a14112 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/FileRead.java @@ -0,0 +1,175 @@ +package org.criu.java.tests; + +import java.io.*; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class FileRead { + private static String TESTNAME = "FileRead"; + + /** + * @param i int value denoting the line number. + * @return The line as a string. + */ + private static String getLine(int i) { + return "Line No: " + i + "\n"; + } + + /** + * Write in a file, line by line, and read it, checkpoint and restore + * and then continue to read and write the file. + * + * @param args Not used + */ + public static void main(String[] args) { + MappedByteBuffer b = null; + Logger logger = null; + int wi, ri = 0; + try { + File file = new File(Helper.OUTPUT_FOLDER_NAME + "/" + TESTNAME + "/FileRead_write.txt"); + File f = new File(Helper.MEMORY_MAPPED_FILE_NAME); + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + String pid = bean.getName(); + int val = Helper.init(TESTNAME, pid, logger); + if (0 != val) { + logger.log(Level.SEVERE, "Helper.init returned a non-zero code."); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Test init done; pid written to pid file; beginning with test"); + FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + b = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + /* + * Mapped Byte Buffer should be in init state at the beginning of test + */ + if ('I' != b.getChar(Helper.MAPPED_INDEX)) { + logger.log(Level.SEVERE, "Error: Error in memory mapping, test is not in init state"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + logger.log(Level.INFO, "Checking existence of file to be read and written to."); + if (file.exists()) { + file.delete(); + } + boolean newFile = file.createNewFile(); + if (!newFile) { + logger.log(Level.SEVERE, "Cannot create a new file to read and write to."); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + BufferedWriter brw = new BufferedWriter(new FileWriter(file)); + BufferedReader brr = new BufferedReader(new FileReader(file)); + + logger.log(Level.INFO, "Start writing the lines in file"); + + for (wi = 1; wi <= 5; wi++) { + brw.write(getLine(wi)); + } + + brw.flush(); + String s = "Line No: 0"; + int i; + + for (i = 0; i < 50; i++) { + brw.write(getLine(wi)); + brw.flush(); + wi++; + s = brr.readLine(); + ri = Integer.parseInt(s.replaceAll("[\\D]", "")); + } + + wi--; + logger.log(Level.INFO, "Going to checkpoint"); + + /* + * Checkpoint and wait for restore + */ + Helper.checkpointAndWait(b, logger); + logger.log(Level.INFO, "Test has been restored!"); + + brw.flush(); + + try { + s = brr.readLine(); + + } catch (Exception e) { + logger.log(Level.SEVERE, "Error: Buffered Reader is not reading file"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + if (null == s || s.isEmpty()) { + logger.log(Level.SEVERE, "Error: Error while reading lines after restore: Line read is null"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + int readLineNo = Integer.parseInt(s.replaceAll("[\\D]", "")); + if (ri + 1 != readLineNo) { + logger.log(Level.SEVERE, "Error: Not reading at correct line"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + String ch = brr.readLine(); + while (null != ch && !ch.isEmpty()) { + s = ch; + ch = brr.readLine(); + } + + readLineNo = Integer.parseInt(s.replaceAll("[\\D]", "")); + + if (readLineNo != wi) { + logger.log(Level.SEVERE, "Error: Data written has been lost"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + try { + brw.write(getLine(wi + 1)); + brw.flush(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Error: cannot write file after restore"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + s = brr.readLine(); + readLineNo = Integer.parseInt(s.replaceAll("[\\D]", "")); + + if (readLineNo != wi + 1) { + logger.log(Level.SEVERE, "Error: Data not written correctly"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + logger.log(Level.INFO, "File is being read and written to correctly after restore!"); + logger.log(Level.INFO, Helper.PASS_MESSAGE); + brw.close(); + brr.close(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + System.exit(0); + } catch (Exception e) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + e.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occurred:" + e); + logger.log(Level.FINE, writer.toString()); + } + + if (null != b) { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + System.exit(5); + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/Helper.java b/test/javaTests/src/org/criu/java/tests/Helper.java new file mode 100644 index 000000000..d608fba47 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/Helper.java @@ -0,0 +1,99 @@ +package org.criu.java.tests; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.MappedByteBuffer; +import java.util.logging.FileHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; + +class Helper { + static String MEMORY_MAPPED_FILE_NAME = "output/file"; + static String PASS_MESSAGE = "Test was a Success!!!"; + static String OUTPUT_FOLDER_NAME = "output"; + static String PACKAGE_NAME = "org.criu.java.tests"; + static String PID_APPEND = ".pid"; + static String SOURCE_FOLDER = "src/org/criu/java/tests"; + static String LOG_FOLDER = "CRlogs"; + static int MAPPED_REGION_SIZE = 100; + static int MAPPED_INDEX = 1; + static char STATE_RESTORE = 'R'; + static char STATE_CHECKPOINT = 'C'; + static char STATE_INIT = 'I'; + static char STATE_TERMINATE = 'T'; + static char STATE_END = 'E'; + static char STATE_FAIL = 'F'; + static char STATE_PASS = 'P'; + + /** + * Create a new log file and pidfile and write + * the pid to the pidFile. + * + * @param testName Name of the java test + * @param pid Pid of the java test process + * @param logger + * @return 0 or 1 denoting whether the function was successful or not. + * @throws IOException + */ + static int init(String testName, String pid, Logger logger) throws IOException { + File pidfile = new File(OUTPUT_FOLDER_NAME + "/" + testName + "/" + testName + PID_APPEND); + + FileHandler handler = new FileHandler(Helper.OUTPUT_FOLDER_NAME + "/" + testName + "/" + testName + ".log", false); + handler.setFormatter(new SimpleFormatter()); + handler.setLevel(Level.FINE); + logger.addHandler(handler); + logger.setLevel(Level.FINE); + + /* + * Create a pid file and write the process's pid into it. + */ + if (pidfile.exists()) { + pidfile.delete(); + } + boolean newFile = pidfile.createNewFile(); + if (!newFile) { + logger.log(Level.SEVERE, "Cannot create new pid file."); + return 1; + } + BufferedWriter pidWriter = new BufferedWriter(new FileWriter(pidfile)); + pidWriter.write(pid + "\n"); + pidWriter.close(); + return 0; + } + + /** + * Put the Mapped Buffer to 'Ready to be checkpointed' state and wait for restore. + * + * @param b The MappedByteBuffer from the calling process. + * @param logger The Logger from the calling process. + */ + static void checkpointAndWait(MappedByteBuffer b, Logger logger) { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_CHECKPOINT); + char c = b.getChar(Helper.MAPPED_INDEX); + /* + * Loop while MappedByteBuffer is in 'To be checkpointed' state + */ + while (Helper.STATE_CHECKPOINT == c) { + c = b.getChar(Helper.MAPPED_INDEX); + } + /* + * Test is in 'T' state if some error or exception occurs during checkpoint or restore. + */ + if (Helper.STATE_TERMINATE == c) { + logger.log(Level.SEVERE, "Error during checkpoint-restore, Test terminated"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + /* + * The expected state of MappedByteBuffer is Helper.STATE_RESTORE-restored state. + */ + if (Helper.STATE_RESTORE != c) { + logger.log(Level.INFO, "Error: Test state is not the expected Restored state"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/ImgFilter.java b/test/javaTests/src/org/criu/java/tests/ImgFilter.java new file mode 100644 index 000000000..97087c2cc --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/ImgFilter.java @@ -0,0 +1,11 @@ +package org.criu.java.tests; + +import java.io.File; +import java.io.FilenameFilter; + +class ImgFilter implements FilenameFilter { + @Override + public boolean accept(File dir, String fileName) { + return (fileName.endsWith(".img")); + } +} diff --git a/test/javaTests/test.xml b/test/javaTests/test.xml new file mode 100644 index 000000000..8ff67c5e0 --- /dev/null +++ b/test/javaTests/test.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + From 9325339e64e0485e981e880ae460729cd9b9b648 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 9 Nov 2019 18:31:58 +0000 Subject: [PATCH 2207/4375] travis: Disallow failures on ia32 It seems pretty stable and hasn't add many false-positives during last months. While can reveal some issues for compatible C/R code. Signed-off-by: Dmitry Safonov --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4cde9c4fb..7a0c29a55 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,8 +40,6 @@ matrix: - env: TR_ARCH=fedora-rawhide-aarch64 - env: TR_ARCH=s390x - env: TR_ARCH=local GCOV=1 - - env: TR_ARCH=local COMPAT_TEST=y - - env: TR_ARCH=local CLANG=1 COMPAT_TEST=y script: - sudo make CCACHE=1 -C scripts/travis $TR_ARCH after_success: From d804f70a680b0ba7410e3845aa8179d8ab5c4219 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 7 Feb 2019 15:17:48 +0300 Subject: [PATCH 2208/4375] mount: remove useless check in populate_mnt_ns The path: restore_root_task prepare_namespace_before_tasks mntns_maybe_create_roots is always called before the path below: retore_root_task fork_with_pid restore_task_with_children prepare_namespace prepare_mnt_ns populate_mnt_ns So (!!mnt_roots) == (root_ns_mask & CLONE_NEWNS) in populate_mnt_ns, but in prepare_mnt_ns we've already checked that it is true, so there is no need in these check - remove it. Signed-off-by: Pavel Tikhomirov --- criu/mount.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 486d01719..802295778 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -3139,15 +3139,12 @@ static int populate_mnt_ns(void) struct ns_id *nsid; int ret; - if (mnt_roots) { - /* mnt_roots is a tmpfs mount and it's private */ - root_yard_mp = mnt_entry_alloc(); - if (!root_yard_mp) - return -1; + root_yard_mp = mnt_entry_alloc(); + if (!root_yard_mp) + return -1; - root_yard_mp->mountpoint = mnt_roots; - root_yard_mp->mounted = true; - } + root_yard_mp->mountpoint = mnt_roots; + root_yard_mp->mounted = true; pms = mnt_build_tree(mntinfo, root_yard_mp); if (!pms) From 71dff54aa474efa105043cd86cc38103c3c21859 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 7 Feb 2019 15:17:49 +0300 Subject: [PATCH 2209/4375] ns: make rst_new_ns_id static It's never used outside of namespaces.c Signed-off-by: Pavel Tikhomirov --- criu/include/namespaces.h | 1 - criu/namespaces.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index 287abb3c8..a9a970a9b 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -166,7 +166,6 @@ extern int restore_ns(int rst, struct ns_desc *nd); extern int dump_task_ns_ids(struct pstree_item *); extern int predump_task_ns_ids(struct pstree_item *); -extern struct ns_id *rst_new_ns_id(unsigned int id, pid_t pid, struct ns_desc *nd, enum ns_type t); extern int rst_add_ns_id(unsigned int id, struct pstree_item *, struct ns_desc *nd); extern struct ns_id *lookup_ns_by_id(unsigned int id, struct ns_desc *nd); diff --git a/criu/namespaces.c b/criu/namespaces.c index a228737ee..57f6bdfef 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -290,7 +290,7 @@ static void nsid_add(struct ns_id *ns, struct ns_desc *nd, unsigned int id, pid_ pr_info("Add %s ns %d pid %d\n", nd->str, ns->id, ns->ns_pid); } -struct ns_id *rst_new_ns_id(unsigned int id, pid_t pid, +static struct ns_id *rst_new_ns_id(unsigned int id, pid_t pid, struct ns_desc *nd, enum ns_type type) { struct ns_id *nsid; From 7be7260261a1f94b111b9390a2b39179e87d7d8b Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 7 Feb 2019 15:17:50 +0300 Subject: [PATCH 2210/4375] ns/restore/image: do not read namespace images for non-namespaced case Images for mount and net namespaces are empty if ns does not belong to us, thus we don't need to collect on restore. By adding these checks we will eliminate suspicious messages in logs about lack of images: ./test/zdtm.py run -k always -f h -t zdtm/static/env00 env00/54/2/restore.log:(00.000332) No mountpoints-5.img image env00/54/2/restore.log:(00.000342) No netns-2.img image Signed-off-by: Pavel Tikhomirov --- criu/mount.c | 5 +++++ criu/net.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/criu/mount.c b/criu/mount.c index 802295778..fdaaa7b31 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2989,6 +2989,11 @@ int read_mnt_ns_img(void) struct mount_info *pms = NULL; struct ns_id *nsid; + if (!(root_ns_mask & CLONE_NEWNS)) { + mntinfo = NULL; + return 0; + } + for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { if (nsid->nd != &mnt_ns_desc) continue; diff --git a/criu/net.c b/criu/net.c index 44b0ce224..9825db10f 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2057,6 +2057,9 @@ int read_net_ns_img(void) { struct ns_id *ns; + if (!(root_ns_mask & CLONE_NEWNET)) + return 0; + for (ns = ns_ids; ns != NULL; ns = ns->next) { struct cr_img *img; int ret; From 35adc08598f78e9845388f235ffe0917d7606779 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 7 Feb 2019 15:17:51 +0300 Subject: [PATCH 2211/4375] mount: rework mount tree build step on restore Build each mntns mount tree alone just after reading mounts for it from image. These additional step before merging everything to a single mount tree allows us to have pointers to each mntns root mount at hand, also it allows us to remove extra complication from mnt_build_tree. Teach collect_mnt_from_image return a tail pointer, so we can merge lists together later after building each tree. Add separate merge_mount_trees helper to create joint mount tree for all mntns'es and simplify mnt_build_ids_tree. I don't see any place where we use mntinfo_tree on restore, so save the real root of mntns mounts tree in it, instead of root_yard_mp, will need it in next patches for checking restore of these trees. v2: prepend children to the root_yard in merge_mount_trees so that the order in merged tree persists Signed-off-by: Pavel Tikhomirov --- criu/mount.c | 131 +++++++++++++++++++++++++-------------------------- 1 file changed, 65 insertions(+), 66 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index fdaaa7b31..49708ffd5 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -330,7 +330,7 @@ static bool mounts_equal(struct mount_info *a, struct mount_info *b) */ static char *mnt_roots; -static struct mount_info *mnt_build_ids_tree(struct mount_info *list, struct mount_info *yard_mount) +static struct mount_info *mnt_build_ids_tree(struct mount_info *list) { struct mount_info *m, *root = NULL; @@ -351,41 +351,14 @@ static struct mount_info *mnt_build_ids_tree(struct mount_info *list, struct mou if (!parent) { /* Only a root mount can be without parent */ - if (root == NULL && m->is_ns_root) { + if (!root && m->is_ns_root) { root = m; - if (!yard_mount) - continue; + continue; } - if (!root) { - pr_err("No parent found for mountpoint %d (@%s)\n", - m->mnt_id, m->mountpoint); - return NULL; - } - - pr_debug("Mountpoint %d (@%s) w/o parent %d\n", - m->mnt_id, m->mountpoint, m->parent_mnt_id); - - if (!mounts_sb_equal(root, m) || - strcmp(root->root, m->root)) { - pr_err("Nested mount namespaces with different " - "roots %d (@%s %s) %d (@%s %s) are not supported yet\n", - root->mnt_id, root->mountpoint, root->root, - m->mnt_id, m->mountpoint, m->root); - return NULL; - } - - /* Mount all namespace roots into the roots yard. */ - parent = yard_mount; - if (unlikely(!yard_mount)) { - pr_err("Nested mount %d (@%s %s) w/o root insertion detected\n", - m->mnt_id, m->mountpoint, m->root); - return NULL; - } - - pr_debug("Mountpoint %d (@%s) get parent %d (@%s)\n", - m->mnt_id, m->mountpoint, - parent->mnt_id, parent->mountpoint); + pr_err("No parent found for mountpoint %d (@%s)\n", + m->mnt_id, m->mountpoint); + return NULL; } m->parent = parent; @@ -397,9 +370,6 @@ static struct mount_info *mnt_build_ids_tree(struct mount_info *list, struct mou return NULL; } - if (yard_mount) - return yard_mount; - return root; } @@ -997,8 +967,7 @@ static int resolve_shared_mounts(struct mount_info *info, int root_master_id) return 0; } -static struct mount_info *mnt_build_tree(struct mount_info *list, - struct mount_info *root_mp) +static struct mount_info *mnt_build_tree(struct mount_info *list) { struct mount_info *tree; @@ -1007,7 +976,7 @@ static struct mount_info *mnt_build_tree(struct mount_info *list, */ pr_info("Building mountpoints tree\n"); - tree = mnt_build_ids_tree(list, root_mp); + tree = mnt_build_ids_tree(list); if (!tree) return NULL; @@ -1690,7 +1659,7 @@ struct mount_info *collect_mntinfo(struct ns_id *ns, bool for_dump) return NULL; } - ns->mnt.mntinfo_tree = mnt_build_tree(pm, NULL); + ns->mnt.mntinfo_tree = mnt_build_tree(pm); if (ns->mnt.mntinfo_tree == NULL) goto err; @@ -2881,7 +2850,7 @@ static int get_mp_mountpoint(char *mountpoint, struct mount_info *mi, char *root return 0; } -static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid) +static int collect_mnt_from_image(struct mount_info **head, struct mount_info **tail, struct ns_id *nsid) { MntEntry *me = NULL; int ret, root_len = 1; @@ -2909,8 +2878,10 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid) goto err; pm->nsid = nsid; - pm->next = *pms; - *pms = pm; + pm->next = *head; + *head = pm; + if (!*tail) + *tail = pm; pm->mnt_id = me->mnt_id; pm->parent_mnt_id = me->parent_mnt_id; @@ -2995,11 +2966,20 @@ int read_mnt_ns_img(void) } for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) { + struct mount_info *head = NULL, *tail = NULL; + if (nsid->nd != &mnt_ns_desc) continue; - if (collect_mnt_from_image(&pms, nsid)) + if (collect_mnt_from_image(&head, &tail, nsid)) return -1; + + nsid->mnt.mntinfo_tree = mnt_build_tree(head); + if (!nsid->mnt.mntinfo_tree) + return -1; + + tail->next = pms; + pms = head; } mntinfo = pms; @@ -3101,6 +3081,40 @@ void fini_restore_mntns(void) } } +static int merge_mount_trees(struct mount_info *root_yard) +{ + struct mount_info *first = NULL; + struct ns_id *nsid; + + /* Merge mount trees together under root_yard */ + for (nsid = ns_ids; nsid; nsid = nsid->next) { + struct mount_info *root; + + if (nsid->nd != &mnt_ns_desc) + continue; + + root = nsid->mnt.mntinfo_tree; + + if (!first) + first = root; + else if (!mounts_sb_equal(root, first) || + strcmp(root->root, first->root)) { + pr_err("Nested mount namespaces with different " + "roots %d (@%s %s) %d (@%s %s) are not supported yet\n", + root->mnt_id, root->mountpoint, root->root, + first->mnt_id, first->mountpoint, first->root); + return -1; + } + + pr_debug("Mountpoint %d (@%s) moved to the root yard\n", + root->mnt_id, root->mountpoint); + root->parent = root_yard; + list_add(&root->siblings, &root_yard->children); + } + + return 0; +} + /* * All nested mount namespaces are restore as sub-trees of the root namespace. */ @@ -3140,8 +3154,6 @@ static int populate_roots_yard(void) static int populate_mnt_ns(void) { - struct mount_info *pms; - struct ns_id *nsid; int ret; root_yard_mp = mnt_entry_alloc(); @@ -3151,40 +3163,27 @@ static int populate_mnt_ns(void) root_yard_mp->mountpoint = mnt_roots; root_yard_mp->mounted = true; - pms = mnt_build_tree(mntinfo, root_yard_mp); - if (!pms) + if (merge_mount_trees(root_yard_mp)) return -1; #ifdef CONFIG_BINFMT_MISC_VIRTUALIZED if (!opts.has_binfmt_misc && !list_empty(&binfmt_misc_list)) { /* Add to mount tree. Generic code will mount it later */ - ret = add_cr_time_mount(pms, "binfmt_misc", BINFMT_MISC_HOME, 0); + ret = add_cr_time_mount(root_yard_mp, "binfmt_misc", BINFMT_MISC_HOME, 0); if (ret) return -1; } #endif - if (resolve_shared_mounts(mntinfo, pms->master_id)) + if (resolve_shared_mounts(mntinfo, 0)) return -1; - for (nsid = ns_ids; nsid; nsid = nsid->next) { - if (nsid->nd != &mnt_ns_desc) - continue; - - /* - * Make trees of all namespaces look the - * same, so that manual paths resolution - * works on them. - */ - nsid->mnt.mntinfo_tree = pms; - } - if (validate_mounts(mntinfo, false)) return -1; - mnt_tree_for_each(pms, set_is_overmounted); + mnt_tree_for_each(root_yard_mp, set_is_overmounted); - if (find_remap_mounts(pms)) + if (find_remap_mounts(root_yard_mp)) return -1; if (populate_roots_yard()) @@ -3193,8 +3192,8 @@ static int populate_mnt_ns(void) if (mount_clean_path()) return -1; - ret = mnt_tree_for_each(pms, do_mount_one); - mnt_tree_for_each(pms, do_close_one); + ret = mnt_tree_for_each(root_yard_mp, do_mount_one); + mnt_tree_for_each(root_yard_mp, do_close_one); if (ret == 0 && fixup_remap_mounts()) return -1; From f3cca97d80c77a6f2b9702edc8225ea8bb6034e5 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 27 Jun 2019 12:43:40 +0300 Subject: [PATCH 2212/4375] mount: make mnt_resort_siblings nonrecursive and reuse friendly Add mnt_subtree_next DFS-next search to remove recursion. v5: add these patch, remove recursion from sorting helpers v6: rip out butifull yet unused step-part of nfs-next algorithm Signed-off-by: Pavel Tikhomirov --- criu/mount.c | 57 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 49708ffd5..974af6eb2 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -385,13 +385,12 @@ static unsigned int mnt_depth(struct mount_info *m) return depth; } -static void mnt_resort_siblings(struct mount_info *tree) +static void __mnt_resort_children(struct mount_info *parent) { - struct mount_info *m, *p; LIST_HEAD(list); /* - * Put siblings of each node in an order they can be (u)mounted + * Put children mounts in an order they can be (u)mounted * I.e. if we have mounts on foo/bar/, foo/bar/foobar/ and foo/ * we should put them in the foo/bar/foobar/, foo/bar/, foo/ order. * Otherwise we will not be able to (u)mount them in a sequence. @@ -403,11 +402,12 @@ static void mnt_resort_siblings(struct mount_info *tree) * to contain hundreds (or more) elements. */ - pr_info("\tResorting siblings on %d\n", tree->mnt_id); - while (!list_empty(&tree->children)) { + pr_info("\tResorting children of %d in mount order\n", parent->mnt_id); + while (!list_empty(&parent->children)) { + struct mount_info *m, *p; unsigned int depth; - m = list_first_entry(&tree->children, struct mount_info, siblings); + m = list_first_entry(&parent->children, struct mount_info, siblings); list_del(&m->siblings); depth = mnt_depth(m); @@ -416,10 +416,31 @@ static void mnt_resort_siblings(struct mount_info *tree) break; list_add_tail(&m->siblings, &p->siblings); - mnt_resort_siblings(m); } - list_splice(&list, &tree->children); + list_splice(&list, &parent->children); +} + +static struct mount_info *mnt_subtree_next(struct mount_info *mi, + struct mount_info *root); + +static void resort_siblings(struct mount_info *root, + void (*resort_children)(struct mount_info *)) { + struct mount_info *mi = root; + while (1) { + /* + * Explanation: sorting the children of the tree like these is + * safe and does not break the tree search in mnt_subtree_next + * (DFS-next search), as we sort children before calling next + * on parent and thus before DFS-next ever touches them, so + * from the perspective of DFS-next all children look like they + * are already sorted. + */ + resort_children(mi); + mi = mnt_subtree_next(mi, root); + if (!mi) + break; + } } static void mnt_tree_show(struct mount_info *tree, int off) @@ -980,7 +1001,7 @@ static struct mount_info *mnt_build_tree(struct mount_info *list) if (!tree) return NULL; - mnt_resort_siblings(tree); + resort_siblings(tree, __mnt_resort_children); pr_info("Done:\n"); mnt_tree_show(tree, 0); return tree; @@ -3821,3 +3842,21 @@ int remount_readonly_mounts(void) */ return call_helper_process(ns_remount_readonly_mounts, NULL); } + +static struct mount_info *mnt_subtree_next(struct mount_info *mi, + struct mount_info *root) +{ + if (!list_empty(&mi->children)) + return list_entry(mi->children.next, + struct mount_info, siblings); + + while (mi->parent && mi != root) { + if (mi->siblings.next == &mi->parent->children) + mi = mi->parent; + else + return list_entry(mi->siblings.next, + struct mount_info, siblings); + } + + return NULL; +} From 2b4e653361ec0c3b827fb4af4e0b8848fb9a26f0 Mon Sep 17 00:00:00 2001 From: Nidhi Gupta Date: Tue, 5 Nov 2019 15:19:25 +0530 Subject: [PATCH 2213/4375] Run java functional tests on travis Signed-off-by: Nidhi Gupta --- .travis.yml | 2 ++ scripts/build/Dockerfile.openj9-alpine | 33 ++++++++++++++++++++++++++ scripts/build/Dockerfile.openj9-ubuntu | 30 +++++++++++++++++++++++ scripts/travis/Makefile | 3 +++ scripts/travis/openj9-test.sh | 22 +++++++++++++++++ 5 files changed, 90 insertions(+) create mode 100644 scripts/build/Dockerfile.openj9-alpine create mode 100644 scripts/build/Dockerfile.openj9-ubuntu create mode 100755 scripts/travis/openj9-test.sh diff --git a/.travis.yml b/.travis.yml index 7a0c29a55..6e854540b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,8 @@ env: - TR_ARCH=fedora-rawhide-aarch64 - TR_ARCH=centos - TR_ARCH=podman-test + - TR_ARCH=openj9-test + matrix: include: - os: linux diff --git a/scripts/build/Dockerfile.openj9-alpine b/scripts/build/Dockerfile.openj9-alpine new file mode 100644 index 000000000..654e7bf31 --- /dev/null +++ b/scripts/build/Dockerfile.openj9-alpine @@ -0,0 +1,33 @@ +FROM adoptopenjdk/openjdk8-openj9:alpine + +RUN apk update && apk add \ + bash \ + build-base \ + ccache \ + coreutils \ + git \ + gnutls-dev \ + libaio-dev \ + libcap-dev \ + libnet-dev \ + libnl3-dev \ + pkgconfig \ + protobuf-c-dev \ + protobuf-dev \ + python \ + sudo \ + maven \ + py-yaml \ + py-pip \ + py2-future \ + ip6tables \ + iptables \ + bash + +COPY . /criu +WORKDIR /criu + +RUN make + +ENTRYPOINT mvn -f test/javaTests/pom.xml test + diff --git a/scripts/build/Dockerfile.openj9-ubuntu b/scripts/build/Dockerfile.openj9-ubuntu new file mode 100644 index 000000000..13d9080ff --- /dev/null +++ b/scripts/build/Dockerfile.openj9-ubuntu @@ -0,0 +1,30 @@ +FROM adoptopenjdk/openjdk8-openj9:latest + +RUN apt-get update && apt-get install -y --no-install-recommends protobuf-c-compiler \ + libprotobuf-c-dev \ + libaio-dev \ + python-future \ + libprotobuf-dev \ + protobuf-compiler \ + libcap-dev \ + libnl-3-dev \ + gdb \ + bash \ + python-protobuf \ + python-yaml \ + libnet-dev \ + libnl-route-3-dev \ + libbsd-dev \ + make \ + git \ + pkg-config \ + gcc \ + maven + +COPY . /criu +WORKDIR /criu + +RUN make + +ENTRYPOINT mvn -f test/javaTests/pom.xml test + diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index baddd6eb1..c6b67935b 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -41,5 +41,8 @@ docker-test: podman-test: ./podman-test.sh +openj9-test: + ./openj9-test.sh + %: $(MAKE) -C ../build $@$(target-suffix) diff --git a/scripts/travis/openj9-test.sh b/scripts/travis/openj9-test.sh new file mode 100755 index 000000000..968f064f8 --- /dev/null +++ b/scripts/travis/openj9-test.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +cd ../.. + +failures="" + +docker build -t criu-openj9-ubuntu-test:latest -f scripts/build/Dockerfile.openj9-ubuntu . +docker run --rm --privileged criu-openj9-ubuntu-test:latest +if [ $? -ne 0 ]; then + failures=`echo "$failures ubuntu"` +fi + +docker build -t criu-openj9-alpine-test:latest -f scripts/build/Dockerfile.openj9-alpine . +docker run --rm --privileged criu-openj9-alpine-test:latest +if [ $? -ne 0 ]; then + failures=`echo "$failures alpine"` +fi + +if [ -n "$failures" ]; then + echo "Tests failed on $failures" + exit 1 +fi From 62953d4334b0294ac90e0ec088267fa99daf9f92 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 4 Nov 2019 08:52:55 +0100 Subject: [PATCH 2214/4375] travis: fix copy paste error from previous commit In my previous commit I copied a line with a return into the main script body. bash can only return from functions. This changes return to exit. Signed-off-by: Adrian Reber --- scripts/travis/travis-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 1f6b19130..07311511c 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -86,7 +86,7 @@ if [ "$WIDTH" -gt 80 ]; then exit 1 fi -[ -n "$SKIP_TRAVIS_TEST" ] && return +[ -n "$SKIP_TRAVIS_TEST" ] && exit 0 ulimit -c unlimited From 6be414bb2be1e8be13b996f60977ecc44b765a2e Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 4 Nov 2019 08:54:22 +0100 Subject: [PATCH 2215/4375] travis: Do not run privileged containers in LXD Travis uses unprivileged containers for aarch64 in LXD. Docker with '--privileged' fails in such situation. This changes the travis setup to only start docker with '--privileged' if running on x86_64. Signed-off-by: Adrian Reber --- scripts/travis/Makefile | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index c6b67935b..80c7b9230 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -13,6 +13,9 @@ endif TARGETS := alpine fedora-rawhide centos ZDTM_OPTIONS := +UNAME := $(shell uname -m) + +export UNAME alpine: ZDTM_OPTIONS=-x zdtm/static/binfmt_misc -x zdtm/static/netns-nf -x zdtm/static/sched_policy00 -x zdtm/static/seccomp_strict -x zdtm/static/sigaltstack -x zdtm/static/signalfd00 -x zdtm/static/config_inotify_irmap @@ -23,17 +26,29 @@ define DOCKER_JSON endef export DOCKER_JSON -$(TARGETS): - echo "$$DOCKER_JSON" > /etc/docker/daemon.json - systemctl restart docker - $(MAKE) -C ../build $@$(target-suffix) - docker run --env-file docker.env --rm -it --privileged -v /lib/modules:/lib/modules --tmpfs /run criu-$@ scripts/travis/travis-tests -fedora-asan: - echo "$$DOCKER_JSON" > /etc/docker/daemon.json - systemctl restart docker +ifeq ($(UNAME),x86_64) + CONTAINER_OPTS := --rm -it --privileged -v /lib/modules:/lib/modules --tmpfs /run +else + CONTAINER_OPTS := --rm -v /lib/modules:/lib/modules --tmpfs /run +endif + +restart-docker: + if [ "$$UNAME" = "x86_64" ]; then \ + echo "$$DOCKER_JSON" > /etc/docker/daemon.json; \ + cat /etc/docker/daemon.json; \ + systemctl status docker; \ + systemctl restart docker; \ + systemctl status docker; \ + fi + +$(TARGETS): restart-docker $(MAKE) -C ../build $@$(target-suffix) - docker run --rm -it --privileged -v /lib/modules:/lib/modules --tmpfs /run criu-$@ ./scripts/travis/asan.sh $(ZDTM_OPTIONS) + docker run --env-file docker.env $(CONTAINER_OPTS) criu-$@ scripts/travis/travis-tests + +fedora-asan: restart-docker + $(MAKE) -C ../build $@$(target-suffix) + docker run -it $(CONTAINER_OPTS) criu-$@ ./scripts/travis/asan.sh $(ZDTM_OPTIONS) docker-test: ./docker-test.sh From 075f1beaf7d36cb9ea5030e1faab9661c33290ab Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 4 Nov 2019 08:56:15 +0100 Subject: [PATCH 2216/4375] Makefile hack for travis aarch64/armv8l For CRIU's compile only tests for armv7hf on Travis we are using 'setarch linux32' which returns armv8l on Travis aarch64. This adds a path in the Makefile to treat armv8l just as armv7hf during compile. This enables us to run armv7hf compile tests on Travis aarch64 hardware. Much faster. Maybe not entirely correct, but probably good enough for compile testing in an armv7hf container. Signed-off-by: Adrian Reber --- Makefile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0140330e1..f827e7baa 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,6 @@ endif # Architecture specific options. ifeq ($(ARCH),arm) ARMV := $(shell echo $(UNAME-M) | sed -nr 's/armv([[:digit:]]).*/\1/p; t; i7') - DEFINES := -DCONFIG_ARMV$(ARMV) -DCONFIG_VDSO_32 ifeq ($(ARMV),6) USERCFLAGS += -march=armv6 @@ -45,6 +44,16 @@ ifeq ($(ARCH),arm) USERCFLAGS += -march=armv7-a endif + ifeq ($(ARMV),8) + # Running 'setarch linux32 uname -m' returns armv8l on travis aarch64. + # This tells CRIU to handle armv8l just as armv7hf. Right now this is + # only used for compile testing. No further verification of armv8l exists. + USERCFLAGS += -march=armv7-a + ARMV := 7 + endif + + DEFINES := -DCONFIG_ARMV$(ARMV) -DCONFIG_VDSO_32 + PROTOUFIX := y # For simplicity - compile code in Arm mode without interwork. # We could choose Thumb mode as default instead - but a dirty From eab8cf0775ed5569bb22795a86817dae06cf0005 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 4 Nov 2019 08:58:54 +0100 Subject: [PATCH 2217/4375] travis: switch all arm related tests to real hardware This switches all arm related tests (32bit and 64bit) to the aarch64 systems Travis provides. For arm32 we are running in a armv7hf container on aarch64 with 'setarch linux32'. The main changes are that docker on Travis aarch64 cannot use '--privileged' as Travis is using unprivileged LXD containers to setup the testing environment. Signed-off-by: Adrian Reber --- .travis.yml | 50 +++++++++++++++---- scripts/build/Dockerfile.armv7hf.hdr | 4 +- scripts/build/Dockerfile.armv7hf.tmpl | 2 +- .../Dockerfile.fedora-rawhide-aarch64.hdr | 3 -- .../Dockerfile.fedora-rawhide-aarch64.tmpl | 1 - scripts/build/Dockerfile.linux32.tmpl | 47 +++++++++++++++++ scripts/build/Makefile | 4 +- scripts/travis/Makefile | 2 + scripts/travis/podman-test.sh | 2 +- 9 files changed, 93 insertions(+), 22 deletions(-) delete mode 100644 scripts/build/Dockerfile.fedora-rawhide-aarch64.hdr delete mode 120000 scripts/build/Dockerfile.fedora-rawhide-aarch64.tmpl create mode 100644 scripts/build/Dockerfile.linux32.tmpl diff --git a/.travis.yml b/.travis.yml index 6e854540b..85b6b6e07 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: c sudo: required -dist: xenial +dist: bionic cache: ccache services: - docker @@ -9,21 +9,12 @@ env: - TR_ARCH=local CLANG=1 - TR_ARCH=local COMPAT_TEST=y - TR_ARCH=local CLANG=1 COMPAT_TEST=y - - TR_ARCH=alpine - - TR_ARCH=fedora-asan - TR_ARCH=x86_64 - TR_ARCH=x86_64 CLANG=1 - - TR_ARCH=armv7hf - TR_ARCH=ppc64le - TR_ARCH=s390x - - TR_ARCH=armv7hf CLANG=1 - TR_ARCH=ppc64le CLANG=1 - - TR_ARCH=alpine CLANG=1 - TR_ARCH=docker-test - - TR_ARCH=fedora-rawhide - - TR_ARCH=fedora-rawhide-aarch64 - - TR_ARCH=centos - - TR_ARCH=podman-test - TR_ARCH=openj9-test matrix: @@ -36,10 +27,47 @@ matrix: arch: arm64 env: TR_ARCH=local CLANG=1 dist: bionic + - os: linux + arch: arm64 + # This runs on aarch64 with 'setarch linux32' + env: TR_ARCH=armv7hf + dist: bionic + - os: linux + arch: arm64 + # This runs on aarch64 with 'setarch linux32' + env: TR_ARCH=armv7hf CLANG=1 + dist: bionic + - os: linux + arch: arm64 + env: TR_ARCH=fedora-rawhide + dist: bionic + - os: linux + arch: amd64 + env: TR_ARCH=fedora-rawhide + dist: xenial # test hangs on bionic + - os: linux + arch: amd64 + env: TR_ARCH=podman-test + dist: bionic + - os: linux + arch: amd64 + env: TR_ARCH=alpine CLANG=1 + dist: xenial # test hangs on bionic + - os: linux + arch: amd64 + env: TR_ARCH=alpine + dist: xenial # test hangs on bionic + - os: linux + arch: amd64 + env: TR_ARCH=centos + dist: xenial # test hangs on bionic + - os: linux + arch: amd64 + env: TR_ARCH=fedora-asan + dist: xenial # test hangs on bionic allow_failures: - env: TR_ARCH=docker-test - env: TR_ARCH=fedora-rawhide - - env: TR_ARCH=fedora-rawhide-aarch64 - env: TR_ARCH=s390x - env: TR_ARCH=local GCOV=1 script: diff --git a/scripts/build/Dockerfile.armv7hf.hdr b/scripts/build/Dockerfile.armv7hf.hdr index d453d6df7..7c66474e5 100644 --- a/scripts/build/Dockerfile.armv7hf.hdr +++ b/scripts/build/Dockerfile.armv7hf.hdr @@ -1,3 +1 @@ -FROM arm32v7/ubuntu:xenial - -COPY scripts/build/qemu-user-static/usr/bin/qemu-arm-static /usr/bin/qemu-arm-static +FROM arm32v7/ubuntu:bionic diff --git a/scripts/build/Dockerfile.armv7hf.tmpl b/scripts/build/Dockerfile.armv7hf.tmpl index cb804790e..7bc6d9cde 120000 --- a/scripts/build/Dockerfile.armv7hf.tmpl +++ b/scripts/build/Dockerfile.armv7hf.tmpl @@ -1 +1 @@ -Dockerfile.tmpl \ No newline at end of file +Dockerfile.linux32.tmpl \ No newline at end of file diff --git a/scripts/build/Dockerfile.fedora-rawhide-aarch64.hdr b/scripts/build/Dockerfile.fedora-rawhide-aarch64.hdr deleted file mode 100644 index 82f29e336..000000000 --- a/scripts/build/Dockerfile.fedora-rawhide-aarch64.hdr +++ /dev/null @@ -1,3 +0,0 @@ -FROM arm64v8/fedora:rawhide - -COPY scripts/build/qemu-user-static/usr/bin/qemu-aarch64-static /usr/bin/qemu-aarch64-static diff --git a/scripts/build/Dockerfile.fedora-rawhide-aarch64.tmpl b/scripts/build/Dockerfile.fedora-rawhide-aarch64.tmpl deleted file mode 120000 index e4c40309c..000000000 --- a/scripts/build/Dockerfile.fedora-rawhide-aarch64.tmpl +++ /dev/null @@ -1 +0,0 @@ -Dockerfile.fedora.tmpl \ No newline at end of file diff --git a/scripts/build/Dockerfile.linux32.tmpl b/scripts/build/Dockerfile.linux32.tmpl new file mode 100644 index 000000000..5d3fe5139 --- /dev/null +++ b/scripts/build/Dockerfile.linux32.tmpl @@ -0,0 +1,47 @@ +ARG CC=gcc +ARG ENV1=FOOBAR + +RUN apt-get update && apt-get install -y \ + ccache \ + libnet-dev \ + libnl-route-3-dev \ + $CC \ + bsdmainutils \ + build-essential \ + git-core \ + iptables \ + libaio-dev \ + libcap-dev \ + libgnutls28-dev \ + libgnutls30 \ + libnl-3-dev \ + libprotobuf-c-dev \ + libprotobuf-dev \ + libselinux-dev \ + pkg-config \ + protobuf-c-compiler \ + protobuf-compiler \ + python-minimal \ + python-future + +COPY . /criu +WORKDIR /criu +ENV CC="ccache $CC" CCACHE_DIR=/tmp/.ccache CCACHE_NOCOMPRESS=1 $ENV1=yes + +RUN uname -m && setarch linux32 uname -m && setarch --list + +RUN mv .ccache /tmp && make mrproper && ccache -s && \ + date && \ +# Check single object build + setarch linux32 make -j $(nproc) CC="$CC" criu/parasite-syscall.o && \ +# Compile criu + setarch linux32 make -j $(nproc) CC="$CC" && \ + date && \ +# Check that "make mrproper" works + setarch linux32 make mrproper && ! git clean -ndx --exclude=scripts/build \ + --exclude=.config --exclude=test | grep . + +# Compile tests +RUN date && setarch linux32 make -j $(nproc) CC="$CC" -C test/zdtm && date + +#RUN make test/compel/handle_binary && ./test/compel/handle_binary diff --git a/scripts/build/Makefile b/scripts/build/Makefile index 3d4d91cd5..d7ad82aec 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -1,5 +1,5 @@ -QEMU_ARCHES := armv7hf ppc64le s390x fedora-rawhide-aarch64 # require qemu -ARCHES := $(QEMU_ARCHES) aarch64 x86_64 fedora-asan fedora-rawhide centos +QEMU_ARCHES := ppc64le s390x # require qemu +ARCHES := $(QEMU_ARCHES) aarch64 x86_64 fedora-asan fedora-rawhide centos armv7hf TARGETS := $(ARCHES) alpine TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) CONTAINER_RUNTIME := docker diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index 80c7b9230..373171149 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -28,6 +28,8 @@ endef export DOCKER_JSON ifeq ($(UNAME),x86_64) + # On anything besides x86_64 Travis is running unprivileged LXD + # containers which do not support running docker with '--privileged'. CONTAINER_OPTS := --rm -it --privileged -v /lib/modules:/lib/modules --tmpfs /run else CONTAINER_OPTS := --rm -v /lib/modules:/lib/modules --tmpfs /run diff --git a/scripts/travis/podman-test.sh b/scripts/travis/podman-test.sh index 9bd1f3d8b..eafdc73be 100755 --- a/scripts/travis/podman-test.sh +++ b/scripts/travis/podman-test.sh @@ -11,7 +11,7 @@ apt-get install -qq \ apt-get update -qq -apt-get install -qqy podman +apt-get install -qqy podman containernetworking-plugins export SKIP_TRAVIS_TEST=1 From fe668075ad2afe1021f8ff86d774eccb7bd1bef7 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 13 Nov 2019 08:38:16 +0100 Subject: [PATCH 2218/4375] travis: switch pcp64le and s390x to real hardware Now that Travis also supports ppc64le and s390x we can remove all qemu based docker emulation from our test setup. This now runs ppc64le and s390x tests on real hardware (LXD containers). Signed-off-by: Adrian Reber --- .travis.yml | 17 +++++++++---- scripts/build/Dockerfile.aarch64.hdr | 3 --- scripts/build/Dockerfile.aarch64.tmpl | 1 - scripts/build/Dockerfile.ppc64le.hdr | 5 ---- scripts/build/Dockerfile.ppc64le.tmpl | 1 - scripts/build/Dockerfile.s390x.hdr | 6 ----- scripts/build/Dockerfile.s390x.tmpl | 1 - scripts/build/Makefile | 21 +--------------- scripts/build/binfmt_misc | 13 ---------- scripts/build/extract-deb-pkg | 36 --------------------------- scripts/travis/travis-tests | 7 ------ 11 files changed, 13 insertions(+), 98 deletions(-) delete mode 100644 scripts/build/Dockerfile.aarch64.hdr delete mode 120000 scripts/build/Dockerfile.aarch64.tmpl delete mode 100644 scripts/build/Dockerfile.ppc64le.hdr delete mode 120000 scripts/build/Dockerfile.ppc64le.tmpl delete mode 100644 scripts/build/Dockerfile.s390x.hdr delete mode 120000 scripts/build/Dockerfile.s390x.tmpl delete mode 100755 scripts/build/binfmt_misc delete mode 100755 scripts/build/extract-deb-pkg diff --git a/.travis.yml b/.travis.yml index 85b6b6e07..3c760d08a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,14 +11,22 @@ env: - TR_ARCH=local CLANG=1 COMPAT_TEST=y - TR_ARCH=x86_64 - TR_ARCH=x86_64 CLANG=1 - - TR_ARCH=ppc64le - - TR_ARCH=s390x - - TR_ARCH=ppc64le CLANG=1 - TR_ARCH=docker-test - TR_ARCH=openj9-test - matrix: include: + - os: linux + arch: ppc64le + env: TR_ARCH=local + dist: bionic + - os: linux + arch: ppc64le + env: TR_ARCH=local CLANG=1 + dist: bionic + - os: linux + arch: s390x + env: TR_ARCH=local + dist: bionic - os: linux arch: arm64 env: TR_ARCH=local @@ -68,7 +76,6 @@ matrix: allow_failures: - env: TR_ARCH=docker-test - env: TR_ARCH=fedora-rawhide - - env: TR_ARCH=s390x - env: TR_ARCH=local GCOV=1 script: - sudo make CCACHE=1 -C scripts/travis $TR_ARCH diff --git a/scripts/build/Dockerfile.aarch64.hdr b/scripts/build/Dockerfile.aarch64.hdr deleted file mode 100644 index c90c98088..000000000 --- a/scripts/build/Dockerfile.aarch64.hdr +++ /dev/null @@ -1,3 +0,0 @@ -FROM arm64v8/ubuntu:xenial - -COPY scripts/build/qemu-user-static/usr/bin/qemu-aarch64-static /usr/bin/qemu-aarch64-static diff --git a/scripts/build/Dockerfile.aarch64.tmpl b/scripts/build/Dockerfile.aarch64.tmpl deleted file mode 120000 index cb804790e..000000000 --- a/scripts/build/Dockerfile.aarch64.tmpl +++ /dev/null @@ -1 +0,0 @@ -Dockerfile.tmpl \ No newline at end of file diff --git a/scripts/build/Dockerfile.ppc64le.hdr b/scripts/build/Dockerfile.ppc64le.hdr deleted file mode 100644 index ba65901c2..000000000 --- a/scripts/build/Dockerfile.ppc64le.hdr +++ /dev/null @@ -1,5 +0,0 @@ -FROM ppc64le/ubuntu:xenial - -ENV QEMU_CPU POWER8 -COPY scripts/build/qemu-user-static/usr/bin/qemu-ppc64le-static /usr/bin/qemu-ppc64le-static -RUN sed -i '/security/ d' /etc/apt/sources.list diff --git a/scripts/build/Dockerfile.ppc64le.tmpl b/scripts/build/Dockerfile.ppc64le.tmpl deleted file mode 120000 index cb804790e..000000000 --- a/scripts/build/Dockerfile.ppc64le.tmpl +++ /dev/null @@ -1 +0,0 @@ -Dockerfile.tmpl \ No newline at end of file diff --git a/scripts/build/Dockerfile.s390x.hdr b/scripts/build/Dockerfile.s390x.hdr deleted file mode 100644 index e02097f62..000000000 --- a/scripts/build/Dockerfile.s390x.hdr +++ /dev/null @@ -1,6 +0,0 @@ -FROM s390x/debian:latest - -ENV QEMU_CPU z900 -COPY scripts/build/qemu-user-static/usr/bin/qemu-s390x-static /usr/bin/qemu-s390x-static -# The security repository does not seem to exist anymore -RUN sed -i '/security/ d' /etc/apt/sources.list diff --git a/scripts/build/Dockerfile.s390x.tmpl b/scripts/build/Dockerfile.s390x.tmpl deleted file mode 120000 index cb804790e..000000000 --- a/scripts/build/Dockerfile.s390x.tmpl +++ /dev/null @@ -1 +0,0 @@ -Dockerfile.tmpl \ No newline at end of file diff --git a/scripts/build/Makefile b/scripts/build/Makefile index d7ad82aec..a7c78e8bd 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -1,5 +1,4 @@ -QEMU_ARCHES := ppc64le s390x # require qemu -ARCHES := $(QEMU_ARCHES) aarch64 x86_64 fedora-asan fedora-rawhide centos armv7hf +ARCHES := x86_64 fedora-asan fedora-rawhide centos armv7hf TARGETS := $(ARCHES) alpine TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) CONTAINER_RUNTIME := docker @@ -16,15 +15,6 @@ $(foreach arch,$(ARCHES),$(eval $(call ARCH_DEP,$(arch)))) Dockerfile.%: Dockerfile.%.hdr Dockerfile.%.tmpl cat $^ > $@ -qemu-user-static: - ./extract-deb-pkg qemu-user-static - -binfmt_misc: - ./binfmt_misc -.PHONY: binfmt_misc - -$(QEMU_ARCHES): qemu-user-static binfmt_misc - $(TARGETS): mkdir -p $(HOME)/.ccache mv $(HOME)/.ccache ../../ @@ -42,12 +32,3 @@ $(foreach t,$(TARGETS),$(eval $(call CLANG_DEP,$(t)))) %-clang: DB_ENV=--build-arg ENV1=CCACHE_CPP2 s390x-clang: DB_CC=--build-arg CC=clang-3.8 .PHONY: $(TARGETS_CLANG) - -clean: - rm -rf qemu-user-static - for ARCH in $(ARCHES); do \ - FILE=/proc/sys/fs/binfmt_misc/$$ARCH; \ - test -f $$FILE && echo -1 > $$FILE; \ - rm -f Dockerfile.$$ARCH; \ - done -.PHONY: clean diff --git a/scripts/build/binfmt_misc b/scripts/build/binfmt_misc deleted file mode 100755 index bf2a2ecad..000000000 --- a/scripts/build/binfmt_misc +++ /dev/null @@ -1,13 +0,0 @@ -set -e -x - -test -f /proc/sys/fs/binfmt_misc/armv7hf || - echo ':armv7hf:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:' > /proc/sys/fs/binfmt_misc/register; - -test -f /proc/sys/fs/binfmt_misc/aarch64 || - echo ':aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-aarch64-static:' > /proc/sys/fs/binfmt_misc/register - -test -f /proc/sys/fs/binfmt_misc/ppc64le || - echo ':ppc64le:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00:\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00:/usr/bin/qemu-ppc64le-static:' > /proc/sys/fs/binfmt_misc/register - -test -f /proc/sys/fs/binfmt_misc/s390x || - echo ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-s390x-static:' > /proc/sys/fs/binfmt_misc/register diff --git a/scripts/build/extract-deb-pkg b/scripts/build/extract-deb-pkg deleted file mode 100755 index 44457bc5a..000000000 --- a/scripts/build/extract-deb-pkg +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -set -e -set -u -set -o pipefail -MIRROR="https://mirrors.kernel.org/ubuntu" -PKGS="$MIRROR/dists/bionic/universe/binary-amd64/Packages.gz" - -if [ $# -ne 1 ]; then - echo "Usage: $0 package-name" 1>&2 - exit 1 -fi - -if [ -d "$1" ]; then - echo "Directory $1 already exists -- exiting" - exit 0 -fi - -if ! pkg=$(curl -sSL "$PKGS" | zgrep "Filename.*$1" | awk '{ print $2 }'); then - echo "ERROR: no packages matching $1" 1>&2 - exit 1 -fi - -if [ "$(wc -w <<< "$pkg")" -gt 1 ]; then - echo "$pkg" 1>&2 - echo "ERROR: more than one match for $1" 1>&2 - exit 1 -fi - -mkdir "$1" -cd "$1" - -wget "$MIRROR/$pkg" -pkg=$(basename "$pkg") -ar vx "$pkg" -tar xJvf data.tar.xz diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 07311511c..bc97fd455 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -51,13 +51,6 @@ travis_prep () { CC="ccache $CC" fi - # The /etc/apt/sources.list in the current trusty image for ppc64le is - # broken and needs to be fixed - if [ "$TR_ARCH" = "ppc64le" ] ; then - sed -i '/security/ d' /etc/apt/sources.list - fi - - # Do not install x86_64 specific packages on other architectures if [ "$UNAME_M" = "x86_64" ]; then TRAVIS_PKGS="$TRAVIS_PKGS $X86_64_PKGS" From ea018e9a9c78353b8f5532a2e5a36a0d1c5e8769 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 13 Nov 2019 13:25:30 +0100 Subject: [PATCH 2219/4375] travis: remove group from .travis.yml Tests are successful even after removing 'group:' from .travis.yml. Apparently it is not necessary. Signed-off-by: Adrian Reber --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3c760d08a..f6f71be48 100644 --- a/.travis.yml +++ b/.travis.yml @@ -82,4 +82,3 @@ script: after_success: - ccache -s - make -C scripts/travis after_success -group: deprecated-2017Q2 From ef277068de3f6f89f394b9f63a3870eddde8c998 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 9 Nov 2019 22:20:34 +0000 Subject: [PATCH 2220/4375] lib/ptrace: Allow PTRACE_PEEKDATA with errno != 0 >From man ptrace: > On error, all requests return -1, and errno is set appropriately. > Since the value returned by a successful PTRACE_PEEK* request may be > -1, the caller must clear errno before the call, and then check > it afterward to determine whether or not an error occurred. FWIW: if ptrace_peek_area() is called with (errno != 0) it may false-fail if the data is (-1). Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/src/lib/ptrace.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compel/src/lib/ptrace.c b/compel/src/lib/ptrace.c index 9142bac42..715e564df 100644 --- a/compel/src/lib/ptrace.c +++ b/compel/src/lib/ptrace.c @@ -34,14 +34,20 @@ int ptrace_suspend_seccomp(pid_t pid) int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes) { unsigned long w; + int old_errno = errno; + if (bytes & (sizeof(long) - 1)) return -1; + + errno = 0; for (w = 0; w < bytes / sizeof(long); w++) { unsigned long *d = dst, *a = addr; + d[w] = ptrace(PTRACE_PEEKDATA, pid, a + w, NULL); if (d[w] == -1U && errno) goto err; } + errno = old_errno; return 0; err: return -2; From a93117ede1e58db68246f775c00bc21683954c39 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 9 Nov 2019 22:20:35 +0000 Subject: [PATCH 2221/4375] lib/ptrace: Be more elaborate about failures Also, don't use the magic -2 => return errno on failure. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/src/lib/ptrace.c | 46 ++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/compel/src/lib/ptrace.c b/compel/src/lib/ptrace.c index 715e564df..4c3530c85 100644 --- a/compel/src/lib/ptrace.c +++ b/compel/src/lib/ptrace.c @@ -36,50 +36,72 @@ int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes) unsigned long w; int old_errno = errno; - if (bytes & (sizeof(long) - 1)) + if (bytes & (sizeof(long) - 1)) { + pr_err("Peek request with non-word size %ld\n", bytes); return -1; + } errno = 0; for (w = 0; w < bytes / sizeof(long); w++) { unsigned long *d = dst, *a = addr; d[w] = ptrace(PTRACE_PEEKDATA, pid, a + w, NULL); - if (d[w] == -1U && errno) + if (d[w] == -1U && errno) { + pr_perror("PEEKDATA failed"); goto err; + } } errno = old_errno; return 0; err: - return -2; + return -errno; } int ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes) { unsigned long w; - if (bytes & (sizeof(long) - 1)) + + if (bytes & (sizeof(long) - 1)) { + pr_err("Poke request with non-word size %ld\n", bytes); return -1; + } + for (w = 0; w < bytes / sizeof(long); w++) { unsigned long *s = src, *a = addr; - if (ptrace(PTRACE_POKEDATA, pid, a + w, s[w])) + + if (ptrace(PTRACE_POKEDATA, pid, a + w, s[w])) { + pr_perror("POKEDATA failed"); goto err; + } } return 0; err: - return -2; + return -errno; } /* don't swap big space, it might overflow the stack */ int ptrace_swap_area(pid_t pid, void *dst, void *src, long bytes) { void *t = alloca(bytes); + int err; - if (ptrace_peek_area(pid, t, dst, bytes)) - return -1; + err = ptrace_peek_area(pid, t, dst, bytes); + if (err) + return err; - if (ptrace_poke_area(pid, src, dst, bytes)) { - if (ptrace_poke_area(pid, t, dst, bytes)) - return -2; - return -1; + err = ptrace_poke_area(pid, src, dst, bytes); + if (err) { + int err2; + + pr_err("Can't poke %d @ %p from %p sized %ld\n", + pid, dst, src, bytes); + + err2 = ptrace_poke_area(pid, t, dst, bytes); + if (err2) { + pr_err("Can't restore the original data with poke\n"); + return err2; + } + return err; } memcpy(src, t, bytes); From c8f16bfacb82b98841a9de49f5f9a15254d7b95f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 9 Nov 2019 22:20:36 +0000 Subject: [PATCH 2222/4375] compel/infect: Warn if close() failed on memfd As a preparation for __must_check on compel_syscall(), check it on close() too - maybe not as useful as with other syscalls, but why not. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/src/lib/infect.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index f0bcaf334..f726a9895 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -718,14 +718,25 @@ static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size) return 0; } +static void parasite_memfd_close(struct parasite_ctl *ctl, int fd) +{ + bool __maybe_unused compat = !compel_mode_native(ctl); + long ret; + int err; + + err = compel_syscall(ctl, __NR(close, compat), &ret, fd, 0, 0, 0, 0, 0); + if (err || ret) + pr_err("Can't close memfd\n"); +} + static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) { void *where = (void *)ctl->ictx.syscall_ip + BUILTIN_SYSCALL_SIZE; + bool __maybe_unused compat_task = !compel_mode_native(ctl); uint8_t orig_code[MEMFD_FNAME_SZ] = MEMFD_FNAME; pid_t pid = ctl->rpid; long sret = -ENOSYS; int ret, fd, lfd; - bool __maybe_unused compat_task = !compel_mode_native(ctl); if (ctl->ictx.flags & INFECT_NO_MEMFD) return 1; @@ -741,10 +752,9 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) (unsigned long)where, 0, 0, 0, 0, 0); if (ptrace_poke_area(pid, orig_code, where, sizeof(orig_code))) { - fd = (int)(long)sret; + fd = (int)sret; if (fd >= 0) - compel_syscall(ctl, __NR(close, compat_task), &sret, - fd, 0, 0, 0, 0, 0); + parasite_memfd_close(ctl, fd); pr_err("Can't restore memfd args (pid: %d)\n", pid); return -1; } @@ -752,7 +762,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) if (ret < 0) return ret; - fd = (int)(long)sret; + fd = (int)sret; if (fd == -ENOSYS) return 1; if (fd < 0) { @@ -787,7 +797,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) goto err_curef; } - compel_syscall(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); + parasite_memfd_close(ctl, fd); close(lfd); pr_info("Set up parasite blob using memfd\n"); @@ -796,7 +806,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) err_curef: close(lfd); err_cure: - compel_syscall(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); + parasite_memfd_close(ctl, fd); return -1; } From ee449e27c6979291660772db9724474a55d83b12 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 9 Nov 2019 22:20:37 +0000 Subject: [PATCH 2223/4375] compel: Mark compat argument of __NR() as used And remove __maybe_unused work-around. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/aarch64/src/lib/include/syscall.h | 2 +- compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h | 2 +- compel/arch/arm/src/lib/include/syscall.h | 2 +- compel/arch/arm/src/lib/include/uapi/asm/infect-types.h | 2 +- compel/arch/ppc64/src/lib/include/syscall.h | 2 +- compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h | 2 +- compel/arch/s390/src/lib/include/uapi/asm/infect-types.h | 2 +- compel/src/lib/infect.c | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compel/arch/aarch64/src/lib/include/syscall.h b/compel/arch/aarch64/src/lib/include/syscall.h index e2ec1272e..30290667a 100644 --- a/compel/arch/aarch64/src/lib/include/syscall.h +++ b/compel/arch/aarch64/src/lib/include/syscall.h @@ -1,4 +1,4 @@ #ifndef __COMPEL_SYSCALL_H__ #define __COMPEL_SYSCALL_H__ -#define __NR(syscall, compat) __NR_##syscall +#define __NR(syscall, compat) ({ (void)compat; __NR_##syscall; }) #endif diff --git a/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h b/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h index 4662f7689..7a33baa8e 100644 --- a/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/infect-types.h @@ -27,6 +27,6 @@ typedef struct user_fpsimd_state user_fpregs_struct_t; #define ARCH_SI_TRAP TRAP_BRKPT -#define __NR(syscall, compat) __NR_##syscall +#define __NR(syscall, compat) ({ (void)compat; __NR_##syscall; }) #endif /* UAPI_COMPEL_ASM_TYPES_H__ */ diff --git a/compel/arch/arm/src/lib/include/syscall.h b/compel/arch/arm/src/lib/include/syscall.h index e2ec1272e..30290667a 100644 --- a/compel/arch/arm/src/lib/include/syscall.h +++ b/compel/arch/arm/src/lib/include/syscall.h @@ -1,4 +1,4 @@ #ifndef __COMPEL_SYSCALL_H__ #define __COMPEL_SYSCALL_H__ -#define __NR(syscall, compat) __NR_##syscall +#define __NR(syscall, compat) ({ (void)compat; __NR_##syscall; }) #endif diff --git a/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h b/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h index b8286d404..69222b251 100644 --- a/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/arm/src/lib/include/uapi/asm/infect-types.h @@ -61,6 +61,6 @@ struct user_vfp_exc { #define ARCH_SI_TRAP TRAP_BRKPT -#define __NR(syscall, compat) __NR_##syscall +#define __NR(syscall, compat) ({ (void)compat; __NR_##syscall; }) #endif /* UAPI_COMPEL_ASM_TYPES_H__ */ diff --git a/compel/arch/ppc64/src/lib/include/syscall.h b/compel/arch/ppc64/src/lib/include/syscall.h index e2ec1272e..30290667a 100644 --- a/compel/arch/ppc64/src/lib/include/syscall.h +++ b/compel/arch/ppc64/src/lib/include/syscall.h @@ -1,4 +1,4 @@ #ifndef __COMPEL_SYSCALL_H__ #define __COMPEL_SYSCALL_H__ -#define __NR(syscall, compat) __NR_##syscall +#define __NR(syscall, compat) ({ (void)compat; __NR_##syscall; }) #endif diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h b/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h index 89fc4aa3c..126fa2ea3 100644 --- a/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/infect-types.h @@ -81,6 +81,6 @@ typedef struct { #define ARCH_SI_TRAP TRAP_BRKPT -#define __NR(syscall, compat) __NR_##syscall +#define __NR(syscall, compat) ({ (void)compat; __NR_##syscall; }) #endif /* UAPI_COMPEL_ASM_TYPES_H__ */ diff --git a/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h b/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h index fddf65d3b..8171d3395 100644 --- a/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h +++ b/compel/arch/s390/src/lib/include/uapi/asm/infect-types.h @@ -73,7 +73,7 @@ typedef struct { #define user_regs_native(pregs) true -#define __NR(syscall, compat) __NR_##syscall +#define __NR(syscall, compat) ({ (void)compat; __NR_##syscall; }) struct mmap_arg_struct { unsigned long addr; diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index f726a9895..656cc030d 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -720,7 +720,7 @@ static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size) static void parasite_memfd_close(struct parasite_ctl *ctl, int fd) { - bool __maybe_unused compat = !compel_mode_native(ctl); + bool compat = !compel_mode_native(ctl); long ret; int err; @@ -732,7 +732,7 @@ static void parasite_memfd_close(struct parasite_ctl *ctl, int fd) static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) { void *where = (void *)ctl->ictx.syscall_ip + BUILTIN_SYSCALL_SIZE; - bool __maybe_unused compat_task = !compel_mode_native(ctl); + bool compat_task = !compel_mode_native(ctl); uint8_t orig_code[MEMFD_FNAME_SZ] = MEMFD_FNAME; pid_t pid = ctl->rpid; long sret = -ENOSYS; From 71738565780552b93fad5dcd42ecfcb4e972471f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 9 Nov 2019 22:20:38 +0000 Subject: [PATCH 2224/4375] lib/infect: Check if compel succeed in executing munmap Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/arch/s390/src/lib/infect.c | 4 +++- compel/src/lib/infect.c | 10 +++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compel/arch/s390/src/lib/infect.c b/compel/arch/s390/src/lib/infect.c index 00e9c36d2..7e7d24ce2 100644 --- a/compel/arch/s390/src/lib/infect.c +++ b/compel/arch/s390/src/lib/infect.c @@ -453,8 +453,10 @@ void *remote_mmap(struct parasite_ctl *ctl, if (ptrace_poke_area(pid, &arg_struct, where, sizeof(arg_struct))) { pr_err("Can't restore mmap args (pid: %d)\n", pid); if (map != 0) { - compel_syscall(ctl, __NR_munmap, NULL, map, + err = compel_syscall(ctl, __NR_munmap, NULL, map, length, 0, 0, 0, 0); + if (err) + pr_err("Can't munmap %d\n", err); map = 0; } } diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 656cc030d..8b377e7d2 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -1303,6 +1303,7 @@ int compel_stop_daemon(struct parasite_ctl *ctl) int compel_cure_remote(struct parasite_ctl *ctl) { long ret; + int err; if (compel_stop_daemon(ctl)) return -1; @@ -1310,9 +1311,12 @@ int compel_cure_remote(struct parasite_ctl *ctl) if (!ctl->remote_map) return 0; - compel_syscall(ctl, __NR(munmap, !compel_mode_native(ctl)), &ret, - (unsigned long)ctl->remote_map, ctl->map_length, - 0, 0, 0, 0); + err = compel_syscall(ctl, __NR(munmap, !compel_mode_native(ctl)), &ret, + (unsigned long)ctl->remote_map, ctl->map_length, + 0, 0, 0, 0); + if (err) + return err; + if (ret) { pr_err("munmap for remote map %p, %lu returned %lu\n", ctl->remote_map, ctl->map_length, ret); From b5a83623b0327c19a2b9e6da28c434f28e33f7c3 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 9 Nov 2019 22:20:39 +0000 Subject: [PATCH 2225/4375] cr-dump: Try to cure remote on err-pathes On daemon stop or threads dump failures it's still desired to remove parasite from the remote (if possible). Try best and keep hopeing. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index f72373d22..56724f9a5 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1385,16 +1385,20 @@ static int dump_one_task(struct pstree_item *item, InventoryEntry *parent_ie) ret = compel_stop_daemon(parasite_ctl); if (ret) { - pr_err("Can't cure (pid: %d) from parasite\n", pid); - goto err; + pr_err("Can't stop daemon in parasite (pid: %d)\n", pid); + goto err_cure; } ret = dump_task_threads(parasite_ctl, item); if (ret) { pr_err("Can't dump threads\n"); - goto err; + goto err_cure; } + /* + * On failure local map will be cured in cr_dump_finish() + * for lazy pages. + */ if (opts.lazy_pages) ret = compel_cure_remote(parasite_ctl); else @@ -1427,7 +1431,9 @@ err: err_cure: close_cr_imgset(&cr_imgset); err_cure_imgset: - compel_cure(parasite_ctl); + ret = compel_cure(parasite_ctl); + if (ret) + pr_err("Can't cure (pid: %d) from parasite\n", pid); goto err; } From 1038a0ae44971129b3720c4351b788913e7be8f2 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 9 Nov 2019 22:20:40 +0000 Subject: [PATCH 2226/4375] cr-dump: Warn if unmapping local memfd failed Probably, not the worst that could happen, but still unexpected. Preparing the ground to make compel_cure*() functions __must_check. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 56724f9a5..4b5a01cfd 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1537,7 +1537,8 @@ static int cr_pre_dump_finish(int status) timing_stop(TIME_MEMWRITE); destroy_page_pipe(mem_pp); - compel_cure_local(ctl); + if (compel_cure_local(ctl)) + pr_err("Can't cure local: something happened with mapping?\n"); } free_pstree(root_item); @@ -1664,7 +1665,8 @@ static int cr_lazy_mem_dump(void) for_each_pstree_item(item) { if (item->pid->state != TASK_DEAD) { destroy_page_pipe(dmpi(item)->mem_pp); - compel_cure_local(dmpi(item)->parasite_ctl); + if (compel_cure_local(dmpi(item)->parasite_ctl)) + pr_err("Can't cure local: something happened with mapping?\n"); } } From abe48f8c3618113035c3e5ff76747b0342b6c7e7 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 9 Nov 2019 22:20:41 +0000 Subject: [PATCH 2227/4375] cr-restore: Warn if restorer can't be unmapped Too late to stop restore: it's already printed that restore was successful. Oh, well warn aloud about infection. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index b4530f8e5..25b820132 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1952,6 +1952,7 @@ static void finalize_restore(void) for_each_pstree_item(item) { pid_t pid = item->pid->real; struct parasite_ctl *ctl; + unsigned long restorer_addr; if (!task_alive(item)) continue; @@ -1961,7 +1962,9 @@ static void finalize_restore(void) if (ctl == NULL) continue; - compel_unmap(ctl, (unsigned long)rsti(item)->munmap_restorer); + restorer_addr = (unsigned long)rsti(item)->munmap_restorer; + if (compel_unmap(ctl, restorer_addr)) + pr_err("Failed to unmap restorer from %d\n", pid); xfree(ctl); From bd17ee85882033ead401a89e1eb21b18c7cb2afb Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 9 Nov 2019 22:20:42 +0000 Subject: [PATCH 2228/4375] parasite-syscall: Log if can't cure on failed infection Maybe expected, hopefully never happens - let's warn in any case. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/parasite-syscall.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index b9788a4c2..e5a8194e5 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -565,7 +565,8 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, parasite_ensure_args_size(aio_rings_args_size(vma_area_list)); if (compel_infect(ctl, item->nr_threads, parasite_args_size) < 0) { - compel_cure(ctl); + if (compel_cure(ctl)) + pr_warn("Can't cure failed infection\n"); return NULL; } From c21c0aea1bd11b9d5c99803a7413314e0d6a0866 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 9 Nov 2019 22:20:43 +0000 Subject: [PATCH 2229/4375] compel/infect: Detach but fail compel_resume_task() Unknown state means that the task in the end may be not in wanted state. Return err code. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/src/lib/infect.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 8b377e7d2..3fad85ed3 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -313,6 +313,8 @@ err: int compel_resume_task(pid_t pid, int orig_st, int st) { + int ret = 0; + pr_debug("\tUnseizing %d into %d\n", pid, st); if (st == COMPEL_TASK_DEAD) { @@ -335,15 +337,17 @@ int compel_resume_task(pid_t pid, int orig_st, int st) */ if (orig_st == COMPEL_TASK_STOPPED) kill(pid, SIGSTOP); - } else + } else { pr_err("Unknown final state %d\n", st); + ret = -1; + } if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) { pr_perror("Unable to detach from %d", pid); return -1; } - return 0; + return ret; } static int gen_parasite_saddr(struct sockaddr_un *saddr, int key) From 56bc4189e47c3f356c6f407544f5a88768bd4f00 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 9 Nov 2019 22:20:44 +0000 Subject: [PATCH 2230/4375] criu: Kill tasks even when the network is unlocked Currently if anything fails after network has been unlocked tasks aren't killed. Which doesn't work anyway: any stage sets `ret` and nothing later gets called. Which means the tasks aren't resumed properly. Furthermore, functions like catch_tasks() and compel_stop_on_syscall() return failure on the first error. Let's do the cleanup even when the network is unlocked. If we want to keep the mess and ignore failures - a cli option should be introduced for that (and existing code should be reworked with decisions what is critical and what can be ignored). Move "Restore finished successfully" message accordingly where everything is evidently good. While at here, any late failure will result not only in cleanup but in criu returning error code. Which in result makes tests to fail in such case: > ======================= Run zdtm/static/inotify04 in ns ======================== > Start test > ./inotify04 --pidfile=inotify04.pid --outfile=inotify04.out --dirname=inotify04.test > Run criu dump > =[log]=> dump/zdtm/static/inotify04/84/1/dump.log > ------------------------ grep Error ------------------------ > (00.119763) fsnotify: openable (inode match) as zdtm/static/inotify04.test/inotify-testfile > (00.119766) fsnotify: Dumping /zdtm/static/inotify04.test/inotify-testfile as path for handle > (00.119769) fsnotify: id 0x00000b flags 0x000800 > (00.119787) 88 fdinfo 5: pos: 0 flags: 4000/0 > (00.119796) Warn (criu/fsnotify.c:336): fsnotify: The 0x00000c inotify events will be dropped > ------------------------ ERROR OVER ------------------------ > Run criu restore > =[log]=> dump/zdtm/static/inotify04/84/1/restore.log > ------------------------ grep Error ------------------------ > (00.391582) 123 was stopped > (00.391667) 106 was trapped > (00.391674) 106 (native) is going to execute the syscall 11, required is 11 > (00.391697) 106 was stopped > (00.391720) Error (compel/src/lib/infect.c:1439): Task 123 is in unexpected state: b7f > (00.391736) Error (compel/src/lib/infect.c:1447): Task stopped with 11: Segmentation fault > ------------------------ ERROR OVER ------------------------ > 5: Old maps lost: set([]) > 5: New maps appeared: set([u'10000-1a000 rwxp', u'1a000-24000 rw-p']) > ############### Test zdtm/static/inotify04 FAIL at maps compare ################ > Send the 9 signal to 106 > Wait for zdtm/static/inotify04(106) to die for 0.100000 > ======================= Test zdtm/static/inotify04 PASS ======================== Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 50 ++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 25b820132..05a25835a 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1974,7 +1974,7 @@ static void finalize_restore(void) } } -static void finalize_restore_detach(int status) +static int finalize_restore_detach(void) { struct pstree_item *item; @@ -1988,16 +1988,21 @@ static void finalize_restore_detach(int status) for (i = 0; i < item->nr_threads; i++) { pid = item->threads[i].real; if (pid < 0) { - BUG_ON(status >= 0); - break; + pr_err("pstree item has unvalid pid %d\n", pid); + continue; } - if (arch_set_thread_regs_nosigrt(&item->threads[i])) + if (arch_set_thread_regs_nosigrt(&item->threads[i])) { pr_perror("Restoring regs for %d failed", pid); - if (ptrace(PTRACE_DETACH, pid, NULL, 0)) - pr_perror("Unable to execute %d", pid); + return -1; + } + if (ptrace(PTRACE_DETACH, pid, NULL, 0)) { + pr_perror("Unable to detach %d", pid); + return -1; + } } } + return 0; } static void ignore_kids(void) @@ -2255,32 +2260,37 @@ skip_ns_bouncing: /* * ------------------------------------------------------------- - * Below this line nothing should fail, because network is unlocked + * Network is unlocked. If something fails below - we lose data + * or a connection. */ attach_to_tasks(root_seized); - ret = restore_switch_stage(CR_STATE_RESTORE_CREDS); - BUG_ON(ret); + if (restore_switch_stage(CR_STATE_RESTORE_CREDS)) + goto out_kill_network_unlocked; timing_stop(TIME_RESTORE); - ret = catch_tasks(root_seized, &flag); + if (catch_tasks(root_seized, &flag)) { + pr_err("Can't catch all tasks\n"); + goto out_kill_network_unlocked; + } if (lazy_pages_finish_restore()) - goto out_kill; + goto out_kill_network_unlocked; - pr_info("Restore finished successfully. Resuming tasks.\n"); __restore_switch_stage(CR_STATE_COMPLETE); - if (ret == 0) - ret = compel_stop_on_syscall(task_entries->nr_threads, - __NR(rt_sigreturn, 0), __NR(rt_sigreturn, 1), flag); + ret = compel_stop_on_syscall(task_entries->nr_threads, + __NR(rt_sigreturn, 0), __NR(rt_sigreturn, 1), flag); + if (ret) { + pr_err("Can't stop all tasks on rt_sigreturn\n"); + goto out_kill_network_unlocked; + } if (clear_breakpoints()) pr_err("Unable to flush breakpoints\n"); - if (ret == 0) - finalize_restore(); + finalize_restore(); ret = run_scripts(ACT_PRE_RESUME); if (ret) @@ -2292,8 +2302,10 @@ skip_ns_bouncing: fini_cgroup(); /* Detaches from processes and they continue run through sigreturn. */ - finalize_restore_detach(ret); + if (finalize_restore_detach()) + goto out_kill_network_unlocked; + pr_info("Restore finished successfully. Tasks resumed.\n"); write_stats(RESTORE_STATS); ret = run_scripts(ACT_POST_RESUME); @@ -2305,6 +2317,8 @@ skip_ns_bouncing: return 0; +out_kill_network_unlocked: + pr_err("Killing processes because of failure on restore.\nThe Network was unlocked so some data or a connection may have been lost.\n"); out_kill: /* * The processes can be killed only when all of them have been created, From 1c0716924bbc1128c478388b70904438a5934e73 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sat, 9 Nov 2019 22:20:45 +0000 Subject: [PATCH 2231/4375] compel/criu: Add __must_check All those compel functions can fail by various reasons. It may be status of the system, interruption by user or anything else. It's really desired to handle as many PIE related errors as possible otherwise it's hard to analyze statuses of parasite/restorer and the C/R process. At least warning for logs should be produced or even C/R stopped. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- compel/include/uapi/cpu.h | 2 +- compel/include/uapi/infect-rpc.h | 6 ++-- compel/include/uapi/infect-util.h | 5 ++- compel/include/uapi/infect.h | 39 +++++++++++++----------- compel/include/uapi/ptrace.h | 7 +++-- compel/include/uapi/sigframe-common.h | 5 +-- compel/plugins/include/uapi/plugin-fds.h | 2 +- compel/plugins/include/uapi/std/infect.h | 8 +++-- compel/plugins/include/uapi/std/log.h | 1 + criu/seize.c | 2 +- include/common/compiler.h | 27 ++++++++++++++++ 11 files changed, 71 insertions(+), 33 deletions(-) diff --git a/compel/include/uapi/cpu.h b/compel/include/uapi/cpu.h index 6f827d447..72c8a516c 100644 --- a/compel/include/uapi/cpu.h +++ b/compel/include/uapi/cpu.h @@ -6,7 +6,7 @@ #include -extern int compel_cpuid(compel_cpuinfo_t *info); +extern int /* TODO: __must_check */ compel_cpuid(compel_cpuinfo_t *info); extern bool compel_cpu_has_feature(unsigned int feature); extern bool compel_fpu_has_feature(unsigned int feature); extern uint32_t compel_fpu_feature_size(unsigned int feature); diff --git a/compel/include/uapi/infect-rpc.h b/compel/include/uapi/infect-rpc.h index 0176c1142..180dedf1f 100644 --- a/compel/include/uapi/infect-rpc.h +++ b/compel/include/uapi/infect-rpc.h @@ -6,9 +6,9 @@ #include struct parasite_ctl; -extern int compel_rpc_sync(unsigned int cmd, struct parasite_ctl *ctl); -extern int compel_rpc_call(unsigned int cmd, struct parasite_ctl *ctl); -extern int compel_rpc_call_sync(unsigned int cmd, struct parasite_ctl *ctl); +extern int __must_check compel_rpc_sync(unsigned int cmd, struct parasite_ctl *ctl); +extern int __must_check compel_rpc_call(unsigned int cmd, struct parasite_ctl *ctl); +extern int __must_check compel_rpc_call_sync(unsigned int cmd, struct parasite_ctl *ctl); extern int compel_rpc_sock(struct parasite_ctl *ctl); #define PARASITE_USER_CMDS 64 diff --git a/compel/include/uapi/infect-util.h b/compel/include/uapi/infect-util.h index 7307ba57a..4e32d13dc 100644 --- a/compel/include/uapi/infect-util.h +++ b/compel/include/uapi/infect-util.h @@ -1,6 +1,9 @@ #ifndef __COMPEL_INFECT_UTIL_H__ #define __COMPEL_INFECT_UTIL_H__ + +#include "common/compiler.h" + struct parasite_ctl; -extern int compel_util_send_fd(struct parasite_ctl *ctl, int fd); +extern int __must_check compel_util_send_fd(struct parasite_ctl *ctl, int fd); extern int compel_util_recv_fd(struct parasite_ctl *ctl, int *pfd); #endif diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 08beaffcd..dd672bc1c 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -13,7 +13,7 @@ #define PARASITE_START_AREA_MIN (4096) -extern int compel_interrupt_task(int pid); +extern int __must_check compel_interrupt_task(int pid); struct seize_task_status { unsigned long long sigpnd; @@ -23,27 +23,28 @@ struct seize_task_status { int seccomp_mode; }; -extern int compel_wait_task(int pid, int ppid, +extern int __must_check compel_wait_task(int pid, int ppid, int (*get_status)(int pid, struct seize_task_status *, void *data), void (*free_status)(int pid, struct seize_task_status *, void *data), struct seize_task_status *st, void *data); -extern int compel_stop_task(int pid); +extern int __must_check compel_stop_task(int pid); extern int compel_resume_task(pid_t pid, int orig_state, int state); struct parasite_ctl; struct parasite_thread_ctl; -extern struct parasite_ctl *compel_prepare(int pid); -extern struct parasite_ctl *compel_prepare_noctx(int pid); -extern int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size); -extern struct parasite_thread_ctl *compel_prepare_thread(struct parasite_ctl *ctl, int pid); +extern struct parasite_ctl __must_check *compel_prepare(int pid); +extern struct parasite_ctl __must_check *compel_prepare_noctx(int pid); +extern int __must_check compel_infect(struct parasite_ctl *ctl, + unsigned long nr_threads, unsigned long args_size); +extern struct parasite_thread_ctl __must_check *compel_prepare_thread(struct parasite_ctl *ctl, int pid); extern void compel_release_thread(struct parasite_thread_ctl *); -extern int compel_stop_daemon(struct parasite_ctl *ctl); -extern int compel_cure_remote(struct parasite_ctl *ctl); -extern int compel_cure_local(struct parasite_ctl *ctl); -extern int compel_cure(struct parasite_ctl *ctl); +extern int __must_check compel_stop_daemon(struct parasite_ctl *ctl); +extern int __must_check compel_cure_remote(struct parasite_ctl *ctl); +extern int __must_check compel_cure_local(struct parasite_ctl *ctl); +extern int __must_check compel_cure(struct parasite_ctl *ctl); #define PARASITE_ARG_SIZE_MIN ( 1 << 12) @@ -58,15 +59,16 @@ extern int compel_cure(struct parasite_ctl *ctl); extern void *compel_parasite_args_p(struct parasite_ctl *ctl); extern void *compel_parasite_args_s(struct parasite_ctl *ctl, unsigned long args_size); -extern int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, +extern int __must_check compel_syscall(struct parasite_ctl *ctl, + int nr, long *ret, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6); -extern int compel_run_in_thread(struct parasite_thread_ctl *tctl, unsigned int cmd); -extern int compel_run_at(struct parasite_ctl *ctl, unsigned long ip, user_regs_struct_t *ret_regs); +extern int __must_check compel_run_in_thread(struct parasite_thread_ctl *tctl, unsigned int cmd); +extern int __must_check compel_run_at(struct parasite_ctl *ctl, unsigned long ip, user_regs_struct_t *ret_regs); /* * The PTRACE_SYSCALL will trap task twice -- on @@ -80,12 +82,13 @@ enum trace_flags { TRACE_EXIT, }; -extern int compel_stop_on_syscall(int tasks, int sys_nr, +extern int __must_check compel_stop_on_syscall(int tasks, int sys_nr, int sys_nr_compat, enum trace_flags trace); -extern int compel_stop_pie(pid_t pid, void *addr, enum trace_flags *tf, bool no_bp); +extern int __must_check compel_stop_pie(pid_t pid, void *addr, + enum trace_flags *tf, bool no_bp); -extern int compel_unmap(struct parasite_ctl *ctl, unsigned long addr); +extern int __must_check compel_unmap(struct parasite_ctl *ctl, unsigned long addr); extern int compel_mode_native(struct parasite_ctl *ctl); @@ -159,7 +162,7 @@ struct parasite_blob_desc { extern struct parasite_blob_desc *compel_parasite_blob_desc(struct parasite_ctl *); -extern int compel_get_thread_regs(struct parasite_thread_ctl *, save_regs_t, void *); +extern int __must_check compel_get_thread_regs(struct parasite_thread_ctl *, save_regs_t, void *); extern void compel_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *elf_relocs, size_t nr_relocs); diff --git a/compel/include/uapi/ptrace.h b/compel/include/uapi/ptrace.h index 4df00b6e1..13eed7232 100644 --- a/compel/include/uapi/ptrace.h +++ b/compel/include/uapi/ptrace.h @@ -1,6 +1,7 @@ #ifndef UAPI_COMPEL_PTRACE_H__ #define UAPI_COMPEL_PTRACE_H__ +#include "common/compiler.h" /* * We'd want to include both sys/ptrace.h and linux/ptrace.h, * hoping that most definitions come from either one or another. @@ -75,8 +76,8 @@ typedef struct { extern int ptrace_suspend_seccomp(pid_t pid); -extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes); -extern int ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes); -extern int ptrace_swap_area(pid_t pid, void *dst, void *src, long bytes); +extern int __must_check ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes); +extern int __must_check ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes); +extern int __must_check ptrace_swap_area(pid_t pid, void *dst, void *src, long bytes); #endif /* UAPI_COMPEL_PTRACE_H__ */ diff --git a/compel/include/uapi/sigframe-common.h b/compel/include/uapi/sigframe-common.h index fc93c5480..177bf4c48 100644 --- a/compel/include/uapi/sigframe-common.h +++ b/compel/include/uapi/sigframe-common.h @@ -8,6 +8,7 @@ # error "Direct inclusion is forbidden, use instead" #endif +#include "common/compiler.h" #include #include @@ -56,7 +57,7 @@ struct rt_ucontext { unsigned long uc_regspace[128] __attribute__((aligned(8))); }; -extern int sigreturn_prep_fpu_frame(struct rt_sigframe *frame, - struct rt_sigframe *rframe); +extern int __must_check sigreturn_prep_fpu_frame(struct rt_sigframe *frame, + struct rt_sigframe *rframe); #endif /* UAPI_COMPEL_SIGFRAME_COMMON_H__ */ diff --git a/compel/plugins/include/uapi/plugin-fds.h b/compel/plugins/include/uapi/plugin-fds.h index cececb21d..e995b4b66 100644 --- a/compel/plugins/include/uapi/plugin-fds.h +++ b/compel/plugins/include/uapi/plugin-fds.h @@ -1,7 +1,7 @@ #ifndef COMPEL_PLUGIN_STD_STD_H__ #define COMPEL_PLUGIN_STD_STD_H__ -extern int fds_send_fd(int fd); +extern int __must_check fds_send_fd(int fd); extern int fds_recv_fd(void); #endif /* COMPEL_PLUGIN_STD_STD_H__ */ diff --git a/compel/plugins/include/uapi/std/infect.h b/compel/plugins/include/uapi/std/infect.h index 800df2509..1e784f8b4 100644 --- a/compel/plugins/include/uapi/std/infect.h +++ b/compel/plugins/include/uapi/std/infect.h @@ -1,14 +1,16 @@ #ifndef COMPEL_PLUGIN_STD_INFECT_H__ #define COMPEL_PLUGIN_STD_INFECT_H__ +#include "common/compiler.h" + extern int parasite_get_rpc_sock(void); -extern int parasite_service(unsigned int cmd, void *args); +extern int __must_check parasite_service(unsigned int cmd, void *args); /* * Must be supplied by user plugins. */ -extern int parasite_daemon_cmd(int cmd, void *args); -extern int parasite_trap_cmd(int cmd, void *args); +extern int __must_check parasite_daemon_cmd(int cmd, void *args); +extern int __must_check parasite_trap_cmd(int cmd, void *args); extern void parasite_cleanup(void); /* diff --git a/compel/plugins/include/uapi/std/log.h b/compel/plugins/include/uapi/std/log.h index f21b6df0d..91462c85b 100644 --- a/compel/plugins/include/uapi/std/log.h +++ b/compel/plugins/include/uapi/std/log.h @@ -2,6 +2,7 @@ #define COMPEL_PLUGIN_STD_LOG_H__ #include "compel/loglevels.h" +#include "common/compiler.h" #define STD_LOG_SIMPLE_CHUNK 256 diff --git a/criu/seize.c b/criu/seize.c index cce8911b9..e1e6b8195 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -483,7 +483,7 @@ static int collect_children(struct pstree_item *item) if (!opts.freeze_cgroup) /* fails when meets a zombie */ - compel_interrupt_task(pid); + __ignore_value(compel_interrupt_task(pid)); ret = compel_wait_task(pid, item->pid->real, parse_pid_status, NULL, &creds.s, NULL); if (ret < 0) { diff --git a/include/common/compiler.h b/include/common/compiler.h index fc8abcfef..1d431a529 100644 --- a/include/common/compiler.h +++ b/include/common/compiler.h @@ -22,6 +22,7 @@ #define __used __attribute__((__used__)) #define __maybe_unused __attribute__((unused)) #define __always_unused __attribute__((unused)) +#define __must_check __attribute__((__warn_unused_result__)) #define __section(S) __attribute__ ((__section__(#S))) @@ -99,4 +100,30 @@ #define is_log2(v) (((v) & ((v) - 1)) == 0) +/* + * Use "__ignore_value" to avoid a warning when using a function declared with + * gcc's warn_unused_result attribute, but for which you really do want to + * ignore the result. Traditionally, people have used a "(void)" cast to + * indicate that a function's return value is deliberately unused. However, + * if the function is declared with __attribute__((warn_unused_result)), + * gcc issues a warning even with the cast. + * + * Caution: most of the time, you really should heed gcc's warning, and + * check the return value. However, in those exceptional cases in which + * you're sure you know what you're doing, use this function. + * + * Normally casting an expression to void discards its value, but GCC + * versions 3.4 and newer have __attribute__ ((__warn_unused_result__)) + * which may cause unwanted diagnostics in that case. Use __typeof__ + * and __extension__ to work around the problem, if the workaround is + * known to be needed. + * Written by Jim Meyering, Eric Blake and Pádraig Brady. + * (See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 for the details) + */ +#if 3 < __GNUC__ + (4 <= __GNUC_MINOR__) +# define __ignore_value(x) ({ __typeof__ (x) __x = (x); (void) __x; }) +#else +# define __ignore_value(x) ((void) (x)) +#endif + #endif /* __CR_COMPILER_H__ */ From dc4677123ba03f93deab2d1ec6047d3a35ba694c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20C=C5=82api=C5=84ski?= Date: Wed, 6 Nov 2019 02:15:20 +0100 Subject: [PATCH 2232/4375] Checkpoint only specified controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this change CRIU would checkpoint all controllers, even the ones not specified in --cgroup-dump-controller. That becomes a problem if there's a cgroup controller on the checkpointing machine that doesn't exist on the restoring machine even if CRIU is instructed not to dump that controller. After that change everything works as expected. Signed-off-by: Michał Cłapiński --- criu/proc_parse.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/criu/proc_parse.c b/criu/proc_parse.c index d67392a12..fa7644992 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -2498,6 +2498,12 @@ int collect_controllers(struct list_head *cgroups, unsigned int *n_cgroups) goto err; } *off = '\0'; + + if (cgp_should_skip_controller(controllers)) { + pr_debug("cg-prop: Skipping controller %s\n", controllers); + continue; + } + while (1) { off = strchr(controllers, ','); if (off) From 8f45330d168df043c400593f2387a92e2b686ef8 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 17 Nov 2019 16:04:16 +0200 Subject: [PATCH 2233/4375] travis: group lazy-pages options The amount of lazy-pages options keeps growing, let's put the common ones into a variable. Signed-off-by: Mike Rapoport --- scripts/travis/travis-tests | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index bc97fd455..a87ddbaf4 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -146,10 +146,11 @@ fi LAZY_EXCLUDE="$LAZY_EXCLUDE -x maps04" LAZY_TESTS=.*\(maps0\|uffd-events\|lazy-thp\|futex\|fork\).* +LAZY_OPTS="-p 2 -T $LAZY_TESTS $LAZY_EXCLUDE $ZDTM_OPTS" -./test/zdtm.py run -p 2 -T $LAZY_TESTS --lazy-pages $LAZY_EXCLUDE $ZDTM_OPTS -./test/zdtm.py run -p 2 -T $LAZY_TESTS --remote-lazy-pages $LAZY_EXCLUDE $ZDTM_OPTS -./test/zdtm.py run -p 2 -T $LAZY_TESTS --remote-lazy-pages --tls $LAZY_EXCLUDE $ZDTM_OPTS +./test/zdtm.py run $LAZY_OPTS --lazy-pages +./test/zdtm.py run $LAZY_OPTS --remote-lazy-pages +./test/zdtm.py run $LAZY_OPTS --remote-lazy-pages --tls bash ./test/jenkins/criu-fault.sh bash ./test/jenkins/criu-fcg.sh From 75fcec0ecbccea5b8258def25adb056e4d02c0c1 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 17 Nov 2019 16:05:47 +0200 Subject: [PATCH 2234/4375] travis: exclude uns tests for lazy-pages on newer kernels Kernels 5.4 and higher will restrict availability of UFFD_EVENT_FORK only for users with SYS_CAP_PTRACE. This prevents running --lazy-pages tests with 'uns' flavor. Disable 'uns' for lazy pages testing in travis for newer kernels. Signed-off-by: Mike Rapoport --- scripts/travis/travis-tests | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index a87ddbaf4..4cb842c97 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -145,8 +145,15 @@ else fi LAZY_EXCLUDE="$LAZY_EXCLUDE -x maps04" +# Starting with 5.4 kernel requires SYS_CAP_PTRACE to use uffd events; as such +# we cannot run lazy-pages tests in uns +LAZY_FLAVORS="" +if [ $KERN_MAJ -ge "5" ] && [ $KERN_MIN -ge "4" ]; then + LAZY_FLAVORS = "-f h,ns" +fi + LAZY_TESTS=.*\(maps0\|uffd-events\|lazy-thp\|futex\|fork\).* -LAZY_OPTS="-p 2 -T $LAZY_TESTS $LAZY_EXCLUDE $ZDTM_OPTS" +LAZY_OPTS="-p 2 -T $LAZY_TESTS $LAZY_EXCLUDE $LAZY_FLAVORS $ZDTM_OPTS" ./test/zdtm.py run $LAZY_OPTS --lazy-pages ./test/zdtm.py run $LAZY_OPTS --remote-lazy-pages From b50b6ea09e7a80b91f2bdeb0b5cd444b0ae800ca Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 3 Nov 2019 20:18:38 +0000 Subject: [PATCH 2235/4375] mount: Add error messages Suggested-by: Andrei Vagin Signed-off-by: Radostin Stoyanov --- criu/mount.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 974af6eb2..6b1adecc6 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1325,8 +1325,10 @@ int ns_open_mountpoint(void *arg) } /* Remount all mounts as private to disable propagation */ - if (mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)) + if (mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)) { + pr_perror("Unable to remount"); goto err; + } if (umount_overmounts(mi)) goto err; @@ -1536,6 +1538,7 @@ static __maybe_unused int mount_cr_time_mount(struct ns_id *ns, unsigned int *s_ ret = mount(source, target, type, 0, NULL); if (ret < 0) { + pr_perror("Unable to mount %s %s", source, target); exit_code = -errno; goto restore_ns; } else { @@ -2004,7 +2007,10 @@ static int fetch_rt_stat(struct mount_info *m, const char *where) static int do_simple_mount(struct mount_info *mi, const char *src, const char *fstype, unsigned long mountflags) { - return mount(src, mi->mountpoint, fstype, mountflags, mi->options); + int ret = mount(src, mi->mountpoint, fstype, mountflags, mi->options); + if (ret) + pr_perror("Unable to mount %s %s (id=%d)", src, mi->mountpoint, mi->mnt_id); + return ret; } static char *mnt_fsname(struct mount_info *mi) @@ -2491,8 +2497,11 @@ static int do_mount_one(struct mount_info *mi) } /* do_mount_root() is called from populate_mnt_ns() */ - if (mount(opts.root, mi->mountpoint, NULL, MS_BIND | MS_REC, NULL)) + if (mount(opts.root, mi->mountpoint, NULL, MS_BIND | MS_REC, NULL)) { + pr_perror("Unable to mount %s %s (id=%d)", opts.root, mi->mountpoint, mi->mnt_id); return -1; + } + if (do_mount_root(mi)) return -1; mi->mounted = true; From d99ee9753e90df1040dc49341a38357e58d838ee Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sat, 9 Nov 2019 22:48:32 +0000 Subject: [PATCH 2236/4375] mount: Bind-mount root via userns_call When restoring a runc container with enabled user namespace CRIU fails to mount the specified root directory because the path is under /run/runc which is inaccessible to unprivileged users. Signed-off-by: Radostin Stoyanov --- criu/mount.c | 51 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 6b1adecc6..52e70d376 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2020,20 +2020,20 @@ static char *mnt_fsname(struct mount_info *mi) return mi->fstype->name; } -static int apply_sb_flags(void *args, int fd, pid_t pid) +static int userns_mount(char *src, void *args, int fd, pid_t pid) { unsigned long flags = *(unsigned long *) args; int rst = -1, err = -1; - char path[PSFDS]; + char target[PSFDS]; - snprintf(path, sizeof(path), "/proc/self/fd/%d", fd); + snprintf(target, sizeof(target), "/proc/self/fd/%d", fd); if (pid != getpid() && switch_ns(pid, &mnt_ns_desc, &rst)) return -1; - err = mount(NULL, path, NULL, MS_REMOUNT | flags, NULL); + err = mount(src, target, NULL, flags, NULL); if (err) - pr_perror("Unable to remount %s", path); + pr_perror("Unable to mount %s", target); if (rst >= 0 && restore_ns(rst, &mnt_ns_desc)) return -1; @@ -2041,6 +2041,16 @@ static int apply_sb_flags(void *args, int fd, pid_t pid) return err; } +static int apply_sb_flags(void *args, int fd, pid_t pid) +{ + return userns_mount(NULL, args, fd, pid); +} + +static int mount_root(void *args, int fd, pid_t pid) +{ + return userns_mount(opts.root, args, fd, pid); +} + static int do_new_mount(struct mount_info *mi) { unsigned long sflags = mi->sb_flags; @@ -2088,10 +2098,9 @@ static int do_new_mount(struct mount_info *mi) pr_perror("Unable to open %s", mi->mountpoint); return -1; } - sflags |= MS_RDONLY; - if (userns_call(apply_sb_flags, 0, - &sflags, sizeof(sflags), fd)) { - pr_perror("Unable to apply mount flags %d for %s", + sflags |= MS_RDONLY | MS_REMOUNT; + if (userns_call(apply_sb_flags, 0, &sflags, sizeof(sflags), fd)) { + pr_err("Unable to apply mount flags %d for %s", mi->sb_flags, mi->mountpoint); close(fd); return -1; @@ -2491,15 +2500,33 @@ static int do_mount_one(struct mount_info *mi) pr_debug("\tMounting %s @%s (%d)\n", mi->fstype->name, mi->mountpoint, mi->need_plugin); if (rst_mnt_is_root(mi)) { + int fd; + unsigned long flags = MS_BIND | MS_REC; + if (opts.root == NULL) { pr_err("The --root option is required to restore a mount namespace\n"); return -1; } /* do_mount_root() is called from populate_mnt_ns() */ - if (mount(opts.root, mi->mountpoint, NULL, MS_BIND | MS_REC, NULL)) { - pr_perror("Unable to mount %s %s (id=%d)", opts.root, mi->mountpoint, mi->mnt_id); - return -1; + if (root_ns_mask & CLONE_NEWUSER) { + fd = open(mi->mountpoint, O_PATH); + if (fd < 0) { + pr_perror("Unable to open %s", mi->mountpoint); + return -1; + } + + if (userns_call(mount_root, 0, &flags, sizeof(flags), fd)) { + pr_err("Unable to mount %s\n", mi->mountpoint); + close(fd); + return -1; + } + close(fd); + } else { + if (mount(opts.root, mi->mountpoint, NULL, flags, NULL)) { + pr_perror("Unable to mount %s %s (id=%d)", opts.root, mi->mountpoint, mi->mnt_id); + return -1; + } } if (do_mount_root(mi)) From 8ab3e40e3e45a4e0337c6715c923fb640e2e8973 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 10 Nov 2019 07:35:50 +0000 Subject: [PATCH 2237/4375] restore: Create temp proc in /tmp When restoring a container with user namespace, CRIU fails to create a temporary directory for proc. The is because the unprivileged user that has been just restored does not have permissions to access the working directory used by CRIU. Resolves #828 Signed-off-by: Radostin Stoyanov --- criu/cr-restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 05a25835a..5694931f4 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1588,7 +1588,7 @@ static void restore_pgid(void) static int mount_proc(void) { int fd, ret; - char proc_mountpoint[] = "crtools-proc.XXXXXX"; + char proc_mountpoint[] = "/tmp/crtools-proc.XXXXXX"; if (root_ns_mask == 0) fd = ret = open("/proc", O_DIRECTORY); From 9a50fbce72228404c29642af70af7b42fbc60a7b Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 3 Nov 2019 20:35:18 +0000 Subject: [PATCH 2238/4375] man: Describe --root option requirements These requirements have been described in https://github.com/opencontainers/runc/blob/b133feae/libcontainer/container_linux.go#L1265 Signed-off-by: Radostin Stoyanov --- Documentation/criu.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 2729bc95a..133a094c0 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -414,6 +414,8 @@ usually need to be escaped from shell. *-r*, *--root* 'path':: Change the root filesystem to 'path' (when run in a mount namespace). + This option is required to restore a mount namespace. The directory + 'path' must be a mount point and its parent must not be overmounted. *--external* 'type'*[*'id'*]:*'value':: Restore an instance of an external resource. The generic syntax is From 90cbeadb668d99f9d9557cee7a4c67e593f6e7ad Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 19 Nov 2019 22:10:39 +0000 Subject: [PATCH 2239/4375] zdtm: Replace if->continue with if->elif->else Replacing the if->continue pattern with if->elif->else reduces the number of lines while preserving the logic. Signed-off-by: Radostin Stoyanov --- test/zdtm.py | 63 ++++++++++++++++++---------------------------------- 1 file changed, 22 insertions(+), 41 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 6d3fddfad..17e0540eb 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -867,76 +867,57 @@ class criu_rpc: def __set_opts(criu, args, ctx): while len(args) != 0: arg = args.pop(0) - if arg == '-v4': + if "-v4" == arg: criu.opts.log_level = 4 - continue - if arg == '-o': + elif "-o" == arg: criu.opts.log_file = args.pop(0) - continue - if arg == '-D': + elif "-D" == arg: criu.opts.images_dir_fd = os.open(args.pop(0), os.O_DIRECTORY) ctx['imgd'] = criu.opts.images_dir_fd - continue - if arg == '-t': + elif "-t" == arg: criu.opts.pid = int(args.pop(0)) - continue - if arg == '--pidfile': + elif "--pidfile" == arg: ctx['pidf'] = args.pop(0) - continue - if arg == '--timeout': + elif "--timeout" == arg: criu.opts.timeout = int(args.pop(0)) - continue - if arg == '--restore-detached': - # Set by service by default - ctx['rd'] = True - continue - if arg == '--root': + elif "--restore-detached" == arg: + ctx['rd'] = True # Set by service by default + elif "--root" == arg: criu.opts.root = args.pop(0) - continue - if arg == '--external': + elif "--external" == arg: criu.opts.external.append(args.pop(0)) - continue - if arg == '--status-fd': + elif "--status-fd" == arg: fd = int(args.pop(0)) os.write(fd, b"\0") fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC) - continue - if arg == '--port': + elif "--port" == arg: criu.opts.ps.port = int(args.pop(0)) - continue - if arg == '--address': + elif "--address" == arg: criu.opts.ps.address = args.pop(0) + elif "--page-server" == arg: continue - if arg == '--page-server': - continue - if arg == '--prev-images-dir': + elif "--prev-images-dir" == arg: criu.opts.parent_img = args.pop(0) - continue - if arg == '--pre-dump-mode': + elif "--pre-dump-mode" == arg: key = args.pop(0) mode = crpc.rpc.VM_READ if key == "splice": mode = crpc.rpc.SPLICE criu.opts.pre_dump_mode = mode - continue - if arg == '--track-mem': + elif "--track-mem" == arg: criu.opts.track_mem = True - continue - if arg == '--tcp-established': + elif "--tcp-established" == arg: criu.opts.tcp_established = True - continue - if arg == '--restore-sibling': + elif "--restore-sibling" == arg: criu.opts.rst_sibling = True - continue - if arg == "--inherit-fd": + elif "--inherit-fd" == arg: inhfd = criu.opts.inherit_fd.add() key = args.pop(0) fd, key = key.split(":", 1) inhfd.fd = int(fd[3:-1]) inhfd.key = key - continue - - raise test_fail_exc('RPC for %s(%s) required' % (arg, args.pop(0))) + else: + raise test_fail_exc('RPC for %s(%s) required' % (arg, args.pop(0))) @staticmethod def run(action, From 60bb5c731078ad15b3d9e62782d692d91c5c2db0 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 19 Nov 2019 22:48:44 +0000 Subject: [PATCH 2240/4375] zdtm: Set --root path to 0700 on restore Update zdtm tests to verify that CRIU does not require the --root path to be accessible to the unprivileged user being restored when restoring user namespace. Signed-off-by: Radostin Stoyanov --- test/zdtm.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 17e0540eb..16ff0b379 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -62,6 +62,7 @@ tests_root = None def clean_tests_root(): global tests_root if tests_root and tests_root[0] == os.getpid(): + os.rmdir(os.path.join(tests_root[1], "root")) os.rmdir(tests_root[1]) @@ -70,7 +71,9 @@ def make_tests_root(): if not tests_root: tests_root = (os.getpid(), tempfile.mkdtemp("", "criu-root-", "/tmp")) atexit.register(clean_tests_root) - return tests_root[1] + os.mkdir(os.path.join(tests_root[1], "root")) + os.chmod(tests_root[1], 0o777) + return os.path.join(tests_root[1], "root") # Report generation @@ -483,6 +486,13 @@ class zdtm_test: # move into some semi-random state time.sleep(random.random()) + if self.__flavor.ns: + # In the case of runc the path specified with the opts.root + # option is created in /run/runc/ which is inaccessible to + # unprivileged users. The permissions here are set to test + # this use case. + os.chmod(os.path.dirname(self.__flavor.root), 0o700) + def kill(self, sig=signal.SIGKILL): self.__freezer.thaw() if self.__pid: From 25f6d4f72fb995cb776d65a9d4d539d4fdcc6740 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 21 Nov 2019 21:56:34 +0000 Subject: [PATCH 2241/4375] build: Remove SRCARCH SRCARCH is always equal ARCH. There are no rules when to use one or another and architectures may forget to set one of them up. No need for a second variable meaning the same and confusing people. Remove it completely. Self-correction [after some debug]: SRCARCH was different in one place: zdtm Makefile by some unintentional mistake: > ifeq ($(ARCH),arm64) > ARCH ?= aarch64 > SRCARCH ?= aarch64 > endif That meant to be "ARCH := aarch64" because "?=" would never work inside that ifeq. Fix up this part of mess too. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 3 +-- Makefile.config | 2 +- compel/plugins/Makefile | 4 ++-- criu/Makefile | 2 +- criu/pie/Makefile | 6 +++--- criu/pie/Makefile.library | 4 ++-- test/zdtm/Makefile.inc | 7 ++----- test/zdtm/static/Makefile | 4 ++-- 8 files changed, 14 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index f827e7baa..2e62f6f39 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,6 @@ endif # commit "S/390: Fix 64 bit sibcall". ifeq ($(ARCH),s390) ARCH := s390 - SRCARCH := s390 DEFINES := -DCONFIG_S390 CFLAGS_PIE := -fno-optimize-sibling-calls endif @@ -94,7 +93,7 @@ endif CFLAGS_PIE += -DCR_NOGLIBC export CFLAGS_PIE -LDARCH ?= $(SRCARCH) +LDARCH ?= $(ARCH) export LDARCH export PROTOUFIX DEFINES diff --git a/Makefile.config b/Makefile.config index 1e4352b9d..5af3fed38 100644 --- a/Makefile.config +++ b/Makefile.config @@ -30,7 +30,7 @@ CONFIG_FILE = .config $(CONFIG_FILE): touch $(CONFIG_FILE) -ifeq ($(SRCARCH),x86) +ifeq ($(ARCH),x86) # CONFIG_COMPAT is only for x86 now, no need for compile-test other archs ifeq ($(call try-asm,$(FEATURE_TEST_X86_COMPAT)),true) export CONFIG_COMPAT := y diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index a326e2a66..197ff1b24 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -53,11 +53,11 @@ std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/parasite-head.o target += fds fds-lib-y += fds/fds.o -ifeq ($(SRCARCH),x86) +ifeq ($(ARCH),x86) std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/memcpy.o endif -ifeq ($(SRCARCH),ppc64) +ifeq ($(ARCH),ppc64) std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/memcpy.o std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/memcmp.o endif diff --git a/criu/Makefile b/criu/Makefile index 4134e5052..ceb49ce09 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -2,7 +2,7 @@ # 6a8d90f5fec4 "attr: Allow attribute type 0" WRAPFLAGS += -Wl,--wrap=nla_parse,--wrap=nlmsg_parse -ARCH_DIR := criu/arch/$(SRCARCH) +ARCH_DIR := criu/arch/$(ARCH) PIE_DIR := criu/pie export ARCH_DIR PIE_DIR diff --git a/criu/pie/Makefile b/criu/pie/Makefile index 1ad456f43..a30747ac3 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -14,7 +14,7 @@ ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) compel_plugins := $(shell $(COMPEL_BIN) plugins) endif -LDS := compel/arch/$(SRCARCH)/scripts/compel-pack.lds.S +LDS := compel/arch/$(ARCH)/scripts/compel-pack.lds.S restorer-obj-y += parasite-vdso.o ./$(ARCH_DIR)/vdso-pie.o restorer-obj-y += ./$(ARCH_DIR)/restorer.o @@ -26,11 +26,11 @@ ifeq ($(ARCH),x86) endif endif -ifeq ($(SRCARCH),aarch64) +ifeq ($(ARCH),aarch64) restorer-obj-y += ./$(ARCH_DIR)/intraprocedure.o endif -ifeq ($(SRCARCH),ppc64) +ifeq ($(ARCH),ppc64) restorer-obj-y += ./$(ARCH_DIR)/vdso-trampoline.o endif diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index 658c8a4eb..de75b11d4 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -9,14 +9,14 @@ lib-name := pie.lib.a lib-y += util.o lib-y += util-vdso.o -ifeq ($(SRCARCH),x86) +ifeq ($(ARCH),x86) ifeq ($(CONFIG_COMPAT),y) lib-y += util-vdso-elf32.o endif CFLAGS_util-vdso-elf32.o += -DCONFIG_VDSO_32 endif -ifeq ($(SRCARCH),arm) +ifeq ($(ARCH),arm) lib-y += ./$(ARCH_DIR)/aeabi-helpers.o lib-y += ./$(ARCH_DIR)/pie-cacheflush.o endif diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index 170f31632..d5c013a3e 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -15,12 +15,9 @@ ARCH ?= $(shell uname -m | sed \ -e s/aarch64.*/arm64/) ifeq ($(ARCH),arm64) - ARCH ?= aarch64 - SRCARCH ?= aarch64 + ARCH := aarch64 endif -SRCARCH ?= $(ARCH) - ifeq ($(ARCH),arm) ARMV := $(shell echo $(UNAME-M) | sed -nr 's/armv([[:digit:]]).*/\1/p; t; i7') @@ -35,7 +32,7 @@ CC := gcc CFLAGS += -g -O2 -Wall -Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS += $(USERCFLAGS) CFLAGS += -D_GNU_SOURCE -CPPFLAGS += -iquote $(LIBDIR)/arch/$(SRCARCH)/include +CPPFLAGS += -iquote $(LIBDIR)/arch/$(ARCH)/include ifeq ($(strip $(V)),) E = @echo diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index a38482f44..e0d4d2c5c 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -219,13 +219,13 @@ TST_NOFILE := \ child_subreaper_and_reparent \ # jobctl00 \ -ifneq ($(SRCARCH),arm) +ifneq ($(ARCH),arm) ifneq ($(COMPAT_TEST),y) TST_NOFILE += maps03 endif endif -ifeq ($(SRCARCH),s390) +ifeq ($(ARCH),s390) TST_NOFILE += s390x_regs_check \ s390x_gs_threads \ s390x_runtime_instr From a4fa4162d410c0bbc751d92119022f9a1c3a6723 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 21 Nov 2019 21:56:35 +0000 Subject: [PATCH 2242/4375] build/nmk: Remove SRCARCH It's not used anywhere now. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/include.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/nmk/scripts/include.mk b/scripts/nmk/scripts/include.mk index e1701103f..ee0e32f62 100644 --- a/scripts/nmk/scripts/include.mk +++ b/scripts/nmk/scripts/include.mk @@ -22,9 +22,8 @@ SUBARCH := $(shell uname -m | sed \ -e s/aarch64.*/aarch64/) ARCH ?= $(SUBARCH) -SRCARCH := $(ARCH) -export SUBARCH ARCH SRCARCH +export SUBARCH ARCH ifndef ____nmk_defined__tools include $(__nmk_dir)tools.mk From df66aa99b6ce59108055759d5ebda69e2fd00669 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 21 Nov 2019 21:56:36 +0000 Subject: [PATCH 2243/4375] build/nmk: Provide proper SUBARCH It's always equal ARCH and not very useful (so nothing actually uses it). Time for a change: SUBARCH now is meaningful and gives a way to detect what kind of ARCH flavor build is dealing with. Also, for cross-compiling sake don't set SUBARCH if the user supplied it. (and don't call useless uname during cross compilation) Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- scripts/nmk/scripts/include.mk | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/scripts/nmk/scripts/include.mk b/scripts/nmk/scripts/include.mk index ee0e32f62..c1c1e94af 100644 --- a/scripts/nmk/scripts/include.mk +++ b/scripts/nmk/scripts/include.mk @@ -8,21 +8,20 @@ endif # # Common vars. -SUBARCH := $(shell uname -m | sed \ - -e s/i.86/x86/ \ - -e s/x86_64/x86/ \ - -e s/sun4u/sparc64/ \ - -e s/arm.*/arm/ \ - -e s/sa110/arm/ \ - -e s/s390x/s390/ \ - -e s/parisc64/parisc/ \ - -e s/ppc64.*/ppc64/ \ - -e s/mips.*/mips/ \ - -e s/sh[234].*/sh/ \ +SUBARCH ?= $(shell uname -m) +ARCH ?= $(shell echo $(SUBARCH) | sed \ + -e s/i.86/x86/ \ + -e s/x86_64/x86/ \ + -e s/sun4u/sparc64/ \ + -e s/arm.*/arm/ \ + -e s/sa110/arm/ \ + -e s/s390x/s390/ \ + -e s/parisc64/parisc/ \ + -e s/ppc64.*/ppc64/ \ + -e s/mips.*/mips/ \ + -e s/sh[234].*/sh/ \ -e s/aarch64.*/aarch64/) -ARCH ?= $(SUBARCH) - export SUBARCH ARCH ifndef ____nmk_defined__tools From 1463c41119c8eef8ccf135e71359f579e821a21e Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 21 Nov 2019 21:56:37 +0000 Subject: [PATCH 2244/4375] build: Use SUBARCH Instead of doing additional `uname -m` - use provided $(SUBARCH) to detect what architecture flavour the build should produce the result for. Fixes two things: - zdtm make now correctly supplies $(USERCFLAGS) - subtly fixes cross compilation by providing a way to specify $(SUBARCH) Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Makefile | 6 ++---- test/zdtm/Makefile.inc | 25 +++++++++++++------------ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 2e62f6f39..ef76d706c 100644 --- a/Makefile +++ b/Makefile @@ -17,8 +17,6 @@ ifeq ($(origin HOSTCFLAGS), undefined) HOSTCFLAGS := $(CFLAGS) $(USERCFLAGS) endif -UNAME-M := $(shell uname -m) - # # Supported Architectures ifneq ($(filter-out x86 arm aarch64 ppc64 s390,$(ARCH)),) @@ -27,14 +25,14 @@ endif # The PowerPC 64 bits architecture could be big or little endian. # They are handled in the same way. -ifeq ($(UNAME-M),ppc64) +ifeq ($(SUBARCH),ppc64) error := $(error ppc64 big endian is not yet supported) endif # # Architecture specific options. ifeq ($(ARCH),arm) - ARMV := $(shell echo $(UNAME-M) | sed -nr 's/armv([[:digit:]]).*/\1/p; t; i7') + ARMV := $(shell echo $(SUBARCH) | sed -nr 's/armv([[:digit:]]).*/\1/p; t; i7') ifeq ($(ARMV),6) USERCFLAGS += -march=armv6 diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index d5c013a3e..7584d3b06 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -1,17 +1,18 @@ .SUFFIXES: MAKEFLAGS += -r -ARCH ?= $(shell uname -m | sed \ - -e s/i.86/x86/ \ - -e s/x86_64/x86/ \ - -e s/sun4u/sparc64/ \ - -e s/arm.*/arm/ \ - -e s/sa110/arm/ \ - -e s/s390x/s390/ \ - -e s/parisc64/parisc/ \ - -e s/ppc64.*/ppc64/ \ - -e s/mips.*/mips/ \ - -e s/sh[234].*/sh/ \ +SUBARCH ?= $(shell uname -m) +ARCH ?= $(shell echo $(SUBARCH) | sed \ + -e s/i.86/x86/ \ + -e s/x86_64/x86/ \ + -e s/sun4u/sparc64/ \ + -e s/arm.*/arm/ \ + -e s/sa110/arm/ \ + -e s/s390x/s390/ \ + -e s/parisc64/parisc/ \ + -e s/ppc64.*/ppc64/ \ + -e s/mips.*/mips/ \ + -e s/sh[234].*/sh/ \ -e s/aarch64.*/arm64/) ifeq ($(ARCH),arm64) @@ -19,7 +20,7 @@ ifeq ($(ARCH),arm64) endif ifeq ($(ARCH),arm) - ARMV := $(shell echo $(UNAME-M) | sed -nr 's/armv([[:digit:]]).*/\1/p; t; i7') + ARMV := $(shell echo $(SUBARCH) | sed -nr 's/armv([[:digit:]]).*/\1/p; t; i7') ifeq ($(ARMV),6) USERCFLAGS += -march=armv6 From 70fae12509d7e0448e00fa0b0aa3a94b2384025f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 21 Nov 2019 21:56:38 +0000 Subject: [PATCH 2245/4375] build/zdtm: Support cross-build Maybe not that useful, but only little change needed. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/Makefile.inc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index 7584d3b06..8f2650b44 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -29,7 +29,10 @@ ifeq ($(ARCH),arm) endif endif -CC := gcc +HOSTCC ?= gcc +ifeq ($(origin CC), default) + CC := $(CROSS_COMPILE)$(HOSTCC) +endif CFLAGS += -g -O2 -Wall -Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS += $(USERCFLAGS) CFLAGS += -D_GNU_SOURCE From 3b24574b6d48b386127386b18036767a89ad6d0f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 21 Nov 2019 21:56:39 +0000 Subject: [PATCH 2246/4375] build/zdtm: Makefile hack for travis aarch64/armv8l The very same hack to build aarch32 zdtm tests on armv8 Travis-CI as in the commit dfa0a1edcbcb ("Makefile hack for travis aarch64/armv8l") Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/Makefile.inc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index 8f2650b44..d132ca981 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -20,13 +20,17 @@ ifeq ($(ARCH),arm64) endif ifeq ($(ARCH),arm) - ARMV := $(shell echo $(SUBARCH) | sed -nr 's/armv([[:digit:]]).*/\1/p; t; i7') + ARMV := $(shell echo $(SUBARCH) | sed -nr 's/armv([[:digit:]]).*/\1/p; t; i7') - ifeq ($(ARMV),6) - USERCFLAGS += -march=armv6 - else ifeq ($(ARMV),7) - USERCFLAGS += -march=armv7-a - endif + ifeq ($(ARMV),6) + USERCFLAGS += -march=armv6 + else ifeq ($(ARMV),7) + USERCFLAGS += -march=armv7-a + else ifeq ($(ARMV),8) + # To build aarch32 on armv8 Travis-CI (see criu Makefile) + USERCFLAGS += -march=armv7-a + ARMV := 7 + endif endif HOSTCC ?= gcc From bffa6e0ad005a3e125b9b6c3da527a929ed18c79 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 21 Nov 2019 21:56:40 +0000 Subject: [PATCH 2247/4375] build/zdtm: Use pkg-config to find includes/libs Helps to cross-compile zdtm tests in case somebody needs it. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/Makefile.inc | 13 +++++++++++++ test/zdtm/static/Makefile | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index d132ca981..32fc72d32 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -53,12 +53,25 @@ endif RM := rm -f --one-file-system ifeq ($(COMPAT_TEST),y) + # Firstly look for 32-bit libs and then in standard path. + PKG_CONFIG_PATH := $(shell pkg-config --variable pc_path pkg-config) + PKG_CONFIG_PATH := /usr/lib32/pkgconfig:$(PKG_CONFIG_PATH) ifeq ($(ARCH),x86) export CFLAGS += -m32 export LDFLAGS += -m32 + PKG_CONFIG_PATH := /usr/lib/i386-linux-gnu/pkgconfig:$(PKG_CONFIG_PATH) endif + export PKG_CONFIG_PATH endif +define pkg-libs + $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --libs $(1)) +endef + +define pkg-cflags + $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --cflags $(1)) +endef + %.d: %.c $(E) " DEP " $@ $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -MM -MP -c $< -o $@ diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index e0d4d2c5c..36d00ca5c 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -528,8 +528,8 @@ stopped12: CFLAGS += -DZDTM_STOPPED_KILL -DZDTM_STOPPED_TKILL clone_fs: LDLIBS += -pthread # As generating dependencies won't work without proper includes, # we have to explicitly specify both .o and .d for this case: -netns_sub_veth.o netns_sub_veth.d: CPPFLAGS += -I/usr/include/libnl3 -netns_sub_veth: LDLIBS += -lnl-3 -l nl-route-3 +netns_sub_veth.o netns_sub_veth.d: CPPFLAGS += $(call pkg-cflags, libnl-3.0) +netns_sub_veth: LDLIBS += $(call pkg-libs, libnl-route-3.0 libnl-3.0) socket-tcp-fin-wait1: CFLAGS += -D ZDTM_TCP_FIN_WAIT1 socket-tcp-fin-wait2: CFLAGS += -D ZDTM_TCP_FIN_WAIT2 From 1dbc835954d9c27ad1edb8184c02cfea1fd414b1 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 21 Nov 2019 21:56:41 +0000 Subject: [PATCH 2248/4375] travis: Add armv7-cross as cross-compile test Fixes: #455 Based-on-patch-by: Andrei Vagin Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- .travis.yml | 4 +++ scripts/build/Dockerfile.armv7-cross | 44 ++++++++++++++++++++++++++++ scripts/build/Makefile | 1 + 3 files changed, 49 insertions(+) create mode 100644 scripts/build/Dockerfile.armv7-cross diff --git a/.travis.yml b/.travis.yml index f6f71be48..b27dbfe7b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -73,6 +73,10 @@ matrix: arch: amd64 env: TR_ARCH=fedora-asan dist: xenial # test hangs on bionic + - os: linux + arch: amd64 + env: TR_ARCH=armv7-cross + dist: bionic allow_failures: - env: TR_ARCH=docker-test - env: TR_ARCH=fedora-rawhide diff --git a/scripts/build/Dockerfile.armv7-cross b/scripts/build/Dockerfile.armv7-cross new file mode 100644 index 000000000..434934aad --- /dev/null +++ b/scripts/build/Dockerfile.armv7-cross @@ -0,0 +1,44 @@ +FROM dockcross/base:latest + +# Add the cross compiler sources +RUN echo "deb http://ftp.us.debian.org/debian/ jessie main" >> /etc/apt/sources.list && \ + dpkg --add-architecture armhf && \ + apt-get install emdebian-archive-keyring + +RUN apt-get update && apt-get install -y \ + crossbuild-essential-armhf \ + libbz2-dev:armhf \ + libexpat1-dev:armhf \ + ncurses-dev:armhf \ + libssl-dev:armhf \ + protobuf-c-compiler \ + protobuf-compiler \ + python-protobuf \ + libnl-3-dev:armhf \ + libprotobuf-dev:armhf \ + libnet-dev:armhf \ + libprotobuf-c-dev:armhf \ + libcap-dev:armhf \ + libaio-dev:armhf \ + libnl-route-3-dev:armhf + +ENV CROSS_TRIPLE=arm-linux-gnueabihf +ENV CROSS_COMPILE=${CROSS_TRIPLE}- \ + CROSS_ROOT=/usr/${CROSS_TRIPLE} \ + AS=/usr/bin/${CROSS_TRIPLE}-as \ + AR=/usr/bin/${CROSS_TRIPLE}-ar \ + CC=/usr/bin/${CROSS_TRIPLE}-gcc \ + CPP=/usr/bin/${CROSS_TRIPLE}-cpp \ + CXX=/usr/bin/${CROSS_TRIPLE}-g++ \ + LD=/usr/bin/${CROSS_TRIPLE}-ld \ + FC=/usr/bin/${CROSS_TRIPLE}-gfortran + +ENV PATH="${PATH}:${CROSS_ROOT}/bin" \ + PKG_CONFIG_PATH=/usr/lib/${CROSS_TRIPLE}/pkgconfig \ + ARCH=arm \ + SUBARCH=armv7 + +COPY . /criu +WORKDIR /criu + +RUN make mrproper && date && make -j $(nproc) zdtm && date diff --git a/scripts/build/Makefile b/scripts/build/Makefile index a7c78e8bd..d093ce76c 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -2,6 +2,7 @@ ARCHES := x86_64 fedora-asan fedora-rawhide centos armv7hf TARGETS := $(ARCHES) alpine TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) CONTAINER_RUNTIME := docker +TARGETS += armv7-cross all: $(TARGETS) $(TARGETS_CLANG) .PHONY: all From 434e6b92dbcd47354f02e3a992ead6c25a6db16f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 21 Nov 2019 21:56:42 +0000 Subject: [PATCH 2249/4375] Documentation: Add a hint about docker build The original/old guide probably doesn't work anymore: - the patch isn't accessible; - criu now depends on more libraries not only protobuf Still, keep it as it might be helpful for someone. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- Documentation/HOWTO.cross-compile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Documentation/HOWTO.cross-compile b/Documentation/HOWTO.cross-compile index f1b17842b..44b19dfea 100644 --- a/Documentation/HOWTO.cross-compile +++ b/Documentation/HOWTO.cross-compile @@ -1,4 +1,10 @@ -This HOWTO explains how to cross-compile CRIU on x86 +How to cross-compile CRIU on x86: + +Use the Dockerfile provided: + scripts/build/Dockerfile.armv7-cross + +Historical guide how-to do it without docker container: +[Unsupported, may not work anymore!] 1. Download the protobuf sources. 2. Apply the patch http://16918.selcdn.ru/crtools/aarch64/0001-protobuf-added-the-support-for-the-acrchitecture-AAr.patch From 6ab2bdd940c392ba58ebe68b5134d6327381a498 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 21 Nov 2019 21:56:43 +0000 Subject: [PATCH 2250/4375] zdtm/socket-tcp-fin-wait1: Use array index fro TEST_MSG Fixes the following compile-error: > CC socket-tcp-fin-wait1.o > socket-tcp-fin-wait1.c:144:26: error: adding 'int' to a string does not append to the string [-Werror,-Wstring-plus-int] > if (write(fd, TEST_MSG + 2, sizeof(TEST_MSG) - 2) != sizeof(TEST_MSG) - 2) { > ~~~~~~~~~^~~ > socket-tcp-fin-wait1.c:144:26: note: use array indexing to silence this warning > if (write(fd, TEST_MSG + 2, sizeof(TEST_MSG) - 2) != sizeof(TEST_MSG) - 2) { > ^ > & [ ] > 1 error generated. Signed-off-by: Dmitry Safonov Signed-off-by: Andrei Vagin --- test/zdtm/static/socket-tcp-fin-wait1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm/static/socket-tcp-fin-wait1.c b/test/zdtm/static/socket-tcp-fin-wait1.c index 6c7cc93e5..50da9c152 100644 --- a/test/zdtm/static/socket-tcp-fin-wait1.c +++ b/test/zdtm/static/socket-tcp-fin-wait1.c @@ -141,7 +141,7 @@ int main(int argc, char **argv) return 1; } - if (write(fd, TEST_MSG + 2, sizeof(TEST_MSG) - 2) != sizeof(TEST_MSG) - 2) { + if (write(fd, &TEST_MSG[2], sizeof(TEST_MSG) - 2) != sizeof(TEST_MSG) - 2) { pr_err("write"); return 1; } From 37220b3c418d8d09ff2ef147e94c37fc897b3e27 Mon Sep 17 00:00:00 2001 From: Nidhi Gupta Date: Thu, 7 Nov 2019 14:38:42 +0530 Subject: [PATCH 2251/4375] Add File-based Java Functional Tests Signed-off-by: Nidhi Gupta --- test/javaTests/README.md | 8 + .../criu/java/tests/CheckpointRestore.java | 4 +- .../src/org/criu/java/tests/FileRead.java | 2 +- .../src/org/criu/java/tests/Helper.java | 39 +++- .../org/criu/java/tests/MemoryMappings.java | 121 +++++++++++ .../org/criu/java/tests/MultipleFileRead.java | 203 ++++++++++++++++++ .../criu/java/tests/MultipleFileWrite.java | 140 ++++++++++++ .../src/org/criu/java/tests/ReadWrite.java | 119 ++++++++++ test/javaTests/test.xml | 30 +++ 9 files changed, 659 insertions(+), 7 deletions(-) create mode 100644 test/javaTests/src/org/criu/java/tests/MemoryMappings.java create mode 100644 test/javaTests/src/org/criu/java/tests/MultipleFileRead.java create mode 100644 test/javaTests/src/org/criu/java/tests/MultipleFileWrite.java create mode 100644 test/javaTests/src/org/criu/java/tests/ReadWrite.java diff --git a/test/javaTests/README.md b/test/javaTests/README.md index cb779285e..670741677 100644 --- a/test/javaTests/README.md +++ b/test/javaTests/README.md @@ -23,6 +23,14 @@ CAP_SETUID Here we test the File-Based Java APIs by checkpointing the application in the following scenarios and verifying the contents of the file after restore: - Reading and writing in the same file. (FileRead.java) +- Read from a file and write its content to another file. (ReadWrite.java) +- Reading from multiple files and writing their content to another file. (MultipleFileRead) +- Reading from a file and writing its content to multiple files. (MultipleFileWrite) + +## Memory mapping Java APIs + +Here we test the Memory Mapping APIs by checkpointing the application in following scenario and verifying the contents after restore: +- Memory-mapping a file and writing its content to another file. (MemoryMappings.java) ### Prerequisites for running the tests: - Maven diff --git a/test/javaTests/src/org/criu/java/tests/CheckpointRestore.java b/test/javaTests/src/org/criu/java/tests/CheckpointRestore.java index 968488191..b848c9938 100644 --- a/test/javaTests/src/org/criu/java/tests/CheckpointRestore.java +++ b/test/javaTests/src/org/criu/java/tests/CheckpointRestore.java @@ -77,7 +77,7 @@ public class CheckpointRestore { private void testSetup(String testName) throws IOException { Path testFolderPath = Paths.get(outputFolder + testName + "/"); if (!Files.exists(testFolderPath)) { - System.out.println("Test Folder does not exist creating it"); + System.out.println("Creating the test folder"); Files.createDirectory(testFolderPath); } } @@ -245,7 +245,7 @@ public class CheckpointRestore { Assert.assertNotEquals(currentState, Helper.STATE_TERMINATE, testName + ": ERROR: Checkpoint-Restore failed"); Assert.assertNotEquals(currentState, Helper.STATE_FAIL, testName + ": ERROR: Test Failed, Check Log for details"); Assert.assertEquals(currentState, Helper.STATE_PASS, testName + " ERROR: Unexpected State of Mapped Buffer"); - System.out.println("-----" + "PASS" + "-----"); + System.out.println("----- " + "PASS" + " -----"); } diff --git a/test/javaTests/src/org/criu/java/tests/FileRead.java b/test/javaTests/src/org/criu/java/tests/FileRead.java index d94a14112..d8851a73e 100644 --- a/test/javaTests/src/org/criu/java/tests/FileRead.java +++ b/test/javaTests/src/org/criu/java/tests/FileRead.java @@ -50,7 +50,7 @@ class FileRead { /* * Mapped Byte Buffer should be in init state at the beginning of test */ - if ('I' != b.getChar(Helper.MAPPED_INDEX)) { + if (Helper.STATE_INIT != b.getChar(Helper.MAPPED_INDEX)) { logger.log(Level.SEVERE, "Error: Error in memory mapping, test is not in init state"); b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); System.exit(1); diff --git a/test/javaTests/src/org/criu/java/tests/Helper.java b/test/javaTests/src/org/criu/java/tests/Helper.java index d608fba47..fdf20bb52 100644 --- a/test/javaTests/src/org/criu/java/tests/Helper.java +++ b/test/javaTests/src/org/criu/java/tests/Helper.java @@ -1,9 +1,6 @@ package org.criu.java.tests; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; import java.nio.MappedByteBuffer; import java.util.logging.FileHandler; import java.util.logging.Level; @@ -96,4 +93,38 @@ class Helper { System.exit(1); } } + + + /** + * Compare two files and return true if their content is similar. + * + * @param readFile File 1 whose content has to be compared. + * @param writeFile File 2 whose content has to be compared. + * @return true if the files are similar, false otherwise. + * @throws IOException + */ + static boolean compare(File readFile, File writeFile) throws IOException { + BufferedReader bir = new BufferedReader(new FileReader(readFile)); + BufferedReader bor = new BufferedReader(new FileReader(writeFile)); + String si, so; + si = bir.readLine(); + so = bor.readLine(); + while (null != si && null != so) { + if (!si.equals(so)) { + return false; + } + + si = bir.readLine(); + so = bor.readLine(); + } + + if ((null == si) && (null == so)) { + return true; + } + bir.close(); + bor.close(); + + return false; + } + } diff --git a/test/javaTests/src/org/criu/java/tests/MemoryMappings.java b/test/javaTests/src/org/criu/java/tests/MemoryMappings.java new file mode 100644 index 000000000..4ac6f4a17 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/MemoryMappings.java @@ -0,0 +1,121 @@ +package org.criu.java.tests; + +import java.io.*; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class MemoryMappings { + private static String TESTNAME = "MemoryMappings"; + + /** + * Map a file to memory and write the mapped data into a file, + * checkpointing and restoring in between. + * + * @param args Not used + */ + public static void main(String[] args) { + MappedByteBuffer b = null; + Logger logger = null; + + try { + MappedByteBuffer testBuffer; + char ch; + int i = 1; + boolean similar; + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + File f = new File(Helper.MEMORY_MAPPED_FILE_NAME); + File readFile = new File(Helper.SOURCE_FOLDER + "/" + "ReadWrite.java"); + File writeFile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + TESTNAME + "/" + "MemoryMappings_file.txt"); + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + String pid = bean.getName(); + int val = Helper.init(TESTNAME, pid, logger); + if (0 != val) { + logger.log(Level.SEVERE, "Helper.init returned a non-zero code."); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Test init done; pid written to pid file; beginning with test"); + + FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + b = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + /* + * Mapped Byte Buffer should be in init state at the beginning of test + */ + if (Helper.STATE_INIT != b.getChar(Helper.MAPPED_INDEX)) { + logger.log(Level.SEVERE, "Error: Error in memory mapping, test is not in init state"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Checking existence of file to be memory mapped"); + if (!readFile.exists()) { + logger.log(Level.SEVERE, "Error: File from which to read does not exist"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + channel = FileChannel.open(readFile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + testBuffer = channel.map(MapMode.READ_WRITE, 0, readFile.length()); + channel.close(); + + if (writeFile.exists()) { + writeFile.delete(); + } + boolean newFile = writeFile.createNewFile(); + if (!newFile) { + logger.log(Level.SEVERE, "Error: Cannot create a new file to write to."); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + BufferedWriter brw = new BufferedWriter(new FileWriter(writeFile)); + + while (testBuffer.hasRemaining()) { + ch = (char) testBuffer.get(); + brw.write(ch); + i++; + if (200 == i) { + logger.log(Level.INFO, "Going to checkpoint"); + Helper.checkpointAndWait(b, logger); + logger.log(Level.INFO, "Test has been restored!"); + } + } + + brw.close(); + logger.log(Level.INFO, "Comparing contents of the file"); + + similar = Helper.compare(readFile, writeFile); + if (!similar) { + logger.log(Level.SEVERE, "Error: Files are not similar after writing"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + logger.log(Level.INFO, "Data was read and written correctly!"); + logger.log(Level.INFO, Helper.PASS_MESSAGE); + brw.close(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + System.exit(0); + + } catch (Exception e) { + if (null != logger) { + + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + e.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occurred:" + e); + logger.log(Level.FINE, writer.toString()); + } + + if (null != b) { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + System.exit(5); + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/MultipleFileRead.java b/test/javaTests/src/org/criu/java/tests/MultipleFileRead.java new file mode 100644 index 000000000..7b023673e --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/MultipleFileRead.java @@ -0,0 +1,203 @@ +package org.criu.java.tests; + +import java.io.*; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class MultipleFileRead { + private static String TESTNAME = "MultipleFileRead"; + + /** + * @param readFile1 File 1 whose contents are read. + * @param readFile2 File 2 whose contents are read. + * @param writeFile File in which data has been written to. + * @return true if the data written is as expected, false otherwise. + * @throws IOException + */ + private static boolean compare(File readFile1, File readFile2, File writeFile) throws IOException { + BufferedReader br1 = new BufferedReader(new FileReader(readFile1)); + BufferedReader br2 = new BufferedReader(new FileReader(readFile2)); + BufferedReader brw = new BufferedReader(new FileReader(writeFile)); + boolean eof1, eof2; + eof1 = false; + eof2 = false; + String inpString, wrtString; + + while (!eof1 || !eof2) { + if (!eof1) { + inpString = br1.readLine(); + if (null == inpString) { + eof1 = true; + } else { + wrtString = brw.readLine(); + if (null == wrtString) { + return false; + } + if (!wrtString.equals(inpString)) { + return false; + } + } + } + if (!eof2) { + inpString = br2.readLine(); + if (null == inpString) { + eof2 = true; + } else { + wrtString = brw.readLine(); + if (null == wrtString) { + return false; + } + if (!wrtString.equals(inpString)) { + return false; + } + } + } + } + + wrtString = brw.readLine(); + if (null != wrtString) { + return false; + } + + br1.close(); + br2.close(); + brw.close(); + + return true; + } + + /** + * Read from multiple files and write their content into another file, + * checkpointing and restoring in between. + * + * @param args Not used. + */ + public static void main(String[] args) { + MappedByteBuffer b = null; + String s; + int i = 0; + Logger logger = null; + try { + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + File f = new File(Helper.MEMORY_MAPPED_FILE_NAME); + File readFile1 = new File(Helper.SOURCE_FOLDER + "/" + "FileRead.java"); + File readFile2 = new File(Helper.SOURCE_FOLDER + "/" + "ReadWrite.java"); + File writeFile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + TESTNAME + "/" + "MultipleFileRead_file.txt"); + boolean eofFile1 = false, eofFile2 = false, check; + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + String pid = bean.getName(); + int val = Helper.init(TESTNAME, pid, logger); + if (0 != val) { + logger.log(Level.SEVERE, "Helper.init returned a non-zero code."); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Test init done; pid written to pid file; beginning with test"); + + FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + b = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + /* + * Mapped Byte Buffer should be in init state at the beginning of test + */ + if (b.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT) { + logger.log(Level.SEVERE, "Error: Error in memory mapping, test is not in init state"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Checking existence of the read files"); + + if (!readFile1.exists()) { + logger.log(Level.SEVERE, "Error: File from which to read does not exist"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (!readFile2.exists()) { + logger.log(Level.SEVERE, "Error: File from which to read does not exist"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (writeFile.exists()) { + writeFile.delete(); + } + logger.log(Level.INFO, "Creating writeFile"); + boolean newFile = writeFile.createNewFile(); + if (!newFile) { + logger.log(Level.SEVERE, "Error: Cannot create a new file to write to."); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + BufferedReader br1 = new BufferedReader(new FileReader(readFile1)); + BufferedReader br2 = new BufferedReader(new FileReader(readFile2)); + BufferedWriter brw = new BufferedWriter(new FileWriter(writeFile)); + + logger.log(Level.INFO, "Writing in file"); + + while (!eofFile1 || !eofFile2) { + if (!eofFile1) { + s = br1.readLine(); + i++; + if (null == s) { + eofFile1 = true; + } else { + brw.write(s + "\n"); + } + } + if (!eofFile2) { + s = br2.readLine(); + i++; + if (null == s) { + eofFile2 = true; + } else { + brw.write(s + "\n"); + } + } + if (10 == i) { + /* + * Checkpoint and Restore + */ + logger.log(Level.INFO, "Going to checkpoint"); + Helper.checkpointAndWait(b, logger); + logger.log(Level.INFO, "Test has been restored!"); + } + } + brw.flush(); + logger.log(Level.INFO, "Checking the content of the file"); + check = compare(readFile1, readFile2, writeFile); + + if (!check) { + logger.log(Level.SEVERE, "Error: Files are not similar after writing"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + logger.log(Level.INFO, "The file has been written as expected"); + logger.log(Level.INFO, Helper.PASS_MESSAGE); + br1.close(); + br2.close(); + brw.close(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + System.exit(0); + + } catch (Exception e) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + e.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occurred:" + e); + logger.log(Level.FINE, writer.toString()); + } + + if (null != b) { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + System.exit(5); + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/MultipleFileWrite.java b/test/javaTests/src/org/criu/java/tests/MultipleFileWrite.java new file mode 100644 index 000000000..76d287a07 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/MultipleFileWrite.java @@ -0,0 +1,140 @@ +package org.criu.java.tests; + +import java.io.*; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class MultipleFileWrite { + private static String TESTNAME = "MultipleFileWrite"; + + /** + * Reads from a file and write its content into multiple files, + * checkpointing and restoring in between. + * + * @param args Not used. + */ + public static void main(String[] args) { + MappedByteBuffer b = null; + String s, pid; + int i = 1; + Logger logger = null; + boolean similar1, similar2; + try { + File readFile = new File(Helper.SOURCE_FOLDER + "/" + "FileRead.java"); + File writeFile1 = new File(Helper.OUTPUT_FOLDER_NAME + "/" + TESTNAME + "/" + TESTNAME + "1_file.txt"); + File writeFile2 = new File(Helper.OUTPUT_FOLDER_NAME + "/" + TESTNAME + "/" + TESTNAME + "2_file.txt"); + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + File f = new File(Helper.MEMORY_MAPPED_FILE_NAME); + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + pid = bean.getName(); + int val = Helper.init(TESTNAME, pid, logger); + if (0 != val) { + logger.log(Level.SEVERE, "Helper.init returned a non-zero code."); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Test init done; pid written to pid file; beginning with test"); + + FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + b = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + /* + * Mapped Byte Buffer should be in init state at the beginning of test + */ + if (Helper.STATE_INIT != b.getChar(Helper.MAPPED_INDEX)) { + logger.log(Level.SEVERE, "Error: Error in memory mapping, test is not in init state"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Checking existence of read files!"); + + if (!readFile.exists()) { + logger.log(Level.SEVERE, "Error: File from which to read does not exist"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (writeFile1.exists()) { + writeFile1.delete(); + } + boolean newFile = writeFile1.createNewFile(); + if (!newFile) { + logger.log(Level.SEVERE, "Error: Cannot create a new file to write to."); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + if (writeFile2.exists()) { + writeFile2.delete(); + } + newFile = writeFile2.createNewFile(); + if (!newFile) { + logger.log(Level.SEVERE, "Error: Cannot create a new file to write to."); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Created write files"); + + BufferedReader br = new BufferedReader(new FileReader(readFile)); + BufferedWriter bw1 = new BufferedWriter(new FileWriter(writeFile1)); + BufferedWriter bw2 = new BufferedWriter(new FileWriter(writeFile2)); + + s = br.readLine(); + + while (null != s) { + bw1.write(s + "\n"); + bw2.write(s + "\n"); + if (90 == i) { + /* + * Checkpoint and Restore + */ + logger.log(Level.INFO, "Going to checkpoint"); + Helper.checkpointAndWait(b, logger); + logger.log(Level.INFO, "Test has been restored!"); + } + + i++; + s = br.readLine(); + } + + bw1.flush(); + bw2.flush(); + logger.log(Level.INFO, "Checking files have been written correctly"); + + similar1 = Helper.compare(readFile, writeFile1); + similar2 = Helper.compare(readFile, writeFile2); + + if (!similar1 || !similar2) { + logger.log(Level.SEVERE, "Error: Written data is not identical to the data read"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + logger.log(Level.INFO, "Content of files is as expected"); + logger.log(Level.INFO, Helper.PASS_MESSAGE); + br.close(); + bw1.close(); + bw2.close(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + System.exit(0); + + } catch (Exception e) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + e.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occurred:" + e); + logger.log(Level.FINE, writer.toString()); + } + + if (null != b) { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + System.exit(5); + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/ReadWrite.java b/test/javaTests/src/org/criu/java/tests/ReadWrite.java new file mode 100644 index 000000000..fa98447ed --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/ReadWrite.java @@ -0,0 +1,119 @@ +package org.criu.java.tests; + +import java.io.*; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class ReadWrite { + private static String TESTNAME = "ReadWrite"; + + /** + * Read from a file and write its content into another file, + * checkpointing and restoring in between. + * + * @param args Not used. + */ + public static void main(String[] args) { + int i = 0; + String s, pid; + boolean similar; + MappedByteBuffer b = null; + Logger logger = null; + try { + File readFile = new File(Helper.SOURCE_FOLDER + "/" + "FileRead.java"); + File writeFile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + TESTNAME + "/" + "ReadWrite_file.txt"); + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + File f = new File(Helper.MEMORY_MAPPED_FILE_NAME); + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + pid = bean.getName(); + int val = Helper.init(TESTNAME, pid, logger); + if (0 != val) { + logger.log(Level.SEVERE, "Helper.init returned a non-zero code."); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Test init done; pid written to pid file; beginning with test"); + FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + b = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + /* + * Mapped Byte Buffer should be in init state at the beginning of test + */ + if (Helper.STATE_INIT != b.getChar(Helper.MAPPED_INDEX)) { + logger.log(Level.SEVERE, "Error: Error in memory mapping, test is not in init state"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Checking existence of files to be read!"); + if (!readFile.exists()) { + logger.log(Level.SEVERE, "Error: File from which to read does not exist"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + if (writeFile.exists()) { + writeFile.delete(); + } + logger.log(Level.INFO, "Creating the writeFile"); + boolean newFile = writeFile.createNewFile(); + if (!newFile) { + logger.log(Level.SEVERE, "Error: Cannot create a new file to write to."); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + BufferedReader brr = new BufferedReader(new FileReader(readFile)); + BufferedWriter brw = new BufferedWriter(new FileWriter(writeFile)); + logger.log(Level.INFO, "Start writing"); + + s = brr.readLine(); + + while (null != s) { + i++; + brw.write(s + "\n"); + + if (50 == i) { + /* + * Checkpoint and Restore + */ + logger.log(Level.INFO, "Going to checkpoint"); + Helper.checkpointAndWait(b, logger); + logger.log(Level.INFO, "Test has been restored!"); + } + s = brr.readLine(); + } + + brw.flush(); + logger.log(Level.INFO, "Checking content of the files."); + similar = Helper.compare(readFile, writeFile); + + if (!similar) { + logger.log(Level.SEVERE, "Error: Files are not similar after writing"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + logger.log(Level.INFO, "Content of file is as expected"); + logger.log(Level.INFO, Helper.PASS_MESSAGE); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + System.exit(0); + } catch (Exception e) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + e.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occurred:" + e); + logger.log(Level.FINE, writer.toString()); + } + if (null != b) { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + System.exit(5); + } + } +} diff --git a/test/javaTests/test.xml b/test/javaTests/test.xml index 8ff67c5e0..b73a31db2 100644 --- a/test/javaTests/test.xml +++ b/test/javaTests/test.xml @@ -4,10 +4,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3ca09b191429a4260a12daf6bbaf58da2aebd656 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 20 Nov 2019 11:01:33 +0300 Subject: [PATCH 2252/4375] travis: ignore fails of podman-test until it will not be fixed. Signed-off-by: Andrei Vagin --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b27dbfe7b..e6e410191 100644 --- a/.travis.yml +++ b/.travis.yml @@ -81,6 +81,7 @@ matrix: - env: TR_ARCH=docker-test - env: TR_ARCH=fedora-rawhide - env: TR_ARCH=local GCOV=1 + - env: TR_ARCH=podman-test script: - sudo make CCACHE=1 -C scripts/travis $TR_ARCH after_success: From b5b1c4ec4506df7cee6a9ba8ffff36f43e0cd8e3 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 21 Nov 2019 01:24:44 +0300 Subject: [PATCH 2253/4375] kerndat: check whether the new mount API is supported of not Signed-off-by: Andrei Vagin --- Makefile.config | 2 +- .../arch/arm/plugins/std/syscalls/syscall.def | 3 ++ .../plugins/std/syscalls/syscall-ppc64.tbl | 3 ++ .../plugins/std/syscalls/syscall-s390.tbl | 3 ++ .../x86/plugins/std/syscalls/syscall_32.tbl | 3 ++ .../x86/plugins/std/syscalls/syscall_64.tbl | 3 ++ criu/include/kerndat.h | 1 + criu/include/linux/mount.h | 35 +++++++++++++++++++ criu/kerndat.c | 16 +++++++++ scripts/feature-tests.mak | 12 +++++++ 10 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 criu/include/linux/mount.h diff --git a/Makefile.config b/Makefile.config index 5af3fed38..81aae24f8 100644 --- a/Makefile.config +++ b/Makefile.config @@ -47,7 +47,7 @@ export DEFINES += $(FEATURE_DEFINES) export CFLAGS += $(FEATURE_DEFINES) FEATURES_LIST := TCP_REPAIR STRLCPY STRLCAT PTRACE_PEEKSIGINFO \ - SETPROCTITLE_INIT MEMFD TCP_REPAIR_WINDOW + SETPROCTITLE_INIT MEMFD TCP_REPAIR_WINDOW FSCONFIG # $1 - config name define gen-feature-test diff --git a/compel/arch/arm/plugins/std/syscalls/syscall.def b/compel/arch/arm/plugins/std/syscalls/syscall.def index 721ff16dc..d5bdc677e 100644 --- a/compel/arch/arm/plugins/std/syscalls/syscall.def +++ b/compel/arch/arm/plugins/std/syscalls/syscall.def @@ -112,3 +112,6 @@ userfaultfd 282 388 (int flags) fallocate 47 352 (int fd, int mode, loff_t offset, loff_t len) cacheflush ! 983042 (void *start, void *end, int flags) ppoll 73 336 (struct pollfd *fds, unsigned int nfds, const struct timespec *tmo, const sigset_t *sigmask, size_t sigsetsize) +fsopen 430 430 (char *fsname, unsigned int flags) +fsconfig 431 431 (int fd, unsigned int cmd, const char *key, const char *value, int aux) +fsmount 432 432 (int fd, unsigned int flags, unsigned int attr_flags) diff --git a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl index 3b3079040..4e283d5e9 100644 --- a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl +++ b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl @@ -108,3 +108,6 @@ __NR_gettimeofday 78 sys_gettimeofday (struct timeval *tv, struct timezone *tz) __NR_preadv 320 sys_preadv_raw (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) __NR_userfaultfd 364 sys_userfaultfd (int flags) __NR_ppoll 281 sys_ppoll (struct pollfd *fds, unsigned int nfds, const struct timespec *tmo, const sigset_t *sigmask, size_t sigsetsize) +__NR_fsopen 430 sys_fsopen (char *fsname, unsigned int flags) +__NR_fsconfig 431 sys_fsconfig (int fd, unsigned int cmd, const char *key, const char *value, int aux) +__NR_fsmount 432 sys_fsmount (int fd, unsigned int flags, unsigned int attr_flags) diff --git a/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl b/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl index cc13a63dd..fd48e3950 100644 --- a/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl +++ b/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl @@ -108,3 +108,6 @@ __NR_userfaultfd 355 sys_userfaultfd (int flags) __NR_preadv 328 sys_preadv_raw (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) __NR_gettimeofday 78 sys_gettimeofday (struct timeval *tv, struct timezone *tz) __NR_ppoll 302 sys_ppoll (struct pollfd *fds, unsigned int nfds, const struct timespec *tmo, const sigset_t *sigmask, size_t sigsetsize) +__NR_fsopen 430 sys_fsopen (char *fsname, unsigned int flags) +__NR_fsconfig 431 sys_fsconfig (int fd, unsigned int cmd, const char *key, const char *value, int aux) +__NR_fsmount 432 sys_fsmount (int fd, unsigned int flags, unsigned int attr_flags) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl index 7903ab150..038aeb4f7 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl @@ -96,3 +96,6 @@ __NR_seccomp 354 sys_seccomp (unsigned int op, unsigned int flags, const char __NR_memfd_create 356 sys_memfd_create (const char *name, unsigned int flags) __NR_userfaultfd 374 sys_userfaultfd (int flags) __NR_ppoll 309 sys_ppoll (struct pollfd *fds, unsigned int nfds, const struct timespec *tmo, const sigset_t *sigmask, size_t sigsetsize) +__NR_fsopen 430 sys_fsopen (char *fsname, unsigned int flags) +__NR_fsconfig 431 sys_fsconfig (int fd, unsigned int cmd, const char *key, const char *value, int aux) +__NR_fsmount 432 sys_fsmount (int fd, unsigned int flags, unsigned int attr_flags) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl index 4ac9164ea..215f32026 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl @@ -107,3 +107,6 @@ __NR_kcmp 312 sys_kcmp (pid_t pid1, pid_t pid2, int type, unsigned long idx1 __NR_memfd_create 319 sys_memfd_create (const char *name, unsigned int flags) __NR_userfaultfd 323 sys_userfaultfd (int flags) __NR_ppoll 271 sys_ppoll (struct pollfd *fds, unsigned int nfds, const struct timespec *tmo, const sigset_t *sigmask, size_t sigsetsize) +__NR_fsopen 430 sys_fsopen (char *fsname, unsigned int flags) +__NR_fsconfig 431 sys_fsconfig (int fd, unsigned int cmd, const char *key, const char *value, int aux) +__NR_fsmount 432 sys_fsmount (int fd, unsigned int flags, unsigned int attr_flags) diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index d93e07813..771195860 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -65,6 +65,7 @@ struct kerndat_s { bool x86_has_ptrace_fpu_xsave_bug; bool has_inotify_setnextwd; bool has_kcmp_epoll_tfd; + bool has_fsopen; }; extern struct kerndat_s kdat; diff --git a/criu/include/linux/mount.h b/criu/include/linux/mount.h new file mode 100644 index 000000000..aa6be69ec --- /dev/null +++ b/criu/include/linux/mount.h @@ -0,0 +1,35 @@ +#ifndef _CRIU_LINUX_MOUNT_H +#define _CRIU_LINUX_MOUNT_H + +#include "common/config.h" +#include "compel/plugins/std/syscall-codes.h" + +#ifdef CONFIG_HAS_FSCONFIG +#include +#else +enum fsconfig_command { + FSCONFIG_SET_FLAG = 0, /* Set parameter, supplying no value */ + FSCONFIG_SET_STRING = 1, /* Set parameter, supplying a string value */ + FSCONFIG_SET_BINARY = 2, /* Set parameter, supplying a binary blob value */ + FSCONFIG_SET_PATH = 3, /* Set parameter, supplying an object by path */ + FSCONFIG_SET_PATH_EMPTY = 4, /* Set parameter, supplying an object by (empty) path */ + FSCONFIG_SET_FD = 5, /* Set parameter, supplying an object by fd */ + FSCONFIG_CMD_CREATE = 6, /* Invoke superblock creation */ + FSCONFIG_CMD_RECONFIGURE = 7, /* Invoke superblock reconfiguration */ +}; +#endif + +static inline int sys_fsopen(const char *fsname, unsigned int flags) +{ + return syscall(__NR_fsopen, fsname, flags); +} +static inline int sys_fsconfig(int fd, unsigned int cmd, const char *key, const char *value, int aux) +{ + return syscall(__NR_fsconfig, fd, cmd, key, value, aux); +} +static inline int sys_fsmount(int fd, unsigned int flags, unsigned int attr_flags) +{ + return syscall(__NR_fsmount, fd, flags, attr_flags); +} + +#endif diff --git a/criu/kerndat.c b/criu/kerndat.c index 39cacb8fe..b0dd83135 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -723,6 +723,20 @@ static int kerndat_has_inotify_setnextwd(void) return ret; } +static int kerndat_has_fsopen(void) +{ + if (syscall(__NR_fsopen, NULL, -1) != -1) { + pr_err("fsopen should fail\n"); + return -1; + } + if (errno == ENOSYS) + pr_info("The new mount API (fsopen, fsmount) isn't supported\n"); + else + kdat.has_fsopen = true; + + return 0; +} + static int has_kcmp_epoll_tfd(void) { kcmp_epoll_slot_t slot = { }; @@ -1043,6 +1057,8 @@ int kerndat_init(void) ret = kerndat_has_inotify_setnextwd(); if (!ret) ret = has_kcmp_epoll_tfd(); + if (!ret) + ret = kerndat_has_fsopen(); kerndat_lsm(); kerndat_mmap_min_addr(); diff --git a/scripts/feature-tests.mak b/scripts/feature-tests.mak index e39d97bb1..39ddfd053 100644 --- a/scripts/feature-tests.mak +++ b/scripts/feature-tests.mak @@ -136,3 +136,15 @@ ENTRY(main) nop END(main) endef + +define FEATURE_TEST_FSCONFIG + +#include + +int main(void) +{ + if (FSCONFIG_CMD_CREATE > 0) + return 0; + return 0; +} +endef From 4997a096e4ffad4778a24f903e4450842171e576 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 25 Nov 2019 09:50:08 +0300 Subject: [PATCH 2254/4375] util: introduce the mount_detached_fs helper Signed-off-by: Andrei Vagin --- criu/include/util.h | 2 ++ criu/util.c | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/criu/include/util.h b/criu/include/util.h index 313aacd8c..45bebf673 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -380,4 +380,6 @@ static inline void print_stack_trace(pid_t pid) {} ___ret; \ }) +extern int mount_detached_fs(const char *fsname); + #endif /* __CR_UTIL_H__ */ diff --git a/criu/util.c b/criu/util.c index e47e109ae..3bae18ab2 100644 --- a/criu/util.c +++ b/criu/util.c @@ -28,6 +28,8 @@ #include #include +#include "linux/mount.h" + #include "kerndat.h" #include "page.h" #include "util.h" @@ -1423,3 +1425,27 @@ void print_stack_trace(pid_t pid) free(strings); } #endif + +int mount_detached_fs(const char *fsname) +{ + int fsfd, fd; + + fsfd = sys_fsopen(fsname, 0); + if (fsfd < 0) { + pr_perror("Unable to open the %s file system", fsname); + return -1; + } + + if (sys_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) { + pr_perror("Unable to create the %s file system", fsname); + close(fsfd); + return -1; + } + + fd = sys_fsmount(fsfd, 0, 0); + if (fd < 0) + pr_perror("Unable to mount the %s file system", fsname); + close(fsfd); + return fd; +} + From 1a2d8ad7e162adf95124064109c959c7f7beb77a Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 21 Nov 2019 01:26:38 +0300 Subject: [PATCH 2255/4375] mount: use new mount API to open the proc file system It doesn't require to create a temporary directory and mount the proc file system in it. Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 5694931f4..b920ce262 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -23,6 +23,8 @@ #include #include "common/compiler.h" +#include "linux/mount.h" + #include "clone-noasan.h" #include "cr_options.h" #include "servicefd.h" @@ -1585,27 +1587,39 @@ static void restore_pgid(void) futex_set_and_wake(&rsti(current)->pgrp_set, 1); } +static int __legacy_mount_proc() +{ + char proc_mountpoint[] = "/tmp/crtools-proc.XXXXXX"; + int fd; + + if (mkdtemp(proc_mountpoint) == NULL) { + pr_perror("mkdtemp failed %s", proc_mountpoint); + return -1; + } + + pr_info("Mount procfs in %s\n", proc_mountpoint); + if (mount("proc", proc_mountpoint, "proc", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL)) { + pr_perror("mount failed"); + if (rmdir(proc_mountpoint)) + pr_perror("Unable to remove %s", proc_mountpoint); + return -1; + } + + fd = open_detach_mount(proc_mountpoint); + return fd; +} + static int mount_proc(void) { int fd, ret; - char proc_mountpoint[] = "/tmp/crtools-proc.XXXXXX"; if (root_ns_mask == 0) fd = ret = open("/proc", O_DIRECTORY); else { - if (mkdtemp(proc_mountpoint) == NULL) { - pr_perror("mkdtemp failed %s", proc_mountpoint); - return -1; - } - - pr_info("Mount procfs in %s\n", proc_mountpoint); - if (mount("proc", proc_mountpoint, "proc", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL)) { - pr_perror("mount failed"); - rmdir(proc_mountpoint); - return -1; - } - - ret = fd = open_detach_mount(proc_mountpoint); + if (kdat.has_fsopen) + fd = ret = mount_detached_fs("proc"); + else + fd = ret = __legacy_mount_proc(); } if (fd >= 0) { From 76e4d31a3fa6a8d4ccee9a111c212c27ab69474f Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 25 Nov 2019 09:51:40 +0300 Subject: [PATCH 2256/4375] net: use new mount API to open the sysfs file system It doesn't require to create a temporary directory and mount the proc file system in it. Signed-off-by: Andrei Vagin --- criu/net.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/criu/net.c b/criu/net.c index 9825db10f..5822de629 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2133,6 +2133,11 @@ static int mount_ns_sysfs(void) BUG_ON(ns_sysfs_fd != -1); + if (kdat.has_fsopen) { + ns_sysfs_fd = mount_detached_fs("sysfs"); + return ns_sysfs_fd >= 0 ? 0 : -1; + } + /* * A new mntns is required to avoid the race between * open_detach_mount and creating mntns. From be43c3b840b657a6a31a6885ca6e03da70de1b04 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 25 Nov 2019 09:52:25 +0300 Subject: [PATCH 2257/4375] cgroup: use new mount API to open the cgroup file system It doesn't require to create a temporary directory and mount the proc file system in it. Signed-off-by: Andrei Vagin --- criu/cgroup.c | 105 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 82 insertions(+), 23 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index a66fc960e..d4c712167 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -8,6 +8,7 @@ #include #include #include + #include "common/list.h" #include "xmalloc.h" #include "cgroup.h" @@ -24,6 +25,8 @@ #include "protobuf.h" #include "images/core.pb-c.h" #include "images/cgroup.pb-c.h" +#include "kerndat.h" +#include "linux/mount.h" /* * This structure describes set of controller groups @@ -542,6 +545,84 @@ static int add_freezer_state(struct cg_controller *controller) return 0; } +static const char namestr[] = "name="; +static int __new_open_cgroupfs(struct cg_ctl *cc) +{ + int fsfd, fd; + char *name; + + fsfd = sys_fsopen("cgroup", 0); + if (fsfd < 0) { + pr_perror("Unable to open the cgroup file system"); + return -1; + } + + if (strstartswith(cc->name, namestr)) { + if (sys_fsconfig(fsfd, FSCONFIG_SET_STRING, + "name", cc->name + strlen(namestr), 0)) { + pr_perror("Unable to configure the cgroup (%s) file system", cc->name); + goto err; + } + } else { + char *saveptr = NULL, *buf = strdupa(cc->name); + name = strtok_r(buf, ",", &saveptr); + while (name) { + if (sys_fsconfig(fsfd, FSCONFIG_SET_FLAG, name, NULL, 0)) { + pr_perror("Unable to configure the cgroup (%s) file system", name); + goto err; + } + name = strtok_r(NULL, ",", &saveptr); + } + } + + if (sys_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0)) { + pr_perror("Unable to create the cgroup (%s) file system", cc->name); + goto err; + } + + fd = sys_fsmount(fsfd, 0, 0); + if (fd < 0) + pr_perror("Unable to mount the cgroup (%s) file system", cc->name); + close(fsfd); + + return fd; +err: + close(fsfd); + return -1; +} + +static int open_cgroupfs(struct cg_ctl *cc) +{ + char prefix[] = ".criu.cgmounts.XXXXXX"; + char mopts[1024]; + int fd; + + if (kdat.has_fsopen) + return __new_open_cgroupfs(cc); + + if (strstartswith(cc->name, namestr)) + snprintf(mopts, sizeof(mopts), "none,%s", cc->name); + else + snprintf(mopts, sizeof(mopts), "%s", cc->name); + + if (mkdtemp(prefix) == NULL) { + pr_perror("can't make dir for cg mounts"); + return -1; + } + + if (mount("none", prefix, "cgroup", 0, mopts) < 0) { + pr_perror("Unable to mount %s", mopts); + rmdir(prefix); + return -1; + } + + fd = open_detach_mount(prefix); + if (fd < 0) + return -1; + + return fd; +} + static int collect_cgroups(struct list_head *ctls) { struct cg_ctl *cc; @@ -550,8 +631,6 @@ static int collect_cgroups(struct list_head *ctls) list_for_each_entry(cc, ctls, l) { char path[PATH_MAX], *root; - char prefix[] = ".criu.cgmounts.XXXXXX"; - const char namestr[] = "name="; struct cg_controller *cg; struct cg_root_opt *o; @@ -603,27 +682,7 @@ static int collect_cgroups(struct list_head *ctls) return -1; } } else { - char mopts[1024]; - - if (strstartswith(cc->name, namestr)) - snprintf(mopts, sizeof(mopts), "none,%s", cc->name); - else - snprintf(mopts, sizeof(mopts), "%s", cc->name); - - if (mkdtemp(prefix) == NULL) { - pr_perror("can't make dir for cg mounts"); - return -1; - } - - if (mount("none", prefix, "cgroup", 0, mopts) < 0) { - pr_perror("couldn't mount %s", mopts); - rmdir(prefix); - return -1; - } - - fd = open_detach_mount(prefix); - if (fd < 0) - return -1; + fd = open_cgroupfs(cc); } path_pref_len = snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd); From af7e5f994b4d2221af1a0110dbfe5bdadd67f964 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 26 Nov 2019 07:26:31 +0300 Subject: [PATCH 2258/4375] readme: github pull-requests is the preferred way to contribute We will continue accepting patches. Signed-off-by: Andrei Vagin --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 558e87160..6a578b953 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Here are some useful hints to get involved. * CRIU does need [extensive testing](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Atesting); * Documentation is always hard, we have [some information](https://criu.org/Category:Empty_articles) that is to be extracted from people's heads into wiki pages as well as [some texts](https://criu.org/Category:Editor_help_needed) that all need to be converted into useful articles; * Feedback is expected on the github issues page and on the [mailing list](https://lists.openvz.org/mailman/listinfo/criu); -* For historical reasons we do not accept PRs, instead [patches are welcome](http://criu.org/How_to_submit_patches); +* We accept github pull requests and this is the preferred way to contribute to CRIU. If you prefer to send patches by email, you are welcome to send them to [the devel list](http://criu.org/How_to_submit_patches); * Spread the word about CRIU in [social networks](http://criu.org/Contacts); * If you're giving a talk about CRIU -- let us know, we'll mention it on the [wiki main page](https://criu.org/News/events); From 2237666ac1d277051d2bb90796fb1a0c5febb885 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 12 Nov 2019 14:31:08 +0300 Subject: [PATCH 2259/4375] restorer/inotify: reorder inotify cleanup after waiting helpers and zombies We've seen ppoll interrupted with signal in VZ7 CT migration tests, that is because in the beggining of CR_STATE_RESTORE_SIGCHLD zombies and helpers die, and that can trigger SIGCHILDs sent to their parents. Adding additional debug (printing "Task..." for zombies and helpers) in sigchld_handler I see: (15.644339) pie: 1: Task 10718 exited, status= 0 (15.644349) pie: 1: Cleaning inotify events from 29 (15.644359) pie: 1: Cleaning inotify events from 19 (15.644367) pie: 1: Cleaning inotify events from 10 And previousely we had: (05.718449) pie: 104: Cleaning inotify events from 5 (05.718835) pie: 330: Cleaning inotify events from 3 (05.719046) pie: 1: Cleaning inotify events from 23 (05.719164) pie: 80: Cleaning inotify events from 7 (05.719185) pie: 1: Error (criu/pie/restorer.c:1287): Failed to poll from inotify fd: -4 (05.719202) pie: 95: Cleaning inotify events from 6 (05.719269) pie: 1: Error (criu/pie/restorer.c:1890): Restorer fail 1 So reordering cleanup and wait should fix it. Signed-off-by: Pavel Tikhomirov --- criu/pie/restorer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index dab58add6..888eb8e65 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1839,9 +1839,6 @@ long __export_restore_task(struct task_restore_args *args) restore_finish_stage(task_entries_local, CR_STATE_RESTORE); - if (cleanup_current_inotify_events(args)) - goto core_restore_end; - if (wait_helpers(args) < 0) goto core_restore_end; if (wait_zombies(args) < 0) @@ -1854,6 +1851,9 @@ long __export_restore_task(struct task_restore_args *args) goto core_restore_end; } + if (cleanup_current_inotify_events(args)) + goto core_restore_end; + if (!args->compatible_mode) { ret = sys_sigaction(SIGCHLD, &args->sigchld_act, NULL, sizeof(k_rtsigset_t)); From 1d23dc4a3042599cabea90a81c063db453b89abb Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 29 Nov 2019 10:57:29 +0300 Subject: [PATCH 2260/4375] mount: Order call_helper_process calls When we do clone threads in a later stage of restore procedure it may race with helpers which do call clone_noasan by self. Thus we need to walk over each clone_noasan call and figure out if calling it without last_pid lock is safe. - open_mountpoint: called by fusectl_dump, dump_empty_fs, binfmt_misc_dump, tmpfs_dump -- they all are processing dump stage, thus safe - call_helper_process: try_remount_writable -- called from various places in reg-files.c, in particular open_reg_by_id called in parallel with other threads, needs a lock remount_readonly_mounts -- called from sigreturn_restore, so in parallel, needs a lock - call_in_child_process: prepare_net_namespaces -- called from prepare_namespace which runs before we start forking, no need for lock Thus call_helper_process should use lock_last_pid and unlock_last_pid helpers and wait for subprocess to finish. Same time put a warning text into clone_noasan comment so next time we need to use it we would recall the pitfalls. v2: - fix unitialized ret variable v3: - use exit_code instead of ret Signed-off-by: Cyrill Gorcunov --- criu/clone-noasan.c | 9 +++++++++ criu/mount.c | 21 ++++++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/criu/clone-noasan.c b/criu/clone-noasan.c index 5ca280eb8..5f1858d4d 100644 --- a/criu/clone-noasan.c +++ b/criu/clone-noasan.c @@ -18,6 +18,15 @@ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69863 * * So the only way is to put this wrapper in separate non-instrumented file + * + * WARNING: When calling clone_noasan make sure your not sitting in a later + * __restore__ phase where other tasks might be creating threads, otherwise + * all calls to clone_noasan should be guarder with + * + * lock_last_pid + * clone_noasan + * ... wait for process to finish ... + * unlock_last_pid */ int clone_noasan(int (*fn)(void *), int flags, void *arg) { diff --git a/criu/mount.c b/criu/mount.c index 52e70d376..24a8516c6 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -3738,27 +3738,38 @@ struct ns_desc mnt_ns_desc = NS_DESC_ENTRY(CLONE_NEWNS, "mnt"); static int call_helper_process(int (*call)(void *), void *arg) { - int pid, status; + int pid, status, exit_code = -1; + + /* + * Running new helper process on the restore must be + * done under last_pid mutex: other tasks may be restoring + * threads and the PID we need there might be occupied by + * this clone() call. + */ + lock_last_pid(); pid = clone_noasan(call, CLONE_VFORK | CLONE_VM | CLONE_FILES | CLONE_IO | CLONE_SIGHAND | CLONE_SYSVSEM, arg); if (pid == -1) { pr_perror("Can't clone helper process"); - return -1; + goto out; } errno = 0; if (waitpid(pid, &status, __WALL) != pid) { pr_perror("Unable to wait %d", pid); - return -1; + goto out; } if (status) { pr_err("Bad child exit status: %d\n", status); - return -1; + goto out; } - return 0; + exit_code = 0; +out: + unlock_last_pid(); + return exit_code; } static int ns_remount_writable(void *arg) From ebe3b52353c5d380d01c332e7d57594995258c18 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 14 Nov 2019 14:41:04 +0300 Subject: [PATCH 2261/4375] unix: sysctl -- Preserve max_dgram_qlen value The /proc/sys/net/unix/max_dgram_qlen is a per-net variable and we already noticed that systemd inside a container may change its value (for example it sets it to 512 by now instead of kernel's default value 10), thus we need keep it inside image and restore then. Signed-off-by: Cyrill Gorcunov Signed-off-by: Alexander Mikhalitsyn Signed-off-by: Alexander Mikhalitsyn --- criu/net.c | 104 +++++++++++++++++++++++++++++++++++++++++++- images/netdev.proto | 1 + 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/criu/net.c b/criu/net.c index 5822de629..e960a34f9 100644 --- a/criu/net.c +++ b/criu/net.c @@ -210,6 +210,19 @@ char *devconfs6[] = { #define MAX_CONF_OPT_PATH IFNAMSIZ+60 #define MAX_STR_CONF_LEN 200 +static const char *unix_conf_entries[] = { + "max_dgram_qlen", +}; + +/* + * MAX_CONF_UNIX_PATH = (sizeof(CONF_UNIX_FMT) - strlen("%s")) + * + MAX_CONF_UNIX_OPT_PATH + */ +#define CONF_UNIX_BASE "net/unix" +#define CONF_UNIX_FMT CONF_UNIX_BASE"/%s" +#define MAX_CONF_UNIX_OPT_PATH 32 +#define MAX_CONF_UNIX_PATH (sizeof(CONF_UNIX_FMT) + MAX_CONF_UNIX_OPT_PATH - 2) + static int net_conf_op(char *tgt, SysctlEntry **conf, int n, int op, char *proto, struct sysctl_req *req, char (*path)[MAX_CONF_OPT_PATH], int size, char **devconfs, SysctlEntry **def_conf) @@ -339,6 +352,72 @@ static int ipv6_conf_op(char *tgt, SysctlEntry **conf, int n, int op, SysctlEntr devconfs6, def_conf); } +static int unix_conf_op(SysctlEntry ***rconf, size_t *n, int op) +{ + int i, ret = -1, flags = 0; + char path[ARRAY_SIZE(unix_conf_entries)][MAX_CONF_UNIX_PATH] = { }; + struct sysctl_req req[ARRAY_SIZE(unix_conf_entries)] = { }; + SysctlEntry **conf = *rconf; + + if (*n != ARRAY_SIZE(unix_conf_entries)) { + pr_err("unix: Unexpected entries in config (%zu %zu)\n", + *n, ARRAY_SIZE(unix_conf_entries)); + return -EINVAL; + } + + if (opts.weak_sysctls || op == CTL_READ) + flags = CTL_FLAGS_OPTIONAL; + + for (i = 0; i < *n; i++) { + snprintf(path[i], MAX_CONF_UNIX_PATH, CONF_UNIX_FMT, + unix_conf_entries[i]); + req[i].name = path[i]; + req[i].flags = flags; + + switch (conf[i]->type) { + case SYSCTL_TYPE__CTL_32: + req[i].type = CTL_32; + req[i].arg = &conf[i]->iarg; + break; + default: + pr_err("unix: Unknown config type %d\n", + conf[i]->type); + return -1; + } + } + + ret = sysctl_op(req, *n, op, CLONE_NEWNET); + if (ret < 0) { + pr_err("unix: Failed to %s %s/\n", + (op == CTL_READ) ? "read" : "write", + CONF_UNIX_BASE); + return -1; + } + + if (op == CTL_READ) { + bool has_entries = false; + + for (i = 0; i < *n; i++) { + if (req[i].flags & CTL_FLAGS_HAS) { + conf[i]->has_iarg = true; + if (!has_entries) + has_entries = true; + } + } + + /* + * Zap the whole section of data. + * Unix conf is optional. + */ + if (!has_entries) { + *n = 0; + *rconf = NULL; + } + } + + return 0; +} + /* * I case if some entry is missing in * the kernel, simply write DEVCONFS_UNUSED @@ -1824,6 +1903,8 @@ static int dump_netns_conf(struct ns_id *ns, struct cr_imgset *fds) int ret = -1; int i; NetnsEntry netns = NETNS_ENTRY__INIT; + SysctlEntry *unix_confs = NULL; + size_t sizex = ARRAY_SIZE(unix_conf_entries); SysctlEntry *def_confs4 = NULL, *all_confs4 = NULL; int size4 = ARRAY_SIZE(devconfs4); SysctlEntry *def_confs6 = NULL, *all_confs6 = NULL; @@ -1840,7 +1921,8 @@ static int dump_netns_conf(struct ns_id *ns, struct cr_imgset *fds) o_buf = buf = xmalloc( i * (sizeof(NetnsId*) + sizeof(NetnsId)) + size4 * (sizeof(SysctlEntry*) + sizeof(SysctlEntry)) * 2 + - size6 * (sizeof(SysctlEntry*) + sizeof(SysctlEntry)) * 2 + size6 * (sizeof(SysctlEntry*) + sizeof(SysctlEntry)) * 2 + + sizex * (sizeof(SysctlEntry*) + sizeof(SysctlEntry)) ); if (!buf) goto out; @@ -1896,6 +1978,16 @@ static int dump_netns_conf(struct ns_id *ns, struct cr_imgset *fds) } } + netns.n_unix_conf = sizex; + netns.unix_conf = xptr_pull_s(&buf, sizex * sizeof(SysctlEntry*)); + unix_confs = xptr_pull_s(&buf, sizex * sizeof(SysctlEntry)); + + for (i = 0; i < sizex; i++) { + sysctl_entry__init(&unix_confs[i]); + netns.unix_conf[i] = &unix_confs[i]; + netns.unix_conf[i]->type = SYSCTL_TYPE__CTL_32; + } + ret = ipv4_conf_op("default", netns.def_conf4, size4, CTL_READ, NULL); if (ret < 0) goto err_free; @@ -1910,6 +2002,10 @@ static int dump_netns_conf(struct ns_id *ns, struct cr_imgset *fds) if (ret < 0) goto err_free; + ret = unix_conf_op(&netns.unix_conf, &netns.n_unix_conf, CTL_READ); + if (ret < 0) + goto err_free; + ret = pb_write_one(img_from_set(fds, CR_FD_NETNS), &netns, PB_NETNS); err_free: xfree(o_buf); @@ -2122,6 +2218,12 @@ static int restore_netns_conf(struct ns_id *ns) ret = ipv6_conf_op("default", (netns)->def_conf6, (netns)->n_def_conf6, CTL_WRITE, NULL); } + if ((netns)->unix_conf) { + ret = unix_conf_op(&(netns)->unix_conf, &(netns)->n_unix_conf, CTL_WRITE); + if (ret) + goto out; + } + ns->net.netns = netns; out: return ret; diff --git a/images/netdev.proto b/images/netdev.proto index 476a92ced..ae9c99531 100644 --- a/images/netdev.proto +++ b/images/netdev.proto @@ -71,4 +71,5 @@ message netns_entry { repeated netns_id nsids = 7; optional string ext_key = 8; + repeated sysctl_entry unix_conf = 9; } From 55f7a571f286baa6eac6fe7a020914505a0eb464 Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Thu, 14 Nov 2019 14:50:43 +0300 Subject: [PATCH 2262/4375] zdtm: sysctl net.unix.max_dgram_qlen value preservation test Test checks that if the /proc/sys/net/unix/max_dgram_qlen value has been changed in process net namespace, then it is saved after c/r. Signed-off-by: Alexander Mikhalitsyn Signed-off-by: Alexander Mikhalitsyn --- test/zdtm/lib/Makefile | 2 +- test/zdtm/lib/sysctl.c | 59 ++++++++++++++++++++++++++ test/zdtm/lib/sysctl.h | 7 +++ test/zdtm/static/Makefile | 1 + test/zdtm/static/netns_sub_sysctl.c | 56 ++++++++++++++++++++++++ test/zdtm/static/netns_sub_sysctl.desc | 4 ++ 6 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 test/zdtm/lib/sysctl.c create mode 100644 test/zdtm/lib/sysctl.h create mode 100644 test/zdtm/static/netns_sub_sysctl.c create mode 100644 test/zdtm/static/netns_sub_sysctl.desc diff --git a/test/zdtm/lib/Makefile b/test/zdtm/lib/Makefile index d2d9f1cc3..b87f36e8f 100644 --- a/test/zdtm/lib/Makefile +++ b/test/zdtm/lib/Makefile @@ -4,7 +4,7 @@ CFLAGS += $(USERCFLAGS) LIB := libzdtmtst.a -LIBSRC := datagen.c msg.c parseargs.c test.c streamutil.c lock.c ns.c tcp.c fs.c +LIBSRC := datagen.c msg.c parseargs.c test.c streamutil.c lock.c ns.c tcp.c fs.c sysctl.c LIBOBJ := $(LIBSRC:%.c=%.o) BIN := groups diff --git a/test/zdtm/lib/sysctl.c b/test/zdtm/lib/sysctl.c new file mode 100644 index 000000000..9583ec3df --- /dev/null +++ b/test/zdtm/lib/sysctl.c @@ -0,0 +1,59 @@ +#include + +#include "zdtmtst.h" +#include "sysctl.h" + +int sysctl_read_int(const char *name, int *data) +{ + int fd; + int ret; + char buf[16]; + + fd = open(name, O_RDONLY); + if (fd < 0) { + pr_perror("Can't open %s", name); + return fd; + } + + ret = read(fd, buf, sizeof(buf) - 1); + if (ret < 0) { + pr_perror("Can't read %s", name); + ret = -errno; + goto err; + } + + buf[ret] = '\0'; + + *data = (int)strtoul(buf, NULL, 10); + ret = 0; +err: + close(fd); + return ret; +} + +int sysctl_write_int(const char *name, int val) +{ + int fd; + int ret; + char buf[16]; + + fd = open(name, O_WRONLY); + if (fd < 0) { + pr_perror("Can't open %s", name); + return fd; + } + + sprintf(buf, "%d\n", val); + + ret = write(fd, buf, strlen(buf)); + if (ret < 0) { + pr_perror("Can't write %d into %s", val, name); + ret = -errno; + goto err; + } + + ret = 0; +err: + close(fd); + return ret; +} diff --git a/test/zdtm/lib/sysctl.h b/test/zdtm/lib/sysctl.h new file mode 100644 index 000000000..67129102f --- /dev/null +++ b/test/zdtm/lib/sysctl.h @@ -0,0 +1,7 @@ +#ifndef __ZDTM_SYSCTL__ +#define __ZDTM_SYSCTL__ + +extern int sysctl_read_int(const char *name, int *data); +extern int sysctl_write_int(const char *name, int val); + +#endif diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 36d00ca5c..f9d2efe74 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -207,6 +207,7 @@ TST_NOFILE := \ pipe03 \ netns_sub \ netns_sub_veth \ + netns_sub_sysctl \ unlink_multiple_largefiles \ config_inotify_irmap \ thp_disable \ diff --git a/test/zdtm/static/netns_sub_sysctl.c b/test/zdtm/static/netns_sub_sysctl.c new file mode 100644 index 000000000..bf828e08e --- /dev/null +++ b/test/zdtm/static/netns_sub_sysctl.c @@ -0,0 +1,56 @@ +#include + +#include "zdtmtst.h" +#include "sysctl.h" + +const char *test_doc = "Check dump and restore a net.unix.max_dgram_qlen sysctl parameter in subns"; +const char *test_author = "Alexander Mikhalitsyn "; + +typedef struct { + const char *path; + int old; + int new; +} sysctl_opt_t; + +#define CONF_UNIX_BASE "/proc/sys/net/unix" + +static sysctl_opt_t net_unix_params[] = { + {CONF_UNIX_BASE"/max_dgram_qlen", 0, 0}, + {NULL, 0, 0} +}; + +int main(int argc, char **argv) +{ + int ret = 0; + sysctl_opt_t *p; + test_init(argc, argv); + + for (p = net_unix_params; p->path != NULL; p++) { + p->old = (((unsigned)lrand48()) % 1023) + 1; + if (sysctl_write_int(p->path, p->old)) { + pr_perror("Can't change %s", p->path); + return -1; + } + } + + test_daemon(); + test_waitsig(); + + for (p = net_unix_params; p->path != NULL; p++) { + if (sysctl_read_int(p->path, &p->new)) + ret = 1; + + if (p->old != p->new) { + errno = EINVAL; + pr_perror("%s changed: %d ---> %d", p->path, p->old, p->new); + ret = 1; + } + } + + if (ret) + fail(); + else + pass(); + + return ret; +} diff --git a/test/zdtm/static/netns_sub_sysctl.desc b/test/zdtm/static/netns_sub_sysctl.desc new file mode 100644 index 000000000..535842668 --- /dev/null +++ b/test/zdtm/static/netns_sub_sysctl.desc @@ -0,0 +1,4 @@ +{ + 'flavor': 'ns', + 'flags': 'suid' +} From 4c46cbc4d86c7578b98e64b8f664cf9c0b0fe978 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 16 Dec 2019 15:34:10 +0300 Subject: [PATCH 2263/4375] x86/cpu: cleanup and improve xfeatures_mask check Make xfeatures_mask check explicit. We were relying on our guess about hardware "backward compatibility" and used ">" check here for a long time. But it looks better to explicitly check that all xfeature bits available on the source are also available on the destination. For xsave_size we need to have smaller size on destination than on source, because xsave operation on small allocated buffer may corrupt the nearby data. So split up comments about xfeatures_mask and xsave_size, as having single comment for quiet a different cases is less understandable. v2: improve comments, remove extra else-ifs, remove extra typecast Signed-off-by: Pavel Tikhomirov --- criu/arch/x86/cpu.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index 3808b9d33..72c5bd59c 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -236,6 +236,7 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) return -1; if (opts.cpu_cap & CPU_CAP_FPU) { + uint64_t m; /* * If we're requested to check FPU only ignore * any other bit. It's up to a user if the @@ -261,24 +262,33 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info) #undef __mismatch_fpu_bit /* - * Make sure the xsave features are compatible. We already hit the - * issue with libc where we've checkpointed the container on old - * machine but restored on more modern one and libc fetched new - * xsave frame size directly by xsave instruction with greedy - * feature mask causing programs to misbehave. + * Make sure the xsave features are compatible. Check that on + * the destination there are all the features which were on the + * source. */ - if (cpu_info->xfeatures_mask > rt_cpu_info.xfeatures_mask) { - uint64_t m = cpu_info->xfeatures_mask & ~rt_cpu_info.xfeatures_mask; - pr_err("CPU xfeatures has unsupported bits (%#llx)\n", - (unsigned long long)m); + if ((m = cpu_info->xfeatures_mask & + ~rt_cpu_info.xfeatures_mask)) { + pr_err("CPU xfeatures has unsupported bits (%#" + PRIx64")\n", m); return -1; - } else if (cpu_info->xsave_size != rt_cpu_info.xsave_size) { + } + + /* + * Make sure the xsave sizes are compatible. We already hit the + * issue with libc where we've checkpointed the container on + * old machine but restored on more modern one and libc fetched + * new xsave frame size directly by xsave instruction with + * greedy feature mask causing programs to misbehave. + */ + if (cpu_info->xsave_size != rt_cpu_info.xsave_size) { pr_err("CPU xsave size mismatch (%u/%u)\n", cpu_info->xsave_size, rt_cpu_info.xsave_size); return -1; - } else if (cpu_info->xsave_size_max != rt_cpu_info.xsave_size_max) { + } + if (cpu_info->xsave_size_max != rt_cpu_info.xsave_size_max) { pr_err("CPU xsave max size mismatch (%u/%u)\n", - cpu_info->xsave_size_max, rt_cpu_info.xsave_size_max); + cpu_info->xsave_size_max, + rt_cpu_info.xsave_size_max); return -1; } } From 2e656222d78fecc1bf6490bed59078083bdb4351 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 18 Dec 2019 23:32:32 +0000 Subject: [PATCH 2264/4375] crit: fix python3 encoding issues Signed-off-by: Nicolas Viennot --- lib/py/images/images.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/py/images/images.py b/lib/py/images/images.py index f4517d845..3eedfca69 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -244,7 +244,7 @@ class ghost_file_handler: while True: gc = pb.ghost_chunk_entry() buf = f.read(4) - if buf == '': + if len(buf) == 0: break size, = struct.unpack('i', buf) gc.ParseFromString(f.read(size)) @@ -252,13 +252,13 @@ class ghost_file_handler: if no_payload: f.seek(gc.len, os.SEEK_CUR) else: - entry['extra'] = base64.encodebytes(f.read(gc.len)) + entry['extra'] = base64.encodebytes(f.read(gc.len)).decode('utf-8') entries.append(entry) else: if no_payload: f.seek(0, os.SEEK_END) else: - g_entry['extra'] = base64.encodebytes(f.read()) + g_entry['extra'] = base64.encodebytes(f.read()).decode('utf-8') entries.append(g_entry) return entries From 00bb068785a8b1a7c4481e2e7f2c0b9f903d941b Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 20 Dec 2019 18:09:15 +0000 Subject: [PATCH 2265/4375] scripts: alpine: Install py2 packages with pip The py-future package has been renamed to py3-future [1] and py2 package for yaml has been dropped [2]. [1] https://git.alpinelinux.org/aports/commit/main?id=316d44abaed13964e97eb43c095cd1b64e3943ad [2] https://git.alpinelinux.org/aports/commit/main?id=e369c1fd7707a73f2c3e2b11b613198d9a4106de Signed-off-by: Radostin Stoyanov --- scripts/build/Dockerfile.alpine | 4 +--- scripts/build/Dockerfile.openj9-alpine | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index 70fdf480a..a1d1d9191 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -27,9 +27,7 @@ RUN mv .ccache /tmp && make mrproper && ccache -sz && \ date && make -j $(nproc) CC="$CC" && date && ccache -s RUN apk add \ - py-yaml \ py-pip \ - py2-future \ ip6tables \ iptables \ iproute2 \ @@ -42,5 +40,5 @@ RUN apk add \ # The rpc test cases are running as user #1000, let's add the user RUN adduser -u 1000 -D test -RUN pip install protobuf ipaddress junit_xml flake8 +RUN pip install PyYAML future protobuf ipaddress junit_xml flake8 RUN make -C test/zdtm diff --git a/scripts/build/Dockerfile.openj9-alpine b/scripts/build/Dockerfile.openj9-alpine index 654e7bf31..43a993444 100644 --- a/scripts/build/Dockerfile.openj9-alpine +++ b/scripts/build/Dockerfile.openj9-alpine @@ -17,9 +17,6 @@ RUN apk update && apk add \ python \ sudo \ maven \ - py-yaml \ - py-pip \ - py2-future \ ip6tables \ iptables \ bash From 0980617e24004ea00e4e0841c97b138f0a4e0073 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 12 Dec 2019 23:04:30 +0000 Subject: [PATCH 2266/4375] sockets: Remove duplicate variable assignment Signed-off-by: Radostin Stoyanov --- criu/sockets.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/criu/sockets.c b/criu/sockets.c index 312b55c6d..80f3153ba 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -524,7 +524,7 @@ int restore_prepare_socket(int sk) int restore_socket_opts(int sk, SkOptsEntry *soe) { - int ret = 0, val; + int ret = 0, val = 1; struct timeval tv; /* In kernel a bufsize value is doubled. */ u32 bufs[2] = { soe->so_sndbuf / 2, soe->so_rcvbuf / 2}; @@ -547,27 +547,22 @@ int restore_socket_opts(int sk, SkOptsEntry *soe) ret |= restore_opt(sk, SOL_SOCKET, SO_MARK, &soe->so_mark); } if (soe->has_so_passcred && soe->so_passcred) { - val = 1; pr_debug("\tset passcred for socket\n"); ret |= restore_opt(sk, SOL_SOCKET, SO_PASSCRED, &val); } if (soe->has_so_passsec && soe->so_passsec) { - val = 1; pr_debug("\tset passsec for socket\n"); ret |= restore_opt(sk, SOL_SOCKET, SO_PASSSEC, &val); } if (soe->has_so_dontroute && soe->so_dontroute) { - val = 1; pr_debug("\tset dontroute for socket\n"); ret |= restore_opt(sk, SOL_SOCKET, SO_DONTROUTE, &val); } if (soe->has_so_no_check && soe->so_no_check) { - val = 1; pr_debug("\tset no_check for socket\n"); ret |= restore_opt(sk, SOL_SOCKET, SO_NO_CHECK, &val); } if (soe->has_so_broadcast && soe->so_broadcast) { - val = 1; pr_debug("\tset broadcast for socket\n"); ret |= restore_opt(sk, SOL_SOCKET, SO_BROADCAST, &val); } From d4e6fc2a0dcff62ff246544d3d9a78d6961f253a Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 13 Dec 2019 00:10:28 +0000 Subject: [PATCH 2267/4375] socket: c/r support for SO_KEEPALIVE TCP keepalive packets can be used to determine if a connection is still valid. When the SO_KEEPALIVE option is set, TCP packets are periodically sent to keep the connection alive. This patch implements checkpoint/restore support for SO_KEEPALIVE, TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT options. Signed-off-by: Radostin Stoyanov --- criu/include/sk-inet.h | 2 +- criu/sk-inet.c | 6 +++++- criu/sk-tcp.c | 20 +++++++++++++++++++- criu/sockets.c | 20 ++++++++++++++++++++ images/sk-opts.proto | 4 ++++ 5 files changed, 49 insertions(+), 3 deletions(-) diff --git a/criu/include/sk-inet.h b/criu/include/sk-inet.h index 79966517b..dec67ca6c 100644 --- a/criu/include/sk-inet.h +++ b/criu/include/sk-inet.h @@ -83,7 +83,7 @@ extern void tcp_locked_conn_add(struct inet_sk_info *); extern void rst_unlock_tcp_connections(void); extern void cpt_unlock_tcp_connections(void); -extern int dump_one_tcp(int sk, struct inet_sk_desc *sd); +extern int dump_one_tcp(int sk, struct inet_sk_desc *sd, SkOptsEntry *soe); extern int restore_one_tcp(int sk, struct inet_sk_info *si); #define SK_EST_PARAM "tcp-established" diff --git a/criu/sk-inet.c b/criu/sk-inet.c index f9c64c7af..342548585 100644 --- a/criu/sk-inet.c +++ b/criu/sk-inet.c @@ -551,7 +551,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa switch (proto) { case IPPROTO_TCP: - err = (type != SOCK_RAW) ? dump_one_tcp(lfd, sk) : 0; + err = (type != SOCK_RAW) ? dump_one_tcp(lfd, sk, &skopts) : 0; break; case IPPROTO_UDP: case IPPROTO_UDPLITE: @@ -747,6 +747,10 @@ static int post_open_inet_sk(struct file_desc *d, int sk) if (!val && restore_opt(sk, SOL_SOCKET, SO_BROADCAST, &val)) return -1; + val = ii->ie->opts->so_keepalive; + if (!val && restore_opt(sk, SOL_SOCKET, SO_KEEPALIVE, &val)) + return -1; + return 0; } diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c index 4fd2eb8e6..7ee603818 100644 --- a/criu/sk-tcp.c +++ b/criu/sk-tcp.c @@ -218,8 +218,26 @@ err_r: return ret; } -int dump_one_tcp(int fd, struct inet_sk_desc *sk) +int dump_one_tcp(int fd, struct inet_sk_desc *sk, SkOptsEntry *soe) { + soe->has_tcp_keepcnt = true; + if (dump_opt(fd, SOL_TCP, TCP_KEEPCNT, &soe->tcp_keepcnt)) { + pr_perror("Can't read TCP_KEEPCNT"); + return -1; + } + + soe->has_tcp_keepidle = true; + if (dump_opt(fd, SOL_TCP, TCP_KEEPIDLE, &soe->tcp_keepidle)) { + pr_perror("Can't read TCP_KEEPIDLE"); + return -1; + } + + soe->has_tcp_keepintvl = true; + if (dump_opt(fd, SOL_TCP, TCP_KEEPINTVL, &soe->tcp_keepintvl)) { + pr_perror("Can't read TCP_KEEPINTVL"); + return -1; + } + if (sk->dst_port == 0) return 0; diff --git a/criu/sockets.c b/criu/sockets.c index 80f3153ba..2e1ce9d7b 100644 --- a/criu/sockets.c +++ b/criu/sockets.c @@ -566,6 +566,22 @@ int restore_socket_opts(int sk, SkOptsEntry *soe) pr_debug("\tset broadcast for socket\n"); ret |= restore_opt(sk, SOL_SOCKET, SO_BROADCAST, &val); } + if (soe->has_so_keepalive && soe->so_keepalive) { + pr_debug("\tset keepalive for socket\n"); + ret |= restore_opt(sk, SOL_SOCKET, SO_KEEPALIVE, &val); + } + if (soe->has_tcp_keepcnt) { + pr_debug("\tset keepcnt for socket\n"); + ret |= restore_opt(sk, SOL_TCP, TCP_KEEPCNT, &soe->tcp_keepcnt); + } + if (soe->has_tcp_keepidle) { + pr_debug("\tset keepidle for socket\n"); + ret |= restore_opt(sk, SOL_TCP, TCP_KEEPIDLE, &soe->tcp_keepidle); + } + if (soe->has_tcp_keepintvl) { + pr_debug("\tset keepintvl for socket\n"); + ret |= restore_opt(sk, SOL_TCP, TCP_KEEPINTVL, &soe->tcp_keepintvl); + } tv.tv_sec = soe->so_snd_tmo_sec; tv.tv_usec = soe->so_snd_tmo_usec; @@ -651,6 +667,10 @@ int dump_socket_opts(int sk, SkOptsEntry *soe) soe->has_so_broadcast = true; soe->so_broadcast = val ? true : false; + ret |= dump_opt(sk, SOL_SOCKET, SO_KEEPALIVE, &val); + soe->has_so_keepalive = true; + soe->so_keepalive = val ? true : false; + ret |= dump_bound_dev(sk, soe); ret |= dump_socket_filter(sk, soe); diff --git a/images/sk-opts.proto b/images/sk-opts.proto index c93ec5fd5..336cca22a 100644 --- a/images/sk-opts.proto +++ b/images/sk-opts.proto @@ -23,6 +23,10 @@ message sk_opts_entry { repeated fixed64 so_filter = 16; optional bool so_reuseport = 17; optional bool so_broadcast = 18; + optional bool so_keepalive = 19; + optional uint32 tcp_keepcnt = 20; + optional uint32 tcp_keepidle = 21; + optional uint32 tcp_keepintvl = 22; } enum sk_shutdown { From 8b467dd944f6b3bed0a468800b041efdb218d6e8 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 13 Dec 2019 04:01:36 +0000 Subject: [PATCH 2268/4375] zdtm: Add test for SO_KEEPALIVE Signed-off-by: Radostin Stoyanov --- test/zdtm/static/Makefile | 3 +- test/zdtm/static/socket-tcp-keepalive.c | 97 +++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 test/zdtm/static/socket-tcp-keepalive.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index f9d2efe74..ea5d3c42e 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -105,7 +105,8 @@ TST_NOFILE := \ socket-tcp-unconn \ socket-tcp6-unconn \ socket-tcp-syn-sent \ - socket-tcp-skip-in-flight \ + socket-tcp-skip-in-flight \ + socket-tcp-keepalive \ sock_opts00 \ sock_opts01 \ sk-unix-unconn \ diff --git a/test/zdtm/static/socket-tcp-keepalive.c b/test/zdtm/static/socket-tcp-keepalive.c new file mode 100644 index 000000000..a977a03b5 --- /dev/null +++ b/test/zdtm/static/socket-tcp-keepalive.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "test checkpoint/restore of SO_KEEPALIVE\n"; +const char *test_author = "Radostin Stoyanov \n"; + +int main(int argc, char **argv) +{ + int sk; + int alive = 1; + int cnt = 5; + int idle = 10; + int intvl = 15; + int optval; + socklen_t optlen; + + test_init(argc, argv); + + sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sk < 0) { + pr_perror("Can't create socket"); + return 1; + } + + /* Set the option active */ + if (setsockopt(sk, SOL_SOCKET, SO_KEEPALIVE, &alive, sizeof(alive)) < 0) { + pr_perror("setsockopt SO_KEEPALIVE"); + return 1; + } + + if (setsockopt(sk, SOL_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)) < 0) { + pr_perror("setsockopt TCP_KEEPCNT"); + return 1; + } + + if (setsockopt(sk, SOL_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)) < 0) { + pr_perror("setsockopt TCP_KEEPIDLE"); + return 1; + } + + optval = 5; + optlen = sizeof(optval); + if (setsockopt(sk, SOL_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)) < 0) { + pr_perror("setsockopt TCP_KEEPINTVL"); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (getsockopt(sk, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen)) { + pr_perror("getsockopt SO_KEEPALIVE"); + return 1; + } + + if (optlen != sizeof(optval) || optval != alive) { + fail("SO_KEEPALIVE not set"); + return 1; + } + + if (getsockopt(sk, SOL_TCP, TCP_KEEPCNT, &optval, &optlen) < 0) { + pr_perror("getsockopt TCP_KEEPCNT"); + return 1; + } + + if (optval != cnt) { + fail("TCP_KEEPCNT has incorrect value (%d != %d)", cnt, optval); + return 1; + } + + if (getsockopt(sk, SOL_TCP, TCP_KEEPIDLE, &optval, &optlen) < 0) { + pr_perror("getsockopt TCP_KEEPIDLE"); + return 1; + } + + if (optval != idle) { + fail("TCP_KEEPIDLE has incorrect value (%d != %d)", idle, optval); + return 1; + } + + if (getsockopt(sk, SOL_TCP, TCP_KEEPINTVL, &optval, &optlen) < 0) { + pr_perror("getsockopt TCP_KEEPINTVL"); + return 1; + } + + if (optval != intvl) { + fail("TCP_KEEPINTVL has incorrect value (%d != %d)", intvl, optval); + return 1; + } + + pass(); + return 0; +} \ No newline at end of file From 79559bef92b524911b766d674ac8bc4470b8b378 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Fri, 20 Dec 2019 17:50:37 +0100 Subject: [PATCH 2269/4375] Fix tests on Ubuntu It seems like Ubuntu introduced a overlayfs change which breaks CRIU: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1857257 This disables overlayfs (unfortunately) in most tests by switching to devicemapper or vfs. Upstream kernels do not seem to have this problem. This also adds the 'docker-test' for xenial which still has a working overlayfs from CRIU's point of view. Also adjust Podman Ubuntu package location Podman Ubuntu packages are now available via OBS and no longer via PPA. Signed-off-by: Adrian Reber --- .travis.yml | 13 +++++++++++-- scripts/travis/Makefile | 5 ++++- scripts/travis/docker-test.sh | 15 ++++++++++----- scripts/travis/podman-test.sh | 13 ++++++++++--- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index e6e410191..25dd6a29b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,6 @@ env: - TR_ARCH=local CLANG=1 COMPAT_TEST=y - TR_ARCH=x86_64 - TR_ARCH=x86_64 CLANG=1 - - TR_ARCH=docker-test - TR_ARCH=openj9-test matrix: include: @@ -57,6 +56,16 @@ matrix: arch: amd64 env: TR_ARCH=podman-test dist: bionic + - os: linux + arch: amd64 + env: TR_ARCH=docker-test + dist: bionic + - os: linux + arch: amd64 + env: TR_ARCH=docker-test DIST=xenial + # On xenial it should be possible to test overlayfs; + # broken on the latest bionic kernel + dist: xenial - os: linux arch: amd64 env: TR_ARCH=alpine CLANG=1 @@ -79,9 +88,9 @@ matrix: dist: bionic allow_failures: - env: TR_ARCH=docker-test + - env: TR_ARCH=docker-test DIST=xenial - env: TR_ARCH=fedora-rawhide - env: TR_ARCH=local GCOV=1 - - env: TR_ARCH=podman-test script: - sudo make CCACHE=1 -C scripts/travis $TR_ARCH after_success: diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index 373171149..17abb703a 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -58,7 +58,10 @@ docker-test: podman-test: ./podman-test.sh -openj9-test: +# overlayfs behaves differently on Ubuntu and breaks CRIU +# https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1857257 +# Switch to devicemapper +openj9-test: restart-docker ./openj9-test.sh %: diff --git a/scripts/travis/docker-test.sh b/scripts/travis/docker-test.sh index ee96fef48..ac420a445 100755 --- a/scripts/travis/docker-test.sh +++ b/scripts/travis/docker-test.sh @@ -19,11 +19,16 @@ apt-get update -qq apt-get install -qq docker-ce -cat > /etc/docker/daemon.json < /etc/docker/daemon.json +else + echo '{ "experimental": true }' > /etc/docker/daemon.json +fi service docker restart diff --git a/scripts/travis/podman-test.sh b/scripts/travis/podman-test.sh index eafdc73be..5189477cd 100755 --- a/scripts/travis/podman-test.sh +++ b/scripts/travis/podman-test.sh @@ -1,7 +1,13 @@ #!/bin/bash set -x -e -o pipefail -add-apt-repository -y ppa:projectatomic/ppa +echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_18.04/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list + +wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/xUbuntu_18.04/Release.key -O- | apt-key add - + +# podman conflicts with a man page from docker-ce +# this is a podman packaging bug (https://github.com/containers/libpod/issues/4747) +apt-get -y purge docker-ce apt-get install -qq \ apt-transport-https \ @@ -10,7 +16,6 @@ apt-get install -qq \ software-properties-common apt-get update -qq - apt-get install -qqy podman containernetworking-plugins export SKIP_TRAVIS_TEST=1 @@ -21,7 +26,9 @@ cd ../../ make install -podman info +# overlaysfs behaves differently on Ubuntu and breaks CRIU +# https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1857257 +podman --storage-driver vfs info criu --version From 8bb3c17a0f7f14baaed8d9b6ebf953c24a793ccc Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 21 Dec 2019 18:08:23 +0000 Subject: [PATCH 2270/4375] style: Enforce kernel style -Wdeclaration-after-statement Include warnings that the kernel uses during compilation: -Wdeclaration-after-statement: enforces having variables declared at the top of scopes Signed-off-by: Nicolas Viennot [Generated a commit message from the pull request] Signed-off-by: Dmitry Safonov --- Makefile | 2 +- criu/net.c | 7 +++++-- criu/page-xfer.c | 10 +++++----- criu/pie/util-vdso.c | 3 ++- test/zdtm/Makefile.inc | 1 + test/zdtm/static/arm-neon00.c | 11 +++++----- test/zdtm/static/child_subreaper.c | 6 +++--- test/zdtm/static/config_inotify_irmap.c | 3 ++- test/zdtm/static/inotify00.c | 3 ++- test/zdtm/static/maps03.c | 3 ++- test/zdtm/static/mnt_ext_dev.c | 3 ++- test/zdtm/static/mntns_link_remap.c | 2 +- test/zdtm/static/mntns_open.c | 2 +- test/zdtm/static/mountpoints.c | 2 +- test/zdtm/static/remap_dead_pid.c | 4 ++-- test/zdtm/static/selinux01.c | 3 ++- test/zdtm/static/sigaltstack.c | 20 +++++++++---------- test/zdtm/static/socket-tcp-syn-sent.c | 4 ++-- test/zdtm/static/unlink_multiple_largefiles.c | 3 ++- test/zdtm/transition/file_aio.c | 3 ++- test/zdtm/transition/file_read.c | 5 ++++- test/zdtm/transition/maps008.c | 14 +++++++------ 22 files changed, 66 insertions(+), 48 deletions(-) diff --git a/Makefile b/Makefile index ef76d706c..133390f17 100644 --- a/Makefile +++ b/Makefile @@ -100,7 +100,7 @@ export PROTOUFIX DEFINES DEFINES += -D_FILE_OFFSET_BITS=64 DEFINES += -D_GNU_SOURCE -WARNINGS := -Wall -Wformat-security +WARNINGS := -Wall -Wformat-security -Wdeclaration-after-statement CFLAGS-GCOV := --coverage -fno-exceptions -fno-inline -fprofile-update=atomic export CFLAGS-GCOV diff --git a/criu/net.c b/criu/net.c index e960a34f9..712837782 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2817,6 +2817,9 @@ int macvlan_ext_add(struct external *ext) static int prep_ns_sockets(struct ns_id *ns, bool for_dump) { int nsret = -1, ret; +#ifdef CONFIG_HAS_SELINUX + security_context_t ctx; +#endif if (ns->type != NS_CRIU) { pr_info("Switching to %d's net for collecting sockets\n", ns->ns_pid); @@ -2854,7 +2857,6 @@ static int prep_ns_sockets(struct ns_id *ns, bool for_dump) * policies installed. For Fedora based systems this is part * of the container-selinux package. */ - security_context_t ctx; /* * This assumes that all processes CRIU wants to dump are labeled @@ -3294,6 +3296,7 @@ int kerndat_link_nsid() } if (pid == 0) { + bool has_link_nsid; NetDeviceEntry nde = NET_DEVICE_ENTRY__INIT; struct net_link link = { .created = false, @@ -3336,7 +3339,7 @@ int kerndat_link_nsid() exit(1); } - bool has_link_nsid = false; + has_link_nsid = false; if (check_link_nsid(sk, &has_link_nsid)) exit(1); diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 4d2d046ef..9affc2706 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -624,17 +624,17 @@ unsigned long handle_faulty_iov(int pid, struct iovec* riov, unsigned long* aux_len, unsigned long partial_read_bytes) { + struct iovec dummy; + ssize_t bytes_read; + unsigned long offset = 0; + unsigned long final_read_cnt = 0; + /* Handling Case 2*/ if (riov[faulty_index].iov_len == PAGE_SIZE) { cnt_sub(CNT_PAGES_WRITTEN, 1); return 0; } - struct iovec dummy; - ssize_t bytes_read; - unsigned long offset = 0; - unsigned long final_read_cnt = 0; - /* Handling Case 3-Part 3.2*/ offset = (partial_read_bytes)? partial_read_bytes : PAGE_SIZE; diff --git a/criu/pie/util-vdso.c b/criu/pie/util-vdso.c index 104da0633..58b27680c 100644 --- a/criu/pie/util-vdso.c +++ b/criu/pie/util-vdso.c @@ -243,10 +243,11 @@ static void parse_elf_symbols(uintptr_t mem, size_t size, Phdr_t *load, k = elf_hash((const unsigned char *)symbol); for (j = bucket[k % nbucket]; j < nchain && j != STN_UNDEF; j = chain[j]) { - addr = mem + dyn_symtab->d_un.d_ptr - load->p_vaddr; Sym_t *sym; char *name; + addr = mem + dyn_symtab->d_un.d_ptr - load->p_vaddr; + addr += sizeof(Sym_t)*j; if (__ptr_struct_oob(addr, sizeof(Sym_t), mem, size)) continue; diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index 32fc72d32..6958d128e 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -38,6 +38,7 @@ ifeq ($(origin CC), default) CC := $(CROSS_COMPILE)$(HOSTCC) endif CFLAGS += -g -O2 -Wall -Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 +CFLAGS += -Wdeclaration-after-statement CFLAGS += $(USERCFLAGS) CFLAGS += -D_GNU_SOURCE CPPFLAGS += -iquote $(LIBDIR)/arch/$(ARCH)/include diff --git a/test/zdtm/static/arm-neon00.c b/test/zdtm/static/arm-neon00.c index 96da16c6b..ce8123e51 100644 --- a/test/zdtm/static/arm-neon00.c +++ b/test/zdtm/static/arm-neon00.c @@ -12,13 +12,14 @@ const char *test_author = "Alexander Karatshov "; int main(int argc, char ** argv) { + int a, b, c, y1, y2; + srand(time(0)); - int a = rand() % 100; - int b = rand() % 100; - int c = rand() % 100; - int y1 = a + b*c; - int y2; + a = rand() % 100; + b = rand() % 100; + c = rand() % 100; + y1 = a + b*c; test_init(argc, argv); diff --git a/test/zdtm/static/child_subreaper.c b/test/zdtm/static/child_subreaper.c index 267795249..6d02c9f93 100644 --- a/test/zdtm/static/child_subreaper.c +++ b/test/zdtm/static/child_subreaper.c @@ -8,10 +8,11 @@ const char *test_author = "Michał Cłapiński "; int main(int argc, char **argv) { + int cs_before = 1, cs_after, ret; + test_init(argc, argv); - int cs_before = 1; - int ret = prctl(PR_SET_CHILD_SUBREAPER, cs_before, 0, 0, 0); + ret = prctl(PR_SET_CHILD_SUBREAPER, cs_before, 0, 0, 0); if (ret) { pr_perror("Can't set child subreaper attribute, err = %d", ret); exit(1); @@ -20,7 +21,6 @@ int main(int argc, char **argv) test_daemon(); test_waitsig(); - int cs_after; ret = prctl(PR_GET_CHILD_SUBREAPER, (unsigned long)&cs_after, 0, 0, 0); if (ret) { pr_perror("Can't get child subreaper attribute, err = %d", ret); diff --git a/test/zdtm/static/config_inotify_irmap.c b/test/zdtm/static/config_inotify_irmap.c index 831dc1974..3cbeba7d3 100644 --- a/test/zdtm/static/config_inotify_irmap.c +++ b/test/zdtm/static/config_inotify_irmap.c @@ -31,6 +31,7 @@ char test_files[2][128] = {TDIR"/zdtm-test", TDIR"/zdtm-test1",}; int main (int argc, char *argv[]) { + FILE *configfile; char buf[BUFF_SIZE]; int fd, wd, i; @@ -56,7 +57,7 @@ int main (int argc, char *argv[]) } } - FILE *configfile = fopen(CONFIG_PATH, "w"); + configfile = fopen(CONFIG_PATH, "w"); if (configfile == NULL) { pr_perror("Unable to create configuration file %s", CONFIG_PATH); goto err; diff --git a/test/zdtm/static/inotify00.c b/test/zdtm/static/inotify00.c index 67088edd8..635c05047 100644 --- a/test/zdtm/static/inotify00.c +++ b/test/zdtm/static/inotify00.c @@ -125,9 +125,10 @@ int main (int argc, char *argv[]) { pid_t pid; task_waiter_t t; - task_waiter_init(&t); static char buf[PATH_MAX]; + task_waiter_init(&t); + if (mount(NULL, "/", NULL, MS_PRIVATE | MS_REC, NULL)) { pr_perror("Unable to remount /"); return 1; diff --git a/test/zdtm/static/maps03.c b/test/zdtm/static/maps03.c index f2bf7957a..0e0a5b8f2 100644 --- a/test/zdtm/static/maps03.c +++ b/test/zdtm/static/maps03.c @@ -16,9 +16,10 @@ const char *test_author = "Cyrill Gorcunov "; int main(int argc, char **argv) { - test_init(argc, argv); unsigned char *mem; + test_init(argc, argv); + test_msg("Alloc huge VMA\n"); mem = (void *)mmap(NULL, (10L << 30), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); diff --git a/test/zdtm/static/mnt_ext_dev.c b/test/zdtm/static/mnt_ext_dev.c index a9ac01333..1d60fc92f 100644 --- a/test/zdtm/static/mnt_ext_dev.c +++ b/test/zdtm/static/mnt_ext_dev.c @@ -20,10 +20,11 @@ TEST_OPTION(dirname, string, "directory name", 1); int main(int argc, char **argv) { char *loop, fd, dfd, fd2; - test_init(argc, argv); struct stat st, stp, st2; char dname[PATH_MAX], dname2[PATH_MAX]; + test_init(argc, argv); + snprintf(dname, sizeof(dname), "%s/test_dir", dirname); snprintf(dname2, sizeof(dname2), "%s/test_dir2", dirname); diff --git a/test/zdtm/static/mntns_link_remap.c b/test/zdtm/static/mntns_link_remap.c index 642641b16..6ac08191a 100644 --- a/test/zdtm/static/mntns_link_remap.c +++ b/test/zdtm/static/mntns_link_remap.c @@ -230,8 +230,8 @@ int main(int argc, char **argv) if (pid > 0) { - kill(pid, SIGTERM); int status = 1; + kill(pid, SIGTERM); wait(&status); if (WIFEXITED(status)) { if (WEXITSTATUS(status) == AWK_OK) diff --git a/test/zdtm/static/mntns_open.c b/test/zdtm/static/mntns_open.c index e19c4ea72..c687080a7 100644 --- a/test/zdtm/static/mntns_open.c +++ b/test/zdtm/static/mntns_open.c @@ -119,8 +119,8 @@ int main(int argc, char **argv) test_waitsig(); if (pid > 0) { - kill(pid, SIGTERM); int status = 1; + kill(pid, SIGTERM); wait(&status); if (WIFEXITED(status)) { if (WEXITSTATUS(status) == AWK_OK) diff --git a/test/zdtm/static/mountpoints.c b/test/zdtm/static/mountpoints.c index 00475cdc5..cf54d1096 100644 --- a/test/zdtm/static/mountpoints.c +++ b/test/zdtm/static/mountpoints.c @@ -292,8 +292,8 @@ int main(int argc, char **argv) } if (pid > 0) { - kill(pid, SIGTERM); int status = 1; + kill(pid, SIGTERM); wait(&status); if (status) return 1; diff --git a/test/zdtm/static/remap_dead_pid.c b/test/zdtm/static/remap_dead_pid.c index 261c591b7..5d4241fc6 100644 --- a/test/zdtm/static/remap_dead_pid.c +++ b/test/zdtm/static/remap_dead_pid.c @@ -40,12 +40,12 @@ int main(int argc, char **argv) while(1) sleep(10); } else { - test_msg("child is %d\n", pid); - int fd, ret; char path[PATH_MAX]; pid_t result; + test_msg("child is %d\n", pid); + sprintf(path, proc_path, pid); fd = open(path, O_RDONLY); if (fd < 0) { diff --git a/test/zdtm/static/selinux01.c b/test/zdtm/static/selinux01.c index 9966455c4..cec5980e8 100644 --- a/test/zdtm/static/selinux01.c +++ b/test/zdtm/static/selinux01.c @@ -133,6 +133,7 @@ int check_sockcreate_empty() int main(int argc, char **argv) { + int sk; char ctx[1024]; test_init(argc, argv); @@ -159,7 +160,7 @@ int main(int argc, char **argv) #endif /* Open our test socket */ - int sk = socket(AF_INET, SOCK_STREAM, 0); + sk = socket(AF_INET, SOCK_STREAM, 0); memset(ctx, 0, 1024); /* Read out the socket label */ if (fgetxattr(sk, "security.selinux", ctx, 1024) == -1) { diff --git a/test/zdtm/static/sigaltstack.c b/test/zdtm/static/sigaltstack.c index d324b0d37..f36d409f5 100644 --- a/test/zdtm/static/sigaltstack.c +++ b/test/zdtm/static/sigaltstack.c @@ -61,17 +61,17 @@ void thread_sigaction(int signo, siginfo_t *info, void *context) static void *thread_func(void *arg) { + struct sigaction sa = { + .sa_sigaction = thread_sigaction, + .sa_flags = SA_RESTART | SA_ONSTACK, + }; + sas_state[SAS_THRD_OLD] = (stack_t) { .ss_size = sizeof(stack_thread) - 8, .ss_sp = stack_thread, .ss_flags = 0, }; - struct sigaction sa = { - .sa_sigaction = thread_sigaction, - .sa_flags = SA_RESTART | SA_ONSTACK, - }; - sigemptyset(&sa.sa_mask); if (sigaction(SIGUSR2, &sa, NULL)) { @@ -103,17 +103,17 @@ int main(int argc, char *argv[]) { pthread_t thread; + struct sigaction sa = { + .sa_sigaction = leader_sigaction, + .sa_flags = SA_RESTART | SA_ONSTACK, + }; + sas_state[SAS_MAIN_OLD] = (stack_t) { .ss_size = sizeof(stack_main) - 8, .ss_sp = stack_main, .ss_flags = 0, }; - struct sigaction sa = { - .sa_sigaction = leader_sigaction, - .sa_flags = SA_RESTART | SA_ONSTACK, - }; - sigemptyset(&sa.sa_mask); test_init(argc, argv); diff --git a/test/zdtm/static/socket-tcp-syn-sent.c b/test/zdtm/static/socket-tcp-syn-sent.c index cf4c3bb46..755532a8a 100644 --- a/test/zdtm/static/socket-tcp-syn-sent.c +++ b/test/zdtm/static/socket-tcp-syn-sent.c @@ -37,7 +37,7 @@ int main(int argc, char **argv) { int fd, fd_s, sock, sk; union sockaddr_inet addr; - char cmd[4096]; + char c, cmd[4096]; test_init(argc, argv); @@ -113,7 +113,7 @@ int main(int argc, char **argv) fcntl(sock, F_SETFL, 0); - char c = 5; + c = 5; if (write(sock, &c, 1) != 1) { fail("Unable to send data"); return 1; diff --git a/test/zdtm/static/unlink_multiple_largefiles.c b/test/zdtm/static/unlink_multiple_largefiles.c index 7cf628606..2f9248c2f 100644 --- a/test/zdtm/static/unlink_multiple_largefiles.c +++ b/test/zdtm/static/unlink_multiple_largefiles.c @@ -30,10 +30,11 @@ void create_check_pattern(char *buf, size_t count, unsigned char seed) struct fiemap *read_fiemap(int fd) { - test_msg("Obtaining fiemap for fd %d\n", fd); struct fiemap *fiemap, *tmp; int extents_size; + test_msg("Obtaining fiemap for fd %d\n", fd); + fiemap = malloc(sizeof(struct fiemap)); if (fiemap == NULL) { pr_perror("Cannot allocate fiemap"); diff --git a/test/zdtm/transition/file_aio.c b/test/zdtm/transition/file_aio.c index a16010158..4a76c9390 100644 --- a/test/zdtm/transition/file_aio.c +++ b/test/zdtm/transition/file_aio.c @@ -17,7 +17,6 @@ const char *test_author = "Andrew Vagin "; int main(int argc, char **argv) { - test_init(argc, argv); char buf[BUF_SIZE]; int fd; struct aiocb aiocb; @@ -25,6 +24,8 @@ int main(int argc, char **argv) char tmpfname[256]="/tmp/file_aio.XXXXXX"; int ret; + test_init(argc, argv); + fd = mkstemp(tmpfname); if (fd == -1) { pr_perror("mkstemp() failed"); diff --git a/test/zdtm/transition/file_read.c b/test/zdtm/transition/file_read.c index 50dffd8c4..5d6e4dbba 100644 --- a/test/zdtm/transition/file_read.c +++ b/test/zdtm/transition/file_read.c @@ -158,9 +158,11 @@ static void chew_some_file(int num) rv = SEEK_FAILED; goto out_exit; case 1: - rv = FILE_CORRUPTED; + { int fd1; char str[PATH_MAX]; + + rv = FILE_CORRUPTED; // create standard file sprintf(str, "standard_%s.%d", filename, num); fd1 = open(str, O_WRONLY | O_CREAT | O_TRUNC, 0666); @@ -168,6 +170,7 @@ static void chew_some_file(int num) pr_perror("can't write %s", str); close(fd1); goto out_exit; + } } } rv = SUCCESS; diff --git a/test/zdtm/transition/maps008.c b/test/zdtm/transition/maps008.c index 5f6eb0887..7ed7c10a5 100644 --- a/test/zdtm/transition/maps008.c +++ b/test/zdtm/transition/maps008.c @@ -348,6 +348,7 @@ static int proc11_func(task_waiter_t *setup_waiter) void *mem3_old = mem3; size_t mem3_size_old = mem3_size; uint32_t crc_epoch = 0; + uint8_t *proc1_mem3; pstree->proc11 = getpid(); xmunmap(mem3, MEM3_START_CUT); @@ -382,7 +383,7 @@ static int proc11_func(task_waiter_t *setup_waiter) chk_proc_mem_eq(pstree->proc11, mem3, mem3_size, pstree->proc112, mem3, mem3_size + MEM3_END_CUT); - uint8_t *proc1_mem3 = mmap_proc_mem(pstree->proc1, + proc1_mem3 = mmap_proc_mem(pstree->proc1, (unsigned long)mem3_old, mem3_size_old); check_mem_eq(mem3, mem3_size, proc1_mem3 + MEM3_START_CUT, mem3_size); xmunmap(proc1_mem3, mem3_size_old); @@ -489,16 +490,17 @@ static void sigchld_hand(int signo, siginfo_t *info, void *ucontext) int main(int argc, char **argv) { - test_init(argc, argv); - - pstree = (struct pstree *)mmap_ashmem(PAGE_SIZE); - test_sync = (struct test_sync *)mmap_ashmem(sizeof(*test_sync)); - struct sigaction sa = { .sa_sigaction = sigchld_hand, .sa_flags = SA_RESTART | SA_SIGINFO | SA_NOCLDSTOP }; sigemptyset(&sa.sa_mask); + + test_init(argc, argv); + + pstree = (struct pstree *)mmap_ashmem(PAGE_SIZE); + test_sync = (struct test_sync *)mmap_ashmem(sizeof(*test_sync)); + if (sigaction(SIGCHLD, &sa, NULL)) { pr_perror("SIGCHLD handler setup"); exit(1); From 17c4a8b24507d1bd1a906aa4a9d5ea3054072141 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 21 Dec 2019 18:13:06 +0000 Subject: [PATCH 2271/4375] style: Enforce kernel style -Wstrict-prototypes Include warnings that the kernel uses during compilation: -Wstrict-prototypes: enforces full declaration of functions. Previously, when declaring extern void func(), one can call func(123) and have no compilation error. This is dangerous. The correct declaration is extern void func(void). Signed-off-by: Nicolas Viennot [Generated a commit message from the pull request] Signed-off-by: Dmitry Safonov --- Makefile | 2 +- criu/config.c | 2 +- criu/cr-check.c | 10 ++++----- criu/cr-dump.c | 4 ++-- criu/cr-restore.c | 8 +++---- criu/cr-service.c | 4 ++-- criu/crtools.c | 2 +- criu/fault-injection.c | 2 +- criu/include/cr_options.h | 4 ++-- criu/include/lsm.h | 4 ++-- criu/include/mount.h | 2 +- criu/include/net.h | 8 +++---- criu/include/tls.h | 2 +- criu/kerndat.c | 6 ++--- criu/lsm.c | 2 +- criu/mount.c | 6 ++--- criu/namespaces.c | 2 +- criu/net.c | 10 ++++----- criu/pstree.c | 2 +- criu/seize.c | 2 +- criu/tls.c | 6 ++--- criu/util.c | 4 ++-- soccr/test/tcp-conn.c | 2 +- soccr/test/tcp-constructor.c | 2 +- test/others/unix-callback/unix-client.c | 2 +- test/others/unix-callback/unix-server.c | 2 +- test/zdtm/Makefile.inc | 2 +- test/zdtm/lib/test.c | 6 ++--- test/zdtm/static/apparmor.c | 4 ++-- .../static/child_subreaper_and_reparent.c | 6 ++--- .../static/child_subreaper_existing_child.c | 6 ++--- test/zdtm/static/dumpable02.c | 2 +- test/zdtm/static/fdt_shared.c | 4 ++-- test/zdtm/static/file_locks00.c | 2 +- test/zdtm/static/inotify_system.c | 2 +- test/zdtm/static/maps00.c | 7 +++--- test/zdtm/static/selinux00.c | 8 +++---- test/zdtm/static/selinux01.c | 10 ++++----- test/zdtm/static/session02.c | 8 +++---- test/zdtm/static/session03.c | 10 ++++----- test/zdtm/transition/netlink00.c | 22 +++++++++---------- 41 files changed, 101 insertions(+), 100 deletions(-) diff --git a/Makefile b/Makefile index 133390f17..00e563c11 100644 --- a/Makefile +++ b/Makefile @@ -100,7 +100,7 @@ export PROTOUFIX DEFINES DEFINES += -D_FILE_OFFSET_BITS=64 DEFINES += -D_GNU_SOURCE -WARNINGS := -Wall -Wformat-security -Wdeclaration-after-statement +WARNINGS := -Wall -Wformat-security -Wdeclaration-after-statement -Wstrict-prototypes CFLAGS-GCOV := --coverage -fno-exceptions -fno-inline -fprofile-update=atomic export CFLAGS-GCOV diff --git a/criu/config.c b/criu/config.c index e5d42efe4..73c62f5bb 100644 --- a/criu/config.c +++ b/criu/config.c @@ -853,7 +853,7 @@ bad_arg: return 1; } -int check_options() +int check_options(void) { if (opts.tcp_established_ok) pr_info("Will dump/restore TCP connections\n"); diff --git a/criu/cr-check.c b/criu/cr-check.c index 729b2dc38..17dd29b42 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -51,7 +51,7 @@ #include "restorer.h" #include "uffd.h" -static char *feature_name(int (*func)()); +static char *feature_name(int (*func)(void)); static int check_tty(void) { @@ -513,7 +513,7 @@ static int check_ipc(void) return -1; } -static int check_sigqueuinfo() +static int check_sigqueuinfo(void) { siginfo_t info = { .si_code = 1 }; @@ -960,7 +960,7 @@ static int clone_cb(void *_arg) { exit(0); } -static int check_clone_parent_vs_pid() +static int check_clone_parent_vs_pid(void) { struct clone_arg ca; pid_t pid; @@ -1447,7 +1447,7 @@ static int check_external_net_ns(void) struct feature_list { char *name; - int (*func)(); + int (*func)(void); }; static struct feature_list feature_list[] = { @@ -1517,7 +1517,7 @@ int check_add_feature(char *feat) return -1; } -static char *feature_name(int (*func)()) +static char *feature_name(int (*func)(void)) { struct feature_list *fl; diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 4b5a01cfd..88323af92 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1439,7 +1439,7 @@ err_cure_imgset: static int alarm_attempts = 0; -bool alarm_timeouted() { +bool alarm_timeouted(void) { return alarm_attempts > 0; } @@ -1456,7 +1456,7 @@ static void alarm_handler(int signo) BUG(); } -static int setup_alarm_handler() +static int setup_alarm_handler(void) { struct sigaction sa = { .sa_handler = alarm_handler, diff --git a/criu/cr-restore.c b/criu/cr-restore.c index b920ce262..687cd6c68 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -182,13 +182,13 @@ static int __restore_wait_inprogress_tasks(int participants) return 0; } -static int restore_wait_inprogress_tasks() +static int restore_wait_inprogress_tasks(void) { return __restore_wait_inprogress_tasks(0); } /* Wait all tasks except the current one */ -static int restore_wait_other_tasks() +static int restore_wait_other_tasks(void) { int participants, stage; @@ -1587,7 +1587,7 @@ static void restore_pgid(void) futex_set_and_wake(&rsti(current)->pgrp_set, 1); } -static int __legacy_mount_proc() +static int __legacy_mount_proc(void) { char proc_mountpoint[] = "/tmp/crtools-proc.XXXXXX"; int fd; @@ -1941,7 +1941,7 @@ static int catch_tasks(bool root_seized, enum trace_flags *flag) return 0; } -static int clear_breakpoints() +static int clear_breakpoints(void) { struct pstree_item *item; int ret = 0, i; diff --git a/criu/cr-service.c b/criu/cr-service.c index 549b3368b..279016bcd 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -1278,7 +1278,7 @@ static void reap_worker(int signo) } } -static int setup_sigchld_handler() +static int setup_sigchld_handler(void) { struct sigaction action; @@ -1295,7 +1295,7 @@ static int setup_sigchld_handler() return 0; } -static int restore_sigchld_handler() +static int restore_sigchld_handler(void) { struct sigaction action; diff --git a/criu/crtools.c b/criu/crtools.c index 700fad994..9b6e94809 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -47,7 +47,7 @@ #include "setproctitle.h" #include "sysctl.h" -void flush_early_log_to_stderr() __attribute__((destructor)); +void flush_early_log_to_stderr(void) __attribute__((destructor)); void flush_early_log_to_stderr(void) { diff --git a/criu/fault-injection.c b/criu/fault-injection.c index 4128814d5..4b0650008 100644 --- a/criu/fault-injection.c +++ b/criu/fault-injection.c @@ -3,7 +3,7 @@ enum faults fi_strategy; -int fault_injection_init() +int fault_injection_init(void) { char *val; int start; diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index 2c1451e86..c5af33186 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -158,7 +158,7 @@ extern struct cr_options opts; char *rpc_cfg_file; extern int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd, int state); -extern int check_options(); -extern void init_opts(); +extern int check_options(void); +extern void init_opts(void); #endif /* __CR_OPTIONS_H__ */ diff --git a/criu/include/lsm.h b/criu/include/lsm.h index 3b8271282..a41915a4c 100644 --- a/criu/include/lsm.h +++ b/criu/include/lsm.h @@ -39,7 +39,7 @@ extern int lsm_check_opts(void); #ifdef CONFIG_HAS_SELINUX int dump_xattr_security_selinux(int fd, FdinfoEntry *e); int run_setsockcreatecon(FdinfoEntry *e); -int reset_setsockcreatecon(); +int reset_setsockcreatecon(void); #else static inline int dump_xattr_security_selinux(int fd, FdinfoEntry *e) { return 0; @@ -47,7 +47,7 @@ static inline int dump_xattr_security_selinux(int fd, FdinfoEntry *e) { static inline int run_setsockcreatecon(FdinfoEntry *e) { return 0; } -static inline int reset_setsockcreatecon() { +static inline int reset_setsockcreatecon(void) { return 0; } #endif diff --git a/criu/include/mount.h b/criu/include/mount.h index d9b375f5d..8bf19b266 100644 --- a/criu/include/mount.h +++ b/criu/include/mount.h @@ -96,7 +96,7 @@ extern int collect_binfmt_misc(void); static inline int collect_binfmt_misc(void) { return 0; } #endif -extern struct mount_info *mnt_entry_alloc(); +extern struct mount_info *mnt_entry_alloc(void); extern void mnt_entry_free(struct mount_info *mi); extern int __mntns_get_root_fd(pid_t pid); diff --git a/criu/include/net.h b/criu/include/net.h index 9976f6eb0..0a556f3da 100644 --- a/criu/include/net.h +++ b/criu/include/net.h @@ -31,7 +31,7 @@ extern int collect_net_namespaces(bool for_dump); extern int network_lock(void); extern void network_unlock(void); -extern int network_lock_internal(); +extern int network_lock_internal(void); extern struct ns_desc net_ns_desc; @@ -47,11 +47,11 @@ extern int move_veth_to_bridge(void); extern int kerndat_link_nsid(void); extern int net_get_nsid(int rtsk, int fd, int *nsid); -extern struct ns_id *net_get_root_ns(); +extern struct ns_id *net_get_root_ns(void); extern int kerndat_nsid(void); extern void check_has_netns_ioc(int fd, bool *kdat_val, const char *name); extern int net_set_ext(struct ns_id *ns); -extern struct ns_id *get_root_netns(); -extern int read_net_ns_img(); +extern struct ns_id *get_root_netns(void); +extern int read_net_ns_img(void); #endif /* __CR_NET_H__ */ diff --git a/criu/include/tls.h b/criu/include/tls.h index aa2517887..b48e4b480 100644 --- a/criu/include/tls.h +++ b/criu/include/tls.h @@ -4,7 +4,7 @@ # ifdef CONFIG_GNUTLS int tls_x509_init(int sockfd, bool is_server); -void tls_terminate_session(); +void tls_terminate_session(void); ssize_t tls_send(const void *buf, size_t len, int flags); ssize_t tls_recv(void *buf, size_t len, int flags); diff --git a/criu/kerndat.c b/criu/kerndat.c index b0dd83135..d1afde71d 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -364,7 +364,7 @@ no_dt: } /* The page frame number (PFN) is constant for the zero page */ -static int init_zero_page_pfn() +static int init_zero_page_pfn(void) { void *addr; int ret = 0; @@ -429,7 +429,7 @@ static int get_task_size(void) return 0; } -static int kerndat_fdinfo_has_lock() +static int kerndat_fdinfo_has_lock(void) { int fd, pfd = -1, exit_code = -1, len; char buf[PAGE_SIZE]; @@ -464,7 +464,7 @@ out: return exit_code; } -static int get_ipv6() +static int get_ipv6(void) { if (access("/proc/sys/net/ipv6", F_OK) < 0) { if (errno == ENOENT) { diff --git a/criu/lsm.c b/criu/lsm.c index 9d7e55c11..060f10259 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -133,7 +133,7 @@ static int selinux_get_sockcreate_label(pid_t pid, char **output) return 0; } -int reset_setsockcreatecon() +int reset_setsockcreatecon(void) { /* Currently this only works for SELinux. */ if (kdat.lsm != LSMTYPE__SELINUX) diff --git a/criu/mount.c b/criu/mount.c index 24a8516c6..180f2a62d 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -2140,7 +2140,7 @@ static int restore_ext_mount(struct mount_info *mi) static char mnt_clean_path[] = "/tmp/cr-tmpfs.XXXXXX"; -static int mount_clean_path() +static int mount_clean_path(void) { /* * To make a bind mount, we need to have access to a source directory, @@ -2167,7 +2167,7 @@ static int mount_clean_path() return 0; } -static int umount_clean_path() +static int umount_clean_path(void) { if (umount2(mnt_clean_path, MNT_DETACH)) { pr_perror("Unable to umount %s", mnt_clean_path); @@ -2659,7 +2659,7 @@ static int find_remap_mounts(struct mount_info *root) } /* Move remapped mounts to places where they have to be */ -static int fixup_remap_mounts() +static int fixup_remap_mounts(void) { struct mnt_remap_entry *r; diff --git a/criu/namespaces.c b/criu/namespaces.c index 57f6bdfef..21266df7c 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -976,7 +976,7 @@ err: return exit_code; } -void free_userns_maps() +void free_userns_maps(void) { if (userns_entry.n_uid_map > 0) { xfree(userns_entry.uid_map[0]); diff --git a/criu/net.c b/criu/net.c index 712837782..8e6cfaff1 100644 --- a/criu/net.c +++ b/criu/net.c @@ -1765,7 +1765,7 @@ static int __restore_links(struct ns_id *nsid, int *nrlinks, int *nrcreated) return 0; } -static int restore_links() +static int restore_links(void) { int nrcreated, nrlinks; struct ns_id *nsid; @@ -2080,7 +2080,7 @@ out: * iptables-restore is executed from a target userns and it may have not enough * rights to open /run/xtables.lock. Here we try to workaround this problem. */ -static int prepare_xtable_lock() +static int prepare_xtable_lock(void) { int fd; @@ -2700,7 +2700,7 @@ err: return ret; } -int network_lock_internal() +int network_lock_internal(void) { char conf[] = "*filter\n" ":CRIU - [0:0]\n" @@ -2731,7 +2731,7 @@ int network_lock_internal() return ret; } -static int network_unlock_internal() +static int network_unlock_internal(void) { char conf[] = "*filter\n" ":CRIU - [0:0]\n" @@ -3284,7 +3284,7 @@ static int check_link_nsid(int rtsk, void *args) return do_rtnl_req(rtsk, &req, sizeof(req), check_one_link_nsid, NULL, NULL, args); } -int kerndat_link_nsid() +int kerndat_link_nsid(void) { int status; pid_t pid; diff --git a/criu/pstree.c b/criu/pstree.c index 92b4167aa..19cf5ad38 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -608,7 +608,7 @@ err: } #define RESERVED_PIDS 300 -static int get_free_pid() +static int get_free_pid(void) { static struct pid *prev, *next; diff --git a/criu/seize.c b/criu/seize.c index e1e6b8195..fd314666f 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -194,7 +194,7 @@ static int seize_cgroup_tree(char *root_path, const char *state) * A freezer cgroup can contain tasks which will not be dumped * and we need to wait them, because the are interrupted them by ptrace. */ -static int freezer_wait_processes() +static int freezer_wait_processes(void) { int i; diff --git a/criu/tls.c b/criu/tls.c index db9cc4f5a..f7b94dee8 100644 --- a/criu/tls.c +++ b/criu/tls.c @@ -31,7 +31,7 @@ static gnutls_certificate_credentials_t x509_cred; static int tls_sk = -1; static int tls_sk_flags = 0; -void tls_terminate_session() +void tls_terminate_session(void) { int ret; @@ -227,7 +227,7 @@ static int tls_x509_verify_peer_cert(void) return 0; } -static int tls_handshake() +static int tls_handshake(void) { int ret = -1; while (ret != GNUTLS_E_SUCCESS) { @@ -241,7 +241,7 @@ static int tls_handshake() return 0; } -static int tls_x509_setup_creds() +static int tls_x509_setup_creds(void) { int ret; char *cacert = CRIU_CACERT; diff --git a/criu/util.c b/criu/util.c index 3bae18ab2..1646ce1c4 100644 --- a/criu/util.c +++ b/criu/util.c @@ -326,7 +326,7 @@ int close_pid_proc(void) return 0; } -void close_proc() +void close_proc(void) { close_pid_proc(); close_service_fd(PROC_FD_OFF); @@ -690,7 +690,7 @@ int cr_daemon(int nochdir, int noclose, int close_fd) return 0; } -int is_root_user() +int is_root_user(void) { if (geteuid() != 0) { pr_err("You need to be root to run this command\n"); diff --git a/soccr/test/tcp-conn.c b/soccr/test/tcp-conn.c index 1a1a5bb39..e31f58e7e 100644 --- a/soccr/test/tcp-conn.c +++ b/soccr/test/tcp-conn.c @@ -23,7 +23,7 @@ static void pr_printf(unsigned int level, const char *fmt, ...) va_end(args); } -int main() +int main(void) { union libsoccr_addr addr, dst; int srv, sock, clnt, rst; diff --git a/soccr/test/tcp-constructor.c b/soccr/test/tcp-constructor.c index 89f201000..973dbf10c 100644 --- a/soccr/test/tcp-constructor.c +++ b/soccr/test/tcp-constructor.c @@ -20,7 +20,7 @@ struct tcp { uint16_t wscale; }; -static void usage() +static void usage(void) { printf( "Usage: --addr ADDR -port PORT --seq SEQ --next --addr ADDR -port PORT --seq SEQ -- CMD ...\n" diff --git a/test/others/unix-callback/unix-client.c b/test/others/unix-callback/unix-client.c index 69808b53c..676c4adbc 100644 --- a/test/others/unix-callback/unix-client.c +++ b/test/others/unix-callback/unix-client.c @@ -86,7 +86,7 @@ static int check_sock(int i) return 0; } -int main() +int main(void) { int i, fd; sigset_t set; diff --git a/test/others/unix-callback/unix-server.c b/test/others/unix-callback/unix-server.c index 8f32f53dd..47bebd05d 100644 --- a/test/others/unix-callback/unix-server.c +++ b/test/others/unix-callback/unix-server.c @@ -19,7 +19,7 @@ struct ticket *tickets; #define SK_NAME "/tmp/criu.unix.callback.test" -int main() +int main(void) { int sk, ret, id; char buf[4096]; diff --git a/test/zdtm/Makefile.inc b/test/zdtm/Makefile.inc index 6958d128e..43763321f 100644 --- a/test/zdtm/Makefile.inc +++ b/test/zdtm/Makefile.inc @@ -38,7 +38,7 @@ ifeq ($(origin CC), default) CC := $(CROSS_COMPILE)$(HOSTCC) endif CFLAGS += -g -O2 -Wall -Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -CFLAGS += -Wdeclaration-after-statement +CFLAGS += -Wdeclaration-after-statement -Wstrict-prototypes CFLAGS += $(USERCFLAGS) CFLAGS += -D_GNU_SOURCE CPPFLAGS += -iquote $(LIBDIR)/arch/$(ARCH)/include diff --git a/test/zdtm/lib/test.c b/test/zdtm/lib/test.c index a1bdfc1b4..630476de0 100644 --- a/test/zdtm/lib/test.c +++ b/test/zdtm/lib/test.c @@ -71,7 +71,7 @@ static void test_fini(void) unlinkat(cwd, pidfile, 0); } -static void setup_outfile() +static void setup_outfile(void) { if (!access(outfile, F_OK) || errno != ENOENT) { fprintf(stderr, "Output file %s appears to exist, aborting\n", @@ -93,7 +93,7 @@ static void setup_outfile() exit(1); } -static void redir_stdfds() +static void redir_stdfds(void) { int nullfd; @@ -346,7 +346,7 @@ void test_init(int argc, char **argv) srand48(time(NULL)); /* just in case we need it */ } -void test_daemon() +void test_daemon(void) { futex_set_and_wake(&test_shared_state->stage, TEST_RUNNING_STAGE); } diff --git a/test/zdtm/static/apparmor.c b/test/zdtm/static/apparmor.c index 15930c761..b3a4d7549 100644 --- a/test/zdtm/static/apparmor.c +++ b/test/zdtm/static/apparmor.c @@ -15,7 +15,7 @@ const char *test_author = "Tycho Andersen "; #define PROFILE "criu_test" -int setprofile() +int setprofile(void) { char profile[1024]; int fd, len; @@ -45,7 +45,7 @@ int setprofile() return 0; } -int checkprofile() +int checkprofile(void) { FILE *f; char path[PATH_MAX], profile[1024]; diff --git a/test/zdtm/static/child_subreaper_and_reparent.c b/test/zdtm/static/child_subreaper_and_reparent.c index 57943a67b..e3955d3d9 100644 --- a/test/zdtm/static/child_subreaper_and_reparent.c +++ b/test/zdtm/static/child_subreaper_and_reparent.c @@ -25,7 +25,7 @@ struct shared { int parent_after_cr; } *sh; -int orphan() +int orphan(void) { /* * Wait until reparented to the pidns init. (By waiting @@ -45,7 +45,7 @@ int orphan() return 0; } -int helper() +int helper(void) { int pid; @@ -59,7 +59,7 @@ int helper() return 0; } -int subreaper() +int subreaper(void) { int pid, ret, status; diff --git a/test/zdtm/static/child_subreaper_existing_child.c b/test/zdtm/static/child_subreaper_existing_child.c index 28e9dbb8a..8291aba08 100644 --- a/test/zdtm/static/child_subreaper_existing_child.c +++ b/test/zdtm/static/child_subreaper_existing_child.c @@ -24,7 +24,7 @@ struct shared { } *sh; -int orphan() +int orphan(void) { /* Return the control back to MAIN worker to do C/R */ futex_set_and_wake(&sh->fstate, TEST_CRIU); @@ -36,7 +36,7 @@ int orphan() return 0; } -int helper() +int helper(void) { int pid; @@ -52,7 +52,7 @@ int helper() return 0; } -int subreaper() +int subreaper(void) { int pid, ret, status; diff --git a/test/zdtm/static/dumpable02.c b/test/zdtm/static/dumpable02.c index 024371bd8..7e2eee2d1 100644 --- a/test/zdtm/static/dumpable02.c +++ b/test/zdtm/static/dumpable02.c @@ -13,7 +13,7 @@ const char *test_doc = "Check dumpable flag handling (non-dumpable case)"; const char *test_author = "Filipe Brandenburger "; -int dumpable_server() { +int dumpable_server(void) { char buf[256]; int ret; diff --git a/test/zdtm/static/fdt_shared.c b/test/zdtm/static/fdt_shared.c index 2111356f5..a84444af5 100644 --- a/test/zdtm/static/fdt_shared.c +++ b/test/zdtm/static/fdt_shared.c @@ -22,7 +22,7 @@ TEST_OPTION(filename, string, "file name", 1); #define CHILDREN 4 static int fork_pfd[2]; -static void forked() +static void forked(void) { char c = 0; @@ -32,7 +32,7 @@ static void forked() } } -static void wait_children() +static void wait_children(void) { int i; char c; diff --git a/test/zdtm/static/file_locks00.c b/test/zdtm/static/file_locks00.c index 59e19cfe1..fa98a31b3 100644 --- a/test/zdtm/static/file_locks00.c +++ b/test/zdtm/static/file_locks00.c @@ -101,7 +101,7 @@ static int check_write_lock(int fd, int whence, off_t offset, off_t len) return -1; } -static int check_file_locks() +static int check_file_locks(void) { int fd_0, fd_1; int ret0, ret1; diff --git a/test/zdtm/static/inotify_system.c b/test/zdtm/static/inotify_system.c index 59f47c41c..3e6b2ad48 100644 --- a/test/zdtm/static/inotify_system.c +++ b/test/zdtm/static/inotify_system.c @@ -68,7 +68,7 @@ typedef struct { int dir; } desc; -void do_wait() { +void do_wait(void) { test_daemon(); test_waitsig(); } diff --git a/test/zdtm/static/maps00.c b/test/zdtm/static/maps00.c index a6c68cd25..f2da9b975 100644 --- a/test/zdtm/static/maps00.c +++ b/test/zdtm/static/maps00.c @@ -123,7 +123,7 @@ static void segfault(int signo) * after test func should be placed check map, because size of test_func * is calculated as (check_map-test_func) */ -int test_func() +int test_func(void) { return 1; } @@ -176,8 +176,9 @@ static int check_map(struct map *map) memcpy(map->ptr,test_func, getpagesize()); } else { if (!(map->flag & MAP_ANONYMOUS)) { + uint8_t funlen = (uint8_t *)check_map - (uint8_t *)test_func; lseek(map->fd,0,SEEK_SET); - if (write(map->fd,test_func,check_map - test_func)fd,test_func,funlen)filename); return -1; } @@ -185,7 +186,7 @@ static int check_map(struct map *map) } if (!(map->flag & MAP_ANONYMOUS) || map->prot & PROT_WRITE) /* Function body has been copied into the mapping */ - ((int (*)())map->ptr)(); /* perform exec access */ + ((int (*)(void))map->ptr)(); /* perform exec access */ else /* No way to copy function body into mapping, * clear exec bit from effective protection diff --git a/test/zdtm/static/selinux00.c b/test/zdtm/static/selinux00.c index db8420eac..b5b3e3cc0 100644 --- a/test/zdtm/static/selinux00.c +++ b/test/zdtm/static/selinux00.c @@ -26,14 +26,14 @@ const char *test_author = "Adrian Reber "; */ char state; -int check_for_selinux() +int check_for_selinux(void) { if (access("/sys/fs/selinux", F_OK) == 0) return 0; return 1; } -int setprofile() +int setprofile(void) { int fd, len; @@ -54,7 +54,7 @@ int setprofile() return 0; } -int checkprofile() +int checkprofile(void) { int fd; char context[1024]; @@ -83,7 +83,7 @@ int checkprofile() return 0; } -int check_sockcreate() +int check_sockcreate(void) { char *output = NULL; FILE *f = fopen("/proc/self/attr/sockcreate", "r"); diff --git a/test/zdtm/static/selinux01.c b/test/zdtm/static/selinux01.c index cec5980e8..cbf145d2a 100644 --- a/test/zdtm/static/selinux01.c +++ b/test/zdtm/static/selinux01.c @@ -28,14 +28,14 @@ const char *test_author = "Adrian Reber "; */ char state; -int check_for_selinux() +int check_for_selinux(void) { if (access("/sys/fs/selinux", F_OK) == 0) return 0; return 1; } -int setprofile() +int setprofile(void) { int fd, len; @@ -56,7 +56,7 @@ int setprofile() return 0; } -int set_sockcreate() +int set_sockcreate(void) { int fd, len; @@ -77,7 +77,7 @@ int set_sockcreate() return 0; } -int check_sockcreate() +int check_sockcreate(void) { int fd; char context[1024]; @@ -106,7 +106,7 @@ int check_sockcreate() return 0; } -int check_sockcreate_empty() +int check_sockcreate_empty(void) { char *output = NULL; FILE *f = fopen("/proc/self/attr/sockcreate", "r"); diff --git a/test/zdtm/static/session02.c b/test/zdtm/static/session02.c index 37f245d2e..f5c81df16 100644 --- a/test/zdtm/static/session02.c +++ b/test/zdtm/static/session02.c @@ -25,7 +25,7 @@ struct process *processes; int nr_processes = 20; int current = 0; -static void cleanup() +static void cleanup(void) { int i; @@ -55,9 +55,9 @@ struct command int arg2; }; -static void handle_command(); +static void handle_command(void); -static void mainloop() +static void mainloop(void) { while (1) handle_command(); @@ -100,7 +100,7 @@ static int make_child(int id, int flags) return cid; } -static void handle_command() +static void handle_command(void) { int sk = processes[current].sks[0], ret, status = 0; struct command cmd; diff --git a/test/zdtm/static/session03.c b/test/zdtm/static/session03.c index 2b3c46c32..8ca16e410 100644 --- a/test/zdtm/static/session03.c +++ b/test/zdtm/static/session03.c @@ -36,7 +36,7 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) waitpid(pid, NULL, WNOHANG); } -static void cleanup() +static void cleanup(void) { int i, ret; @@ -72,7 +72,7 @@ enum commands int cmd_weght[TEST_MAX] = {10, 3, 1, 10, 7}; int sum_weight = 0; -static int get_rnd_op() +static int get_rnd_op(void) { int i, m; if (sum_weight == 0) { @@ -97,9 +97,9 @@ struct command int arg2; }; -static void handle_command(); +static void handle_command(void); -static void mainloop() +static void mainloop(void) { while (1) handle_command(); @@ -142,7 +142,7 @@ static int make_child(int id, int flags) return cid; } -static void handle_command() +static void handle_command(void) { int sk = processes[current].sks[0], ret, status = 0; struct command cmd; diff --git a/test/zdtm/transition/netlink00.c b/test/zdtm/transition/netlink00.c index c9b2303e8..3504a48a1 100644 --- a/test/zdtm/transition/netlink00.c +++ b/test/zdtm/transition/netlink00.c @@ -56,12 +56,12 @@ struct rtmsg *rtp; int rtl; struct rtattr *rtap; -int send_request(); -int recv_reply(); -int form_request_add(); -int form_request_del(); -int read_reply(); -typedef int (*cmd_t)(); +int send_request(void); +int recv_reply(void); +int form_request_add(void); +int form_request_del(void); +int read_reply(void); +typedef int (*cmd_t)(void); #define CMD_NUM 2 cmd_t cmd[CMD_NUM]={form_request_add, form_request_del}; @@ -120,7 +120,7 @@ out: return 0; } -int send_request() +int send_request(void) { // create the remote address // to communicate @@ -145,7 +145,7 @@ int send_request() } return 0; } -int recv_reply() +int recv_reply(void) { char *p; // initialize the socket read buffer @@ -191,7 +191,7 @@ int recv_reply() return 0; } -int read_reply() +int read_reply(void) { //string to hold content of the route // table (i.e. one entry) @@ -250,7 +250,7 @@ int read_reply() #define NLMSG_TAIL(nmsg) \ ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) -int form_request_del() +int form_request_del(void) { bzero(&req, sizeof(req)); req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); @@ -272,7 +272,7 @@ int form_request_del() return 0; } -int form_request_add() +int form_request_add(void) { int ifcn = 1; //interface number From e1c4871759d6edb4d7c2d3129981060b873ec912 Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Mon, 11 Nov 2019 19:07:52 +0300 Subject: [PATCH 2272/4375] net: add nftables c/r After Centos-8 nft used instead of iptables. But we had never supported nft rules in CRIU, and after c/r all rules are flushed. Co-developed-by: Pavel Tikhomirov Signed-off-by: Pavel Tikhomirov Signed-off-by: Alexander Mikhalitsyn Signed-off-by: Alexander Mikhalitsyn Signed-off-by: Dmitry Safonov --- Makefile.config | 17 ++++ criu/image-desc.c | 1 + criu/include/image-desc.h | 1 + criu/include/magic.h | 1 + criu/net.c | 115 +++++++++++++++++++++++++++ scripts/build/Dockerfile.alpine | 1 + scripts/build/Dockerfile.fedora.tmpl | 2 + scripts/feature-tests.mak | 23 ++++++ 8 files changed, 161 insertions(+) diff --git a/Makefile.config b/Makefile.config index 81aae24f8..161365960 100644 --- a/Makefile.config +++ b/Makefile.config @@ -23,6 +23,23 @@ else $(info Note: Building without GnuTLS support) endif +ifeq ($(call pkg-config-check,libnftables),y) + LIB_NFTABLES := $(shell pkg-config --libs libnftables) + ifeq ($(call try-cc,$(FEATURE_TEST_NFTABLES_LIB_API_0),$(LIB_NFTABLES)),true) + LIBS_FEATURES += $(LIB_NFTABLES) + FEATURE_DEFINES += -DCONFIG_HAS_NFTABLES_LIB_API_0 + else ifeq ($(call try-cc,$(FEATURE_TEST_NFTABLES_LIB_API_1),$(LIB_NFTABLES)),true) + LIBS_FEATURES += $(LIB_NFTABLES) + FEATURE_DEFINES += -DCONFIG_HAS_NFTABLES_LIB_API_1 + else + $(warning Warn: you have libnftables installed but it has incompatible API) + $(warning Warn: Building without nftables support) + endif +else + $(warning Warn: you have no libnftables installed) + $(warning Warn: Building without nftables support) +endif + export LIBS += $(LIBS_FEATURES) CONFIG_FILE = .config diff --git a/criu/image-desc.c b/criu/image-desc.c index 81cd07484..ae5d817fe 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -76,6 +76,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY_F(RULE, "rule-%u", O_NOBUF), FD_ENTRY_F(IPTABLES, "iptables-%u", O_NOBUF), FD_ENTRY_F(IP6TABLES, "ip6tables-%u", O_NOBUF), + FD_ENTRY_F(NFTABLES, "nftables-%u", O_NOBUF), FD_ENTRY_F(TMPFS_IMG, "tmpfs-%u.tar.gz", O_NOBUF), FD_ENTRY_F(TMPFS_DEV, "tmpfs-dev-%u.tar.gz", O_NOBUF), FD_ENTRY_F(AUTOFS, "autofs-%u", O_NOBUF), diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index fea80a719..6db8bf94f 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -42,6 +42,7 @@ enum { CR_FD_RULE, CR_FD_IPTABLES, CR_FD_IP6TABLES, + CR_FD_NFTABLES, CR_FD_NETNS, CR_FD_NETNF_CT, CR_FD_NETNF_EXP, diff --git a/criu/include/magic.h b/criu/include/magic.h index 05101f436..1a583f4ed 100644 --- a/criu/include/magic.h +++ b/criu/include/magic.h @@ -103,6 +103,7 @@ #define TMPFS_DEV_MAGIC RAW_IMAGE_MAGIC #define IPTABLES_MAGIC RAW_IMAGE_MAGIC #define IP6TABLES_MAGIC RAW_IMAGE_MAGIC +#define NFTABLES_MAGIC RAW_IMAGE_MAGIC #define NETNF_CT_MAGIC RAW_IMAGE_MAGIC #define NETNF_EXP_MAGIC RAW_IMAGE_MAGIC diff --git a/criu/net.c b/criu/net.c index 8e6cfaff1..762f9b547 100644 --- a/criu/net.c +++ b/criu/net.c @@ -17,6 +17,10 @@ #include #include +#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1) +#include +#endif + #ifdef CONFIG_HAS_SELINUX #include #endif @@ -1897,6 +1901,55 @@ static inline int dump_iptables(struct cr_imgset *fds) return 0; } +#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1) +static inline int dump_nftables(struct cr_imgset *fds) +{ + int ret = -1; + struct cr_img *img; + int img_fd; + FILE *fp; + struct nft_ctx *nft; + + nft = nft_ctx_new(NFT_CTX_DEFAULT); + if (!nft) + return -1; + + img = img_from_set(fds, CR_FD_NFTABLES); + img_fd = dup(img_raw_fd(img)); + if (img_fd < 0) { + pr_perror("dup() failed"); + goto nft_ctx_free_out; + } + + fp = fdopen(img_fd, "w"); + if (!fp) { + pr_perror("fdopen() failed"); + close(img_fd); + goto nft_ctx_free_out; + } + + nft_ctx_set_output(nft, fp); +#define DUMP_NFTABLES_CMD "list ruleset" +#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) + if (nft_run_cmd_from_buffer(nft, DUMP_NFTABLES_CMD, strlen(DUMP_NFTABLES_CMD))) +#elif defined(CONFIG_HAS_NFTABLES_LIB_API_1) + if (nft_run_cmd_from_buffer(nft, DUMP_NFTABLES_CMD)) +#else + BUILD_BUG_ON(1); +#endif + goto fp_close_out; + + ret = 0; + +fp_close_out: + fclose(fp); +nft_ctx_free_out: + nft_ctx_free(nft); + + return ret; +} +#endif + static int dump_netns_conf(struct ns_id *ns, struct cr_imgset *fds) { void *buf, *o_buf; @@ -2149,6 +2202,60 @@ out: return ret; } +#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1) +static inline int restore_nftables(int pid) +{ + int ret = -1; + struct cr_img *img; + struct nft_ctx *nft; + off_t img_data_size; + char *buf; + + img = open_image(CR_FD_NFTABLES, O_RSTR, pid); + if (img == NULL) + return -1; + if (empty_image(img)) { + /* Backward compatibility */ + pr_info("Skipping nft restore, no image"); + ret = 0; + goto image_close_out; + } + + if ((img_data_size = img_raw_size(img)) < 0) + goto image_close_out; + + if (read_img_str(img, &buf, img_data_size) < 0) + goto image_close_out; + + nft = nft_ctx_new(NFT_CTX_DEFAULT); + if (!nft) + goto buf_free_out; + + if (nft_ctx_buffer_output(nft) || nft_ctx_buffer_error(nft) || +#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) + nft_run_cmd_from_buffer(nft, buf, strlen(buf))) +#elif defined(CONFIG_HAS_NFTABLES_LIB_API_1) + nft_run_cmd_from_buffer(nft, buf)) +#else + { + BUILD_BUG_ON(1); + } +#endif + goto nft_ctx_free_out; + + ret = 0; + +nft_ctx_free_out: + nft_ctx_free(nft); +buf_free_out: + xfree(buf); +image_close_out: + close_image(img); + + return ret; +} +#endif + int read_net_ns_img(void) { struct ns_id *ns; @@ -2380,6 +2487,10 @@ int dump_net_ns(struct ns_id *ns) ret = dump_rule(fds); if (!ret) ret = dump_iptables(fds); +#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1) + if (!ret) + ret = dump_nftables(fds); +#endif if (!ret) ret = dump_netns_conf(ns, fds); } else if (ns->type != NS_ROOT) { @@ -2473,6 +2584,10 @@ static int prepare_net_ns_second_stage(struct ns_id *ns) ret = restore_rule(nsid); if (!ret) ret = restore_iptables(nsid); +#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1) + if (!ret) + ret = restore_nftables(nsid); +#endif } if (!ret) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index a1d1d9191..29a754058 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -14,6 +14,7 @@ RUN apk update && apk add \ libcap-dev \ libnet-dev \ libnl3-dev \ + nftables \ pkgconfig \ protobuf-c-dev \ protobuf-dev \ diff --git a/scripts/build/Dockerfile.fedora.tmpl b/scripts/build/Dockerfile.fedora.tmpl index 0500a8fc5..138588bce 100644 --- a/scripts/build/Dockerfile.fedora.tmpl +++ b/scripts/build/Dockerfile.fedora.tmpl @@ -10,6 +10,8 @@ RUN dnf install -y \ gnutls-devel \ iproute \ iptables \ + nftables \ + nftables-devel \ libaio-devel \ libasan \ libcap-devel \ diff --git a/scripts/feature-tests.mak b/scripts/feature-tests.mak index 39ddfd053..6f67c6035 100644 --- a/scripts/feature-tests.mak +++ b/scripts/feature-tests.mak @@ -147,4 +147,27 @@ int main(void) return 0; return 0; } + +endef + +define FEATURE_TEST_NFTABLES_LIB_API_0 + +#include + +int main(int argc, char **argv) +{ + return nft_run_cmd_from_buffer(nft_ctx_new(NFT_CTX_DEFAULT), \"cmd\", strlen(\"cmd\")); +} + +endef + +define FEATURE_TEST_NFTABLES_LIB_API_1 + +#include + +int main(int argc, char **argv) +{ + return nft_run_cmd_from_buffer(nft_ctx_new(NFT_CTX_DEFAULT), \"cmd\"); +} + endef From acb42456dc707a303b308fef67b2be92c81ab427 Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Mon, 11 Nov 2019 19:20:22 +0300 Subject: [PATCH 2273/4375] zdtm: nft tables preservation test Signed-off-by: Alexander Mikhalitsyn Signed-off-by: Alexander Mikhalitsyn [Added test_author to zdtm test] Signed-off-by: Dmitry Safonov --- scripts/build/Dockerfile.alpine | 1 + test/zdtm/static/Makefile | 1 + test/zdtm/static/netns-nft.c | 64 ++++++++++++++++++++++++++++ test/zdtm/static/netns-nft.checkskip | 3 ++ test/zdtm/static/netns-nft.desc | 5 +++ 5 files changed, 74 insertions(+) create mode 100644 test/zdtm/static/netns-nft.c create mode 100755 test/zdtm/static/netns-nft.checkskip create mode 100644 test/zdtm/static/netns-nft.desc diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index 29a754058..601a8693a 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -31,6 +31,7 @@ RUN apk add \ py-pip \ ip6tables \ iptables \ + nftables \ iproute2 \ tar \ bash \ diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index ea5d3c42e..19d93e315 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -288,6 +288,7 @@ TST_FILE = \ file_locks07 \ file_locks08 \ netns-nf \ + netns-nft \ maps_file_prot \ socket_close_data01 \ diff --git a/test/zdtm/static/netns-nft.c b/test/zdtm/static/netns-nft.c new file mode 100644 index 000000000..f4991afda --- /dev/null +++ b/test/zdtm/static/netns-nft.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check that nft rules (some) are kept"; +const char *test_author = "Alexander Mikhalitsyn "; + +char *filename; +TEST_OPTION(filename, string, "file name", 1); + +int main(int argc, char **argv) +{ + char cmd[128]; + + test_init(argc, argv); + + /* create nft table */ + if (system("nft add table inet netns-nft-zdtm-test")) { + pr_perror("Can't create nft table"); + return -1; + } + + /* create input chain in table */ + if (system("nft add chain inet netns-nft-zdtm-test input { type filter hook input priority 0 \\; }")) { + pr_perror("Can't create input chain in nft table"); + return -1; + } + + /* block ICMPv4 traffic */ + if (system("nft add rule inet netns-nft-zdtm-test input meta nfproto ipv4 icmp type { echo-request } reject")) { + pr_perror("Can't set input rule"); + return -1; + } + + /* save resulting nft table */ + sprintf(cmd, "nft list table inet netns-nft-zdtm-test > pre-%s", filename); + if (system(cmd)) { + pr_perror("Can't get nft table"); + return -1; + } + + test_daemon(); + test_waitsig(); + + /* get nft table */ + sprintf(cmd, "nft list table inet netns-nft-zdtm-test > post-%s", filename); + if (system(cmd)) { + fail("Can't get nft table"); + return -1; + } + + /* compare nft table before/after c/r */ + sprintf(cmd, "diff pre-%s post-%s", filename, filename); + if (system(cmd)) { + fail("nft table differ"); + return -1; + } + + pass(); + return 0; +} diff --git a/test/zdtm/static/netns-nft.checkskip b/test/zdtm/static/netns-nft.checkskip new file mode 100755 index 000000000..270cafeb5 --- /dev/null +++ b/test/zdtm/static/netns-nft.checkskip @@ -0,0 +1,3 @@ +#!/bin/bash + +test -f /usr/sbin/nft || exit 1 diff --git a/test/zdtm/static/netns-nft.desc b/test/zdtm/static/netns-nft.desc new file mode 100644 index 000000000..f53890a24 --- /dev/null +++ b/test/zdtm/static/netns-nft.desc @@ -0,0 +1,5 @@ +{ 'deps': [ '/bin/sh', + '/usr/sbin/nft', + '/usr/bin/diff'], + 'flags': 'suid', + 'flavor': 'ns uns'} From 7622b7a70eb7a00b2ba542f9118f4351b3df2538 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 18 Dec 2019 23:32:32 +0000 Subject: [PATCH 2274/4375] files: fix ghost file error path Signed-off-by: Nicolas Viennot --- criu/files-reg.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 2f68bc03f..90fb7dd7f 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -844,10 +844,13 @@ static int dump_ghost_remap(char *path, const struct stat *st, gf->dev = phys_dev; gf->ino = st->st_ino; gf->id = ghost_file_ids++; - list_add_tail(&gf->list, &ghost_files); - if (dump_ghost_file(lfd, gf->id, st, phys_dev)) + if (dump_ghost_file(lfd, gf->id, st, phys_dev)) { + xfree(gf); return -1; + } + + list_add_tail(&gf->list, &ghost_files); dump_entry: rpe.orig_id = id; From 2ac43cd426badfc6d68582b203ace318e5f79427 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 30 Dec 2019 20:27:40 +0000 Subject: [PATCH 2275/4375] python: Improve decoding of file flags Signed-off-by: Nicolas Viennot --- lib/py/images/pb2dict.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index daaa7297e..6fce4be22 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -105,11 +105,22 @@ mmap_status_map = [ ] rfile_flags_map = [ - ('O_WRONLY', 0o1), - ('O_RDWR', 0o2), - ('O_APPEND', 0o2000), - ('O_DIRECT', 0o40000), - ('O_LARGEFILE', 0o100000), + ('O_WRONLY', 0o00000001), + ('O_RDWR', 0o00000002), + ('O_CREAT', 0o00000100), + ('O_EXCL', 0o00000200), + ('O_NOCTTY', 0o00000400), + ('O_TRUNC', 0o00001000), + ('O_APPEND', 0o00002000), + ('O_NONBLOCK', 0o00004000), + ('O_DSYNC', 0o00010000), + ('FASYNC', 0o00020000), + ('O_DIRECT', 0o00040000), + ('O_LARGEFILE', 0o00100000), + ('O_DIRECTORY', 0o00200000), + ('O_NOFOLLOW', 0o00400000), + ('O_NOATIME', 0o01000000), + ('O_CLOEXEC', 0o02000000), ] pmap_flags_map = [ From 8255caf27b5e2bb96af6affc161b8d0d3bbdccbe Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 30 Dec 2019 20:29:27 +0000 Subject: [PATCH 2276/4375] files: Remove O_CLOEXEC from file flags The kernel artificially adds the O_CLOEXEC flag when reading from the /proc/fdinfo/fd interface if FD_CLOEXEC is set on the file descriptor used to access the file. This commit removes the O_CLOEXEC flag in our file flags. To restore the proper FD_CLOEXEC value in each of the file descriptors, CRIU uses fcntl(F_GETFD) to retrieve the FD_CLOEXEC status, and restore it later with fcntl(F_SETFD). This is necessary because multiple file descriptors may point to the same open file. --- criu/files.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/criu/files.c b/criu/files.c index ffdaa459f..e26897870 100644 --- a/criu/files.c +++ b/criu/files.c @@ -382,7 +382,13 @@ static int fill_fd_params(struct pid *owner_pid, int fd, int lfd, p->fs_type = fsbuf.f_type; p->fd = fd; p->pos = fdinfo.pos; - p->flags = fdinfo.flags; + /* + * The kernel artificially adds the O_CLOEXEC flag on the file pointer + * flags by looking at the flags on the file descriptor (see kernel + * code fs/proc/fd.c). FD_CLOEXEC is a file descriptor property, which + * is saved in fd_flags. + */ + p->flags = fdinfo.flags & ~O_CLOEXEC; p->mnt_id = fdinfo.mnt_id; p->pid = owner_pid->real; p->fd_flags = opts->flags; From 75a74423801a83ef7657e67e0b016a76f741db11 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 30 Dec 2019 20:21:03 +0000 Subject: [PATCH 2277/4375] files: Add FD_CLOEXEC test --- test/zdtm/static/Makefile | 1 + test/zdtm/static/file_cloexec.c | 63 +++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 test/zdtm/static/file_cloexec.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 19d93e315..5ca05ee9e 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -122,6 +122,7 @@ TST_NOFILE := \ groups \ pdeath_sig \ file_fown \ + file_cloexec \ proc-self \ eventfs00 \ epoll \ diff --git a/test/zdtm/static/file_cloexec.c b/test/zdtm/static/file_cloexec.c new file mode 100644 index 000000000..b8eba39e5 --- /dev/null +++ b/test/zdtm/static/file_cloexec.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check FD_CLOEXEC flag"; +const char *test_author = "Nicolas Viennot "; + +#define err(exitcode, msg, ...) ({ pr_perror(msg, ##__VA_ARGS__); exit(exitcode); }) + +static void assert_fd_flags(int fd, int mask, int value) +{ + int flags = fcntl(fd, F_GETFD); + if (flags == -1) + err(1, "Can't get fd flags"); + + if ((flags & mask) != value) { + fail("fd flags mismatch"); + exit(1); + } +} + +int main(int argc, char *argv[]) +{ + int fd1, fd2, fd3, fd4; + + test_init(argc, argv); + + fd1 = open("/", O_RDONLY | O_CLOEXEC); + if (fd1 < 0) + err(1, "Can't open()"); + + fd2 = open("/", O_RDONLY); + if (fd2 < 0) + err(1, "Can't open()"); + + fd3 = dup(fd1); + if (fd3 < 0) + err(1, "Can't dup()"); + + fd4 = fcntl(fd2, F_DUPFD_CLOEXEC, 0); + if (fd4 < 0) + err(1, "Can't dup()"); + + test_daemon(); + test_waitsig(); + + assert_fd_flags(fd1, FD_CLOEXEC, FD_CLOEXEC); + assert_fd_flags(fd2, FD_CLOEXEC, 0); + assert_fd_flags(fd3, FD_CLOEXEC, 0); + assert_fd_flags(fd4, FD_CLOEXEC, FD_CLOEXEC); + + pass(); + + return 0; +} From 8b5dea33f6bff8e8d35e709e026218caf7d4a2d8 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 9 Jan 2020 10:31:41 +0000 Subject: [PATCH 2278/4375] travis: switch alpine to python3 Now that Python 2 has officially reached its end of life also switch the Alpine based test to Python 3. Signed-off-by: Adrian Reber --- scripts/build/Dockerfile.alpine | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index 601a8693a..5785102da 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -18,7 +18,7 @@ RUN apk update && apk add \ pkgconfig \ protobuf-c-dev \ protobuf-dev \ - python \ + python3 \ sudo COPY . /criu @@ -28,7 +28,6 @@ RUN mv .ccache /tmp && make mrproper && ccache -sz && \ date && make -j $(nproc) CC="$CC" && date && ccache -s RUN apk add \ - py-pip \ ip6tables \ iptables \ nftables \ @@ -37,10 +36,16 @@ RUN apk add \ bash \ go \ e2fsprogs \ + py-yaml \ + py3-flake8 \ asciidoctor # The rpc test cases are running as user #1000, let's add the user RUN adduser -u 1000 -D test -RUN pip install PyYAML future protobuf ipaddress junit_xml flake8 +RUN pip3 install protobuf junit_xml + +# For zdtm we need an unversioned python binary +RUN ln -s /usr/bin/python3 /usr/bin/python + RUN make -C test/zdtm From 1e9ff2aa03206102a7aeaf1d32f61056d3d05e46 Mon Sep 17 00:00:00 2001 From: Nidhi Gupta Date: Sun, 8 Dec 2019 10:14:40 +0530 Subject: [PATCH 2279/4375] Add Socket-based Java Functional Tests Signed-off-by: Nidhi Gupta --- scripts/build/Dockerfile.openj9-ubuntu | 1 + test/javaTests/README.md | 11 +- .../criu/java/tests/CheckpointRestore.java | 1 + .../src/org/criu/java/tests/Helper.java | 2 +- .../src/org/criu/java/tests/SocketHelper.java | 100 ++++++++ .../src/org/criu/java/tests/Sockets.java | 141 ++++++++++++ .../org/criu/java/tests/SocketsClient.java | 133 +++++++++++ .../org/criu/java/tests/SocketsConnect.java | 157 +++++++++++++ .../criu/java/tests/SocketsConnectClient.java | 130 +++++++++++ .../criu/java/tests/SocketsConnectServer.java | 151 ++++++++++++ .../src/org/criu/java/tests/SocketsData.java | 156 +++++++++++++ .../criu/java/tests/SocketsDataClient.java | 141 ++++++++++++ .../criu/java/tests/SocketsDataServer.java | 124 ++++++++++ .../org/criu/java/tests/SocketsListen.java | 153 +++++++++++++ .../criu/java/tests/SocketsListenClient.java | 136 +++++++++++ .../criu/java/tests/SocketsListenServer.java | 160 +++++++++++++ .../org/criu/java/tests/SocketsMultiple.java | 152 +++++++++++++ .../java/tests/SocketsMultipleClient.java | 174 ++++++++++++++ .../java/tests/SocketsMultipleServer.java | 215 ++++++++++++++++++ .../org/criu/java/tests/SocketsServer.java | 142 ++++++++++++ test/javaTests/test.xml | 46 ++++ 21 files changed, 2424 insertions(+), 2 deletions(-) create mode 100644 test/javaTests/src/org/criu/java/tests/SocketHelper.java create mode 100644 test/javaTests/src/org/criu/java/tests/Sockets.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsClient.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsConnect.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsConnectClient.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsConnectServer.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsData.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsDataClient.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsDataServer.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsListen.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsListenClient.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsListenServer.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsMultiple.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsMultipleClient.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsMultipleServer.java create mode 100644 test/javaTests/src/org/criu/java/tests/SocketsServer.java diff --git a/scripts/build/Dockerfile.openj9-ubuntu b/scripts/build/Dockerfile.openj9-ubuntu index 13d9080ff..f235cc004 100644 --- a/scripts/build/Dockerfile.openj9-ubuntu +++ b/scripts/build/Dockerfile.openj9-ubuntu @@ -18,6 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends protobuf-c-comp make \ git \ pkg-config \ + iptables \ gcc \ maven diff --git a/test/javaTests/README.md b/test/javaTests/README.md index 670741677..4315b9b12 100644 --- a/test/javaTests/README.md +++ b/test/javaTests/README.md @@ -30,7 +30,16 @@ Here we test the File-Based Java APIs by checkpointing the application in the fo ## Memory mapping Java APIs Here we test the Memory Mapping APIs by checkpointing the application in following scenario and verifying the contents after restore: -- Memory-mapping a file and writing its content to another file. (MemoryMappings.java) +- Memory-mapping a file and writing its content to another file. (MemoryMappings.java) + +## Socket-based Java APIs + +Here we test the Socket-based API's by checkpointing the application in the following scenario and verifying the state after restore: +- Checkpointing the server process in the middle of data transfer. (Sockets.java) +- Checkpointing the server process after it has bound to a port but is not listening for client connections. (SocketListen.java) +- Checkpointing the server process while it is listening for client connections, and no client has connected yet. (SocketConnect.java) +- Checkpointing the server process when it has multiple clients in multiple states connected to it. (SocketMultiple.java) +- Checkpointing the client process in the middle of data transfer. (SocketsData.java) ### Prerequisites for running the tests: - Maven diff --git a/test/javaTests/src/org/criu/java/tests/CheckpointRestore.java b/test/javaTests/src/org/criu/java/tests/CheckpointRestore.java index b848c9938..9d61e126f 100644 --- a/test/javaTests/src/org/criu/java/tests/CheckpointRestore.java +++ b/test/javaTests/src/org/criu/java/tests/CheckpointRestore.java @@ -154,6 +154,7 @@ public class CheckpointRestore { */ while (Helper.STATE_INIT == currentState) { currentState = mappedByteBuffer.getChar(Helper.MAPPED_INDEX); + Thread.sleep(100); } /* diff --git a/test/javaTests/src/org/criu/java/tests/Helper.java b/test/javaTests/src/org/criu/java/tests/Helper.java index fdf20bb52..9a1b33328 100644 --- a/test/javaTests/src/org/criu/java/tests/Helper.java +++ b/test/javaTests/src/org/criu/java/tests/Helper.java @@ -30,7 +30,7 @@ class Helper { * the pid to the pidFile. * * @param testName Name of the java test - * @param pid Pid of the java test process + * @param pid Pid of the java test process * @param logger * @return 0 or 1 denoting whether the function was successful or not. * @throws IOException diff --git a/test/javaTests/src/org/criu/java/tests/SocketHelper.java b/test/javaTests/src/org/criu/java/tests/SocketHelper.java new file mode 100644 index 000000000..684125019 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketHelper.java @@ -0,0 +1,100 @@ +package org.criu.java.tests; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.MappedByteBuffer; +import java.util.logging.FileHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; + +class SocketHelper { + + static char STATE_LISTEN = 'S'; + static char STATE_SUCCESS = 'Z'; + static String IP_ADDRESS = "127.0.0.1"; + + /** + * Creates a new log file, for the logger to log in. + * + * @param testName Name of the server or client program + * @param parentTestName Name of the test + * @param logger + * @throws IOException + */ + static void init(String testName, String parentTestName, Logger logger) throws IOException { + FileHandler handler = new FileHandler(Helper.OUTPUT_FOLDER_NAME + "/" + parentTestName + "/" + testName + ".log", false); + handler.setFormatter(new SimpleFormatter()); + handler.setLevel(Level.FINE); + logger.addHandler(handler); + logger.setLevel(Level.FINE); + } + + /** + * Writes pid of the process to be checkpointed in the file + * + * @param parentTestName Name of the test + * @param pid Pid of the process to be checkpointed + * @throws IOException + */ + static void writePid(String parentTestName, String pid) throws IOException { + File pidfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + parentTestName + "/" + parentTestName + Helper.PID_APPEND); + BufferedWriter pidwriter = new BufferedWriter(new FileWriter(pidfile)); + /* + * Overwriting pid to be checkpointed + */ + pidwriter.write(pid + "\n"); + pidwriter.close(); + } + + /** + * Waits for the MappedByteBuffer to change state from STATE_CHECKPOINT to STATE_RESTORE + * + * @param socketMappedBuffer MappedByteBuffer between the client, server and the controller process. + * @param logger + */ + static void socketWaitForRestore(MappedByteBuffer socketMappedBuffer, Logger logger) { + while (Helper.STATE_CHECKPOINT == socketMappedBuffer.getChar(Helper.MAPPED_INDEX)) { + ; + } + if (Helper.STATE_RESTORE != socketMappedBuffer.getChar(Helper.MAPPED_INDEX)) { + logger.log(Level.SEVERE, "Server socket was not in expected restore state " + socketMappedBuffer.getChar(Helper.MAPPED_INDEX)); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } else { + logger.log(Level.INFO, "Restored!!!"); + } + } + + /** + * Puts the MappedByteBuffer to Helper.STATE_CHECKPOINT and waits for CheckpointRestore.java to change its state to Helper.STATE_RESTORE + * + * @param b MappedByteBuffer between the controller process and CheckpointRestore.java + * @param logger Logger to log the messages + * @param p1 Process object for the client process + * @param p2 Process object for the server process + */ + static void checkpointAndWait(MappedByteBuffer b, Logger logger, Process p1, Process p2) { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_CHECKPOINT); + char c = b.getChar(Helper.MAPPED_INDEX); + while (Helper.STATE_CHECKPOINT == c) { + c = b.getChar(Helper.MAPPED_INDEX); + } + if (Helper.STATE_TERMINATE == c) { + logger.log(Level.SEVERE, "Error during checkpoint-restore, Test terminated"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + p1.destroy(); + p2.destroy(); + System.exit(1); + } + if (Helper.STATE_RESTORE != c) { + logger.log(Level.SEVERE, "Error: Test state is not the expected Restored state"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + p1.destroy(); + p2.destroy(); + System.exit(1); + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/Sockets.java b/test/javaTests/src/org/criu/java/tests/Sockets.java new file mode 100644 index 000000000..94cc217c4 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/Sockets.java @@ -0,0 +1,141 @@ +package org.criu.java.tests; + +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class Sockets { + static String TESTNAME = "Sockets"; + + /** + * Runs the client and server process, checkpoints the server process while its in the middle of data transfer + * + * @param args Not used + */ + public static void main(String[] args) { + MappedByteBuffer b = null, socketMappedBuffer = null; + FileChannel channel; + String pid; + String port = "49200"; + Logger logger = null; + try { + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + + /* + * Mapped buffer 'b' to communicate between CheckpointRestore.java and this process. + */ + File f = new File(Helper.MEMORY_MAPPED_FILE_NAME); + channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + b = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + pid = bean.getName(); + Helper.init(TESTNAME, pid, logger); + logger.log(Level.INFO, "Test init done; pid written to pid file; beginning with test"); + + if (Helper.STATE_INIT != b.getChar(Helper.MAPPED_INDEX)) { + logger.log(Level.SEVERE, "Error: Error in memory mapping, test is not in init state"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Creating socketBufferFile and setting the init value of buffer"); + + /* + * Socket Mapped Buffer to communicate between server process, client process and this process. + */ + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + TESTNAME + "/SocketsFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_INIT); + + logger.log(Level.INFO, "Starting server and client process"); + ProcessBuilder builder = new ProcessBuilder("java", "-cp", "target/classes", Helper.PACKAGE_NAME + "." + "SocketsServer", TESTNAME, port); + Process serverProcess = builder.start(); + logger.log(Level.INFO, "Server process started"); + builder = new ProcessBuilder("java", "-cp", "target/classes", Helper.PACKAGE_NAME + "." + "SocketsClient", TESTNAME, port); + Process clientProcess = builder.start(); + + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_INIT || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_LISTEN) { + ; + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + logger.log(Level.SEVERE, "Killing the server and client process"); + logger.log(Level.SEVERE, "Error took place in the client or server process; check their log for details"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_CHECKPOINT) { + logger.log(Level.SEVERE, "Killing the server and client process"); + logger.log(Level.SEVERE, "State is not the expected 'to be checkpointed' state"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_CHECKPOINT) { + logger.log(Level.INFO, "Going to checkpoint server process"); + SocketHelper.checkpointAndWait(b, logger, serverProcess, clientProcess); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_RESTORE); + logger.log(Level.INFO, "Process has been restored"); + } + /* + * Loop while test is running. + */ + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_RESTORE || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_SUCCESS) { + ; + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_FAIL && socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_PASS) { + logger.log(Level.SEVERE, "Killing the server and client process"); + logger.log(Level.SEVERE, "Received wrong message from the child process: not the expected finish message"); + logger.log(Level.SEVERE, "Check their log files for more details"); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL) { + logger.log(Level.SEVERE, "Killing the server and client process"); + logger.log(Level.SEVERE, "Error in the client or server process: check their log for details"); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + /* + * Client process puts socketMappedBuffer to Pass state if the test passed. + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_PASS) { + logger.log(Level.INFO, Helper.PASS_MESSAGE); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + } else { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + System.exit(0); + + } catch (Exception e) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + e.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occured:" + e); + logger.log(Level.FINE, writer.toString()); + } + if (b != null) { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + System.exit(5); + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsClient.java b/test/javaTests/src/org/criu/java/tests/SocketsClient.java new file mode 100644 index 000000000..1c8e7b9a1 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsClient.java @@ -0,0 +1,133 @@ +package org.criu.java.tests; + +import java.io.*; +import java.net.Socket; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsClient { + static String TESTNAME = "SocketsClient"; + + public static void main(String[] args) { + MappedByteBuffer socketMappedBuffer = null; + FileChannel channel; + Socket socket = null; + Logger logger = null; + String msg1 = "Ch@ckM@$$@Ge!1", msg2 = "cH@C!m$SG!!2", + readMssg, msg3 = "@Ft@rCPM$$g3", msg4 = "Aft@rCPM$$g4"; + String parentTestName, portArg; + int port; + + try { + parentTestName = args[0]; + portArg = args[1]; + port = Integer.parseInt(portArg); + + /* + * Socket Mapped Buffer to communicate between server process, client process and the calling parent process. + */ + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + parentTestName + "/SocketsFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + SocketHelper.init(TESTNAME, parentTestName, logger); + + logger.log(Level.INFO, "Begin"); + logger.log(Level.INFO, "Parent name: " + parentTestName); + + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT && socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != SocketHelper.STATE_LISTEN) { + logger.log(Level.SEVERE, "Error: Socket-buffer not in expected Init state"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + } + logger.log(Level.INFO, "Client socket sending req to server at IP: 127.0.0.1 port:" + port); + + /* + * Ensure client does not try to connect to port before server has bound itself. + */ + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_INIT) { + ; + } + /* + * Socket Buffer should be put in SocketHelper.STATE_LISTEN state by server process, just before + * it starts listening for client connections. + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != SocketHelper.STATE_LISTEN) { + logger.log(Level.SEVERE, "Error: Buffer does not contain the expected 'server bound to port and listening' state"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + /* + * Ensure server has bound to port + */ + try { + Thread.sleep(10); + } catch (InterruptedException e) { + logger.log(Level.WARNING, "InterruptedException occurred!"); + } + + socket = new Socket(SocketHelper.IP_ADDRESS, port); + + PrintStream out = new PrintStream(socket.getOutputStream()); + BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + logger.log(Level.INFO, "Sending message to server " + msg1); + out.println(msg1); + + readMssg = br.readLine(); + logger.log(Level.INFO, "Message received from server " + readMssg); + if (!msg2.equals(readMssg)) { + logger.log(Level.SEVERE, "Error: wrong message received; message expected " + msg2); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + } + + logger.log(Level.INFO, "Sending message to server " + msg3); + out.println(msg3); + + readMssg = br.readLine(); + logger.log(Level.INFO, "Message received from server " + readMssg); + if (!msg4.equals(readMssg)) { + logger.log(Level.SEVERE, "Error: wrong message received; message expected " + msg4); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + socket.close(); + /* + * Wait for server process to end and then check whether it ended successfully or not + * If it has finished properly the socketMappedBuffer will contain SocketHelper.STATE_SUCCESS + */ + logger.log(Level.INFO, "Waiting for server process to end...."); + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_RESTORE) { + ; + } + /* + * Check the server process has ended successfully, if it was a success put Mapped Buffer to pass state, else to failed state + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_SUCCESS) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + } else { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + logger.log(Level.INFO, "Test ends"); + + } catch (Exception exception) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + exception.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occured:" + exception); + logger.log(Level.FINE, writer.toString()); + } + + if (socketMappedBuffer != null) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsConnect.java b/test/javaTests/src/org/criu/java/tests/SocketsConnect.java new file mode 100644 index 000000000..164c21089 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsConnect.java @@ -0,0 +1,157 @@ +package org.criu.java.tests; + +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsConnect { + static String TESTNAME = "SocketsConnect"; + + /** + * Runs the client and server process, checkpoints the server when its listening for incoming client connection requests on a port but no client has connected yet + * + * @param args Not used + */ + public static void main(String[] args) { + MappedByteBuffer b = null, socketMappedBuffer = null; + FileChannel channel; + String pid; + String port = "49200"; + Logger logger = null; + try { + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + + /* + * Mapped buffer 'b' to communicate between CheckpointRestore.java and this process. + */ + File f = new File(Helper.MEMORY_MAPPED_FILE_NAME); + channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + b = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + pid = bean.getName(); + Helper.init(TESTNAME, pid, logger); + logger.log(Level.INFO, "Test init done; pid written to pid file; beginning with test"); + + if (b.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT) { + logger.log(Level.SEVERE, "Error: Error in memory mapping, test is not in init state"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + /* + * Socket Mapped Buffer to communicate between server process, client process and this process. + */ + logger.log(Level.INFO, "Creating socketbufferfile and setting the init value of buffer"); + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + TESTNAME + "/SocketsConnectFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + /* + * Set socketMappedBuffer to init state. + */ + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_INIT); + logger.log(Level.INFO, "Starting server and client process"); + ProcessBuilder builder = new ProcessBuilder("java", "-cp", "target/classes", Helper.PACKAGE_NAME + "." + "SocketsConnectServer", TESTNAME, port); + Process serverProcess = builder.start(); + builder = new ProcessBuilder("java", "-cp", "target/classes", Helper.PACKAGE_NAME + "." + "SocketsConnectClient", TESTNAME, port); + Process clientProcess = builder.start(); + + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_INIT) { + ; + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + logger.log(Level.SEVERE, "Killing the server process and client process"); + logger.log(Level.SEVERE, "Some error took place in the client or server process: check their log for details"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL) { + logger.log(Level.SEVERE, "Killing the server process and client process"); + logger.log(Level.SEVERE, "Exception occured in the client or server process: check their log for details"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_CHECKPOINT) { + logger.log(Level.SEVERE, "Killing the server process and client process"); + logger.log(Level.SEVERE, "State is not the expected 'to be checkpointed' state"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_CHECKPOINT) { + logger.log(Level.INFO, "Going to checkpoint server process"); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + logger.log(Level.WARNING, "Thread was interrupted"); + } + SocketHelper.checkpointAndWait(b, logger, serverProcess, clientProcess); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_RESTORE); + logger.log(Level.INFO, "Process has been restored!"); + } + + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_RESTORE || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_LISTEN) { + ; + } + char bufchar = socketMappedBuffer.getChar(Helper.MAPPED_INDEX); + if (bufchar != Helper.STATE_FAIL && bufchar != Helper.STATE_PASS && bufchar != SocketHelper.STATE_SUCCESS) { + logger.log(Level.SEVERE, "Received wrong message from the child process: not the expected finish message"); + logger.log(Level.SEVERE, "Check their log files for more details"); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + logger.log(Level.SEVERE, "Error in the client or server process: check their log for details"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_SUCCESS) { + ; + } + + /* + * Client process puts socketMappedBuffer to 'P'-Pass state if the test passed. + * Send pass message to Checkpoint-restore.java + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_PASS) { + logger.log(Level.INFO, Helper.PASS_MESSAGE); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + } else { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + System.exit(0); + + } catch (Exception e) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + e.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occured:" + e); + logger.log(Level.FINE, writer.toString()); + } + if (b != null) { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + System.exit(5); + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsConnectClient.java b/test/javaTests/src/org/criu/java/tests/SocketsConnectClient.java new file mode 100644 index 000000000..ed1c7fab3 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsConnectClient.java @@ -0,0 +1,130 @@ +package org.criu.java.tests; + +import java.io.*; +import java.net.Socket; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsConnectClient { + static String TESTNAME = "SocketsConnectClient"; + + public static void main(String[] args) { + MappedByteBuffer socketMappedBuffer = null; + FileChannel channel; + Socket socket = null; + String parentTestName, portArg; + int port; + Logger logger = null; + try { + parentTestName = args[0]; + portArg = args[1]; + port = Integer.parseInt(portArg); + + String msg1 = "Ch@ckM@$$@Ge!1", msg2 = "cH@C!m$SG!!2", + readMssg, msg3 = "@Ft@rCPM$$g3", msg4 = "Aft@rCPM$$g4"; + + /* + * Socket Mapped Buffer to communicate between server process, client process and the calling parent process. + */ + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + parentTestName + "/SocketsConnectFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + SocketHelper.init(TESTNAME, parentTestName, logger); + + logger.log(Level.INFO, "Begin"); + logger.log(Level.INFO, "Parent name: " + parentTestName); + + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT && socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_CHECKPOINT && socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_RESTORE) { + logger.log(Level.SEVERE, "Error: Socket-buffer not in expected Init state"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Waiting for CR"); + /* + * Wait for Checkpoint-Restore to occur + */ + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_INIT || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_CHECKPOINT) { + ; + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_RESTORE) { + logger.log(Level.SEVERE, "Error:Buffer does not contain the expected restored state: " + socketMappedBuffer.getChar(Helper.MAPPED_INDEX)); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + logger.log(Level.INFO, "Restored"); + logger.log(Level.INFO, "Client socket sending req to server at IP: 127.0.0.1 port:" + port); + + /* + * Server should has have been listening for client connections when it was checkpointed, and it should continue to listen after restore. + */ + try { + socket = new Socket(SocketHelper.IP_ADDRESS, port); + } catch (Exception e) { + logger.log(Level.SEVERE, "Exception occured when connecting to port: " + e); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + PrintStream out = new PrintStream(socket.getOutputStream()); + BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + logger.log(Level.INFO, "Sending message to server " + msg1); + out.println(msg1); + + readMssg = br.readLine(); + logger.log(Level.INFO, "message received from server " + readMssg); + if (!msg2.equals(readMssg)) { + logger.log(Level.SEVERE, "wrong message received; Expected " + msg2); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + logger.log(Level.INFO, "Sending message to server " + msg3); + out.println(msg3); + + readMssg = br.readLine(); + logger.log(Level.INFO, "message received from server " + readMssg); + if (!msg4.equals(readMssg)) { + logger.log(Level.SEVERE, "wrong message received; Expected " + msg4); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + socket.close(); + + /* + * Wait for server process to end. + */ + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_RESTORE) { + ; + } + /* + * Check the server process has ended successfully, if it was a success put Mapped Buffer to pass state, else to failed state + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_SUCCESS) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + } else { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + } catch (Exception exception) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + exception.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occured:" + exception); + logger.log(Level.FINE, writer.toString()); + } + + if (socketMappedBuffer != null) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsConnectServer.java b/test/javaTests/src/org/criu/java/tests/SocketsConnectServer.java new file mode 100644 index 000000000..1e4cf3aeb --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsConnectServer.java @@ -0,0 +1,151 @@ +package org.criu.java.tests; + +import java.io.*; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsConnectServer { + static String TESTNAME = "SocketsConnectServer"; + + public static void main(String[] args) { + MappedByteBuffer socketMappedBuffer = null; + FileChannel channel; + Socket socket = null; + String msg1 = "Ch@ckM@$$@Ge!1", msg2 = "cH@C!m$SG!!2", msg3 = "@Ft@rCPM$$g3", + msg4 = "Aft@rCPM$$g4", readMssg; + Logger logger = null; + String parentTestName, portArg; + int port; + try { + parentTestName = args[0]; + portArg = args[1]; + port = Integer.parseInt(portArg); + + /* + * Socket Mapped Buffer to communicate between server process, client process and the calling parent process. + */ + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + parentTestName + "/SocketsConnectFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + SocketHelper.init(TESTNAME, parentTestName, logger); + + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + String pid = bean.getName(); + SocketHelper.writePid(parentTestName, pid); + + logger.log(Level.INFO, "Begin"); + logger.log(Level.INFO, "Parent name: " + parentTestName); + logger.log(Level.INFO, "Server pid: " + pid); + logger.log(Level.INFO, "socket buffer connection opened"); + + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT) { + logger.log(Level.SEVERE, "Socket-buffer not in expected Init state"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + } + + ServerSocket ser = new ServerSocket(port); + logger.log(Level.INFO, "Server will be listening on Port: " + port); + + /* + * Timeout after 7 sec if client does not connect + */ + try { + ser.setSoTimeout(7 * 1000); + + } catch (SocketException e) { + logger.log(Level.SEVERE, "Cannot set timeout!"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + logger.log(Level.INFO, "Waiting for client to connect"); + logger.log(Level.INFO, "Going to checkpoint"); + + try { + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + ser.close(); + System.exit(1); + } + /* + * Checkpoint when server is listening for connections, and no client has connected to the server. + */ + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_CHECKPOINT); + socket = ser.accept(); + SocketHelper.socketWaitForRestore(socketMappedBuffer, logger); + + } catch (Exception e) { + logger.log(Level.SEVERE, "Timed out while waiting for client to connect\n" + e); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + if (!ser.isBound()) { + logger.log(Level.SEVERE, "Server is not bound to a port"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + if (ser.getLocalPort() != port) { + logger.log(Level.SEVERE, "Server is not listening on correct port"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); + PrintStream outstream = new PrintStream(socket.getOutputStream()); + + readMssg = br.readLine(); + logger.log(Level.INFO, "Read message 1: " + readMssg); + if (!msg1.equals(readMssg)) { + logger.log(Level.SEVERE, "Message 1 received was wrong,received: " + readMssg + " expected: " + msg1); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + logger.log(Level.INFO, "Sending message: " + msg2); + outstream.println(msg2); + + readMssg = br.readLine(); + logger.log(Level.INFO, "Read message 3: " + readMssg); + + if (!msg3.equals(readMssg)) { + logger.log(Level.SEVERE, "Message 3 received was wrong, received: " + readMssg + " expected: " + msg3); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + outstream.println(msg4); + logger.log(Level.INFO, "Sent message 4 " + msg4); + + socket.close(); + + /* + * Put Socket-MappedBuffer to state SocketHelper.STATE_SUCCESS telling the server process has ended successfully. + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + System.exit(1); + } else { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, SocketHelper.STATE_SUCCESS); + } + } catch (Exception exception) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + exception.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occurred:" + exception); + logger.log(Level.FINE, writer.toString()); + } + + if (socketMappedBuffer != null) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsData.java b/test/javaTests/src/org/criu/java/tests/SocketsData.java new file mode 100644 index 000000000..67d8cef0e --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsData.java @@ -0,0 +1,156 @@ +package org.criu.java.tests; + +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsData { + static String TESTNAME = "SocketsData"; + + /** + * Runs the server and client processes, checkpoints the client process when its in the middle of data transfer + * + * @param args Not used + */ + public static void main(String[] args) { + MappedByteBuffer b = null, socketMappedBuffer = null; + FileChannel channel; + String pid; + Logger logger = null; + String port = "49200"; + try { + /* + * Mapped buffer 'b' to communicate between CheckpointRestore.java and this process. + */ + File f = new File(Helper.MEMORY_MAPPED_FILE_NAME); + channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + b = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + pid = bean.getName(); + Helper.init(TESTNAME, pid, logger); + logger.log(Level.INFO, "Test init done; pid written to pid file; beginning with test"); + + if (b.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT) { + logger.log(Level.SEVERE, "Error: Error in memory mapping, test is not in init state"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + /* + * Socket Mapped Buffer to communicate between server process, client process and this process. + */ + logger.log(Level.INFO, "Creating socketbufferfile and setting the init value of buffer"); + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + TESTNAME + "/SocketsDataFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + /* + * Set socketMappedBuffer to init state. + */ + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_INIT); + logger.log(Level.INFO, "Starting server and client process"); + ProcessBuilder builder = new ProcessBuilder("java", "-cp", "target/classes", Helper.PACKAGE_NAME + "." + "SocketsDataServer", TESTNAME, port); + Process serverProcess = builder.start(); + builder = new ProcessBuilder("java", "-cp", "target/classes", Helper.PACKAGE_NAME + "." + "SocketsDataClient", TESTNAME, port); + Process clientProcess = builder.start(); + + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_INIT || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_LISTEN) { + ; + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + logger.log(Level.SEVERE, "Killing the server process and client process"); + logger.log(Level.SEVERE, "Some error took place in the client or server process: check their log for details"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL) { + logger.log(Level.SEVERE, "Killing the server process and client process"); + logger.log(Level.SEVERE, "Exception occured in the client or server process: check their log for details"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_CHECKPOINT) { + logger.log(Level.SEVERE, "Killing the server process and client process"); + logger.log(Level.SEVERE, "State is not the expected 'to be checkpointed' state"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_CHECKPOINT) { + logger.log(Level.INFO, "Going to checkpoint client process"); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + logger.log(Level.WARNING, "Thread was interrupted"); + } + SocketHelper.checkpointAndWait(b, logger, serverProcess, clientProcess); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_RESTORE); + logger.log(Level.INFO, "Process has been restored!"); + } + + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_RESTORE) { + ; + } + char bufchar = socketMappedBuffer.getChar(Helper.MAPPED_INDEX); + if (bufchar != Helper.STATE_FAIL && bufchar != Helper.STATE_PASS && bufchar != SocketHelper.STATE_SUCCESS) { + logger.log(Level.SEVERE, "Received wrong message from the child process: not the expected finish message"); + logger.log(Level.SEVERE, "Check their log files for more details"); + serverProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + logger.log(Level.SEVERE, "Error in the client or server process: check their log for details"); + serverProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_SUCCESS) { + ; + } + + /* + * Client process puts socketMappedBuffer to STATE_PASS if the test passed. + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_PASS) { + logger.log(Level.INFO, Helper.PASS_MESSAGE); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + } else { + logger.log(Level.INFO, "Did not receive pass message from the client process"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + } catch (Exception e) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + e.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occured:" + e); + logger.log(Level.FINE, writer.toString()); + } + if (b != null) { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + System.exit(5); + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsDataClient.java b/test/javaTests/src/org/criu/java/tests/SocketsDataClient.java new file mode 100644 index 000000000..49885a886 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsDataClient.java @@ -0,0 +1,141 @@ +package org.criu.java.tests; + +import java.io.*; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.net.Socket; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsDataClient { + static String TESTNAME = "SocketsDataClient"; + + public static void main(String[] args) { + MappedByteBuffer socketMappedBuffer = null; + FileChannel channel; + Socket socket = null; + String parentTestName, portArg; + int port; + Logger logger = null; + + try { + parentTestName = args[0]; + portArg = args[1]; + port = Integer.parseInt(portArg); + String msg1 = "Ch@ckM@$$@Ge!1", msg2 = "cH@C!m$SG!!2", + readMssg, msg3 = "@Ft@rCPM$$g3", msg4 = "Aft@rCPM$$g4"; + + /* + * Socket Mapped Buffer to communicate between server process, client process and the calling parent process. + */ + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + parentTestName + "/SocketsDataFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + SocketHelper.init(TESTNAME, parentTestName, logger); + + logger.log(Level.INFO, "Begin"); + logger.log(Level.INFO, "Parent name: " + parentTestName); + + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + String pid = bean.getName(); + + logger.log(Level.INFO, "Client pid: " + pid); + SocketHelper.writePid(parentTestName, pid); + + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT && socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != SocketHelper.STATE_LISTEN) { + logger.log(Level.SEVERE, "Error: Socket-buffer not in expected Init state"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_INIT) { + ; + } + /* + * Socket Mapped Buffer should be in 'Server listening for connections' state + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != SocketHelper.STATE_LISTEN) { + logger.log(Level.SEVERE, "socket-buffer not in expected state, current state: " + socketMappedBuffer.getChar(Helper.MAPPED_INDEX)); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + /* + * Server starts listening on port after putting the Mapped Buffer is in SocketHelper.STATE_LISTEN state + */ + logger.log(Level.INFO, "Client socket sending req to server at IP: 127.0.0.1 port:" + port); + + try { + socket = new Socket(SocketHelper.IP_ADDRESS, port); + } catch (IOException e) { + logger.log(Level.SEVERE, "Exception occured when connecting to port: " + e); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + PrintStream out = new PrintStream(socket.getOutputStream()); + BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + logger.log(Level.INFO, "Sending message to server " + msg1); + out.println(msg1); + + readMssg = br.readLine(); + logger.log(Level.INFO, "message received from server " + readMssg); + if (!msg2.equals(readMssg)) { + logger.log(Level.SEVERE, "wrong message received; Expected " + msg2); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + /* + * Checkpoints and wait for Restore + */ + logger.log(Level.INFO, "Going to checkpoint"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_CHECKPOINT); + SocketHelper.socketWaitForRestore(socketMappedBuffer, logger); + + logger.log(Level.INFO, "Sending message to server " + msg3); + out.println(msg3); + + readMssg = br.readLine(); + logger.log(Level.INFO, "message received from server " + readMssg); + if (!msg4.equals(readMssg)) { + logger.log(Level.SEVERE, "wrong message received; Expected " + msg2); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + socket.close(); + /* + * Wait for server process to end. + */ + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_RESTORE) { + ; + } + /* + * Check the server process has ended successfully, if it was a success put Mapped Buffer to pass state, else to failed state + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_SUCCESS) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + } else { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + } catch (Exception exception) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + exception.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occured:" + exception); + logger.log(Level.FINE, writer.toString()); + } + if (socketMappedBuffer != null) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsDataServer.java b/test/javaTests/src/org/criu/java/tests/SocketsDataServer.java new file mode 100644 index 000000000..65fe92a9d --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsDataServer.java @@ -0,0 +1,124 @@ +package org.criu.java.tests; + +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsDataServer { + static String TESTNAME = "SocketsDataServer"; + + public static void main(String[] args) { + MappedByteBuffer socketMappedBuffer = null; + FileChannel channel; + String parentTestName, portArg; + int port; + Socket socket = null; + Logger logger = null; + String msg1 = "Ch@ckM@$$@Ge!1", msg2 = "cH@C!m$SG!!2", + msg3 = "@Ft@rCPM$$g3", msg4 = "Aft@rCPM$$g4", readMssg; + + try { + parentTestName = args[0]; + portArg = args[1]; + port = Integer.parseInt(portArg); + + /* + * Socket Mapped Buffer to communicate between server process, client process and the calling parent process. + */ + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + parentTestName + "/SocketsDataFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + SocketHelper.init(TESTNAME, parentTestName, logger); + + logger.log(Level.INFO, "Begin"); + logger.log(Level.INFO, "Parent name: " + parentTestName); + logger.log(Level.INFO, "socket buffer connection opened"); + + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT) { + logger.log(Level.SEVERE, "Socket-buffer not in expected Init state"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + ServerSocket ser = new ServerSocket(port); + logger.log(Level.INFO, "Server will be listening on Port " + port); + + /* + * Wait for 7 seconds for client to connect, else throw a timeout exception + */ + try { + ser.setSoTimeout(7 * 1000); + + } catch (SocketException e) { + logger.log(Level.SEVERE, "cannot set timeout"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + logger.log(Level.INFO, "Waiting for client to connect"); + /* + * Put Socket Mapped Buffer to SocketHelper.STATE_LISTEN state - server has bound to port and + * begin listening for connections. + */ + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, SocketHelper.STATE_LISTEN); + socket = ser.accept(); + BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); + PrintStream outstream = new PrintStream(socket.getOutputStream()); + + readMssg = br.readLine(); + logger.log(Level.INFO, "Read message 1: " + readMssg); + + if (!msg1.equals(readMssg)) { + logger.log(Level.SEVERE, "Message 1 received was wrong:rec " + readMssg + " expected: " + msg1); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + logger.log(Level.INFO, "Sending message: " + msg2); + outstream.println(msg2); + + readMssg = br.readLine(); + logger.log(Level.INFO, "Read message 3: " + readMssg); + + if (!msg3.equals(readMssg)) { + logger.log(Level.SEVERE, "Message 3 received was wrong:rec " + readMssg + " expected: " + msg3); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + outstream.println(msg4); + logger.log(Level.INFO, "Sent message 4 " + msg4); + + socket.close(); + /* + * Put Socket-MappedBuffer to state SocketHelper.STATE_SUCCESS telling the server process has ended successfully. + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + System.exit(1); + } else { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, SocketHelper.STATE_SUCCESS); + } + } catch (Exception exception) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + exception.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occurred:" + exception); + logger.log(Level.FINE, writer.toString()); + } + + if (socketMappedBuffer != null) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsListen.java b/test/javaTests/src/org/criu/java/tests/SocketsListen.java new file mode 100644 index 000000000..3fad38549 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsListen.java @@ -0,0 +1,153 @@ +package org.criu.java.tests; + +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsListen { + static String TESTNAME = "SocketsListen"; + + /** + * Runs the client and server process, checkpoints the server process when the server has bound to a port, but has not yet started listening + * + * @param args Not used + */ + public static void main(String[] args) { + MappedByteBuffer b = null, socketMappedBuffer = null; + FileChannel channel; + String pid; + String port = "49200"; + Logger logger = null; + try { + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + /* + * Mapped buffer 'b' to communicate between CheckpointRestore.java and this process. + */ + File f = new File(Helper.MEMORY_MAPPED_FILE_NAME); + channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + b = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + pid = bean.getName(); + Helper.init(TESTNAME, pid, logger); + logger.log(Level.INFO, "Test init done; pid written to pid file; beginning with test"); + + + if (b.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT) { + logger.log(Level.SEVERE, "Error: Error in memory mapping, test is not in init state"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Creating socketbufferfile and setting the init value of buffer"); + + /* + * Socket Mapped Buffer to communicate between server process, client process and this process. + */ + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + TESTNAME + "/SocketsListenFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + /* + * Set socketMappedBuffer to init state. + */ + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_INIT); + + logger.log(Level.INFO, "Starting server and client process"); + ProcessBuilder builder = new ProcessBuilder("java", "-cp", "target/classes", Helper.PACKAGE_NAME + "." + "SocketsListenServer", TESTNAME, port); + Process serverProcess = builder.start(); + builder = new ProcessBuilder("java", "-cp", "target/classes", Helper.PACKAGE_NAME + "." + "SocketsListenClient", TESTNAME, port); + Process clientProcess = builder.start(); + + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_INIT) { + ; + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + logger.log(Level.SEVERE, "Killing the server process and client process"); + logger.log(Level.SEVERE, "Some error took place in the client or server process: check their log for details"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL) { + logger.log(Level.SEVERE, "Killing the server process and client process"); + logger.log(Level.SEVERE, "Exception occured in the client or server process: check their log for details"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_CHECKPOINT) { + logger.log(Level.SEVERE, "Killing the server process and client process"); + logger.log(Level.SEVERE, "State is not the expected 'to be checkpointed' state"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_CHECKPOINT) { + logger.log(Level.INFO, "Going to checkpoint server process"); + SocketHelper.checkpointAndWait(b, logger, serverProcess, clientProcess); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_RESTORE); + logger.log(Level.INFO, "Process has been restored!"); + } + + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_RESTORE || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_LISTEN) { + ; + } + char bufchar = socketMappedBuffer.getChar(Helper.MAPPED_INDEX); + if (bufchar != Helper.STATE_FAIL && bufchar != Helper.STATE_PASS && bufchar != SocketHelper.STATE_SUCCESS) { + logger.log(Level.SEVERE, "Received wrong message from the child process: not the expected finish message"); + logger.log(Level.SEVERE, "Check their log files for more details"); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + logger.log(Level.SEVERE, "Error in the client or server process: check their log for details"); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_SUCCESS) { + ; + } + + /* + * Client process puts socketMappedBuffer to Helper.STATE_PASS-Pass state if the test passed. + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_PASS) { + logger.log(Level.INFO, Helper.PASS_MESSAGE); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + } else { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + System.exit(0); + + } catch (Exception e) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + e.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occured:" + e); + logger.log(Level.FINE, writer.toString()); + } + if (b != null) { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + System.exit(5); + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsListenClient.java b/test/javaTests/src/org/criu/java/tests/SocketsListenClient.java new file mode 100644 index 000000000..efcb3d545 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsListenClient.java @@ -0,0 +1,136 @@ +package org.criu.java.tests; + +import java.io.*; +import java.net.Socket; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsListenClient { + static String TESTNAME = "SocketsListenClient"; + + public static void main(String[] args) { + MappedByteBuffer socketMappedBuffer = null; + FileChannel channel; + Socket socket = null; + String parentTestName, portArg; + int port; + Logger logger = null; + try { + parentTestName = args[0]; + portArg = args[1]; + port = Integer.parseInt(portArg); + String msg1 = "Ch@ckM@$$@Ge!1", msg2 = "cH@C!m$SG!!2", readMssg, + msg3 = "@Ft@rCPM$$g3", msg4 = "Aft@rCPM$$g4"; + + /* + * Socket Mapped Buffer to communicate between server process, client process and the calling parent process. + */ + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + parentTestName + "/SocketsListenFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + SocketHelper.init(TESTNAME, parentTestName, logger); + + logger.log(Level.INFO, "Begin"); + logger.log(Level.INFO, "Parent name: " + parentTestName); + + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT && socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_CHECKPOINT && socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_RESTORE && socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != SocketHelper.STATE_LISTEN) { + logger.log(Level.SEVERE, "Error: Socket-buffer not in expected Init state"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + logger.log(Level.INFO, "Waiting for CR"); + + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_INIT || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_CHECKPOINT) { + ; + } + + logger.log(Level.INFO, "Restored"); + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_RESTORE) { + ; + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != SocketHelper.STATE_LISTEN) { + logger.log(Level.SEVERE, "Buffer does not contain the expected 'server bound to port' state" + socketMappedBuffer.getChar(Helper.MAPPED_INDEX)); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + /* + * Make the thread sleep to ensure server is listening on the port for client connections. + */ + logger.log(Level.INFO, "Put thread to sleep"); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + logger.log(Level.WARNING, "Thread was interuptedp"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + logger.log(Level.INFO, "Client socket sending req to server at IP: 127.0.0.1 port:" + port); + try { + socket = new Socket(SocketHelper.IP_ADDRESS, port); + } catch (Exception e) { + logger.log(Level.SEVERE, "Exception occured when connecting to port: " + e); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + PrintStream out = new PrintStream(socket.getOutputStream()); + BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + logger.log(Level.INFO, "Sending message to server " + msg1); + out.println(msg1); + + readMssg = br.readLine(); + logger.log(Level.INFO, "message received from server " + readMssg); + if (!msg2.equals(readMssg)) { + logger.log(Level.SEVERE, "wrong message received; Expected " + msg2); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + logger.log(Level.INFO, "Sending message to server " + msg3); + out.println(msg3); + + readMssg = br.readLine(); + logger.log(Level.INFO, "message received from server " + readMssg); + if (!msg4.equals(readMssg)) { + logger.log(Level.SEVERE, "wrong message received; Expected " + msg4); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + socket.close(); + + /* + * Wait for server process to end. + */ + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_LISTEN) { + ; + } + /* + * Check the server process has ended successfully, if it was a success put MappedBuffer to STATE_PASS, else to STATE_FAIL + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_SUCCESS) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + } else { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + } catch (Exception exception) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + exception.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occured:" + exception); + logger.log(Level.FINE, writer.toString()); + } + + if (socketMappedBuffer != null) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsListenServer.java b/test/javaTests/src/org/criu/java/tests/SocketsListenServer.java new file mode 100644 index 000000000..46fef40ec --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsListenServer.java @@ -0,0 +1,160 @@ +package org.criu.java.tests; + +import java.io.*; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsListenServer { + static String TESTNAME = "SocketsListenServer"; + + public static void main(String[] args) { + MappedByteBuffer socketMappedBuffer = null; + FileChannel channel; + String parentTestName, portArg; + int port; + Logger logger = null; + Socket socket = null; + String readMssg, msg1 = "Ch@ckM@$$@Ge!1", msg2 = "cH@C!m$SG!!2", + msg3 = "@Ft@rCPM$$g3", msg4 = "Aft@rCPM$$g4"; + + try { + parentTestName = args[0]; + portArg = args[1]; + port = Integer.parseInt(portArg); + + /* + * Socket Mapped Buffer to communicate between server process, client process and the calling parent process. + */ + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + parentTestName + "/SocketsListenFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + SocketHelper.init(TESTNAME, parentTestName, logger); + + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + String pid = bean.getName(); + SocketHelper.writePid(parentTestName, pid); + + logger.log(Level.INFO, "Begin"); + logger.log(Level.INFO, "Parent name: " + parentTestName); + logger.log(Level.INFO, "Server pid: " + pid); + logger.log(Level.INFO, "socket buffer connection opened"); + + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT) { + logger.log(Level.SEVERE, "Socket-buffer not in expected Init state"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + logger.log(Level.INFO, "Server will be listening on Port " + port); + ServerSocket ser = new ServerSocket(port); + /* + * Server has bound to a port but is not listening yet! + */ + logger.log(Level.INFO, "Going to checkpoint"); + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + ser.close(); + System.exit(1); + } + /* + * Checkpoint and wait for Restore. + */ + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_CHECKPOINT); + SocketHelper.socketWaitForRestore(socketMappedBuffer, logger); + + if (!ser.isBound()) { + logger.log(Level.SEVERE, "Server is not bound to a port"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + if (ser.getLocalPort() != port) { + logger.log(Level.SEVERE, "SServer is not listening on correct port"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + /* + * Timeout after 5 sec if client does not connect + */ + try { + ser.setSoTimeout(5 * 1000); + + } catch (SocketException e) { + logger.log(Level.SEVERE, "cannot set timeout"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + try { + logger.log(Level.INFO, "Waiting for client to connect"); + /* + * Put Socket Mapped Buffer to SocketHelper.STATE_LISTEN state - server has bound to port and + * will begin listening for connections. + */ + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, SocketHelper.STATE_LISTEN); + socket = ser.accept(); + + } catch (Exception e) { + logger.log(Level.SEVERE, "Timed out while waiting for client to connect\n" + e); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); + PrintStream outstream = new PrintStream(socket.getOutputStream()); + + readMssg = br.readLine(); + logger.log(Level.INFO, "Read message 1: " + readMssg); + if (!msg1.equals(readMssg)) { + logger.log(Level.SEVERE, "Message 1 received was wrong:rec " + readMssg + " expected: " + msg1); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + logger.log(Level.INFO, "Sending message: " + msg2); + outstream.println(msg2); + + readMssg = br.readLine(); + logger.log(Level.INFO, "Read message 3: " + readMssg); + + if (!msg3.equals(readMssg)) { + logger.log(Level.SEVERE, "Message 3 received was wrong:rec " + readMssg + " expected: " + msg3); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + outstream.println(msg4); + logger.log(Level.INFO, "Sending message: " + msg4); + + /* + * Put Socket-MappedBuffer to state SocketHelper.STATE_SUCCESS telling the server process has ended successfully. + */ + socket.close(); + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + System.exit(1); + } else { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, SocketHelper.STATE_SUCCESS); + } + } catch (Exception exception) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + exception.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occurred:" + exception); + logger.log(Level.FINE, writer.toString()); + } + if (socketMappedBuffer != null) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsMultiple.java b/test/javaTests/src/org/criu/java/tests/SocketsMultiple.java new file mode 100644 index 000000000..5e55c4274 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsMultiple.java @@ -0,0 +1,152 @@ +package org.criu.java.tests; + +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsMultiple { + static String TESTNAME = "SocketsMultiple"; + + /** + * Runs the Client and Server Processes, Multiple clients connect to server Process, checkpoints the server process + * + * @param args Not used + */ + public static void main(String[] args) { + MappedByteBuffer b = null, socketMappedBuffer = null; + FileChannel channel; + String pid; + String port = "49200"; + Logger logger = null; + try { + /* + * Mapped buffer 'b' to communicate between CheckpointRestore.java and this process. + */ + File f = new File(Helper.MEMORY_MAPPED_FILE_NAME); + channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + b = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + pid = bean.getName(); + Helper.init(TESTNAME, pid, logger); + logger.log(Level.INFO, "Test init done; pid written to pid file; beginning with test"); + + if (b.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT) { + logger.log(Level.SEVERE, "Error: Error in memory mapping, test is not in init state"); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + /* + * Socket Mapped Buffer to communicate between server process, client process and this process. + */ + logger.log(Level.INFO, "Creating socketBufferFile and setting the init value of buffer"); + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + TESTNAME + "/SocketsMultipleFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + /* + * Set socketMappedBuffer to init state. + */ + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_INIT); + + logger.log(Level.INFO, "Starting server and client process"); + ProcessBuilder builder = new ProcessBuilder("java", "-cp", "target/classes", Helper.PACKAGE_NAME + "." + "SocketsMultipleServer", TESTNAME, port); + Process serverProcess = builder.start(); + builder = new ProcessBuilder("java", "-cp", "target/classes", Helper.PACKAGE_NAME + "." + "SocketsMultipleClient", TESTNAME, port); + Process clientProcess = builder.start(); + + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_INIT || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_LISTEN) { + ; + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + logger.log(Level.SEVERE, "Killing the server process and client process"); + logger.log(Level.SEVERE, "Some error took place in the client or server process: check their log for details"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL) { + logger.log(Level.SEVERE, "Killing the server process and client process"); + logger.log(Level.SEVERE, "Exception occured in the client or server process: check their log for details"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_CHECKPOINT) { + logger.log(Level.SEVERE, "Killing the server process and client process"); + logger.log(Level.SEVERE, "State is not the expected 'to be checkpointed' state"); + serverProcess.destroy(); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_CHECKPOINT) { + logger.log(Level.INFO, "Going to checkpoint server process"); + SocketHelper.checkpointAndWait(b, logger, serverProcess, clientProcess); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_RESTORE); + logger.log(Level.INFO, "Process has been restored!"); + } + + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_RESTORE) { + ; + } + char bufchar = socketMappedBuffer.getChar(Helper.MAPPED_INDEX); + if (bufchar != Helper.STATE_FAIL && bufchar != Helper.STATE_PASS && bufchar != SocketHelper.STATE_SUCCESS) { + logger.log(Level.SEVERE, "Received wrong message from the child process: not the expected finish message"); + logger.log(Level.SEVERE, "Check their log files for more details"); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + logger.log(Level.SEVERE, "Error in the client or server process: check their log for details"); + clientProcess.destroy(); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_SUCCESS) { + ; + } + + /* + * Client process puts socketMappedBuffer to STATE_PASS state if the test passed. + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_PASS) { + logger.log(Level.INFO, Helper.PASS_MESSAGE); + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + } else { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + System.exit(0); + + } catch (Exception e) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + e.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occured:" + e); + logger.log(Level.FINE, writer.toString()); + } + if (b != null) { + b.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + System.exit(5); + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsMultipleClient.java b/test/javaTests/src/org/criu/java/tests/SocketsMultipleClient.java new file mode 100644 index 000000000..d97a946fd --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsMultipleClient.java @@ -0,0 +1,174 @@ +package org.criu.java.tests; + +import java.io.*; +import java.net.Socket; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsMultipleClient { + static String TESTNAME = "SocketsMultipleClient"; + + public static void main(String[] args) { + MappedByteBuffer socketMappedBuffer = null; + FileChannel channel; + String msg1 = "Message1", msg2 = "Message2", readMssg; + Socket socket1 = null, socket2 = null, socket3 = null, socket4 = null; + String parentTestName, portArg; + int port; + Logger logger = null; + + try { + parentTestName = args[0]; + portArg = args[1]; + port = Integer.parseInt(portArg); + + /* + * Socket Mapped Buffer to communicate between server process, client process and the calling parent process. + */ + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + parentTestName + "/SocketsMultipleFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + SocketHelper.init(TESTNAME, parentTestName, logger); + + logger.log(Level.INFO, "Begin"); + logger.log(Level.INFO, "Parent name: " + parentTestName); + + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_INIT) { + ; + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != SocketHelper.STATE_LISTEN) { + logger.log(Level.SEVERE, "Error: Socket-buffer not in expected state"); + + } + try { + logger.log(Level.INFO, "client 1 connecting..."); + socket1 = new Socket(SocketHelper.IP_ADDRESS, port); + } catch (Exception e) { + logger.log(Level.SEVERE, "Exception when client connects to server: " + e); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + } + logger.log(Level.INFO, "Client 1 connected to server successfully"); + PrintStream out1 = new PrintStream(socket1.getOutputStream()); + BufferedReader br1 = new BufferedReader(new InputStreamReader(socket1.getInputStream())); + logger.log(Level.INFO, "Got input and output streams for socket1"); + try { + logger.log(Level.INFO, "client 2 connecting..."); + socket2 = new Socket(SocketHelper.IP_ADDRESS, port); + } catch (Exception e) { + logger.log(Level.SEVERE, "Exception when client connects to server: " + e); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + } + logger.log(Level.INFO, "Client 2 connected to server successfully"); + PrintStream out2 = new PrintStream(socket2.getOutputStream()); + BufferedReader br2 = new BufferedReader(new InputStreamReader(socket2.getInputStream())); + logger.log(Level.INFO, "Got input and output streams for socket2"); + + try { + logger.log(Level.INFO, "client 3 connecting..."); + socket3 = new Socket(SocketHelper.IP_ADDRESS, port); + } catch (Exception e) { + logger.log(Level.SEVERE, "Exception when client connects to server: " + e); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + } + logger.log(Level.INFO, "Client 3 connected to server successfully"); + PrintStream out3 = new PrintStream(socket3.getOutputStream()); + BufferedReader br3 = new BufferedReader(new InputStreamReader(socket3.getInputStream())); + logger.log(Level.INFO, "Got input and output streams for socket3"); + + out1.println(msg1); + + readMssg = br1.readLine(); + if (!msg2.equals(readMssg)) { + logger.log(Level.SEVERE, "wrong message received; Received: " + readMssg); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + } + socket1.close(); + + out2.println(msg1); + + /* + * Wait for Checkpoint-Restore + */ + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_INIT || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_LISTEN || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_CHECKPOINT) { + ; + } + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_RESTORE) { + logger.log(Level.SEVERE, "Socket-mapped-buffer is not in restored state"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + logger.log(Level.INFO, "Server is Restored!!"); + + out3.println(msg1); + readMssg = br2.readLine(); + if (!msg2.equals(readMssg)) { + logger.log(Level.SEVERE, "wrong message received by client 2; Received: " + readMssg); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + readMssg = br3.readLine(); + if (!msg2.equals(readMssg)) { + logger.log(Level.SEVERE, "wrong message received by client 3; Received: " + readMssg); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + socket2.close(); + socket3.close(); + + try { + logger.log(Level.INFO, "client 4 connecting..."); + socket4 = new Socket(SocketHelper.IP_ADDRESS, port); + } catch (Exception e) { + logger.log(Level.SEVERE, "Exception when client connects to server: " + e); + } + logger.log(Level.INFO, "Client 4 connected to server successfully"); + PrintStream out4 = new PrintStream(socket4.getOutputStream()); + BufferedReader br4 = new BufferedReader(new InputStreamReader(socket4.getInputStream())); + logger.log(Level.INFO, "Got input and output streams for socket4"); + + out4.println(msg1); + readMssg = br4.readLine(); + if (!msg2.equals(readMssg)) { + logger.log(Level.SEVERE, "wrong message received by client 4; Received: " + readMssg); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + socket4.close(); + /* + * Wait for server process to end. + */ + while (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_RESTORE) { + ; + } + /* + * Check the server process has ended successfully, if it was a success put Mapped Buffer to STATE_PASS, else to STATE_FAIL + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == SocketHelper.STATE_SUCCESS) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_PASS); + } else { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + + } catch (Exception exception) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + exception.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occured:" + exception); + logger.log(Level.FINE, writer.toString()); + } + + if (socketMappedBuffer != null) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsMultipleServer.java b/test/javaTests/src/org/criu/java/tests/SocketsMultipleServer.java new file mode 100644 index 000000000..a7e4d3b9e --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsMultipleServer.java @@ -0,0 +1,215 @@ +package org.criu.java.tests; + +import java.io.*; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsMultipleServer { + static String TESTNAME = "SocketsMultipleServer"; + + public static void main(String[] args) { + MappedByteBuffer socketMappedBuffer = null; + FileChannel channel; + String parentTestName, portArg; + int port; + Logger logger = null; + try { + parentTestName = args[0]; + portArg = args[1]; + port = Integer.parseInt(portArg); + + /* + * Socket Mapped Buffer to communicate between server process, client process and the calling parent process. + */ + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + parentTestName + "/SocketsMultipleFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + SocketHelper.init(TESTNAME, parentTestName, logger); + + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + String pid = bean.getName(); + SocketHelper.writePid(parentTestName, pid); + + logger.log(Level.INFO, "Begin"); + logger.log(Level.INFO, "Parent name: " + parentTestName); + logger.log(Level.INFO, "Server pid: " + pid); + logger.log(Level.INFO, "socket buffer connection opened"); + + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT) { + logger.log(Level.SEVERE, "Socket-buffer not in expected Init state"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + System.exit(1); + } + + /* + * The array indexes 3, 5, 7 and 9 will map the state of client 1, 2, 3 and 4. + * Set these array indexes to init state. + */ + + socketMappedBuffer.putChar(3, Helper.STATE_INIT); + socketMappedBuffer.putChar(5, Helper.STATE_INIT); + socketMappedBuffer.putChar(7, Helper.STATE_INIT); + socketMappedBuffer.putChar(9, Helper.STATE_INIT); + + ServerSocket ser = new ServerSocket(port); + logger.log(Level.INFO, "Server will be listening on Port " + port); + + Socket[] sockets = new Socket[4]; + + /* + * Set the SocketMappedBuffer to S state-server will be listening for connections + */ + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, SocketHelper.STATE_LISTEN); + + for (int i = 1; i <= 4; i++) { + sockets[i - 1] = ser.accept(); + ServerThread serverThread = new ServerThread(sockets[i - 1], "ser-socket " + i, 2 * i + 1, logger, socketMappedBuffer); + serverThread.start(); + if (i == 3) { + logger.log(Level.INFO, "Connected to client: 3"); + /* + * Client 3 has connected, wait for thread 1 to finish and then checkpoint. + */ + while (socketMappedBuffer.getChar(3) != Helper.STATE_FAIL && socketMappedBuffer.getChar(3) != Helper.STATE_PASS) { + ; + } + logger.log(Level.INFO, "Going to checkpoint"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_CHECKPOINT); + SocketHelper.socketWaitForRestore(socketMappedBuffer, logger); + } + } + + /* + * Loop while any of the 4 thread is running + */ + while (socketMappedBuffer.getChar(3) == Helper.STATE_INIT || socketMappedBuffer.getChar(5) == Helper.STATE_INIT + || socketMappedBuffer.getChar(7) == Helper.STATE_INIT || socketMappedBuffer.getChar(9) == Helper.STATE_INIT) { + ; + } + + /* + * Check Socket Mapped Buffer for a thread that failed + */ + for (int i = 1; i <= 4; i++) { + if (socketMappedBuffer.getChar(i * 2 + 1) == Helper.STATE_FAIL) { + logger.log(Level.SEVERE, "Error in thread connected to client " + i); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + } + + /* + * Check the 1st Socket is closed + */ + if (!sockets[0].isClosed()) { + logger.log(Level.SEVERE, "socket 1 is not closed"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + logger.log(Level.INFO, "Socket 1 is in expected closed state: " + sockets[0].isClosed()); + + /* + * Check all threads are in expected pass state + */ + for (int i = 1; i <= 4; i++) { + if (socketMappedBuffer.getChar(i * 2 + 1) != Helper.STATE_PASS) { + logger.log(Level.SEVERE, "Unexpected State of buffer: " + socketMappedBuffer.getChar(i * 2 + 1) + ", client: " + i); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + } + logger.log(Level.INFO, "Done"); + + /* + * Put Socket-MappedBuffer to state SocketHelper.STATE_SUCCESS telling the server process has ended successfully. + */ + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + System.exit(1); + } else { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, SocketHelper.STATE_SUCCESS); + } + + } catch (Exception exception) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + exception.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occurred:" + exception); + logger.log(Level.FINE, writer.toString()); + } + + if (socketMappedBuffer != null) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + } + } +} + +class ServerThread extends Thread { + Socket socket = null; + String name; + int num; + MappedByteBuffer socketMappedBuffer; + Logger logger; + + ServerThread(Socket socket, String name, int num, Logger logger, MappedByteBuffer socketMappedBuffer) { + this.socket = socket; + this.name = name; + this.logger = logger; + this.num = num; + this.socketMappedBuffer = socketMappedBuffer; + } + + public void run() { + try { + String readMssg, msg1 = "Message1", msg2 = "Message2"; + BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); + PrintStream out = new PrintStream(socket.getOutputStream()); + readMssg = br.readLine(); + if (!msg1.equals(readMssg)) { + logger.log(Level.SEVERE, "Message read by thread " + name + " was not 'Message1', received Message: " + readMssg); + socket.close(); + socketMappedBuffer.putChar(num, Helper.STATE_FAIL); + } else { + logger.log(Level.INFO, name + " received correct message"); + out.println(msg2); + logger.log(Level.INFO, name + " has sent message"); + socket.close(); + socketMappedBuffer.putChar(num, Helper.STATE_PASS); + } + + } catch (Exception exception) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + exception.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occurred in thread :" + name + " " + exception); + logger.log(Level.FINE, writer.toString()); + } + + try { + if (socket != null) { + socket.close(); + } + } catch (IOException e) { + ; + } + + /* + * If exception occurs fail the thread + */ + socketMappedBuffer.putChar(num, Helper.STATE_FAIL); + } + } +} diff --git a/test/javaTests/src/org/criu/java/tests/SocketsServer.java b/test/javaTests/src/org/criu/java/tests/SocketsServer.java new file mode 100644 index 000000000..051233443 --- /dev/null +++ b/test/javaTests/src/org/criu/java/tests/SocketsServer.java @@ -0,0 +1,142 @@ +package org.criu.java.tests; + +import java.io.*; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SocketsServer { + static String TESTNAME = "SocketsServer"; + + public static void main(String[] args) { + MappedByteBuffer socketMappedBuffer = null; + String msg1 = "Ch@ckM@$$@Ge!1", msg2 = "cH@C!m$SG!!2", + msg3 = "@Ft@rCPM$$g3", msg4 = "Aft@rCPM$$g4", readMssg; + FileChannel channel; + String parentTestName, portArg; + int port; + Logger logger = null; + + try { + parentTestName = args[0]; + portArg = args[1]; + port = Integer.parseInt(portArg); + + /* + * Socket Mapped Buffer to communicate between server process, client process and the calling parent process. + */ + File socketfile = new File(Helper.OUTPUT_FOLDER_NAME + "/" + parentTestName + "/SocketsFile"); + channel = FileChannel.open(socketfile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + socketMappedBuffer = channel.map(MapMode.READ_WRITE, 0, Helper.MAPPED_REGION_SIZE); + channel.close(); + + logger = Logger.getLogger(Helper.PACKAGE_NAME + "." + TESTNAME); + + SocketHelper.init(TESTNAME, parentTestName, logger); + logger.log(Level.INFO, "Begin"); + logger.log(Level.INFO, "Parent name: " + parentTestName); + + RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); + String pid = bean.getName(); + SocketHelper.writePid(parentTestName, pid); + + logger.log(Level.INFO, "Socket buffer mapped"); + + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) != Helper.STATE_INIT) { + logger.log(Level.SEVERE, "Socket-buffer not in expected Init state"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + } + + ServerSocket ser = new ServerSocket(port); + logger.log(Level.INFO, "Server will be listening on Port " + port); + + /* + * Timeout after 5 second if client does not connect + */ + ser.setSoTimeout(5 * 1000); + logger.log(Level.INFO, "Waiting for client to connect"); + Socket socket = null; + try { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, SocketHelper.STATE_LISTEN); + socket = ser.accept(); + } catch (Exception e) { + logger.log(Level.SEVERE, "Timed out while waiting for client to connect"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + } + BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); + PrintStream outstream = new PrintStream(socket.getOutputStream()); + + readMssg = br.readLine(); + logger.log(Level.INFO, "Read message 1: " + readMssg); + if (!msg1.equals(readMssg)) { + logger.log(Level.SEVERE, "Message 1 received was wrong:rec " + readMssg + " expected: " + msg1); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_END); + } + + logger.log(Level.INFO, "Sending message: " + msg2); + outstream.println(msg2); + + logger.log(Level.INFO, "Going to checkpoint"); + /* + * Put socket Mapped Buffer to 'to be checkpointed' state and wait for restore + */ + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_CHECKPOINT); + SocketHelper.socketWaitForRestore(socketMappedBuffer, logger); + + if (!ser.isBound()) { + logger.log(Level.SEVERE, "Server is not bound to a port"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + if (ser.getLocalPort() != port) { + logger.log(Level.SEVERE, "Server is not listening on correct port"); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + System.exit(1); + } + + readMssg = br.readLine(); + logger.log(Level.INFO, "Read message 3: " + readMssg); + + if (!msg3.equals(readMssg)) { + logger.log(Level.SEVERE, "Message 3 received was wrong:rec " + readMssg + " expected: " + msg3); + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + socket.close(); + System.exit(1); + } + + outstream.println(msg4); + logger.log(Level.INFO, "Sent message 4 " + msg4); + + /* + * Put Socket-MappedBuffer to state SocketHelper.STATE_SUCCESS telling the server process has ended successfully. + */ + socket.close(); + if (socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_FAIL || socketMappedBuffer.getChar(Helper.MAPPED_INDEX) == Helper.STATE_END) { + System.exit(1); + } else { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, SocketHelper.STATE_SUCCESS); + } + + } catch (Exception exception) { + if (null != logger) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + exception.printStackTrace(printWriter); + logger.log(Level.SEVERE, "Exception occurred:" + exception); + logger.log(Level.FINE, writer.toString()); + } + + if (socketMappedBuffer != null) { + socketMappedBuffer.putChar(Helper.MAPPED_INDEX, Helper.STATE_FAIL); + } + } + } +} diff --git a/test/javaTests/test.xml b/test/javaTests/test.xml index b73a31db2..4768bf193 100644 --- a/test/javaTests/test.xml +++ b/test/javaTests/test.xml @@ -40,4 +40,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 0c218746d587483346d5dcb7638b642392a4985f Mon Sep 17 00:00:00 2001 From: Nidhi Gupta Date: Thu, 9 Jan 2020 22:43:25 +0530 Subject: [PATCH 2280/4375] Switch open-j9 alpine tests to python3 Signed-off-by: Nidhi Gupta --- scripts/build/Dockerfile.openj9-alpine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Dockerfile.openj9-alpine b/scripts/build/Dockerfile.openj9-alpine index 43a993444..39ea4d08e 100644 --- a/scripts/build/Dockerfile.openj9-alpine +++ b/scripts/build/Dockerfile.openj9-alpine @@ -14,7 +14,7 @@ RUN apk update && apk add \ pkgconfig \ protobuf-c-dev \ protobuf-dev \ - python \ + python3 \ sudo \ maven \ ip6tables \ From f1abc9aa26421b0c0ea52a703590cd998e676b55 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 14 Jan 2020 14:47:18 +0100 Subject: [PATCH 2281/4375] ppc64le: remove register '1' from clobber list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compiling 'criu-dev' on Fedora 31 gives two errors about wrong clobber lists: compel/include/uapi/compel/asm/sigframe.h:47:9: error: listing the stack pointer register ‘1’ in a clobber list is deprecated [-Werror=deprecated] criu/arch/ppc64/include/asm/restore.h:14:2: error: listing the stack pointer register ‘1’ in a clobber list is deprecated [-Werror=deprecated] There was also a bug report from Debian that CRIU does not build because of this. Each of these errors comes with the following note: note: the value of the stack pointer after an ‘asm’ statement must be the same as it was before the statement As far as I understand it this should not be a problem in this cases as the code never returns anyway. Running zdtm very seldom fails during 'zdtm/static/cgroup_ifpriomap' with a double free or corruption. This happens not very often and I cannot verify if it happens without this patch. As CRIU does not build without the patch. Signed-off-by: Adrian Reber --- compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h | 2 +- criu/arch/ppc64/include/asm/restore.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h b/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h index 9467a1b99..5c98b199d 100644 --- a/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/sigframe.h @@ -50,7 +50,7 @@ struct rt_sigframe { "sc \n" \ : \ : "r"(new_sp) \ - : "1", "memory") + : "memory") #if _CALL_ELF != 2 # error Only supporting ABIv2. diff --git a/criu/arch/ppc64/include/asm/restore.h b/criu/arch/ppc64/include/asm/restore.h index 8d4516090..f065ec3a0 100644 --- a/criu/arch/ppc64/include/asm/restore.h +++ b/criu/arch/ppc64/include/asm/restore.h @@ -21,7 +21,7 @@ : "r"(new_sp), \ "r"((unsigned long)restore_task_exec_start), \ "r"(task_args) \ - : "1", "3", "12") + : "3", "12") /* There is nothing to do since TLS is accessed through r13 */ #define core_get_tls(pcore, ptls) From 4232b270b8a0c866b9ee26e7b5f381cbf7cea56a Mon Sep 17 00:00:00 2001 From: Valeriy Vdovin Date: Fri, 10 Jan 2020 15:57:50 +0300 Subject: [PATCH 2282/4375] image: core -- Reserve start_time field To ensure consistency of runtime environment processes within a container need to see same start time values over suspend/resume cycles. We introduce new field to the core image structure to store start time of a dumped process. Later same value would be restored to a newly created task. In future the feature is likely to be pulled here, so we reserve field id in protobuf descriptor. Signed-off-by: Valeriy Vdovin --- images/core.proto | 2 ++ 1 file changed, 2 insertions(+) diff --git a/images/core.proto b/images/core.proto index c3dba6f6d..e90522914 100644 --- a/images/core.proto +++ b/images/core.proto @@ -53,6 +53,8 @@ message task_core_entry { //optional int32 tty_pgrp = 17; optional bool child_subreaper = 18; + // Reserved for container relative start time + //optional uint64 start_time = 19; } message task_kobj_ids_entry { From 8fea2647b69fc0be0cac6a43639ed648cdd08db6 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 9 Jan 2020 18:54:50 +0000 Subject: [PATCH 2283/4375] travis: reduce the number of podman tests We are running each podman test loop 50 times. This takes more than 20 minutes in Travis. Reduce both test loops to only run 20 times. Signed-off-by: Adrian Reber --- scripts/travis/podman-test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/travis/podman-test.sh b/scripts/travis/podman-test.sh index 5189477cd..825bca746 100755 --- a/scripts/travis/podman-test.sh +++ b/scripts/travis/podman-test.sh @@ -35,7 +35,7 @@ criu --version podman run --name cr -d docker.io/library/alpine /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done' sleep 1 -for i in `seq 50`; do +for i in `seq 20`; do echo "Test $i for podman container checkpoint" podman exec cr ps axf podman logs cr @@ -48,7 +48,7 @@ for i in `seq 50`; do podman logs cr done -for i in `seq 50`; do +for i in `seq 20`; do echo "Test $i for podman container checkpoint --export" podman ps -a podman exec cr ps axf From ca02c47075b69c3387d03ae2a09ab9499d5bd27f Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Sun, 15 Dec 2019 20:38:46 +0000 Subject: [PATCH 2284/4375] kerndat: detect if system support clone3() with set_tid Linux kernel 5.4 extends clone3() with set_tid to allow processes to specify the PID of a newly created process. This introduces detection of the clone3() syscall and if set_tid is supported. This first implementation is X86_64 only. Signed-off-by: Adrian Reber --- .../arch/arm/plugins/std/syscalls/syscall.def | 1 + .../plugins/std/syscalls/syscall-ppc64.tbl | 1 + .../plugins/std/syscalls/syscall-s390.tbl | 1 + .../x86/plugins/std/syscalls/syscall_32.tbl | 1 + .../x86/plugins/std/syscalls/syscall_64.tbl | 1 + .../plugins/include/uapi/std/syscall-types.h | 1 + criu/cr-check.c | 12 ++++++ criu/include/kerndat.h | 1 + criu/include/sched.h | 33 +++++++++++++++ criu/kerndat.c | 41 +++++++++++++++++++ 10 files changed, 93 insertions(+) create mode 100644 criu/include/sched.h diff --git a/compel/arch/arm/plugins/std/syscalls/syscall.def b/compel/arch/arm/plugins/std/syscalls/syscall.def index d5bdc677e..f7ebc8527 100644 --- a/compel/arch/arm/plugins/std/syscalls/syscall.def +++ b/compel/arch/arm/plugins/std/syscalls/syscall.def @@ -115,3 +115,4 @@ ppoll 73 336 (struct pollfd *fds, unsigned int nfds, const struct timespec *t fsopen 430 430 (char *fsname, unsigned int flags) fsconfig 431 431 (int fd, unsigned int cmd, const char *key, const char *value, int aux) fsmount 432 432 (int fd, unsigned int flags, unsigned int attr_flags) +clone3 435 435 (struct clone_args *uargs, size_t size) diff --git a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl index 4e283d5e9..1afaf1e70 100644 --- a/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl +++ b/compel/arch/ppc64/plugins/std/syscalls/syscall-ppc64.tbl @@ -111,3 +111,4 @@ __NR_ppoll 281 sys_ppoll (struct pollfd *fds, unsigned int nfds, const struct __NR_fsopen 430 sys_fsopen (char *fsname, unsigned int flags) __NR_fsconfig 431 sys_fsconfig (int fd, unsigned int cmd, const char *key, const char *value, int aux) __NR_fsmount 432 sys_fsmount (int fd, unsigned int flags, unsigned int attr_flags) +__NR_clone3 435 sys_clone3 (struct clone_args *uargs, size_t size) diff --git a/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl b/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl index fd48e3950..ae6fdb5f8 100644 --- a/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl +++ b/compel/arch/s390/plugins/std/syscalls/syscall-s390.tbl @@ -111,3 +111,4 @@ __NR_ppoll 302 sys_ppoll (struct pollfd *fds, unsigned int nfds, const struct __NR_fsopen 430 sys_fsopen (char *fsname, unsigned int flags) __NR_fsconfig 431 sys_fsconfig (int fd, unsigned int cmd, const char *key, const char *value, int aux) __NR_fsmount 432 sys_fsmount (int fd, unsigned int flags, unsigned int attr_flags) +__NR_clone3 435 sys_clone3 (struct clone_args *uargs, size_t size) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl index 038aeb4f7..7a487110d 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_32.tbl @@ -99,3 +99,4 @@ __NR_ppoll 309 sys_ppoll (struct pollfd *fds, unsigned int nfds, const struct __NR_fsopen 430 sys_fsopen (char *fsname, unsigned int flags) __NR_fsconfig 431 sys_fsconfig (int fd, unsigned int cmd, const char *key, const char *value, int aux) __NR_fsmount 432 sys_fsmount (int fd, unsigned int flags, unsigned int attr_flags) +__NR_clone3 435 sys_clone3 (struct clone_args *uargs, size_t size) diff --git a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl index 215f32026..6667c07db 100644 --- a/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl +++ b/compel/arch/x86/plugins/std/syscalls/syscall_64.tbl @@ -110,3 +110,4 @@ __NR_ppoll 271 sys_ppoll (struct pollfd *fds, unsigned int nfds, const struc __NR_fsopen 430 sys_fsopen (char *fsname, unsigned int flags) __NR_fsconfig 431 sys_fsconfig (int fd, unsigned int cmd, const char *key, const char *value, int aux) __NR_fsmount 432 sys_fsmount (int fd, unsigned int flags, unsigned int attr_flags) +__NR_clone3 435 sys_clone3 (struct clone_args *uargs, size_t size) diff --git a/compel/plugins/include/uapi/std/syscall-types.h b/compel/plugins/include/uapi/std/syscall-types.h index 57865e741..031e773bb 100644 --- a/compel/plugins/include/uapi/std/syscall-types.h +++ b/compel/plugins/include/uapi/std/syscall-types.h @@ -39,6 +39,7 @@ struct msghdr; struct rusage; struct iocb; struct pollfd; +struct clone_args; typedef unsigned long aio_context_t; diff --git a/criu/cr-check.c b/criu/cr-check.c index 17dd29b42..80df3f7cd 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1224,6 +1224,16 @@ static int check_uffd_noncoop(void) return 0; } +static int check_clone3_set_tid(void) +{ + if (!kdat.has_clone3_set_tid) { + pr_warn("clone3() with set_tid not supported\n"); + return -1; + } + + return 0; +} + static int check_can_map_vdso(void) { if (kdat_can_map_vdso() == 1) @@ -1373,6 +1383,7 @@ int cr_check(void) ret |= check_sk_netns(); ret |= check_kcmp_epoll(); ret |= check_net_diag_raw(); + ret |= check_clone3_set_tid(); } /* @@ -1476,6 +1487,7 @@ static struct feature_list feature_list[] = { { "link_nsid", check_link_nsid}, { "kcmp_epoll", check_kcmp_epoll}, { "external_net_ns", check_external_net_ns}, + { "clone3_set_tid", check_clone3_set_tid}, { NULL, NULL }, }; diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 771195860..27c870bb8 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -66,6 +66,7 @@ struct kerndat_s { bool has_inotify_setnextwd; bool has_kcmp_epoll_tfd; bool has_fsopen; + bool has_clone3_set_tid; }; extern struct kerndat_s kdat; diff --git a/criu/include/sched.h b/criu/include/sched.h new file mode 100644 index 000000000..78f65e3b7 --- /dev/null +++ b/criu/include/sched.h @@ -0,0 +1,33 @@ +#ifndef __CR_SCHED_H__ +#define __CR_SCHED_H__ + +#include + +#ifndef ptr_to_u64 +#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr))) +#endif +#ifndef u64_to_ptr +#define u64_to_ptr(x) ((void *)(uintptr_t)x) +#endif + +/* + * This structure is needed by clone3(). The kernel + * calls it 'struct clone_args'. As CRIU will always + * need at least this part of the structure (VER1) + * to be able to test if clone3() with set_tid works, + * the structure is defined here as 'struct _clone_args'. + */ + +struct _clone_args { + __aligned_u64 flags; + __aligned_u64 pidfd; + __aligned_u64 child_tid; + __aligned_u64 parent_tid; + __aligned_u64 exit_signal; + __aligned_u64 stack; + __aligned_u64 stack_size; + __aligned_u64 tls; + __aligned_u64 set_tid; + __aligned_u64 set_tid_size; +}; +#endif /* __CR_SCHED_H__ */ diff --git a/criu/kerndat.c b/criu/kerndat.c index d1afde71d..0772828bc 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -41,6 +41,7 @@ #include "uffd.h" #include "vdso.h" #include "kcmp.h" +#include "sched.h" struct kerndat_s kdat = { }; @@ -986,6 +987,44 @@ static int kerndat_tun_netns(void) return check_tun_netns_cr(&kdat.tun_ns); } +static bool kerndat_has_clone3_set_tid(void) +{ + pid_t pid; + struct _clone_args args = {}; + +#ifndef CONFIG_X86_64 + /* + * Currently the CRIU PIE assembler clone3() wrapper is + * only implemented for X86_64. + */ + kdat.has_clone3_set_tid = false; + return 0; +#endif + + args.set_tid = -1; + /* + * On a system without clone3() this will return ENOSYS. + * On a system with clone3() but without set_tid this + * will return E2BIG. + * On a system with clone3() and set_tid it will return + * EINVAL. + */ + pid = syscall(__NR_clone3, &args, sizeof(args)); + + if (pid == -1 && (errno == ENOSYS || errno == E2BIG)) { + kdat.has_clone3_set_tid = false; + return 0; + } + if (pid == -1 && errno == EINVAL) { + kdat.has_clone3_set_tid = true; + } else { + pr_perror("Unexpected error from clone3\n"); + return -1; + } + + return 0; +} + int kerndat_init(void) { int ret; @@ -1059,6 +1098,8 @@ int kerndat_init(void) ret = has_kcmp_epoll_tfd(); if (!ret) ret = kerndat_has_fsopen(); + if (!ret) + ret = kerndat_has_clone3_set_tid(); kerndat_lsm(); kerndat_mmap_min_addr(); From 97c03b97d00e27397ca2ea0f9b5569739e24ae27 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 16 Dec 2019 07:57:03 +0000 Subject: [PATCH 2285/4375] Add assembler wrapper for clone3() To create a new process/thread with a certain PID based on clone3() a new assembler wrapper is necessary as there is not glibc wrapper (yet). Signed-off-by: Adrian Reber --- criu/arch/aarch64/include/asm/restorer.h | 7 ++ criu/arch/arm/include/asm/restorer.h | 7 ++ criu/arch/ppc64/include/asm/restorer.h | 7 ++ criu/arch/s390/include/asm/restorer.h | 7 ++ criu/arch/x86/include/asm/restorer.h | 92 ++++++++++++++++++++++++ 5 files changed, 120 insertions(+) diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h index f502cdcaf..2fe58915b 100644 --- a/criu/arch/aarch64/include/asm/restorer.h +++ b/criu/arch/aarch64/include/asm/restorer.h @@ -42,6 +42,13 @@ "r"(&thread_args[i]) \ : "x0", "x1", "x2", "x3", "x8", "memory") +#define RUN_CLONE3_RESTORE_FN(ret, clone_args, size, args, \ + clone_restore_fn) do { \ + pr_err("This architecture does not support clone3() with set_tid, yet!\n"); \ + pr_err("Not creating a process with PID: %d\n", ((pid_t *)u64_to_ptr(clone_args.set_tid))[0]); \ + ret = -1; \ +} while (0) + #define ARCH_FAIL_CORE_RESTORE \ asm volatile( \ "mov sp, %0 \n" \ diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h index 217d920e8..ad4b58f93 100644 --- a/criu/arch/arm/include/asm/restorer.h +++ b/criu/arch/arm/include/asm/restorer.h @@ -43,6 +43,13 @@ "r"(&thread_args[i]) \ : "r0", "r1", "r2", "r3", "r7", "memory") +#define RUN_CLONE3_RESTORE_FN(ret, clone_args, size, args, \ + clone_restore_fn) do { \ + pr_err("This architecture does not support clone3() with set_tid, yet!\n"); \ + pr_err("Not creating a process with PID: %d\n", ((pid_t *)u64_to_ptr(clone_args.set_tid))[0]); \ + ret = -1; \ +} while (0) + #define ARCH_FAIL_CORE_RESTORE \ asm volatile( \ "mov sp, %0 \n" \ diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h index d48d833d6..19bc3ea36 100644 --- a/criu/arch/ppc64/include/asm/restorer.h +++ b/criu/arch/ppc64/include/asm/restorer.h @@ -48,6 +48,13 @@ "r"(&thread_args[i]) /* %6 */ \ : "memory","0","3","4","5","6","7","14","15") +#define RUN_CLONE3_RESTORE_FN(ret, clone_args, size, args, \ + clone_restore_fn) do { \ + pr_err("This architecture does not support clone3() with set_tid, yet!\n"); \ + pr_err("Not creating a process with PID: %d\n", ((pid_t *)u64_to_ptr(clone_args.set_tid))[0]); \ + ret = -1; \ +} while (0) + #define arch_map_vdso(map, compat) -1 int restore_gpregs(struct rt_sigframe *f, UserPpc64RegsEntry *r); diff --git a/criu/arch/s390/include/asm/restorer.h b/criu/arch/s390/include/asm/restorer.h index cfdefcab9..733f2de33 100644 --- a/criu/arch/s390/include/asm/restorer.h +++ b/criu/arch/s390/include/asm/restorer.h @@ -39,6 +39,13 @@ "d"(&thread_args[i]) \ : "0", "1", "2", "3", "4", "5", "6", "cc", "memory") +#define RUN_CLONE3_RESTORE_FN(ret, clone_args, size, args, \ + clone_restore_fn) do { \ + pr_err("This architecture does not support clone3() with set_tid, yet!\n"); \ + pr_err("Not creating a process with PID: %d\n", ((pid_t *)u64_to_ptr(clone_args.set_tid))[0]); \ + ret = -1; \ +} while (0) + #define arch_map_vdso(map, compat) -1 int restore_gpregs(struct rt_sigframe *f, UserS390RegsEntry *r); diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h index 25559b57c..731477ec9 100644 --- a/criu/arch/x86/include/asm/restorer.h +++ b/criu/arch/x86/include/asm/restorer.h @@ -25,6 +25,21 @@ static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) } #endif /* !CONFIG_COMPAT */ +/* + * Documentation copied from glibc sysdeps/unix/sysv/linux/x86_64/clone.S + * The kernel expects: + * rax: system call number + * rdi: flags + * rsi: child_stack + * rdx: TID field in parent + * r10: TID field in child + * r8: thread pointer + * + * int clone(unsigned long clone_flags, unsigned long newsp, + * int *parent_tidptr, int *child_tidptr, + * unsigned long tls); + */ + #define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \ thread_args, clone_restore_fn) \ asm volatile( \ @@ -63,6 +78,83 @@ static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) "g"(&thread_args[i]) \ : "rax", "rcx", "rdi", "rsi", "rdx", "r10", "r11", "memory") +/* int clone3(struct clone_args *args, size_t size) */ +#define RUN_CLONE3_RESTORE_FN(ret, clone_args, size, args, \ + clone_restore_fn) \ + asm volatile( \ + "clone3_emul: \n" \ + /* + * Prepare stack pointer for child process. The kernel does + * stack + stack_size before passing the stack pointer to the + * child process. As we have to put the function and the + * arguments for the new process on that stack we have handle + * the kernel's implicit stack + stack_size. + */ \ + "movq (%3), %%rsi /* new stack pointer */ \n" \ + /* Move the stack_size to %rax to use later as the offset */ \ + "movq %4, %%rax \n" \ + /* 16 bytes are needed on the stack for function and args */ \ + "subq $16, (%%rsi, %%rax) \n" \ + "movq %6, %%rdi /* thread args */ \n" \ + "movq %%rdi, 8(%%rsi, %%rax) \n" \ + "movq %5, %%rdi /* thread function */ \n" \ + "movq %%rdi, 0(%%rsi, %%rax) \n" \ + /* + * The stack address has been modified for the two + * elements above (child function, child arguments). + * This modified stack needs to be stored back into the + * clone_args structure. + */ \ + "movq (%%rsi), %3 \n" \ + /* + * Do the actual clone3() syscall. First argument (%rdi) is + * the clone_args structure, second argument is the size + * of clone_args. + */ \ + "movq %1, %%rdi /* clone_args */ \n" \ + "movq %2, %%rsi /* size */ \n" \ + "movl $"__stringify(__NR_clone3)", %%eax \n" \ + "syscall \n" \ + /* + * If clone3() was successful and if we are in the child + * '0' is returned. Jump to the child function handler. + */ \ + "testq %%rax,%%rax \n" \ + "jz thread3_run \n" \ + /* Return the PID to the parent process. */ \ + "movq %%rax, %0 \n" \ + "jmp clone3_end \n" \ + \ + "thread3_run: /* Child process */ \n" \ + /* Clear the frame pointer */ \ + "xorq %%rbp, %%rbp \n" \ + /* Pop the child function from the stack */ \ + "popq %%rax \n" \ + /* Pop the child function arguments from the stack */ \ + "popq %%rdi \n" \ + /* Run the child function */ \ + "callq *%%rax \n" \ + /* + * If the child function is expected to return, this + * would be the place to handle the return code. In CRIU's + * case the child function is expected to not return + * and do exit() itself. + */ \ + \ + "clone3_end: \n" \ + : "=r"(ret) \ + /* + * This uses the "r" modifier for all parameters + * as clang complained if using "g". + */ \ + : "r"(&clone_args), \ + "r"(size), \ + "r"(&clone_args.stack), \ + "r"(clone_args.stack_size), \ + "r"(clone_restore_fn), \ + "r"(args) \ + : "rax", "rcx", "rdi", "rsi", "rdx", "r10", "r11", "memory") + #define ARCH_FAIL_CORE_RESTORE \ asm volatile( \ "movq %0, %%rsp \n" \ From a1ea8deb4c0824dc2178dbe116c9b10f81a608aa Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 16 Dec 2019 10:42:13 +0000 Subject: [PATCH 2286/4375] Use clone3() with set_tid to create processes With the in Linux Kernel 5.4 introduced clone3() with set_tid it is no longer necessary to write to to /proc/../ns_last_pid to influence the next PID number. clone3() can directly select a PID for the newly created process/thread. After checking for the availability of clone3() with set_tid and adding the assembler wrapper for clone3() in previous patches, this extends criu/pie/restorer.c and criu/clone-noasan.c to use the newly added assembler clone3() wrapper to create processes with a certain PID. This is a RFC and WIP, but I wanted to share it and run it through CI for feedback. As the CI will probably not use a 5.4 based kernel it should just keep on working as before. Signed-off-by: Adrian Reber --- criu/clone-noasan.c | 32 +++++++++++++++++++ criu/cr-restore.c | 64 +++++++++++++++++++++++-------------- criu/include/clone-noasan.h | 2 ++ criu/include/restorer.h | 1 + criu/include/rst_info.h | 1 + criu/pie/restorer.c | 64 ++++++++++++++++++++++++------------- 6 files changed, 117 insertions(+), 47 deletions(-) diff --git a/criu/clone-noasan.c b/criu/clone-noasan.c index 5f1858d4d..bcbc3e4bd 100644 --- a/criu/clone-noasan.c +++ b/criu/clone-noasan.c @@ -1,4 +1,10 @@ +#include #include +#include + +#include + +#include "sched.h" #include "common/compiler.h" #include "log.h" #include "common/bug.h" @@ -31,6 +37,7 @@ int clone_noasan(int (*fn)(void *), int flags, void *arg) { void *stack_ptr = (void *)round_down((unsigned long)&stack_ptr - 1024, 16); + BUG_ON((flags & CLONE_VM) && !(flags & CLONE_VFORK)); /* * Reserve some bytes for clone() internal needs @@ -38,3 +45,28 @@ int clone_noasan(int (*fn)(void *), int flags, void *arg) */ return clone(fn, stack_ptr, flags, arg); } + +int clone3_with_pid_noasan(int (*fn)(void *), void *arg, int flags, + int exit_signal, pid_t pid) +{ + struct _clone_args c_args = {}; + + BUG_ON(flags & CLONE_VM); + + /* + * Make sure no child signals are requested. clone3() uses + * exit_signal for that. + */ + BUG_ON(flags & 0xff); + + pr_debug("Creating process using clone3()\n"); + + c_args.exit_signal = exit_signal; + c_args.flags = flags; + c_args.set_tid = ptr_to_u64(&pid); + c_args.set_tid_size = 1; + pid = syscall(__NR_clone3, &c_args, sizeof(c_args)); + if (pid == 0) + exit(fn(arg)); + return pid; +} diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 687cd6c68..b4f8d9e75 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1374,40 +1374,55 @@ static inline int fork_with_pid(struct pstree_item *item) if (!(ca.clone_flags & CLONE_NEWPID)) { char buf[32]; int len; - int fd; + int fd = -1; - fd = open_proc_rw(PROC_GEN, LAST_PID_PATH); - if (fd < 0) - goto err; + if (!kdat.has_clone3_set_tid) { + fd = open_proc_rw(PROC_GEN, LAST_PID_PATH); + if (fd < 0) + goto err; + } lock_last_pid(); - len = snprintf(buf, sizeof(buf), "%d", pid - 1); - if (write(fd, buf, len) != len) { - pr_perror("%d: Write %s to %s", pid, buf, LAST_PID_PATH); + if (!kdat.has_clone3_set_tid) { + len = snprintf(buf, sizeof(buf), "%d", pid - 1); + if (write(fd, buf, len) != len) { + pr_perror("%d: Write %s to %s", pid, buf, + LAST_PID_PATH); + close(fd); + goto err_unlock; + } close(fd); - goto err_unlock; } - close(fd); } else { BUG_ON(pid != INIT_PID); } - /* - * Some kernel modules, such as network packet generator - * run kernel thread upon net-namespace creattion taking - * the @pid we've been requeting via LAST_PID_PATH interface - * so that we can't restore a take with pid needed. - * - * Here is an idea -- unhare net namespace in callee instead. - */ - /* - * The cgroup namespace is also unshared explicitly in the - * move_in_cgroup(), so drop this flag here as well. - */ - close_pid_proc(); - ret = clone_noasan(restore_task_with_children, - (ca.clone_flags & ~(CLONE_NEWNET | CLONE_NEWCGROUP)) | SIGCHLD, &ca); + if (kdat.has_clone3_set_tid) { + ret = clone3_with_pid_noasan(restore_task_with_children, + &ca, (ca.clone_flags & + ~(CLONE_NEWNET | CLONE_NEWCGROUP)), + SIGCHLD, pid); + } else { + /* + * Some kernel modules, such as network packet generator + * run kernel thread upon net-namespace creation taking + * the @pid we've been requesting via LAST_PID_PATH interface + * so that we can't restore a take with pid needed. + * + * Here is an idea -- unshare net namespace in callee instead. + */ + /* + * The cgroup namespace is also unshared explicitly in the + * move_in_cgroup(), so drop this flag here as well. + */ + close_pid_proc(); + ret = clone_noasan(restore_task_with_children, + (ca.clone_flags & + ~(CLONE_NEWNET | CLONE_NEWCGROUP)) | SIGCHLD, + &ca); + } + if (ret < 0) { pr_perror("Can't fork for %d", pid); goto err_unlock; @@ -3588,6 +3603,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns task_args->vdso_maps_rt = vdso_maps_rt; task_args->vdso_rt_size = vdso_rt_size; task_args->can_map_vdso = kdat.can_map_vdso; + task_args->has_clone3_set_tid = kdat.has_clone3_set_tid; new_sp = restorer_stack(task_args->t->mz); diff --git a/criu/include/clone-noasan.h b/criu/include/clone-noasan.h index 8ef75fa73..0cfdaa1d9 100644 --- a/criu/include/clone-noasan.h +++ b/criu/include/clone-noasan.h @@ -2,5 +2,7 @@ #define __CR_CLONE_NOASAN_H__ int clone_noasan(int (*fn)(void *), int flags, void *arg); +int clone3_with_pid_noasan(int (*fn)(void *), void *arg, int flags, + int exit_signal, pid_t pid); #endif /* __CR_CLONE_NOASAN_H__ */ diff --git a/criu/include/restorer.h b/criu/include/restorer.h index b93807f5f..dfb4e6b71 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -221,6 +221,7 @@ struct task_restore_args { #endif int lsm_type; int child_subreaper; + bool has_clone3_set_tid; } __aligned(64); /* diff --git a/criu/include/rst_info.h b/criu/include/rst_info.h index 07c634f4a..3283849e4 100644 --- a/criu/include/rst_info.h +++ b/criu/include/rst_info.h @@ -4,6 +4,7 @@ #include "common/lock.h" #include "common/list.h" #include "vma.h" +#include "kerndat.h" struct task_entries { int nr_threads, nr_tasks, nr_helpers; diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 888eb8e65..7012b88a1 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -35,6 +35,7 @@ #include "sk-inet.h" #include "vma.h" #include "uffd.h" +#include "sched.h" #include "common/lock.h" #include "common/page.h" @@ -1771,16 +1772,19 @@ long __export_restore_task(struct task_restore_args *args) long clone_flags = CLONE_VM | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | CLONE_FS; long last_pid_len; + pid_t thread_pid; long parent_tid; int i, fd = -1; - /* One level pid ns hierarhy */ - fd = sys_openat(args->proc_fd, LAST_PID_PATH, O_RDWR, 0); - if (fd < 0) { - pr_err("can't open last pid fd %d\n", fd); - goto core_restore_end; - } + if (!args->has_clone3_set_tid) { + /* One level pid ns hierarhy */ + fd = sys_openat(args->proc_fd, LAST_PID_PATH, O_RDWR, 0); + if (fd < 0) { + pr_err("can't open last pid fd %d\n", fd); + goto core_restore_end; + } + } mutex_lock(&task_entries_local->last_pid_mutex); for (i = 0; i < args->nr_threads; i++) { @@ -1791,24 +1795,38 @@ long __export_restore_task(struct task_restore_args *args) continue; new_sp = restorer_stack(thread_args[i].mz); - last_pid_len = std_vprint_num(last_pid_buf, sizeof(last_pid_buf), thread_args[i].pid - 1, &s); - sys_lseek(fd, 0, SEEK_SET); - ret = sys_write(fd, s, last_pid_len); - if (ret < 0) { - pr_err("Can't set last_pid %ld/%s\n", ret, last_pid_buf); - sys_close(fd); - mutex_unlock(&task_entries_local->last_pid_mutex); - goto core_restore_end; + if (args->has_clone3_set_tid) { + struct _clone_args c_args = {}; + thread_pid = thread_args[i].pid; + c_args.set_tid = ptr_to_u64(&thread_pid); + c_args.flags = clone_flags; + c_args.set_tid_size = 1; + /* The kernel does stack + stack_size. */ + c_args.stack = new_sp - RESTORE_STACK_SIZE; + c_args.stack_size = RESTORE_STACK_SIZE; + c_args.child_tid = ptr_to_u64(&thread_args[i].pid); + c_args.parent_tid = ptr_to_u64(&parent_tid); + pr_debug("Using clone3 to restore the process\n"); + RUN_CLONE3_RESTORE_FN(ret, c_args, sizeof(c_args), &thread_args[i], args->clone_restore_fn); + } else { + last_pid_len = std_vprint_num(last_pid_buf, sizeof(last_pid_buf), thread_args[i].pid - 1, &s); + sys_lseek(fd, 0, SEEK_SET); + ret = sys_write(fd, s, last_pid_len); + if (ret < 0) { + pr_err("Can't set last_pid %ld/%s\n", ret, last_pid_buf); + sys_close(fd); + mutex_unlock(&task_entries_local->last_pid_mutex); + goto core_restore_end; + } + + /* + * To achieve functionality like libc's clone() + * we need a pure assembly here, because clone()'ed + * thread will run with own stack and we must not + * have any additional instructions... oh, dear... + */ + RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, thread_args, args->clone_restore_fn); } - - /* - * To achieve functionality like libc's clone() - * we need a pure assembly here, because clone()'ed - * thread will run with own stack and we must not - * have any additional instructions... oh, dear... - */ - - RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, thread_args, args->clone_restore_fn); if (ret != thread_args[i].pid) { pr_err("Unable to create a thread: %ld\n", ret); mutex_unlock(&task_entries_local->last_pid_mutex); From 4c4f67a56be60300e734d92411e16e26928d3776 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 Jan 2020 14:27:09 +0100 Subject: [PATCH 2287/4375] s390x: remove stack pointer from clobber list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just like on all other supported architectures gcc complains about the stack pointer register being part of the clobber list: error: listing the stack pointer register ‘15’ in a clobber list is deprecated [-Werror=deprecated] This removes the stack pointer from the clobber list. 'zdtm.py run -a' still runs without any errors after this change. Signed-off-by: Adrian Reber --- compel/arch/s390/src/lib/include/uapi/asm/sigframe.h | 2 +- criu/arch/s390/include/asm/restore.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h b/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h index b6b894473..c599ef3ab 100644 --- a/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h +++ b/compel/arch/s390/src/lib/include/uapi/asm/sigframe.h @@ -66,7 +66,7 @@ struct rt_sigframe { "svc 0\n" \ : \ : "d" (new_sp) \ - : "15", "memory") + : "memory") #define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->uc) #define RT_SIGFRAME_REGIP(rt_sigframe) (rt_sigframe)->uc.uc_mcontext.regs.psw.addr diff --git a/criu/arch/s390/include/asm/restore.h b/criu/arch/s390/include/asm/restore.h index 6463d8e62..b77e36c77 100644 --- a/criu/arch/s390/include/asm/restore.h +++ b/criu/arch/s390/include/asm/restore.h @@ -18,7 +18,7 @@ : "d" (new_sp), \ "d"((unsigned long)restore_task_exec_start), \ "d" (task_args) \ - : "2", "14", "15", "memory") + : "2", "14", "memory") /* There is nothing to do since TLS is accessed through %a01 */ #define core_get_tls(pcore, ptls) From cbadd201cbd20b7e44b9f8edea932a9420f67230 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 16 Jan 2020 16:41:40 +0100 Subject: [PATCH 2288/4375] s390x: use clone3() if possible This adds the parasite clone3() with set_tid wrapper for s390x. In contrast to the x86_64 implementation the thread start address and arguments are not put on the thread stack but passed via r4 and r5. As those registers are caller-saved they still contain the correct value (thread start address and arguments) after returning from the syscall. Tested on 5.5.0-rc6. Signed-off-by: Adrian Reber --- criu/arch/s390/include/asm/restorer.h | 40 +++++++++++++++++++++++---- criu/kerndat.c | 4 +-- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/criu/arch/s390/include/asm/restorer.h b/criu/arch/s390/include/asm/restorer.h index 733f2de33..2fc266535 100644 --- a/criu/arch/s390/include/asm/restorer.h +++ b/criu/arch/s390/include/asm/restorer.h @@ -40,11 +40,41 @@ : "0", "1", "2", "3", "4", "5", "6", "cc", "memory") #define RUN_CLONE3_RESTORE_FN(ret, clone_args, size, args, \ - clone_restore_fn) do { \ - pr_err("This architecture does not support clone3() with set_tid, yet!\n"); \ - pr_err("Not creating a process with PID: %d\n", ((pid_t *)u64_to_ptr(clone_args.set_tid))[0]); \ - ret = -1; \ -} while (0) + clone_restore_fn) \ + asm volatile( \ + /* + * clone3 only needs two arguments (r2, r3), this means + * we can use r4 and r5 for args and thread function. + * r4 and r5 are callee-saved and are not overwritten. + * No need to put these values on the child stack. + */ \ + "lgr %%r4,%4\n" /* Save args in %r4 */ \ + "lgr %%r5,%3\n" /* Save clone_restore_fn in %r5 */ \ + "lgr %%r2,%1\n" /* Parameter 1: clone_args */ \ + "lgr %%r3,%2\n" /* Parameter 2: size */ \ + /* + * On s390x a syscall is done sc . + * That only works for syscalls < 255. clone3 is 435, + * therefore it is necessary to load the syscall number + * into r1 and do 'svc 0'. + */ \ + "lghi %%r1,"__stringify(__NR_clone3)"\n" \ + "svc 0\n" \ + "ltgr %0,%%r2\n" /* Set and check "ret" */ \ + "jnz 0f\n" /* ret != 0: Continue caller */ \ + "lgr %%r2,%%r4\n" /* Thread arguments taken from r4. */ \ + "lgr %%r1,%%r5\n" /* Thread function taken from r5. */ \ + "aghi %%r15,-160\n" /* Prepare stack frame */ \ + "xc 0(8,%%r15),0(%%r15)\n" \ + "basr %%r14,%%r1\n" /* Jump to clone_restore_fn() */ \ + "j .+2\n" /* BUG(): Force PGM check */ \ +"0:\n" /* Continue caller */ \ + : "=d"(ret) \ + : "a"(&clone_args), \ + "d"(size), \ + "d"(clone_restore_fn), \ + "d"(args) \ + : "0", "1", "2", "3", "4", "5", "cc", "memory") #define arch_map_vdso(map, compat) -1 diff --git a/criu/kerndat.c b/criu/kerndat.c index 0772828bc..2261cca60 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -992,10 +992,10 @@ static bool kerndat_has_clone3_set_tid(void) pid_t pid; struct _clone_args args = {}; -#ifndef CONFIG_X86_64 +#if !defined(CONFIG_X86_64) && !defined(CONFIG_S390) /* * Currently the CRIU PIE assembler clone3() wrapper is - * only implemented for X86_64. + * only implemented for X86_64 and S390X. */ kdat.has_clone3_set_tid = false; return 0; From 55c8ec62a53e2728b09ee93d36fd6dd36eeb0c49 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 21 Jan 2020 14:20:05 +0100 Subject: [PATCH 2289/4375] arm: remove stack pointer from clobber list Just like on all other supported architectures gcc complains about the stack pointer register being part of the clobber list. This removes the stack pointer from the clobber list. Signed-off-by: Adrian Reber --- criu/arch/arm/include/asm/restore.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/arch/arm/include/asm/restore.h b/criu/arch/arm/include/asm/restore.h index 4c64d58ef..c3b64c5b7 100644 --- a/criu/arch/arm/include/asm/restore.h +++ b/criu/arch/arm/include/asm/restore.h @@ -16,7 +16,7 @@ : "r"(new_sp), \ "r"(restore_task_exec_start), \ "r"(task_args) \ - : "sp", "r0", "r1", "memory") + : "r0", "r1", "memory") static inline void core_get_tls(CoreEntry *pcore, tls_t *ptls) { From f6469493dd739d4c16c8230524fa5d5a88731b80 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Fri, 17 Jan 2020 13:35:48 +0100 Subject: [PATCH 2290/4375] ppc64le: use clone3() if possible This adds the parasite clone3() with set_tid wrapper for ppc64le. Signed-off-by: Adrian Reber --- criu/arch/ppc64/include/asm/restorer.h | 46 ++++++++++++++++++++++---- criu/kerndat.c | 4 +-- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h index 19bc3ea36..c447eefea 100644 --- a/criu/arch/ppc64/include/asm/restorer.h +++ b/criu/arch/ppc64/include/asm/restorer.h @@ -48,12 +48,46 @@ "r"(&thread_args[i]) /* %6 */ \ : "memory","0","3","4","5","6","7","14","15") -#define RUN_CLONE3_RESTORE_FN(ret, clone_args, size, args, \ - clone_restore_fn) do { \ - pr_err("This architecture does not support clone3() with set_tid, yet!\n"); \ - pr_err("Not creating a process with PID: %d\n", ((pid_t *)u64_to_ptr(clone_args.set_tid))[0]); \ - ret = -1; \ -} while (0) +#define RUN_CLONE3_RESTORE_FN(ret, clone_args, size, args, \ + clone_restore_fn) \ +/* + * The clone3() function accepts following parameters: + * int clone3(struct clone_args *args, size_t size) + * + * Always consult the CLONE3 wrappers for other architectures + * for additional details. + * + * For PPC64LE the first parameter (clone_args) is passed in r3 and + * the second parameter (size) is passed in r4. + * + * This clone3() wrapper is based on the clone() wrapper from above. + */ \ + asm volatile( \ + "clone3_emul: \n" \ + "/* Save fn, args across syscall. */ \n" \ + "mr 14, %3 /* clone_restore_fn in r14 */ \n" \ + "mr 15, %4 /* &thread_args[i] in r15 */ \n" \ + "mr 3, %1 /* clone_args */ \n" \ + "mr 4, %2 /* size */ \n" \ + "li 0,"__stringify(__NR_clone3)" \n" \ + "sc \n" \ + "/* Check for child process. */ \n" \ + "cmpdi cr1,3,0 \n" \ + "crandc cr1*4+eq,cr1*4+eq,cr0*4+so \n" \ + "bne- cr1,clone3_end \n" \ + "/* child */ \n" \ + "addi 14, 14, 8 /* jump over r2 fixup */ \n" \ + "mtctr 14 \n" \ + "mr 3,15 \n" \ + "bctr \n" \ + "clone3_end: \n" \ + "mr %0,3 \n" \ + : "=r"(ret) /* %0 */ \ + : "r"(&clone_args), /* %1 */ \ + "r"(size), /* %2 */ \ + "r"(clone_restore_fn), /* %3 */ \ + "r"(args) /* %4 */ \ + : "memory","0","3","4","5","14","15") #define arch_map_vdso(map, compat) -1 diff --git a/criu/kerndat.c b/criu/kerndat.c index 2261cca60..c1fc9259b 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -992,10 +992,10 @@ static bool kerndat_has_clone3_set_tid(void) pid_t pid; struct _clone_args args = {}; -#if !defined(CONFIG_X86_64) && !defined(CONFIG_S390) +#if !defined(CONFIG_X86_64) && !defined(CONFIG_S390) && !defined(CONFIG_PPC64) /* * Currently the CRIU PIE assembler clone3() wrapper is - * only implemented for X86_64 and S390X. + * only implemented for X86_64, S390X and PPC64LE. */ kdat.has_clone3_set_tid = false; return 0; From 3dabd38a8292872dcf4c5710449a4c8017304ac2 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Sat, 25 Jan 2020 13:25:21 +0100 Subject: [PATCH 2291/4375] clone3: handle clone3() with CLONE_PARENT clone3() explicitly blocks setting an exit_signal if CLONE_PARENT is specified. With clone() it also did not work, but there was no error message. The exit signal from the thread group leader is taken. Signed-off-by: Adrian Reber --- criu/clone-noasan.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/criu/clone-noasan.c b/criu/clone-noasan.c index bcbc3e4bd..a2190ba0a 100644 --- a/criu/clone-noasan.c +++ b/criu/clone-noasan.c @@ -61,7 +61,19 @@ int clone3_with_pid_noasan(int (*fn)(void *), void *arg, int flags, pr_debug("Creating process using clone3()\n"); - c_args.exit_signal = exit_signal; + /* + * clone3() explicitly blocks setting an exit_signal + * if CLONE_PARENT is specified. With clone() it also + * did not work, but there was no error message. The + * exit signal from the thread group leader is taken. + */ + if (!(flags & CLONE_PARENT)) { + if (exit_signal != SIGCHLD) { + pr_err("Exit signal not SIGCHLD\n"); + return -1; + } + c_args.exit_signal = exit_signal; + } c_args.flags = flags; c_args.set_tid = ptr_to_u64(&pid); c_args.set_tid_size = 1; From f991f235064807a59ad8e4f98e82f34767b05e18 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Sun, 19 Jan 2020 21:42:58 +0100 Subject: [PATCH 2292/4375] aarch64: use clone3() if possible This adds the parasite clone3() with set_tid wrapper for aarch64. Tested on Fedora 31 with 5.5.0-rc6. Signed-off-by: Adrian Reber --- criu/arch/aarch64/include/asm/restorer.h | 67 +++++++++++++++++++++--- criu/kerndat.c | 4 +- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h index 2fe58915b..120fa8fb2 100644 --- a/criu/arch/aarch64/include/asm/restorer.h +++ b/criu/arch/aarch64/include/asm/restorer.h @@ -42,12 +42,67 @@ "r"(&thread_args[i]) \ : "x0", "x1", "x2", "x3", "x8", "memory") -#define RUN_CLONE3_RESTORE_FN(ret, clone_args, size, args, \ - clone_restore_fn) do { \ - pr_err("This architecture does not support clone3() with set_tid, yet!\n"); \ - pr_err("Not creating a process with PID: %d\n", ((pid_t *)u64_to_ptr(clone_args.set_tid))[0]); \ - ret = -1; \ -} while (0) +/* + * Based on sysdeps/unix/sysv/linux/aarch64/clone.S + * + * int clone(int (*fn)(void *arg), x0 + * void *child_stack, x1 + * int flags, x2 + * void *arg, x3 + * pid_t *ptid, x4 + * struct user_desc *tls, x5 + * pid_t *ctid); x6 + * + * int clone3(struct clone_args *args, x0 + * size_t size); x1 + * + * Always consult the CLONE3 wrappers for other architectures + * for additional details. + * + */ + +#define RUN_CLONE3_RESTORE_FN(ret, clone_args, size, args, \ + clone_restore_fn) \ + asm volatile( \ + /* In contrast to the clone() wrapper above this does not put + * the thread function and its arguments on the child stack, + * but uses registers to pass these parameters to the child process. + * Based on the glibc clone() wrapper at + * sysdeps/unix/sysv/linux/aarch64/clone.S. + */ \ + "clone3_emul: \n" \ + /* + * Based on the glibc clone() wrapper, which uses x10 and x11 + * to save the arguments for the child process, this does the same. + * x10 for the thread function and x11 for the thread arguments. + */ \ + "mov x10, %3 /* clone_restore_fn */ \n" \ + "mov x11, %4 /* args */ \n" \ + "mov x0, %1 /* &clone_args */ \n" \ + "mov x1, %2 /* size */ \n" \ + /* Load syscall number */ \ + "mov x8, #"__stringify(__NR_clone3)" \n" \ + /* Do the syscall */ \ + "svc #0 \n" \ + \ + "cbz x0, clone3_thread_run \n" \ + \ + "mov %0, x0 \n" \ + "b clone3_end \n" \ + \ + "clone3_thread_run: \n" \ + /* Move args to x0 */ \ + "mov x0, x11 \n" \ + /* Jump to clone_restore_fn */ \ + "br x10 \n" \ + \ + "clone3_end: \n" \ + : "=r"(ret) \ + : "r"(&clone_args), \ + "r"(size), \ + "r"(clone_restore_fn), \ + "r"(args) \ + : "x0", "x1", "x8", "x10", "x11", "memory") #define ARCH_FAIL_CORE_RESTORE \ asm volatile( \ diff --git a/criu/kerndat.c b/criu/kerndat.c index c1fc9259b..4070e01d2 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -992,10 +992,10 @@ static bool kerndat_has_clone3_set_tid(void) pid_t pid; struct _clone_args args = {}; -#if !defined(CONFIG_X86_64) && !defined(CONFIG_S390) && !defined(CONFIG_PPC64) +#if !defined(CONFIG_X86_64) && !defined(CONFIG_S390) && !defined(CONFIG_PPC64) && !defined(CONFIG_AARCH64) /* * Currently the CRIU PIE assembler clone3() wrapper is - * only implemented for X86_64, S390X and PPC64LE. + * only implemented for X86_64, S390X, AARCH64 and PPC64LE. */ kdat.has_clone3_set_tid = false; return 0; From 0e291d26c9e0258f60ae8921f0e03c89f332dc31 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 22 Jan 2020 19:41:41 +0100 Subject: [PATCH 2293/4375] arm: use clone3() if it exists This is the last architecture specific change to make CRIU use clone3() with set_tid if available. Just as on all other architectures this adds a clone3() based assembler wrapper to be used in the restorer code. Tested on Fedora 31 with the same 5.5.0-rc6 kernel as on the other architectures. Signed-off-by: Adrian Reber --- criu/arch/arm/include/asm/restorer.h | 62 +++++++++++++++++++++++++--- criu/kerndat.c | 9 ---- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h index ad4b58f93..13ed15b26 100644 --- a/criu/arch/arm/include/asm/restorer.h +++ b/criu/arch/arm/include/asm/restorer.h @@ -43,12 +43,62 @@ "r"(&thread_args[i]) \ : "r0", "r1", "r2", "r3", "r7", "memory") -#define RUN_CLONE3_RESTORE_FN(ret, clone_args, size, args, \ - clone_restore_fn) do { \ - pr_err("This architecture does not support clone3() with set_tid, yet!\n"); \ - pr_err("Not creating a process with PID: %d\n", ((pid_t *)u64_to_ptr(clone_args.set_tid))[0]); \ - ret = -1; \ -} while (0) + +/* + * The clone3() assembler wrapper is based on the clone() wrapper above + * and on code from the glibc wrapper at + * sysdeps/unix/sysv/linux/arm/clone.S + * + * For arm it is necessary to change the child stack as on x86_64 as + * it seems there are not registers which stay the same over a syscall + * like on s390x, ppc64le and aarch64. + * + * Changing the child stack means that this code has to deal with the + * kernel doing stack + stack_size implicitly. + * + * int clone3(struct clone_args *args, size_t size) + */ + +#define RUN_CLONE3_RESTORE_FN(ret, clone_args, size, args, \ + clone_restore_fn) \ + asm volatile( \ + "clone3_emul: \n" \ + /* Load thread stack pointer */ \ + "ldr r1, [%3] \n" \ + /* Load thread stack size */ \ + "mov r2, %4 \n" \ + /* Goto to the end of stack */ \ + "add r1, r1, r2 \n" \ + /* Load thread function and arguments and push on stack */ \ + "mov r2, %6 /* args */ \n" \ + "str r2, [r1, #4] /* args */ \n" \ + "mov r2, %5 /* function */ \n" \ + "str r2, [r1] /* function */ \n" \ + "mov r0, %1 /* clone_args */ \n" \ + "mov r1, %2 /* size */ \n" \ + "mov r7, #"__stringify(__NR_clone3)" \n" \ + "svc #0 \n" \ + \ + "cmp r0, #0 \n" \ + "beq thread3_run \n" \ + \ + "mov %0, r0 \n" \ + "b clone3_end \n" \ + \ + "thread3_run: \n" \ + "pop { r1 } \n" \ + "pop { r0 } \n" \ + "bx r1 \n" \ + \ + "clone3_end: \n" \ + : "=r"(ret) \ + : "r"(&clone_args), \ + "r"(size), \ + "r"(&clone_args.stack), \ + "r"(clone_args.stack_size), \ + "r"(clone_restore_fn), \ + "r"(args) \ + : "r0", "r1", "r2", "r7", "memory") #define ARCH_FAIL_CORE_RESTORE \ asm volatile( \ diff --git a/criu/kerndat.c b/criu/kerndat.c index 4070e01d2..e0b5731d5 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -992,15 +992,6 @@ static bool kerndat_has_clone3_set_tid(void) pid_t pid; struct _clone_args args = {}; -#if !defined(CONFIG_X86_64) && !defined(CONFIG_S390) && !defined(CONFIG_PPC64) && !defined(CONFIG_AARCH64) - /* - * Currently the CRIU PIE assembler clone3() wrapper is - * only implemented for X86_64, S390X, AARCH64 and PPC64LE. - */ - kdat.has_clone3_set_tid = false; - return 0; -#endif - args.set_tid = -1; /* * On a system without clone3() this will return ENOSYS. From f6de8d4ea9a2d0ce8f9d3373ab04a3c080348a86 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 4 Feb 2020 14:43:59 +0000 Subject: [PATCH 2294/4375] travis: fix warning and errors from validation This fixes the validation errors from Travis: Build config validation root: deprecated key sudo (The key `sudo` has no effect anymore.) root: missing os, using the default linux root: key matrix is an alias for jobs, using jobs Signed-off-by: Adrian Reber --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 25dd6a29b..7c36af006 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: c -sudo: required +os: linux dist: bionic cache: ccache services: @@ -12,7 +12,7 @@ env: - TR_ARCH=x86_64 - TR_ARCH=x86_64 CLANG=1 - TR_ARCH=openj9-test -matrix: +jobs: include: - os: linux arch: ppc64le From c98af78c58e2168d2322cd0ee15837468fd4ffb0 Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Tue, 14 Jan 2020 12:04:40 +0300 Subject: [PATCH 2295/4375] compel: add -ffreestanding to force gcc not to use builtin memcpy, memset This patch fixes the problem with SSE (xmm) registers corruption on amd64 architecture. The problem was that gcc generates parasite blob that uses xmm registers, but we don't preserve this registers in CRIU when injecting parasite. Also, gcc, even with -nostdlib option uses builtin memcpy, memset functions that optimized for amd64 and involves SSE registers. It seems, that optimal solution is to use -ffreestanding gcc option to compile parasite. This option implies -fno-builtin and also it designed for OS kernels compilation/another code that suited to work on non-hosted environments and could prevent future sumilar bugs. To check that you amd64 CRIU build affected by this problem you could simply objdump -dS criu/pie/parasite.o | grep xmm Output should be empty. Reported-by: Diyu Zhou Signed-off-by: Alexander Mikhalitsyn Signed-off-by: Alexander Mikhalitsyn --- compel/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compel/src/main.c b/compel/src/main.c index 51bac099f..8b2c8bc8d 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -21,7 +21,7 @@ #define CFLAGS_DEFAULT_SET \ "-Wstrict-prototypes " \ - "-fno-stack-protector -nostdlib -fomit-frame-pointer " + "-fno-stack-protector -nostdlib -fomit-frame-pointer -ffreestanding " #define COMPEL_CFLAGS_PIE CFLAGS_DEFAULT_SET "-fpie" #define COMPEL_CFLAGS_NOPIC CFLAGS_DEFAULT_SET "-fno-pic" From 8477875dc29e82485318b1c0f8482735755d5265 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 30 Jan 2020 15:21:54 -0800 Subject: [PATCH 2296/4375] doc/Makefile: don't hide xmlto stderr In case asciidoc is installed and xmlto is not, make returns an error but there's no diagnostics shown, since "xmlto: command not found" goes to /dev/null. Remove the redirect. Signed-off-by: Kir Kolyshkin --- Documentation/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index cbc7ff2c8..5025e2b99 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -54,7 +54,7 @@ ifneq ($(USE_ASCIIDOCTOR),) $(Q) $(ASCIIDOC) -b manpage -d manpage -o $@ $< else $(Q) $(ASCIIDOC) -b docbook -d manpage -o $(patsubst %.1,%.xml,$@) $< - $(Q) $(XMLTO) man -m custom.xsl $(patsubst %.1,%.xml,$@) 2>/dev/null + $(Q) $(XMLTO) man -m custom.xsl $(patsubst %.1,%.xml,$@) endif %.8: %.txt $(FOOTER) custom.xsl @@ -63,7 +63,7 @@ ifneq ($(USE_ASCIIDOCTOR),) $(Q) $(ASCIIDOC) -b manpage -d manpage -o $@ $< else $(Q) $(ASCIIDOC) -b docbook -d manpage -o $(patsubst %.8,%.xml,$@) $< - $(Q) $(XMLTO) man -m custom.xsl $(patsubst %.8,%.xml,$@) 2>/dev/null + $(Q) $(XMLTO) man -m custom.xsl $(patsubst %.8,%.xml,$@) endif %.ps: %.1 From a15426a111eb50e2339607225b0ab0d1dc49e0ed Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 30 Jan 2020 15:27:07 -0800 Subject: [PATCH 2297/4375] criu(8): some minor rewording 1. Add a/the articles where I see them missing 2. s/Forbid/disable/ 3. s/crit/crit(1)/ as we're referring to a man page 4. Simplify some descriptions Signed-off-by: Kir Kolyshkin --- Documentation/criu.txt | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 133a094c0..64b33ce6d 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -24,8 +24,8 @@ on a different system, or both. OPTIONS ------- -Most of the true / false long options (the ones without arguments) can be -prefixed with *--no-* to negate the option (example: *--display-stats* +Most of the long flags can be +prefixed with *no-* to negate the option (example: *--display-stats* and *--no-display-stats*). Common options @@ -33,9 +33,8 @@ Common options Common options are applicable to any 'command'. *-v*[*v*...], *--verbosity*:: - Increase verbosity up from the default level. Multiple *v* can be used, - each increasing verbosity by one level. Using long option without argument - increases verbosity by one level. + Increase verbosity up from the default level. In case of short option, + multiple *v* can be used, each increasing verbosity by one. *-v*'num', *--verbosity*='num':: Set verbosity level to 'num'. The higher the level, the more output @@ -57,22 +56,22 @@ The following levels are available: Pass a specific configuration file to criu. *--no-default-config*:: - Forbid parsing of default configuration files. + Disable parsing of default configuration files. *--pidfile* 'file':: Write root task, service or page-server pid into a 'file'. *-o*, *--log-file* 'file':: - Write logging messages to 'file'. + Write logging messages to a 'file'. *--display-stats*:: - During dump as well as during restore *criu* collects information - like the time required to dump or restore the process or the + During dump, as well as during restore, *criu* collects some statistics, + like the time required to dump or restore the process, or the number of pages dumped or restored. This information is always - written to the files 'stats-dump' and 'stats-restore' and can - be easily displayed using *crit*. The option *--display-stats* - additionally prints out this information on the console at the end - of a dump or a restore. + saved to the *stats-dump* and *stats-restore* files, and can + be shown using *crit*(1). The option *--display-stats* + prints out this information on the console at the end + of a dump or restore operation. *-D*, *--images-dir* 'path':: Use 'path' as a base directory where to look for sets of image files. From 23374b779898470016b2a0e95af56b0766aa6b3e Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 30 Jan 2020 15:30:57 -0800 Subject: [PATCH 2298/4375] criu(8): fix for asciidoctor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 0493724c8eda3 added support for using asciidoctor (instead of asciidoc + xmlto) to generate man pages. For some reason, asciidoctor does not deal well with some complex formatting that we use for options such as --external, leading to literal ’ and ' appearing in the man page instead of italic formatting. For example: > --inherit-fd fd[’N']:’resource' (here both N and resource should be in italic). Asciidoctor documentation (asciidoctor --help syntax) tells: > == Text Formatting > > .Constrained (applied at word boundaries) > *strong importance* (aka bold) > _stress emphasis_ (aka italic) > `monospaced` (aka typewriter text) > "`double`" and '`single`' typographic quotes > +passthrough text+ (substitutions disabled) > `+literal text+` (monospaced with substitutions disabled) > > .Unconstrained (applied anywhere) > **C**reate+**R**ead+**U**pdate+**D**elete > fan__freakin__tastic > ``mono``culture so I had to carefully replace *bold* with **bold** and 'italic' with __italic__ to make it all work. Tested with both terminal and postscript output, with both asciidoctor and asciidoc+xmlto. TODO: figure out how to fix examples (literal multi-line text), since asciidoctor does not display it in monospaced font (this is only true for postscript/pdf output so low priority). Signed-off-by: Kir Kolyshkin --- Documentation/criu.txt | 51 +++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 64b33ce6d..a6b9f7fae 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -36,8 +36,8 @@ Common options are applicable to any 'command'. Increase verbosity up from the default level. In case of short option, multiple *v* can be used, each increasing verbosity by one. -*-v*'num', *--verbosity*='num':: - Set verbosity level to 'num'. The higher the level, the more output +**-v**__num__, **--verbosity=**__num__:: + Set verbosity level to _num_. The higher the level, the more output is produced. + The following levels are available: @@ -184,7 +184,7 @@ In other words, do not use it unless really needed. *-s*, *--leave-stopped*:: Leave tasks in stopped state after checkpoint, instead of killing. -*--external* 'type'*[*'id'*]:*'value':: +*--external* __type__**[**__id__**]:**__value__:: Dump an instance of an external resource. The generic syntax is 'type' of resource, followed by resource 'id' (enclosed in literal square brackets), and optional 'value' (prepended by a literal colon). @@ -193,35 +193,36 @@ In other words, do not use it unless really needed. Note to restore external resources, either *--external* or *--inherit-fd* is used, depending on resource type. -*--external mnt[*'mountpoint'*]:*'name':: +*--external* **mnt[**__mountpoint__**]:**__name__:: Dump an external bind mount referenced by 'mountpoint', saving it to image under the identifier 'name'. -*--external mnt[]:*'flags':: +*--external* **mnt[]:**__flags__:: Dump all external bind mounts, autodetecting those. Optional 'flags' can contain *m* to also dump external master mounts, *s* to also dump external shared mounts (default behavior is to abort dumping if such mounts are found). If 'flags' are not provided, colon is optional. -*--external dev[*'major'*/*'minor'*]:*'name':: +*--external* **dev[**__major__**/**__minor__**]:**__name__:: Allow to dump a mount namespace having a real block device mounted. A block device is identified by its 'major' and 'minor' numbers, and *criu* saves its information to image under the identifier 'name'. -*--external file[*'mnt_id'*:*'inode'*]*:: +*--external* **file[**__mnt_id__**:**__inode__**]**:: Dump an external file, i.e. an opened file that is can not be resolved from the current mount namespace, which can not be dumped without using this option. The file is identified by 'mnt_id' (a field obtained from - */proc/*'pid'*/fdinfo/*'N') and 'inode' (as returned by *stat*(2)). + **/proc/**__pid__**/fdinfo/**__N__) and 'inode' (as returned by + *stat*(2)). -*--external tty[*'rdev'*:*'dev'*]*:: +*--external* **tty[**__rdev__**:**__dev__**]**:: Dump an external TTY, identified by *st_rdev* and *st_dev* fields returned by *stat*(2). -*--external unix[*'id'*]*:: +*--external* **unix[**__id__**]**:: Tell *criu* that one end of a pair of UNIX sockets (created by - *socketpair*(2)) with 'id' is OK to be disconnected. + *socketpair*(2)) with the given _id_ is OK to be disconnected. *--freeze-cgroup*:: Use cgroup freezer to collect processes. @@ -379,7 +380,7 @@ By default the option is set to *fpu* and *ins*. ~~~~~~~~~ Restores previously checkpointed processes. -*--inherit-fd* *fd[*'N'*]:*'resource':: +*--inherit-fd* **fd[**__N__**]:**__resource__:: Inherit a file descriptor. This option lets *criu* use an already opened file descriptor 'N' for restoring a file identified by 'resource'. This option can be used to restore an external resource dumped @@ -387,10 +388,10 @@ Restores previously checkpointed processes. + The 'resource' argument can be one of the following: + - - *tty[*'rdev'*:*'dev'*]* - - *pipe[*'inode'*]* - - *socket[*'inode'*]* - - *file[*'mnt_id'*:*'inode'*]* + - **tty[**__rdev__**:**__dev__**]** + - **pipe[**__inode__**]** + - **socket[**__inode__*]* + - **file[**__mnt_id__**:**__inode__**]** - 'path/to/file' + @@ -416,7 +417,7 @@ usually need to be escaped from shell. This option is required to restore a mount namespace. The directory 'path' must be a mount point and its parent must not be overmounted. -*--external* 'type'*[*'id'*]:*'value':: +*--external* __type__**[**__id__**]:**__value__:: Restore an instance of an external resource. The generic syntax is 'type' of resource, followed by resource 'id' (enclosed in literal square brackets), and optional 'value' (prepended by a literal colon). @@ -426,7 +427,7 @@ usually need to be escaped from shell. the help of *--external* *file*, *tty*, and *unix* options), option *--inherit-fd* should be used. -*--external mnt[*'name'*]:*'mountpoint':: +*--external* **mnt[**__name__**]:**__mountpoint__:: Restore an external bind mount referenced in the image by 'name', bind-mounting it from the host 'mountpoint' to a proper mount point. @@ -434,17 +435,17 @@ usually need to be escaped from shell. Restore all external bind mounts (dumped with the help of *--external mnt[]* auto-detection). -*--external dev[*'name'*]:*'/dev/path':: +*--external* **dev[**__name__**]:**__/dev/path__:: Restore an external mount device, identified in the image by 'name', using the existing block device '/dev/path'. -*--external veth[*'inner_dev'*]:*'outer_dev'*@*'bridge':: +*--external* **veth[**__inner_dev__**]:**__outer_dev__**@**__bridge__:: Set the outer VETH device name (corresponding to 'inner_dev' being - restored) to 'outer_dev'. If optional *@*'bridge' is specified, + restored) to 'outer_dev'. If optional **@**_bridge_ is specified, 'outer_dev' is added to that bridge. If the option is not used, 'outer_dev' will be autogenerated by the kernel. -*--external macvlan[*'inner_dev'*]:*'outer_dev':: +*--external* **macvlan[**__inner_dev__**]:**__outer_dev__:: When restoring an image that have a MacVLAN device in it, this option must be used to specify to which 'outer_dev' (an existing network device in CRIU namespace) the restored 'inner_dev' should be bound to. @@ -489,14 +490,14 @@ The 'mode' may be one of the following: *--tcp-close*:: Restore connected TCP sockets in closed state. -*--veth-pair* 'IN'*=*'OUT':: +*--veth-pair* __IN__**=**__OUT__:: Correspondence between outside and inside names of veth devices. *-l*, *--file-locks*:: Restore file locks from the image. -*--lsm-profile* 'type'*:*'name':: - Specify an LSM profile to be used during restore. The `type` can be +*--lsm-profile* __type__**:**__name__:: + Specify an LSM profile to be used during restore. The _type_ can be either *apparmor* or *selinux*. *--auto-dedup*:: From 56258da17619883631d0d3c96ad583bc697f953e Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Sun, 2 Feb 2020 18:45:59 +0000 Subject: [PATCH 2299/4375] criu: fix build failure against gcc-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On gcc-10 (and gcc-9 -fno-common) build fails as: ``` ld: criu/arch/x86/crtools.o:criu/include/cr_options.h:159: multiple definition of `rpc_cfg_file'; criu/arch/x86/cpu.o:criu/include/cr_options.h:159: first defined here make[2]: *** [scripts/nmk/scripts/build.mk:164: criu/arch/x86/crtools.built-in.o] Error 1 ``` gcc-10 will change the default from -fcommon to fno-common: https://gcc.gnu.org/PR85678. The error also happens if CFLAGS=-fno-common passed explicitly. Reported-by: Toralf Förster Bug: https://bugs.gentoo.org/707942 Signed-off-by: Sergei Trofimovich --- criu/config.c | 1 + criu/include/cr_options.h | 2 +- criu/include/pstree.h | 2 +- criu/include/tun.h | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/criu/config.c b/criu/config.c index 73c62f5bb..b84b7da28 100644 --- a/criu/config.c +++ b/criu/config.c @@ -30,6 +30,7 @@ #include "common/xmalloc.h" struct cr_options opts; +char *rpc_cfg_file; static int count_elements(char **to_count) { diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index c5af33186..ba405182e 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -155,7 +155,7 @@ struct cr_options { }; extern struct cr_options opts; -char *rpc_cfg_file; +extern char *rpc_cfg_file; extern int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd, int state); extern int check_options(void); diff --git a/criu/include/pstree.h b/criu/include/pstree.h index 7303c1fed..61ab0ce0e 100644 --- a/criu/include/pstree.h +++ b/criu/include/pstree.h @@ -42,7 +42,7 @@ enum { }; #define FDS_EVENT (1 << FDS_EVENT_BIT) -struct pstree_item *current; +extern struct pstree_item *current; struct rst_info; /* See alloc_pstree_item() for details */ diff --git a/criu/include/tun.h b/criu/include/tun.h index ce0b266a6..b82c445a7 100644 --- a/criu/include/tun.h +++ b/criu/include/tun.h @@ -5,7 +5,7 @@ #define TUN_MINOR 200 #endif -struct ns_id *ns; +extern struct ns_id *ns; #include From f1714ccce714093170a2616474cfc7b33298c75e Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 4 Feb 2020 23:12:22 -0800 Subject: [PATCH 2300/4375] test/vdso: check the code path when here is no API to map vDSO Signed-off-by: Andrei Vagin --- criu/crtools.c | 3 +++ criu/include/fault-injection.h | 1 + test/jenkins/criu-fault.sh | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/criu/crtools.c b/criu/crtools.c index 9b6e94809..3cd40e87d 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -176,6 +176,9 @@ int main(int argc, char *argv[], char *envp[]) if (kerndat_init()) return 1; + if (fault_injected(FI_CANNOT_MAP_VDSO)) + kdat.can_map_vdso = 0; + if (opts.deprecated_ok) pr_debug("DEPRECATED ON\n"); diff --git a/criu/include/fault-injection.h b/criu/include/fault-injection.h index 852d27166..31fe16178 100644 --- a/criu/include/fault-injection.h +++ b/criu/include/fault-injection.h @@ -17,6 +17,7 @@ enum faults { FI_NO_BREAKPOINTS = 130, FI_PARTIAL_PAGES = 131, FI_HUGE_ANON_SHMEM_ID = 132, + FI_CANNOT_MAP_VDSO = 133, FI_MAX, }; diff --git a/test/jenkins/criu-fault.sh b/test/jenkins/criu-fault.sh index ec6d26f89..4e3790e59 100755 --- a/test/jenkins/criu-fault.sh +++ b/test/jenkins/criu-fault.sh @@ -12,6 +12,10 @@ prep ./test/zdtm.py run -t zdtm/static/vdso01 --fault 127 || fail ./test/zdtm.py run -t zdtm/static/vdso-proxy --fault 127 --iters 3 || fail +if [ "${COMPAT_TEST}" != "y" ] ; then + ./test/zdtm.py run -t zdtm/static/vdso01 --fault 133 -f h || fail +fi + ./test/zdtm.py run -t zdtm/static/mntns_ghost --fault 2 --keep-going --report report || fail ./test/zdtm.py run -t zdtm/static/mntns_ghost --fault 4 --keep-going --report report || fail @@ -23,3 +27,4 @@ prep ./test/zdtm.py run -t zdtm/static/maps04 --fault 131 --keep-going --report report --pre 2:1 || fail ./test/zdtm.py run -t zdtm/transition/maps008 --fault 131 --keep-going --report report --pre 2:1 || fail ./test/zdtm.py run -t zdtm/static/maps01 --fault 132 -f h || fail + From 9bc9366c94d2c81f706d56d0227bf32a2425eef1 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 4 Feb 2020 23:13:43 -0800 Subject: [PATCH 2301/4375] vdso: use correct offsets to remap vdso and vvar mappings In the current version, the offsets of remapping vvar and vdso regions are mixed up. If vdso is before vvar, vvar has to be mapped with the vdso_size offset. if vvar is before vdso, vdso has to be mapped with the vvar_size offset. Signed-off-by: Andrei Vagin --- criu/pie/parasite-vdso.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 38da76680..3a1684d35 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -119,9 +119,9 @@ int vdso_do_park(struct vdso_maps *rt, unsigned long addr, unsigned long space) BUG_ON((vdso_size + vvar_size) < space); if (rt->sym.vdso_before_vvar) - return park_at(rt, addr, addr + vvar_size); + return park_at(rt, addr, addr + vdso_size); else - return park_at(rt, addr + vdso_size, addr); + return park_at(rt, addr + vvar_size, addr); } #ifndef CONFIG_COMPAT From 0f438ceeed27f3473a9ebda6c9e15d593ceeebde Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 5 Feb 2020 22:33:02 +0000 Subject: [PATCH 2302/4375] typo: fix missing space in error message Signed-off-by: Nicolas Viennot --- criu/sk-unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index f43aa2124..048ff44ae 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1877,7 +1877,7 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd) !(opts.ext_unix_sk)) { pr_err("External socket found in image. " "Consider using the --" USK_EXT_PARAM - "option to allow restoring it.\n"); + " option to allow restoring it.\n"); return -1; } From 72ff29070816e57b408f0bd6b8f71ff50c2e9cd4 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 6 Feb 2020 18:01:00 +0000 Subject: [PATCH 2303/4375] criu: Make use strlcpy() to copy into allocated strings strncpy() with n == strlen(src) won't put NULL-terminator in dst. Signed-off-by: Dmitry Safonov --- criu/cr-restore.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index b4f8d9e75..c1dfc44f1 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -75,6 +75,7 @@ #include "sk-queue.h" #include "sigframe.h" #include "fdstore.h" +#include "string.h" #include "parasite-syscall.h" #include "files-reg.h" @@ -3142,7 +3143,7 @@ rst_prep_creds_args(CredsEntry *ce, unsigned long *prev_pos) args = rst_mem_remap_ptr(this_pos, RM_PRIVATE); args->lsm_profile = lsm_profile; - strncpy(args->lsm_profile, rendered, lsm_profile_len); + strlcpy(args->lsm_profile, rendered, lsm_profile_len + 1); xfree(rendered); } } else { @@ -3176,7 +3177,7 @@ rst_prep_creds_args(CredsEntry *ce, unsigned long *prev_pos) args = rst_mem_remap_ptr(this_pos, RM_PRIVATE); args->lsm_sockcreate = lsm_sockcreate; - strncpy(args->lsm_sockcreate, rendered, lsm_sockcreate_len); + strlcpy(args->lsm_sockcreate, rendered, lsm_sockcreate_len + 1); xfree(rendered); } } else { From 99346a28247a3abeae094008fefa2edbc78fbb4d Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 24 Jan 2020 11:55:00 +0000 Subject: [PATCH 2304/4375] zdtm: Make test_{doc,author} weak variables Allows to override them in every test, optionally. Signed-off-by: Dmitry Safonov --- test/zdtm/lib/parseargs.c | 4 ++-- test/zdtm/lib/zdtmtst.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/test/zdtm/lib/parseargs.c b/test/zdtm/lib/parseargs.c index 7e411f6b6..d8aa4ed63 100644 --- a/test/zdtm/lib/parseargs.c +++ b/test/zdtm/lib/parseargs.c @@ -113,8 +113,8 @@ static void helpexit(void) exit(1); } -const char *test_doc; -const char *test_author; +const char __attribute__((weak)) *test_doc; +const char __attribute__((weak)) *test_author; static void prdoc(void) { diff --git a/test/zdtm/lib/zdtmtst.h b/test/zdtm/lib/zdtmtst.h index 1fbf795bf..2cd4bdd1d 100644 --- a/test/zdtm/lib/zdtmtst.h +++ b/test/zdtm/lib/zdtmtst.h @@ -155,6 +155,9 @@ struct zdtm_tcp_opts { int flags; }; +extern const char *test_author; +extern const char *test_doc; + extern int tcp_init_server_with_opts(int family, int *port, struct zdtm_tcp_opts *opts); extern pid_t sys_clone_unified(unsigned long flags, void *child_stack, void *parent_tid, void *child_tid, unsigned long newtls); From 0022c28468714a5329fd41ec12d744340b250cd4 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 21 Jan 2020 12:31:00 +0000 Subject: [PATCH 2305/4375] vdso: Add vdso_is_present() helper Use it in kerndat to check if the kernel provides vDSO. Signed-off-by: Dmitry Safonov --- criu/include/util-vdso.h | 5 +++++ criu/vdso.c | 10 ++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/criu/include/util-vdso.h b/criu/include/util-vdso.h index 33b7411de..046cd96d7 100644 --- a/criu/include/util-vdso.h +++ b/criu/include/util-vdso.h @@ -41,6 +41,11 @@ struct vdso_maps { bool compatible; }; +static inline bool vdso_is_present(struct vdso_maps *m) +{ + return m->vdso_start != VDSO_BAD_ADDR; +} + #define VDSO_SYMBOL_INIT { .offset = VDSO_BAD_ADDR, } #define VDSO_SYMTABLE_INIT \ diff --git a/criu/vdso.c b/criu/vdso.c index 50b8b8dba..b8df2d7a6 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -611,6 +611,12 @@ int kerndat_vdso_fill_symtable(void) return -1; } + if (!vdso_is_present(&vdso_maps)) { + pr_debug("Kernel doesn't premap vDSO - probably CONFIG_VDSO is not set\n"); + kdat.vdso_sym = vdso_maps.sym; + return 0; + } + if (vdso_fill_self_symtable(&vdso_maps)) { pr_err("Failed to fill self vdso symtable\n"); return -1; @@ -643,7 +649,7 @@ int kerndat_vdso_preserves_hint(void) kdat.vdso_hint_reliable = 0; - if (vdso_maps.vdso_start == VDSO_BAD_ADDR) + if (!vdso_is_present(&vdso_maps)) return 0; child = fork(); @@ -693,7 +699,7 @@ int kerndat_vdso_preserves_hint(void) goto out_kill; } - if (vdso_maps_after.vdso_start != VDSO_BAD_ADDR) + if (vdso_is_present(&vdso_maps_after)) kdat.vdso_hint_reliable = 1; ret = 0; From a96a7ed87fece0eeb397b9dd4901f680fbf2b4f6 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 22 Jan 2020 14:00:27 +0000 Subject: [PATCH 2306/4375] vdso: Repair !CONFIG_VDSO Apparently, C/R is broken when CONFIG_VDSO is not set. Probably, I've broken it while adding arm vdso support. Or maybe some commits after. Repair it by adding checks into vdso_init_dump(), vdso_init_restore(). Also, don't try handling vDSO in restorer if it wasn't present in parent. And prevent summing VDSO_BAD_SIZE to {vdso,vvar}_rt_size. Reported-by: Adrian Reber Signed-off-by: Dmitry Safonov --- criu/cr-restore.c | 9 +++++--- criu/pie/parasite-vdso.c | 12 ++++++++++ criu/pie/restorer.c | 2 +- criu/vdso.c | 48 ++++++++++++++++++++++++++-------------- 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index c1dfc44f1..03dbc850f 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3373,10 +3373,13 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns vdso_maps_rt = vdso_maps; /* * Figure out how much memory runtime vdso and vvar will need. + * Check if vDSO or VVAR is not provided by kernel. */ - vdso_rt_size = vdso_maps_rt.sym.vdso_size; - if (vdso_rt_size && vdso_maps_rt.sym.vvar_size) - vdso_rt_size += ALIGN(vdso_maps_rt.sym.vvar_size, PAGE_SIZE); + if (vdso_maps_rt.sym.vdso_size != VDSO_BAD_SIZE) { + vdso_rt_size = vdso_maps_rt.sym.vdso_size; + if (vdso_maps_rt.sym.vvar_size != VVAR_BAD_SIZE) + vdso_rt_size += ALIGN(vdso_maps_rt.sym.vvar_size, PAGE_SIZE); + } task_args->bootstrap_len += vdso_rt_size; /* diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 3a1684d35..3f5cb1431 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -292,6 +292,18 @@ int vdso_proxify(struct vdso_maps *rt, bool *added_proxy, return -1; } + /* + * We could still do something about it here.. + * 1. Hope that vDSO from images still works (might not be the case). + * 2. Try to map vDSO. + * But, hopefully no one intends to migrate application that uses + * vDSO to a dut where kernel doesn't provide it. + */ + if (!vdso_is_present(rt)) { + pr_err("vDSO isn't provided by kernel, but exists in images\n"); + return -1; + } + /* * vDSO mark overwrites Elf program header of proxy vDSO thus * it must never ever be greater in size. diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 7012b88a1..afe185f04 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1454,7 +1454,7 @@ long __export_restore_task(struct task_restore_args *args) * it's presence in original task: vdso will be used for fast * getttimeofday() in restorer's log timings. */ - if (!args->can_map_vdso) { + if (!args->can_map_vdso && vdso_is_present(&args->vdso_maps_rt)) { /* It's already checked in kdat, but let's check again */ if (args->compatible_mode) { pr_err("Compatible mode without vdso map support\n"); diff --git a/criu/vdso.c b/criu/vdso.c index b8df2d7a6..19ba4765d 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -275,6 +275,10 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct vma_area *vma; int fd = -1; + /* vDSO is not provided by kernel */ + if (kdat.vdso_sym.vdso_size == VDSO_BAD_SIZE) + return 0; + vcheck = get_vdso_check_type(ctl); if (vcheck == VDSO_CHECK_PFN) { BUG_ON(vdso_pfn == VDSO_BAD_PFN); @@ -534,21 +538,6 @@ out_unmap: } #endif /* CONFIG_COMPAT */ -int vdso_init_dump(void) -{ - if (vdso_parse_maps(PROC_SELF, &vdso_maps)) { - pr_err("Failed reading self/maps for filling vdso/vvar bounds\n"); - return -1; - } - - if (kdat.pmap != PM_FULL) - pr_info("VDSO detection turned off\n"); - else if (vaddr_to_pfn(-1, vdso_maps.vdso_start, &vdso_pfn)) - return -1; - - return 0; -} - /* * Check vdso/vvar sized read from maps to kdat values. * We do not read /proc/self/maps for compatible vdso as it's @@ -566,11 +555,36 @@ static int is_kdat_vdso_sym_valid(void) return true; } +int vdso_init_dump(void) +{ + if (vdso_parse_maps(PROC_SELF, &vdso_maps)) { + pr_err("Failed reading self/maps for filling vdso/vvar bounds\n"); + return -1; + } + + if (!is_kdat_vdso_sym_valid()) { + pr_err("Kdat sizes of vdso/vvar differ to maps file \n"); + return -1; + } + + if (kdat.vdso_sym.vdso_size == VDSO_BAD_SIZE) { + pr_debug("Kdat has empty vdso symtable - probably CONFIG_VDSO is not set\n"); + return 0; + } + + if (kdat.pmap != PM_FULL) + pr_info("VDSO detection turned off\n"); + else if (vaddr_to_pfn(-1, vdso_maps.vdso_start, &vdso_pfn)) + return -1; + + return 0; +} + int vdso_init_restore(void) { if (kdat.vdso_sym.vdso_size == VDSO_BAD_SIZE) { - pr_err("Kdat has empty vdso symtable\n"); - return -1; + pr_debug("Kdat has empty vdso symtable - probably CONFIG_VDSO is not set\n"); + return 0; } /* Already filled vdso_maps during kdat test */ From 9cb4067e132ba48eb36b0b8075043b13e96e8974 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 22 Jan 2020 14:05:47 +0000 Subject: [PATCH 2307/4375] vdso: Don't page-align vvar It's always page-aligned (as any VMA). Signed-off-by: Dmitry Safonov --- criu/cr-restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 03dbc850f..e5e8fc9c5 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3378,7 +3378,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns if (vdso_maps_rt.sym.vdso_size != VDSO_BAD_SIZE) { vdso_rt_size = vdso_maps_rt.sym.vdso_size; if (vdso_maps_rt.sym.vvar_size != VVAR_BAD_SIZE) - vdso_rt_size += ALIGN(vdso_maps_rt.sym.vvar_size, PAGE_SIZE); + vdso_rt_size += vdso_maps_rt.sym.vvar_size; } task_args->bootstrap_len += vdso_rt_size; From 3a4c33c502b8ed685d1ffe81b15d11159d43848a Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sat, 18 Jan 2020 14:28:03 +0000 Subject: [PATCH 2308/4375] zdtm: mntns_rw_ro_rw update error msg Signed-off-by: Radostin Stoyanov --- test/zdtm/static/mntns_rw_ro_rw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/zdtm/static/mntns_rw_ro_rw.c b/test/zdtm/static/mntns_rw_ro_rw.c index 7aed254b6..6179c4788 100644 --- a/test/zdtm/static/mntns_rw_ro_rw.c +++ b/test/zdtm/static/mntns_rw_ro_rw.c @@ -31,12 +31,12 @@ int main(int argc, char **argv) test_waitsig(); if (access("/proc/sys/net/ipv4/ip_forward", W_OK)) { - fail("Unable to access /proc/sys/net/core/wmem_max"); + fail("Unable to access /proc/sys/net/ipv4/ip_forward"); return 1; } if (access("/proc/sys/kernel/ns_last_pid", W_OK) != -1 || errno != EROFS) { - fail("Unable to access /proc/sys/kernel/pid_max"); + fail("Unable to access /proc/sys/kernel/ns_last_pid"); return 1; } From f5181b2767d03f17e72dd6f70c83ce394b750e68 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Sat, 8 Feb 2020 19:43:39 +0100 Subject: [PATCH 2309/4375] Travis: fix podman test case Podman changed the output of 'podman ps'. For the test only running containers are interesting. Adding the filter '-f status=running' only returns running containers as previously. Signed-off-by: Adrian Reber --- scripts/travis/podman-test.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/travis/podman-test.sh b/scripts/travis/podman-test.sh index 825bca746..7490d5fe9 100755 --- a/scripts/travis/podman-test.sh +++ b/scripts/travis/podman-test.sh @@ -39,12 +39,12 @@ for i in `seq 20`; do echo "Test $i for podman container checkpoint" podman exec cr ps axf podman logs cr - [ `podman ps -f name=cr -q | wc -l` -eq "1" ] + [ `podman ps -f name=cr -q -f status=running | wc -l` -eq "1" ] podman container checkpoint cr - [ `podman ps -f name=cr -q | wc -l` -eq "0" ] + [ `podman ps -f name=cr -q -f status=running | wc -l` -eq "0" ] podman ps -a podman container restore cr - [ `podman ps -f name=cr -q | wc -l` -eq "1" ] + [ `podman ps -f name=cr -q -f status=running | wc -l` -eq "1" ] podman logs cr done @@ -53,16 +53,16 @@ for i in `seq 20`; do podman ps -a podman exec cr ps axf podman logs cr - [ `podman ps -f name=cr -q | wc -l` -eq "1" ] + [ `podman ps -f name=cr -q -f status=running | wc -l` -eq "1" ] podman container checkpoint -l --export /tmp/chkpt.tar.gz - [ `podman ps -f name=cr -q | wc -l` -eq "0" ] + [ `podman ps -f name=cr -q -f status=running | wc -l` -eq "0" ] podman ps -a podman rm -fa podman ps -a podman container restore --import /tmp/chkpt.tar.gz - [ `podman ps -f name=cr -q | wc -l` -eq "1" ] + [ `podman ps -f name=cr -q -f status=running | wc -l` -eq "1" ] podman container restore --name cr2 --import /tmp/chkpt.tar.gz - [ `podman ps -f name=cr2 -q | wc -l` -eq "1" ] + [ `podman ps -f name=cr2 -q -f status=running | wc -l` -eq "1" ] podman ps -a podman logs cr podman logs cr2 @@ -70,7 +70,7 @@ for i in `seq 20`; do podman rm -fa podman ps -a podman container restore --import /tmp/chkpt.tar.gz - [ `podman ps -f name=cr -q | wc -l` -eq "1" ] + [ `podman ps -f name=cr -q -f status=running | wc -l` -eq "1" ] podman ps -a rm -f /tmp/chkpt.tar.gz done From d68a68b8f478e12bd457eccfbf8e49b50ca95e86 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 6 Feb 2020 20:46:17 -0800 Subject: [PATCH 2310/4375] test/zdtm/inhfd: update dump options one each iteration This allows to run inhfd tests with many iterations of C/R. Signed-off-by: Andrei Vagin --- test/zdtm.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/zdtm.py b/test/zdtm.py index 16ff0b379..47c89a162 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -757,6 +757,11 @@ class inhfd_test: fcntl.fcntl(fd, fcntl.F_SETFD, fdflags) peer_file_name = self.__peer_file_names[i] ropts.extend(["--inherit-fd", "fd[%d]:%s" % (fd, peer_file_name)]) + self.__peer_file_names = [] + self.__dump_opts = [] + for _, peer_file in self.__files: + self.__peer_file_names.append(self.__fdtyp.filename(peer_file)) + self.__dump_opts += self.__fdtyp.dump_opts(peer_file) return ropts def print_output(self): From ff756cbb28c4ee10651ed80f38b8ef37ee74fc39 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 6 Feb 2020 21:20:20 -0800 Subject: [PATCH 2311/4375] python: sort imports 202 Additional newline in a group of imports. I100 Import statements are in the wrong order. Signed-off-by: Andrei Vagin --- lib/py/images/pb2dict.py | 13 ++++++------ test/inhfd/socket.py | 2 +- test/others/rpc/config_file.py | 7 ++++--- test/zdtm.py | 38 ++++++++++++++++++---------------- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index 6fce4be22..a89850a1d 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -1,12 +1,13 @@ -from google.protobuf.descriptor import FieldDescriptor as FD -import opts_pb2 -from ipaddress import IPv4Address, ip_address -from ipaddress import IPv6Address -import socket +import base64 import collections import os -import base64 import quopri +import socket +from ipaddress import IPv4Address, IPv6Address, ip_address + +from google.protobuf.descriptor import FieldDescriptor as FD + +import opts_pb2 if "encodebytes" not in dir(base64): base64.encodebytes = base64.encodestring diff --git a/test/inhfd/socket.py b/test/inhfd/socket.py index 9cea16ffb..7efe7faab 100755 --- a/test/inhfd/socket.py +++ b/test/inhfd/socket.py @@ -1,5 +1,5 @@ -import socket import os +import socket def create_fds(): diff --git a/test/others/rpc/config_file.py b/test/others/rpc/config_file.py index 7b07bc145..90c80fcae 100755 --- a/test/others/rpc/config_file.py +++ b/test/others/rpc/config_file.py @@ -1,11 +1,12 @@ #!/usr/bin/python +import argparse import os import sys -import rpc_pb2 as rpc -import argparse -from tempfile import mkstemp import time +from tempfile import mkstemp + +import rpc_pb2 as rpc from setup_swrk import setup_swrk diff --git a/test/zdtm.py b/test/zdtm.py index 47c89a162..3fc57ba55 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1,31 +1,33 @@ #!/usr/bin/env python # vim: noet ts=8 sw=8 sts=8 from __future__ import absolute_import, division, print_function, unicode_literals -from builtins import (str, open, range, zip, int, input) import argparse -import glob -import os -import subprocess -import time -import tempfile -import shutil -import re -import stat -import signal import atexit -import sys -import linecache -import random -import string -import fcntl -import errno import datetime -import yaml -import struct +import errno +import fcntl +import glob +import linecache import mmap +import os +import random +import re +import shutil +import signal +import stat +import string +import struct +import subprocess +import sys +import tempfile +import time +from builtins import (input, int, open, range, str, zip) + import pycriu as crpc +import yaml + os.chdir(os.path.dirname(os.path.abspath(__file__))) prev_line = None From 872b795a5678d82a415419e139d680cbf81391ff Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 21 Feb 2020 18:48:41 +0300 Subject: [PATCH 2312/4375] Maintainers: Suggest the maintainers codex (#932) The guide is based on the one from the RunC project, but has some criu-related specifics. Signed-off-by: Pavel Emelyanov --- MAINTAINERS | 2 + MAINTAINERS_GUIDE.md | 136 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 MAINTAINERS create mode 100644 MAINTAINERS_GUIDE.md diff --git a/MAINTAINERS b/MAINTAINERS new file mode 100644 index 000000000..fbd5d03e8 --- /dev/null +++ b/MAINTAINERS @@ -0,0 +1,2 @@ +Pavel Emelyanov (chief) +Andrey Vagin diff --git a/MAINTAINERS_GUIDE.md b/MAINTAINERS_GUIDE.md new file mode 100644 index 000000000..2830a3caa --- /dev/null +++ b/MAINTAINERS_GUIDE.md @@ -0,0 +1,136 @@ +## Introduction + +Dear maintainer. Thank you for investing the time and energy to help +make CRIU as useful as possible. Maintaining a project is difficult, +sometimes unrewarding work. Sure, you will contribute cool features +to the project, but most of your time will be spent reviewing patches, +cleaning things up, documenting, answering questions, justifying design +decisions - while everyone else will just have fun! But remember -- the +quality of the maintainers work is what distinguishes the good projects +from the great. So please be proud of your work, even the unglamorous +parts, and encourage a culture of appreciation and respect for *every* +aspect of improving the project -- not just the hot new features. + +Being a maintainer is a time consuming commitment and should not be +taken lightly. This document is a manual for maintainers old and new. +It explains what is expected of maintainers, how they should work, and +what tools are available to them. + +This is a living document - if you see something out of date or missing, +speak up! + +## What are a maintainer's responsibility? + +Part of a healthy project is to have active maintainers to support the +community in contributions and perform tasks to keep the project running. +It is every maintainer's responsibility to: + + * Keep the community a friendly place + * Deliver prompt feedback and decisions on pull requests and mailing + list threads + * Encourage other members to help each other, especially in cases the + maintainer is overloaded or feels the lack of needed expertise + * Make sure the changes made respects the philosophy, design and + roadmap of the project + +## How are decisions made? + +CRIU is an open-source project with an open design philosophy. This +means that the repository is the source of truth for EVERY aspect of the +project. *If it's part of the project, it's in the repo. It's in the +repo, it's part of the project.* + +All decisions affecting CRIU, big and small, follow the same 3 steps: + + * Submit a change. Anyone can do this + + * Discuss it. Anyone can and is encouraged to do this + + * Accept or decline it. Only maintainers do this + +*I'm a maintainer, should I make pull requests / send patches too?* + +Yes. Nobody should ever push to the repository directly. All changes +should be made through submitting (and accepting) the change. + +### Two-steps decision making ### + +Since CRIU is extremely complex piece of software we try double hard +not to make mistakes, that would be hard to fix in the future. In order +to facilitate this, the "final" decision is made in two stages: + + * We definitely want to try something out + + * We think that the attempt was successful + +Respectively, new features get accepted first into the *criu-dev* branch and +after they have been validated they are merged into the *master* branch. Yet, +urgent bug fixes may land directly in the master branch. If a change in +the criu-dev branch is considered to be bad (whatever it means), then it +can be reverted without propagation to the master branch. Reverting from +the master branch is expected not to happen at all, but if such an +extraordinary case occurs, the impact of this step, especially the question +of backward compatibility, should be considered in the most careful manner. + +## Who decides what? + +All decisions can be expressed as changes to the repository (either in the +form of pull requests, or patches sent to the mailing list), and maintainers +make decisions by merging or rejecting them. Review and approval or +disagreement can be done by anyone and is denoted by adding a respective +comment in the pull request. However, merging the change into either branch +only happens after approvals from maintainers. + +In order for a patch to be merged into the criu-dev branch at least two +maintainers should accept it. In order for a patch to be merged into the +master branch the majority of maintainers should decide that (then prepare +a pull request, submit it, etc.). + +Overall the maintainer system works because of mutual respect across the +maintainers of the project. The maintainers trust one another to make +decisions in the best interests of the project. Sometimes maintainers +can disagree and this is part of a healthy project to represent the point +of views of various people. In the case where maintainers cannot find +agreement on a specific change the role of a Chief Maintainer comes into +play. + +### Chief maintainer + +The chief maintainer for the project is responsible for overall architecture +of the project to maintain conceptual integrity. Large decisions and +architecture changes should be reviewed by the chief maintainer. + +Also the chief maintainer has the veto power on any change submitted +to any branch. Naturally, a change in the criu-dev branch can be reverted +after a chief maintainer veto, a change in the master branch must be +carefully reviwed by the chief maintainer and vetoed in advance. + +### How are maintainers added (and removed)? + +The best maintainers have a vested interest in the project. Maintainers +are first and foremost contributors that have shown they are committed to +the long term success of the project. Contributors wanting to become +maintainers are expected to be deeply involved in contributing code, +patches review, and paying needed attention to the issues in the project. +Just contributing does not make you a maintainer, it is about building trust +with the current maintainers of the project and being a person that they can +rely on and trust to make decisions in the best interest of the project. + +When a contributor wants to become a maintainer or nominate someone as a +maintainer, one can submit a "nomination", which technically is the +respective modification to the `MAINTAINERS` file. When a maintainer feels +they is unable to perform the required duties, or someone else wants to draw +the community attention to this fact, one can submit a "(self-)removing" +change. + +The final vote to add or to remove a maintainer is to be approved by the +majority of current maintainers (with the chief maintainer having veto power +on that too). + +One might have noticed, that the chief maintainer (re-)assignment is not +regulated by this document. That's true :) However, this can be done. If +the community decides that the chief maintainer needs to be changed the +respective "decision making rules" are to be prepared, submitted and +accepted into this file first. + +Good luck! From 42db2c1563544fc4307c95b8cc2cba8ddfc51262 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 26 Feb 2020 20:35:12 +0200 Subject: [PATCH 2313/4375] MAINTAINERS: add Mike Signed-off-by: Mike Rapoport --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index fbd5d03e8..ed5bf25c1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1,2 +1,3 @@ Pavel Emelyanov (chief) Andrey Vagin +Mike Rapoport From e19f4cf3b120b91384cdd87fb138a319857f8d8b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 3 Mar 2020 11:46:08 -0800 Subject: [PATCH 2314/4375] MAINTAINERS: Add Dima and Adrian to maintainers Signed-off-by: Andrei Vagin --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ed5bf25c1..5c28463a7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1,3 +1,5 @@ Pavel Emelyanov (chief) Andrey Vagin Mike Rapoport +Dmitry Safonov <0x7f454c46@gmail.com> +Adrian Reber From 5dbc24b206cd365db7498dddcd03798c5d8ed4e4 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 25 Nov 2019 09:50:08 +0300 Subject: [PATCH 2315/4375] util: introduce the mount_detached_fs helper Signed-off-by: Andrei Vagin --- criu/util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/util.c b/criu/util.c index 1646ce1c4..a0a49c5a3 100644 --- a/criu/util.c +++ b/criu/util.c @@ -30,6 +30,8 @@ #include "linux/mount.h" +#include "linux/mount.h" + #include "kerndat.h" #include "page.h" #include "util.h" From c1e72aa936bd86fb4cd819e84791e8a9a5c4d572 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 18 Dec 2019 23:32:32 +0000 Subject: [PATCH 2316/4375] memfd: add file support See "man memfd_create" for more information of what memfd is. This adds support for memfd open files, that are not not memory mapped. * We add a new kind of file: MEMFD. * We add two image types MEMFD_FILE, and MEMFD_INODE. MEMFD_FILE contains usual file information (e.g., position). MEMFD_INODE contains the memfd name, and a shmid identifier referring to the content. * We reuse the shmem facilities for dumping memfd content as it would be easier to support incremental checkpoints in the future. Signed-off-by: Nicolas Viennot --- Makefile.config | 2 +- criu/Makefile.crtools | 1 + criu/cr-restore.c | 2 + criu/files.c | 18 +- criu/image-desc.c | 1 + criu/include/image-desc.h | 2 + criu/include/magic.h | 1 + criu/include/memfd.h | 24 +++ criu/include/protobuf-desc.h | 2 + criu/include/shmem.h | 3 + criu/kerndat.c | 3 +- criu/memfd.c | 350 +++++++++++++++++++++++++++++++++++ criu/shmem.c | 66 ++++++- images/Makefile | 1 + images/fdinfo.proto | 3 + images/memfd.proto | 20 ++ lib/py/images/images.py | 2 + scripts/feature-tests.mak | 11 ++ 18 files changed, 503 insertions(+), 9 deletions(-) create mode 100644 criu/include/memfd.h create mode 100644 criu/memfd.c create mode 100644 images/memfd.proto diff --git a/Makefile.config b/Makefile.config index 161365960..98ba5d892 100644 --- a/Makefile.config +++ b/Makefile.config @@ -64,7 +64,7 @@ export DEFINES += $(FEATURE_DEFINES) export CFLAGS += $(FEATURE_DEFINES) FEATURES_LIST := TCP_REPAIR STRLCPY STRLCAT PTRACE_PEEKSIGINFO \ - SETPROCTITLE_INIT MEMFD TCP_REPAIR_WINDOW FSCONFIG + SETPROCTITLE_INIT MEMFD TCP_REPAIR_WINDOW FSCONFIG MEMFD_CREATE # $1 - config name define gen-feature-test diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 4588ea5b8..1a6e0b5b5 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -37,6 +37,7 @@ obj-y += libnetlink.o obj-y += log.o obj-y += lsm.o obj-y += mem.o +obj-y += memfd.o obj-y += mount.o obj-y += filesystems.o obj-y += namespaces.o diff --git a/criu/cr-restore.c b/criu/cr-restore.c index e5e8fc9c5..13d1001c9 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -76,6 +76,7 @@ #include "sigframe.h" #include "fdstore.h" #include "string.h" +#include "memfd.h" #include "parasite-syscall.h" #include "files-reg.h" @@ -289,6 +290,7 @@ static struct collect_image_info *cinfos_files[] = { &fanotify_cinfo, &fanotify_mark_cinfo, &ext_file_cinfo, + &memfd_cinfo, }; /* These images are required to restore namespaces */ diff --git a/criu/files.c b/criu/files.c index e26897870..ea86deaa3 100644 --- a/criu/files.c +++ b/criu/files.c @@ -34,6 +34,7 @@ #include "sk-packet.h" #include "mount.h" #include "signalfd.h" +#include "memfd.h" #include "namespaces.h" #include "tun.h" #include "timerfd.h" @@ -546,13 +547,17 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, return -1; p.link = &link; - if (link.name[1] == '/') - return do_dump_gen_file(&p, lfd, ®file_dump_ops, e); - if (check_ns_proc(&link)) - return do_dump_gen_file(&p, lfd, &nsfile_dump_ops, e); + if (is_memfd(p.stat.st_dev, &link.name[1])) + ops = &memfd_dump_ops; + else if (link.name[1] == '/') + ops = ®file_dump_ops; + else if (check_ns_proc(&link)) + ops = &nsfile_dump_ops; + else + return dump_unsupp_fd(&p, lfd, "reg", link.name + 1, e); - return dump_unsupp_fd(&p, lfd, "reg", link.name + 1, e); + return do_dump_gen_file(&p, lfd, ops, e); } if (S_ISFIFO(p.stat.st_mode)) { @@ -1721,6 +1726,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i) case FD_TYPES__TTY: ret = collect_one_file_entry(fe, fe->tty->id, &fe->tty->base, &tty_cinfo); break; + case FD_TYPES__MEMFD: + ret = collect_one_file_entry(fe, fe->memfd->id, &fe->memfd->base, &memfd_cinfo); + break; } return ret; diff --git a/criu/image-desc.c b/criu/image-desc.c index ae5d817fe..b538a76ea 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -66,6 +66,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY(FS, "fs-%u"), FD_ENTRY(REMAP_FPATH, "remap-fpath"), FD_ENTRY_F(GHOST_FILE, "ghost-file-%x", O_NOBUF), + FD_ENTRY_F(MEMFD_INODE, "memfd-%u", O_NOBUF), FD_ENTRY(TCP_STREAM, "tcp-stream-%x"), FD_ENTRY(MNTS, "mountpoints-%u"), FD_ENTRY(NETDEV, "netdev-%u"), diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 6db8bf94f..9ca9643a1 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -106,6 +106,8 @@ enum { CR_FD_FIFO, CR_FD_PIPES, CR_FD_TTY_FILES, + CR_FD_MEMFD_FILE, + CR_FD_MEMFD_INODE, CR_FD_AUTOFS, diff --git a/criu/include/magic.h b/criu/include/magic.h index 1a583f4ed..bdaca968d 100644 --- a/criu/include/magic.h +++ b/criu/include/magic.h @@ -94,6 +94,7 @@ #define BINFMT_MISC_MAGIC 0x67343323 /* Apatity */ #define AUTOFS_MAGIC 0x49353943 /* Sochi */ #define FILES_MAGIC 0x56303138 /* Toropets */ +#define MEMFD_INODE_MAGIC 0x48453499 /* Dnipro */ #define IFADDR_MAGIC RAW_IMAGE_MAGIC #define ROUTE_MAGIC RAW_IMAGE_MAGIC diff --git a/criu/include/memfd.h b/criu/include/memfd.h new file mode 100644 index 000000000..c1d7949cb --- /dev/null +++ b/criu/include/memfd.h @@ -0,0 +1,24 @@ +#ifndef __CR_MEMFD_H__ +#define __CR_MEMFD_H__ + +#include +#include "int.h" +#include "common/config.h" + +extern int is_memfd(dev_t dev, const char *path); +extern const struct fdtype_ops memfd_dump_ops; + +extern struct collect_image_info memfd_cinfo; + +#ifdef CONFIG_HAS_MEMFD_CREATE +# include +#else +# include +# include +static inline int memfd_create(const char *name, unsigned int flags) +{ + return syscall(SYS_memfd_create, name, flags); +} +#endif /* CONFIG_HAS_MEMFD_CREATE */ + +#endif /* __CR_MEMFD_H__ */ diff --git a/criu/include/protobuf-desc.h b/criu/include/protobuf-desc.h index 31f5b9a79..7e0385ef4 100644 --- a/criu/include/protobuf-desc.h +++ b/criu/include/protobuf-desc.h @@ -61,6 +61,8 @@ enum { PB_AUTOFS, PB_GHOST_CHUNK, PB_FILE, + PB_MEMFD_FILE, + PB_MEMFD_INODE, /* 60 */ /* PB_AUTOGEN_STOP */ diff --git a/criu/include/shmem.h b/criu/include/shmem.h index 04ab8d076..9afdb799a 100644 --- a/criu/include/shmem.h +++ b/criu/include/shmem.h @@ -13,8 +13,11 @@ extern int collect_sysv_shmem(unsigned long shmid, unsigned long size); extern int cr_dump_shmem(void); extern int add_shmem_area(pid_t pid, VmaEntry *vma, u64 *map); extern int fixup_sysv_shmems(void); +extern int dump_one_memfd_shmem(int fd, unsigned long shmid, unsigned long size); extern int dump_one_sysv_shmem(void *addr, unsigned long size, unsigned long shmid); extern int restore_sysv_shmem_content(void *addr, unsigned long size, unsigned long shmid); +extern int restore_memfd_shmem_content(int fd, unsigned long shmid, unsigned long size); + #define SYSV_SHMEM_SKIP_FD (0x7fffffff) diff --git a/criu/kerndat.c b/criu/kerndat.c index e0b5731d5..8ac83820b 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -42,6 +42,7 @@ #include "vdso.h" #include "kcmp.h" #include "sched.h" +#include "memfd.h" struct kerndat_s kdat = { }; @@ -409,7 +410,7 @@ static bool kerndat_has_memfd_create(void) { int ret; - ret = syscall(SYS_memfd_create, NULL, 0); + ret = memfd_create(NULL, 0); if (ret == -1 && errno == ENOSYS) kdat.has_memfd = false; diff --git a/criu/memfd.c b/criu/memfd.c new file mode 100644 index 000000000..bcef35e75 --- /dev/null +++ b/criu/memfd.c @@ -0,0 +1,350 @@ +#include + +#include "common/compiler.h" +#include "common/lock.h" +#include "memfd.h" +#include "fdinfo.h" +#include "imgset.h" +#include "image.h" +#include "util.h" +#include "log.h" +#include "files.h" +#include "fs-magic.h" +#include "kerndat.h" +#include "files-reg.h" +#include "rst-malloc.h" +#include "fdstore.h" +#include "file-ids.h" +#include "namespaces.h" +#include "shmem.h" + +#include "protobuf.h" +#include "images/memfd.pb-c.h" + +#define MEMFD_PREFIX "/memfd:" +#define MEMFD_PREFIX_LEN (sizeof(MEMFD_PREFIX)-1) + +struct memfd_inode { + struct list_head list; + u32 id; + union { + /* Only for dump */ + struct { + u32 dev; + u32 ino; + }; + /* Only for restore */ + struct { + mutex_t lock; + int fdstore_id; + }; + }; +}; + +static LIST_HEAD(memfd_inodes); + +/* + * Dump only + */ + +static u32 memfd_inode_ids = 1; + +int is_memfd(dev_t dev, const char *path) +{ + /* + * TODO When MAP_HUGETLB is used, the file device is not shmem_dev, + * Note that other parts of CRIU have similar issues, see + * is_anon_shmem_map(). + */ + return dev == kdat.shmem_dev && + !strncmp(path, MEMFD_PREFIX, MEMFD_PREFIX_LEN); +} + +static int dump_memfd_inode(int fd, struct memfd_inode *inode, + const char *name, const struct stat *st) +{ + int ret = -1; + struct cr_img *img = NULL; + MemfdInodeEntry mie = MEMFD_INODE_ENTRY__INIT; + u32 shmid; + + /* + * shmids are chosen as the inode number of the corresponding mmaped + * file. See handle_vma() in proc_parse.c. + * It works for memfd too, because we share the same device as the + * shmem device. + */ + shmid = inode->ino; + + pr_info("Dumping memfd:%s contents (id %#x, shmid: %#x, size: %"PRIu64")\n", + name, inode->id, shmid, st->st_size); + + if (dump_one_memfd_shmem(fd, shmid, st->st_size) < 0) + goto out; + + img = open_image(CR_FD_MEMFD_INODE, O_DUMP, inode->id); + if (!img) + goto out; + + mie.uid = userns_uid(st->st_uid); + mie.gid = userns_gid(st->st_gid); + mie.name = (char *)name; + mie.size = st->st_size; + mie.shmid = shmid; + + if (pb_write_one(img, &mie, PB_MEMFD_INODE)) + goto out; + + ret = 0; + +out: + if (img) + close_image(img); + return ret; +} + +static struct memfd_inode *dump_unique_memfd_inode(int lfd, const char *name, const struct stat *st) +{ + struct memfd_inode *inode; + + list_for_each_entry(inode, &memfd_inodes, list) + if ((inode->dev == st->st_dev) && (inode->ino == st->st_ino)) + return inode; + + inode = xmalloc(sizeof(*inode)); + if (inode == NULL) + return NULL; + + inode->dev = st->st_dev; + inode->ino = st->st_ino; + inode->id = memfd_inode_ids++; + + if (dump_memfd_inode(lfd, inode, name, st)) { + xfree(inode); + return NULL; + } + + list_add_tail(&inode->list, &memfd_inodes); + + return inode; +} + +static int dump_one_memfd(int lfd, u32 id, const struct fd_parms *p) +{ + MemfdFileEntry mfe = MEMFD_FILE_ENTRY__INIT; + FileEntry fe = FILE_ENTRY__INIT; + struct memfd_inode *inode; + struct fd_link _link, *link; + const char *name; + + if (!p->link) { + if (fill_fdlink(lfd, p, &_link)) + return -1; + link = &_link; + } else + link = p->link; + + strip_deleted(link); + name = &link->name[1+MEMFD_PREFIX_LEN]; + + inode = dump_unique_memfd_inode(lfd, name, &p->stat); + if (!inode) + return -1; + + mfe.id = id; + mfe.flags = p->flags; + mfe.pos = p->pos; + mfe.fown = (FownEntry *)&p->fown; + mfe.inode_id = inode->id; + + fe.type = FD_TYPES__MEMFD; + fe.id = mfe.id; + fe.memfd = &mfe; + + return pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); +} + +const struct fdtype_ops memfd_dump_ops = { + .type = FD_TYPES__MEMFD, + .dump = dump_one_memfd, +}; + + +/* + * Restore only + */ + +struct memfd_info { + MemfdFileEntry *mfe; + struct file_desc d; + struct memfd_inode *inode; +}; + +static struct memfd_inode *memfd_alloc_inode(int id) +{ + struct memfd_inode *inode; + + list_for_each_entry(inode, &memfd_inodes, list) + if (inode->id == id) + return inode; + + inode = shmalloc(sizeof(*inode)); + if (!inode) + return NULL; + + inode->id = id; + mutex_init(&inode->lock); + inode->fdstore_id = -1; + + list_add_tail(&inode->list, &memfd_inodes); + return inode; +} + +extern int restore_memfd_shm(int fd, u64 id, u64 size); +static int memfd_open_inode_nocache(struct memfd_inode *inode) +{ + MemfdInodeEntry *mie = NULL; + struct cr_img *img = NULL; + int fd = -1; + int ret = -1; + int flags; + + img = open_image(CR_FD_MEMFD_INODE, O_RSTR, inode->id); + if (!img) + goto out; + + if (pb_read_one(img, &mie, PB_MEMFD_INODE) < 0) + goto out; + + fd = memfd_create(mie->name, 0); + if (fd < 0) { + pr_perror("Can't create memfd:%s", mie->name); + goto out; + } + + if (restore_memfd_shmem_content(fd, mie->shmid, mie->size)) + goto out; + + if (fchown(fd, mie->uid, mie->gid)) { + pr_perror("Can't change uid %d gid %d of memfd:%s", + (int)mie->uid, (int)mie->gid, mie->name); + goto out; + } + + inode->fdstore_id = fdstore_add(fd); + if (inode->fdstore_id < 0) + goto out; + + ret = fd; + fd = -1; + +out: + if (fd != -1) + close(fd); + if (img) + close_image(img); + if (mie) + memfd_inode_entry__free_unpacked(mie, NULL); + return ret; +} + +static int memfd_open_inode(struct memfd_inode *inode) +{ + int fd; + + if (inode->fdstore_id != -1) + return fdstore_get(inode->fdstore_id); + + mutex_lock(&inode->lock); + if (inode->fdstore_id != -1) + fd = fdstore_get(inode->fdstore_id); + else + fd = memfd_open_inode_nocache(inode); + mutex_unlock(&inode->lock); + + return fd; +} + +static int memfd_open(struct file_desc *d, u32 *fdflags) +{ + char lpath[PSFDS]; + struct memfd_info *mfi; + MemfdFileEntry *mfe; + int fd, _fd; + u32 flags; + + mfi = container_of(d, struct memfd_info, d); + mfe = mfi->mfe; + + pr_info("Restoring memfd id=%d\n", mfe->id); + + fd = memfd_open_inode(mfi->inode); + if (fd < 0) + goto err; + + /* Reopen the fd with original permissions */ + sprintf(lpath, "/proc/self/fd/%d", fd); + flags = fdflags ? *fdflags : mfe->flags; + /* + * Ideally we should call compat version open() to not force the + * O_LARGEFILE file flag with regular open(). It doesn't seem that + * important though. + */ + _fd = open(lpath, flags); + if (_fd < 0) { + pr_perror("Can't reopen memfd id=%d", mfe->id); + goto err; + } + close(fd); + fd = _fd; + + if (restore_fown(fd, mfe->fown) < 0) + goto err; + + if (lseek(fd, mfe->pos, SEEK_SET) < 0) { + pr_perror("Can't restore file position of memfd id=%d", mfe->id); + goto err; + } + + return fd; + +err: + if (fd >= 0) + close(fd); + return -1; +} + +static int memfd_open_fe_fd(struct file_desc *fd, int *new_fd) +{ + int tmp; + + tmp = memfd_open(fd, NULL); + if (tmp < 0) + return -1; + *new_fd = tmp; + return 0; +} + +static struct file_desc_ops memfd_desc_ops = { + .type = FD_TYPES__MEMFD, + .open = memfd_open_fe_fd, +}; + +static int collect_one_memfd(void *o, ProtobufCMessage *msg, struct cr_img *i) +{ + struct memfd_info *info = o; + + info->mfe = pb_msg(msg, MemfdFileEntry); + info->inode = memfd_alloc_inode(info->mfe->inode_id); + if (!info->inode) + return -1; + + return file_desc_add(&info->d, info->mfe->id, &memfd_desc_ops); +} + +struct collect_image_info memfd_cinfo = { + .fd_type = CR_FD_MEMFD_FILE, + .pb_type = PB_MEMFD_FILE, + .priv_size = sizeof(struct memfd_info), + .collect = collect_one_memfd, +}; diff --git a/criu/shmem.c b/criu/shmem.c index cee47dba7..29383e79a 100644 --- a/criu/shmem.c +++ b/criu/shmem.c @@ -23,6 +23,7 @@ #include "types.h" #include "page.h" #include "util.h" +#include "memfd.h" #include "protobuf.h" #include "images/pagemap.pb-c.h" @@ -490,7 +491,7 @@ static int do_restore_shmem_content(void *addr, unsigned long size, unsigned lon return ret; } -static int restore_shmem_content(void *addr, struct shmem_info *si) +int restore_shmem_content(void *addr, struct shmem_info *si) { return do_restore_shmem_content(addr, si->size, si->shmid); } @@ -500,6 +501,41 @@ int restore_sysv_shmem_content(void *addr, unsigned long size, unsigned long shm return do_restore_shmem_content(addr, round_up(size, PAGE_SIZE), shmid); } +int restore_memfd_shmem_content(int fd, unsigned long shmid, unsigned long size) +{ + void *addr = NULL; + int ret = 1; + + if (size == 0) + return 0; + + if (ftruncate(fd, size) < 0) { + pr_perror("Can't resize shmem 0x%lx size=%ld", shmid, size); + goto out; + } + + addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { + pr_perror("Can't mmap shmem 0x%lx size=%ld", shmid, size); + goto out; + } + + /* + * do_restore_shmem_content needs size to be page aligned. + */ + if (do_restore_shmem_content(addr, round_up(size, PAGE_SIZE), shmid) < 0) { + pr_err("Can't restore shmem content\n"); + goto out; + } + + ret = 0; + +out: + if (addr) + munmap(addr, size); + return ret; +} + static int open_shmem(int pid, struct vma_area *vma) { VmaEntry *vi = vma->e; @@ -532,7 +568,7 @@ static int open_shmem(int pid, struct vma_area *vma) flags = MAP_SHARED; if (kdat.has_memfd) { - f = syscall(SYS_memfd_create, "", 0); + f = memfd_create("", 0); if (f < 0) { pr_perror("Unable to create memfd"); goto err; @@ -779,6 +815,32 @@ err: return ret; } +int dump_one_memfd_shmem(int fd, unsigned long shmid, unsigned long size) +{ + int ret = -1; + void *addr; + struct shmem_info si; + + if (size == 0) + return 0; + + memset(&si, 0, sizeof(si)); + si.shmid = shmid; + si.size = size; + + addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) { + pr_perror("Can't mmap shmem 0x%lx", shmid); + goto err; + } + + ret = do_dump_one_shmem(fd, addr, &si); + + munmap(addr, size); +err: + return ret; +} + int dump_one_sysv_shmem(void *addr, unsigned long size, unsigned long shmid) { int fd, ret; diff --git a/images/Makefile b/images/Makefile index edaab0633..e7f0580cf 100644 --- a/images/Makefile +++ b/images/Makefile @@ -63,6 +63,7 @@ proto-obj-y += sysctl.o proto-obj-y += autofs.o proto-obj-y += macvlan.o proto-obj-y += sit.o +proto-obj-y += memfd.o CFLAGS += -iquote $(obj)/ diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 77e375aa9..d966d5bc5 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -16,6 +16,7 @@ import "sk-unix.proto"; import "fifo.proto"; import "pipe.proto"; import "tty.proto"; +import "memfd.proto"; enum fd_types { UND = 0; @@ -36,6 +37,7 @@ enum fd_types { TUNF = 15; EXT = 16; TIMERFD = 17; + MEMFD = 18; /* Any number above the real used. Not stored to image */ CTL_TTY = 65534; @@ -70,4 +72,5 @@ message file_entry { optional fifo_entry fifo = 17; optional pipe_entry pipe = 18; optional tty_file_entry tty = 19; + optional memfd_file_entry memfd = 20; } diff --git a/images/memfd.proto b/images/memfd.proto new file mode 100644 index 000000000..8eccd6f4f --- /dev/null +++ b/images/memfd.proto @@ -0,0 +1,20 @@ +syntax = "proto2"; + +import "opts.proto"; +import "fown.proto"; + +message memfd_file_entry { + required uint32 id = 1; + required uint32 flags = 2 [(criu).flags = "rfile.flags"]; + required uint64 pos = 3; + required fown_entry fown = 4; + required uint32 inode_id = 5; +}; + +message memfd_inode_entry { + required string name = 1; + required uint32 uid = 2; + required uint32 gid = 3; + required uint64 size = 4; + required uint32 shmid = 5; +}; diff --git a/lib/py/images/images.py b/lib/py/images/images.py index 3eedfca69..dca080657 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -522,6 +522,8 @@ handlers = { 'AUTOFS': entry_handler(pb.autofs_entry), 'FILES': entry_handler(pb.file_entry), 'CPUINFO': entry_handler(pb.cpuinfo_entry), + 'MEMFD_FILE': entry_handler(pb.memfd_file_entry), + 'MEMFD_INODE': entry_handler(pb.memfd_inode_entry), } diff --git a/scripts/feature-tests.mak b/scripts/feature-tests.mak index 6f67c6035..21b390092 100644 --- a/scripts/feature-tests.mak +++ b/scripts/feature-tests.mak @@ -171,3 +171,14 @@ int main(int argc, char **argv) } endef + +define FEATURE_TEST_MEMFD_CREATE + +#include +#include + +int main(void) +{ + return memfd_create(NULL, 0); +} +endef From 875ac4d03f9034adb88eec5875d63d0561c48107 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 18 Dec 2019 23:32:32 +0000 Subject: [PATCH 2317/4375] files: increase path buffer size in inherited_fd() Prepare memfd to use inherited_fd(), needing long path names support. Signed-off-by: Nicolas Viennot --- criu/files.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/files.c b/criu/files.c index ea86deaa3..789b08a4c 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1608,7 +1608,7 @@ int inherit_fd_lookup_id(char *id) bool inherited_fd(struct file_desc *d, int *fd_p) { - char buf[32], *id_str; + char buf[PATH_MAX], *id_str; int i_fd; if (!d->ops->name) From b25684e24ae7643f2a8da73617c22a44dc9023ca Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 18 Dec 2019 23:32:32 +0000 Subject: [PATCH 2318/4375] memfd: add --inherit-fd support Upon file restore, inherited_fd() is called to check for a user-defined inerit-fd override. Note that the MEMFD_INODE image is read at each invocation (memfd name is not cached). Signed-off-by: Nicolas Viennot --- criu/crtools.c | 1 + criu/memfd.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/criu/crtools.c b/criu/crtools.c index 3cd40e87d..7f72dde27 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -392,6 +392,7 @@ usage: " pipe[inode]\n" " socket[inode]\n" " file[mnt_id:inode]\n" +" /memfd:name\n" " path/to/file\n" " --empty-ns net Create a namespace, but don't restore its properties\n" " (assuming it will be restored by action scripts)\n" diff --git a/criu/memfd.c b/criu/memfd.c index bcef35e75..36b3be8df 100644 --- a/criu/memfd.c +++ b/criu/memfd.c @@ -276,6 +276,9 @@ static int memfd_open(struct file_desc *d, u32 *fdflags) mfi = container_of(d, struct memfd_info, d); mfe = mfi->mfe; + if (inherited_fd(d, &fd)) + return fd; + pr_info("Restoring memfd id=%d\n", mfe->id); fd = memfd_open_inode(mfi->inode); @@ -325,9 +328,42 @@ static int memfd_open_fe_fd(struct file_desc *fd, int *new_fd) return 0; } +static char *memfd_d_name(struct file_desc *d, char *buf, size_t s) +{ + MemfdInodeEntry *mie = NULL; + struct cr_img *img = NULL; + struct memfd_info *mfi; + char *ret = NULL; + + mfi = container_of(d, struct memfd_info, d); + + img = open_image(CR_FD_MEMFD_INODE, O_RSTR, mfi->inode->id); + if (!img) + goto out; + + if (pb_read_one(img, &mie, PB_MEMFD_INODE) < 0) + goto out; + + if (snprintf(buf, s, "%s%s", MEMFD_PREFIX, mie->name) >= s) { + pr_err("Buffer too small for memfd name %s\n", mie->name); + goto out; + } + + ret = buf; + +out: + if (img) + close_image(img); + if (mie) + memfd_inode_entry__free_unpacked(mie, NULL); + + return ret; +} + static struct file_desc_ops memfd_desc_ops = { .type = FD_TYPES__MEMFD, .open = memfd_open_fe_fd, + .name = memfd_d_name, }; static int collect_one_memfd(void *o, ProtobufCMessage *msg, struct cr_img *i) From 29a1a88bcebaf9d83591077d2bec424da82c0e71 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 18 Dec 2019 23:32:32 +0000 Subject: [PATCH 2319/4375] memfd: add memory mapping support * During checkpoint, we add a vma flags: VMA_AREA_MEMFD to denote memfd regions. * Even though memfd is backed by the shmem device, we use the file semantics of memfd (via /proc/map_files/) which we already have support for. Signed-off-by: Nicolas Viennot --- criu/cr-dump.c | 6 +++++- criu/files-reg.c | 11 +++++++++-- criu/include/image.h | 1 + criu/include/memfd.h | 6 ++++++ criu/memfd.c | 19 ++++++++++++++++++- criu/proc_parse.c | 35 +++++++++++++++++++++++++++++++++++ 6 files changed, 74 insertions(+), 4 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 88323af92..6aa114c2d 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -80,6 +80,7 @@ #include "fault-injection.h" #include "dump.h" #include "eventpoll.h" +#include "memfd.h" /* * Architectures can overwrite this function to restore register sets that @@ -414,7 +415,10 @@ static int dump_filemap(struct vma_area *vma_area, int fd) /* Flags will be set during restore in open_filmap() */ - ret = dump_one_reg_file_cond(fd, &id, &p); + if (vma->status & VMA_AREA_MEMFD) + ret = dump_one_memfd_cond(fd, &id, &p); + else + ret = dump_one_reg_file_cond(fd, &id, &p); vma->shmid = id; return ret; diff --git a/criu/files-reg.c b/criu/files-reg.c index 90fb7dd7f..b0dad78e6 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -35,6 +35,7 @@ #include "pstree.h" #include "fault-injection.h" #include "external.h" +#include "memfd.h" #include "protobuf.h" #include "util.h" @@ -1879,7 +1880,10 @@ static int open_filemap(int pid, struct vma_area *vma) flags = vma->e->fdflags; if (ctx.flags != flags || ctx.desc != vma->vmfd) { - ret = open_path(vma->vmfd, do_open_reg_noseek_flags, &flags); + if (vma->e->status & VMA_AREA_MEMFD) + ret = memfd_open(vma->vmfd, &flags); + else + ret = open_path(vma->vmfd, do_open_reg_noseek_flags, &flags); if (ret < 0) return ret; @@ -1909,7 +1913,10 @@ int collect_filemap(struct vma_area *vma) vma->e->fdflags = O_RDONLY; } - fd = collect_special_file(vma->e->shmid); + if (vma->e->status & VMA_AREA_MEMFD) + fd = collect_memfd(vma->e->shmid); + else + fd = collect_special_file(vma->e->shmid); if (!fd) return -1; diff --git a/criu/include/image.h b/criu/include/image.h index 2baa39496..1c7cc5471 100644 --- a/criu/include/image.h +++ b/criu/include/image.h @@ -83,6 +83,7 @@ #define VMA_AREA_SOCKET (1 << 11) #define VMA_AREA_VVAR (1 << 12) #define VMA_AREA_AIORING (1 << 13) +#define VMA_AREA_MEMFD (1 << 14) #define VMA_CLOSE (1 << 28) #define VMA_NO_PROT_WRITE (1 << 29) diff --git a/criu/include/memfd.h b/criu/include/memfd.h index c1d7949cb..0a9aeff2f 100644 --- a/criu/include/memfd.h +++ b/criu/include/memfd.h @@ -5,10 +5,16 @@ #include "int.h" #include "common/config.h" +struct fd_parms; +struct file_desc; + extern int is_memfd(dev_t dev, const char *path); +extern int dump_one_memfd_cond(int lfd, u32 *id, struct fd_parms *parms); extern const struct fdtype_ops memfd_dump_ops; +extern int memfd_open(struct file_desc *d, u32 *fdflags); extern struct collect_image_info memfd_cinfo; +extern struct file_desc *collect_memfd(u32 id); #ifdef CONFIG_HAS_MEMFD_CREATE # include diff --git a/criu/memfd.c b/criu/memfd.c index 36b3be8df..1cca96a32 100644 --- a/criu/memfd.c +++ b/criu/memfd.c @@ -164,6 +164,13 @@ static int dump_one_memfd(int lfd, u32 id, const struct fd_parms *p) return pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE); } +int dump_one_memfd_cond(int lfd, u32 *id, struct fd_parms *parms) +{ + if (fd_id_generate_special(parms, id)) + return dump_one_memfd(lfd, *id, parms); + return 0; +} + const struct fdtype_ops memfd_dump_ops = { .type = FD_TYPES__MEMFD, .dump = dump_one_memfd, @@ -265,7 +272,7 @@ static int memfd_open_inode(struct memfd_inode *inode) return fd; } -static int memfd_open(struct file_desc *d, u32 *fdflags) +int memfd_open(struct file_desc *d, u32 *fdflags) { char lpath[PSFDS]; struct memfd_info *mfi; @@ -384,3 +391,13 @@ struct collect_image_info memfd_cinfo = { .priv_size = sizeof(struct memfd_info), .collect = collect_one_memfd, }; + +struct file_desc *collect_memfd(u32 id) { + struct file_desc *fdesc; + + fdesc = find_file_desc_raw(FD_TYPES__MEMFD, id); + if (fdesc == NULL) + pr_err("No entry for memfd %#x\n", id); + + return fdesc; +} diff --git a/criu/proc_parse.c b/criu/proc_parse.c index fa7644992..468afcdf3 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -41,6 +41,7 @@ #include "timerfd.h" #include "path.h" #include "fault-injection.h" +#include "memfd.h" #include "protobuf.h" #include "images/fdinfo.pb-c.h" @@ -303,6 +304,26 @@ static int vma_get_mapfile_user(const char *fname, struct vma_area *vma, } vfi_dev = makedev(vfi->dev_maj, vfi->dev_min); + + if (is_memfd(vfi_dev, fname)) { + struct fd_link link; + link.len = strlen(fname); + strlcpy(link.name, fname, sizeof(link.name)); + strip_deleted(&link); + + /* + * The error EPERM will be shown in the following pr_perror(). + * It comes from the previous open() call. + */ + pr_perror("Can't open mapped [%s]", link.name); + + /* + * TODO Perhaps we could do better than failing and dump the + * memory like what is being done in shmem.c + */ + return -1; + } + if (is_anon_shmem_map(vfi_dev)) { if (!(vma->e->flags & MAP_SHARED)) return -1; @@ -578,7 +599,20 @@ static int handle_vma(pid_t pid, struct vma_area *vma_area, /* * /dev/zero stands for anon-shared mapping * otherwise it's some file mapping. + * + * We treat memfd mappings as regular file mappings because + * their backing can be seen as files, which is easy to + * support. So even though memfd is an anonymous shmem, we + * treat it differently. + * Note: maybe we should revisit this as /proc/map_files/ + * may not always be accessible. */ + + if (is_memfd(st_buf->st_dev, file_path)) { + vma_area->e->status |= VMA_AREA_MEMFD; + goto normal_file; + } + if (is_anon_shmem_map(st_buf->st_dev)) { if (!(vma_area->e->flags & MAP_SHARED)) goto err_bogus_mapping; @@ -594,6 +628,7 @@ static int handle_vma(pid_t pid, struct vma_area *vma_area, vma_area->e->shmid += FI_HUGE_ANON_SHMEM_ID_BASE; } } else { +normal_file: if (vma_area->e->flags & MAP_PRIVATE) vma_area->e->status |= VMA_FILE_PRIVATE; else From 56d8e2455fb86b885775db6c236cbb04ba403f4d Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 18 Dec 2019 23:32:32 +0000 Subject: [PATCH 2320/4375] memfd: add seals support See "man fcntl" for more information about seals. memfd are the only files that can be sealed, currently. For this reason, we dump the seal values in the MEMFD_INODE image. Restoring seals must be done carefully as the seal F_SEAL_FUTURE_WRITE prevents future write access. This means that any memory mapping with write access must be restored before restoring the seals. Signed-off-by: Nicolas Viennot --- criu/cr-restore.c | 4 +++ criu/include/fcntl.h | 8 ++++++ criu/include/memfd.h | 1 + criu/memfd.c | 59 +++++++++++++++++++++++++++++++++++++++- images/memfd.proto | 1 + lib/py/images/pb2dict.py | 9 ++++++ 6 files changed, 81 insertions(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 13d1001c9..f50448cd2 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2232,6 +2232,10 @@ skip_ns_bouncing: if (ret < 0) goto out_kill; + ret = apply_memfd_seals(); + if (ret < 0) + goto out_kill; + /* * Zombies die after CR_STATE_RESTORE which is switched * by root task, not by us. See comment before CR_STATE_FORKING diff --git a/criu/include/fcntl.h b/criu/include/fcntl.h index d9c5c5e7b..ea9d48c72 100644 --- a/criu/include/fcntl.h +++ b/criu/include/fcntl.h @@ -34,6 +34,14 @@ struct f_owner_ex { # define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8) #endif +#ifndef F_ADD_SEALS +# define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) +#endif + +#ifndef F_GET_SEALS +# define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) +#endif + #ifndef O_PATH # define O_PATH 010000000 #endif diff --git a/criu/include/memfd.h b/criu/include/memfd.h index 0a9aeff2f..2d8eda545 100644 --- a/criu/include/memfd.h +++ b/criu/include/memfd.h @@ -15,6 +15,7 @@ extern const struct fdtype_ops memfd_dump_ops; extern int memfd_open(struct file_desc *d, u32 *fdflags); extern struct collect_image_info memfd_cinfo; extern struct file_desc *collect_memfd(u32 id); +extern int apply_memfd_seals(void); #ifdef CONFIG_HAS_MEMFD_CREATE # include diff --git a/criu/memfd.c b/criu/memfd.c index 1cca96a32..d17c10fb7 100644 --- a/criu/memfd.c +++ b/criu/memfd.c @@ -1,4 +1,5 @@ #include +#include #include "common/compiler.h" #include "common/lock.h" @@ -24,6 +25,13 @@ #define MEMFD_PREFIX "/memfd:" #define MEMFD_PREFIX_LEN (sizeof(MEMFD_PREFIX)-1) +#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ +#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ +#define F_SEAL_GROW 0x0004 /* prevent file from growing */ +#define F_SEAL_WRITE 0x0008 /* prevent writes */ +/* Linux 5.1+ */ +#define F_SEAL_FUTURE_WRITE 0x0010 /* prevent future writes while mapped */ + struct memfd_inode { struct list_head list; u32 id; @@ -37,6 +45,7 @@ struct memfd_inode { struct { mutex_t lock; int fdstore_id; + unsigned int pending_seals; }; }; }; @@ -92,6 +101,10 @@ static int dump_memfd_inode(int fd, struct memfd_inode *inode, mie.size = st->st_size; mie.shmid = shmid; + mie.seals = fcntl(fd, F_GET_SEALS); + if (mie.seals == -1) + goto out; + if (pb_write_one(img, &mie, PB_MEMFD_INODE)) goto out; @@ -187,6 +200,8 @@ struct memfd_info { struct memfd_inode *inode; }; +static int memfd_open_inode(struct memfd_inode *inode); + static struct memfd_inode *memfd_alloc_inode(int id) { struct memfd_inode *inode; @@ -202,6 +217,7 @@ static struct memfd_inode *memfd_alloc_inode(int id) inode->id = id; mutex_init(&inode->lock); inode->fdstore_id = -1; + inode->pending_seals = 0; list_add_tail(&inode->list, &memfd_inodes); return inode; @@ -223,7 +239,16 @@ static int memfd_open_inode_nocache(struct memfd_inode *inode) if (pb_read_one(img, &mie, PB_MEMFD_INODE) < 0) goto out; - fd = memfd_create(mie->name, 0); + if (mie->seals == F_SEAL_SEAL) { + inode->pending_seals = 0; + flags = 0; + } else { + /* Seals are applied later due to F_SEAL_FUTURE_WRITE */ + inode->pending_seals = mie->seals; + flags = MFD_ALLOW_SEALING; + } + + fd = memfd_create(mie->name, flags); if (fd < 0) { pr_perror("Can't create memfd:%s", mie->name); goto out; @@ -401,3 +426,35 @@ struct file_desc *collect_memfd(u32 id) { return fdesc; } + +int apply_memfd_seals(void) +{ + /* + * We apply the seals after all the mappings are done because the seal + * F_SEAL_FUTURE_WRITE prevents future write access (added in + * Linux 5.1). Thus we must make sure all writable mappings are opened + * before applying this seal. + */ + + int ret, fd; + struct memfd_inode *inode; + + list_for_each_entry(inode, &memfd_inodes, list) { + if (!inode->pending_seals) + continue; + + fd = memfd_open_inode(inode); + if (fd < 0) + return -1; + + ret = fcntl(fd, F_ADD_SEALS, inode->pending_seals); + close(fd); + + if (ret < 0) { + pr_perror("Cannot apply seals on memfd"); + return -1; + } + } + + return 0; +} diff --git a/images/memfd.proto b/images/memfd.proto index 8eccd6f4f..546ffc2ab 100644 --- a/images/memfd.proto +++ b/images/memfd.proto @@ -17,4 +17,5 @@ message memfd_inode_entry { required uint32 gid = 3; required uint64 size = 4; required uint32 shmid = 5; + required uint32 seals = 6 [(criu).flags = "seals.flags"]; }; diff --git a/lib/py/images/pb2dict.py b/lib/py/images/pb2dict.py index a89850a1d..40a6036cf 100644 --- a/lib/py/images/pb2dict.py +++ b/lib/py/images/pb2dict.py @@ -124,6 +124,14 @@ rfile_flags_map = [ ('O_CLOEXEC', 0o02000000), ] +seals_flags_map = [ + ('F_SEAL_SEAL', 0x0001), + ('F_SEAL_SHRINK', 0x0002), + ('F_SEAL_GROW', 0x0004), + ('F_SEAL_WRITE', 0x0008), + ('F_SEAL_FUTURE_WRITE', 0x0010), +] + pmap_flags_map = [ ('PE_PARENT', 1 << 0), ('PE_LAZY', 1 << 1), @@ -136,6 +144,7 @@ flags_maps = { 'mmap.status': mmap_status_map, 'rfile.flags': rfile_flags_map, 'pmap.flags': pmap_flags_map, + 'seals.flags': seals_flags_map, } gen_maps = { From b133c375ad2d21cf6a1a9e96e7dab3741c966fbe Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 4 Feb 2020 16:39:53 +0000 Subject: [PATCH 2321/4375] inhfd_test: add support for non-pair files File pairs naturally block on read() until the write() happen (or the writer is closed). This is not the case for regular files, so we take extra precaution for these. Also cleaned-up an extra my_file.close() Signed-off-by: Nicolas Viennot --- test/zdtm.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 3fc57ba55..4110b5142 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -691,9 +691,14 @@ class inhfd_test: i = 0 for _, peer_file in self.__files: msg = self.__get_message(i) - my_file.close() try: - data = peer_file.read(16) + # File pairs naturally block on read() until the write() + # happen (or the writer is closed). This is not the case for + # regular files, so we loop. + data = b'' + while not data: + data = peer_file.read(16) + time.sleep(0.1) except Exception as e: print("Unable to read a peer file: %s" % e) sys.exit(1) From 2dd105b8dfb23399e18ab4e3f7d13b00c19ad910 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Fri, 20 Dec 2019 21:56:38 -0500 Subject: [PATCH 2322/4375] memfd: add tests Testing for all the memfd features, namely support for CR of: * the same fd shared by multiple processes * the same file shared by multiple processes * the memfd content * file flags and fd flags * mmaps, MAP_SHARED and MAP_PRIVATE * seals, excluding F_SEAL_FUTURE_WRITE because this feature only exists in recent kernels (5.1 and up) * inherited fd Signed-off-by: Nicolas Viennot --- test/inhfd/memfd.py | 28 +++++++++ test/inhfd/memfd.py.checkskip | 7 +++ test/inhfd/memfd.py.desc | 1 + test/zdtm/static/Makefile | 4 ++ test/zdtm/static/memfd00.c | 103 ++++++++++++++++++++++++++++++ test/zdtm/static/memfd01.c | 114 ++++++++++++++++++++++++++++++++++ test/zdtm/static/memfd02.c | 87 ++++++++++++++++++++++++++ test/zdtm/static/memfd03.c | 97 +++++++++++++++++++++++++++++ 8 files changed, 441 insertions(+) create mode 100755 test/inhfd/memfd.py create mode 100755 test/inhfd/memfd.py.checkskip create mode 100644 test/inhfd/memfd.py.desc create mode 100644 test/zdtm/static/memfd00.c create mode 100644 test/zdtm/static/memfd01.c create mode 100644 test/zdtm/static/memfd02.c create mode 100644 test/zdtm/static/memfd03.c diff --git a/test/inhfd/memfd.py b/test/inhfd/memfd.py new file mode 100755 index 000000000..d9ce01e41 --- /dev/null +++ b/test/inhfd/memfd.py @@ -0,0 +1,28 @@ +import os +import ctypes +libc = ctypes.CDLL(None) + + +def memfd_create(name, flags): + return libc.memfd_create(name.encode('utf8'), flags) + + +def create_fds(): + def create_memfd_pair(name): + fd = memfd_create(name, 0) + fw = open('/proc/self/fd/{}'.format(fd), 'wb') + fr = open('/proc/self/fd/{}'.format(fd), 'rb') + os.close(fd) + return (fw, fr) + + return [create_memfd_pair("name{}".format(i)) for i in range(10)] + + +def filename(f): + name = os.readlink('/proc/self/fd/{}'.format(f.fileno())) + name = name.replace(' (deleted)', '') + return name + + +def dump_opts(sockf): + return [] diff --git a/test/inhfd/memfd.py.checkskip b/test/inhfd/memfd.py.checkskip new file mode 100755 index 000000000..252778969 --- /dev/null +++ b/test/inhfd/memfd.py.checkskip @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +import ctypes +libc = ctypes.CDLL(None) + +# libc may not have memfd_create (e.g., centos on travis) +libc.memfd_create("test".encode('utf8'), 0) diff --git a/test/inhfd/memfd.py.desc b/test/inhfd/memfd.py.desc new file mode 100644 index 000000000..10666c823 --- /dev/null +++ b/test/inhfd/memfd.py.desc @@ -0,0 +1 @@ +{ 'flavor': 'h' } diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 5ca05ee9e..5afd18cd6 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -220,6 +220,10 @@ TST_NOFILE := \ child_subreaper \ child_subreaper_existing_child \ child_subreaper_and_reparent \ + memfd00 \ + memfd01 \ + memfd02 \ + memfd03 \ # jobctl00 \ ifneq ($(ARCH),arm) diff --git a/test/zdtm/static/memfd00.c b/test/zdtm/static/memfd00.c new file mode 100644 index 000000000..6b56eca01 --- /dev/null +++ b/test/zdtm/static/memfd00.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "memfd file descriptor"; +const char *test_author = "Nicolas Viennot "; + +#define err(exitcode, msg, ...) ({ pr_perror(msg, ##__VA_ARGS__); exit(exitcode); }) + +static int _memfd_create(const char *name, unsigned int flags) +{ + return syscall(SYS_memfd_create, name, flags); +} + +int main(int argc, char *argv[]) +{ + int fd, fl_flags1, fl_flags2, fd_flags1, fd_flags2; + struct statfs statfs1, statfs2; + off_t pos1, pos2; + char buf[5]; + + test_init(argc, argv); + + fd = _memfd_create("somename", MFD_CLOEXEC); + if (fd < 0) + err(1, "Can't call memfd_create"); + + if (fcntl(fd, F_SETFL, O_APPEND) < 0) + err(1, "Can't get fl flags"); + + if ((fl_flags1 = fcntl(fd, F_GETFL)) == -1) + err(1, "Can't get fl flags"); + + if ((fd_flags1 = fcntl(fd, F_GETFD)) == -1) + err(1, "Can't get fd flags"); + + if (fstatfs(fd, &statfs1) < 0) + err(1, "statfs issue"); + + if (write(fd, "hello", 5) != 5) + err(1, "write error"); + + pos1 = 3; + if (lseek(fd, pos1, SEEK_SET) < 0) + err(1, "seek error"); + + test_daemon(); + test_waitsig(); + + if ((fl_flags2 = fcntl(fd, F_GETFL)) == -1) + err(1, "Can't get fl flags"); + + if (fl_flags1 != fl_flags2) { + fail("fl flags differs"); + return 1; + } + + if ((fd_flags2 = fcntl(fd, F_GETFD)) == -1) + err(1, "Can't get fd flags"); + + if (fd_flags1 != fd_flags2) { + fail("fd flags differs"); + return 1; + } + + if (fstatfs(fd, &statfs2) < 0) + err(1, "statfs issue"); + + if (statfs1.f_type != statfs2.f_type) { + fail("statfs.f_type differs"); + return 1; + } + + pos2 = lseek(fd, 0, SEEK_CUR); + if (pos1 != pos2) { + fail("position differs"); + return 1; + } + + if (pread(fd, buf, sizeof(buf), 0) != sizeof(buf)) { + fail("read problem"); + return 1; + } + + if (memcmp(buf, "hello", sizeof(buf))) { + fail("content mismatch"); + return 1; + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/memfd01.c b/test/zdtm/static/memfd01.c new file mode 100644 index 000000000..7a7853642 --- /dev/null +++ b/test/zdtm/static/memfd01.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "memfd with different file pointer"; +const char *test_author = "Nicolas Viennot "; + +#define err(exitcode, msg, ...) ({ pr_perror(msg, ##__VA_ARGS__); exit(exitcode); }) + +static int _memfd_create(const char *name, unsigned int flags) +{ + return syscall(SYS_memfd_create, name, flags); +} + +int main(int argc, char *argv[]) +{ + pid_t pid, pid_child; + int fd, ret, status; + task_waiter_t t; + + test_init(argc, argv); + + task_waiter_init(&t); + + fd = _memfd_create("somename", MFD_CLOEXEC); + if (fd < 0) + err(1, "Can't call memfd_create"); + + pid = getpid(); + + pid_child = fork(); + if (pid_child < 0) + err(1, "Can't fork"); + + if (!pid_child) { + char fdpath[100]; + char buf[1]; + int fl_flags1, fl_flags2, fd_flags1, fd_flags2; + + snprintf(fdpath, sizeof(fdpath), "/proc/%d/fd/%d", pid, fd); + /* + * We pass O_LARGEFILE because in compat mode, our file + * descriptor does not get O_LARGEFILE automatically, but the + * restorer using non-compat open() is forced O_LARGEFILE. + * This creates a flag difference, which we don't want to deal + * with this at the moment. + */ + fd = open(fdpath, O_RDONLY | O_LARGEFILE); + if (fd < 0) + err(1, "Can't open memfd via proc"); + + if ((fl_flags1 = fcntl(fd, F_GETFL)) == -1) + err(1, "Can't get fl flags"); + + if ((fd_flags1 = fcntl(fd, F_GETFD)) == -1) + err(1, "Can't get fd flags"); + + task_waiter_complete(&t, 1); + // checkpoint-restore happens here + task_waiter_wait4(&t, 2); + + if (read(fd, buf, 1) != 1) + err(1, "Can't read"); + + if ((fl_flags2 = fcntl(fd, F_GETFL)) == -1) + err(1, "Can't get fl flags"); + + if (fl_flags1 != fl_flags2) + err(1, "fl flags differs"); + + if ((fd_flags2 = fcntl(fd, F_GETFD)) == -1) + err(1, "Can't get fd flags"); + + if (fd_flags1 != fd_flags2) + err(1, "fd flags differs"); + + if (buf[0] != 'x') + err(1, "Read incorrect"); + + return 0; + } + + task_waiter_wait4(&t, 1); + + test_daemon(); + test_waitsig(); + + if (write(fd, "x", 1) != 1) + err(1, "Can't write"); + + task_waiter_complete(&t, 2); + + ret = wait(&status); + if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status)) { + kill(pid, SIGKILL); + fail("child had issue"); + return 1; + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/memfd02.c b/test/zdtm/static/memfd02.c new file mode 100644 index 000000000..1843e9c9a --- /dev/null +++ b/test/zdtm/static/memfd02.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "memfd mmap"; +const char *test_author = "Nicolas Viennot "; + +#define err(exitcode, msg, ...) ({ pr_perror(msg, ##__VA_ARGS__); exit(exitcode); }) + +static int _memfd_create(const char *name, unsigned int flags) +{ + return syscall(SYS_memfd_create, name, flags); +} + +int main(int argc, char *argv[]) +{ +#define LEN 6 + int fd; + void *addr_shared, *addr_private; + char buf[LEN]; + + test_init(argc, argv); + + fd = _memfd_create("somename", MFD_CLOEXEC); + if (fd < 0) + err(1, "Can't call memfd_create"); + + if (ftruncate(fd, LEN) < 0) + err(1, "Can't truncate"); + + addr_shared = mmap(NULL, LEN, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (addr_shared == MAP_FAILED) + err(1, "Can't mmap"); + + write(fd, "write1", LEN); + + addr_private = mmap(NULL, LEN, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (addr_private == MAP_FAILED) + err(1, "Can't mmap"); + + test_daemon(); + test_waitsig(); + + if (memcmp(addr_shared, "write1", LEN)) { + fail("content mismatch (shared)"); + return 1; + } + + strcpy(addr_shared, "write2"); + + if (pread(fd, buf, LEN, 0) != LEN) { + fail("read problem"); + return 1; + } + + if (memcmp(buf, "write2", LEN)) { + fail("content mismatch (shared)"); + return 1; + } + + if (memcmp(addr_private, "write2", LEN)) { + fail("content mismatch (private)"); + return 1; + } + + strcpy(addr_private, "write3"); + + if (memcmp(addr_shared, "write2", LEN)) { + fail("content mismatch (shared)"); + return 1; + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/memfd03.c b/test/zdtm/static/memfd03.c new file mode 100644 index 000000000..faedf9383 --- /dev/null +++ b/test/zdtm/static/memfd03.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "memfd seals"; +const char *test_author = "Nicolas Viennot "; + +#define err(exitcode, msg, ...) ({ pr_perror(msg, ##__VA_ARGS__); exit(exitcode); }) + +static int _memfd_create(const char *name, unsigned int flags) +{ + return syscall(SYS_memfd_create, name, flags); +} + + +#ifndef F_LINUX_SPECIFIC_BASE +# define F_LINUX_SPECIFIC_BASE 1024 +#endif + +#ifndef F_ADD_SEALS + #define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) +#endif + +#ifndef F_GET_SEALS + #define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) +#endif + + +#ifndef F_SEAL_SEAL +#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ +#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ +#define F_SEAL_GROW 0x0004 /* prevent file from growing */ +#define F_SEAL_WRITE 0x0008 /* prevent writes */ +#endif + +int main(int argc, char *argv[]) +{ +#define LEN 5 + int fd, fd2; + void *addr_write, *addr_read; + char fdpath[100]; + + test_init(argc, argv); + + fd = _memfd_create("somename", MFD_ALLOW_SEALING | MFD_CLOEXEC); + if (fd < 0) + err(1, "Can't call memfd_create"); + + if (write(fd, "hello", LEN) != LEN) + err(1, "Can't write"); + + if (fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) < 0) + err(1, "Can't add seals"); + + test_daemon(); + test_waitsig(); + + snprintf(fdpath, sizeof(fdpath), "/proc/self/fd/%d", fd); + fd2 = open(fdpath, O_RDWR); + if (fd2 < 0) + err(1, "Can't open memfd via proc"); + + if (fcntl(fd, F_GET_SEALS) != F_SEAL_WRITE) { + fail("Seals are different"); + return 1; + } + + addr_write = mmap(NULL, LEN, PROT_WRITE, MAP_SHARED, fd2, 0); + if (addr_write != MAP_FAILED) { + fail("Should not be able to get write access"); + return 1; + } + + addr_read = mmap(NULL, 1, PROT_READ, MAP_PRIVATE, fd2, 0); + if (addr_read == MAP_FAILED) + err(1, "Can't mmap"); + + if (memcmp(addr_read, "hello", LEN)) { + fail("Mapping has bad data"); + return 1; + } + + pass(); + + return 0; +} From ec116449544cd2f062b7523c2eadc6d791baa0ac Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 23 Jan 2020 16:39:28 +0000 Subject: [PATCH 2323/4375] criu: Use strlcpy() instead of strncpy() gcc8 in Fedora Rawhide has a new useful warning: > criu/img-remote.c: In function 'push_snapshot_id': > criu/img-remote.c:1099:2: error: 'strncpy' specified bound 4096 equals destination size [-Werror=stringop-truncation] > 1099 | strncpy(rn.snapshot_id, snapshot_id, PATH_MAX); > | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From man 3 strncpy: > Warning: If there is no null byte among the first n bytes of src, > the string placed in dest will not be null-terminated. Signed-off-by: Dmitry Safonov --- criu/files-reg.c | 3 ++- criu/files.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index b0dad78e6..c2a55aeb3 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -33,6 +33,7 @@ #include "namespaces.h" #include "proc_parse.h" #include "pstree.h" +#include "string.h" #include "fault-injection.h" #include "external.h" #include "memfd.h" @@ -457,7 +458,7 @@ static int open_remap_ghost(struct reg_file_info *rfi, gf->remap.rmnt_id = rfi->rfe->mnt_id; if (S_ISDIR(gfe->mode)) - strncpy(gf->remap.rpath, rfi->path, PATH_MAX); + strlcpy(gf->remap.rpath, rfi->path, PATH_MAX); else ghost_path(gf->remap.rpath, PATH_MAX, rfi, rpe); diff --git a/criu/files.c b/criu/files.c index 789b08a4c..f7963bf54 100644 --- a/criu/files.c +++ b/criu/files.c @@ -45,6 +45,7 @@ #include "autofs.h" #include "parasite.h" #include "parasite-syscall.h" +#include "string.h" #include "kerndat.h" #include "fdstore.h" @@ -291,8 +292,7 @@ static int fixup_overlayfs(struct fd_parms *p, struct fd_link *link) char buf[PATH_MAX]; int n; - strncpy(buf, link->name, PATH_MAX); - buf[PATH_MAX - 1] = 0; + strlcpy(buf, link->name, PATH_MAX); n = snprintf(link->name, PATH_MAX, "%s/%s", m->mountpoint, buf + 2); if (n >= PATH_MAX) { pr_err("Not enough space to replace %s\n", buf); From bc49927bbc28b41e4b2759d42dc24f1d66e22df3 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 6 Feb 2020 18:01:00 +0000 Subject: [PATCH 2324/4375] criu: Make use strlcpy() to copy into allocated strings strncpy() with n == strlen(src) won't put NULL-terminator in dst. Signed-off-by: Dmitry Safonov --- criu/cr-restore.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index f50448cd2..85105a18e 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -77,6 +77,7 @@ #include "fdstore.h" #include "string.h" #include "memfd.h" +#include "string.h" #include "parasite-syscall.h" #include "files-reg.h" From 3eab205bae1d31f00922d1e717a1cd56c1cb7177 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 6 Feb 2020 21:20:20 -0800 Subject: [PATCH 2325/4375] python: sort imports 202 Additional newline in a group of imports. I100 Import statements are in the wrong order. Signed-off-by: Andrei Vagin --- test/inhfd/memfd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/inhfd/memfd.py b/test/inhfd/memfd.py index d9ce01e41..b06e35068 100755 --- a/test/inhfd/memfd.py +++ b/test/inhfd/memfd.py @@ -1,5 +1,5 @@ -import os import ctypes +import os libc = ctypes.CDLL(None) From 38793699e7f0e97d14b6b17e83e8bc071c3ce283 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 21 Feb 2020 12:14:38 +0300 Subject: [PATCH 2326/4375] test/jenkins: remove empty line at the end of file Signed-off-by: Pavel Tikhomirov --- test/jenkins/criu-fault.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/test/jenkins/criu-fault.sh b/test/jenkins/criu-fault.sh index 4e3790e59..c27dd3738 100755 --- a/test/jenkins/criu-fault.sh +++ b/test/jenkins/criu-fault.sh @@ -27,4 +27,3 @@ fi ./test/zdtm.py run -t zdtm/static/maps04 --fault 131 --keep-going --report report --pre 2:1 || fail ./test/zdtm.py run -t zdtm/transition/maps008 --fault 131 --keep-going --report report --pre 2:1 || fail ./test/zdtm.py run -t zdtm/static/maps01 --fault 132 -f h || fail - From cdd08cdff8692aad9d05dd83e2ab24379cd83393 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 26 Feb 2020 12:25:37 +0200 Subject: [PATCH 2327/4375] uffd: use userns_call() to execute ioctl(UFFDIO_API) In the recent kernels the userfaultfd support for FORK events is limited to CAP_SYS_PTRACE. That causes the followong error when the ioctl(UFFDIO_API) is executed from non-privilieged userns: Error (criu/uffd.c:273): uffd: Failed to get uffd API: Operation not permitted Wrapping the call to ioctl(UFFDIO_API) in userns_call() resolves the issue. Fixes: #964 Signed-off-by: Mike Rapoport --- criu/uffd.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index c47b35b1f..99373c04d 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -40,6 +40,7 @@ #include "tls.h" #include "fdstore.h" #include "util.h" +#include "namespaces.h" #undef LOG_PREFIX #define LOG_PREFIX "uffd: " @@ -254,6 +255,13 @@ bool uffd_noncooperative(void) return (kdat.uffd_features & features) == features; } +static int uffd_api_ioctl(void *arg, int fd, pid_t pid) +{ + struct uffdio_api *uffdio_api = arg; + + return ioctl(fd, UFFDIO_API, uffdio_api); +} + int uffd_open(int flags, unsigned long *features) { struct uffdio_api uffdio_api = { 0 }; @@ -269,7 +277,8 @@ int uffd_open(int flags, unsigned long *features) if (features) uffdio_api.features = *features; - if (ioctl(uffd, UFFDIO_API, &uffdio_api)) { + if (userns_call(uffd_api_ioctl, 0, &uffdio_api, sizeof(uffdio_api), + uffd)) { pr_perror("Failed to get uffd API"); goto err; } From 48f3b6516b384f9c4f240aff76f671697198884b Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 18 Feb 2020 19:45:08 +0000 Subject: [PATCH 2328/4375] criu(8): Add documentation for --enable-fs This option was introduced with: https://github.com/checkpoint-restore/criu/commit/e2c38245c613df5e36dcf0253c7652f928e46abf v2: (comment from Pavel Tikhomirov) --enable-fs does not fit with --external dev[]:, see try_resolve_ext_mount, external dev mounts only determined for FSTYPE__UNSUPPORTED. Signed-off-by: Radostin Stoyanov --- Documentation/criu.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index a6b9f7fae..0ac29103a 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -90,6 +90,19 @@ The following levels are available: *-L*, *--libdir* 'path':: Path to plugins directory. +*--enable-fs* ['fs'[,'fs'...]]:: + Specify a comma-separated list of filesystem names that should + be auto-detected. The value 'all' enables auto-detection for + all filesystems. ++ +Note: This option is not safe, use at your own risk. +Auto-detecting a filesystem mount assumes that the mountpoint can +be restored with *mount(src, mountpoint, flags, options)*. When used, +*dump* is expected to always succeed if a mountpoint is to be +auto-detected, however *restore* may fail (or do something wrong) +if the assumption for restore logic is incorrect. This option is +not compatable with *--external* *dev*. + *--action-script* 'script':: Add an external action script to be executed at certain stages. The environment variable *CRTOOLS_SCRIPT_ACTION* is available From bb032cc3e218c4aee5394642caa59be3909b259a Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 18 Feb 2020 19:53:36 +0000 Subject: [PATCH 2329/4375] criu(8): Convert tabs to spaces Signed-off-by: Radostin Stoyanov --- Documentation/criu.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index 0ac29103a..ab63e461c 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -477,7 +477,7 @@ The 'mode' may be one of the following: *soft*::: Restore cgroup properties if only cgroup has been created by *criu*, otherwise do not restore properties. This is the - default if mode is unspecified. + default if mode is unspecified. *full*::: Always restore all cgroups and their properties. @@ -575,17 +575,17 @@ check* always checks Category 1 features unless *--feature* is specified which only checks a specified feature. *Category 1*::: Absolutely required. These are features like support for - */proc/PID/map_files*, *NETLINK_SOCK_DIAG* socket - monitoring, */proc/sys/kernel/ns_last_pid* etc. + */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* and others that are only - required if a process being dumped or restored - is using those. + like AIO remap, */dev/net/tun* and others that are only + required if a process being dumped or restored + is using those. *Category 3*::: Experimental. These are features like *task-diag* that - are used for experimental purposes (mostly - during development). + are used for experimental purposes (mostly + during development). If there are no errors or warnings, *criu* prints "Looks good." and its exit code is 0. From 563c5e5e763949de7b1c48bd04c777db17d768e1 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 4 Feb 2020 09:10:49 +0000 Subject: [PATCH 2330/4375] seize: prepare for cgroupv2 freezer The cgroupv2 freezer does not return the same strings as v1. Instead of THAWED and FROZEN v2 returns 0 and 1 (strings). This prepares the seize code to use 0 and 1 everywhere and THAWED and FROZEN only for v1 specific code paths. Signed-off-by: Adrian Reber --- criu/seize.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/criu/seize.c b/criu/seize.c index fd314666f..14cd82417 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -30,7 +30,14 @@ static const char frozen[] = "FROZEN"; static const char freezing[] = "FREEZING"; static const char thawed[] = "THAWED"; -static const char *get_freezer_state(int fd) +enum freezer_state { + FREEZER_ERROR = -1, + THAWED, + FROZEN, + FREEZING +}; + +static enum freezer_state get_freezer_state(int fd) { char state[32]; int ret; @@ -52,15 +59,15 @@ static const char *get_freezer_state(int fd) pr_debug("freezer.state=%s\n", state); if (strcmp(state, frozen) == 0) - return frozen; + return FROZEN; else if (strcmp(state, freezing) == 0) - return freezing; + return FREEZING; else if (strcmp(state, thawed) == 0) - return thawed; + return THAWED; pr_err("Unknown freezer state: %s\n", state); err: - return NULL; + return FREEZER_ERROR; } static bool freezer_thawed; @@ -98,7 +105,7 @@ static int freezer_restore_state(void) static int processes_to_wait; static pid_t *processes_to_wait_pids; -static int seize_cgroup_tree(char *root_path, const char *state) +static int seize_cgroup_tree(char *root_path, enum freezer_state state) { DIR *dir; struct dirent *de; @@ -134,7 +141,7 @@ static int seize_cgroup_tree(char *root_path, const char *state) if (!compel_interrupt_task(pid)) { pr_debug("SEIZE %d: success\n", pid); processes_to_wait++; - } else if (state == frozen) { + } else if (state == FROZEN) { char buf[] = "/proc/XXXXXXXXXX/exe"; struct stat st; @@ -332,7 +339,7 @@ static int freeze_processes(void) { int fd, exit_code = -1; char path[PATH_MAX]; - const char *state = thawed; + enum freezer_state state = THAWED; static const unsigned long step_ms = 100; unsigned long nr_attempts = (opts.timeout * 1000000) / step_ms; @@ -361,11 +368,11 @@ static int freeze_processes(void) return -1; } state = get_freezer_state(fd); - if (!state) { + if (state == FREEZER_ERROR) { close(fd); return -1; } - if (state == thawed) { + if (state == THAWED) { freezer_thawed = true; lseek(fd, 0, SEEK_SET); @@ -384,12 +391,12 @@ static int freeze_processes(void) */ for (; i <= nr_attempts; i++) { state = get_freezer_state(fd); - if (!state) { + if (state == FREEZER_ERROR) { close(fd); return -1; } - if (state == frozen) + if (state == FROZEN) break; if (alarm_timeouted()) goto err; From 9f902e0c6b74ce2d7abf6a632d3abdf6b1370751 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 4 Feb 2020 09:53:51 +0000 Subject: [PATCH 2331/4375] seize: factor out opening and writing the freezer state More preparations for cgroupv2 freezer. Factor our the freezer state opening and writing to have one location where to handle v1 and v2 differences. Signed-off-by: Adrian Reber --- criu/seize.c | 81 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/criu/seize.c b/criu/seize.c index 14cd82417..b53707e44 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -20,6 +20,7 @@ #include "seccomp.h" #include "seize.h" #include "stats.h" +#include "string.h" #include "xmalloc.h" #include "util.h" #include @@ -77,13 +78,39 @@ const char *get_real_freezer_state(void) return freezer_thawed ? thawed : frozen; } -static int freezer_restore_state(void) +static int freezer_write_state(int fd, enum freezer_state new_state) { - int fd; - char path[PATH_MAX]; + char state[32]; + int ret; - if (!opts.freeze_cgroup || freezer_thawed) - return 0; + if (new_state == THAWED) { + if (strlcpy(state, thawed, sizeof(state)) >= sizeof(state)) + return -1; + } else if (new_state == FROZEN) { + if (strlcpy(state, frozen, sizeof(state)) >= sizeof(state)) + return -1; + } else { + return -1; + } + + ret = lseek(fd, 0, SEEK_SET); + if (ret < 0) { + pr_perror("Unable to seek freezer FD"); + return -1; + } + if (write(fd, state, sizeof(state)) != sizeof(state)) { + pr_perror("Unable to %s tasks", + (new_state == THAWED) ? "thaw" : "freeze"); + return -1; + } + + return 0; +} + +static int freezer_open(void) +{ + char path[PATH_MAX]; + int fd; snprintf(path, sizeof(path), "%s/freezer.state", opts.freeze_cgroup); fd = open(path, O_RDWR); @@ -92,13 +119,24 @@ static int freezer_restore_state(void) return -1; } - if (write(fd, frozen, sizeof(frozen)) != sizeof(frozen)) { - pr_perror("Unable to freeze tasks"); - close(fd); + return fd; +} + +static int freezer_restore_state(void) +{ + int fd; + int ret; + + if (!opts.freeze_cgroup || freezer_thawed) + return 0; + + fd = freezer_open(); + if (fd < 0) return -1; - } + + ret = freezer_write_state(fd, FROZEN); close(fd); - return 0; + return ret; } /* A number of tasks in a freezer cgroup which are not going to be dumped */ @@ -338,7 +376,6 @@ static int log_unfrozen_stacks(char *root) static int freeze_processes(void) { int fd, exit_code = -1; - char path[PATH_MAX]; enum freezer_state state = THAWED; static const unsigned long step_ms = 100; @@ -361,12 +398,10 @@ static int freeze_processes(void) pr_debug("freezing processes: %lu attempts with %lu ms steps\n", nr_attempts, step_ms); - snprintf(path, sizeof(path), "%s/freezer.state", opts.freeze_cgroup); - fd = open(path, O_RDWR); - if (fd < 0) { - pr_perror("Unable to open %s", path); + fd = freezer_open(); + if (fd < 0) return -1; - } + state = get_freezer_state(fd); if (state == FREEZER_ERROR) { close(fd); @@ -375,9 +410,7 @@ static int freeze_processes(void) if (state == THAWED) { freezer_thawed = true; - lseek(fd, 0, SEEK_SET); - if (write(fd, frozen, sizeof(frozen)) != sizeof(frozen)) { - pr_perror("Unable to freeze tasks"); + if (freezer_write_state(fd, FROZEN)) { close(fd); return -1; } @@ -427,13 +460,9 @@ static int freeze_processes(void) } err: - if (exit_code == 0 || freezer_thawed) { - lseek(fd, 0, SEEK_SET); - if (write(fd, thawed, sizeof(thawed)) != sizeof(thawed)) { - pr_perror("Unable to thaw tasks"); - exit_code = -1; - } - } + if (exit_code == 0 || freezer_thawed) + exit_code = freezer_write_state(fd, THAWED); + if (close(fd)) { pr_perror("Unable to thaw tasks"); return -1; From 10416bcbcb3c2ab4732971083f99d9390f8d168b Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 4 Feb 2020 13:38:42 +0000 Subject: [PATCH 2332/4375] seize: support cgroup v2 freezer This adds support to checkpoint processes using the cgroup v2 freezer. Signed-off-by: Adrian Reber --- criu/seize.c | 150 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 133 insertions(+), 17 deletions(-) diff --git a/criu/seize.c b/criu/seize.c index b53707e44..0ba2d9b1d 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -38,7 +38,10 @@ enum freezer_state { FREEZING }; -static enum freezer_state get_freezer_state(int fd) +/* Track if we are running on cgroup v2 system. */ +static bool cgroup_v2 = false; + +static enum freezer_state get_freezer_v1_state(int fd) { char state[32]; int ret; @@ -71,6 +74,70 @@ err: return FREEZER_ERROR; } +static enum freezer_state get_freezer_v2_state(int fd) +{ + int exit_code = FREEZER_ERROR; + char path[PATH_MAX]; + FILE *event; + char state; + int ret; + + /* + * cgroupv2 freezer uses cgroup.freeze to control the state. The file + * can return 0 or 1. 1 means the cgroup is frozen; 0 means it is not + * frozen. Writing 1 to an unfrozen cgroup can freeze it. Freezing can + * take some time and if the cgroup has finished freezing can be + * seen in cgroup.events: frozen 0|1. + */ + + ret = lseek(fd, 0, SEEK_SET); + if (ret < 0) { + pr_perror("Unable to seek freezer FD"); + goto out; + } + ret = read(fd, &state, 1); + if (ret <= 0) { + pr_perror("Unable to read from freezer FD"); + goto out; + } + pr_debug("cgroup.freeze=%c\n", state); + if (state == '0') { + exit_code = THAWED; + goto out; + } + + snprintf(path, sizeof(path), "%s/cgroup.events", opts.freeze_cgroup); + event = fopen(path, "r"); + if (event == NULL) { + pr_perror("Unable to open %s", path); + goto out; + } + while (fgets(path, sizeof(path), event)) { + if (strncmp(path, "frozen", 6) != 0) { + continue; + } else if (strncmp(path, "frozen 0", 8) == 0) { + exit_code = FREEZING; + goto close; + } else if (strncmp(path, "frozen 1", 8) == 0) { + exit_code = FROZEN; + goto close; + } + } + + pr_err("Unknown freezer state: %c\n", state); +close: + fclose(event); +out: + return exit_code; +} + +static enum freezer_state get_freezer_state(int fd) +{ + if (cgroup_v2) + return get_freezer_v2_state(fd); + return get_freezer_v1_state(fd); +} + static bool freezer_thawed; const char *get_real_freezer_state(void) @@ -80,15 +147,23 @@ const char *get_real_freezer_state(void) static int freezer_write_state(int fd, enum freezer_state new_state) { - char state[32]; + char state[32] = {0}; int ret; if (new_state == THAWED) { - if (strlcpy(state, thawed, sizeof(state)) >= sizeof(state)) - return -1; + if (cgroup_v2) + state[0] = '0'; + else + if (strlcpy(state, thawed, sizeof(state)) >= + sizeof(state)) + return -1; } else if (new_state == FROZEN) { - if (strlcpy(state, frozen, sizeof(state)) >= sizeof(state)) - return -1; + if (cgroup_v2) + state[0] = '1'; + else + if (strlcpy(state, frozen, sizeof(state)) >= + sizeof(state)) + return -1; } else { return -1; } @@ -109,10 +184,13 @@ static int freezer_write_state(int fd, enum freezer_state new_state) static int freezer_open(void) { + const char freezer_v1[] = "freezer.state"; + const char freezer_v2[] = "cgroup.freeze"; char path[PATH_MAX]; int fd; - snprintf(path, sizeof(path), "%s/freezer.state", opts.freeze_cgroup); + snprintf(path, sizeof(path), "%s/%s", opts.freeze_cgroup, + cgroup_v2 ? freezer_v2 : freezer_v1); fd = open(path, O_RDWR); if (fd < 0) { pr_perror("Unable to open %s", path); @@ -139,6 +217,22 @@ static int freezer_restore_state(void) return ret; } +static FILE *freezer_open_thread_list(char *root_path) +{ + char path[PATH_MAX]; + FILE *f; + + snprintf(path, sizeof(path), "%s/%s", root_path, + cgroup_v2 ? "cgroup.threads" : "tasks"); + f = fopen(path, "r"); + if (f == NULL) { + pr_perror("Unable to open %s", path); + return NULL; + } + + return f; +} + /* A number of tasks in a freezer cgroup which are not going to be dumped */ static int processes_to_wait; static pid_t *processes_to_wait_pids; @@ -154,12 +248,10 @@ static int seize_cgroup_tree(char *root_path, enum freezer_state state) * New tasks can appear while a freezer state isn't * frozen, so we need to catch all new tasks. */ - snprintf(path, sizeof(path), "%s/tasks", root_path); - f = fopen(path, "r"); - if (f == NULL) { - pr_perror("Unable to open %s", path); + f = freezer_open_thread_list(root_path); + if (f == NULL) return -1; - } + while (fgets(path, sizeof(path), f)) { pid_t pid; int ret; @@ -306,12 +398,10 @@ static int log_unfrozen_stacks(char *root) char path[PATH_MAX]; FILE *f; - snprintf(path, sizeof(path), "%s/tasks", root); - f = fopen(path, "r"); - if (f == NULL) { - pr_perror("Unable to open %s", path); + f = freezer_open_thread_list(root); + if (f == NULL) return -1; - } + while (fgets(path, sizeof(path), f)) { pid_t pid; int ret, stack; @@ -820,6 +910,27 @@ err_close: return -1; } +static int cgroup_version(void) +{ + char path[PATH_MAX]; + + snprintf(path, sizeof(path), "%s/freezer.state", opts.freeze_cgroup); + if (access(path, F_OK) == 0) { + cgroup_v2 = false; + return 0; + } + + snprintf(path, sizeof(path), "%s/cgroup.freeze", opts.freeze_cgroup); + if (access(path, F_OK) == 0) { + cgroup_v2 = true; + return 0; + } + + pr_err("Neither a cgroupv1 (freezer.state) or cgroupv2 (cgroup.freeze) control file found.\n"); + + return -1; +} + int collect_pstree(void) { pid_t pid = root_item->pid->real; @@ -835,6 +946,11 @@ int collect_pstree(void) */ alarm(opts.timeout); + if (opts.freeze_cgroup && cgroup_version()) + goto err; + + pr_debug("Detected cgroup V%d freezer\n", cgroup_v2 ? 2 : 1); + if (opts.freeze_cgroup && freeze_processes()) goto err; From 4129d3262ad2d2ac6875c2c86d565528969d8e72 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 5 Feb 2020 09:39:32 +0000 Subject: [PATCH 2333/4375] cgroup2: add minimal cgroup2 support The runc test cases are (sometimes) mounting a cgroup inside of the container. For these tests to succeed, let CRIU know that cgroup2 exists and how to restore such a mount. This does not fix any specific cgroup2 settings, it just enables CRIU to mount cgroup2 in the restored container. Signed-off-by: Adrian Reber --- criu/filesystems.c | 5 +++++ images/mnt.proto | 2 ++ 2 files changed, 7 insertions(+) diff --git a/criu/filesystems.c b/criu/filesystems.c index 1e4550b37..d76b18291 100644 --- a/criu/filesystems.c +++ b/criu/filesystems.c @@ -747,6 +747,11 @@ static struct fstype fstypes[] = { .code = FSTYPE__CGROUP, .parse = cgroup_parse, .sb_equal = cgroup_sb_equal, + }, { + .name = "cgroup2", + .code = FSTYPE__CGROUP2, + .parse = cgroup_parse, + .sb_equal = cgroup_sb_equal, }, { .name = "aufs", .code = FSTYPE__AUFS, diff --git a/images/mnt.proto b/images/mnt.proto index 4160acbf6..8983395ae 100644 --- a/images/mnt.proto +++ b/images/mnt.proto @@ -28,6 +28,8 @@ enum fstype { // RPC_PIPEFS = 20; // NFS = 21; // NFS4 = 22; + + CGROUP2 = 23; }; message mnt_entry { From ffe0896ed01790e62cd617cf01bc6a4076fa4e87 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 1 Mar 2020 04:26:12 +0300 Subject: [PATCH 2334/4375] fs: use __open_proc instead of open("/proc/...", ... ) Processes can run in a mount namespace without /proc. Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin --- criu/files-reg.c | 4 +--- criu/memfd.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index c2a55aeb3..0d0076666 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -778,14 +778,12 @@ static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_de if (S_ISREG(st->st_mode)) { int fd, ret; - char lpath[PSFDS]; /* * Reopen file locally since it may have no read * permissions when drained */ - sprintf(lpath, "/proc/self/fd/%d", _fd); - fd = open(lpath, O_RDONLY); + fd = open_proc(PROC_SELF, "fd/%d", _fd); if (fd < 0) { pr_perror("Can't open ghost original file"); goto err_out; diff --git a/criu/memfd.c b/criu/memfd.c index d17c10fb7..30ccdf22c 100644 --- a/criu/memfd.c +++ b/criu/memfd.c @@ -299,7 +299,6 @@ static int memfd_open_inode(struct memfd_inode *inode) int memfd_open(struct file_desc *d, u32 *fdflags) { - char lpath[PSFDS]; struct memfd_info *mfi; MemfdFileEntry *mfe; int fd, _fd; @@ -318,14 +317,13 @@ int memfd_open(struct file_desc *d, u32 *fdflags) goto err; /* Reopen the fd with original permissions */ - sprintf(lpath, "/proc/self/fd/%d", fd); flags = fdflags ? *fdflags : mfe->flags; /* * Ideally we should call compat version open() to not force the * O_LARGEFILE file flag with regular open(). It doesn't seem that * important though. */ - _fd = open(lpath, flags); + _fd = __open_proc(getpid(), 0, flags, "fd/%d", fd); if (_fd < 0) { pr_perror("Can't reopen memfd id=%d", mfe->id); goto err; From fce196d88df8363666922ac2fa2d6e23bb774289 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 29 Feb 2020 09:51:33 +0300 Subject: [PATCH 2335/4375] memfd: don't corrupt a state of the dumped fd Right now, criu uses a dumped fd to dump content of a memfd "file". Here are two reasons why we should not do this: * a state of a dumped fd doesn't have to be changed, but now criu calls lseek on it. This can be workarounded by using pread. * a dumped descriptor can be write-only. Reported-by: Mr Jenkins Cc: Nicolas Viennot Signed-off-by: Andrei Vagin --- criu/memfd.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/criu/memfd.c b/criu/memfd.c index 30ccdf22c..983e01b38 100644 --- a/criu/memfd.c +++ b/criu/memfd.c @@ -119,6 +119,7 @@ out: static struct memfd_inode *dump_unique_memfd_inode(int lfd, const char *name, const struct stat *st) { struct memfd_inode *inode; + int fd; list_for_each_entry(inode, &memfd_inodes, list) if ((inode->dev == st->st_dev) && (inode->ino == st->st_ino)) @@ -132,11 +133,19 @@ static struct memfd_inode *dump_unique_memfd_inode(int lfd, const char *name, co inode->ino = st->st_ino; inode->id = memfd_inode_ids++; - if (dump_memfd_inode(lfd, inode, name, st)) { + fd = open_proc(PROC_SELF, "fd/%d", lfd); + if (fd < 0) { xfree(inode); return NULL; } + if (dump_memfd_inode(fd, inode, name, st)) { + close(fd); + xfree(inode); + return NULL; + } + close(fd); + list_add_tail(&inode->list, &memfd_inodes); return inode; From 58fd63042c925c6422f5453b9a13147ebd2a6769 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 1 Mar 2020 01:04:20 +0300 Subject: [PATCH 2336/4375] zdtm/inhfd: force python to read new data from a file python 2.7 doesn't call the read system call if it's read file to the end once. The next seek allows to workaround this problem. inhfd/memfd.py hangs due to this issue. Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin --- test/zdtm.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 4110b5142..0bd7b84cc 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -697,7 +697,10 @@ class inhfd_test: # regular files, so we loop. data = b'' while not data: - data = peer_file.read(16) + # In python 2.7, peer_file.read() doesn't call the read + # system call if it's read file to the end once. The + # next seek allows to workaround this problem. + data = os.read(peer_file.fileno(), 16) time.sleep(0.1) except Exception as e: print("Unable to read a peer file: %s" % e) From f167d1f4e9eb24dfbda077746f25cfdf8a2b59b9 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 7 Feb 2020 15:59:45 +0300 Subject: [PATCH 2337/4375] fown: Don't fail on dumping files opened with O_PATH O_PATH opened files are special: they have empty file operations in kernel space, so there not that much we can do with them, even setting position is not allowed. Same applies to a signal number for owner settings. Signed-off-by: Cyrill Gorcunov Co-developed-by: Alexander Mikhalitsyn Signed-off-by: Alexander Mikhalitsyn (Virtuozzo) --- criu/files-reg.c | 16 +++++++--- criu/files.c | 5 ++- criu/pie/parasite.c | 75 +++++++++++++++++++++++++++++---------------- 3 files changed, 64 insertions(+), 32 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 0d0076666..d1d1ee5af 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -1776,11 +1776,17 @@ static int do_open_reg(int ns_root_fd, struct reg_file_info *rfi, void *arg) if (fd < 0) return fd; - if ((rfi->rfe->pos != -1ULL) && - lseek(fd, rfi->rfe->pos, SEEK_SET) < 0) { - pr_perror("Can't restore file pos"); - close(fd); - return -1; + /* + * O_PATH opened files carry empty fops in kernel, + * just ignore positioning at all. + */ + if (!(rfi->rfe->flags & O_PATH)) { + if (rfi->rfe->pos != -1ULL && + lseek(fd, rfi->rfe->pos, SEEK_SET) < 0) { + pr_perror("Can't restore file pos"); + close(fd); + return -1; + } } return fd; diff --git a/criu/files.c b/criu/files.c index f7963bf54..3f1d77931 100644 --- a/criu/files.c +++ b/criu/files.c @@ -399,7 +399,10 @@ static int fill_fd_params(struct pid *owner_pid, int fd, int lfd, pr_info("%d fdinfo %d: pos: %#16"PRIx64" flags: %16o/%#x\n", owner_pid->real, fd, p->pos, p->flags, (int)p->fd_flags); - ret = fcntl(lfd, F_GETSIG, 0); + if (p->flags & O_PATH) + ret = 0; + else + ret = fcntl(lfd, F_GETSIG, 0); if (ret < 0) { pr_perror("Can't get owner signum on %d", lfd); return -1; diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index 387a976da..64b5bbb3e 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -317,15 +317,60 @@ grps_err: return -1; } +static int fill_fds_fown(int fd, struct fd_opts *p) +{ + int flags, ret; + struct f_owner_ex owner_ex; + uint32_t v[2]; + + /* + * For O_PATH opened files there is no owner at all. + */ + flags = sys_fcntl(fd, F_GETFL, 0); + if (flags < 0) { + pr_err("fcntl(%d, F_GETFL) -> %d\n", fd, flags); + return -1; + } + if (flags & O_PATH) { + p->fown.pid = 0; + return 0; + } + + ret = sys_fcntl(fd, F_GETOWN_EX, (long)&owner_ex); + if (ret) { + pr_err("fcntl(%d, F_GETOWN_EX) -> %d\n", fd, ret); + return -1; + } + + /* + * Simple case -- nothing is changed. + */ + if (owner_ex.pid == 0) { + p->fown.pid = 0; + return 0; + } + + ret = sys_fcntl(fd, F_GETOWNER_UIDS, (long)&v); + if (ret) { + pr_err("fcntl(%d, F_GETOWNER_UIDS) -> %d\n", fd, ret); + return -1; + } + + p->fown.uid = v[0]; + p->fown.euid = v[1]; + p->fown.pid_type = owner_ex.type; + p->fown.pid = owner_ex.pid; + + return 0; +} + static int fill_fds_opts(struct parasite_drain_fd *fds, struct fd_opts *opts) { int i; for (i = 0; i < fds->nr_fds; i++) { - int flags, fd = fds->fds[i], ret; + int flags, fd = fds->fds[i]; struct fd_opts *p = opts + i; - struct f_owner_ex owner_ex; - uint32_t v[2]; flags = sys_fcntl(fd, F_GETFD, 0); if (flags < 0) { @@ -335,30 +380,8 @@ static int fill_fds_opts(struct parasite_drain_fd *fds, struct fd_opts *opts) p->flags = (char)flags; - ret = sys_fcntl(fd, F_GETOWN_EX, (long)&owner_ex); - if (ret) { - pr_err("fcntl(%d, F_GETOWN_EX) -> %d\n", fd, ret); + if (fill_fds_fown(fd, p)) return -1; - } - - /* - * Simple case -- nothing is changed. - */ - if (owner_ex.pid == 0) { - p->fown.pid = 0; - continue; - } - - ret = sys_fcntl(fd, F_GETOWNER_UIDS, (long)&v); - if (ret) { - pr_err("fcntl(%d, F_GETOWNER_UIDS) -> %d\n", fd, ret); - return -1; - } - - p->fown.uid = v[0]; - p->fown.euid = v[1]; - p->fown.pid_type = owner_ex.type; - p->fown.pid = owner_ex.pid; } return 0; From 8b9c1f4c5bebd501f544cfe81534e4386f85246f Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 7 Feb 2020 15:59:55 +0300 Subject: [PATCH 2338/4375] zdtm: add a test for files opened with O_PATH On these test without the patch ("fown: Don't fail on dumping files opened wit O_PATH") we trigger these errors: Error (criu/pie/parasite.c:340): fcntl(4, F_GETOWN_EX) -> -9 Error (criu/files.c:403): Can't get owner signum on 18: Bad file descriptor Error (criu/files-reg.c:1887): Can't restore file pos: Bad file descriptor Signed-off-by: Pavel Tikhomirov Signed-off-by: Alexander Mikhalitsyn (Virtuozzo) --- test/zdtm/static/Makefile | 1 + test/zdtm/static/opath_file.c | 95 +++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 test/zdtm/static/opath_file.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 5afd18cd6..035b8fa9c 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -363,6 +363,7 @@ TST_DIR = \ private_bind_propagation \ ghost_on_rofs \ overmounted_file \ + opath_file \ TST_DIR_FILE = \ chroot \ diff --git a/test/zdtm/static/opath_file.c b/test/zdtm/static/opath_file.c new file mode 100644 index 000000000..602a5af27 --- /dev/null +++ b/test/zdtm/static/opath_file.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" + +#define TEST_FILE "test_file" +#define BUF_SIZE 4096 +#define fdinfo_field(str, field) !strncmp(str, field":", sizeof(field)) +#define pr_debug(format, arg...) test_msg("DBG: %s:%d: " format, __FILE__, __LINE__, ## arg) + +const char *test_doc = "Check open file with O_PATH preserved"; +const char *test_author = "Pavel Tikhomirov "; + +char *dirname; +TEST_OPTION(dirname, string, "directory name", 1); + +struct fdinfo { + int flags; +}; + +static int parse_self_fdinfo(int fd, struct fdinfo *fi) +{ + char path[PATH_MAX], line[BUF_SIZE]; + FILE *file; + int ret = -1; + unsigned long long val; + + snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd); + file = fopen(path, "r"); + if (!file) { + pr_perror("fopen"); + return -1; + } + + while (fgets(line, sizeof(line), file)) { + if (fdinfo_field(line, "flags")) { + if (sscanf(line, "%*s %llu", &val) != 1) { + pr_err("failed to read flags: %s", line); + goto fail; + } + pr_debug("Open flags = %llu\n", val); + fi->flags = val; + ret = 0; + break; + } + } +fail: + fclose(file); + return ret; +} + +int main(int argc, char **argv) +{ + char test_file[PATH_MAX]; + struct fdinfo fi; + int fd; + + test_init(argc, argv); + + if (mkdir(dirname, 0700)) { + pr_perror("can't make directory %s", dirname); + exit(1); + } + + snprintf(test_file, sizeof(test_file), "%s/%s", dirname, TEST_FILE); + fd = creat(test_file, 0644); + if (fd == -1) { + pr_perror("cat't create %s", test_file); + return 1; + } + close(fd); + + fd = open(test_file, O_PATH); + if (fd == -1) { + pr_perror("cat't open file %s with O_PATH", test_file); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (parse_self_fdinfo(fd, &fi)) + return 1; + + if (!(fi.flags & O_PATH)) { + fail("File lost O_PATH open flag"); + return 1; + } + + close(fd); + pass(); + return 0; +} From 1936608ce42283b6c5aa007c883092bb2776af4b Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Fri, 7 Feb 2020 16:00:01 +0300 Subject: [PATCH 2339/4375] files: allow dumping opened symlinks To really open symlink file and not the regular file below it, one needs to do open with O_PATH|O_NOFOLLOW flags. Looks like systemd started to open /etc/localtime symlink this way sometimes, and before that nobody actually used this and thus we never supported this in CRIU. Error (criu/files-ext.c:96): Can't dump file 11 of that type [120777] (unknown /etc/localtime) Looks like it is quiet easy to support, as c/r of symlink file is almost the same as c/r of regular one. We need to only make fstatat not following links in check_path_remap. Also we need to take into account support of ghost symlinks. Signed-off-by: Alexander Mikhalitsyn (Virtuozzo) Co-developed-by: Pavel Tikhomirov Signed-off-by: Pavel Tikhomirov --- criu/files-reg.c | 88 +++++++++++++++++++++++++++++++++++++---- criu/files.c | 3 +- images/ghost-file.proto | 2 + 3 files changed, 84 insertions(+), 9 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index d1d1ee5af..b53e9b080 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -282,19 +282,53 @@ static int mkreg_ghost(char *path, GhostFileEntry *gfe, struct cr_img *img) return ret; } +static int mklnk_ghost(char *path, GhostFileEntry *gfe) +{ + if (!gfe->symlnk_target) { + pr_err("Ghost symlink target is NULL for %s. Image from old CRIU?\n", path); + return -1; + } + + if (symlink(gfe->symlnk_target, path) < 0) { + /* + * ENOENT case is OK + * Take a look closer on create_ghost() function + */ + if (errno != ENOENT) + pr_perror("symlink(%s, %s) failed", gfe->symlnk_target, path); + return -1; + } + + return 0; +} + static int ghost_apply_metadata(const char *path, GhostFileEntry *gfe) { struct timeval tv[2]; int ret = -1; - if (chown(path, gfe->uid, gfe->gid) < 0) { - pr_perror("Can't reset user/group on ghost %s", path); - goto err; - } + if (S_ISLNK(gfe->mode)) { + if (lchown(path, gfe->uid, gfe->gid) < 0) { + pr_perror("Can't reset user/group on ghost %s", path); + goto err; + } - if (chmod(path, gfe->mode)) { - pr_perror("Can't set perms %o on ghost %s", gfe->mode, path); - goto err; + /* + * We have no lchmod() function, and fchmod() will fail on + * O_PATH | O_NOFOLLOW fd. Yes, we have fchmodat() + * function and flag AT_SYMLINK_NOFOLLOW described in + * man 2 fchmodat, but it is not currently implemented. %) + */ + } else { + if (chown(path, gfe->uid, gfe->gid) < 0) { + pr_perror("Can't reset user/group on ghost %s", path); + goto err; + } + + if (chmod(path, gfe->mode)) { + pr_perror("Can't set perms %o on ghost %s", gfe->mode, path); + goto err; + } } if (gfe->atim) { @@ -353,6 +387,9 @@ again: } else if (S_ISDIR(gfe->mode)) { if ((ret = mkdirpat(AT_FDCWD, path, gfe->mode)) < 0) msg = "Can't make ghost dir"; + } else if (S_ISLNK(gfe->mode)) { + if ((ret = mklnk_ghost(path, gfe)) < 0) + msg = "Can't create ghost symlink"; } else { if ((ret = mkreg_ghost(path, gfe, img)) < 0) msg = "Can't create ghost regfile"; @@ -740,6 +777,7 @@ static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_de int exit_code = -1; GhostFileEntry gfe = GHOST_FILE_ENTRY__INIT; Timeval atim = TIMEVAL__INIT, mtim = TIMEVAL__INIT; + char pathbuf[PATH_MAX]; pr_info("Dumping ghost file contents (id %#x)\n", id); @@ -773,6 +811,36 @@ static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_de gfe.size = st->st_size; } + /* + * We set gfe.symlnk_target only if we need to dump + * symlink content, otherwise we leave it NULL. + * It will be taken into account on restore in mklnk_ghost function. + */ + if (S_ISLNK(st->st_mode)) { + ssize_t ret; + + /* + * We assume that _fd opened with O_PATH | O_NOFOLLOW + * flags because S_ISLNK(st->st_mode). With current kernel version, + * it's looks like correct assumption in any case. + */ + ret = readlinkat(_fd, "", pathbuf, sizeof(pathbuf) - 1); + if (ret < 0) { + pr_perror("Can't readlinkat"); + goto err_out; + } + + pathbuf[ret] = 0; + + if (ret != st->st_size) { + pr_err("Buffer for readlinkat is too small: ret %zd, st_size %"PRId64", buf %u %s\n", + ret, st->st_size, PATH_MAX, pathbuf); + goto err_out; + } + + gfe.symlnk_target = pathbuf; + } + if (pb_write_one(img, &gfe, PB_GHOST_FILE)) goto err_out; @@ -1116,6 +1184,7 @@ static int check_path_remap(struct fd_link *link, const struct fd_parms *parms, int ret, mntns_root; struct stat pst; const struct stat *ost = &parms->stat; + int flags = 0; if (parms->fs_type == PROC_SUPER_MAGIC) { /* The file points to /proc/pid/ where pid is a dead @@ -1212,7 +1281,10 @@ static int check_path_remap(struct fd_link *link, const struct fd_parms *parms, if (mntns_root < 0) return -1; - ret = fstatat(mntns_root, rpath, &pst, 0); + if (S_ISLNK(parms->stat.st_mode)) + flags = AT_SYMLINK_NOFOLLOW; + + ret = fstatat(mntns_root, rpath, &pst, flags); if (ret < 0) { /* * Linked file, but path is not accessible (unless any diff --git a/criu/files.c b/criu/files.c index 3f1d77931..f6ba39a30 100644 --- a/criu/files.c +++ b/criu/files.c @@ -545,7 +545,8 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, return do_dump_gen_file(&p, lfd, ops, e); } - if (S_ISREG(p.stat.st_mode) || S_ISDIR(p.stat.st_mode)) { + if (S_ISREG(p.stat.st_mode) || S_ISDIR(p.stat.st_mode) || + S_ISLNK(p.stat.st_mode)) { if (fill_fdlink(lfd, &p, &link)) return -1; diff --git a/images/ghost-file.proto b/images/ghost-file.proto index eda466451..0576089fd 100644 --- a/images/ghost-file.proto +++ b/images/ghost-file.proto @@ -15,6 +15,8 @@ message ghost_file_entry { optional timeval mtim = 8; optional bool chunks = 9; optional uint64 size = 10; + /* this field makes sense only when S_ISLNK(mode) */ + optional string symlnk_target = 11; } message ghost_chunk_entry { From 73e0ed3b8ae2a87d4232dd4a39ce3dab4edb1f24 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 7 Feb 2020 16:00:05 +0300 Subject: [PATCH 2340/4375] zdtm: add a test on open symlink migration Signed-off-by: Pavel Tikhomirov Co-Developed-by: Vitaly Ostrosablin Signed-off-by: Vitaly Ostrosablin Signed-off-by: Alexander Mikhalitsyn (Virtuozzo) --- test/zdtm/static/Makefile | 3 + test/zdtm/static/opath_file.c | 2 +- test/zdtm/static/symlink.c | 102 ++++++++++++++++++++++++++++++++++ test/zdtm/static/symlink01.c | 1 + 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 test/zdtm/static/symlink.c create mode 120000 test/zdtm/static/symlink01.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 035b8fa9c..ee69612c7 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -364,6 +364,8 @@ TST_DIR = \ ghost_on_rofs \ overmounted_file \ opath_file \ + symlink \ + symlink01 \ TST_DIR_FILE = \ chroot \ @@ -539,6 +541,7 @@ clone_fs: LDLIBS += -pthread # we have to explicitly specify both .o and .d for this case: netns_sub_veth.o netns_sub_veth.d: CPPFLAGS += $(call pkg-cflags, libnl-3.0) netns_sub_veth: LDLIBS += $(call pkg-libs, libnl-route-3.0 libnl-3.0) +symlink01: CFLAGS += -DZDTM_UNLINK_SYMLINK socket-tcp-fin-wait1: CFLAGS += -D ZDTM_TCP_FIN_WAIT1 socket-tcp-fin-wait2: CFLAGS += -D ZDTM_TCP_FIN_WAIT2 diff --git a/test/zdtm/static/opath_file.c b/test/zdtm/static/opath_file.c index 602a5af27..943f4eddb 100644 --- a/test/zdtm/static/opath_file.c +++ b/test/zdtm/static/opath_file.c @@ -36,7 +36,7 @@ static int parse_self_fdinfo(int fd, struct fdinfo *fi) while (fgets(line, sizeof(line), file)) { if (fdinfo_field(line, "flags")) { - if (sscanf(line, "%*s %llu", &val) != 1) { + if (sscanf(line, "%*s %llo", &val) != 1) { pr_err("failed to read flags: %s", line); goto fail; } diff --git a/test/zdtm/static/symlink.c b/test/zdtm/static/symlink.c new file mode 100644 index 000000000..074c80052 --- /dev/null +++ b/test/zdtm/static/symlink.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +#define TEST_FILE "test_file" +#define TEST_SYMLINK "test_symlink" + +const char *test_doc = "Check open symlink preserved"; +const char *test_author = "Pavel Tikhomirov "; + +char *dirname; +TEST_OPTION(dirname, string, "directory name", 1); + +int main(int argc, char **argv) +{ + char test_symlink[PATH_MAX]; + char test_file[PATH_MAX]; + char pathbuf[PATH_MAX]; + struct stat stb, sta; + int ret, fd; + + test_init(argc, argv); + + if (mkdir(dirname, 0700)) { + pr_perror("can't make directory %s", dirname); + exit(1); + } + + snprintf(test_file, sizeof(test_file), "%s/%s", dirname, TEST_FILE); + ret = creat(test_file, 0644); + if (ret == -1) { + pr_perror("cat't create %s", test_file); + return 1; + } + close(ret); + + snprintf(test_symlink, sizeof(test_symlink), "%s/%s", dirname, TEST_SYMLINK); + ret = symlink(test_file, test_symlink); + if (ret == -1) { + pr_perror("cat't symlink to %s", test_symlink); + return 1; + } + + fd = open(test_symlink, O_PATH | O_NOFOLLOW); + if (fd == -1) { + pr_perror("cat't open symlink %s", test_symlink); + return 1; + } + + ret = fstat(fd, &sta); + if (ret == -1) { + pr_perror("cat't fstat %s", test_symlink); + return 1; + } + + if (!S_ISLNK(sta.st_mode)) { + pr_perror("file is not symlink %s", test_symlink); + return 1; + } + +#ifdef ZDTM_UNLINK_SYMLINK + if (unlink(test_symlink)) { + pr_perror("can't unlink symlink %s", test_symlink); + return 1; + } +#endif + + test_daemon(); + test_waitsig(); + + ret = fstat(fd, &stb); + if (ret == -1) { + fail("cat't fstat %s", test_symlink); + return 1; + } + + if (!S_ISLNK(stb.st_mode)) { + fail("file is not symlink %s", test_symlink); + return 1; + } + + ret = readlinkat(fd, "", pathbuf, sizeof(pathbuf) - 1); + if (ret < 0) { + fail("Can't readlinkat"); + return 1; + } + pathbuf[ret] = 0; + + if (strcmp(test_file, pathbuf)) { + fail("symlink points to %s but %s expected", pathbuf, test_file); + return 1; + } + + close(fd); + pass(); + return 0; +} diff --git a/test/zdtm/static/symlink01.c b/test/zdtm/static/symlink01.c new file mode 120000 index 000000000..e2d071ea4 --- /dev/null +++ b/test/zdtm/static/symlink01.c @@ -0,0 +1 @@ +symlink.c \ No newline at end of file From 065ff6f4151805fe50cc881ef506b6ae6407ec57 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 5 Mar 2020 08:30:23 +0300 Subject: [PATCH 2341/4375] zdtm/fifo_loop: don't try to write more than pipe size ... otherwise write() can block. Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin --- test/zdtm/transition/fifo_loop.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/test/zdtm/transition/fifo_loop.c b/test/zdtm/transition/fifo_loop.c index 2e28320ba..b028c2fd5 100644 --- a/test/zdtm/transition/fifo_loop.c +++ b/test/zdtm/transition/fifo_loop.c @@ -39,6 +39,7 @@ int main(int argc, char **argv) int i; uint8_t buf[0x100000]; char *file_path; + int pipe_size; test_init(argc, argv); @@ -104,6 +105,13 @@ int main(int argc, char **argv) exit(1); } + pipe_size = fcntl(writefd, F_SETPIPE_SZ, sizeof(buf)); + if (pipe_size != sizeof(buf)) { + pr_perror("fcntl(writefd, F_GETPIPE_SZ) -> %d", pipe_size); + kill(0, SIGKILL); + exit(1); + } + file_path = path[i - 1]; readfd = open(file_path, O_RDONLY); if (readfd < 0) { @@ -138,13 +146,14 @@ int main(int argc, char **argv) for (p = rbuf, len = wlen; len > 0; p += rlen, len -= rlen) { rlen = read(readfd, p, len); + if (rlen < 0 && errno == EINTR) { + continue; + } + if (rlen <= 0) break; } - if (rlen < 0 && errno == EINTR) - continue; - if (len > 0) { fail("read failed: %m\n"); ret = 1; From 62ad2f6095b466bfade1af6fea60bcb0fa1505ec Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 5 Mar 2020 14:45:34 +0000 Subject: [PATCH 2342/4375] criu: Remove compel.h includes The plan is to remove "compel.h". That file only includes other headers (which may be not needed). If we aim for one-include-for-compel, we could instead paste all subheaders into "compel.h". Rather, I think it's worth to migrate to more fine-grained compel headers than follow the strategy 'one header to rule them all'. Further, the header creates problems for cross-compilation: it's included in files, those are used by host-compel. Which rightfully confuses compiler/linker as host's definitions for fpu regs/other platform details get drained into host's compel. As a first step - stop including "compel.h" in criu. Signed-off-by: Dmitry Safonov --- criu/aio.c | 2 +- criu/arch/aarch64/crtools.c | 2 +- criu/arch/arm/crtools.c | 3 +-- criu/arch/ppc64/crtools.c | 2 +- criu/arch/s390/crtools.c | 2 +- criu/arch/x86/crtools.c | 2 +- criu/arch/x86/sys-exec-tbl.c | 1 - criu/cr-restore.c | 1 - criu/include/proc_parse.h | 2 +- criu/kerndat.c | 1 - criu/mem.c | 2 +- criu/parasite-syscall.c | 2 -- criu/pie/pie-relocs.h | 2 -- criu/seize.c | 1 - criu/vdso.c | 1 - 15 files changed, 8 insertions(+), 18 deletions(-) diff --git a/criu/aio.c b/criu/aio.c index 45651f2d3..6ee65d5f4 100644 --- a/criu/aio.c +++ b/criu/aio.c @@ -11,7 +11,7 @@ #include "parasite.h" #include "parasite-syscall.h" #include "images/mm.pb-c.h" -#include +#include "compel/infect.h" #define NR_IOEVENTS_IN_NPAGES(npages) ((PAGE_SIZE * (npages) - sizeof(struct aio_ring)) / sizeof(struct io_event)) diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index f98743a23..76bd1fea7 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -19,7 +19,7 @@ #include "util.h" #include "cpu.h" #include "restorer.h" -#include +#include "compel/infect.h" #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))(src)->e diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index c216cdc5c..840d489a6 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -18,8 +18,7 @@ #include "elf.h" #include "parasite-syscall.h" #include "restorer.h" - -#include +#include "compel/infect.h" #define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))((src)->ARM_##e) diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index 5a5966ad4..0d9f49c3f 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -17,7 +17,7 @@ #include "log.h" #include "util.h" #include "cpu.h" -#include +#include "compel/infect.h" #include "protobuf.h" #include "images/core.pb-c.h" diff --git a/criu/arch/s390/crtools.c b/criu/arch/s390/crtools.c index 238035b76..000b7779f 100644 --- a/criu/arch/s390/crtools.c +++ b/criu/arch/s390/crtools.c @@ -17,7 +17,7 @@ #include "log.h" #include "util.h" #include "cpu.h" -#include +#include "compel/infect.h" #include "protobuf.h" #include "images/core.pb-c.h" diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index e4073c27b..9c8beeedd 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -1,5 +1,5 @@ #include "compel/asm/fpu.h" -#include "compel/compel.h" +#include "compel/infect.h" #include "compel/plugins/std/syscall-codes.h" #include "cpu.h" #include "cr_options.h" diff --git a/criu/arch/x86/sys-exec-tbl.c b/criu/arch/x86/sys-exec-tbl.c index 608dc2510..225b8a153 100644 --- a/criu/arch/x86/sys-exec-tbl.c +++ b/criu/arch/x86/sys-exec-tbl.c @@ -1,4 +1,3 @@ -#include static struct syscall_exec_desc sc_exec_table_64[] = { #include "sys-exec-tbl-64.c" diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 85105a18e..41146d4ad 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -67,7 +67,6 @@ #include "timerfd.h" #include "action-scripts.h" #include "shmem.h" -#include #include "aio.h" #include "lsm.h" #include "seccomp.h" diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h index 96a097b3d..fd50ff47e 100644 --- a/criu/include/proc_parse.h +++ b/criu/include/proc_parse.h @@ -3,7 +3,7 @@ #include -#include +#include "compel/infect.h" #define PROC_TASK_COMM_LEN 32 #define PROC_TASK_COMM_LEN_FMT "(%31s" diff --git a/criu/kerndat.c b/criu/kerndat.c index 8ac83820b..2ad72c350 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -33,7 +33,6 @@ #include "net.h" #include "tun.h" #include -#include #include "netfilter.h" #include "fsnotify.h" #include "linux/userfaultfd.h" diff --git a/criu/mem.c b/criu/mem.c index 4e110c9e9..55022d94a 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -29,7 +29,7 @@ #include "pagemap-cache.h" #include "fault-injection.h" #include "prctl.h" -#include +#include "compel/infect-util.h" #include "protobuf.h" #include "images/pagemap.pb-c.h" diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index e5a8194e5..b649d1b51 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -45,8 +45,6 @@ #include "infect-rpc.h" #include "pie/parasite-blob.h" -#include - unsigned long get_exec_start(struct vm_area_list *vmas) { struct vma_area *vma_area; diff --git a/criu/pie/pie-relocs.h b/criu/pie/pie-relocs.h index 6797486c2..e36126be6 100644 --- a/criu/pie/pie-relocs.h +++ b/criu/pie/pie-relocs.h @@ -1,8 +1,6 @@ #ifndef __PIE_RELOCS_H__ #define __PIE_RELOCS_H__ -#include - #include "common/config.h" #include "common/compiler.h" diff --git a/criu/seize.c b/criu/seize.c index 0ba2d9b1d..f973806d9 100644 --- a/criu/seize.c +++ b/criu/seize.c @@ -23,7 +23,6 @@ #include "string.h" #include "xmalloc.h" #include "util.h" -#include #define NR_ATTEMPTS 5 diff --git a/criu/vdso.c b/criu/vdso.c index 19ba4765d..433a54728 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -20,7 +20,6 @@ #include "criu-log.h" #include "mem.h" #include "vma.h" -#include #include #ifdef LOG_PREFIX From 327554ee646ac8c7728981d0607dc42420c3a85a Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 5 Mar 2020 15:00:08 +0000 Subject: [PATCH 2343/4375] compel: Remove compel.h The file only includes other headers (which may be not needed). If we aim for one-include-for-compel, we could instead paste all subheaders into "compel.h". Rather, I think it's worth to migrate to more fine-grained compel headers than follow the strategy 'one header to rule them all'. Further, the header creates problems for cross-compilation: it's included in files, those are used by host-compel. Which rightfully confuses compiler/linker as host's definitions for fpu regs/other platform details get drained into host's compel. Signed-off-by: Dmitry Safonov --- Documentation/compel.txt | 2 +- compel/arch/aarch64/src/lib/handle-elf.c | 3 +-- compel/arch/arm/src/lib/handle-elf.c | 3 +-- compel/arch/arm/src/lib/infect.c | 1 + compel/arch/ppc64/src/lib/cpu.c | 1 + compel/arch/ppc64/src/lib/handle-elf.c | 3 +-- compel/arch/s390/src/lib/handle-elf.c | 3 +-- compel/arch/s390/src/lib/infect.c | 1 + compel/arch/x86/src/lib/handle-elf.c | 3 +-- compel/arch/x86/src/lib/infect.c | 1 + compel/include/log.h | 3 +-- compel/include/uapi/compel.h | 14 -------------- compel/src/lib/handle-elf.c | 6 ++---- compel/src/lib/log.c | 3 --- compel/src/main.c | 2 -- compel/test/fdspy/spy.c | 1 - compel/test/infect/spy.c | 1 - compel/test/rsys/spy.c | 2 -- include/common/scm.h | 2 ++ 19 files changed, 15 insertions(+), 40 deletions(-) delete mode 100644 compel/include/uapi/compel.h diff --git a/Documentation/compel.txt b/Documentation/compel.txt index 744a3b35d..6ccd20861 100644 --- a/Documentation/compel.txt +++ b/Documentation/compel.txt @@ -86,7 +86,7 @@ Infecting code ~~~~~~~~~~~~~~ The parasitic code is compiled and converted to a header using *compel*, and included here. -*#include * +*#include * *#include "parasite.h"* diff --git a/compel/arch/aarch64/src/lib/handle-elf.c b/compel/arch/aarch64/src/lib/handle-elf.c index 1c3686c48..1ee65ee2c 100644 --- a/compel/arch/aarch64/src/lib/handle-elf.c +++ b/compel/arch/aarch64/src/lib/handle-elf.c @@ -1,6 +1,5 @@ #include - -#include "uapi/compel.h" +#include #include "handle-elf.h" #include "piegen.h" diff --git a/compel/arch/arm/src/lib/handle-elf.c b/compel/arch/arm/src/lib/handle-elf.c index 8abf8dad1..5b8d00a6f 100644 --- a/compel/arch/arm/src/lib/handle-elf.c +++ b/compel/arch/arm/src/lib/handle-elf.c @@ -1,6 +1,5 @@ #include - -#include "uapi/compel.h" +#include #include "handle-elf.h" #include "piegen.h" diff --git a/compel/arch/arm/src/lib/infect.c b/compel/arch/arm/src/lib/infect.c index c17cb9c9b..0053bef58 100644 --- a/compel/arch/arm/src/lib/infect.c +++ b/compel/arch/arm/src/lib/infect.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include "common/page.h" diff --git a/compel/arch/ppc64/src/lib/cpu.c b/compel/arch/ppc64/src/lib/cpu.c index 338ab4891..7a3972790 100644 --- a/compel/arch/ppc64/src/lib/cpu.c +++ b/compel/arch/ppc64/src/lib/cpu.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "compel-cpu.h" diff --git a/compel/arch/ppc64/src/lib/handle-elf.c b/compel/arch/ppc64/src/lib/handle-elf.c index 3d4020f59..f29fdc8a3 100644 --- a/compel/arch/ppc64/src/lib/handle-elf.c +++ b/compel/arch/ppc64/src/lib/handle-elf.c @@ -1,6 +1,5 @@ #include - -#include "uapi/compel.h" +#include #include "handle-elf.h" #include "piegen.h" diff --git a/compel/arch/s390/src/lib/handle-elf.c b/compel/arch/s390/src/lib/handle-elf.c index 01a8bf4c8..6ed382c92 100644 --- a/compel/arch/s390/src/lib/handle-elf.c +++ b/compel/arch/s390/src/lib/handle-elf.c @@ -1,6 +1,5 @@ #include - -#include "uapi/compel.h" +#include #include "handle-elf.h" #include "piegen.h" diff --git a/compel/arch/s390/src/lib/infect.c b/compel/arch/s390/src/lib/infect.c index 7e7d24ce2..5a4675449 100644 --- a/compel/arch/s390/src/lib/infect.c +++ b/compel/arch/s390/src/lib/infect.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/compel/arch/x86/src/lib/handle-elf.c b/compel/arch/x86/src/lib/handle-elf.c index 62fb28f49..938999b2e 100644 --- a/compel/arch/x86/src/lib/handle-elf.c +++ b/compel/arch/x86/src/lib/handle-elf.c @@ -1,6 +1,5 @@ #include - -#include "uapi/compel.h" +#include #include "handle-elf.h" #include "piegen.h" diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index 11e7f4c91..9c4abb60c 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -3,6 +3,7 @@ #include #include #include +#include #include diff --git a/compel/include/log.h b/compel/include/log.h index 559f909ce..49e65bb50 100644 --- a/compel/include/log.h +++ b/compel/include/log.h @@ -1,8 +1,7 @@ #ifndef COMPEL_LOG_H__ #define COMPEL_LOG_H__ -#include "uapi/compel/compel.h" -#include "uapi/compel/loglevels.h" +#include "uapi/compel/log.h" #ifndef LOG_PREFIX # define LOG_PREFIX diff --git a/compel/include/uapi/compel.h b/compel/include/uapi/compel.h deleted file mode 100644 index 318a472da..000000000 --- a/compel/include/uapi/compel.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef UAPI_COMPEL_H__ -#define UAPI_COMPEL_H__ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#endif /* UAPI_COMPEL_H__ */ diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index ca7c53b71..69d5104b6 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include @@ -12,8 +12,6 @@ #include #include -#include "uapi/compel.h" - #include "handle-elf.h" #include "piegen.h" #include "log.h" @@ -228,7 +226,7 @@ int __handle_elf(void *mem, size_t size) } pr_out("/* Autogenerated from %s */\n", opts.input_filename); - pr_out("#include \n"); + pr_out("#include \n"); for (i = 0; i < symtab_hdr->sh_size / symtab_hdr->sh_entsize; i++) { Elf_Sym *sym = &symbols[i]; diff --git a/compel/src/lib/log.c b/compel/src/lib/log.c index d195343e4..c86be02c5 100644 --- a/compel/src/lib/log.c +++ b/compel/src/lib/log.c @@ -4,11 +4,8 @@ #include #include #include - #include -#include - #include "log.h" static unsigned int current_loglevel = COMPEL_DEFAULT_LOGLEVEL; diff --git a/compel/src/main.c b/compel/src/main.c index 8b2c8bc8d..36127c357 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -13,8 +13,6 @@ #include #include -#include "uapi/compel/compel.h" - #include "version.h" #include "piegen.h" #include "log.h" diff --git a/compel/test/fdspy/spy.c b/compel/test/fdspy/spy.c index 258e3ab75..1a373b6bb 100644 --- a/compel/test/fdspy/spy.c +++ b/compel/test/fdspy/spy.c @@ -5,7 +5,6 @@ #include #include -#include #include "parasite.h" #define PARASITE_CMD_GETFD PARASITE_USER_CMDS diff --git a/compel/test/infect/spy.c b/compel/test/infect/spy.c index a5aba7308..b5f8b2559 100644 --- a/compel/test/infect/spy.c +++ b/compel/test/infect/spy.c @@ -3,7 +3,6 @@ #include #include -#include #include "parasite.h" #define PARASITE_CMD_INC PARASITE_USER_CMDS diff --git a/compel/test/rsys/spy.c b/compel/test/rsys/spy.c index f5c999d5a..98654efcf 100644 --- a/compel/test/rsys/spy.c +++ b/compel/test/rsys/spy.c @@ -4,8 +4,6 @@ #include #include -#include - static void print_vmsg(unsigned int lvl, const char *fmt, va_list parms) { printf("\tLC%u: ", lvl); diff --git a/include/common/scm.h b/include/common/scm.h index ab27137b8..a8eb9ec4c 100644 --- a/include/common/scm.h +++ b/include/common/scm.h @@ -3,7 +3,9 @@ #include #include +#include #include +#include /* * Because of kernel doing kmalloc for user data passed From 18ac1540c4b64108b53fcd8fa3b3df256075e3f6 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 5 Mar 2020 15:04:15 +0000 Subject: [PATCH 2344/4375] travis: Add aarch64-cross test on amd64 Fixes: #924 Signed-off-by: Dmitry Safonov --- .travis.yml | 4 +++ scripts/build/Dockerfile.aarch64-cross | 45 ++++++++++++++++++++++++++ scripts/build/Makefile | 2 +- 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 scripts/build/Dockerfile.aarch64-cross diff --git a/.travis.yml b/.travis.yml index 7c36af006..ffa82f15f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -86,6 +86,10 @@ jobs: arch: amd64 env: TR_ARCH=armv7-cross dist: bionic + - os: linux + arch: amd64 + env: TR_ARCH=aarch64-cross + dist: bionic allow_failures: - env: TR_ARCH=docker-test - env: TR_ARCH=docker-test DIST=xenial diff --git a/scripts/build/Dockerfile.aarch64-cross b/scripts/build/Dockerfile.aarch64-cross new file mode 100644 index 000000000..38229497a --- /dev/null +++ b/scripts/build/Dockerfile.aarch64-cross @@ -0,0 +1,45 @@ +FROM dockcross/base:latest + +# Add the cross compiler sources +RUN echo "deb http://ftp.us.debian.org/debian/ jessie main" >> /etc/apt/sources.list && \ + dpkg --add-architecture arm64 && \ + apt-get install emdebian-archive-keyring + +RUN apt-get update && apt-get install -y \ + crossbuild-essential-arm64 \ + libc6-dev-arm64-cross \ + libc6-arm64-cross \ + libbz2-dev:arm64 \ + libexpat1-dev:arm64 \ + ncurses-dev:arm64 \ + libssl-dev:arm64 \ + protobuf-c-compiler \ + protobuf-compiler \ + python-protobuf \ + libnl-3-dev:arm64 \ + libprotobuf-dev:arm64 \ + libnet-dev:arm64 \ + libprotobuf-c-dev:arm64 \ + libcap-dev:arm64 \ + libaio-dev:arm64 \ + libnl-route-3-dev:arm64 + +ENV CROSS_TRIPLE=aarch64-linux-gnu +ENV CROSS_COMPILE=${CROSS_TRIPLE}- \ + CROSS_ROOT=/usr/${CROSS_TRIPLE} \ + AS=/usr/bin/${CROSS_TRIPLE}-as \ + AR=/usr/bin/${CROSS_TRIPLE}-ar \ + CC=/usr/bin/${CROSS_TRIPLE}-gcc \ + CPP=/usr/bin/${CROSS_TRIPLE}-cpp \ + CXX=/usr/bin/${CROSS_TRIPLE}-g++ \ + LD=/usr/bin/${CROSS_TRIPLE}-ld \ + FC=/usr/bin/${CROSS_TRIPLE}-gfortran + +ENV PATH="${PATH}:${CROSS_ROOT}/bin" \ + PKG_CONFIG_PATH=/usr/lib/${CROSS_TRIPLE}/pkgconfig \ + ARCH=aarch64 + +COPY . /criu +WORKDIR /criu + +RUN make mrproper && date && make -j $(nproc) zdtm && date diff --git a/scripts/build/Makefile b/scripts/build/Makefile index d093ce76c..913a86d6c 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -2,7 +2,7 @@ ARCHES := x86_64 fedora-asan fedora-rawhide centos armv7hf TARGETS := $(ARCHES) alpine TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) CONTAINER_RUNTIME := docker -TARGETS += armv7-cross +TARGETS += armv7-cross aarch64-cross all: $(TARGETS) $(TARGETS_CLANG) .PHONY: all From 1f74f8d77087ce06624cb54f2fa70afaf1380103 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 5 Mar 2020 16:43:48 +0000 Subject: [PATCH 2345/4375] travis: Use debian/buster as base for cross build tests Jessie is called 'oldoldstable', migrate to Buster. Suggested-by: Adrian Reber Signed-off-by: Dmitry Safonov --- scripts/build/Dockerfile.aarch64-cross | 2 +- scripts/build/Dockerfile.armv7-cross | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build/Dockerfile.aarch64-cross b/scripts/build/Dockerfile.aarch64-cross index 38229497a..252e0f875 100644 --- a/scripts/build/Dockerfile.aarch64-cross +++ b/scripts/build/Dockerfile.aarch64-cross @@ -1,7 +1,7 @@ FROM dockcross/base:latest # Add the cross compiler sources -RUN echo "deb http://ftp.us.debian.org/debian/ jessie main" >> /etc/apt/sources.list && \ +RUN echo "deb http://ftp.us.debian.org/debian/ buster main" >> /etc/apt/sources.list && \ dpkg --add-architecture arm64 && \ apt-get install emdebian-archive-keyring diff --git a/scripts/build/Dockerfile.armv7-cross b/scripts/build/Dockerfile.armv7-cross index 434934aad..17a55561e 100644 --- a/scripts/build/Dockerfile.armv7-cross +++ b/scripts/build/Dockerfile.armv7-cross @@ -1,7 +1,7 @@ FROM dockcross/base:latest # Add the cross compiler sources -RUN echo "deb http://ftp.us.debian.org/debian/ jessie main" >> /etc/apt/sources.list && \ +RUN echo "deb http://ftp.us.debian.org/debian/ buster main" >> /etc/apt/sources.list && \ dpkg --add-architecture armhf && \ apt-get install emdebian-archive-keyring From b9c8e957d8f198fb47ed9e73a5d5c3727ba4d4cc Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Tue, 10 Mar 2020 17:40:57 +0300 Subject: [PATCH 2346/4375] crit-recode: skip (not try to parse) nftables raw image We should ignore (not parse) images that has non-crtool format, that images has no magic number (RAW_IMAGE_MAGIC equals 0). nftables images has format compatible with `nft -f /proc/self/fd/0` input format. Reported-by: Mr Jenkins Signed-off-by: Alexander Mikhalitsyn (Virtuozzo) --- test/crit-recode.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/crit-recode.py b/test/crit-recode.py index a7dcc7272..adaf33733 100755 --- a/test/crit-recode.py +++ b/test/crit-recode.py @@ -47,6 +47,8 @@ for imgf in find.stdout.readlines(): continue if imgf_b.startswith(b'ip6tables-'): continue + if imgf_b.startswith(b'nftables-'): + continue if imgf_b.startswith(b'route-'): continue if imgf_b.startswith(b'route6-'): From c3ad4942d43524c617bb77345ce8912461b6f9aa Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 5 Mar 2020 20:46:16 +0200 Subject: [PATCH 2347/4375] travis: add ppc64-cross test on amd64 Signed-off-by: Mike Rapoport --- .travis.yml | 4 +++ scripts/build/Dockerfile.ppc64-cross | 45 ++++++++++++++++++++++++++++ scripts/build/Makefile | 2 +- 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 scripts/build/Dockerfile.ppc64-cross diff --git a/.travis.yml b/.travis.yml index ffa82f15f..9928f16c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -90,6 +90,10 @@ jobs: arch: amd64 env: TR_ARCH=aarch64-cross dist: bionic + - os: linux + arch: amd64 + env: TR_ARCH=ppc64-cross + dist: bionic allow_failures: - env: TR_ARCH=docker-test - env: TR_ARCH=docker-test DIST=xenial diff --git a/scripts/build/Dockerfile.ppc64-cross b/scripts/build/Dockerfile.ppc64-cross new file mode 100644 index 000000000..44061c558 --- /dev/null +++ b/scripts/build/Dockerfile.ppc64-cross @@ -0,0 +1,45 @@ +FROM dockcross/base:latest + +# Add the cross compiler sources +RUN echo "deb http://ftp.us.debian.org/debian/ buster main" >> /etc/apt/sources.list && \ + dpkg --add-architecture ppc64el && \ + apt-get install emdebian-archive-keyring + +RUN apt-get update && apt-get install -y \ + crossbuild-essential-ppc64el \ + libc6-dev-ppc64el-cross \ + libc6-ppc64el-cross \ + libbz2-dev:ppc64el \ + libexpat1-dev:ppc64el \ + ncurses-dev:ppc64el \ + libssl-dev:ppc64el \ + protobuf-c-compiler \ + protobuf-compiler \ + python-protobuf \ + libnl-3-dev:ppc64el \ + libprotobuf-dev:ppc64el \ + libnet-dev:ppc64el \ + libprotobuf-c-dev:ppc64el \ + libcap-dev:ppc64el \ + libaio-dev:ppc64el \ + libnl-route-3-dev:ppc64el + +ENV CROSS_TRIPLE=powerpc64le-linux-gnu +ENV CROSS_COMPILE=${CROSS_TRIPLE}- \ + CROSS_ROOT=/usr/${CROSS_TRIPLE} \ + AS=/usr/bin/${CROSS_TRIPLE}-as \ + AR=/usr/bin/${CROSS_TRIPLE}-ar \ + CC=/usr/bin/${CROSS_TRIPLE}-gcc \ + CPP=/usr/bin/${CROSS_TRIPLE}-cpp \ + CXX=/usr/bin/${CROSS_TRIPLE}-g++ \ + LD=/usr/bin/${CROSS_TRIPLE}-ld \ + FC=/usr/bin/${CROSS_TRIPLE}-gfortran + +ENV PATH="${PATH}:${CROSS_ROOT}/bin" \ + PKG_CONFIG_PATH=/usr/lib/${CROSS_TRIPLE}/pkgconfig \ + ARCH=ppc64 + +COPY . /criu +WORKDIR /criu + +RUN make mrproper && date && make -j $(nproc) zdtm && date diff --git a/scripts/build/Makefile b/scripts/build/Makefile index 913a86d6c..855539152 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -2,7 +2,7 @@ ARCHES := x86_64 fedora-asan fedora-rawhide centos armv7hf TARGETS := $(ARCHES) alpine TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) CONTAINER_RUNTIME := docker -TARGETS += armv7-cross aarch64-cross +TARGETS += armv7-cross aarch64-cross ppc64-cross all: $(TARGETS) $(TARGETS_CLANG) .PHONY: all From d0d6f1ad108a6bd7eb0e2019aaca7689bff45275 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 21 Mar 2020 10:35:42 -0700 Subject: [PATCH 2348/4375] mailmap: update my email Signed-off-by: Andrei Vagin --- .mailmap | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.mailmap b/.mailmap index d8c3f594d..6f046b972 100644 --- a/.mailmap +++ b/.mailmap @@ -1,6 +1,8 @@ Stanislav Kinsbursky Pavel Emelyanov -Andrey Vagin -Andrey Vagin -Andrey Vagin Andrew Vagin +Andrei Vagin +Andrei Vagin +Andrei Vagin +Andrei Vagin +Andrei Vagin Cyrill Gorcunov From f42ae70c75802787e980715a7ca895eb2b390d06 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Fri, 20 Mar 2020 23:12:59 +0000 Subject: [PATCH 2349/4375] make: use cflags/ldflags for config.h detection mechanism The config.h detection scripts should use the provided CFLAGS/LDFLAGS as it tries to link libnl, libnet, and others. Signed-off-by: Nicolas Viennot --- scripts/nmk/scripts/utils.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nmk/scripts/utils.mk b/scripts/nmk/scripts/utils.mk index 0cf216bc0..b9790615c 100644 --- a/scripts/nmk/scripts/utils.mk +++ b/scripts/nmk/scripts/utils.mk @@ -3,7 +3,7 @@ ifndef ____nmk_defined__utils # # Usage: option := $(call try-compile,language,source-to-build,cc-options,cc-defines) try-compile = $(shell sh -c 'echo "$(2)" | \ - $(CC) $(4) -x $(1) - $(3) -o /dev/null > /dev/null 2>&1 && \ + $(CC) $(CFLAGS) $(LDFLAGS) $(4) -x $(1) - $(3) -o /dev/null > /dev/null 2>&1 && \ echo true || echo false') # From fb65ab2b1a47558c2fe92a635630d53b971e5876 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 15 Mar 2020 10:44:14 +0300 Subject: [PATCH 2350/4375] mem: dump shared memory file descriptors Any shared memroy mapping can be opened via /proc/self/maps_files/. Such file descriptors look like memfd file descriptors, so they can be dumped by the same way. Signed-off-by: Andrei Vagin --- criu/files.c | 2 +- criu/include/memfd.h | 2 +- criu/memfd.c | 11 +++++++---- criu/proc_parse.c | 38 ++++++++++---------------------------- 4 files changed, 19 insertions(+), 34 deletions(-) diff --git a/criu/files.c b/criu/files.c index f6ba39a30..a1fd26764 100644 --- a/criu/files.c +++ b/criu/files.c @@ -552,7 +552,7 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, p.link = &link; - if (is_memfd(p.stat.st_dev, &link.name[1])) + if (is_memfd(p.stat.st_dev)) ops = &memfd_dump_ops; else if (link.name[1] == '/') ops = ®file_dump_ops; diff --git a/criu/include/memfd.h b/criu/include/memfd.h index 2d8eda545..4189766fd 100644 --- a/criu/include/memfd.h +++ b/criu/include/memfd.h @@ -8,7 +8,7 @@ struct fd_parms; struct file_desc; -extern int is_memfd(dev_t dev, const char *path); +extern int is_memfd(dev_t dev); extern int dump_one_memfd_cond(int lfd, u32 *id, struct fd_parms *parms); extern const struct fdtype_ops memfd_dump_ops; diff --git a/criu/memfd.c b/criu/memfd.c index 983e01b38..bca6900cb 100644 --- a/criu/memfd.c +++ b/criu/memfd.c @@ -58,15 +58,14 @@ static LIST_HEAD(memfd_inodes); static u32 memfd_inode_ids = 1; -int is_memfd(dev_t dev, const char *path) +int is_memfd(dev_t dev) { /* * TODO When MAP_HUGETLB is used, the file device is not shmem_dev, * Note that other parts of CRIU have similar issues, see * is_anon_shmem_map(). */ - return dev == kdat.shmem_dev && - !strncmp(path, MEMFD_PREFIX, MEMFD_PREFIX_LEN); + return dev == kdat.shmem_dev; } static int dump_memfd_inode(int fd, struct memfd_inode *inode, @@ -167,7 +166,11 @@ static int dump_one_memfd(int lfd, u32 id, const struct fd_parms *p) link = p->link; strip_deleted(link); - name = &link->name[1+MEMFD_PREFIX_LEN]; + /* link->name is always started with "." which has to be skipped. */ + if (strncmp(link->name + 1, MEMFD_PREFIX, MEMFD_PREFIX_LEN) == 0) + name = &link->name[1 + MEMFD_PREFIX_LEN]; + else + name = link->name + 1; inode = dump_unique_memfd_inode(lfd, name, &p->stat); if (!inode) diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 468afcdf3..980342870 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -305,7 +305,7 @@ static int vma_get_mapfile_user(const char *fname, struct vma_area *vma, vfi_dev = makedev(vfi->dev_maj, vfi->dev_min); - if (is_memfd(vfi_dev, fname)) { + if (is_memfd(vfi_dev)) { struct fd_link link; link.len = strlen(fname); strlcpy(link.name, fname, sizeof(link.name)); @@ -596,39 +596,21 @@ static int handle_vma(pid_t pid, struct vma_area *vma_area, goto err; } - /* - * /dev/zero stands for anon-shared mapping - * otherwise it's some file mapping. - * - * We treat memfd mappings as regular file mappings because - * their backing can be seen as files, which is easy to - * support. So even though memfd is an anonymous shmem, we - * treat it differently. - * Note: maybe we should revisit this as /proc/map_files/ - * may not always be accessible. - */ - - if (is_memfd(st_buf->st_dev, file_path)) { - vma_area->e->status |= VMA_AREA_MEMFD; - goto normal_file; - } - - if (is_anon_shmem_map(st_buf->st_dev)) { - if (!(vma_area->e->flags & MAP_SHARED)) - goto err_bogus_mapping; + if (is_anon_shmem_map(st_buf->st_dev) && !strncmp(file_path, "/SYSV", 5)) { vma_area->e->flags |= MAP_ANONYMOUS; vma_area->e->status |= VMA_ANON_SHARED; vma_area->e->shmid = st_buf->st_ino; - - if (!strncmp(file_path, "/SYSV", 5)) { - pr_info("path: %s\n", file_path); - vma_area->e->status |= VMA_AREA_SYSVIPC; - } else { + if (!(vma_area->e->flags & MAP_SHARED)) + goto err_bogus_mapping; + pr_info("path: %s\n", file_path); + vma_area->e->status |= VMA_AREA_SYSVIPC; + } else { + if (is_anon_shmem_map(st_buf->st_dev)) { + vma_area->e->status |= VMA_AREA_MEMFD; if (fault_injected(FI_HUGE_ANON_SHMEM_ID)) vma_area->e->shmid += FI_HUGE_ANON_SHMEM_ID_BASE; } - } else { -normal_file: + if (vma_area->e->flags & MAP_PRIVATE) vma_area->e->status |= VMA_FILE_PRIVATE; else From 10b1d46f674ec458cd1a006eb1b0546bf5a7135c Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 19 Mar 2020 09:37:18 +0300 Subject: [PATCH 2351/4375] mem/vma: set VMA_FILE_{PRIVATE,SHARED} if a vma file is borrowed Here is a fast path when two consequent vma-s share the same file. But one of these vma-s can map a file with MAP_SHARED, but another one can map it with MAP_PRIVATE and we need to take this into account. --- criu/proc_parse.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 980342870..60aba8788 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -584,6 +584,14 @@ static int handle_vma(pid_t pid, struct vma_area *vma_area, vma_area->e->shmid = prev->e->shmid; vma_area->vmst = prev->vmst; vma_area->mnt_id = prev->mnt_id; + + if (!(vma_area->e->status & VMA_AREA_SYSVIPC)) { + vma_area->e->status &= ~(VMA_FILE_PRIVATE | VMA_FILE_SHARED); + if (vma_area->e->flags & MAP_PRIVATE) + vma_area->e->status |= VMA_FILE_PRIVATE; + else + vma_area->e->status |= VMA_FILE_SHARED; + } } else if (*vm_file_fd >= 0) { struct stat *st_buf = vma_area->vmst; From c40c09cbbf03afc058a761314fcdb14a3f69cb53 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 15 Mar 2020 10:53:51 +0300 Subject: [PATCH 2352/4375] test/zdtmp: add a test to C/R shared memory file descriptors Any shared memory region can be openned via /proc/self/map_files. Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 2 + test/zdtm/static/shmemfd-priv.c | 84 ++++++++++++++++++++++ test/zdtm/static/shmemfd-priv.desc | 1 + test/zdtm/static/shmemfd.c | 107 +++++++++++++++++++++++++++++ test/zdtm/static/shmemfd.desc | 1 + 5 files changed, 195 insertions(+) create mode 100644 test/zdtm/static/shmemfd-priv.c create mode 100644 test/zdtm/static/shmemfd-priv.desc create mode 100644 test/zdtm/static/shmemfd.c create mode 100644 test/zdtm/static/shmemfd.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index ee69612c7..a8e4107d3 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -224,6 +224,8 @@ TST_NOFILE := \ memfd01 \ memfd02 \ memfd03 \ + shmemfd \ + shmemfd-priv \ # jobctl00 \ ifneq ($(ARCH),arm) diff --git a/test/zdtm/static/shmemfd-priv.c b/test/zdtm/static/shmemfd-priv.c new file mode 100644 index 000000000..bbdb46905 --- /dev/null +++ b/test/zdtm/static/shmemfd-priv.c @@ -0,0 +1,84 @@ +#include +#include + +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Test C/R of shared memory file descriptors"; +const char *test_author = "Andrei Vagin "; + +#define err(exitcode, msg, ...) ({ pr_perror(msg, ##__VA_ARGS__); exit(exitcode); }) + +int main(int argc, char *argv[]) +{ + void *addr, *priv_addr, *addr2; + char path[4096]; + int fd; + + test_init(argc, argv); + + addr = mmap(NULL, 5 * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); + if (addr == MAP_FAILED) { + pr_perror("mmap"); + return 1; + } + + *(int *) addr = 1; + *(int *) (addr + PAGE_SIZE) = 11; + *(int *) (addr + 2 * PAGE_SIZE) = 111; + + snprintf(path, sizeof(path), "/proc/self/map_files/%lx-%lx", + (long)addr, (long)addr + 5 * PAGE_SIZE); + fd = open(path, O_RDWR | O_LARGEFILE); + if (fd < 0) + err(1, "Can't open %s", path); + + priv_addr = mmap(NULL, 5 * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE, fd, PAGE_SIZE); + if (priv_addr == MAP_FAILED) { + pr_perror("mmap"); + return 1; + } + + addr2 = mmap(NULL, 5 * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 2 * PAGE_SIZE); + if (addr2 == MAP_FAILED) { + pr_perror("mmap"); + return 1; + } + + *(int *) (priv_addr + PAGE_SIZE) = 22; + + test_daemon(); + test_waitsig(); + + if (*(int *) (priv_addr + PAGE_SIZE) != 22) { + fail("the second page of the private mapping is corrupted"); + return 1; + } + if (*(int *) (priv_addr) != 11) { + fail("the first page of the private mapping is corrupted"); + return 1; + } + if (*(int *) (addr2) != 111) { + fail("the first page of the second shared mapping is corrupted"); + return 1; + } + *(int *) (addr2) = 333; + if (*(int *) (addr + 2 * PAGE_SIZE) != 333) { + fail("the first page of the second shared mapping isn't shared"); + return 1; + } + *(int *) (addr + 3 * PAGE_SIZE) = 444; + if (*(int *) (priv_addr + 2 * PAGE_SIZE) != 444) { + fail("the third page of the private mapping is corrupted"); + return 1; + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/shmemfd-priv.desc b/test/zdtm/static/shmemfd-priv.desc new file mode 100644 index 000000000..d969725f6 --- /dev/null +++ b/test/zdtm/static/shmemfd-priv.desc @@ -0,0 +1 @@ +{'flavor': 'h ns', 'flags': 'suid'} diff --git a/test/zdtm/static/shmemfd.c b/test/zdtm/static/shmemfd.c new file mode 100644 index 000000000..b65faa2e1 --- /dev/null +++ b/test/zdtm/static/shmemfd.c @@ -0,0 +1,107 @@ +#include +#include + +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Test C/R of shared memory file descriptors"; +const char *test_author = "Andrei Vagin "; + +#define err(exitcode, msg, ...) ({ pr_perror(msg, ##__VA_ARGS__); exit(exitcode); }) + +int main(int argc, char *argv[]) +{ + int fd, fl_flags1, fl_flags2, fd_flags1, fd_flags2; + struct statfs statfs1, statfs2; + off_t pos1, pos2; + char path[4096]; + char buf[5]; + void *addr; + + test_init(argc, argv); + + addr = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); + if (addr == MAP_FAILED) { + pr_perror("mmap"); + return 1; + } + + snprintf(path, sizeof(path), "/proc/self/map_files/%lx-%lx", + (long)addr, (long)addr + PAGE_SIZE); + fd = open(path, O_RDWR | O_LARGEFILE); + if (fd < 0) + err(1, "Can't open %s", path); + ftruncate(fd, 0); + munmap(addr, PAGE_SIZE); + + if (fcntl(fd, F_SETFL, O_APPEND) < 0) + err(1, "Can't get fl flags"); + + if ((fl_flags1 = fcntl(fd, F_GETFL)) == -1) + err(1, "Can't get fl flags"); + + if ((fd_flags1 = fcntl(fd, F_GETFD)) == -1) + err(1, "Can't get fd flags"); + + if (fstatfs(fd, &statfs1) < 0) + err(1, "statfs issue"); + + if (write(fd, "hello", 5) != 5) + err(1, "write error"); + + pos1 = 3; + if (lseek(fd, pos1, SEEK_SET) < 0) + err(1, "seek error"); + + test_daemon(); + test_waitsig(); + + if ((fl_flags2 = fcntl(fd, F_GETFL)) == -1) + err(1, "Can't get fl flags"); + + if (fl_flags1 != fl_flags2) { + fail("fl flags differs %x %x", fl_flags1, fl_flags2); + return 1; + } + + if ((fd_flags2 = fcntl(fd, F_GETFD)) == -1) + err(1, "Can't get fd flags"); + + if (fd_flags1 != fd_flags2) { + fail("fd flags differs"); + return 1; + } + + if (fstatfs(fd, &statfs2) < 0) + err(1, "statfs issue"); + + if (statfs1.f_type != statfs2.f_type) { + fail("statfs.f_type differs"); + return 1; + } + + pos2 = lseek(fd, 0, SEEK_CUR); + if (pos1 != pos2) { + fail("position differs"); + return 1; + } + + if (pread(fd, buf, sizeof(buf), 0) != sizeof(buf)) { + fail("read problem"); + return 1; + } + + if (memcmp(buf, "hello", sizeof(buf))) { + fail("content mismatch"); + return 1; + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/shmemfd.desc b/test/zdtm/static/shmemfd.desc new file mode 100644 index 000000000..d969725f6 --- /dev/null +++ b/test/zdtm/static/shmemfd.desc @@ -0,0 +1 @@ +{'flavor': 'h ns', 'flags': 'suid'} From 691b4a4e7ee980778d8f13eaebddf9b04063942a Mon Sep 17 00:00:00 2001 From: Valeriy Vdovin Date: Mon, 3 Feb 2020 15:08:26 +0300 Subject: [PATCH 2353/4375] zdtm: Implemented get_current_dir_name wrapper that checks for 'x' permissions Any filesystem syscall, that needs to navigate to inode by it's absolute path performs successive lookup operations for each part of the path. Lookup operation includes access rights check. Usually but not always zdtm tests processes fall under 'other' access category. Also, usually directories don't have 'x' bit set for other. In case when bit 'x' is not set and user-ID and group-ID of a process relate it to 'other', test's will not succeed in performing these syscalls which are most of filesystem api, that has const char *path as part of it arguments (open, openat, mkdir, bind, etc). The observable behavior of that is that zdtm tests fail at file creation ops on one system and pass on the other. The above is not immediately clear to the developer by just looking at failed test's logs. Investigation of that is also not quick for a developer due to the complex structure of zdtm runtime where nested clones with NAMESPACE flags take place alongside with bind-mounts. As an additional note: 'get_current_dir_name' is documented as returning EACCESS in case when some part of the path lacks read/list permissions. But in fact it's not always so. Practice shows, that test processes can get false success on this operation only to fail on later call to something like mkdir/mknod/bind with a given path in arguments. 'get_cwd_check_perm' is a wrapper around 'get_current_dir_name'. It also checks for permissions on the given filepath and logs the error. This directs the developer towards the right investigation path or even eliminates the need for investigation completely. Signed-off-by: Valeriy Vdovin --- test/zdtm/lib/fs.c | 24 ++++++++++++++++++++++++ test/zdtm/lib/fs.h | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/test/zdtm/lib/fs.c b/test/zdtm/lib/fs.c index 0decfc37b..e82011ec8 100644 --- a/test/zdtm/lib/fs.c +++ b/test/zdtm/lib/fs.c @@ -94,3 +94,27 @@ err: mnt_info_free(&m); goto out; } + +int get_cwd_check_perm(char **result) +{ + char *cwd; + *result = 0; + cwd = get_current_dir_name(); + if (!cwd) { + pr_perror("failed to get current directory"); + return -1; + } + + if (access(cwd, X_OK)) { + pr_err("access check for bit X for current dir path '%s' " + "failed for uid:%d,gid:%d, error: %d(%s). " + "Bit 'x' should be set in all path components of " + "this directory\n", + cwd, getuid(), getgid(), errno, strerror(errno) + ); + return -1; + } + + *result = cwd; + return 0; +} diff --git a/test/zdtm/lib/fs.h b/test/zdtm/lib/fs.h index 972b15aba..af7a665fb 100644 --- a/test/zdtm/lib/fs.h +++ b/test/zdtm/lib/fs.h @@ -50,4 +50,28 @@ extern mnt_info_t *mnt_info_alloc(void); extern void mnt_info_free(mnt_info_t **m); extern mnt_info_t *get_cwd_mnt_info(void); +/* + * get_cwd_check_perm is called to check that cwd is actually usable for a calling + * process. + * + * Example output of a stat command on a '/root' path shows file access bits: + * > stat /root + * File: ‘/root’ + * ... + * Access: (0550/dr-xr-x---) Uid: ( 0/root) Gid: ( 0/root) + * ^- no 'x' bit for other + * + * Here we can see that '/root' dir (that often can be part of cwd path) does not + * allow non-root user and non-root group to list contents of this directory. + * Calling process matching 'other' access category may succeed getting cwd path, but will + * fail performing further filesystem operations based on this path with confusing errors. + * + * This function calls get_current_dir_name and explicitly checks that bit 'x' is enabled for + * a calling process and logs the error. + * + * If check passes, stores get_current_dir's result in *result and returns 0 + * If check fails, stores 0 in *result and returns -1 + */ +extern int get_cwd_check_perm(char **result); + #endif /* ZDTM_FS_H_ */ From fa705e418b4e7c2bce0925ad9f8689cd40b0c00d Mon Sep 17 00:00:00 2001 From: Valeriy Vdovin Date: Mon, 3 Feb 2020 15:27:40 +0300 Subject: [PATCH 2354/4375] zdtm: Use safe helper function to initialize unix socket sockaddr structure The helper function removes code duplication from tests that want to initialize unix socket address to an absolute file path, derived from current working directory of the test + relative filename of a resulting socket. Because the former code used cwd = get_current_dir_name() as part of absolute filename generation, the resulting filepath could later cause failure of bind systcall due to unchecked permissions and introduce confusing permission errors. Signed-off-by: Valeriy Vdovin --- test/zdtm/lib/Makefile | 2 +- test/zdtm/lib/unix.c | 19 ++++++++++++++++ test/zdtm/lib/zdtmtst.h | 3 +++ test/zdtm/static/del_standalone_un.c | 17 +------------- test/zdtm/static/deleted_unix_sock.c | 19 ++-------------- test/zdtm/static/sk-unix01.c | 33 ++++++---------------------- 6 files changed, 33 insertions(+), 60 deletions(-) create mode 100644 test/zdtm/lib/unix.c diff --git a/test/zdtm/lib/Makefile b/test/zdtm/lib/Makefile index b87f36e8f..89ca90933 100644 --- a/test/zdtm/lib/Makefile +++ b/test/zdtm/lib/Makefile @@ -4,7 +4,7 @@ CFLAGS += $(USERCFLAGS) LIB := libzdtmtst.a -LIBSRC := datagen.c msg.c parseargs.c test.c streamutil.c lock.c ns.c tcp.c fs.c sysctl.c +LIBSRC := datagen.c msg.c parseargs.c test.c streamutil.c lock.c ns.c tcp.c unix.c fs.c sysctl.c LIBOBJ := $(LIBSRC:%.c=%.o) BIN := groups diff --git a/test/zdtm/lib/unix.c b/test/zdtm/lib/unix.c new file mode 100644 index 000000000..c36846cad --- /dev/null +++ b/test/zdtm/lib/unix.c @@ -0,0 +1,19 @@ +#include +#include +#include "zdtmtst.h" +#include "fs.h" + +int unix_fill_sock_name(struct sockaddr_un *name, char *relFilename) +{ + char *cwd; + + if (get_cwd_check_perm(&cwd)) { + pr_err("failed to get current working directory with valid permissions.\n"); + return -1; + } + + name->sun_family = AF_LOCAL; + ssprintf(name->sun_path, "%s/%s", cwd, relFilename); + return 0; +} + diff --git a/test/zdtm/lib/zdtmtst.h b/test/zdtm/lib/zdtmtst.h index 2cd4bdd1d..6eec26647 100644 --- a/test/zdtm/lib/zdtmtst.h +++ b/test/zdtm/lib/zdtmtst.h @@ -149,6 +149,9 @@ extern int tcp_init_server(int family, int *port); extern int tcp_accept_server(int sock); extern int tcp_init_client(int family, char *servIP, unsigned short servPort); +struct sockaddr_un; +extern int unix_fill_sock_name(struct sockaddr_un *name, char *relFilename); + struct zdtm_tcp_opts { bool reuseaddr; bool reuseport; diff --git a/test/zdtm/static/del_standalone_un.c b/test/zdtm/static/del_standalone_un.c index d8200068b..5426fc786 100644 --- a/test/zdtm/static/del_standalone_un.c +++ b/test/zdtm/static/del_standalone_un.c @@ -16,19 +16,6 @@ const char *test_author = "Tycho Andersen "; char *dirname; TEST_OPTION(dirname, string, "directory name", 1); -static int fill_sock_name(struct sockaddr_un *name, const char *filename) -{ - char *cwd; - - cwd = get_current_dir_name(); - if (strlen(filename) + strlen(cwd) + 1 >= sizeof(name->sun_path)) - return -1; - - name->sun_family = AF_LOCAL; - ssprintf(name->sun_path, "%s/%s", cwd, filename); - return 0; -} - static int bind_and_listen(struct sockaddr_un *addr) { int sk; @@ -71,10 +58,8 @@ int main(int argc, char **argv) goto out; } - if (fill_sock_name(&addr, filename) < 0) { - pr_err("filename \"%s\" is too long\n", filename); + if (unix_fill_sock_name(&addr, filename)) goto out; - } sk1 = bind_and_listen(&addr); if (sk1 < 0) diff --git a/test/zdtm/static/deleted_unix_sock.c b/test/zdtm/static/deleted_unix_sock.c index bcc33f3de..4d328e996 100644 --- a/test/zdtm/static/deleted_unix_sock.c +++ b/test/zdtm/static/deleted_unix_sock.c @@ -17,28 +17,13 @@ const char *test_author = "Roman Kagan "; char *filename; TEST_OPTION(filename, string, "file name", 1); -static int fill_sock_name(struct sockaddr_un *name, const char *filename) -{ - char *cwd; - - cwd = get_current_dir_name(); - if (strlen(filename) + strlen(cwd) + 1 >= sizeof(name->sun_path)) - return -1; - - name->sun_family = AF_LOCAL; - sprintf(name->sun_path, "%s/%s", cwd, filename); - return 0; -} - static int setup_srv_sock(void) { struct sockaddr_un name; int sock; - if (fill_sock_name(&name, filename) < 0) { - pr_perror("filename \"%s\" is too long", filename); + if (unix_fill_sock_name(&name, filename)) return -1; - } sock = socket(PF_LOCAL, SOCK_STREAM, 0); if (sock < 0) { @@ -67,7 +52,7 @@ static int setup_clnt_sock(void) struct sockaddr_un name; int sock; - if (fill_sock_name(&name, filename) < 0) + if (unix_fill_sock_name(&name, filename)) return -1; sock = socket(PF_LOCAL, SOCK_STREAM, 0); diff --git a/test/zdtm/static/sk-unix01.c b/test/zdtm/static/sk-unix01.c index 2bceef79a..0e9006a15 100644 --- a/test/zdtm/static/sk-unix01.c +++ b/test/zdtm/static/sk-unix01.c @@ -24,22 +24,6 @@ const char *test_author = "Cyrill Gorcunov "; char *dirname; TEST_OPTION(dirname, string, "directory name", 1); -static int fill_sock_name(struct sockaddr_un *name, const char *filename) -{ - char *cwd; - - cwd = get_current_dir_name(); - if (strlen(filename) + strlen(cwd) + 1 >= sizeof(name->sun_path)) { - pr_err("Name %s/%s is too long for socket\n", - cwd, filename); - return -1; - } - - name->sun_family = AF_LOCAL; - ssprintf(name->sun_path, "%s/%s", cwd, filename); - return 0; -} - static int sk_alloc_bind(int type, struct sockaddr_un *addr) { int sk; @@ -155,10 +139,9 @@ int main(int argc, char **argv) */ ssprintf(filename, "%s/%s", subdir_dg, "sk-dt"); - if (fill_sock_name(&addr, filename) < 0) { - pr_err("%s is too long for socket\n", filename); + if (unix_fill_sock_name(&addr, filename)) return 1; - } + unlink(addr.sun_path); sk_dgram[0] = sk_alloc_bind(SOCK_DGRAM, &addr); @@ -184,10 +167,9 @@ int main(int argc, char **argv) test_msg("sk-dt: alloc/connect/unlink %d %s\n", sk_dgram[3], addr.sun_path); ssprintf(filename, "%s/%s", dirname, "sole"); - if (fill_sock_name(&addr, filename) < 0) { - pr_err("%s is too long for socket\n", filename); + if (unix_fill_sock_name(&addr, filename)) return 1; - } + unlink(addr.sun_path); sk_dgram[4] = sk_alloc_bind(SOCK_DGRAM, &addr); @@ -237,7 +219,7 @@ int main(int argc, char **argv) sk_dgram_pair[0], sk_dgram_pair[1]); ssprintf(filename, "%s/%s", subdir_dg, "sk-dtp"); - if (fill_sock_name(&addr, filename) < 0) { + if (unix_fill_sock_name(&addr, filename)) { pr_err("%s is too long for socket\n", filename); return 1; } @@ -270,10 +252,9 @@ int main(int argc, char **argv) * - delete socket on fs */ ssprintf(filename, "%s/%s", subdir_st, "sk-st"); - if (fill_sock_name(&addr, filename) < 0) { - pr_err("%s is too long for socket\n", filename); + if (unix_fill_sock_name(&addr, filename)) return 1; - } + unlink(addr.sun_path); sk_st[0] = sk_alloc_bind(SOCK_STREAM, &addr); From 2b376168efd751856ebef192e764ebd0037e7174 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 21 Mar 2020 21:58:55 +0300 Subject: [PATCH 2355/4375] pipe: restore pipe size even if a pipe is empty Without this patch, pipe size is restored only if a pipe has queued data. Reported-by: Mr Jenkins Signed-off-by: Andrei Vagin --- criu/pipes.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/criu/pipes.c b/criu/pipes.c index cb5da71de..d74329161 100644 --- a/criu/pipes.c +++ b/criu/pipes.c @@ -160,24 +160,24 @@ int restore_pipe_data(int img_type, int pfd, u32 id, struct pipe_data_rst **hash return 0; } - if (!pd->pde->bytes) - goto out; - - if (!pd->data) { - pr_err("Double data restore occurred on %#x\n", id); - return -1; - } - if (pd->pde->has_size) { pr_info("Restoring size %#x for %#x\n", pd->pde->size, pd->pde->pipe_id); ret = fcntl(pfd, F_SETPIPE_SZ, pd->pde->size); if (ret < 0) { pr_perror("Can't restore pipe size"); - goto err; + return -1; } } + if (!pd->pde->bytes) + return 0; + + if (!pd->data) { + pr_err("Double data restore occurred on %#x\n", id); + return -1; + } + iov.iov_base = pd->data; iov.iov_len = pd->pde->bytes; @@ -185,14 +185,13 @@ int restore_pipe_data(int img_type, int pfd, u32 id, struct pipe_data_rst **hash ret = vmsplice(pfd, &iov, 1, SPLICE_F_GIFT | SPLICE_F_NONBLOCK); if (ret < 0) { pr_perror("%#x: Error splicing data", id); - goto err; + return -1; } if (ret == 0 || ret > iov.iov_len /* sanity */) { pr_err("%#x: Wanted to restore %zu bytes, but got %d\n", id, iov.iov_len, ret); - ret = -1; - goto err; + return -1; } iov.iov_base += ret; @@ -211,10 +210,7 @@ int restore_pipe_data(int img_type, int pfd, u32 id, struct pipe_data_rst **hash munmap(pd->data, pd->pde->bytes); pd->data = NULL; -out: - ret = 0; -err: - return ret; + return 0; } static int userns_reopen(void *_arg, int fd, pid_t pid) From 1ad209b9c2b780fe2d5b043c3ffe29634629252c Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 21 Mar 2020 22:08:38 +0300 Subject: [PATCH 2356/4375] test/pipe03: check that pipe size is restored Create two pipes with and without queued data. Signed-off-by: Andrei Vagin --- test/zdtm/static/pipe03.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/test/zdtm/static/pipe03.c b/test/zdtm/static/pipe03.c index a8721e934..d649007b7 100644 --- a/test/zdtm/static/pipe03.c +++ b/test/zdtm/static/pipe03.c @@ -13,27 +13,28 @@ const char *test_author = "Andrei Vagin "; int main(int argc, char **argv) { - int p[2], i; + int p[2][2], i; uint8_t buf[BUF_SIZE]; uint32_t crc; test_init(argc, argv); - if (pipe2(p, O_NONBLOCK)) { - pr_perror("pipe"); - return 1; - } - - if (fcntl(p[1], F_SETPIPE_SZ, DATA_SIZE) == -1) { - pr_perror("Unable to change a pipe size"); - return 1; + for (i = 0; i < 2; i++) { + if (pipe2(p[i], O_NONBLOCK)) { + pr_perror("pipe"); + return 1; + } + if (fcntl(p[i][1], F_SETPIPE_SZ, DATA_SIZE) == -1) { + pr_perror("Unable to change a pipe size"); + return 1; + } } crc = ~0; datagen(buf, BUF_SIZE, &crc); for (i = 0; i < DATA_SIZE / BUF_SIZE; i++) { - if (write(p[1], buf, BUF_SIZE) != BUF_SIZE) { + if (write(p[0][1], buf, BUF_SIZE) != BUF_SIZE) { pr_perror("write"); return 1; } @@ -43,12 +44,26 @@ int main(int argc, char **argv) test_waitsig(); for (i = 0; i < DATA_SIZE / BUF_SIZE; i++) { - if (read(p[0], buf, BUF_SIZE) != BUF_SIZE) { + if (read(p[0][0], buf, BUF_SIZE) != BUF_SIZE) { pr_perror("read"); return 1; } } + for (i = 0; i < 2; i++) { + int size; + + size = fcntl(p[i][1], F_GETPIPE_SZ); + if (size < 0) { + pr_perror("Unable to get a pipe size"); + return 1; + } + if (size != DATA_SIZE) { + fail("%d: size %d expected %d", i, size, DATA_SIZE); + return 1; + } + } + pass(); return 0; } From 5f28b692a0c972ddefb1ca4d1d0ef003dec4f617 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 21 Mar 2020 22:11:28 +0300 Subject: [PATCH 2357/4375] test/fifo_loop: change sizes of all fifo-s to fit a test buffer This test doesn't expect that the write operation will block. Signed-off-by: Andrei Vagin --- test/zdtm/transition/fifo_loop.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/zdtm/transition/fifo_loop.c b/test/zdtm/transition/fifo_loop.c index b028c2fd5..b06592586 100644 --- a/test/zdtm/transition/fifo_loop.c +++ b/test/zdtm/transition/fifo_loop.c @@ -84,6 +84,14 @@ int main(int argc, char **argv) ret = errno; return ret; } + + pipe_size = fcntl(writefd, F_SETPIPE_SZ, sizeof(buf)); + if (pipe_size != sizeof(buf)) { + pr_perror("fcntl(writefd, F_SETPIPE_SZ) -> %d", pipe_size); + kill(0, SIGKILL); + exit(1); + } + signal(SIGPIPE, SIG_IGN); if (pipe_in2out(readfd, writefd, buf, sizeof(buf)) < 0) /* pass errno as exit code to the parent */ @@ -107,7 +115,7 @@ int main(int argc, char **argv) pipe_size = fcntl(writefd, F_SETPIPE_SZ, sizeof(buf)); if (pipe_size != sizeof(buf)) { - pr_perror("fcntl(writefd, F_GETPIPE_SZ) -> %d", pipe_size); + pr_perror("fcntl(writefd, F_SETPIPE_SZ) -> %d", pipe_size); kill(0, SIGKILL); exit(1); } From 1ad8657ddb3d383874cc07cd3cf456cac7977db6 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 24 Mar 2020 19:31:42 +0300 Subject: [PATCH 2358/4375] config/nftables: include string.h for strlen Fixes: 9433b7b9db3e ("make: use cflags/ldflags for config.h detection mechanism") Signed-off-by: Andrei Vagin --- scripts/feature-tests.mak | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/feature-tests.mak b/scripts/feature-tests.mak index 21b390092..8df20afb7 100644 --- a/scripts/feature-tests.mak +++ b/scripts/feature-tests.mak @@ -152,6 +152,8 @@ endef define FEATURE_TEST_NFTABLES_LIB_API_0 +#include + #include int main(int argc, char **argv) From cc362b432e2d2e3ec68628fb33b117fe3e89f9c2 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Fri, 20 Mar 2020 17:34:57 +0300 Subject: [PATCH 2359/4375] namespaces: fix error handling in dump_user_ns Fix n_xid_map leaks on error path and remove useless exit_code. Fixes: 6e1726f8 ("userns: set uid and gid before entering into userns") Signed-off-by: Pavel Tikhomirov --- criu/namespaces.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/criu/namespaces.c b/criu/namespaces.c index 21266df7c..2db805b2f 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -938,9 +938,9 @@ static int check_user_ns(int pid) int dump_user_ns(pid_t pid, int ns_id) { - int ret, exit_code = -1; UsernsEntry *e = &userns_entry; struct cr_img *img; + int ret; ret = parse_id_map(pid, "uid_map", &e->uid_map); if (ret < 0) @@ -953,7 +953,7 @@ int dump_user_ns(pid_t pid, int ns_id) e->n_gid_map = ret; if (check_user_ns(pid)) - return -1; + goto err; img = open_image(CR_FD_USERNS, O_DUMP, ns_id); if (!img) @@ -973,7 +973,7 @@ err: xfree(e->gid_map[0]); xfree(e->gid_map); } - return exit_code; + return -1; } void free_userns_maps(void) From 967797a8676c8b3b7cd8954892b113c6765af25a Mon Sep 17 00:00:00 2001 From: Byeonggon Lee Date: Sun, 15 Mar 2020 16:32:15 +0900 Subject: [PATCH 2360/4375] Add build directory to gitignore After running make install, build directory is generated but not ignored in gitignore. So this commit add build directory to gitignore. Signed-off-by: Byeonggon Lee --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c231104af..23cd703be 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,4 @@ lib/.crit-setup.files compel/include/asm include/common/asm include/common/config.h +build/ From e3a5d0975240f9e9b6b6d7a096af6b4bbad36737 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 23 Mar 2020 07:37:00 +0300 Subject: [PATCH 2361/4375] memfd: save all memfd inodes in one image Per-object image is acceptable if we expect to have 1-3 objects per-container. If we expect to have more objects, it is better to save them all into one image. There are a number of reasons for this: * We need fewer system calls to read all objects from one image. * It is faster to save or move one image. Signed-off-by: Andrei Vagin --- criu/cr-restore.c | 3 ++ criu/image-desc.c | 2 +- criu/include/image-desc.h | 2 +- criu/include/memfd.h | 2 + criu/memfd.c | 90 +++++++++++++++++---------------------- images/memfd.proto | 1 + 6 files changed, 46 insertions(+), 54 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 41146d4ad..1d3092f2f 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -233,6 +233,9 @@ static int restore_finish_ns_stage(int from, int to) static int crtools_prepare_shared(void) { + if (prepare_memfd_inodes()) + return -1; + if (prepare_files()) return -1; diff --git a/criu/image-desc.c b/criu/image-desc.c index b538a76ea..ac627a829 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -66,7 +66,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY(FS, "fs-%u"), FD_ENTRY(REMAP_FPATH, "remap-fpath"), FD_ENTRY_F(GHOST_FILE, "ghost-file-%x", O_NOBUF), - FD_ENTRY_F(MEMFD_INODE, "memfd-%u", O_NOBUF), + FD_ENTRY_F(MEMFD_INODE, "memfd", O_NOBUF), FD_ENTRY(TCP_STREAM, "tcp-stream-%x"), FD_ENTRY(MNTS, "mountpoints-%u"), FD_ENTRY(NETDEV, "netdev-%u"), diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 9ca9643a1..ce6ef1529 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -65,6 +65,7 @@ enum { CR_FD_CGROUP, CR_FD_FILE_LOCKS, CR_FD_SECCOMP, + CR_FD_MEMFD_INODE, _CR_FD_GLOB_TO, CR_FD_TMPFS_IMG, @@ -107,7 +108,6 @@ enum { CR_FD_PIPES, CR_FD_TTY_FILES, CR_FD_MEMFD_FILE, - CR_FD_MEMFD_INODE, CR_FD_AUTOFS, diff --git a/criu/include/memfd.h b/criu/include/memfd.h index 4189766fd..3074a5c0f 100644 --- a/criu/include/memfd.h +++ b/criu/include/memfd.h @@ -17,6 +17,8 @@ extern struct collect_image_info memfd_cinfo; extern struct file_desc *collect_memfd(u32 id); extern int apply_memfd_seals(void); +extern int prepare_memfd_inodes(void); + #ifdef CONFIG_HAS_MEMFD_CREATE # include #else diff --git a/criu/memfd.c b/criu/memfd.c index bca6900cb..2158e925b 100644 --- a/criu/memfd.c +++ b/criu/memfd.c @@ -43,9 +43,10 @@ struct memfd_inode { }; /* Only for restore */ struct { - mutex_t lock; - int fdstore_id; - unsigned int pending_seals; + mutex_t lock; + int fdstore_id; + unsigned int pending_seals; + MemfdInodeEntry *mie; }; }; }; @@ -71,9 +72,8 @@ int is_memfd(dev_t dev) static int dump_memfd_inode(int fd, struct memfd_inode *inode, const char *name, const struct stat *st) { - int ret = -1; - struct cr_img *img = NULL; MemfdInodeEntry mie = MEMFD_INODE_ENTRY__INIT; + int ret = -1; u32 shmid; /* @@ -90,10 +90,7 @@ static int dump_memfd_inode(int fd, struct memfd_inode *inode, if (dump_one_memfd_shmem(fd, shmid, st->st_size) < 0) goto out; - img = open_image(CR_FD_MEMFD_INODE, O_DUMP, inode->id); - if (!img) - goto out; - + mie.inode_id = inode->id; mie.uid = userns_uid(st->st_uid); mie.gid = userns_gid(st->st_gid); mie.name = (char *)name; @@ -104,14 +101,12 @@ static int dump_memfd_inode(int fd, struct memfd_inode *inode, if (mie.seals == -1) goto out; - if (pb_write_one(img, &mie, PB_MEMFD_INODE)) + if (pb_write_one(img_from_set(glob_imgset, CR_FD_MEMFD_INODE), &mie, PB_MEMFD_INODE)) goto out; ret = 0; out: - if (img) - close_image(img); return ret; } @@ -212,8 +207,6 @@ struct memfd_info { struct memfd_inode *inode; }; -static int memfd_open_inode(struct memfd_inode *inode); - static struct memfd_inode *memfd_alloc_inode(int id) { struct memfd_inode *inode; @@ -222,35 +215,47 @@ static struct memfd_inode *memfd_alloc_inode(int id) if (inode->id == id) return inode; - inode = shmalloc(sizeof(*inode)); - if (!inode) - return NULL; + pr_err("Unable to find the %d memfd inode\n", id); + return NULL; +} - inode->id = id; +static int collect_one_memfd_inode(void *o, ProtobufCMessage *base, struct cr_img *i) +{ + MemfdInodeEntry *mie = pb_msg(base, MemfdInodeEntry); + struct memfd_inode *inode = o; + + inode->mie = mie; + inode->id = mie->inode_id; mutex_init(&inode->lock); inode->fdstore_id = -1; inode->pending_seals = 0; list_add_tail(&inode->list, &memfd_inodes); - return inode; + + return 0; +} + +static struct collect_image_info memfd_inode_cinfo = { + .fd_type = CR_FD_MEMFD_INODE, + .pb_type = PB_MEMFD_INODE, + .priv_size = sizeof(struct memfd_inode), + .collect = collect_one_memfd_inode, + .flags = COLLECT_SHARED | COLLECT_NOFREE, +}; + +int prepare_memfd_inodes(void) +{ + return collect_image(&memfd_inode_cinfo); } -extern int restore_memfd_shm(int fd, u64 id, u64 size); static int memfd_open_inode_nocache(struct memfd_inode *inode) { MemfdInodeEntry *mie = NULL; - struct cr_img *img = NULL; int fd = -1; int ret = -1; int flags; - img = open_image(CR_FD_MEMFD_INODE, O_RSTR, inode->id); - if (!img) - goto out; - - if (pb_read_one(img, &mie, PB_MEMFD_INODE) < 0) - goto out; - + mie = inode->mie; if (mie->seals == F_SEAL_SEAL) { inode->pending_seals = 0; flags = 0; @@ -285,10 +290,6 @@ static int memfd_open_inode_nocache(struct memfd_inode *inode) out: if (fd != -1) close(fd); - if (img) - close_image(img); - if (mie) - memfd_inode_entry__free_unpacked(mie, NULL); return ret; } @@ -373,33 +374,17 @@ static int memfd_open_fe_fd(struct file_desc *fd, int *new_fd) static char *memfd_d_name(struct file_desc *d, char *buf, size_t s) { MemfdInodeEntry *mie = NULL; - struct cr_img *img = NULL; struct memfd_info *mfi; - char *ret = NULL; mfi = container_of(d, struct memfd_info, d); - img = open_image(CR_FD_MEMFD_INODE, O_RSTR, mfi->inode->id); - if (!img) - goto out; - - if (pb_read_one(img, &mie, PB_MEMFD_INODE) < 0) - goto out; - + mie = mfi->inode->mie; if (snprintf(buf, s, "%s%s", MEMFD_PREFIX, mie->name) >= s) { pr_err("Buffer too small for memfd name %s\n", mie->name); - goto out; + return NULL; } - ret = buf; - -out: - if (img) - close_image(img); - if (mie) - memfd_inode_entry__free_unpacked(mie, NULL); - - return ret; + return buf; } static struct file_desc_ops memfd_desc_ops = { @@ -427,7 +412,8 @@ struct collect_image_info memfd_cinfo = { .collect = collect_one_memfd, }; -struct file_desc *collect_memfd(u32 id) { +struct file_desc *collect_memfd(u32 id) +{ struct file_desc *fdesc; fdesc = find_file_desc_raw(FD_TYPES__MEMFD, id); diff --git a/images/memfd.proto b/images/memfd.proto index 546ffc2ab..ad5373d10 100644 --- a/images/memfd.proto +++ b/images/memfd.proto @@ -18,4 +18,5 @@ message memfd_inode_entry { required uint64 size = 4; required uint32 shmid = 5; required uint32 seals = 6 [(criu).flags = "seals.flags"]; + required uint64 inode_id = 7; }; From 8c36865c84666c73424b7a0fdb9f460557465ff2 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 25 Mar 2020 20:14:24 +0300 Subject: [PATCH 2362/4375] memfd: split the struct memfd_inode The struct memfd_inode has a union for dump and restore parts. The only common parts are the list_head node, and the inode id. Suggested-by: Nicolas Viennot Signed-off-by: Andrei Vagin --- criu/memfd.c | 58 ++++++++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/criu/memfd.c b/criu/memfd.c index 2158e925b..4419b4bf5 100644 --- a/criu/memfd.c +++ b/criu/memfd.c @@ -32,23 +32,19 @@ /* Linux 5.1+ */ #define F_SEAL_FUTURE_WRITE 0x0010 /* prevent future writes while mapped */ -struct memfd_inode { +struct memfd_dump_inode { struct list_head list; u32 id; - union { - /* Only for dump */ - struct { - u32 dev; - u32 ino; - }; - /* Only for restore */ - struct { - mutex_t lock; - int fdstore_id; - unsigned int pending_seals; - MemfdInodeEntry *mie; - }; - }; + u32 dev; + u32 ino; +}; + +struct memfd_restore_inode { + struct list_head list; + mutex_t lock; + int fdstore_id; + unsigned int pending_seals; + MemfdInodeEntry *mie; }; static LIST_HEAD(memfd_inodes); @@ -69,7 +65,7 @@ int is_memfd(dev_t dev) return dev == kdat.shmem_dev; } -static int dump_memfd_inode(int fd, struct memfd_inode *inode, +static int dump_memfd_inode(int fd, struct memfd_dump_inode *inode, const char *name, const struct stat *st) { MemfdInodeEntry mie = MEMFD_INODE_ENTRY__INIT; @@ -110,9 +106,10 @@ out: return ret; } -static struct memfd_inode *dump_unique_memfd_inode(int lfd, const char *name, const struct stat *st) +static struct memfd_dump_inode * +dump_unique_memfd_inode(int lfd, const char *name, const struct stat *st) { - struct memfd_inode *inode; + struct memfd_dump_inode *inode; int fd; list_for_each_entry(inode, &memfd_inodes, list) @@ -149,7 +146,7 @@ static int dump_one_memfd(int lfd, u32 id, const struct fd_parms *p) { MemfdFileEntry mfe = MEMFD_FILE_ENTRY__INIT; FileEntry fe = FILE_ENTRY__INIT; - struct memfd_inode *inode; + struct memfd_dump_inode *inode; struct fd_link _link, *link; const char *name; @@ -202,17 +199,17 @@ const struct fdtype_ops memfd_dump_ops = { */ struct memfd_info { - MemfdFileEntry *mfe; - struct file_desc d; - struct memfd_inode *inode; + MemfdFileEntry *mfe; + struct file_desc d; + struct memfd_restore_inode *inode; }; -static struct memfd_inode *memfd_alloc_inode(int id) +static struct memfd_restore_inode *memfd_alloc_inode(int id) { - struct memfd_inode *inode; + struct memfd_restore_inode *inode; list_for_each_entry(inode, &memfd_inodes, list) - if (inode->id == id) + if (inode->mie->inode_id == id) return inode; pr_err("Unable to find the %d memfd inode\n", id); @@ -222,10 +219,9 @@ static struct memfd_inode *memfd_alloc_inode(int id) static int collect_one_memfd_inode(void *o, ProtobufCMessage *base, struct cr_img *i) { MemfdInodeEntry *mie = pb_msg(base, MemfdInodeEntry); - struct memfd_inode *inode = o; + struct memfd_restore_inode *inode = o; inode->mie = mie; - inode->id = mie->inode_id; mutex_init(&inode->lock); inode->fdstore_id = -1; inode->pending_seals = 0; @@ -238,7 +234,7 @@ static int collect_one_memfd_inode(void *o, ProtobufCMessage *base, struct cr_im static struct collect_image_info memfd_inode_cinfo = { .fd_type = CR_FD_MEMFD_INODE, .pb_type = PB_MEMFD_INODE, - .priv_size = sizeof(struct memfd_inode), + .priv_size = sizeof(struct memfd_restore_inode), .collect = collect_one_memfd_inode, .flags = COLLECT_SHARED | COLLECT_NOFREE, }; @@ -248,7 +244,7 @@ int prepare_memfd_inodes(void) return collect_image(&memfd_inode_cinfo); } -static int memfd_open_inode_nocache(struct memfd_inode *inode) +static int memfd_open_inode_nocache(struct memfd_restore_inode *inode) { MemfdInodeEntry *mie = NULL; int fd = -1; @@ -293,7 +289,7 @@ out: return ret; } -static int memfd_open_inode(struct memfd_inode *inode) +static int memfd_open_inode(struct memfd_restore_inode *inode) { int fd; @@ -433,7 +429,7 @@ int apply_memfd_seals(void) */ int ret, fd; - struct memfd_inode *inode; + struct memfd_restore_inode *inode; list_for_each_entry(inode, &memfd_inodes, list) { if (!inode->pending_seals) From e3fb52e375d2fdd7160395220cf52eb25dfc8c09 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 30 Mar 2020 14:16:30 +0300 Subject: [PATCH 2363/4375] remove header include statements duplicates Revert "util: introduce the mount_detached_fs helper" This reverts commit 5dbc24b206cd365db7498dddcd03798c5d8ed4e4. Revert "criu: Make use strlcpy() to copy into allocated strings" This reverts commit bc49927bbc28b41e4b2759d42dc24f1d66e22df3. Fixes for https://github.com/checkpoint-restore/criu/pull/1003 Signed-off-by: Pavel Tikhomirov --- criu/cr-restore.c | 1 - criu/util.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 1d3092f2f..74be1a5ca 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -76,7 +76,6 @@ #include "fdstore.h" #include "string.h" #include "memfd.h" -#include "string.h" #include "parasite-syscall.h" #include "files-reg.h" diff --git a/criu/util.c b/criu/util.c index a0a49c5a3..1646ce1c4 100644 --- a/criu/util.c +++ b/criu/util.c @@ -30,8 +30,6 @@ #include "linux/mount.h" -#include "linux/mount.h" - #include "kerndat.h" #include "page.h" #include "util.h" From 0e9b42acf96d2c5fc3a6174ae6e4f2ad8a64c272 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 25 Feb 2020 11:31:07 +0300 Subject: [PATCH 2364/4375] MAINTAINERS: Add Pavel (myself) to maintainers Hope I have enough experience in the project to be nominated. I want to help with review and will try to do my best in it. Signed-off-by: Pavel Tikhomirov --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5c28463a7..bb153f1ab 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3,3 +3,4 @@ Andrey Vagin Mike Rapoport Dmitry Safonov <0x7f454c46@gmail.com> Adrian Reber +Pavel Tikhomirov From 4127ef4ab769dc4417c22d0ce0a4ddaaca4193b4 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 14 Aug 2019 07:40:40 +0300 Subject: [PATCH 2365/4375] criu: Add support for time namespaces The time namespace allows for per-namespace offsets to the system monotonic and boot-time clocks. C/R of time namespaces are very straightforward. On dump, criu enters a target time namespace and dumps currents clocks values, then on restore, criu creates a new namespace and restores clocks values. Signed-off-by: Andrei Vagin --- criu/Makefile.crtools | 1 + criu/cr-check.c | 12 ++++ criu/cr-restore.c | 10 ++- criu/image-desc.c | 1 + criu/include/image-desc.h | 1 + criu/include/kerndat.h | 1 + criu/include/magic.h | 1 + criu/include/namespaces.h | 9 ++- criu/include/proc_parse.h | 2 + criu/include/protobuf-desc.h | 1 + criu/include/timens.h | 9 +++ criu/kerndat.c | 17 +++++ criu/namespaces.c | 24 +++++++ criu/proc_parse.c | 38 ++++++++++ criu/protobuf-desc.c | 1 + criu/pstree.c | 2 + criu/timens.c | 130 +++++++++++++++++++++++++++++++++++ criu/util.c | 2 + images/Makefile | 1 + images/core.proto | 1 + images/timens.proto | 10 +++ lib/py/images/images.py | 1 + 22 files changed, 272 insertions(+), 3 deletions(-) create mode 100644 criu/include/timens.h create mode 100644 criu/timens.c create mode 100644 images/timens.proto diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 1a6e0b5b5..5c25b8928 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -87,6 +87,7 @@ obj-y += config.o obj-y += servicefd.o obj-y += pie-util-vdso.o obj-y += vdso.o +obj-y += timens.o obj-$(CONFIG_COMPAT) += pie-util-vdso-elf32.o CFLAGS_pie-util-vdso-elf32.o += -DCONFIG_VDSO_32 obj-$(CONFIG_COMPAT) += vdso-compat.o diff --git a/criu/cr-check.c b/criu/cr-check.c index 80df3f7cd..b790c2ffb 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1266,6 +1266,16 @@ static int check_kcmp_epoll(void) return 0; } +static int check_time_namespace(void) +{ + if (!kdat.has_timens) { + pr_err("Time namespaces are not supported\n"); + return -1; + } + + return 0; +} + static int check_net_diag_raw(void) { check_sock_diag(); @@ -1384,6 +1394,7 @@ int cr_check(void) ret |= check_kcmp_epoll(); ret |= check_net_diag_raw(); ret |= check_clone3_set_tid(); + ret |= check_time_namespace(); } /* @@ -1486,6 +1497,7 @@ static struct feature_list feature_list[] = { { "nsid", check_nsid }, { "link_nsid", check_link_nsid}, { "kcmp_epoll", check_kcmp_epoll}, + { "timens", check_time_namespace}, { "external_net_ns", check_external_net_ns}, { "clone3_set_tid", check_clone3_set_tid}, { NULL, NULL }, diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 74be1a5ca..ce6e667d7 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -76,6 +76,7 @@ #include "fdstore.h" #include "string.h" #include "memfd.h" +#include "timens.h" #include "parasite-syscall.h" #include "files-reg.h" @@ -1406,7 +1407,7 @@ static inline int fork_with_pid(struct pstree_item *item) if (kdat.has_clone3_set_tid) { ret = clone3_with_pid_noasan(restore_task_with_children, &ca, (ca.clone_flags & - ~(CLONE_NEWNET | CLONE_NEWCGROUP)), + ~(CLONE_NEWNET | CLONE_NEWCGROUP | CLONE_NEWTIME)), SIGCHLD, pid); } else { /* @@ -1424,7 +1425,7 @@ static inline int fork_with_pid(struct pstree_item *item) close_pid_proc(); ret = clone_noasan(restore_task_with_children, (ca.clone_flags & - ~(CLONE_NEWNET | CLONE_NEWCGROUP)) | SIGCHLD, + ~(CLONE_NEWNET | CLONE_NEWCGROUP | CLONE_NEWTIME)) | SIGCHLD, &ca); } @@ -1745,6 +1746,11 @@ static int restore_task_with_children(void *_arg) } } + if (root_ns_mask & CLONE_NEWTIME) { + if (prepare_timens(current->ids->time_ns_id)) + goto err; + } + /* Wait prepare_userns */ if (restore_finish_ns_stage(CR_STATE_ROOT_TASK, CR_STATE_PREPARE_NAMESPACES) < 0) goto err; diff --git a/criu/image-desc.c b/criu/image-desc.c index ac627a829..617b95355 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -102,6 +102,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY(NETNF_CT, "netns-ct-%u"), FD_ENTRY(NETNF_EXP, "netns-exp-%u"), FD_ENTRY(FILES, "files"), + FD_ENTRY(TIMENS, "timens-%u"), [CR_FD_STATS] = { .fmt = "stats-%s", diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index ce6ef1529..6283a576d 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -26,6 +26,7 @@ enum { CR_FD_UTSNS, CR_FD_MNTS, CR_FD_USERNS, + CR_FD_TIMENS, _CR_FD_IPCNS_FROM, CR_FD_IPC_VAR, diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 27c870bb8..ad5f7d324 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -67,6 +67,7 @@ struct kerndat_s { bool has_kcmp_epoll_tfd; bool has_fsopen; bool has_clone3_set_tid; + bool has_timens; }; extern struct kerndat_s kdat; diff --git a/criu/include/magic.h b/criu/include/magic.h index bdaca968d..d078ec422 100644 --- a/criu/include/magic.h +++ b/criu/include/magic.h @@ -95,6 +95,7 @@ #define AUTOFS_MAGIC 0x49353943 /* Sochi */ #define FILES_MAGIC 0x56303138 /* Toropets */ #define MEMFD_INODE_MAGIC 0x48453499 /* Dnipro */ +#define TIMENS_MAGIC 0x43114433 /* Beslan */ #define IFADDR_MAGIC RAW_IMAGE_MAGIC #define ROUTE_MAGIC RAW_IMAGE_MAGIC diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h index a9a970a9b..e570aa0ab 100644 --- a/criu/include/namespaces.h +++ b/criu/include/namespaces.h @@ -34,7 +34,13 @@ #define CLONE_NEWCGROUP 0x02000000 #endif -#define CLONE_ALLNS (CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWCGROUP) +#ifndef CLONE_NEWTIME +#define CLONE_NEWTIME 0x00000080 +#endif + +#define CLONE_ALLNS (CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWIPC | \ + CLONE_NEWUTS | CLONE_NEWNS | CLONE_NEWUSER | \ + CLONE_NEWCGROUP | CLONE_NEWTIME) /* Nested namespaces are supported only for these types */ #define CLONE_SUBNS (CLONE_NEWNS | CLONE_NEWNET) @@ -146,6 +152,7 @@ extern bool check_ns_proc(struct fd_link *link); extern struct ns_desc pid_ns_desc; extern struct ns_desc user_ns_desc; +extern struct ns_desc time_ns_desc; extern unsigned long root_ns_mask; extern const struct fdtype_ops nsfile_dump_ops; diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h index fd50ff47e..25a57df6c 100644 --- a/criu/include/proc_parse.h +++ b/criu/include/proc_parse.h @@ -102,4 +102,6 @@ extern bool is_vma_range_fmt(char *line); extern void parse_vmflags(char *buf, u32 *flags, u64 *madv, int *io_pf); extern int parse_uptime(uint64_t *upt); +extern int parse_timens_offsets(struct timespec *boff, struct timespec *moff); + #endif /* __CR_PROC_PARSE_H__ */ diff --git a/criu/include/protobuf-desc.h b/criu/include/protobuf-desc.h index 7e0385ef4..ee4135d65 100644 --- a/criu/include/protobuf-desc.h +++ b/criu/include/protobuf-desc.h @@ -63,6 +63,7 @@ enum { PB_FILE, PB_MEMFD_FILE, PB_MEMFD_INODE, /* 60 */ + PB_TIMENS, /* PB_AUTOGEN_STOP */ diff --git a/criu/include/timens.h b/criu/include/timens.h new file mode 100644 index 000000000..22a4a5220 --- /dev/null +++ b/criu/include/timens.h @@ -0,0 +1,9 @@ +#ifndef __CR_TIME_NS_H__ +#define __CR_TIME_NS_H__ + +extern int dump_time_ns(int ns_id); +extern int prepare_timens(int pid); + +extern struct ns_desc time_ns_desc; + +#endif /* __CR_TIME_NS_H__ */ diff --git a/criu/kerndat.c b/criu/kerndat.c index 2ad72c350..0c6910da9 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -783,6 +783,21 @@ out: return ret; } +static int has_time_namespace(void) +{ + if (access("/proc/self/timens_offsets", F_OK) < 0) { + if (errno == ENOENT) { + pr_debug("Time namespaces are not supported.\n"); + kdat.has_timens = false; + return 0; + } + pr_perror("Unable to access /proc/self/timens_offsets"); + return -1; + } + kdat.has_timens = true; + return 0; +} + int __attribute__((weak)) kdat_x86_has_ptrace_fpu_xsave_bug(void) { return 0; @@ -1091,6 +1106,8 @@ int kerndat_init(void) ret = kerndat_has_fsopen(); if (!ret) ret = kerndat_has_clone3_set_tid(); + if (!ret) + ret = has_time_namespace(); kerndat_lsm(); kerndat_mmap_min_addr(); diff --git a/criu/namespaces.c b/criu/namespaces.c index 2db805b2f..e376feaca 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -20,6 +20,7 @@ #include "imgset.h" #include "uts_ns.h" #include "ipc_ns.h" +#include "timens.h" #include "mount.h" #include "pstree.h" #include "namespaces.h" @@ -39,6 +40,7 @@ static struct ns_desc *ns_desc_array[] = { &pid_ns_desc, &user_ns_desc, &mnt_ns_desc, + &time_ns_desc, &cgroup_ns_desc, }; @@ -157,6 +159,9 @@ int join_ns_add(const char *type, char *ns_file, char *extra_opts) } else if (!strncmp(type, "uts", 4)) { jn->nd = &uts_ns_desc; join_ns_flags |= CLONE_NEWUTS; + } else if (!strncmp(type, "time", 5)) { + jn->nd = &time_ns_desc; + join_ns_flags |= CLONE_NEWTIME; } else if (!strncmp(type, "ipc", 4)) { jn->nd = &ipc_ns_desc; join_ns_flags |= CLONE_NEWIPC; @@ -568,6 +573,10 @@ static int open_ns_fd(struct file_desc *d, int *new_fd) item = t; nd = &cgroup_ns_desc; break; + } else if (ids->time_ns_id == nfi->nfe->ns_id) { + item = t; + nd = &time_ns_desc; + break; } } @@ -671,6 +680,13 @@ int dump_task_ns_ids(struct pstree_item *item) return -1; } + ids->has_time_ns_id = true; + ids->time_ns_id = get_ns_id(pid, &time_ns_desc, NULL); + if (!ids->time_ns_id) { + pr_err("Can't make timens id\n"); + return -1; + } + ids->has_mnt_ns_id = true; ids->mnt_ns_id = get_ns_id(pid, &mnt_ns_desc, NULL); if (!ids->mnt_ns_id) { @@ -914,6 +930,9 @@ static int check_user_ns(int pid) if ((root_ns_mask & CLONE_NEWUTS) && switch_ns(pid, &uts_ns_desc, NULL)) exit(1); + if ((root_ns_mask & CLONE_NEWTIME) && + switch_ns(pid, &time_ns_desc, NULL)) + exit(1); if ((root_ns_mask & CLONE_NEWIPC) && switch_ns(pid, &ipc_ns_desc, NULL)) exit(1); @@ -1002,6 +1021,11 @@ static int do_dump_namespaces(struct ns_id *ns) ns->id, ns->ns_pid); ret = dump_uts_ns(ns->id); break; + case CLONE_NEWTIME: + pr_info("Dump TIME namespace %d via %d\n", + ns->id, ns->ns_pid); + ret = dump_time_ns(ns->id); + break; case CLONE_NEWIPC: pr_info("Dump IPC namespace %d via %d\n", ns->id, ns->ns_pid); diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 60aba8788..c73fa9776 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1472,6 +1472,44 @@ static bool should_skip_mount(const char *mountpoint) return false; } +int parse_timens_offsets(struct timespec *boff, struct timespec *moff) +{ + int exit_code = -1; + FILE *f; + + f = fopen_proc(PROC_SELF, "timens_offsets"); + if (!f) { + pr_perror("Unable to open /proc/self/timens_offsets"); + goto out; + } + while (fgets(buf, BUF_SIZE, f)) { + int64_t sec, nsec; + int clockid; + + if (sscanf(buf, "%d %"PRId64" %"PRId64"\n", &clockid, &sec, &nsec) != 3) { + pr_err("Unable to parse: %s\n", buf); + goto out; + } + switch (clockid) { + case CLOCK_MONOTONIC: + moff->tv_sec = sec; + moff->tv_nsec = nsec; + break; + case CLOCK_BOOTTIME: + boff->tv_sec = sec; + boff->tv_nsec = nsec; + break; + default: + pr_err("Unknown clockid: %d\n", clockid); + goto out; + } + } + exit_code = 0; +out: + fclose(f); + return exit_code; +} + struct mount_info *parse_mountinfo(pid_t pid, struct ns_id *nsid, bool for_dump) { struct mount_info *list = NULL; diff --git a/criu/protobuf-desc.c b/criu/protobuf-desc.c index 41c208037..2ee81e5db 100644 --- a/criu/protobuf-desc.c +++ b/criu/protobuf-desc.c @@ -37,6 +37,7 @@ #include "images/creds.pb-c.h" #include "images/timer.pb-c.h" #include "images/utsns.pb-c.h" +#include "images/timens.pb-c.h" #include "images/ipc-var.pb-c.h" #include "images/ipc-shm.pb-c.h" #include "images/ipc-msg.pb-c.h" diff --git a/criu/pstree.c b/criu/pstree.c index 19cf5ad38..d0e81bfad 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -814,6 +814,8 @@ static unsigned long get_clone_mask(TaskKobjIdsEntry *i, mask |= CLONE_NEWIPC; if (i->uts_ns_id != p->uts_ns_id) mask |= CLONE_NEWUTS; + if (i->time_ns_id != p->time_ns_id) + mask |= CLONE_NEWTIME; if (i->mnt_ns_id != p->mnt_ns_id) mask |= CLONE_NEWNS; if (i->user_ns_id != p->user_ns_id) diff --git a/criu/timens.c b/criu/timens.c new file mode 100644 index 000000000..79ba6a2ce --- /dev/null +++ b/criu/timens.c @@ -0,0 +1,130 @@ +#include +#include + +#include "types.h" +#include "proc_parse.h" +#include "namespaces.h" +#include "timens.h" + +#include "protobuf.h" +#include "images/timens.pb-c.h" + +int dump_time_ns(int ns_id) +{ + struct cr_img *img; + TimensEntry te = TIMENS_ENTRY__INIT; + Timespec b = TIMESPEC__INIT, m = TIMESPEC__INIT; + struct timespec ts; + int ret; + + img = open_image(CR_FD_TIMENS, O_DUMP, ns_id); + if (!img) + return -1; + + clock_gettime(CLOCK_MONOTONIC, &ts); + te.monotonic = &m; + te.monotonic->tv_sec = ts.tv_sec; + te.monotonic->tv_nsec = ts.tv_nsec; + clock_gettime(CLOCK_BOOTTIME, &ts); + te.boottime = &b; + te.boottime->tv_sec = ts.tv_sec; + te.boottime->tv_nsec = ts.tv_nsec; + + ret = pb_write_one(img, &te, PB_TIMENS); + close_image(img); + + return ret < 0 ? -1 : 0; +} + +static void normalize_timespec(struct timespec *ts) +{ + while (ts->tv_nsec >= NSEC_PER_SEC) { + ts->tv_nsec -= NSEC_PER_SEC; + ++ts->tv_sec; + } + while (ts->tv_nsec < 0) { + ts->tv_nsec += NSEC_PER_SEC; + --ts->tv_sec; + } +} + + +int prepare_timens(int id) +{ + int exit_code = -1; + int ret, fd = -1; + struct cr_img *img; + TimensEntry *te; + struct timespec ts; + struct timespec prev_moff = {}, prev_boff = {}; + + img = open_image(CR_FD_TIMENS, O_RSTR, id); + if (!img) + return -1; + + ret = pb_read_one(img, &te, PB_TIMENS); + close_image(img); + if (ret < 0) + goto err; + + if (unshare(CLONE_NEWTIME)) { + pr_perror("Unable to create a new time namespace"); + return -1; + } + + if (parse_timens_offsets(&prev_boff, &prev_moff)) + goto err; + + fd = open_proc_rw(PROC_SELF, "timens_offsets"); + if (fd < 0) + goto err; + + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec = ts.tv_sec - prev_moff.tv_sec; + ts.tv_nsec = ts.tv_nsec - prev_moff.tv_nsec; + + ts.tv_sec = te->monotonic->tv_sec - ts.tv_sec; + ts.tv_nsec = te->monotonic->tv_nsec - ts.tv_nsec; + normalize_timespec(&ts); + + pr_debug("timens: %d %ld %ld\n", + CLOCK_MONOTONIC, ts.tv_sec, ts.tv_nsec); + if (dprintf(fd, "%d %ld %ld\n", + CLOCK_MONOTONIC, ts.tv_sec, ts.tv_nsec) < 0) { + pr_perror("Unable to set a monotonic clock offset"); + goto err; + } + + clock_gettime(CLOCK_BOOTTIME, &ts); + + ts.tv_sec = ts.tv_sec - prev_boff.tv_sec; + ts.tv_nsec = ts.tv_nsec - prev_boff.tv_nsec; + + ts.tv_sec = te->boottime->tv_sec - ts.tv_sec; + ts.tv_nsec = te->boottime->tv_nsec - ts.tv_nsec; + normalize_timespec(&ts); + + pr_debug("timens: %d %ld %ld\n", + CLOCK_BOOTTIME, ts.tv_sec, ts.tv_nsec); + if (dprintf(fd, "%d %ld %ld\n", + CLOCK_BOOTTIME, ts.tv_sec, ts.tv_nsec) < 0) { + pr_perror("Unable to set a boottime clock offset"); + goto err; + } + + timens_entry__free_unpacked(te, NULL); + close_safe(&fd); + + fd = open_proc(PROC_SELF, "ns/time_for_children"); + if (fd < 0) { + pr_perror("Unable to open ns/time_for_children"); + goto err; + } + if (switch_ns_by_fd(fd, &time_ns_desc, NULL)) + goto err; + exit_code = 0; +err: + close_safe(&fd); + return exit_code; +} +struct ns_desc time_ns_desc = NS_DESC_ENTRY(CLONE_NEWTIME, "time"); diff --git a/criu/util.c b/criu/util.c index 1646ce1c4..6f6a6dde7 100644 --- a/criu/util.c +++ b/criu/util.c @@ -967,6 +967,8 @@ const char *ns_to_string(unsigned int ns) return "user"; case CLONE_NEWUTS: return "uts"; + case CLONE_NEWTIME: + return "time"; default: return NULL; } diff --git a/images/Makefile b/images/Makefile index e7f0580cf..5ddd37664 100644 --- a/images/Makefile +++ b/images/Makefile @@ -64,6 +64,7 @@ proto-obj-y += autofs.o proto-obj-y += macvlan.o proto-obj-y += sit.o proto-obj-y += memfd.o +proto-obj-y += timens.o CFLAGS += -iquote $(obj)/ diff --git a/images/core.proto b/images/core.proto index e90522914..22c2a9f1f 100644 --- a/images/core.proto +++ b/images/core.proto @@ -70,6 +70,7 @@ message task_kobj_ids_entry { optional uint32 mnt_ns_id = 9; optional uint32 user_ns_id = 10; optional uint32 cgroup_ns_id = 11; + optional uint32 time_ns_id = 12; } message thread_sas_entry { diff --git a/images/timens.proto b/images/timens.proto new file mode 100644 index 000000000..a8272609b --- /dev/null +++ b/images/timens.proto @@ -0,0 +1,10 @@ +syntax = "proto2"; + +message timespec { + required uint64 tv_sec = 1; + required uint64 tv_nsec = 2; +} +message timens_entry { + required timespec monotonic = 1; + required timespec boottime = 2; +} diff --git a/lib/py/images/images.py b/lib/py/images/images.py index dca080657..ca6f207bb 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -466,6 +466,7 @@ handlers = { 'IDS': entry_handler(pb.task_kobj_ids_entry), 'CREDS': entry_handler(pb.creds_entry), 'UTSNS': entry_handler(pb.utsns_entry), + 'TIMENS': entry_handler(pb.timens_entry), 'IPC_VAR': entry_handler(pb.ipc_var_entry), 'FS': entry_handler(pb.fs_entry), 'GHOST_FILE': ghost_file_handler(), From ddba4af608d546a968e9558758718bead9c638c5 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 28 Mar 2020 22:14:40 +0300 Subject: [PATCH 2366/4375] namespace: fail if ns/time_for_children isn't equal to ns/time This case isn't supported right now. Signed-off-by: Andrei Vagin --- criu/include/timens.h | 1 + criu/namespaces.c | 20 ++++++++++++++++---- criu/timens.c | 2 ++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/criu/include/timens.h b/criu/include/timens.h index 22a4a5220..0567c5828 100644 --- a/criu/include/timens.h +++ b/criu/include/timens.h @@ -5,5 +5,6 @@ extern int dump_time_ns(int ns_id); extern int prepare_timens(int pid); extern struct ns_desc time_ns_desc; +extern struct ns_desc time_for_children_ns_desc; #endif /* __CR_TIME_NS_H__ */ diff --git a/criu/namespaces.c b/criu/namespaces.c index e376feaca..89d97c7bc 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -341,7 +341,7 @@ struct ns_id *lookup_ns_by_kid(unsigned int kid, struct ns_desc *nd) struct ns_id *nsid; for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) - if (nsid->kid == kid && nsid->nd == nd) + if (nsid->kid == kid && nsid->nd->cflag == nd->cflag) return nsid; return NULL; @@ -447,7 +447,7 @@ static unsigned int __get_ns_id(int pid, struct ns_desc *nd, protobuf_c_boolean { int proc_dir; unsigned int kid; - char ns_path[10]; + char ns_path[32]; struct stat st; proc_dir = open_pid_proc(pid); @@ -680,12 +680,24 @@ int dump_task_ns_ids(struct pstree_item *item) return -1; } - ids->has_time_ns_id = true; - ids->time_ns_id = get_ns_id(pid, &time_ns_desc, NULL); + ids->time_ns_id = get_ns_id(pid, &time_ns_desc, &ids->has_time_ns_id); if (!ids->time_ns_id) { pr_err("Can't make timens id\n"); return -1; } + if (ids->has_time_ns_id) { + unsigned int id; + protobuf_c_boolean supported; + id = get_ns_id(pid, &time_for_children_ns_desc, &supported); + if (!supported || !id) { + pr_err("Can't make timens id\n"); + return -1; + } + if (id != ids->time_ns_id) { + pr_err("Can't dump nested time namespace for %d\n", pid); + return -1; + } + } ids->has_mnt_ns_id = true; ids->mnt_ns_id = get_ns_id(pid, &mnt_ns_desc, NULL); diff --git a/criu/timens.c b/criu/timens.c index 79ba6a2ce..764f8c9e0 100644 --- a/criu/timens.c +++ b/criu/timens.c @@ -128,3 +128,5 @@ err: return exit_code; } struct ns_desc time_ns_desc = NS_DESC_ENTRY(CLONE_NEWTIME, "time"); +struct ns_desc time_for_children_ns_desc = + NS_DESC_ENTRY(CLONE_NEWTIME, "time_for_children"); From 3fd0fa4bdc7d325bb244ef01873255e4ebcbb403 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 14 Aug 2019 07:44:02 +0300 Subject: [PATCH 2367/4375] zdtm: add support for time namespaces For ns and uns flavors, tests run in separate time namespaces. Signed-off-by: Andrei Vagin --- test/zdtm/lib/ns.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/test/zdtm/lib/ns.c b/test/zdtm/lib/ns.c index 3099f7495..0054a3040 100644 --- a/test/zdtm/lib/ns.c +++ b/test/zdtm/lib/ns.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include "zdtmtst.h" #include "ns.h" @@ -207,6 +209,39 @@ write_out: write(STDERR_FILENO, buf, MIN(len, sizeof(buf))); } +#ifndef CLONE_NEWTIME +#define CLONE_NEWTIME 0x00000080 /* New time namespace */ +#endif + +static inline int _settime(clockid_t clk_id, time_t offset) +{ + int fd, len; + char buf[4096]; + + if (clk_id == CLOCK_MONOTONIC_COARSE || clk_id == CLOCK_MONOTONIC_RAW) + clk_id = CLOCK_MONOTONIC; + + len = snprintf(buf, sizeof(buf), "%d %ld 0", clk_id, offset); + + fd = open("/proc/self/timens_offsets", O_WRONLY); + if (fd < 0) { + fprintf(stderr, "open(/proc/self/timens_offsets): %m"); + return -1; + } + + if (write(fd, buf, len) != len) { + fprintf(stderr, "write(/proc/self/timens_offsets): %m"); + return -1; + } + + if (close(fd)) { + fprintf(stderr, "close(/proc/self/timens_offsets): %m"); + return -1; + } + + return 0; +} + #define STATUS_FD 255 static int ns_exec(void *_arg) { @@ -218,6 +253,7 @@ static int ns_exec(void *_arg) setsid(); + prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); ret = dup2(args->status_pipe[1], STATUS_FD); if (ret < 0) { fprintf(stderr, "dup2() failed: %m\n"); @@ -236,6 +272,35 @@ static int ns_exec(void *_arg) return -1; } +static int create_timens(void) +{ + int fd; + + if (unshare(CLONE_NEWTIME)) { + if (errno == EINVAL) { + fprintf(stderr, "timens isn't supported\n"); + return 0; + } else { + fprintf(stderr, "unshare(CLONE_NEWTIME) failed: %m"); + exit(1); + } + } + + if (_settime(CLOCK_MONOTONIC, 10 * 24 * 60 * 60)) + exit(1); + if (_settime(CLOCK_BOOTTIME, 20 * 24 * 60 * 60)) + exit(1); + + fd = open("/proc/self/ns/time_for_children", O_RDONLY); + if (fd < 0) + exit(1); + if (setns(fd, 0)) + exit(1); + close(fd); + + return 0; +} + int ns_init(int argc, char **argv) { struct sigaction sa = { @@ -253,6 +318,9 @@ int ns_init(int argc, char **argv) exit(1); } + if (create_timens()) + exit(1); + if (init_notify()) { fprintf(stderr, "Can't init pre-dump notification: %m"); exit(1); From f1655fd5402f7827415cddbd796e5e44ed33cbc9 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 14 Aug 2019 07:45:34 +0300 Subject: [PATCH 2368/4375] zdtm: add a new test to check c/r of time namespaces This test checks that monotonic and boottime don't jump after C/R. In ns and uns flavors, the test is started in a separate time namespace with big offsets, so if criu will restore a time namespace incorrectly the test will detect the big delta of clocks values before and after C/R. Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 1 + test/zdtm/static/time.c | 47 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 test/zdtm/static/time.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index a8e4107d3..1b7542574 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -226,6 +226,7 @@ TST_NOFILE := \ memfd03 \ shmemfd \ shmemfd-priv \ + time \ # jobctl00 \ ifneq ($(ARCH),arm) diff --git a/test/zdtm/static/time.c b/test/zdtm/static/time.c new file mode 100644 index 000000000..d37e2a8f8 --- /dev/null +++ b/test/zdtm/static/time.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check monotonic and boot clocks"; +const char *test_author = "Andrei Vagin b + 60 * 60 * NSEC_PER_SEC) { + fail("%d: %lld %lld", clocks[i], a, b); + return 1; + } + } + + pass(); + + return 0; +} From 0d8c0562f9d8e67bae04f1b1aea08e485edf7340 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 15 Aug 2019 06:51:15 +0300 Subject: [PATCH 2369/4375] zdtm_ct: run each test in a new time namespace Signed-off-by: Andrei Vagin --- test/zdtm_ct.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/zdtm_ct.c b/test/zdtm_ct.c index bc88dadde..5495d61eb 100644 --- a/test/zdtm_ct.c +++ b/test/zdtm_ct.c @@ -5,6 +5,69 @@ #include #include #include +#include +#include +#include +#include + +#ifndef CLONE_NEWTIME +#define CLONE_NEWTIME 0x00000080 /* New time namespace */ +#endif + +static inline int _settime(clockid_t clk_id, time_t offset) +{ + int fd, len; + char buf[4096]; + + if (clk_id == CLOCK_MONOTONIC_COARSE || clk_id == CLOCK_MONOTONIC_RAW) + clk_id = CLOCK_MONOTONIC; + + len = snprintf(buf, sizeof(buf), "%d %ld 0", clk_id, offset); + + fd = open("/proc/self/timens_offsets", O_WRONLY); + if (fd < 0) { + fprintf(stderr, "/proc/self/timens_offsets: %m"); + return -1; + } + + if (write(fd, buf, len) != len) { + fprintf(stderr, "/proc/self/timens_offsets: %m"); + return -1; + } + + close(fd); + + return 0; +} + +static int create_timens() +{ + int fd; + + if (unshare(CLONE_NEWTIME)) { + if (errno == EINVAL) { + fprintf(stderr, "timens isn't supported\n"); + return 0; + } else { + fprintf(stderr, "unshare(CLONE_NEWTIME) failed: %m"); + exit(1); + } + } + + if (_settime(CLOCK_MONOTONIC, 110 * 24 * 60 * 60)) + exit(1); + if (_settime(CLOCK_BOOTTIME, 40 * 24 * 60 * 60)) + exit(1); + + fd = open("/proc/self/ns/time_for_children", O_RDONLY); + if (fd < 0) + exit(1); + if (setns(fd, 0)) + exit(1); + close(fd); + + return 0; +} int main(int argc, char **argv) { @@ -20,6 +83,8 @@ int main(int argc, char **argv) return 1; pid = fork(); if (pid == 0) { + if (create_timens()) + exit(1); if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL)) { fprintf(stderr, "mount(/, S_REC | MS_SLAVE)): %m"); return 1; From 73438d34bb5bfba5f0ac063c699f66454c722c51 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 26 Mar 2020 10:55:13 +0300 Subject: [PATCH 2370/4375] test: check that C/R of nested time namespaces fails Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 2 + test/zdtm/static/timens_for_kids.c | 36 ++++++++++++++ test/zdtm/static/timens_for_kids.desc | 1 + test/zdtm/static/timens_nested.c | 67 +++++++++++++++++++++++++++ test/zdtm/static/timens_nested.desc | 1 + 5 files changed, 107 insertions(+) create mode 100644 test/zdtm/static/timens_for_kids.c create mode 100644 test/zdtm/static/timens_for_kids.desc create mode 100644 test/zdtm/static/timens_nested.c create mode 100644 test/zdtm/static/timens_nested.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 1b7542574..7d72673c3 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -227,6 +227,8 @@ TST_NOFILE := \ shmemfd \ shmemfd-priv \ time \ + timens_nested \ + timens_for_kids \ # jobctl00 \ ifneq ($(ARCH),arm) diff --git a/test/zdtm/static/timens_for_kids.c b/test/zdtm/static/timens_for_kids.c new file mode 100644 index 000000000..72543486b --- /dev/null +++ b/test/zdtm/static/timens_for_kids.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check nested time namespaces"; +const char *test_author = "Andrei Vagin +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check nested time namespaces"; +const char *test_author = "Andrei Vagin Date: Mon, 23 Mar 2020 03:26:00 +0300 Subject: [PATCH 2371/4375] timens: restore processes in a new timens to restore clocks After restoring processes, we have to be sure that monotonic and boottime clocks will not go backward. For this, we can restore processes in a new time namespace and set proper offsets for the clocks. In this patch, criu dumps clocks values event when processes are running in this host time namespace and on restore, criu creates a new time namespace, sets dumped clock values and restores processes. Signed-off-by: Andrei Vagin --- criu/cr-dump.c | 7 +++++++ criu/cr-restore.c | 3 +++ criu/timens.c | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 6aa114c2d..a38e47d12 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -81,6 +81,7 @@ #include "dump.h" #include "eventpoll.h" #include "memfd.h" +#include "timens.h" /* * Architectures can overwrite this function to restore register sets that @@ -1921,6 +1922,12 @@ int cr_dump_tasks(pid_t pid) goto err; } + if ((root_ns_mask & CLONE_NEWTIME) == 0) { + ret = dump_time_ns(0); + if (ret) + goto err; + } + ret = dump_cgroups(); if (ret) goto err; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index ce6e667d7..ed4b95b91 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1749,6 +1749,9 @@ static int restore_task_with_children(void *_arg) if (root_ns_mask & CLONE_NEWTIME) { if (prepare_timens(current->ids->time_ns_id)) goto err; + } else if (kdat.has_timens) { + if (prepare_timens(0)) + goto err; } /* Wait prepare_userns */ diff --git a/criu/timens.c b/criu/timens.c index 764f8c9e0..f3b50fdff 100644 --- a/criu/timens.c +++ b/criu/timens.c @@ -62,6 +62,11 @@ int prepare_timens(int id) if (!img) return -1; + if (id == 0 && empty_image(img)) { + pr_warn("Clocks values have not been dumped\n"); + return 0; + } + ret = pb_read_one(img, &te, PB_TIMENS); close_image(img); if (ret < 0) From 698f3a4dbd8754a5c8bf1bf8f682d176f3bd24fb Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 26 Mar 2020 20:03:34 +0300 Subject: [PATCH 2372/4375] zdtm: limit the line length for ps by 160 symbols By default, this limit is 80 symbols and this isn't enough: 4730 pts/0 S+ 0:00 \_ ./zdtm_ct zdtm.py 7535 4731 pts/0 S+ 0:00 | \_ python zdtm.py 7536 4839 pts/0 S+ 0:00 | \_ python zdtm.p 7537 4861 pts/0 S+ 0:00 | \_ make --no 7538 4882 pts/0 S+ 0:00 | \_ ./mnt 7539 4883 ? Ss 0:00 | \_ . Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index 0bd7b84cc..ac8d7bee0 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1885,7 +1885,7 @@ class Launcher: pid, status = os.waitpid(0, flags) except OSError as e: if e.errno == errno.EINTR: - subprocess.Popen(["ps", "axf"]).wait() + subprocess.Popen(["ps", "axf", "--width", "160"]).wait() continue signal.alarm(0) raise e From 067a20c815c5a632eee63469bcc9d99af73a9c79 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 28 Mar 2020 22:13:17 +0300 Subject: [PATCH 2373/4375] zdtm: fail if test with the crfail tag passes Signed-off-by: Andrei Vagin --- test/zdtm.py | 2 ++ test/zdtm/static/unhashed_proc.desc | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test/zdtm.py b/test/zdtm.py index ac8d7bee0..5e42c769e 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -1735,6 +1735,8 @@ def do_run_test(tname, tdesc, flavs, opts): t.stop() cr_api.fini() try_run_hook(t, ["--clean"]) + if t.blocking(): + raise test_fail_exc("unexpected success") except test_fail_exc as e: print_sep("Test %s FAIL at %s" % (tname, e.step), '#') t.print_output() diff --git a/test/zdtm/static/unhashed_proc.desc b/test/zdtm/static/unhashed_proc.desc index 847e3b27c..de1915b23 100644 --- a/test/zdtm/static/unhashed_proc.desc +++ b/test/zdtm/static/unhashed_proc.desc @@ -1 +1 @@ -{'flags': 'crfail', 'opts' : '--link-remap'} +{'opts' : '--link-remap'} From bb0b4219efbda66995887b09fb3d6d81dc314031 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 31 Mar 2020 14:16:30 +0000 Subject: [PATCH 2374/4375] img: fix image_name() when image is empty When an image is opened but errored with a ENOENT error, the image is still valid. Later on, do_pb_read_one() can fail and will invoke image_name(). The image fd is EMPTY_IMG_FD (-404). read_fd_link fails. Signed-off-by: Nicolas Viennot --- criu/protobuf.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/criu/protobuf.c b/criu/protobuf.c index e68d42b5c..4accc5ee0 100644 --- a/criu/protobuf.c +++ b/criu/protobuf.c @@ -25,8 +25,13 @@ static char *image_name(struct cr_img *img) int fd = img->_x.fd; static char image_path[PATH_MAX]; - if (read_fd_link(fd, image_path, sizeof(image_path)) > 0) + if (lazy_image(img)) + return img->path; + else if (empty_image(img)) + return "(empty-image)"; + else if (fd >= 0 && read_fd_link(fd, image_path, sizeof(image_path)) > 0) return image_path; + return NULL; } From 4d34f84bb6957f00d3440a428ecd80dd869212be Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Fri, 10 Apr 2020 21:10:27 +0000 Subject: [PATCH 2375/4375] img: rellocate a PATH_MAX buffer from the bss section to the stack Reducing our memory footprint by 4K. Improved-by: Andrei Vagin Signed-off-by: Nicolas Viennot --- criu/protobuf.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/criu/protobuf.c b/criu/protobuf.c index 4accc5ee0..206223ca5 100644 --- a/criu/protobuf.c +++ b/criu/protobuf.c @@ -20,16 +20,16 @@ #include "protobuf.h" #include "util.h" -static char *image_name(struct cr_img *img) +#define image_name(img, buf) __image_name(img, buf, sizeof(buf)) +static char *__image_name(struct cr_img *img, char *image_path, size_t image_path_size) { int fd = img->_x.fd; - static char image_path[PATH_MAX]; if (lazy_image(img)) return img->path; else if (empty_image(img)) return "(empty-image)"; - else if (fd >= 0 && read_fd_link(fd, image_path, sizeof(image_path)) > 0) + else if (fd >= 0 && read_fd_link(fd, image_path, image_path_size) > 0) return image_path; return NULL; @@ -48,6 +48,7 @@ static char *image_name(struct cr_img *img) int do_pb_read_one(struct cr_img *img, void **pobj, int type, bool eof) { + char img_name_buf[PATH_MAX]; u8 local[PB_PKOBJ_LOCAL_SIZE]; void *buf = (void *)&local; u32 size; @@ -55,7 +56,7 @@ int do_pb_read_one(struct cr_img *img, void **pobj, int type, bool eof) if (!cr_pb_descs[type].pb_desc) { pr_err("Wrong object requested %d on %s\n", - type, image_name(img)); + type, image_name(img, img_name_buf)); return -1; } @@ -70,13 +71,13 @@ int do_pb_read_one(struct cr_img *img, void **pobj, int type, bool eof) return 0; } else { pr_err("Unexpected EOF on %s\n", - image_name(img)); + image_name(img, img_name_buf)); return -1; } } else if (ret < sizeof(size)) { pr_perror("Read %d bytes while %d expected on %s", ret, (int)sizeof(size), - image_name(img)); + image_name(img, img_name_buf)); return -1; } @@ -90,11 +91,11 @@ int do_pb_read_one(struct cr_img *img, void **pobj, int type, bool eof) ret = bread(&img->_x, buf, size); if (ret < 0) { pr_perror("Can't read %d bytes from file %s", - size, image_name(img)); + size, image_name(img, img_name_buf)); goto err; } else if (ret != size) { pr_perror("Read %d bytes while %d expected from %s", - ret, size, image_name(img)); + ret, size, image_name(img, img_name_buf)); ret = -1; goto err; } @@ -103,7 +104,7 @@ int do_pb_read_one(struct cr_img *img, void **pobj, int type, bool eof) if (!*pobj) { ret = -1; pr_err("Failed unpacking object %p from %s\n", - pobj, image_name(img)); + pobj, image_name(img, img_name_buf)); goto err; } From 6b9faabf39e14bbc23fe3174f308a5f9f870113f Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 28 Mar 2020 00:18:48 +0000 Subject: [PATCH 2376/4375] mem: avoid re-opening CR_FD_PAGES when not needed This commit introduces an optimization when rsti(t)->vma_io is empty. This optimization allows streaming a non-seekable image as CR_FD_PAGES is not reopened. Signed-off-by: Nicolas Viennot --- criu/mem.c | 14 ++++++++++++++ criu/pie/restorer.c | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/criu/mem.c b/criu/mem.c index 55022d94a..15aa0cbdb 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -1403,6 +1403,20 @@ static int prepare_vma_ios(struct pstree_item *t, struct task_restore_args *ta) { struct cr_img *pages; + /* + * We optimize the case when rsti(t)->vma_io is empty. + * + * This is useful for for remote images, where all VMAs are premapped + * (pr->pieok is false). This avoids re-opening the CR_FD_PAGES file, + * which could be no longer be available. + */ + if (list_empty(&rsti(t)->vma_io)) { + ta->vma_ios = NULL; + ta->vma_ios_n = 0; + ta->vma_ios_fd = -1; + return 0; + } + /* * If auto-dedup is on we need RDWR mode to be able to punch holes in * the input files (in restorer.c) diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index afe185f04..b3d7e2b5c 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -1602,7 +1602,8 @@ long __export_restore_task(struct task_restore_args *args) rio = ((void *)rio) + RIO_SIZE(rio->nr_iovs); } - sys_close(args->vma_ios_fd); + if (args->vma_ios_fd != -1) + sys_close(args->vma_ios_fd); /* * Proxify vDSO. From d1fa1734ee53404f8a06d82a5732dc1daff8d756 Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Wed, 4 Mar 2020 18:26:37 +0300 Subject: [PATCH 2377/4375] autofs: fix integer overflow in mount options parsing In real life cases pipe_ino param could be larger that INT_MAX, but in autofs_parse() function we using atoi function, that uses 4 byte integers. It's a bug. Example of mount info from real case: (00.508286) type autofs source /etc/auto.misc mnt_id 2824 s_dev 0x4b9 / @ ./misc flags 0x300000 options fd=5,pipe_ino=3480845226,pgrp=95929,timeout=300, minproto=5,maxproto=5,indirect 3480845226 > 2147483647 (32-bit wide signed int max value) => we have a problem It causes a error: (03.195915) Error (criu/pipes.c:529): The packetized mode for pipes is not supported yet Signed-off-by: Alexander Mikhalitsyn (Virtuozzo) --- criu/autofs.c | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/criu/autofs.c b/criu/autofs.c index a2dc60ffc..175b8900e 100644 --- a/criu/autofs.c +++ b/criu/autofs.c @@ -62,25 +62,53 @@ int autofs_parse(struct mount_info *pm) { long pipe_ino = AUTOFS_OPT_UNKNOWN; char **opts; - int nr_opts, i; + int nr_opts, i, ret; split(pm->options, ',', &opts, &nr_opts); if (!opts) return -1; + for (i = 0; i < nr_opts; i++) { if (!strncmp(opts[i], "pipe_ino=", strlen("pipe_ino="))) - pipe_ino = atoi(opts[i] + strlen("pipe_ino=")); + if (xatol(opts[i] + strlen("pipe_ino="), &pipe_ino)) { + pr_err("pipe_ino (%s) mount option parse failed\n", opts[i] + strlen("pipe_ino=")); + ret = -1; + goto free; + } + } + + /* + * We must inform user about bug if pipe_ino is greater than UINT32_MAX, + * because it means that something changed in Linux Kernel virtual fs + * inode numbers generation mechanism. What we have at the moment: + * 1. struct inode i_ino field (include/linux/fs.h in Linux kernel) + * has unsigned long type. + * 2. get_next_ino() function (fs/inode.c), that used for generating inode + * numbers on virtual filesystems (pipefs, debugfs for instance) + * has unsigned int as return type. + * So, it means that ATM it is safe to keep uint32 type for pipe_id field + * in pipe-data.proto. + */ + if (pipe_ino > UINT32_MAX) { + pr_err("overflow: pipe_ino > UINT32_MAX\n"); + ret = -1; + goto free; } - for (i = 0; i < nr_opts; i++) - xfree(opts[i]); - free(opts); if (pipe_ino == AUTOFS_OPT_UNKNOWN) { pr_warn("Failed to find pipe_ino option (old kernel?)\n"); - return 0; + ret = 0; + goto free; } - return autofs_gather_pipe(pipe_ino); + ret = autofs_gather_pipe(pipe_ino); + +free: + for (i = 0; i < nr_opts; i++) + xfree(opts[i]); + xfree(opts); + + return ret; } static int autofs_check_fd_stat(struct stat *stat, int prgp, int fd, From 62088c721f08aaec8b63de3904304a3a31dcefea Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 14 Apr 2020 10:04:28 +0300 Subject: [PATCH 2378/4375] criu: put statement continuation on the same line as the closing bracket We should follow Linux Kernel Codding Style: ... the closing brace is empty on a line of its own, except in the cases where it is followed by a continuation of the same statement, ie ... an else in an if-statement ... https://www.kernel.org/doc/html/v4.10/process/coding-style.html#placing-braces-and-spaces Automaticly fixing with: :!git grep --files-with-matches "^\s*else[^{]*{" | xargs :argadd :argdo :%s/}\s*\n\s*\(else[^{]*{\)/} \1/g | update Signed-off-by: Pavel Tikhomirov --- compel/arch/ppc64/src/lib/infect.c | 6 ++---- compel/src/main.c | 9 +++------ criu/arch/ppc64/crtools.c | 3 +-- criu/cr-dump.c | 3 +-- test/zdtm/static/fifo_wronly.c | 3 +-- test/zdtm/static/inotify_system.c | 3 +-- test/zdtm/static/ptrace_sig.c | 3 +-- test/zdtm/static/vsx.c | 3 +-- test/zdtm/transition/epoll.c | 3 +-- 9 files changed, 12 insertions(+), 24 deletions(-) diff --git a/compel/arch/ppc64/src/lib/infect.c b/compel/arch/ppc64/src/lib/infect.c index defed3d85..637acd46d 100644 --- a/compel/arch/ppc64/src/lib/infect.c +++ b/compel/arch/ppc64/src/lib/infect.c @@ -222,8 +222,7 @@ static int get_altivec_regs(pid_t pid, user_fpregs_struct_t *fp) return -1; } pr_debug("Altivec not supported\n"); - } - else { + } else { pr_debug("Dumping Altivec registers\n"); fp->flags |= USER_FPREGS_FL_ALTIVEC; } @@ -251,8 +250,7 @@ static int get_vsx_regs(pid_t pid, user_fpregs_struct_t *fp) return -1; } pr_debug("VSX register's dump not supported.\n"); - } - else { + } else { pr_debug("Dumping VSX registers\n"); fp->flags |= USER_FPREGS_FL_VSX; } diff --git a/compel/src/main.c b/compel/src/main.c index 36127c357..9fc3a924c 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -181,8 +181,7 @@ static void print_ldflags(bool compat) if (uninst_root) { printf("%s/arch/%s/scripts/compel-pack%s.lds.S\n", uninst_root, flags.arch, compat_str); - } - else { + } else { printf("%s/compel/scripts/compel-pack%s.lds.S\n", LIBEXECDIR, compat_str); @@ -222,8 +221,7 @@ static int print_libs(bool is_static) return 1; } printf("%s/%s\n", uninst_root, STATIC_LIB); - } - else { + } else { printf("%s/%s\n", LIBDIR, (is_static) ? STATIC_LIB : DYN_LIB); } @@ -255,8 +253,7 @@ static char *gen_prefix(const char *path) for (i = len - 1; i >= 0; i--) { if (!p1 && path[i] == '.') { p2 = path + i - 1; - } - else if (!p1 && path[i] == '/') { + } else if (!p1 && path[i] == '/') { p1 = path + i + 1; break; } diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index 0d9f49c3f..631150c3e 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -374,8 +374,7 @@ static int __copy_task_regs(user_regs_struct_t *regs, fpstate = &(core->ti_ppc64->tmstate->fpstate); vrstate = &(core->ti_ppc64->tmstate->vrstate); vsxstate = &(core->ti_ppc64->tmstate->vsxstate); - } - else { + } else { gpregs = core->ti_ppc64->gpregs; fpstate = &(core->ti_ppc64->fpstate); vrstate = &(core->ti_ppc64->vrstate); diff --git a/criu/cr-dump.c b/criu/cr-dump.c index a38e47d12..745998afc 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -1529,8 +1529,7 @@ static int cr_pre_dump_finish(int status) timing_stop(TIME_MEMWRITE); ret = page_xfer_predump_pages(item->pid->real, &xfer, mem_pp); - } - else { + } else { ret = page_xfer_dump_pages(&xfer, mem_pp); } diff --git a/test/zdtm/static/fifo_wronly.c b/test/zdtm/static/fifo_wronly.c index 2fbd69e6b..78fc7c8f7 100644 --- a/test/zdtm/static/fifo_wronly.c +++ b/test/zdtm/static/fifo_wronly.c @@ -55,8 +55,7 @@ int main(int argc, char **argv) pr_perror("read error %s", filename); chret = errno; return chret; - } - else if (res == 0) { + } else if (res == 0) { pr_perror("read(%d, rbuf, 7) return 0", fd1); return 1; } diff --git a/test/zdtm/static/inotify_system.c b/test/zdtm/static/inotify_system.c index 3e6b2ad48..f8af3dca2 100644 --- a/test/zdtm/static/inotify_system.c +++ b/test/zdtm/static/inotify_system.c @@ -280,8 +280,7 @@ int errors(int exp_len, int len, char *etalon_buf, char *buf) { fail("Incorrect length of field name."); error++; break; - } - else if (event->len && strncmp(event->name, exp_event->name, event->len)) { + } else if (event->len && strncmp(event->name, exp_event->name, event->len)) { fail("Handled file name %s, expected %s", event->name, exp_event->name); diff --git a/test/zdtm/static/ptrace_sig.c b/test/zdtm/static/ptrace_sig.c index f71517717..b70f8f1b0 100644 --- a/test/zdtm/static/ptrace_sig.c +++ b/test/zdtm/static/ptrace_sig.c @@ -74,8 +74,7 @@ int main(int argc, char ** argv) if (cpid < 0) { pr_perror("fork failed"); return 1; - } - else if (cpid == 0) { + } else if (cpid == 0) { close(child_pipe[0]); return child(child_pipe[1]); } diff --git a/test/zdtm/static/vsx.c b/test/zdtm/static/vsx.c index be02cfe10..e7d81b12c 100644 --- a/test/zdtm/static/vsx.c +++ b/test/zdtm/static/vsx.c @@ -388,8 +388,7 @@ int main(int argc, char *argv[]) test_msg("Data mismatch\n"); fail(); } - } - else { + } else { test_msg("The CPU is missing some features.\n"); fail(); } diff --git a/test/zdtm/transition/epoll.c b/test/zdtm/transition/epoll.c index 4eac5214c..6ab436889 100644 --- a/test/zdtm/transition/epoll.c +++ b/test/zdtm/transition/epoll.c @@ -181,8 +181,7 @@ int main(int argc, char **argv) fail("waitpid error: %m\n"); counter++; continue; - } - else { + } else { rv = WEXITSTATUS(rv); if (rv < MAX_EXIT_CODE && rv > SUCCESS) { fail("Child failed: %s (%d)\n", From ef7ef9cfa0c0ae4a2777c72b9facf994068b817e Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 14 Apr 2020 18:03:38 +0000 Subject: [PATCH 2379/4375] kerndat: remove duplicate call to kerndat_socket_netns() kerndat_socket_netns() is called twice. We keep the latter to avoid changing the behavior. Signed-off-by: Nicolas Viennot --- criu/kerndat.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/criu/kerndat.c b/criu/kerndat.c index 0c6910da9..0421997af 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -1068,8 +1068,6 @@ int kerndat_init(void) ret = kerndat_tcp_repair(); if (!ret) ret = kerndat_compat_restore(); - if (!ret) - ret = kerndat_socket_netns(); if (!ret) ret = kerndat_tun_netns(); if (!ret) From 2c2fdd3334078f5eefea4f82f0df0fccfc8a9238 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 13 Apr 2020 17:20:34 +0000 Subject: [PATCH 2380/4375] parasite-msg: %u is not implemented for parasite code Changed all the %u into %d. Ideally, we should implement the %u format for parasite code. Signed-off-by: Nicolas Viennot --- criu/pie/parasite.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index 64b5bbb3e..d83978317 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -53,7 +53,7 @@ static int mprotect_vmas(struct parasite_dump_pages_args *args) vma = vmas + i; ret = sys_mprotect((void *)vma->start, vma->len, vma->prot | args->add_prot); if (ret) { - pr_err("mprotect(%08lx, %lu) failed with code %d\n", + pr_err("mprotect(%08lx, %ld) failed with code %d\n", vma->start, vma->len, ret); break; } @@ -102,7 +102,7 @@ static int dump_pages(struct parasite_dump_pages_args *args) } if (spliced_bytes != args->nr_pages * PAGE_SIZE) { sys_close(p); - pr_err("Can't splice all pages to pipe (%lu/%d)\n", spliced_bytes, args->nr_pages); + pr_err("Can't splice all pages to pipe (%ld/%d)\n", spliced_bytes, args->nr_pages); return -1; } From 42b5700b72c0bebbef113554c064827a3ab40b18 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 15 Apr 2020 11:34:47 +0300 Subject: [PATCH 2381/4375] kerndat remove duplicate call to kerndat_nsid() Func kerndat_nsid() is called twice. v2: leave kerndat_nsid call near kerndat_link_nsid Signed-off-by: Pavel Tikhomirov --- criu/kerndat.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/criu/kerndat.c b/criu/kerndat.c index 0421997af..0b6d53bc7 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -1092,8 +1092,6 @@ int kerndat_init(void) ret = kerndat_vdso_preserves_hint(); if (!ret) ret = kerndat_socket_netns(); - if (!ret) - ret = kerndat_nsid(); if (!ret) ret = kerndat_x86_has_ptrace_fpu_xsave_bug(); if (!ret) From 7dc89376b85ddea408d43527ff42f4e86ea77a41 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 1 Apr 2020 10:43:25 +0300 Subject: [PATCH 2382/4375] pstree: improve error handling in read_pstree_image First don't free pstree_item as they are allocated with shmalloc on restore. Second always pstree_entry__free_unpacked PstreeEntry. Third remove all breaks replacing them with implict goto err, so that it would be easier to understand that we are on error path. Forth split out code for reading one pstree item in separate function. Sadly there is no much use in xfree-ing pi->threads because in case of an error we still have ->threads unfreed from previous entries anyway. But at least some cleanup can be done here. Signed-off-by: Pavel Tikhomirov --- criu/pstree.c | 197 ++++++++++++++++++++++++++------------------------ 1 file changed, 103 insertions(+), 94 deletions(-) diff --git a/criu/pstree.c b/criu/pstree.c index d0e81bfad..5de367688 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -498,11 +498,109 @@ static int read_pstree_ids(struct pstree_item *pi) return 0; } +/* + * Returns <0 on error, 0 on eof and >0 on successful read + */ +static int read_one_pstree_item(struct cr_img *img, pid_t *pid_max) +{ + struct pstree_item *pi; + PstreeEntry *e; + int ret, i; + + ret = pb_read_one_eof(img, &e, PB_PSTREE); + if (ret <= 0) + return ret; + + ret = -1; + pi = lookup_create_item(e->pid); + if (pi == NULL) + goto err; + BUG_ON(pi->pid->state != TASK_UNDEF); + + /* + * All pids should be added in the tree to be able to find + * free pid-s for helpers. pstree_item for these pid-s will + * be initialized when we meet PstreeEntry with this pid or + * we will create helpers for them. + */ + if (lookup_create_item(e->pgid) == NULL) + goto err; + if (lookup_create_item(e->sid) == NULL) + goto err; + + pi->pid->ns[0].virt = e->pid; + if (e->pid > *pid_max) + *pid_max = e->pid; + pi->pgid = e->pgid; + if (e->pgid > *pid_max) + *pid_max = e->pgid; + pi->sid = e->sid; + if (e->sid > *pid_max) + *pid_max = e->sid; + pi->pid->state = TASK_ALIVE; + + if (e->ppid == 0) { + if (root_item) { + pr_err("Parent missed on non-root task " + "with pid %d, image corruption!\n", e->pid); + goto err; + } + root_item = pi; + pi->parent = NULL; + } else { + struct pid *pid; + struct pstree_item *parent; + + pid = pstree_pid_by_virt(e->ppid); + if (!pid || pid->state == TASK_UNDEF || pid->state == TASK_THREAD) { + pr_err("Can't find a parent for %d\n", vpid(pi)); + goto err; + } + + parent = pid->item; + pi->parent = parent; + list_add(&pi->sibling, &parent->children); + } + + pi->nr_threads = e->n_threads; + pi->threads = xmalloc(e->n_threads * sizeof(struct pid)); + if (!pi->threads) + goto err; + + for (i = 0; i < e->n_threads; i++) { + struct pid *node; + pi->threads[i].real = -1; + pi->threads[i].ns[0].virt = e->threads[i]; + pi->threads[i].state = TASK_THREAD; + pi->threads[i].item = NULL; + if (i == 0) + continue; /* A thread leader is in a tree already */ + node = lookup_create_pid(pi->threads[i].ns[0].virt, &pi->threads[i]); + + BUG_ON(node == NULL); + if (node != &pi->threads[i]) { + pr_err("Unexpected task %d in a tree %d\n", e->threads[i], i); + goto err; + } + } + + task_entries->nr_threads += e->n_threads; + task_entries->nr_tasks++; + + /* note: we don't fail if we have empty ids */ + if (read_pstree_ids(pi) < 0) + goto err; + + ret = 1; +err: + pstree_entry__free_unpacked(e, NULL); + return ret; +} + static int read_pstree_image(pid_t *pid_max) { - int ret = 0, i; struct cr_img *img; - struct pstree_item *pi; + int ret; pr_info("Reading image tree\n"); @@ -510,99 +608,10 @@ static int read_pstree_image(pid_t *pid_max) if (!img) return -1; - while (1) { - PstreeEntry *e; + do { + ret = read_one_pstree_item(img, pid_max); + } while (ret > 0); - ret = pb_read_one_eof(img, &e, PB_PSTREE); - if (ret <= 0) - break; - - ret = -1; - pi = lookup_create_item(e->pid); - if (pi == NULL) - break; - BUG_ON(pi->pid->state != TASK_UNDEF); - - /* - * All pids should be added in the tree to be able to find - * free pid-s for helpers. pstree_item for these pid-s will - * be initialized when we meet PstreeEntry with this pid or - * we will create helpers for them. - */ - if (lookup_create_item(e->pgid) == NULL) - break; - if (lookup_create_item(e->sid) == NULL) - break; - - pi->pid->ns[0].virt = e->pid; - if (e->pid > *pid_max) - *pid_max = e->pid; - pi->pgid = e->pgid; - if (e->pgid > *pid_max) - *pid_max = e->pgid; - pi->sid = e->sid; - if (e->sid > *pid_max) - *pid_max = e->sid; - pi->pid->state = TASK_ALIVE; - - if (e->ppid == 0) { - if (root_item) { - pr_err("Parent missed on non-root task " - "with pid %d, image corruption!\n", e->pid); - goto err; - } - root_item = pi; - pi->parent = NULL; - } else { - struct pid *pid; - struct pstree_item *parent; - - pid = pstree_pid_by_virt(e->ppid); - if (!pid || pid->state == TASK_UNDEF || pid->state == TASK_THREAD) { - pr_err("Can't find a parent for %d\n", vpid(pi)); - pstree_entry__free_unpacked(e, NULL); - xfree(pi); - goto err; - } - - parent = pid->item; - pi->parent = parent; - list_add(&pi->sibling, &parent->children); - } - - pi->nr_threads = e->n_threads; - pi->threads = xmalloc(e->n_threads * sizeof(struct pid)); - if (!pi->threads) - break; - - for (i = 0; i < e->n_threads; i++) { - struct pid *node; - pi->threads[i].real = -1; - pi->threads[i].ns[0].virt = e->threads[i]; - pi->threads[i].state = TASK_THREAD; - pi->threads[i].item = NULL; - if (i == 0) - continue; /* A thread leader is in a tree already */ - node = lookup_create_pid(pi->threads[i].ns[0].virt, &pi->threads[i]); - - BUG_ON(node == NULL); - if (node != &pi->threads[i]) { - pr_err("Unexpected task %d in a tree %d\n", e->threads[i], i); - return -1; - } - } - - task_entries->nr_threads += e->n_threads; - task_entries->nr_tasks++; - - pstree_entry__free_unpacked(e, NULL); - - ret = read_pstree_ids(pi); - if (ret < 0) - goto err; - } - -err: close_image(img); return ret; } From c83a0aae2c71b66abf613c8ef5fe97b7311e1987 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 11 Apr 2020 06:37:38 +0300 Subject: [PATCH 2383/4375] proc: parse clock symbolic names in /proc/pid/timens_offsets Clock IDs in this file has been replaced by clock symbolic names. Now it looks like this: $ cat /proc/774/timens_offsets monotonic 864000 0 boottime 1728000 0 Signed-off-by: Andrei Vagin --- criu/proc_parse.c | 22 ++++++++++++---------- criu/timens.c | 6 ++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/criu/proc_parse.c b/criu/proc_parse.c index c73fa9776..4a22700aa 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1484,25 +1484,27 @@ int parse_timens_offsets(struct timespec *boff, struct timespec *moff) } while (fgets(buf, BUF_SIZE, f)) { int64_t sec, nsec; - int clockid; + char clockid[10]; - if (sscanf(buf, "%d %"PRId64" %"PRId64"\n", &clockid, &sec, &nsec) != 3) { + if (sscanf(buf, "%9s %"PRId64" %"PRId64"\n", clockid, &sec, &nsec) != 3) { pr_err("Unable to parse: %s\n", buf); goto out; } - switch (clockid) { - case CLOCK_MONOTONIC: + clockid[sizeof(clockid) - 1] = 0; + if (strcmp(clockid, "monotonic") == 0 || + strcmp(clockid, __stringify(CLOCK_MONOTONIC)) == 0) { moff->tv_sec = sec; moff->tv_nsec = nsec; - break; - case CLOCK_BOOTTIME: + continue; + } + if (strcmp(clockid, "boottime") == 0 || + strcmp(clockid, __stringify(CLOCK_BOOTTIME)) == 0) { boff->tv_sec = sec; boff->tv_nsec = nsec; - break; - default: - pr_err("Unknown clockid: %d\n", clockid); - goto out; + continue; } + pr_err("Unknown clockid: %s\n", clockid); + goto out; } exit_code = 0; out: diff --git a/criu/timens.c b/criu/timens.c index f3b50fdff..2a7e95284 100644 --- a/criu/timens.c +++ b/criu/timens.c @@ -92,8 +92,7 @@ int prepare_timens(int id) ts.tv_nsec = te->monotonic->tv_nsec - ts.tv_nsec; normalize_timespec(&ts); - pr_debug("timens: %d %ld %ld\n", - CLOCK_MONOTONIC, ts.tv_sec, ts.tv_nsec); + pr_debug("timens: monotonic %ld %ld\n", ts.tv_sec, ts.tv_nsec); if (dprintf(fd, "%d %ld %ld\n", CLOCK_MONOTONIC, ts.tv_sec, ts.tv_nsec) < 0) { pr_perror("Unable to set a monotonic clock offset"); @@ -109,8 +108,7 @@ int prepare_timens(int id) ts.tv_nsec = te->boottime->tv_nsec - ts.tv_nsec; normalize_timespec(&ts); - pr_debug("timens: %d %ld %ld\n", - CLOCK_BOOTTIME, ts.tv_sec, ts.tv_nsec); + pr_debug("timens: boottime %ld %ld\n", ts.tv_sec, ts.tv_nsec); if (dprintf(fd, "%d %ld %ld\n", CLOCK_BOOTTIME, ts.tv_sec, ts.tv_nsec) < 0) { pr_perror("Unable to set a boottime clock offset"); From 5c5e7695a51318b17e3d982df8231ac83971641c Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Mon, 20 Apr 2020 15:45:51 -0700 Subject: [PATCH 2384/4375] get_clean_mount: demote an error to a warning When testing runc checkpointing, I frequently see the following error: > Error (criu/mount.c:1107): mnt: Can't create a temporary directory: Read-only file system This happens because container root is read-only mount. The error here is not actually fatal since it is handled later in ns_open_mountpoint() (at least since [1] is fixed), but it is shown as error in runc integration tests. Since it is not fatal, let's demote it to a warning to avoid confusion. [1] https://github.com/checkpoint-restore/criu/issues/520 Signed-off-by: Kir Kolyshkin --- criu/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/mount.c b/criu/mount.c index 180f2a62d..89b8cff59 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1104,7 +1104,7 @@ static char *get_clean_mnt(struct mount_info *mi, char *mnt_path_tmp, char *mnt_ if (mnt_path == NULL && errno == ENOENT) mnt_path = mkdtemp(mnt_path_root); if (mnt_path == NULL) { - pr_perror("Can't create a temporary directory"); + pr_warn("Can't create a temporary directory: %s\n", strerror(errno)); return NULL; } From 95ead14874244f3c12e5970a74d1f4dd2433d652 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 29 Apr 2020 16:31:49 +0300 Subject: [PATCH 2385/4375] =?UTF-8?q?criu:=20Version=20=CF=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The long-tempting release with lots of new features on board. We have finally the time namespace support, great improvment of the pre-dump memory consumption, new clone3 support and many more. Signed-off-by: Pavel Emelyanov --- Makefile.versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.versions b/Makefile.versions index f3adcb0a6..3ccc48185 100644 --- a/Makefile.versions +++ b/Makefile.versions @@ -1,10 +1,10 @@ # # CRIU version. CRIU_VERSION_MAJOR := 3 -CRIU_VERSION_MINOR := 13 +CRIU_VERSION_MINOR := 14 CRIU_VERSION_SUBLEVEL := CRIU_VERSION_EXTRA := -CRIU_VERSION_NAME := Silicon Willet +CRIU_VERSION_NAME := Platinum Peacock CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA)) export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL From f2edc1e1999e7c495af404fc6c38b82c391854ec Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 6 May 2020 13:13:38 +0000 Subject: [PATCH 2386/4375] Update certificates for failing tls based tests When using zdtm.py with --tls it started to fail as the certificates seem to have expired. Following commands have been used to re-generate the certificate: # Generate CA key and certificate echo -ne "ca\ncert_signing_key" > temp certtool --generate-privkey > cakey.pem certtool --generate-self-signed \ --template temp \ --load-privkey cakey.pem \ --outfile cacert.pem # Generate server key and certificate echo -ne "cn=$HOSTNAME\nencryption_key\nsigning_key" > temp certtool --generate-privkey > key.pem certtool --generate-certificate \ --template temp \ --load-privkey key.pem \ --load-ca-certificate cacert.pem \ --load-ca-privkey cakey.pem \ --outfile cert.pem rm temp cakey.pem Without this tests will fail in Travis. Signed-off-by: Adrian Reber --- test/pki/cacert.pem | 42 +++--- test/pki/cert.pem | 44 +++---- test/pki/key.pem | 310 ++++++++++++++++++++++---------------------- 3 files changed, 198 insertions(+), 198 deletions(-) diff --git a/test/pki/cacert.pem b/test/pki/cacert.pem index 2f8706616..65afd2aa7 100644 --- a/test/pki/cacert.pem +++ b/test/pki/cacert.pem @@ -1,23 +1,23 @@ -----BEGIN CERTIFICATE----- -MIID0TCCAjmgAwIBAgIUWzgmx9p7y7mkrNptGX9+0acjpa4wDQYJKoZIhvcNAQEL -BQAwADAeFw0xOTA1MDYxMjAzMDJaFw0yMDA1MDUxMjAzMDJaMAAwggGiMA0GCSqG -SIb3DQEBAQUAA4IBjwAwggGKAoIBgQD0p0lJUlq917GmJuCBeP2eLNd1/MUg1ojy -s7rrpinPYtLZqqquUhp32lfQtt3uJLjkhTrseZd86zWi3SMZlGs8zGGmKfqg0vaG -BXIgpEIr5C0wU9995kL9A6LS+eFZR6vJQETO5T22tjponoqEPOXeU8VaiC9jNipC -uFJT0wyC0bKIo+TUn573kxsGMt8jMOv0tc/okUlH16UAsYrmN7kWzgkWTJPddB7S -v5a9ibpPkbh+wrIGK5A6V5hTZ8U1wz2bE6/Xp+qjsD2R3jeU6f1tDvc8FZilabQy -Rmbxggucl1G3Ulo6Nvor1lhog72eZlHZujzf/5e/aMiZ7Br6plZ1/WTwtNgoCw6A -rgpLDraasQohiK6opYs2rr7uuiQxPLLVWE/RryXwUEoPXzxaf782XtXxkB0UhGvz -y2JBxCVPn7uUGuyEYywjTjI2UFvsMcXnMiQ4WaAfMbAmrBWM7EQ4b7VpD2c+OZkQ -J/AJeg85/ovTAtHPjhPP+0a9hnirktkCAwEAAaNDMEEwDwYDVR0TAQH/BAUwAwEB -/zAPBgNVHQ8BAf8EBQMDBwQAMB0GA1UdDgQWBBQOg6AA8Qu/m/O/II5spzYsTnsn -pjANBgkqhkiG9w0BAQsFAAOCAYEA1KKtw+ILKOg1AhGwgPsJXAWZoSIt7hdLaJ3P -WGyTWHLKKoJiGlLj3bSsJcMmMO+UwHBH9lmXrOWe/xcOvob2H+7dXbddQ0pX1wzK -KJKzSG35FZ2BfuSn5oEDtRsHnN2Ikc5MYz1a+F4w2tVL/Hcxld+oSAodDlCbGoe+ -0MkI5f1KhdAw00l/5IO7xPOcThjHw+nB5/cZTQ+l4zLWCWaXkor4IAEq/plPcdX1 -uoLSj3JruLz7/ts/EgG+ARAzXQrJ+LM2hdPB1NiaVxFq7MSWM6FybUdmMYgbP5s4 -RMNqI/M+bU9K5LRySDaiPhDXUoVULuqG1a23GQwXLOjF0JbrUQewfAaTO7TaPFh1 -lr25j9Fc9/gcXZjvLl+CEIv6P/haGOwySCTCks0F5bDehbLjZStPmugcnJflXdBn -lzoejlw2rePojQMlffQsaRGmmhj0beU4WQBfGACcZQB8GFNxQB8aynf0CK7Dvvb0 -9c9y4k0gHL7RxeLoQfq+smzKm+Eo +MIID0TCCAjmgAwIBAgIUF0WMpaJUi0+wXbOKQ6P41ZeRwdQwDQYJKoZIhvcNAQEL +BQAwADAeFw0yMDA1MDYxMzEwMzNaFw0yMTA1MDYxMzEwMzNaMAAwggGiMA0GCSqG +SIb3DQEBAQUAA4IBjwAwggGKAoIBgQDMPLu3o8RMlWlblK03GynmvNZDQKW0ZTYg +dE/Dlr/rVKo8KMAm6KbmpUJq8HUtaP/9Epf2eY9+LNNpBFKJuURxD23ObNdbU6o6 +hI4LRQVYsX6FB+6DrIXfD61zxebdpPWlCyoEd43firfwMoeGyarqyrZE+UXkR4fF +LhVm/4kQ8qRZte+GAIVp0SVMlNyhQM5AmTZPAO3iYRhZObkVFUTWnwjdxKOx1VhU +vRdhwI4N5x9EGiq6Lzc0iABxyIZ1mHOYhxDQv5gL4CECUZgzVxJp6DVP/v2w4254 +JeKXOPUm6YHxXxzJyT73mdz0/7VpqOZa5yiZKRBtHoWyovuTzu8jS6TgvjNrmAoO +kyu13jTlBDFUfVKBDoRQMhjt6wpMkUItYvVRq/RYLvXGU7VCzUHoVdBxNNO+MrZ2 +4ebN5l5/CSrOeaa0EylLLlkW7Q0JqmZJpZfK8/AnMyp71AkHTps5LZv/sLbPWwh1 +3XTZA1e+k9lS1Z480HjtNKurL526k8ECAwEAAaNDMEEwDwYDVR0TAQH/BAUwAwEB +/zAPBgNVHQ8BAf8EBQMDBwQAMB0GA1UdDgQWBBR5rZcu6Unhc0ZuuflmHEOa9bBu +1zANBgkqhkiG9w0BAQsFAAOCAYEAehfgQ1y3GTJ3LPQQOgn3AB/Sf+fGSNecZsTO +UxGFxbNGvl7UeFCS8Z1/h57AeIXSvE+BGfMvtq9OSl6t+3w9RfbIdzWzYYILoAVM +t0FkwrjLtVIlUSWD+Aia01ESjw+3ENceGcuo9jVyAI3MMkGftFc7U1UyNB9HY//x +79uUavmWioc3odooC0FOosIzV2KHCUPAnpN7TtNlefe4JisMa6WGXAk9CNU9t0wG +JLHK3E0LrtEreIMBmK6zyxH3OwMi1x/3sFSoon09/fsOLBbtUY+401a+nT+vMTKK +KpVvAC4tsEyFH0vyk68c6Z4VKO5aqoAtaQJZk2A2z1cBAz4aArgx1glkaNjd7sZn +lSEhnpP7uVUyYU9fyQ46zpIZm38gx6+95XL2gCQnEIUEeOCXMonXaavMqRx5zL8z +hihMSoLhE6Wx/tzxKlqz0GN8E0CTlpB1MmvCvOkaHzSq7Yc19Bez8jr6PNfZVsFv +s9a4qqhGKaLz7HKpG0863oCO4dU1 -----END CERTIFICATE----- diff --git a/test/pki/cert.pem b/test/pki/cert.pem index a0946ee41..f5a0452b5 100644 --- a/test/pki/cert.pem +++ b/test/pki/cert.pem @@ -1,24 +1,24 @@ -----BEGIN CERTIFICATE----- -MIIEAzCCAmugAwIBAgIUKV6zLC//OJDnmOYBuIG1Gvmv+V4wDQYJKoZIhvcNAQEL -BQAwADAeFw0xOTA1MDYxMjAzMDJaFw0yMDA1MDUxMjAzMDJaMBQxEjAQBgNVBAMT -CWxvY2FsaG9zdDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBANX1nv4J -U8+TEb2bWej5O2nOowpw2zSYTDAQ1oyAvV3P99Y6GZCuVZ1uT/7DWat0uRpcdmNi -HvownkO4VmDZdVqgiK1eHzY5YBJ7hBVDs3tpWNuN7eJPjnskNmJqKQ6l9rxYl/au -781T+tdtHp1ATtToMgVJxWaUx5lrpEJdmYc8Y6GpAA42D+rI3o4Sll3mI5rPCk16 -QY5dT2lnL2HuCKzM2bjWat6b3lMpfNz3A/blU9E/462Zxr/yKK/0yy3SBZhYzrrQ -1/erjIpm4I0sakHIOexM1AQliFiowFzVvr/paiXApWGOcuBJVIbmPI/bEGuTh0nr -3pmiF0YrkDCRhargElYcz64KQ9IxPFCKcKjkMnFPjTStZ7rcMyqKvGczqFaM5a6c -9gIn2ieUrVZ38yvtI5Lo/uxZ5IjXqB1Fdg4xi2tyf9WMHKy2tydBr9bTjfQRXfNT -/Zm3woDXOYsHzj+Sf6ntLVCkO1fnczw03fPRV03/uVRa5mPGyyj9xdPBqwIDAQAB -o2EwXzAMBgNVHRMBAf8EAjAAMA8GA1UdDwEB/wQFAwMHoAAwHQYDVR0OBBYEFEtF -ELehnIjLzoh/W51TGm2B00QAMB8GA1UdIwQYMBaAFA6DoADxC7+b878gjmynNixO -eyemMA0GCSqGSIb3DQEBCwUAA4IBgQA17NZCaiCgD9P4GPWgdVNkWUrmc8itJuIB -z3c9RdJGduxb9W/D7IW//D3hIblOPorNi3+08kO/IRMGah874MDCprMNppk94WGj -Kgqi/rsxq+rT6bcZXxMrcOIg0j2EvTPIgPh7trd8nHVWxNT/hvFClDtBJ2ssL2Tz -76EA7smDCUsfdzFJ2Xvk95fSTL49nfT2j9N/YoLaBQtCIxWAVZHKiCF2K+yXufHz -B/9UlXwsPJfqxM75dYWXFEqvhNf08YRHT1e1GRrybNGrNKF864KbLsnASdK4N5wu -sK9vZJ7VkLDQz+YpZkbm+UgOYK/BY3M8IX+F+WngV+43fr6Wh89TSgD7acEBvQTm -q1y9FipRvz0my7fwBh6UlYDja6/3yw6/YfN7uMFGsOOSgpNDCrMLqesf8l1HdQUF -VaVJyDjgFswV9KykAeJK2KU8QI7TGHv9soW60sr97DgUtCh4a6OPXLt79Ji3RSNw -MbU54JnpnfmMAj/0suDymdrJWv8EJKc= +MIIEAjCCAmqgAwIBAgIURFKv2lJVvIEfr7yjE7pK0BdK9W8wDQYJKoZIhvcNAQEL +BQAwADAeFw0yMDA1MDYxMzExMDVaFw0yMTA1MDYxMzExMDVaMBMxETAPBgNVBAMT +CGZlZG9yYTAxMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAtS2SivLa +AfsZ1X9xun/6i/1UNSxG5kPvVkfTPWOwSgCYyqn7u2vZsIsvcurqHQBEg1SWF4XA +dcFeCxdDN8em6ISfSOUFL9TSQrZ5eFQYcVTX9IFXDWXbFSC8AgJpYhrPf2O0vxQN +QFD4MpNXrLpEkc3vLrg/JhySC1HAYfO/nuJV3ZnAxJZCIv4upT5j0VjzfPw6WR/O +UUlcmLnh0+qMLv7G2dRLjdAsV1U8k7eykk+z9qXeKAjgFBEEgLTVbHR1zbrUpw42 +DYR7SQpEJ8wrJ9qHdI4H/9MnPu8O75kfgauQV4s/oIgWmVeHMDxpGaLEKgcYVE2F +/HlMfFvCrrZKKXi1/k35rG8sg6cP/bRuRZlgO0xFTrW0QKmWoBLqyqVMvifdkT0E +BWZ4eZWTDn2Rr4HMe7ov54QmKXaXp2VdOGzO1Efv9KvDildb5aEqBrVz+tU+C/Cd +g5p1d2g2m1Uk9wjcYbXOWx9fd9Ur/fxJuHtauxOW4gzFLcTOgvUgVmSXAgMBAAGj +YTBfMAwGA1UdEwEB/wQCMAAwDwYDVR0PAQH/BAUDAwegADAdBgNVHQ4EFgQUh+RA +Kg+4YVs/x9A0hxJlkDxG7IQwHwYDVR0jBBgwFoAUea2XLulJ4XNGbrn5ZhxDmvWw +btcwDQYJKoZIhvcNAQELBQADggGBAMLv1btjFDwxds0XlPH792ECXgYOXPC8cJAx +MJ+qdop/nNW8iUUoOjwy1f9jXBjz1bHKJ+XnyTz4rhLWIHVnhsiLMQ+ljHgTtTjY +3K6Lzo9+KMG/WDRajID8Sk2/B3jnCjgdzb6C4TZQ1mxnhSD7Cj/VitkVLP3D2nYx +55bXqAHAtSkW965LAxILSzt04a8MM9ZxNzyruGVI+jPF0OSgDNcJpcwUw8w8V1lj +c5TC9qqRlokFGphR45vblTw3GaXuZ5TTLOdix0QOhl52H2BtCrvTWJLREC5VJ87C +2FjXIz5zj1WZ3CDZVbpFhTiZy/chHJNaiiDWe6QhD40VvKlo/netp+rxwrpGsFkC +mtyRKrutdKi0vDvI6sKu13gLxetL+Bd6XWZ+XRsA/687QE+epxoh8sTvIt9j0z5r +0yIv/0eTKVZLQ6cAXSoR1g1GwTsWf0eBRgePdl4MCXVAs8+X1hTqnrJomiUdm93C +d2+QakSAhreCtlqMz/AULryv3KgaEg== -----END CERTIFICATE----- diff --git a/test/pki/key.pem b/test/pki/key.pem index eda1aa761..7acde5181 100644 --- a/test/pki/key.pem +++ b/test/pki/key.pem @@ -3,180 +3,180 @@ Public Key Info: Key Security Level: High (3072 bits) modulus: - 00:d5:f5:9e:fe:09:53:cf:93:11:bd:9b:59:e8:f9:3b - 69:ce:a3:0a:70:db:34:98:4c:30:10:d6:8c:80:bd:5d - cf:f7:d6:3a:19:90:ae:55:9d:6e:4f:fe:c3:59:ab:74 - b9:1a:5c:76:63:62:1e:fa:30:9e:43:b8:56:60:d9:75 - 5a:a0:88:ad:5e:1f:36:39:60:12:7b:84:15:43:b3:7b - 69:58:db:8d:ed:e2:4f:8e:7b:24:36:62:6a:29:0e:a5 - f6:bc:58:97:f6:ae:ef:cd:53:fa:d7:6d:1e:9d:40:4e - d4:e8:32:05:49:c5:66:94:c7:99:6b:a4:42:5d:99:87 - 3c:63:a1:a9:00:0e:36:0f:ea:c8:de:8e:12:96:5d:e6 - 23:9a:cf:0a:4d:7a:41:8e:5d:4f:69:67:2f:61:ee:08 - ac:cc:d9:b8:d6:6a:de:9b:de:53:29:7c:dc:f7:03:f6 - e5:53:d1:3f:e3:ad:99:c6:bf:f2:28:af:f4:cb:2d:d2 - 05:98:58:ce:ba:d0:d7:f7:ab:8c:8a:66:e0:8d:2c:6a - 41:c8:39:ec:4c:d4:04:25:88:58:a8:c0:5c:d5:be:bf - e9:6a:25:c0:a5:61:8e:72:e0:49:54:86:e6:3c:8f:db - 10:6b:93:87:49:eb:de:99:a2:17:46:2b:90:30:91:85 - aa:e0:12:56:1c:cf:ae:0a:43:d2:31:3c:50:8a:70:a8 - e4:32:71:4f:8d:34:ad:67:ba:dc:33:2a:8a:bc:67:33 - a8:56:8c:e5:ae:9c:f6:02:27:da:27:94:ad:56:77:f3 - 2b:ed:23:92:e8:fe:ec:59:e4:88:d7:a8:1d:45:76:0e - 31:8b:6b:72:7f:d5:8c:1c:ac:b6:b7:27:41:af:d6:d3 - 8d:f4:11:5d:f3:53:fd:99:b7:c2:80:d7:39:8b:07:ce - 3f:92:7f:a9:ed:2d:50:a4:3b:57:e7:73:3c:34:dd:f3 - d1:57:4d:ff:b9:54:5a:e6:63:c6:cb:28:fd:c5:d3:c1 - ab: + 00:b5:2d:92:8a:f2:da:01:fb:19:d5:7f:71:ba:7f:fa + 8b:fd:54:35:2c:46:e6:43:ef:56:47:d3:3d:63:b0:4a + 00:98:ca:a9:fb:bb:6b:d9:b0:8b:2f:72:ea:ea:1d:00 + 44:83:54:96:17:85:c0:75:c1:5e:0b:17:43:37:c7:a6 + e8:84:9f:48:e5:05:2f:d4:d2:42:b6:79:78:54:18:71 + 54:d7:f4:81:57:0d:65:db:15:20:bc:02:02:69:62:1a + cf:7f:63:b4:bf:14:0d:40:50:f8:32:93:57:ac:ba:44 + 91:cd:ef:2e:b8:3f:26:1c:92:0b:51:c0:61:f3:bf:9e + e2:55:dd:99:c0:c4:96:42:22:fe:2e:a5:3e:63:d1:58 + f3:7c:fc:3a:59:1f:ce:51:49:5c:98:b9:e1:d3:ea:8c + 2e:fe:c6:d9:d4:4b:8d:d0:2c:57:55:3c:93:b7:b2:92 + 4f:b3:f6:a5:de:28:08:e0:14:11:04:80:b4:d5:6c:74 + 75:cd:ba:d4:a7:0e:36:0d:84:7b:49:0a:44:27:cc:2b + 27:da:87:74:8e:07:ff:d3:27:3e:ef:0e:ef:99:1f:81 + ab:90:57:8b:3f:a0:88:16:99:57:87:30:3c:69:19:a2 + c4:2a:07:18:54:4d:85:fc:79:4c:7c:5b:c2:ae:b6:4a + 29:78:b5:fe:4d:f9:ac:6f:2c:83:a7:0f:fd:b4:6e:45 + 99:60:3b:4c:45:4e:b5:b4:40:a9:96:a0:12:ea:ca:a5 + 4c:be:27:dd:91:3d:04:05:66:78:79:95:93:0e:7d:91 + af:81:cc:7b:ba:2f:e7:84:26:29:76:97:a7:65:5d:38 + 6c:ce:d4:47:ef:f4:ab:c3:8a:57:5b:e5:a1:2a:06:b5 + 73:fa:d5:3e:0b:f0:9d:83:9a:75:77:68:36:9b:55:24 + f7:08:dc:61:b5:ce:5b:1f:5f:77:d5:2b:fd:fc:49:b8 + 7b:5a:bb:13:96:e2:0c:c5:2d:c4:ce:82:f5:20:56:64 + 97: public exponent: 01:00:01: private exponent: - 1e:38:b0:79:7f:85:c8:17:24:f5:5c:41:29:e8:32:5d - 32:a3:d2:f0:b7:f5:c8:e1:52:14:be:c9:5f:d1:df:b3 - 65:75:6c:05:7a:6b:35:8a:a4:2f:46:73:ff:71:79:6e - 3f:eb:f9:88:f6:2e:1b:f6:cc:14:12:b0:98:c3:7e:91 - 0b:85:e2:bf:1d:b7:82:09:30:f3:23:68:01:85:13:94 - 80:c9:9a:55:94:96:da:30:48:a0:29:ec:86:da:1b:d5 - 2b:2b:74:63:92:b8:2a:8f:87:29:f0:ae:d7:55:63:0d - 2d:b3:0b:0e:2d:84:dc:d5:08:b5:ac:a0:f7:29:9d:71 - 89:3d:27:6a:eb:96:f5:4e:9b:8a:dc:14:82:0a:c7:5c - 16:1c:d2:7e:b9:1b:13:69:d8:b2:b1:b1:7e:aa:a9:ad - 06:ce:66:0e:5b:50:10:42:2a:0a:fd:29:14:f7:09:63 - c1:20:18:5f:27:81:46:12:8c:b8:f4:89:a6:3d:55:a1 - d4:64:fc:f2:db:d7:9c:f5:be:f7:9d:88:5c:6d:36:a4 - 4b:ea:c5:e3:ea:32:81:6b:f3:47:b5:35:d5:c4:1a:b2 - ae:12:9d:19:a3:ec:a4:af:41:7e:5e:34:9d:f5:bc:b9 - 1f:a3:c2:32:b4:fc:95:a7:7a:54:04:e2:d6:4e:10:2f - 66:68:8b:3b:20:ea:05:db:2e:72:01:11:e7:7c:f8:72 - 0f:60:be:f1:27:19:ad:3a:6f:e9:70:56:3a:86:6e:46 - 0d:e3:55:31:66:77:09:84:48:b9:25:4b:c3:26:70:12 - ca:a4:5f:c6:3d:6a:e5:db:4d:63:04:b8:09:07:c9:30 - 85:08:9d:77:40:26:60:da:10:c2:53:d2:00:0d:9e:d9 - d5:71:06:30:eb:fb:f7:3f:82:1f:b3:9a:f3:4d:24:86 - 2e:94:fd:06:9e:dc:26:68:fa:64:c3:f9:fa:08:c4:b2 - ec:7a:f5:55:c5:10:b5:e2:2d:de:ba:04:30:10:5b:99 - + 66:7a:51:72:30:6c:e9:43:eb:57:dc:4f:2a:ab:2a:bf + 35:da:04:7d:77:d8:d4:c2:32:6e:4b:e8:64:53:99:77 + fe:f4:5a:f3:5d:0e:62:c2:3d:e7:e7:bb:42:12:87:4d + 39:6f:85:b9:e6:58:77:02:99:bb:f2:3b:7d:f8:7a:ca + f8:00:d4:8d:5d:c2:b1:41:00:a5:0f:cd:e4:db:32:77 + 47:f3:2f:99:5a:a5:ab:26:a7:2e:50:80:a6:b4:eb:ef + 43:e1:d4:a1:63:a9:1f:20:ed:52:46:0f:08:4f:0f:6b + dd:2c:95:a3:77:6c:8a:2a:7d:26:8f:87:98:04:61:cd + 29:be:3f:32:4e:bf:a2:c7:02:38:c6:14:a5:07:0b:a6 + 25:a2:d1:2a:0a:18:7b:d7:df:fd:2e:de:b2:2b:ef:80 + c1:71:1e:52:bb:2d:8a:7b:1a:26:c7:2d:d2:70:b9:db + 45:32:94:9d:34:cd:d8:58:e1:4b:47:b5:81:26:68:34 + 2a:32:02:0b:e6:95:3a:d2:d4:d6:e4:c7:bf:8e:04:4e + fc:75:e9:6d:f4:a4:a8:6b:50:76:7c:10:07:81:96:56 + 54:16:d7:39:8a:5f:51:79:1f:96:49:cb:d7:8b:0d:51 + 5d:4a:e8:22:fb:d1:92:a4:a2:02:65:24:0a:62:33:84 + a9:df:a9:4f:40:1a:95:1d:98:ea:0c:23:05:c2:db:1e + 4d:c5:f2:e9:63:6b:de:70:67:3a:a2:f4:72:c1:97:ae + d0:6f:78:82:2b:a1:6f:2c:d7:90:a3:4f:d6:f9:d6:80 + 11:d4:93:8e:e0:06:19:f6:d9:33:72:5d:d8:16:a2:ef + e1:a9:00:de:bc:7e:98:aa:97:45:b8:81:20:01:5d:0b + 10:3d:69:a9:ba:7d:2c:1f:e0:17:0e:bc:ee:97:95:61 + a7:6b:10:94:27:ad:ca:c1:93:3b:fa:dc:8d:3d:58:cc + fb:04:3f:7f:40:d6:6c:e8:83:a1:be:50:cd:46:73:11 + prime1: - 00:fb:d1:47:9d:9e:73:f8:1e:09:21:fd:89:16:05:56 - af:a5:cf:52:d5:cd:f7:26:18:d1:84:3a:36:65:0b:a2 - cd:f9:b8:99:c0:c7:ef:00:c9:2f:c9:92:1a:1d:3d:86 - 58:3b:b1:be:d4:8c:c6:1b:df:ba:ee:87:aa:d1:22:47 - 18:bd:de:01:0f:0d:cb:ac:d0:48:a4:f4:93:e2:a6:cb - b5:b7:f5:f5:72:dd:ec:ac:13:e8:3d:62:23:54:ac:52 - ff:ee:9a:e1:7f:b0:ae:3b:41:38:d8:39:2b:40:ef:25 - 81:50:b0:98:db:f8:40:16:6e:1a:41:79:22:90:58:99 - 80:c2:0d:ba:b5:d3:54:ec:28:33:e4:b0:58:ea:de:61 - a1:b7:30:0b:9d:dc:73:62:c2:07:d3:75:91:48:49:dd - be:cf:b2:90:95:8f:29:6c:6f:f6:68:cb:cf:d5:24:a3 - d7:37:81:1b:34:3b:af:9a:48:52:af:53:7c:f7:32:a2 - 3f: + 00:da:9b:62:22:f8:48:3e:9a:4f:ef:e5:b0:f1:e3:5e + ec:21:3d:3b:8f:ec:f1:d8:f6:fd:a7:2f:69:2a:cd:79 + a1:4b:6b:39:36:e9:c3:a9:5b:f9:59:50:71:6b:72:b0 + 8d:13:ca:93:b1:4d:4b:55:3a:69:b2:84:8d:4e:18:77 + 68:ae:f6:d8:ec:43:ef:c8:21:51:b9:cb:86:b7:62:ab + 5e:90:77:ac:e6:85:a9:e9:f7:19:f7:26:24:4c:18:81 + 53:85:42:cd:35:5c:1d:ae:70:0a:59:b0:44:a2:50:bc + 68:3a:bd:c2:53:7f:2e:ab:04:2d:85:ee:7d:8a:0c:db + cc:85:5a:b5:f8:6f:f8:92:53:0c:93:00:f7:ff:84:61 + d0:67:f4:10:b4:bf:9a:ba:35:df:05:79:d7:78:42:fb + 48:c4:db:35:27:4f:18:cf:8d:da:26:13:36:84:42:5d + 50:c4:9d:38:15:b5:6a:ca:3a:ab:f1:f9:b0:26:1a:54 + 99: prime2: - 00:d9:83:5e:be:0a:ea:0b:d9:66:63:56:3b:9e:44:aa - 46:6d:8d:6c:10:81:4b:de:19:5d:2c:16:7e:30:7c:ad - 23:9a:89:53:cc:18:e8:e8:51:2b:79:35:d0:67:7d:9e - 8f:be:ea:63:5e:14:c0:6b:ba:02:6c:4a:da:07:70:9d - 14:fa:be:1e:40:47:50:6f:f2:5a:87:9e:b6:b1:b8:55 - 2c:b6:a2:e3:b0:24:ba:ea:9b:55:87:8b:4b:cf:40:4a - 25:b4:89:cf:9e:76:ca:79:4a:f4:74:b7:ee:cf:6c:8f - cb:e3:3d:9e:86:3b:44:b7:70:ec:05:0c:68:ce:d6:c3 - a2:ec:e6:11:d6:2f:f7:80:26:a9:5c:aa:b9:a6:33:84 - a9:00:43:cf:72:07:8a:91:59:a2:b1:de:79:07:6b:81 - 67:a5:c2:4b:fd:29:8a:1a:96:66:57:66:d4:37:9a:98 - 69:d1:19:24:53:b1:a4:54:68:1e:8c:2b:b4:93:19:ed - 95: + 00:d4:2b:34:e6:a1:68:c9:c8:7a:22:5c:21:34:0f:67 + 4b:6a:78:d5:0e:63:be:4b:83:a3:ac:28:b6:37:80:c0 + 79:30:ec:0c:87:6d:c1:f2:d1:f8:bd:8d:3c:bb:20:81 + d9:dd:6b:25:0d:0c:e4:15:39:11:06:31:06:84:2c:8d + 12:73:04:b3:cf:fd:57:03:ca:65:3b:f7:e3:e0:6f:37 + 4c:b2:ef:c4:a3:cb:8b:54:f7:35:73:54:e4:f9:62:bd + 1e:7a:c1:76:b1:f0:cc:d9:d0:fc:c7:83:59:07:3b:55 + 1f:a9:88:7e:e9:27:bb:e8:5a:a0:57:de:1d:f4:56:8c + a9:34:9b:0a:43:d5:a1:2a:97:80:27:07:ee:57:20:29 + f7:08:02:78:c7:fc:9b:c9:28:64:a5:63:a4:a6:a2:65 + 48:fd:6d:42:b0:60:59:13:f7:f1:cd:78:09:94:66:42 + 36:6a:ee:7c:40:c5:f1:2f:f9:7e:ca:f7:b5:02:95:10 + af: coefficient: - 00:90:9a:7f:6f:14:a8:bc:79:3f:25:e5:62:f9:5d:29 - 78:a4:78:8e:7a:e4:8a:62:8a:7f:9c:ae:75:95:fe:ee - 1a:99:53:40:01:76:29:7d:48:85:28:a2:2a:9f:0f:10 - 8c:19:6a:36:6b:e1:ac:a2:07:b9:72:5c:b9:a6:20:bb - 8f:cb:f5:ea:dd:3f:0e:ab:9d:c1:57:7e:7b:96:f9:da - b0:52:3c:3f:62:94:e7:5c:04:9e:ac:60:cd:4d:ec:7e - 68:d3:fb:2a:b4:02:f0:0e:be:37:bc:2a:f8:6e:8d:31 - b5:38:67:00:9e:67:9f:71:d0:88:36:32:69:4b:20:73 - eb:a1:d9:bc:72:c2:7e:39:1a:36:cc:c1:45:a2:14:37 - e6:ca:db:4d:0b:5b:68:a4:ff:b7:7b:b1:db:2f:70:27 - a1:6c:31:3f:c0:c3:23:04:b0:7a:e2:0d:21:ba:5a:80 - 52:c1:a1:2b:57:72:20:b6:ed:b1:e8:3b:95:88:81:90 - 5d: + 00:c2:99:5b:b5:1c:59:73:c7:70:78:75:aa:67:4d:92 + d1:27:b6:47:be:e2:71:39:31:f7:5d:be:79:bd:22:b2 + 34:80:b0:a5:39:ab:b2:53:2a:28:f9:4a:34:20:b6:ea + 25:d5:df:34:ad:d0:b3:26:ed:ba:f3:0c:07:95:34:50 + ae:48:40:a7:5b:f7:8c:e4:c6:d6:a4:1f:18:07:2a:ea + 01:38:90:d5:ca:89:19:3d:8e:c2:40:05:e5:09:a8:30 + 78:6c:e9:e6:1d:6c:5b:22:a9:24:d0:07:41:95:0e:82 + f6:19:e4:6c:c1:96:ae:c3:5d:84:a9:02:e5:7c:d6:b9 + f7:94:0f:b9:5a:41:87:db:03:17:9b:39:b2:e9:bb:f5 + 3f:0d:91:6d:d2:32:fe:ef:60:19:3c:15:48:c1:a8:e7 + 4c:b8:bd:dc:31:43:49:df:05:be:c5:3b:6a:5d:68:91 + 6d:e6:47:0b:a4:27:74:44:42:12:31:02:ad:aa:7e:e8 + 0c: exp1: - 00:ef:ce:66:20:01:44:b9:35:89:46:f8:56:33:45:54 - 3f:23:6d:23:9a:7e:71:6d:b3:56:db:50:40:7a:cb:b0 - f7:ec:67:52:ec:96:b9:d1:8a:c6:5a:74:2b:30:4b:66 - 03:e2:9d:2b:78:e8:b2:c4:da:b3:fe:f1:ed:c7:09:98 - a1:44:37:05:d5:1b:33:2a:58:93:c5:9b:30:b6:38:57 - 68:af:4e:a8:b7:02:06:9f:fc:b9:3e:b3:95:a7:ce:0f - a0:b0:ce:88:0e:7c:e7:ff:7f:e6:2d:6b:8b:f8:63:85 - d8:f7:49:a5:d8:5d:3a:52:e1:f9:58:fe:8d:de:de:b1 - 18:40:34:a8:e8:fc:df:33:a2:39:81:00:3b:3d:38:17 - cb:d4:53:09:cd:04:a2:51:9b:2b:ae:c1:98:60:3a:0f - d4:e5:a0:4c:36:51:46:86:80:bd:2d:21:62:c3:bd:07 - d6:2d:82:62:b0:c4:62:3f:4f:be:86:3e:c0:93:fc:81 - 2b: + 00:a6:15:8d:5e:a2:21:49:26:b5:fa:be:18:4b:fe:01 + bd:06:97:dd:eb:c0:0a:12:5b:bc:64:cb:79:6c:22:85 + f9:0c:32:9f:5a:60:09:de:5e:d9:37:89:0d:52:a3:e5 + 0c:99:ef:bb:7b:e6:0c:88:e9:03:2a:b4:d8:22:70:26 + 30:6b:55:71:83:37:2e:32:6f:56:07:01:61:0d:6c:b2 + 63:fb:00:61:65:16:41:fc:56:56:ec:d5:96:98:15:ba + 13:b9:58:02:4e:3a:f8:f5:f1:7b:7b:9e:96:d6:76:de + 5d:95:db:5b:8b:52:42:23:7d:de:14:36:18:3c:cc:fe + 25:09:5f:dc:86:ae:93:3c:a0:4a:1a:59:8f:11:1b:03 + b1:71:79:15:44:2d:9a:21:45:12:76:b7:96:03:71:68 + 36:66:11:60:f5:c7:7b:43:1d:33:92:df:df:f8:65:ef + 3d:90:d3:1d:ac:28:93:c4:a7:04:c1:a7:80:b3:c2:27 + 69: exp2: - 11:e4:73:93:b0:74:26:3b:60:e7:c4:fd:2c:7c:bb:81 - 05:9b:ff:8a:b0:08:1c:a1:fb:7f:17:ee:93:70:7e:11 - 92:b1:bf:39:e7:c6:a8:ed:9c:64:e1:1f:5e:93:ff:ca - 15:4b:54:97:35:9f:ca:7c:c7:9c:3e:e0:06:82:a5:f9 - 46:d3:02:cc:08:d1:be:13:b2:8c:bb:6a:8d:dd:fa:eb - ad:ae:62:8a:67:cb:14:67:68:b6:b8:a7:a8:c9:c2:0f - ad:f5:34:25:f5:e1:9b:ee:a5:83:40:6a:1d:97:f1:90 - 35:06:29:97:23:22:f8:f0:0a:0a:34:46:1e:d5:9d:cc - 36:2e:8a:c3:12:b9:0a:4a:a3:dd:e2:91:58:f1:9d:f5 - 04:f7:8f:05:f3:46:db:c4:02:d5:1c:d6:d9:dc:67:0d - ae:9d:f8:00:40:3d:83:08:62:2c:c8:61:a6:9d:49:f2 - 52:67:fe:0c:00:6d:e3:1f:99:7b:b0:50:af:55:0f:ad - + 3a:11:ad:43:e6:2f:78:f2:be:c2:c2:b6:6f:ba:3b:8a + 3f:94:dc:b3:38:87:6f:c1:92:bd:5e:d3:28:73:bb:ba + 2f:b2:9b:67:41:9a:10:ac:79:48:df:ec:1c:47:34:62 + fd:a0:02:9f:04:c5:34:2d:cf:44:03:8d:06:05:ef:82 + 7a:2a:72:50:5d:c5:40:0b:58:13:c6:af:fe:d0:51:b1 + 53:54:1e:5c:ba:2b:e3:50:59:b7:bc:27:83:3e:0c:06 + d8:90:34:bd:54:eb:ac:3d:ef:c1:67:68:a9:7b:0a:bc + 44:b9:50:0a:de:4e:26:b5:0f:27:9d:6a:53:62:90:d3 + 0a:cb:d8:4e:62:9c:de:bc:62:5d:cc:64:e6:41:ae:5a + a7:3d:8d:f3:26:67:38:f2:2e:41:b9:f8:e9:86:8e:f4 + 20:30:94:4d:13:c1:ad:9e:71:f6:cb:80:cb:b6:05:2f + 41:ab:0e:24:e8:48:2f:da:38:62:b2:d3:3e:e6:af:8f + Public Key PIN: - pin-sha256:EiqPFBPoLKkCzVlK8KoKYGQT/LSo7/0iLg/I7nKt1/0= + pin-sha256:6j7MphUbNRjXh9x/BogWeu4m7+ON7aYmCyFxQsSMsec= Public Key ID: - sha256:122a8f1413e82ca902cd594af0aa0a606413fcb4a8effd222e0fc8ee72add7fd - sha1:4b4510b7a19c88cbce887f5b9d531a6d81d34400 + sha256:ea3ecca6151b3518d787dc7f0688167aee26efe38deda6260b217142c48cb1e7 + sha1:87e4402a0fb8615b3fc7d034871265903c46ec84 -----BEGIN RSA PRIVATE KEY----- -MIIG5AIBAAKCAYEA1fWe/glTz5MRvZtZ6Pk7ac6jCnDbNJhMMBDWjIC9Xc/31joZ -kK5VnW5P/sNZq3S5Glx2Y2Ie+jCeQ7hWYNl1WqCIrV4fNjlgEnuEFUOze2lY243t -4k+OeyQ2YmopDqX2vFiX9q7vzVP6120enUBO1OgyBUnFZpTHmWukQl2ZhzxjoakA -DjYP6sjejhKWXeYjms8KTXpBjl1PaWcvYe4IrMzZuNZq3pveUyl83PcD9uVT0T/j -rZnGv/Ior/TLLdIFmFjOutDX96uMimbgjSxqQcg57EzUBCWIWKjAXNW+v+lqJcCl -YY5y4ElUhuY8j9sQa5OHSevemaIXRiuQMJGFquASVhzPrgpD0jE8UIpwqOQycU+N -NK1nutwzKoq8ZzOoVozlrpz2AifaJ5StVnfzK+0jkuj+7FnkiNeoHUV2DjGLa3J/ -1YwcrLa3J0Gv1tON9BFd81P9mbfCgNc5iwfOP5J/qe0tUKQ7V+dzPDTd89FXTf+5 -VFrmY8bLKP3F08GrAgMBAAECggGAHjiweX+FyBck9VxBKegyXTKj0vC39cjhUhS+ -yV/R37NldWwFems1iqQvRnP/cXluP+v5iPYuG/bMFBKwmMN+kQuF4r8dt4IJMPMj -aAGFE5SAyZpVlJbaMEigKeyG2hvVKyt0Y5K4Ko+HKfCu11VjDS2zCw4thNzVCLWs -oPcpnXGJPSdq65b1TpuK3BSCCsdcFhzSfrkbE2nYsrGxfqqprQbOZg5bUBBCKgr9 -KRT3CWPBIBhfJ4FGEoy49ImmPVWh1GT88tvXnPW+952IXG02pEvqxePqMoFr80e1 -NdXEGrKuEp0Zo+ykr0F+XjSd9by5H6PCMrT8lad6VATi1k4QL2Zoizsg6gXbLnIB -Eed8+HIPYL7xJxmtOm/pcFY6hm5GDeNVMWZ3CYRIuSVLwyZwEsqkX8Y9auXbTWME -uAkHyTCFCJ13QCZg2hDCU9IADZ7Z1XEGMOv79z+CH7Oa800khi6U/Qae3CZo+mTD -+foIxLLsevVVxRC14i3eugQwEFuZAoHBAPvRR52ec/geCSH9iRYFVq+lz1LVzfcm -GNGEOjZlC6LN+biZwMfvAMkvyZIaHT2GWDuxvtSMxhvfuu6HqtEiRxi93gEPDcus -0Eik9JPipsu1t/X1ct3srBPoPWIjVKxS/+6a4X+wrjtBONg5K0DvJYFQsJjb+EAW -bhpBeSKQWJmAwg26tdNU7Cgz5LBY6t5hobcwC53cc2LCB9N1kUhJ3b7PspCVjyls -b/Zoy8/VJKPXN4EbNDuvmkhSr1N89zKiPwKBwQDZg16+CuoL2WZjVjueRKpGbY1s -EIFL3hldLBZ+MHytI5qJU8wY6OhRK3k10Gd9no++6mNeFMBrugJsStoHcJ0U+r4e -QEdQb/Jah562sbhVLLai47AkuuqbVYeLS89ASiW0ic+edsp5SvR0t+7PbI/L4z2e -hjtEt3DsBQxoztbDouzmEdYv94AmqVyquaYzhKkAQ89yB4qRWaKx3nkHa4FnpcJL -/SmKGpZmV2bUN5qYadEZJFOxpFRoHowrtJMZ7ZUCgcEA785mIAFEuTWJRvhWM0VU -PyNtI5p+cW2zVttQQHrLsPfsZ1LslrnRisZadCswS2YD4p0reOiyxNqz/vHtxwmY -oUQ3BdUbMypYk8WbMLY4V2ivTqi3Agaf/Lk+s5Wnzg+gsM6IDnzn/3/mLWuL+GOF -2PdJpdhdOlLh+Vj+jd7esRhANKjo/N8zojmBADs9OBfL1FMJzQSiUZsrrsGYYDoP -1OWgTDZRRoaAvS0hYsO9B9YtgmKwxGI/T76GPsCT/IErAoHAEeRzk7B0Jjtg58T9 -LHy7gQWb/4qwCByh+38X7pNwfhGSsb8558ao7Zxk4R9ek//KFUtUlzWfynzHnD7g -BoKl+UbTAswI0b4Tsoy7ao3d+uutrmKKZ8sUZ2i2uKeoycIPrfU0JfXhm+6lg0Bq -HZfxkDUGKZcjIvjwCgo0Rh7Vncw2LorDErkKSqPd4pFY8Z31BPePBfNG28QC1RzW -2dxnDa6d+ABAPYMIYizIYaadSfJSZ/4MAG3jH5l7sFCvVQ+tAoHBAJCaf28UqLx5 -PyXlYvldKXikeI565Ipiin+crnWV/u4amVNAAXYpfUiFKKIqnw8QjBlqNmvhrKIH -uXJcuaYgu4/L9erdPw6rncFXfnuW+dqwUjw/YpTnXASerGDNTex+aNP7KrQC8A6+ -N7wq+G6NMbU4ZwCeZ59x0Ig2MmlLIHProdm8csJ+ORo2zMFFohQ35srbTQtbaKT/ -t3ux2y9wJ6FsMT/AwyMEsHriDSG6WoBSwaErV3Igtu2x6DuViIGQXQ== +MIIG5AIBAAKCAYEAtS2SivLaAfsZ1X9xun/6i/1UNSxG5kPvVkfTPWOwSgCYyqn7 +u2vZsIsvcurqHQBEg1SWF4XAdcFeCxdDN8em6ISfSOUFL9TSQrZ5eFQYcVTX9IFX +DWXbFSC8AgJpYhrPf2O0vxQNQFD4MpNXrLpEkc3vLrg/JhySC1HAYfO/nuJV3ZnA +xJZCIv4upT5j0VjzfPw6WR/OUUlcmLnh0+qMLv7G2dRLjdAsV1U8k7eykk+z9qXe +KAjgFBEEgLTVbHR1zbrUpw42DYR7SQpEJ8wrJ9qHdI4H/9MnPu8O75kfgauQV4s/ +oIgWmVeHMDxpGaLEKgcYVE2F/HlMfFvCrrZKKXi1/k35rG8sg6cP/bRuRZlgO0xF +TrW0QKmWoBLqyqVMvifdkT0EBWZ4eZWTDn2Rr4HMe7ov54QmKXaXp2VdOGzO1Efv +9KvDildb5aEqBrVz+tU+C/Cdg5p1d2g2m1Uk9wjcYbXOWx9fd9Ur/fxJuHtauxOW +4gzFLcTOgvUgVmSXAgMBAAECggGAZnpRcjBs6UPrV9xPKqsqvzXaBH132NTCMm5L +6GRTmXf+9FrzXQ5iwj3n57tCEodNOW+FueZYdwKZu/I7ffh6yvgA1I1dwrFBAKUP +zeTbMndH8y+ZWqWrJqcuUICmtOvvQ+HUoWOpHyDtUkYPCE8Pa90slaN3bIoqfSaP +h5gEYc0pvj8yTr+ixwI4xhSlBwumJaLRKgoYe9ff/S7esivvgMFxHlK7LYp7GibH +LdJwudtFMpSdNM3YWOFLR7WBJmg0KjICC+aVOtLU1uTHv44ETvx16W30pKhrUHZ8 +EAeBllZUFtc5il9ReR+WScvXiw1RXUroIvvRkqSiAmUkCmIzhKnfqU9AGpUdmOoM +IwXC2x5NxfLpY2vecGc6ovRywZeu0G94giuhbyzXkKNP1vnWgBHUk47gBhn22TNy +XdgWou/hqQDevH6YqpdFuIEgAV0LED1pqbp9LB/gFw687peVYadrEJQnrcrBkzv6 +3I09WMz7BD9/QNZs6IOhvlDNRnMRAoHBANqbYiL4SD6aT+/lsPHjXuwhPTuP7PHY +9v2nL2kqzXmhS2s5NunDqVv5WVBxa3KwjRPKk7FNS1U6abKEjU4Yd2iu9tjsQ+/I +IVG5y4a3YqtekHes5oWp6fcZ9yYkTBiBU4VCzTVcHa5wClmwRKJQvGg6vcJTfy6r +BC2F7n2KDNvMhVq1+G/4klMMkwD3/4Rh0Gf0ELS/mro13wV513hC+0jE2zUnTxjP +jdomEzaEQl1QxJ04FbVqyjqr8fmwJhpUmQKBwQDUKzTmoWjJyHoiXCE0D2dLanjV +DmO+S4OjrCi2N4DAeTDsDIdtwfLR+L2NPLsggdndayUNDOQVOREGMQaELI0ScwSz +z/1XA8plO/fj4G83TLLvxKPLi1T3NXNU5PlivR56wXax8MzZ0PzHg1kHO1UfqYh+ +6Se76FqgV94d9FaMqTSbCkPVoSqXgCcH7lcgKfcIAnjH/JvJKGSlY6SmomVI/W1C +sGBZE/fxzXgJlGZCNmrufEDF8S/5fsr3tQKVEK8CgcEAphWNXqIhSSa1+r4YS/4B +vQaX3evAChJbvGTLeWwihfkMMp9aYAneXtk3iQ1So+UMme+7e+YMiOkDKrTYInAm +MGtVcYM3LjJvVgcBYQ1ssmP7AGFlFkH8Vlbs1ZaYFboTuVgCTjr49fF7e56W1nbe +XZXbW4tSQiN93hQ2GDzM/iUJX9yGrpM8oEoaWY8RGwOxcXkVRC2aIUUSdreWA3Fo +NmYRYPXHe0MdM5Lf3/hl7z2Q0x2sKJPEpwTBp4CzwidpAoHAOhGtQ+YvePK+wsK2 +b7o7ij+U3LM4h2/Bkr1e0yhzu7ovsptnQZoQrHlI3+wcRzRi/aACnwTFNC3PRAON +BgXvgnoqclBdxUALWBPGr/7QUbFTVB5cuivjUFm3vCeDPgwG2JA0vVTrrD3vwWdo +qXsKvES5UAreTia1DyedalNikNMKy9hOYpzevGJdzGTmQa5apz2N8yZnOPIuQbn4 +6YaO9CAwlE0Twa2ecfbLgMu2BS9Bqw4k6Egv2jhistM+5q+PAoHBAMKZW7UcWXPH +cHh1qmdNktEntke+4nE5Mfddvnm9IrI0gLClOauyUyoo+Uo0ILbqJdXfNK3Qsybt +uvMMB5U0UK5IQKdb94zkxtakHxgHKuoBOJDVyokZPY7CQAXlCagweGzp5h1sWyKp +JNAHQZUOgvYZ5GzBlq7DXYSpAuV81rn3lA+5WkGH2wMXmzmy6bv1Pw2RbdIy/u9g +GTwVSMGo50y4vdwxQ0nfBb7FO2pdaJFt5kcLpCd0REISMQKtqn7oDA== -----END RSA PRIVATE KEY----- From d23d1fc0f9483e5b99abd31d92369fa8cbb05150 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Fri, 5 Jun 2020 07:56:39 +0200 Subject: [PATCH 2387/4375] travis: fix alpine builds With the latest version of the alpine container image it seems that alpine changed a few package names. This adapts the alpine container to solve the travis failures. Signed-off-by: Adrian Reber --- scripts/build/Dockerfile.alpine | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/build/Dockerfile.alpine b/scripts/build/Dockerfile.alpine index 5785102da..dbf3c2bf1 100644 --- a/scripts/build/Dockerfile.alpine +++ b/scripts/build/Dockerfile.alpine @@ -15,9 +15,12 @@ RUN apk update && apk add \ libnet-dev \ libnl3-dev \ nftables \ + nftables-dev \ pkgconfig \ protobuf-c-dev \ protobuf-dev \ + py3-pip \ + py3-protobuf \ python3 \ sudo @@ -43,7 +46,7 @@ RUN apk add \ # The rpc test cases are running as user #1000, let's add the user RUN adduser -u 1000 -D test -RUN pip3 install protobuf junit_xml +RUN pip3 install junit_xml # For zdtm we need an unversioned python binary RUN ln -s /usr/bin/python3 /usr/bin/python From be2ded15ee1cff6c0bd5733dda57bb17ea85bcd9 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Fri, 5 Jun 2020 07:55:18 +0200 Subject: [PATCH 2388/4375] test: fix flake8 errors The newest version of flake reports errors that variable names like 'l' should not be used, because they are hard to read. This changes 'l' to 'line' to make flake8 happy. Signed-off-by: Adrian Reber --- test/zdtm.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/zdtm.py b/test/zdtm.py index 5e42c769e..b111fa383 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -2047,11 +2047,11 @@ def grep_errors(fname): print_next = False before = [] with open(fname, errors='replace') as fd: - for l in fd: - before.append(l) + for line in fd: + before.append(line) if len(before) > 5: before.pop(0) - if "Error" in l or "Warn" in l: + if "Error" in line or "Warn" in line: if first: print_fname(fname, 'log') print_sep("grep Error", "-", 60) @@ -2061,7 +2061,7 @@ def grep_errors(fname): before = [] else: if print_next: - print_next = print_error(l) + print_next = print_error(line) before = [] if not first: print_sep("ERROR OVER", "-", 60) From 01cab14dfad656eb1d5f7e6a611a49a87c83b34e Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 22 Feb 2019 18:04:32 +0000 Subject: [PATCH 2389/4375] util: Fix addr casting for IPv4/IPv6 in autobind When saddr.ss_family is AF_INET6 we should cast &saddr to (struct sockaddr_in6 *). Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/util.c b/criu/util.c index 6f6a6dde7..06c594ca9 100644 --- a/criu/util.c +++ b/criu/util.c @@ -1131,9 +1131,9 @@ int setup_tcp_server(char *type, char *addr, unsigned short *port) } if (saddr.ss_family == AF_INET6) { - (*port) = ntohs(((struct sockaddr_in *)&saddr)->sin_port); - } else if (saddr.ss_family == AF_INET) { (*port) = ntohs(((struct sockaddr_in6 *)&saddr)->sin6_port); + } else if (saddr.ss_family == AF_INET) { + (*port) = ntohs(((struct sockaddr_in *)&saddr)->sin_port); } pr_info("Using %u port\n", (*port)); From 0708cbd8839267c30e8dcd8bec63f5bc2d2d36d0 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 13 Sep 2018 18:28:10 +0100 Subject: [PATCH 2390/4375] remote: Use tmp file buffer when restore ip dump When CRIU calls the ip tool on restore, it passes the fd of remote socket by replacing the STDIN before execvp. The stdin is used by the ip tool to receive input. However, the ip tool calls ftell(stdin) which fails with "Illegal seek" since UNIX sockets do not support file positioning operations. To resolve this issue, read the received content from the UNIX socket and store it into temporary file, then replace STDIN with the fd of this tmp file. # python test/zdtm.py run -t zdtm/static/env00 --remote -f ns === Run 1/1 ================ zdtm/static/env00 ========================= Run zdtm/static/env00 in ns ========================== Start test ./env00 --pidfile=env00.pid --outfile=env00.out --envname=ENV_00_TEST Adding image cache Adding image proxy Run criu dump Run criu restore =[log]=> dump/zdtm/static/env00/31/1/restore.log ------------------------ grep Error ------------------------ RTNETLINK answers: File exists (00.229895) 1: do_open_remote_image RDONLY path=route-9.img snapshot_id=dump/zdtm/static/env00/31/1 (00.230316) 1: Running ip route restore Failed to restore: ftell: Illegal seek (00.232757) 1: Error (criu/util.c:712): exited, status=255 (00.232777) 1: Error (criu/net.c:1479): IP tool failed on route restore (00.232803) 1: Error (criu/net.c:2153): Can't create net_ns (00.255091) Error (criu/cr-restore.c:1177): 105 killed by signal 9: Killed (00.255307) Error (criu/mount.c:2960): mnt: Can't remove the directory /tmp/.criu.mntns.dTd7ak: No such file or directory (00.255339) Error (criu/cr-restore.c:2119): Restoring FAILED. ------------------------ ERROR OVER ------------------------ ################# Test zdtm/static/env00 FAIL at CRIU restore ################## ##################################### FAIL ##################################### Fixes #311 Signed-off-by: Radostin Stoyanov Signed-off-by: Andrei Vagin --- criu/net.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/criu/net.c b/criu/net.c index 762f9b547..27e7c7e33 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2068,19 +2068,46 @@ out: static int restore_ip_dump(int type, int pid, char *cmd) { - int ret = -1; + int ret = -1, sockfd, n, written; + FILE *tmp_file; struct cr_img *img; + char buf[1024]; img = open_image(type, O_RSTR, pid); if (empty_image(img)) { close_image(img); return 0; } + sockfd = img_raw_fd(img); + tmp_file = tmpfile(); + if (!tmp_file) { + pr_perror("Failed to open tmpfile"); + return -1; + } + + while ((n = read(sockfd, buf, 1024)) > 0) { + written = fwrite(buf, sizeof(char), n, tmp_file); + if (written < n) { + pr_perror("Failed to write to tmpfile " + "[written: %d; total: %d]", written, n); + return -1; + } + } + + if (fseek(tmp_file, 0, SEEK_SET)) { + pr_perror("Failed to set file position to beginning of tmpfile"); + return -1; + } + if (img) { - ret = run_ip_tool(cmd, "restore", NULL, NULL, img_raw_fd(img), -1, 0); + ret = run_ip_tool(cmd, "restore", NULL, NULL, fileno(tmp_file), -1, 0); close_image(img); } + if(fclose(tmp_file)) { + pr_perror("Failed to close tmpfile"); + } + return ret; } From 51c3f8a908b1738d7d268afc5bb0dd9a59f3d8a5 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 11 Jun 2020 21:01:24 +0000 Subject: [PATCH 2391/4375] pipes: loop over splice() when dumping a pipe's data Instead of erroring, we should loop until we get the desired number of bytes written, like regular I/O loops. Signed-off-by: Nicolas Viennot --- criu/pipes.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/criu/pipes.c b/criu/pipes.c index d74329161..5787fdc53 100644 --- a/criu/pipes.c +++ b/criu/pipes.c @@ -463,18 +463,15 @@ int dump_one_pipe_data(struct pipe_data_dump *pd, int lfd, const struct fd_parms if (pb_write_one(img, &pde, PB_PIPE_DATA)) goto err_close; - if (bytes) { + while (bytes > 0) { int wrote; - wrote = splice(steal_pipe[0], NULL, img_raw_fd(img), NULL, bytes, 0); if (wrote < 0) { pr_perror("Can't push pipe data"); goto err_close; - } else if (wrote != bytes) { - pr_err("%#x: Wanted to write %d bytes, but wrote %d\n", - pipe_id(p), bytes, wrote); - goto err_close; - } + } else if (wrote == 0) + break; + bytes -= wrote; } ret = 0; From 7d79a58f4daa9ddda015fc0aaca2a60d156d12cc Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 21 May 2020 17:40:17 +0000 Subject: [PATCH 2392/4375] img-streamer: introduction of criu-image-streamer This adds the ability to stream images with criu-image-streamer The workflow is the following: 1) criu-image-streamer is started, and starts listening on a UNIX socket. 2) CRIU is started. img_streamer_init() is invoked, which connects to the socket. During dump/restore operations, instead of using local disk to open an image file, img_streamer_open() is called to provide a UNIX pipe that is sent over the UNIX socket. 3) Once the operation is done, img_streamer_finish() is called, and the UNIX socket is disconnected. criu-image-streamer can be found at: https://github.com/checkpoint-restore/criu-image-streamer Signed-off-by: Nicolas Viennot --- Documentation/criu.txt | 5 + criu/Makefile.crtools | 1 + criu/config.c | 1 + criu/cr-dump.c | 2 + criu/cr-restore.c | 4 + criu/cr-service.c | 9 +- criu/crtools.c | 34 ++++- criu/files-reg.c | 10 +- criu/image.c | 32 +++-- criu/img-streamer.c | 232 +++++++++++++++++++++++++++++++++++ criu/include/cr_options.h | 1 + criu/include/image.h | 2 +- criu/include/img-streamer.h | 8 ++ criu/include/protobuf-desc.h | 4 +- criu/include/servicefd.h | 1 + criu/mem.c | 6 +- criu/page-xfer.c | 8 ++ criu/pagemap.c | 63 +++++++++- criu/protobuf-desc.c | 1 + criu/util.c | 14 ++- images/Makefile | 1 + images/img-streamer.proto | 16 +++ 22 files changed, 429 insertions(+), 26 deletions(-) create mode 100644 criu/img-streamer.c create mode 100644 criu/include/img-streamer.h create mode 100644 images/img-streamer.proto diff --git a/Documentation/criu.txt b/Documentation/criu.txt index ab63e461c..4e9b4132e 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -76,6 +76,11 @@ The following levels are available: *-D*, *--images-dir* 'path':: Use 'path' as a base directory where to look for sets of image files. +*--stream*:: + dump/restore images using criu-image-streamer. + See https://github.com/checkpoint-restore/criu-image-streamer for detailed + usage. + *--prev-images-dir* 'path':: Use 'path' as a parent directory where to look for sets of image files. This option makes sense in case of incremental dumps. diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index 5c25b8928..dc92c2ea2 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -29,6 +29,7 @@ obj-y += files-reg.o obj-y += fsnotify.o obj-y += image-desc.o obj-y += image.o +obj-y += img-streamer.o obj-y += ipc_ns.o obj-y += irmap.o obj-y += kcmp-ids.o diff --git a/criu/config.c b/criu/config.c index b84b7da28..e78b534a9 100644 --- a/criu/config.c +++ b/criu/config.c @@ -510,6 +510,7 @@ int parse_options(int argc, char **argv, bool *usage_error, BOOL_OPT(SK_CLOSE_PARAM, &opts.tcp_close), { "verbosity", optional_argument, 0, 'v' }, { "ps-socket", required_argument, 0, 1091}, + BOOL_OPT("stream", &opts.stream), { "config", required_argument, 0, 1089}, { "no-default-config", no_argument, 0, 1090}, { "tls-cacert", required_argument, 0, 1092}, diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 745998afc..2b4c9ae82 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -82,6 +82,7 @@ #include "eventpoll.h" #include "memfd.h" #include "timens.h" +#include "img-streamer.h" /* * Architectures can overwrite this function to restore register sets that @@ -1759,6 +1760,7 @@ static int cr_dump_finish(int ret) free_userns_maps(); close_service_fd(CR_PROC_FD_OFF); + close_image_dir(); if (ret) { pr_err("Dumping FAILED.\n"); diff --git a/criu/cr-restore.c b/criu/cr-restore.c index ed4b95b91..f572f79a0 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -29,6 +29,7 @@ #include "cr_options.h" #include "servicefd.h" #include "image.h" +#include "img-streamer.h" #include "util.h" #include "util-pie.h" #include "criu-log.h" @@ -2355,6 +2356,9 @@ skip_ns_bouncing: pr_info("Restore finished successfully. Tasks resumed.\n"); write_stats(RESTORE_STATS); + /* This has the effect of dismissing the image streamer */ + close_image_dir(); + ret = run_scripts(ACT_POST_RESUME); if (ret != 0) pr_err("Post-resume script ret code %d\n", ret); diff --git a/criu/cr-service.c b/criu/cr-service.c index 279016bcd..53eadb1bc 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -343,7 +343,14 @@ static int setup_opts_from_req(int sk, CriuOpts *req) if (req->parent_img) SET_CHAR_OPTS(img_parent, req->parent_img); - if (open_image_dir(images_dir_path) < 0) { + /* + * Image streaming is not supported with CRIU's service feature as + * the streamer must be started for each dump/restore operation. + * It is unclear how to do that with RPC, so we punt for now. + * This explains why we provide the argument mode=-1 instead of + * O_RSTR or O_DUMP. + */ + if (open_image_dir(images_dir_path, -1) < 0) { pr_perror("Can't open images directory"); goto err; } diff --git a/criu/crtools.c b/criu/crtools.c index 7f72dde27..ad61fa9bb 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -54,6 +54,20 @@ void flush_early_log_to_stderr(void) flush_early_log_buffer(STDERR_FILENO); } +static int image_dir_mode(char *argv[], int optind) +{ + if (!strcmp(argv[optind], "dump") || + !strcmp(argv[optind], "pre-dump") || + (!strcmp(argv[optind], "cpuinfo") && !strcmp(argv[optind + 1], "dump"))) + return O_DUMP; + + if (!strcmp(argv[optind], "restore") || + (!strcmp(argv[optind], "cpuinfo") && !strcmp(argv[optind + 1], "restore"))) + return O_RSTR; + + return -1; +} + int main(int argc, char *argv[], char *envp[]) { int ret = -1; @@ -148,13 +162,30 @@ int main(int argc, char *argv[], char *envp[]) } } + if (opts.stream && image_dir_mode(argv, optind) == -1) { + pr_err("--stream cannot be used with the %s command\n", argv[optind]); + goto usage; + } + /* We must not open imgs dir, if service is called */ if (strcmp(argv[optind], "service")) { - ret = open_image_dir(opts.imgs_dir); + ret = open_image_dir(opts.imgs_dir, image_dir_mode(argv, optind)); if (ret < 0) return 1; } + /* + * The kernel might send us lethal signals when writing to a pipe + * which reader has disappeared. We deal with write() failures on our + * own, and prefer not to get killed. So we ignore SIGPIPEs. + * + * Pipes are used in various places: + * 1) Receiving application page data + * 2) Transmitting data to the image streamer + * 3) Emitting logs (potentially to a pipe). + */ + signal(SIGPIPE, SIG_IGN); + /* * When a process group becomes an orphan, * its processes are sent a SIGHUP signal @@ -322,6 +353,7 @@ usage: " this requires running a second instance of criu\n" " in lazy-pages mode: 'criu lazy-pages -D DIR'\n" " --lazy-pages and lazy-pages mode require userfaultfd\n" +" --stream dump/restore images using criu-image-streamer\n" "\n" "* External resources support:\n" " --external RES dump objects from this list as external resources:\n" diff --git a/criu/files-reg.c b/criu/files-reg.c index b53e9b080..7e84addf2 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -154,7 +154,6 @@ static int trim_last_parent(char *path) static int copy_chunk_from_file(int fd, int img, off_t off, size_t len) { - char *buf = NULL; int ret; while (len > 0) { @@ -167,7 +166,6 @@ static int copy_chunk_from_file(int fd, int img, off_t off, size_t len) len -= ret; } - xfree(buf); return 0; } @@ -213,7 +211,6 @@ static int copy_file_to_chunks(int fd, struct cr_img *img, size_t file_size) static int copy_chunk_to_file(int img, int fd, off_t off, size_t len) { - char *buf = NULL; int ret; while (len > 0) { @@ -221,7 +218,11 @@ static int copy_chunk_to_file(int img, int fd, off_t off, size_t len) pr_perror("Can't seek file"); return -1; } - ret = sendfile(fd, img, NULL, len); + + if (opts.stream) + ret = splice(img, NULL, fd, NULL, len, SPLICE_F_MOVE); + else + ret = sendfile(fd, img, NULL, len); if (ret < 0) { pr_perror("Can't send data"); return -1; @@ -231,7 +232,6 @@ static int copy_chunk_to_file(int img, int fd, off_t off, size_t len) len -= ret; } - xfree(buf); return 0; } diff --git a/criu/image.c b/criu/image.c index 0225788b0..2bbb4dd02 100644 --- a/criu/image.c +++ b/criu/image.c @@ -17,6 +17,7 @@ #include "images/inventory.pb-c.h" #include "images/pagemap.pb-c.h" #include "proc_parse.h" +#include "img-streamer.h" #include "namespaces.h" bool ns_per_id = false; @@ -415,13 +416,16 @@ static int do_open_image(struct cr_img *img, int dfd, int type, unsigned long of flags = oflags & ~(O_NOBUF | O_SERVICE | O_FORCE_LOCAL); - /* - * For pages images dedup we need to open images read-write on - * restore, that may require proper capabilities, so we ask - * usernsd to do it for us - */ - if (root_ns_mask & CLONE_NEWUSER && - type == CR_FD_PAGES && oflags & O_RDWR) { + if (opts.stream && !(oflags & O_FORCE_LOCAL)) { + ret = img_streamer_open(path, flags); + errno = EIO; /* errno value is meaningless, only the ret value is meaningful */ + } else if (root_ns_mask & CLONE_NEWUSER && + type == CR_FD_PAGES && oflags & O_RDWR) { + /* + * For pages images dedup we need to open images read-write on + * restore, that may require proper capabilities, so we ask + * usernsd to do it for us + */ struct openat_args pa = { .flags = flags, .err = 0, @@ -520,7 +524,12 @@ struct cr_img *img_from_fd(int fd) return img; } -int open_image_dir(char *dir) +/* + * `mode` should be O_RSTR or O_DUMP depending on the intent. + * This is used when opts.stream is enabled for picking the right streamer + * socket name. `mode` is ignored when opts.stream is not enabled. + */ +int open_image_dir(char *dir, int mode) { int fd, ret; @@ -535,7 +544,10 @@ int open_image_dir(char *dir) return -1; fd = ret; - if (opts.img_parent) { + if (opts.stream) { + if (img_streamer_init(dir, mode) < 0) + goto err; + } else if (opts.img_parent) { ret = symlinkat(opts.img_parent, fd, CR_PARENT_LINK); if (ret < 0 && errno != EEXIST) { pr_perror("Can't link parent snapshot"); @@ -556,6 +568,8 @@ err: void close_image_dir(void) { + if (opts.stream) + img_streamer_finish(); close_service_fd(IMG_FD_OFF); } diff --git a/criu/img-streamer.c b/criu/img-streamer.c new file mode 100644 index 000000000..e31b17dd9 --- /dev/null +++ b/criu/img-streamer.c @@ -0,0 +1,232 @@ +#include +#include +#include +#include + +#include "cr_options.h" +#include "img-streamer.h" +#include "image.h" +#include "images/img-streamer.pb-c.h" +#include "protobuf.h" +#include "servicefd.h" +#include "rst-malloc.h" +#include "common/scm.h" +#include "common/lock.h" + +/* + * We use different path names for the dump and restore sockets because: + * 1) The user may want to perform both at the same time (akin to live + * migration). Specifying the same images-dir is convenient. + * 2) It fails quickly when the user mix-up the streamer and CRIU operations. + * (e.g., streamer is in capture more, while CRIU is in restore mode). + */ +#define IMG_STREAMER_CAPTURE_SOCKET_NAME "streamer-capture.sock" +#define IMG_STREAMER_SERVE_SOCKET_NAME "streamer-serve.sock" + +/* All requests go through the same socket connection. We must synchronize */ +static mutex_t *img_streamer_fd_lock; + +/* Either O_DUMP or O_RSTR */ +static int img_streamer_mode; + +static const char *socket_name_for_mode(int mode) +{ + switch (mode) { + case O_DUMP: return IMG_STREAMER_CAPTURE_SOCKET_NAME; + case O_RSTR: return IMG_STREAMER_SERVE_SOCKET_NAME; + default: BUG(); return NULL; + } +} + +/* + * img_streamer_init() connects to the image streamer socket. + * mode should be either O_DUMP or O_RSTR. + */ +int img_streamer_init(const char *image_dir, int mode) +{ + struct sockaddr_un addr; + int sockfd; + + img_streamer_mode = mode; + + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) { + pr_perror("Unable to instantiate UNIX socket"); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", + image_dir, socket_name_for_mode(mode)); + + if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + pr_perror("Unable to connect to image streamer socket: %s", addr.sun_path); + goto err; + } + + img_streamer_fd_lock = shmalloc(sizeof(*img_streamer_fd_lock)); + if (!img_streamer_fd_lock) { + pr_err("Failed to allocate memory\n"); + goto err; + } + mutex_init(img_streamer_fd_lock); + + if (install_service_fd(IMG_STREAMER_FD_OFF, sockfd) < 0) + goto err; + + return 0; + +err: + close(sockfd); + return -1; +} + +/* + * img_streamer_finish() indicates that no more files will be opened. + * In other words, img_streamer_open() will no longer be called. + */ +void img_streamer_finish(void) +{ + if (get_service_fd(IMG_STREAMER_FD_OFF) >= 0) { + pr_info("Dismissing the image streamer\n"); + close_service_fd(IMG_STREAMER_FD_OFF); + } +} + +/* + * The regular protobuf APIs pb_write_one() and pb_read_one() operate over a + * `struct cr_img` object. Sadly, we don't have such object. We just have a + * file descriptor. The following pb_write_one_fd() and pb_read_one_fd() + * provide a protobuf API over a file descriptor. The implementation is a bit + * of a hack, but should be fine. At some point we can revisit to have a + * proper protobuf API over fds. + */ +static int pb_write_one_fd(int fd, void *obj, int type) +{ + int ret; + struct cr_img img; + memset(&img, 0, sizeof(img)); + + img._x.fd = fd; + ret = pb_write_one(&img, obj, type); + if (ret < 0) + pr_perror("Failed to communicate with the image streamer"); + return ret; +} + +static int pb_read_one_fd(int fd, void **pobj, int type) +{ + int ret; + struct cr_img img; + memset(&img, 0, sizeof(img)); + + img._x.fd = fd; + ret = pb_read_one(&img, pobj, type); + if (ret < 0) + pr_perror("Failed to communicate with the image streamer"); + return ret; +} + +static int send_file_request(char *filename) +{ + ImgStreamerRequestEntry req = IMG_STREAMER_REQUEST_ENTRY__INIT; + req.filename = filename; + return pb_write_one_fd(get_service_fd(IMG_STREAMER_FD_OFF), + &req, PB_IMG_STREAMER_REQUEST); +} + +static int recv_file_reply(bool *exists) +{ + ImgStreamerReplyEntry *reply; + int ret = pb_read_one_fd(get_service_fd(IMG_STREAMER_FD_OFF), + (void **)&reply, PB_IMG_STREAMER_REPLY); + if (ret < 0) + return ret; + + *exists = reply->exists; + free(reply); + + return 0; +} + +/* + * Using a pipe for image file transfers allows the data to be spliced by the + * image streamer, greatly improving performance. + * Transfer rates of up to 15GB/s can be seen with this technique. + */ +#define READ_PIPE 0 /* index of the read pipe returned by pipe() */ +#define WRITE_PIPE 1 +static int establish_streamer_file_pipe(void) +{ + /* + * If the other end of the pipe closes, the kernel will want to kill + * us with a SIGPIPE. These signal must be ignored, which we do in + * crtools.c:main() with signal(SIGPIPE, SIG_IGN). + */ + int ret = -1; + int criu_pipe_direction = img_streamer_mode == O_DUMP ? WRITE_PIPE : READ_PIPE; + int streamer_pipe_direction = 1 - criu_pipe_direction; + int fds[2]; + + if (pipe(fds) < 0) { + pr_perror("Unable to create pipe"); + return -1; + } + + if (send_fd(get_service_fd(IMG_STREAMER_FD_OFF), + NULL, 0, fds[streamer_pipe_direction]) < 0) + close(fds[criu_pipe_direction]); + else + ret = fds[criu_pipe_direction]; + + close(fds[streamer_pipe_direction]); + + return ret; +} + +static int _img_streamer_open(char *filename) +{ + if (send_file_request(filename) < 0) + return -1; + + if (img_streamer_mode == O_RSTR) { + /* The streamer replies whether the file exists */ + bool exists; + if (recv_file_reply(&exists) < 0) + return -1; + + if (!exists) + return -ENOENT; + } + + /* + * When the image streamer encounters a fatal error, it won't report + * errors via protobufs. Instead, CRIU will get a broken pipe error + * when trying to access a streaming pipe. This behavior is similar to + * what would happen if we were connecting criu and * criu-image-streamer + * via a shell pipe. + */ + + return establish_streamer_file_pipe(); +} + +/* + * Opens an image file via a UNIX pipe with the image streamer. + * + * Return: + * A file descriptor on success + * -ENOENT when the file was not found. + * -1 on any other error. + */ +int img_streamer_open(char *filename, int flags) +{ + int ret; + + BUG_ON(flags != img_streamer_mode); + + mutex_lock(img_streamer_fd_lock); + ret = _img_streamer_open(filename); + mutex_unlock(img_streamer_fd_lock); + return ret; +} diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h index ba405182e..d5655212d 100644 --- a/criu/include/cr_options.h +++ b/criu/include/cr_options.h @@ -143,6 +143,7 @@ struct cr_options { int weak_sysctls; int status_fd; bool orphan_pts_master; + int stream; pid_t tree_id; int log_level; char *imgs_dir; diff --git a/criu/include/image.h b/criu/include/image.h index 1c7cc5471..62c8d7ba0 100644 --- a/criu/include/image.h +++ b/criu/include/image.h @@ -145,7 +145,7 @@ static inline int img_raw_fd(struct cr_img *img) extern off_t img_raw_size(struct cr_img *img); -extern int open_image_dir(char *dir); +extern int open_image_dir(char *dir, int mode); extern void close_image_dir(void); extern struct cr_img *open_image_at(int dfd, int type, unsigned long flags, ...); diff --git a/criu/include/img-streamer.h b/criu/include/img-streamer.h new file mode 100644 index 000000000..0c380c915 --- /dev/null +++ b/criu/include/img-streamer.h @@ -0,0 +1,8 @@ +#ifndef IMAGE_STREAMER_H +#define IMAGE_STREAMER_H + +extern int img_streamer_init(const char *image_dir, int mode); +extern void img_streamer_finish(void); +extern int img_streamer_open(char *filename, int flags); + +#endif /* IMAGE_STREAMER_H */ diff --git a/criu/include/protobuf-desc.h b/criu/include/protobuf-desc.h index ee4135d65..43d961731 100644 --- a/criu/include/protobuf-desc.h +++ b/criu/include/protobuf-desc.h @@ -62,8 +62,10 @@ enum { PB_GHOST_CHUNK, PB_FILE, PB_MEMFD_FILE, - PB_MEMFD_INODE, /* 60 */ + PB_MEMFD_INODE, PB_TIMENS, + PB_IMG_STREAMER_REQUEST, + PB_IMG_STREAMER_REPLY, /* PB_AUTOGEN_STOP */ diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h index 986c46af5..c11f89d37 100644 --- a/criu/include/servicefd.h +++ b/criu/include/servicefd.h @@ -14,6 +14,7 @@ enum sfd_type { LOG_FD_OFF, IMG_FD_OFF, + IMG_STREAMER_FD_OFF, PROC_FD_OFF, /* fd with /proc for all proc_ calls */ PROC_PID_FD_OFF, CR_PROC_FD_OFF, /* some other's proc fd: diff --git a/criu/mem.c b/criu/mem.c index 15aa0cbdb..167838b98 100644 --- a/criu/mem.c +++ b/criu/mem.c @@ -1406,9 +1406,9 @@ static int prepare_vma_ios(struct pstree_item *t, struct task_restore_args *ta) /* * We optimize the case when rsti(t)->vma_io is empty. * - * This is useful for for remote images, where all VMAs are premapped - * (pr->pieok is false). This avoids re-opening the CR_FD_PAGES file, - * which could be no longer be available. + * This is useful when using the image streamer, where all VMAs are + * premapped (pr->pieok is false). This avoids re-opening the + * CR_FD_PAGES file, which may only be readable only once. */ if (list_empty(&rsti(t)->vma_io)) { ta->vma_ios = NULL; diff --git a/criu/page-xfer.c b/criu/page-xfer.c index 9affc2706..db8e5bec2 100644 --- a/criu/page-xfer.c +++ b/criu/page-xfer.c @@ -382,6 +382,10 @@ static int open_page_local_xfer(struct page_xfer *xfer, int fd_type, unsigned lo int pfd; int pr_flags = (fd_type == CR_FD_PAGEMAP) ? PR_TASK : PR_SHMEM; + /* Image streaming lacks support for incremental images */ + if (opts.stream) + goto out; + pfd = openat(get_service_fd(IMG_FD_OFF), CR_PARENT_LINK, O_RDONLY); if (pfd < 0 && errno == ENOENT) goto out; @@ -928,6 +932,10 @@ int check_parent_local_xfer(int fd_type, unsigned long img_id) struct stat st; int ret, pfd; + /* Image streaming lacks support for incremental images */ + if (opts.stream) + return 0; + pfd = openat(get_service_fd(IMG_FD_OFF), CR_PARENT_LINK, O_RDONLY); if (pfd < 0 && errno == ENOENT) return 0; diff --git a/criu/pagemap.c b/criu/pagemap.c index 05f6b82b8..f1e1be91f 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -406,6 +406,49 @@ static int maybe_read_page_local(struct page_read *pr, unsigned long vaddr, return ret; } +/* + * We cannot use maybe_read_page_local() for streaming images as it uses + * pread(), seeking in the file. Instead, we use this custom page reader. + */ +static int maybe_read_page_img_streamer(struct page_read *pr, unsigned long vaddr, + int nr, void *buf, unsigned flags) +{ + unsigned long len = nr * PAGE_SIZE; + int fd = img_raw_fd(pr->pi); + int ret; + size_t curr = 0; + + pr_debug("\tpr%lu-%u Read page from self %lx/%"PRIx64"\n", + pr->img_id, pr->id, pr->cvaddr, pr->pi_off); + + /* We can't seek. The requested address better match */ + BUG_ON(pr->cvaddr != vaddr); + + while (1) { + ret = read(fd, buf + curr, len - curr); + if (ret == 0) { + pr_err("Reached EOF unexpectedly while reading page from image\n"); + return -1; + } else if (ret < 0) { + pr_perror("Can't read mapping page %d", ret); + return -1; + } + curr += ret; + if (curr == len) + break; + } + + if (opts.auto_dedup) + pr_warn_once("Can't dedup when streaming images\n"); + + if (ret == 0 && pr->io_complete) + ret = pr->io_complete(pr, vaddr, nr); + + pr->pi_off += len; + + return ret; +} + static int read_page_complete(unsigned long img_id, unsigned long vaddr, int nr_pages, void *priv) { int ret = 0; @@ -601,6 +644,10 @@ static int try_open_parent(int dfd, unsigned long id, struct page_read *pr, int int pfd, ret; struct page_read *parent = NULL; + /* Image streaming lacks support for incremental images */ + if (opts.stream) + goto out; + pfd = openat(dfd, CR_PARENT_LINK, O_RDONLY); if (pfd < 0 && errno == ENOENT) goto out; @@ -657,7 +704,19 @@ static int init_pagemaps(struct page_read *pr) off_t fsize; int nr_pmes, nr_realloc; - fsize = img_raw_size(pr->pmi); + if (opts.stream) { + /* + * TODO - There is no easy way to estimate the size of the + * pagemap that is still to be read from the pipe. Possible + * solution is to ask the image streamer for the size of the + * image. 1024 is a wild guess (more space is allocated if + * needed). + */ + fsize = 1024; + } else { + fsize = img_raw_size(pr->pmi); + } + if (fsize < 0) return -1; @@ -781,6 +840,8 @@ int open_page_read_at(int dfd, unsigned long img_id, struct page_read *pr, int p if (remote) pr->maybe_read_page = maybe_read_page_remote; + else if (opts.stream) + pr->maybe_read_page = maybe_read_page_img_streamer; else { pr->maybe_read_page = maybe_read_page_local; if (!pr->parent && !opts.lazy_pages) diff --git a/criu/protobuf-desc.c b/criu/protobuf-desc.c index 2ee81e5db..13655264a 100644 --- a/criu/protobuf-desc.c +++ b/criu/protobuf-desc.c @@ -63,6 +63,7 @@ #include "images/seccomp.pb-c.h" #include "images/binfmt-misc.pb-c.h" #include "images/autofs.pb-c.h" +#include "images/img-streamer.pb-c.h" struct cr_pb_message_desc cr_pb_descs[PB_MAX]; diff --git a/criu/util.c b/criu/util.c index 06c594ca9..b30dbc86c 100644 --- a/criu/util.c +++ b/criu/util.c @@ -423,13 +423,19 @@ int copy_file(int fd_in, int fd_out, size_t bytes) { ssize_t written = 0; size_t chunk = bytes ? bytes : 4096; + ssize_t ret; while (1) { - ssize_t ret; - - ret = sendfile(fd_out, fd_in, NULL, chunk); + /* + * When fd_out is a pipe, sendfile() returns -EINVAL, so we + * fallback to splice(). Not sure why. + */ + if (opts.stream) + ret = splice(fd_in, NULL, fd_out, NULL, chunk, SPLICE_F_MOVE); + else + ret = sendfile(fd_out, fd_in, NULL, chunk); if (ret < 0) { - pr_perror("Can't send data to ghost file"); + pr_perror("Can't transfer data to ghost file from image"); return -1; } diff --git a/images/Makefile b/images/Makefile index 5ddd37664..bc67278e6 100644 --- a/images/Makefile +++ b/images/Makefile @@ -65,6 +65,7 @@ proto-obj-y += macvlan.o proto-obj-y += sit.o proto-obj-y += memfd.o proto-obj-y += timens.o +proto-obj-y += img-streamer.o CFLAGS += -iquote $(obj)/ diff --git a/images/img-streamer.proto b/images/img-streamer.proto new file mode 100644 index 000000000..d1bd4cc19 --- /dev/null +++ b/images/img-streamer.proto @@ -0,0 +1,16 @@ +syntax = "proto2"; + +// This message is sent from CRIU to the streamer. +// * During dump, it communicates the name of the file that is about to be sent +// to the streamer. +// * During restore, CRIU requests image files from the streamer. The message is +// used to communicate the name of the desired file. +message img_streamer_request_entry { + required string filename = 1; +} + +// This message is sent from the streamer to CRIU. It is only used during +// restore to report whether the requested file exists. +message img_streamer_reply_entry { + required bool exists = 1; +} From 27ab533cbec281f60726c2ec3a26f74ca661e814 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 10 Jun 2020 20:25:36 +0000 Subject: [PATCH 2393/4375] tests: run tests with criu-image-streamer with --stream One can pass --stream to zdtm.py for testing criu with image streaming. criu-image-streamer should be installed in ../criu-image-streamer relative to the criu project directory. But any path will do providing that criu-image-streamer can be found in the PATH env. Added a few tests to run on travis-ci to make sure streaming works. We run test that are likely to fail. However, it would be good to once in a while run all tests with `--stream -a`. Signed-off-by: Nicolas Viennot --- .travis.yml | 1 + scripts/install-criu-image-streamer.sh | 14 ++++ scripts/travis/travis-tests | 15 ++++ test/zdtm.py | 106 ++++++++++++++++++++++++- 4 files changed, 133 insertions(+), 3 deletions(-) create mode 100755 scripts/install-criu-image-streamer.sh diff --git a/.travis.yml b/.travis.yml index 9928f16c2..69a505193 100644 --- a/.travis.yml +++ b/.travis.yml @@ -94,6 +94,7 @@ jobs: arch: amd64 env: TR_ARCH=ppc64-cross dist: bionic + - env: TR_ARCH=local STREAM_TEST=1 allow_failures: - env: TR_ARCH=docker-test - env: TR_ARCH=docker-test DIST=xenial diff --git a/scripts/install-criu-image-streamer.sh b/scripts/install-criu-image-streamer.sh new file mode 100755 index 000000000..e4f368602 --- /dev/null +++ b/scripts/install-criu-image-streamer.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -eux + +# Install Rust toolchain +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + +# Clone criu-image-streamer in a sibling directory of the criu project directory +cd $(dirname "$0")/../../ +# TODO change dev branch to master once PR is merged +git clone --depth=1 https://github.com/checkpoint-restore/criu-image-streamer.git -b dev + +# Compile +cd criu-image-streamer +make BUILD=debug # debug build compiles faster than release mode (2x faster) diff --git a/scripts/travis/travis-tests b/scripts/travis/travis-tests index 4cb842c97..311236d7d 100755 --- a/scripts/travis/travis-tests +++ b/scripts/travis/travis-tests @@ -61,6 +61,13 @@ travis_prep () { chmod a+x $HOME } +test_stream() { + # We must test CRIU features that dump content into an image file to ensure + # streaming compatibility. + STREAM_TEST_PATTERN='.*(ghost|fifo|unlink|memfd|shmem|socket_queue).*' + ./test/zdtm.py run --stream -p 2 --keep-going -T $STREAM_TEST_PATTERN $ZDTM_OPTS +} + travis_prep export GCOV @@ -132,6 +139,14 @@ chmod 0777 test/ chmod 0777 test/zdtm/static chmod 0777 test/zdtm/transition +# We run streaming tests separately to improve test completion times, +# hence the exit 0. +if [ "${STREAM_TEST}" = "1" ]; then + ./scripts/install-criu-image-streamer.sh + test_stream + exit 0 +fi + ./test/zdtm.py run -a -p 2 --keep-going $ZDTM_OPTS KERN_MAJ=`uname -r | cut -d. -f1` diff --git a/test/zdtm.py b/test/zdtm.py index b111fa383..49387e43e 100755 --- a/test/zdtm.py +++ b/test/zdtm.py @@ -30,6 +30,9 @@ import yaml os.chdir(os.path.dirname(os.path.abspath(__file__))) +# File to store content of streamed images +STREAMED_IMG_FILE_NAME = "img.criu" + prev_line = None @@ -1024,6 +1027,7 @@ class criu: self.__mdedup = bool(opts['noauto_dedup']) self.__user = bool(opts['user']) self.__leave_stopped = bool(opts['stop']) + self.__stream = bool(opts['stream']) self.__criu = (opts['rpc'] and criu_rpc or criu_cli) self.__show_stats = bool(opts['show_stats']) self.__lazy_pages_p = None @@ -1208,11 +1212,19 @@ class criu: stats_written = int(stent['shpages_written']) + int( stent['pages_written']) + if self.__stream: + p = self.spawn_criu_image_streamer("extract") + p.wait() + real_written = 0 for f in os.listdir(self.__ddir()): if f.startswith('pages-'): real_written += os.path.getsize(os.path.join(self.__ddir(), f)) + if self.__stream: + # make sure the extracted image is not usable. + os.unlink(os.path.join(self.__ddir(), "inventory.img")) + r_pages = real_written / mmap.PAGESIZE r_off = real_written % mmap.PAGESIZE if (stats_written != r_pages) or (r_off != 0): @@ -1220,6 +1232,57 @@ class criu: (stats_written, r_pages, r_off)) raise test_fail_exc("page counts mismatch") + # action can be "capture", "extract", or "serve" + def spawn_criu_image_streamer(self, action): + print("Run criu-image-streamer in {} mode".format(action)) + + progress_r, progress_w = os.pipe() + # We fcntl() on both file descriptors due to some potential differences + # with python2 and python3. + fcntl.fcntl(progress_r, fcntl.F_SETFD, fcntl.FD_CLOEXEC) + fcntl.fcntl(progress_w, fcntl.F_SETFD, 0) + + # We use cat because the streamer requires to work with pipes. + if action == 'capture': + cmd = ["criu-image-streamer", + "--images-dir '{images_dir}'", + "--progress-fd {progress_fd}", + action, + "| cat > {img_file}"] + else: + cmd = ["cat {img_file} |", + "criu-image-streamer", + "--images-dir '{images_dir}'", + "--progress-fd {progress_fd}", + action] + + # * As we are using a shell pipe command, we want to use pipefail. + # Otherwise, failures stay unnoticed. For this, we use bash as sh + # doesn't support that feature. + # * We use close_fds=False because we want the child to inherit the progress pipe + p = subprocess.Popen(["bash", "-c", "set -o pipefail; " + " ".join(cmd).format( + progress_fd=progress_w, + images_dir=self.__ddir(), + img_file=os.path.join(self.__ddir(), STREAMED_IMG_FILE_NAME) + )], close_fds=False) + + os.close(progress_w) + progress = os.fdopen(progress_r, "r") + + if action == 'serve' or action == 'extract': + # Consume image statistics + progress.readline() + + if action == 'capture' or action == 'serve': + # The streamer socket is ready for consumption once we receive the + # socket-init message. + if progress.readline().strip() != "socket-init": + p.kill() + raise test_fail_exc( + "criu-image-streamer is not starting (exit_code=%d)" % p.wait()) + + return p + def dump(self, action, opts=[]): self.__iter += 1 os.mkdir(self.__ddir()) @@ -1249,6 +1312,10 @@ class criu: a_opts += self.__test.getdopts() + if self.__stream: + streamer_p = self.spawn_criu_image_streamer("capture") + a_opts += ["--stream"] + if self.__dedup: a_opts += ["--auto-dedup"] @@ -1273,6 +1340,11 @@ class criu: self.__dump_process = self.__criu_act(action, opts=a_opts + opts, nowait=nowait) + if self.__stream: + ret = streamer_p.wait() + if ret: + raise test_fail_exc("criu-image-streamer exited with %d" % ret) + if self.__mdedup and self.__iter > 1: self.__criu_act("dedup", opts=[]) @@ -1303,6 +1375,10 @@ class criu: r_opts += ['--empty-ns', 'net'] r_opts += ['--action-script', os.getcwd() + '/empty-netns-prep.sh'] + if self.__stream: + streamer_p = self.spawn_criu_image_streamer("serve") + r_opts += ["--stream"] + if self.__dedup: r_opts += ["--auto-dedup"] @@ -1336,6 +1412,11 @@ class criu: r_opts += ['--leave-stopped'] self.__criu_act("restore", opts=r_opts + ["--restore-detached"]) + if self.__stream: + ret = streamer_p.wait() + if ret: + raise test_fail_exc("criu-image-streamer exited with %d" % ret) + self.show_stats("restore") if self.__leave_stopped: @@ -1344,6 +1425,13 @@ class criu: @staticmethod def check(feature): + if feature == 'stream': + try: + p = subprocess.Popen(["criu-image-streamer", "--version"]) + return p.wait() == 0 + except Exception: + return False + return criu_cli.run( "check", ["--no-default-config", "-v0", "--feature", feature], opts['criu_bin']) == 0 @@ -1852,7 +1940,7 @@ class Launcher: 'stop', 'empty_ns', 'fault', 'keep_img', 'report', 'snaps', 'sat', 'script', 'rpc', 'lazy_pages', 'join_ns', 'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup', - 'remote_lazy_pages', 'show_stats', 'lazy_migrate', + 'remote_lazy_pages', 'show_stats', 'lazy_migrate', 'stream', 'tls', 'criu_bin', 'crit_bin', 'pre_dump_mode') arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd})) @@ -2138,6 +2226,15 @@ def run_tests(opts): "[WARNING] Non-cooperative UFFD is missing, some tests might spuriously fail" ) + if opts['stream']: + streamer_dir = os.path.realpath(opts['criu_image_streamer_dir']) + os.environ['PATH'] = "{}:{}".format(streamer_dir, os.environ['PATH']) + if not criu.check('stream'): + raise RuntimeError(( + "Streaming tests need the criu-image-streamer binary to be accessible in the {} directory. " + + "Specify --criu-image-streamer-dir or modify PATH to provide an alternate location") + .format(streamer_dir)) + launcher = Launcher(opts, len(torun)) try: for t in torun: @@ -2460,8 +2557,8 @@ rp.add_argument("--rpc", rp.add_argument("--page-server", help="Use page server dump", action='store_true') -rp.add_argument("--remote", - help="Use remote option for diskless C/R", +rp.add_argument("--stream", + help="Use criu-image-streamer", action='store_true') rp.add_argument("-p", "--parallel", help="Run test in parallel") rp.add_argument("--dry-run", @@ -2500,6 +2597,9 @@ rp.add_argument("--criu-bin", rp.add_argument("--crit-bin", help="Path to crit binary", default='../crit/crit') +rp.add_argument("--criu-image-streamer-dir", + help="Directory where the criu-image-streamer binary is located", + default="../../criu-image-streamer") rp.add_argument("--pre-dump-mode", help="Use splice or read mode of pre-dumping", choices=['splice', 'read'], From 8c538ca10dc4385baf911b9b1747ff2287aff5fb Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 6 Jul 2017 12:38:48 +0300 Subject: [PATCH 2394/4375] page-read: Warn about async read w/o completion cb Acked-by: Mike Rapoport Signed-off-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/pagemap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/criu/pagemap.c b/criu/pagemap.c index f1e1be91f..58f2850ff 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -462,6 +462,8 @@ static int read_page_complete(unsigned long img_id, unsigned long vaddr, int nr_ if (pr->io_complete) ret = pr->io_complete(pr, vaddr, nr_pages); + else + pr_warn_once("Remote page read w/o io_complete!\n"); return ret; } From eb732bcf0d7621e3b7a74797e8b4f04b40f2b183 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 24 Mar 2019 14:26:10 +0000 Subject: [PATCH 2395/4375] util: Remove deprecated print_data() routine The print_data() function was part of the deprecated (and removed) 'show' action, and it was moved in util.c with the following commit: a501b4804b3c95e1d83d64dd10ed95c37f0378bb The 'show' action has been deprecated since 1.6, let's finally drop it. The print_data() routine is kept for yet another (to be deprecated too) feature called 'criu exec'. The criu exec feature was removed with: 909590a3558560655c1ce5b72215efbb325999ca Remove criu exec code It's now obsoleted by compel library. Maybe-TODO: Add compel tool exec action? Therefore, now we can drop print_data() as well. Signed-off-by: Radostin Stoyanov --- criu/include/util.h | 2 -- criu/util.c | 75 +-------------------------------------------- 2 files changed, 1 insertion(+), 76 deletions(-) diff --git a/criu/include/util.h b/criu/include/util.h index 45bebf673..d67f6d39d 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -290,8 +290,6 @@ char *xstrcat(char *str, const char *fmt, ...) char *xsprintf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); -void print_data(unsigned long addr, unsigned char *data, size_t size); - int setup_tcp_server(char *type, char *addr, unsigned short *port); int run_tcp_server(bool daemon_mode, int *ask, int cfd, int sk); int setup_tcp_client(char *hostname); diff --git a/criu/util.c b/criu/util.c index b30dbc86c..517f0fc25 100644 --- a/criu/util.c +++ b/criu/util.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "linux/mount.h" @@ -994,85 +993,13 @@ void tcp_nodelay(int sk, bool on) pr_perror("Unable to restore TCP_NODELAY (%d)", val); } -static inline void pr_xsym(unsigned char *data, size_t len, int pos) -{ - char sym; - - if (pos < len) - sym = data[pos]; - else - sym = ' '; - - pr_msg("%c", isprint(sym) ? sym : '.'); -} - -static inline void pr_xdigi(unsigned char *data, size_t len, int pos) -{ - if (pos < len) - pr_msg("%02x ", data[pos]); - else - pr_msg(" "); -} - -static int nice_width_for(unsigned long addr) -{ - int ret = 3; - - while (addr) { - addr >>= 4; - ret++; - } - - return ret; -} - -void print_data(unsigned long addr, unsigned char *data, size_t size) -{ - int i, j, addr_len; - unsigned zero_line = 0; - - addr_len = nice_width_for(addr + size); - - for (i = 0; i < size; i += 16) { - if (*(u64 *)(data + i) == 0 && *(u64 *)(data + i + 8) == 0) { - if (zero_line == 0) - zero_line = 1; - else { - if (zero_line == 1) { - pr_msg("*\n"); - zero_line = 2; - } - - continue; - } - } else - zero_line = 0; - - pr_msg("%#0*lx: ", addr_len, addr + i); - for (j = 0; j < 8; j++) - pr_xdigi(data, size, i + j); - pr_msg(" "); - for (j = 8; j < 16; j++) - pr_xdigi(data, size, i + j); - - pr_msg(" |"); - for (j = 0; j < 8; j++) - pr_xsym(data, size, i + j); - pr_msg(" "); - for (j = 8; j < 16; j++) - pr_xsym(data, size, i + j); - - pr_msg("|\n"); - } -} - static int get_sockaddr_in(struct sockaddr_storage *addr, char *host, unsigned short port) { memset(addr, 0, sizeof(*addr)); if (!host) { - ((struct sockaddr_in *)addr)->sin_addr.s_addr = INADDR_ANY; + ((struct sockaddr_in *)addr)->sin_addr.s_addr = INADDR_ANY; addr->ss_family = AF_INET; } else if (inet_pton(AF_INET, host, &((struct sockaddr_in *)addr)->sin_addr)) { addr->ss_family = AF_INET; From 8be1d457d71c93ea0a592bdc2dc8a982cd3e6fa9 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 15 May 2019 09:47:17 +0000 Subject: [PATCH 2396/4375] net: fix coverity RESOURCE_LEAK criu-3.12/criu/net.c:2043: overwrite_var: Overwriting "img" in "img = open_image_at(-1, CR_FD_IP6TABLES, 0UL, pid)" leaks the storage that "img" points to. Signed-off-by: Adrian Reber --- criu/net.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/criu/net.c b/criu/net.c index 27e7c7e33..86fba2ddc 100644 --- a/criu/net.c +++ b/criu/net.c @@ -2090,13 +2090,13 @@ static int restore_ip_dump(int type, int pid, char *cmd) if (written < n) { pr_perror("Failed to write to tmpfile " "[written: %d; total: %d]", written, n); - return -1; + goto close; } } if (fseek(tmp_file, 0, SEEK_SET)) { pr_perror("Failed to set file position to beginning of tmpfile"); - return -1; + goto close; } if (img) { @@ -2104,6 +2104,7 @@ static int restore_ip_dump(int type, int pid, char *cmd) close_image(img); } +close: if(fclose(tmp_file)) { pr_perror("Failed to close tmpfile"); } @@ -2208,6 +2209,7 @@ static inline int restore_iptables(int pid) return -1; if (empty_image(img)) { ret = 0; + close_image(img); goto ipt6; } From ba0d6dbac1bd237319817ac0f34653a78686be1f Mon Sep 17 00:00:00 2001 From: Guoyun Sun Date: Wed, 8 Apr 2020 10:13:22 +0800 Subject: [PATCH 2397/4375] mips:compel/arch/mips: Add architecture support to compel tool and libraries This patch only adds the support but does not enable it for building. Signed-off-by: Guoyun Sun --- .../arch/mips/plugins/include/asm/prologue.h | 36 ++ .../mips/plugins/include/asm/syscall-types.h | 36 ++ compel/arch/mips/plugins/include/features.h | 6 + compel/arch/mips/plugins/std/memcpy.S | 23 ++ compel/arch/mips/plugins/std/parasite-head.S | 20 ++ .../plugins/std/syscalls/Makefile.syscalls | 117 +++++++ .../std/syscalls/syscall-common-mips-64.S | 12 + .../mips/plugins/std/syscalls/syscall_64.tbl | 115 +++++++ .../mips/scripts/compel-pack-compat.lds.S | 4 + compel/arch/mips/scripts/compel-pack.lds.S | 37 +++ compel/arch/mips/src/lib/cpu.c | 36 ++ compel/arch/mips/src/lib/handle-elf-host.c | 1 + compel/arch/mips/src/lib/handle-elf.c | 23 ++ compel/arch/mips/src/lib/include/handle-elf.h | 8 + compel/arch/mips/src/lib/include/ldsodefs.h | 147 +++++++++ compel/arch/mips/src/lib/include/syscall.h | 7 + .../mips/src/lib/include/uapi/asm/.gitignore | 0 .../src/lib/include/uapi/asm/breakpoints.h | 6 + .../arch/mips/src/lib/include/uapi/asm/cpu.h | 5 + .../arch/mips/src/lib/include/uapi/asm/fpu.h | 4 + .../src/lib/include/uapi/asm/infect-types.h | 66 ++++ .../mips/src/lib/include/uapi/asm/sigframe.h | 63 ++++ .../mips/src/lib/include/uapi/asm/siginfo.h | 124 +++++++ compel/arch/mips/src/lib/infect.c | 310 ++++++++++++++++++ include/common/arch/mips/asm/atomic.h | 148 +++++++++ include/common/arch/mips/asm/bitops.h | 41 +++ include/common/arch/mips/asm/bitsperlong.h | 6 + include/common/arch/mips/asm/cmpxchg.h | 67 ++++ include/common/arch/mips/asm/fls64.h | 38 +++ include/common/arch/mips/asm/linkage.h | 58 ++++ include/common/arch/mips/asm/page.h | 39 +++ include/common/arch/mips/asm/utils.h | 24 ++ 32 files changed, 1627 insertions(+) create mode 100755 compel/arch/mips/plugins/include/asm/prologue.h create mode 100755 compel/arch/mips/plugins/include/asm/syscall-types.h create mode 100755 compel/arch/mips/plugins/include/features.h create mode 100755 compel/arch/mips/plugins/std/memcpy.S create mode 100755 compel/arch/mips/plugins/std/parasite-head.S create mode 100755 compel/arch/mips/plugins/std/syscalls/Makefile.syscalls create mode 100755 compel/arch/mips/plugins/std/syscalls/syscall-common-mips-64.S create mode 100755 compel/arch/mips/plugins/std/syscalls/syscall_64.tbl create mode 100755 compel/arch/mips/scripts/compel-pack-compat.lds.S create mode 100755 compel/arch/mips/scripts/compel-pack.lds.S create mode 100755 compel/arch/mips/src/lib/cpu.c create mode 120000 compel/arch/mips/src/lib/handle-elf-host.c create mode 100755 compel/arch/mips/src/lib/handle-elf.c create mode 100755 compel/arch/mips/src/lib/include/handle-elf.h create mode 100755 compel/arch/mips/src/lib/include/ldsodefs.h create mode 100755 compel/arch/mips/src/lib/include/syscall.h create mode 100755 compel/arch/mips/src/lib/include/uapi/asm/.gitignore create mode 100755 compel/arch/mips/src/lib/include/uapi/asm/breakpoints.h create mode 100755 compel/arch/mips/src/lib/include/uapi/asm/cpu.h create mode 100644 compel/arch/mips/src/lib/include/uapi/asm/fpu.h create mode 100755 compel/arch/mips/src/lib/include/uapi/asm/infect-types.h create mode 100755 compel/arch/mips/src/lib/include/uapi/asm/sigframe.h create mode 100755 compel/arch/mips/src/lib/include/uapi/asm/siginfo.h create mode 100755 compel/arch/mips/src/lib/infect.c create mode 100755 include/common/arch/mips/asm/atomic.h create mode 100644 include/common/arch/mips/asm/bitops.h create mode 100755 include/common/arch/mips/asm/bitsperlong.h create mode 100755 include/common/arch/mips/asm/cmpxchg.h create mode 100644 include/common/arch/mips/asm/fls64.h create mode 100644 include/common/arch/mips/asm/linkage.h create mode 100755 include/common/arch/mips/asm/page.h create mode 100644 include/common/arch/mips/asm/utils.h diff --git a/compel/arch/mips/plugins/include/asm/prologue.h b/compel/arch/mips/plugins/include/asm/prologue.h new file mode 100755 index 000000000..9d812eec9 --- /dev/null +++ b/compel/arch/mips/plugins/include/asm/prologue.h @@ -0,0 +1,36 @@ +#ifndef __ASM_PROLOGUE_H__ +#define __ASM_PROLOGUE_H__ + +#ifndef __ASSEMBLY__ + +#include +#include +#include + +#include + +#define sys_recv(sockfd, ubuf, size, flags) \ + sys_recvfrom(sockfd, ubuf, size, flags, NULL, NULL) + +typedef struct prologue_init_args { + struct sockaddr_un ctl_sock_addr; + unsigned int ctl_sock_addr_len; + + unsigned int arg_s; + void *arg_p; + + void *sigframe; +} prologue_init_args_t; + +#endif /* __ASSEMBLY__ */ + +/* + * Reserve enough space for sigframe. + * + * FIXME It is rather should be taken from sigframe header. + */ +#define PROLOGUE_SGFRAME_SIZE 4096 + +#define PROLOGUE_INIT_ARGS_SIZE 1024 + +#endif /* __ASM_PROLOGUE_H__ */ diff --git a/compel/arch/mips/plugins/include/asm/syscall-types.h b/compel/arch/mips/plugins/include/asm/syscall-types.h new file mode 100755 index 000000000..64daf2c7a --- /dev/null +++ b/compel/arch/mips/plugins/include/asm/syscall-types.h @@ -0,0 +1,36 @@ +#ifndef COMPEL_ARCH_SYSCALL_TYPES_H__ +#define COMPEL_ARCH_SYSCALL_TYPES_H__ + +/* Types for sigaction, sigprocmask syscalls */ +typedef void rt_signalfn_t(int, siginfo_t *, void *); +typedef rt_signalfn_t *rt_sighandler_t; + +typedef void rt_restorefn_t(void); +typedef rt_restorefn_t *rt_sigrestore_t; + +#define SA_RESTORER 0x04000000 + +/** refer to linux-3.10/arch/mips/include/uapi/asm/signal.h*/ +#define _KNSIG 128 +#define _NSIG_BPW 64 + +#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW) + +/* + * Note: as k_rtsigset_t is the same size for 32-bit and 64-bit, + * sig defined as uint64_t rather than (unsigned long) - for the + * purpose if we ever going to support native 32-bit compilation. + */ + +typedef struct { + uint64_t sig[_KNSIG_WORDS]; +} k_rtsigset_t; + +typedef struct { + rt_sighandler_t rt_sa_handler; + unsigned long rt_sa_flags; + rt_sigrestore_t rt_sa_restorer; + k_rtsigset_t rt_sa_mask; +} rt_sigaction_t; + +#endif /* COMPEL_ARCH_SYSCALL_TYPES_H__ */ diff --git a/compel/arch/mips/plugins/include/features.h b/compel/arch/mips/plugins/include/features.h new file mode 100755 index 000000000..0f35725fa --- /dev/null +++ b/compel/arch/mips/plugins/include/features.h @@ -0,0 +1,6 @@ +#ifndef __COMPEL_ARCH_FEATURES_H +#define __COMPEL_ARCH_FEATURES_H + +#define ARCH_HAS_MEMCPY + +#endif /* __COMPEL_ARCH_FEATURES_H */ diff --git a/compel/arch/mips/plugins/std/memcpy.S b/compel/arch/mips/plugins/std/memcpy.S new file mode 100755 index 000000000..262267f7f --- /dev/null +++ b/compel/arch/mips/plugins/std/memcpy.S @@ -0,0 +1,23 @@ + +#include "common/asm/linkage.h" + + .section .head.text, "ax" +ENTRY(memcpy) + .set noreorder + dadd v0,zero,a0 + daddiu t1,zero,0 +loop: + beq t1,a2,exit + nop + lb t2,0(a1) + sb t2,0(a0) + daddiu t1,t1,1 + daddiu a0,a0,1 + daddiu a1,a1,1 + j loop + nop +exit: + jr ra + nop +END(memcpy) + diff --git a/compel/arch/mips/plugins/std/parasite-head.S b/compel/arch/mips/plugins/std/parasite-head.S new file mode 100755 index 000000000..38e87f823 --- /dev/null +++ b/compel/arch/mips/plugins/std/parasite-head.S @@ -0,0 +1,20 @@ + +#include "common/asm/linkage.h" + + + .section .head.text, "ax" +ENTRY(__export_parasite_head_start) + .set push + .set noreorder + lw a0, __export_parasite_cmd + dla a1, __export_parasite_args + jal parasite_service + nop + .byte 0x0d, 0x00, 0x00, 0x00 //break + .set pop +// .byte 0x40,0x01,0x00,0x00 //pause + +__export_parasite_cmd: + .long 0 +END(__export_parasite_head_start) + diff --git a/compel/arch/mips/plugins/std/syscalls/Makefile.syscalls b/compel/arch/mips/plugins/std/syscalls/Makefile.syscalls new file mode 100755 index 000000000..ef75f9e95 --- /dev/null +++ b/compel/arch/mips/plugins/std/syscalls/Makefile.syscalls @@ -0,0 +1,117 @@ +std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/syscalls-64.o +sys-proto-types := $(obj)/include/uapi/std/syscall-types.h +sys-proto-generic := $(obj)/include/uapi/std/syscall.h +sys-codes-generic := $(obj)/include/uapi/std/syscall-codes.h +sys-codes = $(obj)/include/uapi/std/syscall-codes-$(1).h +sys-proto = $(obj)/include/uapi/std/syscall-$(1).h +sys-def = $(PLUGIN_ARCH_DIR)/std/syscalls/syscall_$(1).tbl +sys-asm = $(PLUGIN_ARCH_DIR)/std/syscalls-$(1).S +sys-asm-common-name = std/syscalls/syscall-common-mips-$(1).S +sys-asm-common = $(PLUGIN_ARCH_DIR)/$(sys-asm-common-name) +sys-asm-types := $(obj)/include/uapi/std/asm/syscall-types.h +sys-exec-tbl = $(PLUGIN_ARCH_DIR)/std/sys-exec-tbl-$(1).c + +sys-bits := 64 + +AV := $$$$ + +define gen-rule-sys-codes +$(sys-codes): $(sys-def) $(sys-proto-types) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) echo "#ifndef ASM_SYSCALL_CODES_H_$(1)__" >> $$@ + $(Q) echo "#define ASM_SYSCALL_CODES_H_$(1)__" >> $$@ + $(Q) cat $$< | awk '/^__NR/{SYSN=$(AV)1; \ + sub("^__NR", "SYS", SYSN); \ + print "\n#ifndef ", $(AV)1; \ + print "#define", $(AV)1, $(AV)2; \ + print "#endif"; \ + print "\n#ifndef ", SYSN; \ + print "#define ", SYSN, $(AV)1; \ + print "#endif";}' >> $$@ + $(Q) echo "#endif /* ASM_SYSCALL_CODES_H_$(1)__ */" >> $$@ +endef + +define gen-rule-sys-proto +$(sys-proto): $(sys-def) $(sys-proto-types) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) echo "#ifndef ASM_SYSCALL_PROTO_H_$(1)__" >> $$@ + $(Q) echo "#define ASM_SYSCALL_PROTO_H_$(1)__" >> $$@ + $(Q) echo '#include ' >> $$@ + $(Q) echo '#include ' >> $$@ +ifeq ($(1),32) + $(Q) echo '#include "asm/syscall32.h"' >> $$@ +endif + $(Q) cat $$< | awk '/^__NR/{print "extern long", $(AV)3, \ + substr($(AV)0, index($(AV)0,$(AV)4)), ";"}' >> $$@ + $(Q) echo "#endif /* ASM_SYSCALL_PROTO_H_$(1)__ */" >> $$@ +endef + +define gen-rule-sys-asm +$(sys-asm): $(sys-def) $(sys-asm-common) $(sys-codes) $(sys-proto) $(sys-proto-types) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) echo '#include ' >> $$@ + $(Q) echo '#include "$(sys-asm-common-name)"' >> $$@ + $(Q) cat $$< | awk '/^__NR/{print "SYSCALL(", $(AV)3, ",", $(AV)2, ")"}' >> $$@ +endef + +define gen-rule-sys-exec-tbl +$(sys-exec-tbl): $(sys-def) $(sys-codes) $(sys-proto) $(sys-proto-generic) $(sys-proto-types) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) cat $$< | awk '/^__NR/{print \ + "SYSCALL(", substr($(AV)3, 5), ",", $(AV)2, ")"}' >> $$@ +endef + +$(sys-codes-generic): $(sys-proto-types) + $(call msg-gen, $@) + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_CODES_H__" >> $@ + $(Q) echo "#define __ASM_CR_SYSCALL_CODES_H__" >> $@ + $(Q) echo '#include ' >> $@ + $(Q) cat $< | awk '/^__NR/{NR32=$$1; \ + sub("^__NR", "__NR32", NR32); \ + print "\n#ifndef ", NR32; \ + print "#define ", NR32, $$2; \ + print "#endif";}' >> $@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_CODES_H__ */" >> $@ +mrproper-y += $(sys-codes-generic) + +$(sys-proto-generic): $(strip $(call map,sys-proto,$(sys-bits))) $(sys-proto-types) + $(call msg-gen, $@) + $(Q) echo "/* Autogenerated, don't edit */" > $@ + $(Q) echo "#ifndef __ASM_CR_SYSCALL_PROTO_H__" >> $@ + $(Q) echo "#define __ASM_CR_SYSCALL_PROTO_H__" >> $@ + $(Q) echo "" >> $@ + $(Q) echo '#include ' >> $@ + $(Q) echo "" >> $@ + $(Q) echo "#endif /* __ASM_CR_SYSCALL_PROTO_H__ */" >> $@ +mrproper-y += $(sys-proto-generic) + +define gen-rule-sys-exec-tbl +$(sys-exec-tbl): $(sys-def) $(sys-codes) $(sys-proto) $(sys-proto-generic) + $(call msg-gen, $$@) + $(Q) echo "/* Autogenerated, don't edit */" > $$@ + $(Q) cat $$< | awk '/^__NR/{print \ + "SYSCALL(", substr($(AV)3, 5), ",", $(AV)2, ")"}' >> $$@ +endef + +$(eval $(call map,gen-rule-sys-codes,$(sys-bits))) +$(eval $(call map,gen-rule-sys-proto,$(sys-bits))) +$(eval $(call map,gen-rule-sys-asm,$(sys-bits))) +$(eval $(call map,gen-rule-sys-exec-tbl,$(sys-bits))) + +$(sys-asm-types): $(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h + $(call msg-gen, $@) + $(Q) ln -s ../../../../../../$(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h $(sys-asm-types) + +std-headers-deps += $(call sys-codes,$(sys-bits)) +std-headers-deps += $(call sys-proto,$(sys-bits)) +std-headers-deps += $(call sys-asm,$(sys-bits)) +std-headers-deps += $(call sys-exec-tbl,$(sys-bits)) +std-headers-deps += $(sys-codes-generic) +std-headers-deps += $(sys-proto-generic) +std-headers-deps += $(sys-asm-types) +mrproper-y += $(std-headers-deps) diff --git a/compel/arch/mips/plugins/std/syscalls/syscall-common-mips-64.S b/compel/arch/mips/plugins/std/syscalls/syscall-common-mips-64.S new file mode 100755 index 000000000..3478488da --- /dev/null +++ b/compel/arch/mips/plugins/std/syscalls/syscall-common-mips-64.S @@ -0,0 +1,12 @@ +#include "common/asm/linkage.h" + +#define SYSCALL(name, opcode) \ + ENTRY(name); \ + li v0, opcode; \ + syscall; \ + jr ra; \ + nop; \ + END(name) + +ENTRY(__cr_restore_rt) +END(__cr_restore_rt) diff --git a/compel/arch/mips/plugins/std/syscalls/syscall_64.tbl b/compel/arch/mips/plugins/std/syscalls/syscall_64.tbl new file mode 100755 index 000000000..47c08fc4c --- /dev/null +++ b/compel/arch/mips/plugins/std/syscalls/syscall_64.tbl @@ -0,0 +1,115 @@ +# +# System calls table, please make sure the table consist only the syscalls +# really used somewhere in project. +# from kernel/linux-3.10.84/arch/mips/include/uapi/asm/unistd.h Linux 64-bit syscalls are in the range from 5000 to 5999. +# +# __NR_name code name arguments +# ------------------------------------------------------------------------------------------------------------------------------------------------------------- +__NR_read 5000 sys_read (int fd, void *buf, unsigned long count) +__NR_write 5001 sys_write (int fd, const void *buf, unsigned long count) +__NR_open 5002 sys_open (const char *filename, unsigned long flags, unsigned long mode) +__NR_close 5003 sys_close (int fd) +__NR_lseek 5008 sys_lseek (int fd, unsigned long offset, unsigned long origin) +__NR_mmap 5009 sys_mmap (void *addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long offset) +__NR_mprotect 5010 sys_mprotect (const void *addr, unsigned long len, unsigned long prot) +__NR_munmap 5011 sys_munmap (void *addr, unsigned long len) +__NR_brk 5012 sys_brk (void *addr) +__NR_rt_sigaction 5013 sys_sigaction (int signum, const rt_sigaction_t *act, rt_sigaction_t *oldact, size_t sigsetsize) +__NR_rt_sigprocmask 5014 sys_sigprocmask (int how, k_rtsigset_t *set, k_rtsigset_t *old, size_t sigsetsize) +__NR_rt_sigreturn 5211 sys_rt_sigreturn (void) +__NR_ioctl 5015 sys_ioctl (unsigned int fd, unsigned int cmd, unsigned long arg) +__NR_pread64 5016 sys_pread (unsigned int fd, char *buf, size_t count, loff_t pos) +__NR_mremap 5024 sys_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) +__NR_mincore 5026 sys_mincore (void *addr, unsigned long size, unsigned char *vec) +__NR_madvise 5027 sys_madvise (unsigned long start, size_t len, int behavior) +__NR_shmat 5029 sys_shmat (int shmid, void *shmaddr, int shmflag) +__NR_dup2 5032 sys_dup2 (int oldfd, int newfd) +__NR_nanosleep 5034 sys_nanosleep (struct timespec *req, struct timespec *rem) +__NR_getitimer 5035 sys_getitimer (int which, const struct itimerval *val) +__NR_setitimer 5036 sys_setitimer (int which, const struct itimerval *val, struct itimerval *old) +__NR_getpid 5038 sys_getpid (void) +__NR_socket 5040 sys_socket (int domain, int type, int protocol) +__NR_connect 5041 sys_connect (int sockfd, struct sockaddr *addr, int addrlen) +__NR_sendto 5043 sys_sendto (int sockfd, void *buff, size_t len, unsigned int flags, struct sockaddr *addr, int addr_len) +__NR_recvfrom 5044 sys_recvfrom (int sockfd, void *ubuf, size_t size, unsigned int flags, struct sockaddr *addr, int *addr_len) +__NR_sendmsg 5045 sys_sendmsg (int sockfd, const struct msghdr *msg, int flags) +__NR_recvmsg 5046 sys_recvmsg (int sockfd, struct msghdr *msg, int flags) +__NR_shutdown 5047 sys_shutdown (int sockfd, int how) +__NR_bind 5048 sys_bind (int sockfd, const struct sockaddr *addr, int addrlen) +__NR_setsockopt 5053 sys_setsockopt (int sockfd, int level, int optname, const void *optval, socklen_t optlen) +__NR_getsockopt 5054 sys_getsockopt (int sockfd, int level, int optname, const void *optval, socklen_t *optlen) +__NR_clone 5055 sys_clone (unsigned long flags, void *child_stack, void *parent_tid, unsigned long newtls, void *child_tid) +__NR_exit 5058 sys_exit (unsigned long error_code) +__NR_wait4 5059 sys_wait4 (int pid, int *status, int options, struct rusage *ru) +__NR_kill 5060 sys_kill (long pid, int sig) +__NR_fcntl 5070 sys_fcntl (int fd, int type, long arg) +__NR_flock 5071 sys_flock (int fd, unsigned long cmd) +__NR_mkdir 5081 sys_mkdir (const char *name, int mode) +__NR_rmdir 5082 sys_rmdir (const char *name) +__NR_unlink 5085 sys_unlink (char *pathname) +__NR_umask 5093 sys_umask (int mask) +__NR_gettimeofday 5094 sys_gettimeofday (struct timeval *tv, struct timezone *tz) +__NR_ptrace 5099 sys_ptrace (long request, pid_t pid, void *addr, void *data) +__NR_getgroups 5113 sys_getgroups (int gsize, unsigned int *groups) +__NR_setgroups 5114 sys_setgroups (int gsize, unsigned int *groups) +__NR_setresuid 5115 sys_setresuid (int uid, int euid, int suid) +__NR_getresuid 5116 sys_getresuid (int *uid, int *euid, int *suid) +__NR_setresgid 5117 sys_setresgid (int gid, int egid, int sgid) +__NR_getresgid 5118 sys_getresgid (int *gid, int *egid, int *sgid) +__NR_getpgid 5119 sys_getpgid (pid_t pid) +__NR_setfsuid 5120 sys_setfsuid (int fsuid) +__NR_setfsgid 5121 sys_setfsgid (int fsgid) +__NR_getsid 5122 sys_getsid (void) +__NR_capget 5123 sys_capget (struct cap_header *h, struct cap_data *d) +__NR_capset 5124 sys_capset (struct cap_header *h, struct cap_data *d) +__NR_rt_sigqueueinfo 5127 sys_rt_sigqueueinfo (pid_t pid, int sig, siginfo_t *info) +__NR_sigaltstack 5129 sys_sigaltstack (const void *uss, void *uoss) +__NR_personality 5132 sys_personality (unsigned int personality) +__NR_setpriority 5138 sys_setpriority (int which, int who, int nice) +__NR_sched_setscheduler 5141 sys_sched_setscheduler (int pid, int policy, struct sched_param *p) +__NR_prctl 5153 sys_prctl (int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) +__NR_setrlimit 5155 sys_setrlimit (int resource, struct krlimit *rlim) +__NR_mount 5160 sys_mount (char *dev_nmae, char *dir_name, char *type, unsigned long flags, void *data) +__NR_umount2 5161 sys_umount2 (char *name, int flags) +__NR_gettid 5178 sys_gettid (void) +__NR_futex 5194 sys_futex (uint32_t *uaddr, int op, uint32_t val, struct timespec *utime, uint32_t *uaddr2, uint32_t val3) +__NR_cacheflush 5197 sys_cacheflush (char *addr, int nbytes, int cache) +__NR_io_setup 5200 sys_io_setup (unsigned nr_events, aio_context_t *ctx) +__NR_io_getevents 5202 sys_io_getevents (aio_context_t ctx, long min_nr, long nr, struct io_event *evs, struct timespec *tmo) +__NR_io_submit 5203 sys_io_submit (aio_context_t ctx, long nr, struct iocb **iocbpp) +__NR_set_tid_address 5212 sys_set_tid_address (int *tid_addr) +__NR_restart_syscall 5213 sys_restart_syscall (void) +__NR_sys_timer_create 5216 sys_timer_create (clockid_t which_clock, struct sigevent *timer_event_spec, kernel_timer_t *created_timer_id) +__NR_sys_timer_settime 5217 sys_timer_settime (kernel_timer_t timer_id, int flags, const struct itimerspec *new_setting, struct itimerspec *old_setting) +__NR_sys_timer_gettime 5218 sys_timer_gettime (int timer_id, const struct itimerspec *setting) +__NR_sys_timer_getoverrun 5219 sys_timer_getoverrun (int timer_id) +__NR_sys_timer_delete 5220 sys_timer_delete (kernel_timer_t timer_id) +__NR_clock_gettime 5222 sys_clock_gettime (const clockid_t which_clock, const struct timespec *tp) +__NR_exit_group 5205 sys_exit_group (int error_code) +__NR_set_thread_area 5242 sys_set_thread_area (unsigned long *addr) +__NR_openat 5247 sys_openat (int dfd, const char *filename, int flags, int mode) +__NR_waitid 5237 sys_waitid (int which, pid_t pid, struct siginfo *infop, int options, struct rusage *ru) +__NR_readlinkat 5257 sys_readlinkat (int fd, const char *path, char *buf, int bufsize) +__NR_ppoll 5261 sys_ppoll (struct pollfd *fds, unsigned int nfds, const struct timespec *tmo, const sigset_t *sigmask, size_t sigsetsize) +__NR_set_robust_list 5268 sys_set_robust_list (struct robust_list_head *head, size_t len) +__NR_get_robust_list 5269 sys_get_robust_list (int pid, struct robust_list_head **head_ptr, size_t *len_ptr) +__NR_fallocate 5279 sys_fallocate (int fd, int mode, loff_t offset, loff_t len) +__NR_seccomp 5312 sys_seccomp (unsigned int op, unsigned int flags, const char *uargs) +__NR_vmsplice 5266 sys_vmsplice (int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags) +__NR_timerfd_settime 5282 sys_timerfd_settime (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr) +__NR_signalfd4 5283 sys_signalfd (int fd, k_rtsigset_t *mask, size_t sizemask, int flags) +__NR_preadv 5289 sys_preadv_raw (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h) +__NR_rt_tgsigqueueinfo 5291 sys_rt_tgsigqueueinfo (pid_t tgid, pid_t pid, int sig, siginfo_t *info) +__NR_fanotify_init 5295 sys_fanotify_init (unsigned int flags, unsigned int event_f_flags) +__NR_fanotify_mark 5296 sys_fanotify_mark (int fanotify_fd, unsigned int flags, uint64_t mask, int dfd, const char *pathname) +__NR_open_by_handle_at 5299 sys_open_by_handle_at (int mountdirfd, struct file_handle *handle, int flags) +__NR_setns 5303 sys_setns (int fd, int nstype) +__NR_kcmp 5306 sys_kcmp (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) +__NR_memfd_create 5314 sys_memfd_create (const char *name, unsigned int flags) +__NR_userfaultfd 5317 sys_userfaultfd (int flags) + +##TODO for kernel +__NR_fsopen 5430 sys_fsopen (char *fsname, unsigned int flags) +__NR_fsconfig 5431 sys_fsconfig (int fd, unsigned int cmd, const char *key, const char *value, int aux) +__NR_fsmount 5432 sys_fsmount (int fd, unsigned int flags, unsigned int attr_flags) +__NR_clone3 5435 sys_clone3 (struct clone_args *uargs, size_t size) \ No newline at end of file diff --git a/compel/arch/mips/scripts/compel-pack-compat.lds.S b/compel/arch/mips/scripts/compel-pack-compat.lds.S new file mode 100755 index 000000000..0ae585e0d --- /dev/null +++ b/compel/arch/mips/scripts/compel-pack-compat.lds.S @@ -0,0 +1,4 @@ +OUTPUT_ARCH(mips) +EXTERN(__export_parasite_head_start) +ASSERT(0,"Compatible PIEs are unsupported on mips") + diff --git a/compel/arch/mips/scripts/compel-pack.lds.S b/compel/arch/mips/scripts/compel-pack.lds.S new file mode 100755 index 000000000..cadb19aef --- /dev/null +++ b/compel/arch/mips/scripts/compel-pack.lds.S @@ -0,0 +1,37 @@ +OUTPUT_ARCH(mips) +EXTERN(__export_parasite_head_start) + +SECTIONS +{ + .text : { + *(.head.text) + ASSERT(DEFINED(__export_parasite_head_start), + "Symbol __export_parasite_head_start is missing"); + *(.text*) + *(.compel.exit) + *(.compel.init) + /* .rodata section*/ + *(.rodata*) + *(.got*) + /* .data section */ + *(.data*) + *(.bss*) + *(.sbss*) + *(.toc*) + } + + /DISCARD/ : { /*segments need to discard */ + *(.debug*) + *(.pdr) + *(.comment*) + *(.note*) + *(.group*) + *(.eh_frame*) + *(.MIPS.options) + *(.gnu.attributes) + } + +/* Parasite args should have 4 bytes align, as we have futex inside. */ +. = ALIGN(32); +__export_parasite_args = .; +} diff --git a/compel/arch/mips/src/lib/cpu.c b/compel/arch/mips/src/lib/cpu.c new file mode 100755 index 000000000..4b071cd16 --- /dev/null +++ b/compel/arch/mips/src/lib/cpu.c @@ -0,0 +1,36 @@ +#include +#include + +#include "compel-cpu.h" +#include "common/bitops.h" +#include "common/compiler.h" +#include "log.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "cpu: " + +static compel_cpuinfo_t rt_info; +static bool rt_info_done = false; + +void compel_set_cpu_cap(compel_cpuinfo_t *c, unsigned int feature){ } + +void compel_clear_cpu_cap(compel_cpuinfo_t *c, unsigned int feature){ } + +int compel_test_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) +{ + return 0; +} + +int compel_cpuid(compel_cpuinfo_t *c){ + return 0; +} + +bool compel_cpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + + return compel_test_cpu_cap(&rt_info, feature); +} diff --git a/compel/arch/mips/src/lib/handle-elf-host.c b/compel/arch/mips/src/lib/handle-elf-host.c new file mode 120000 index 000000000..fe4611886 --- /dev/null +++ b/compel/arch/mips/src/lib/handle-elf-host.c @@ -0,0 +1 @@ +handle-elf.c \ No newline at end of file diff --git a/compel/arch/mips/src/lib/handle-elf.c b/compel/arch/mips/src/lib/handle-elf.c new file mode 100755 index 000000000..199bb1581 --- /dev/null +++ b/compel/arch/mips/src/lib/handle-elf.c @@ -0,0 +1,23 @@ +#include +#include + +#include "handle-elf.h" +#include "piegen.h" +#include "log.h" + +static const unsigned char __maybe_unused +elf_ident_64_le[EI_NIDENT] = { + 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +extern int __handle_elf(void *mem, size_t size); + +int handle_binary(void *mem, size_t size) +{ + if (memcmp(mem, elf_ident_64_le, sizeof(elf_ident_64_le)) == 0) + return __handle_elf(mem, size); + + pr_err("Unsupported Elf format detected\n"); + return -EINVAL; +} diff --git a/compel/arch/mips/src/lib/include/handle-elf.h b/compel/arch/mips/src/lib/include/handle-elf.h new file mode 100755 index 000000000..f28188136 --- /dev/null +++ b/compel/arch/mips/src/lib/include/handle-elf.h @@ -0,0 +1,8 @@ +#ifndef COMPEL_HANDLE_ELF_H__ +#define COMPEL_HANDLE_ELF_H__ + +#include "elf64-types.h" + +#define arch_is_machine_supported(e_machine) (e_machine == EM_MIPS) + +#endif /* COMPEL_HANDLE_ELF_H__ */ diff --git a/compel/arch/mips/src/lib/include/ldsodefs.h b/compel/arch/mips/src/lib/include/ldsodefs.h new file mode 100755 index 000000000..6e2d4f549 --- /dev/null +++ b/compel/arch/mips/src/lib/include/ldsodefs.h @@ -0,0 +1,147 @@ +/* Run-time dynamic linker data structures for loaded ELF shared objects. + Copyright (C) 2000-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#ifndef _MIPS_LDSODEFS_H +#define _MIPS_LDSODEFS_H 1 + +#include + +struct La_mips_32_regs; +struct La_mips_32_retval; +struct La_mips_64_regs; +struct La_mips_64_retval; + +#define ARCH_PLTENTER_MEMBERS \ + Elf32_Addr (*mips_o32_gnu_pltenter) (Elf32_Sym *, unsigned int, \ + uintptr_t *, uintptr_t *, \ + struct La_mips_32_regs *, \ + unsigned int *, const char *name, \ + long int *framesizep); \ + Elf32_Addr (*mips_n32_gnu_pltenter) (Elf32_Sym *, unsigned int, \ + uintptr_t *, uintptr_t *, \ + struct La_mips_64_regs *, \ + unsigned int *, const char *name, \ + long int *framesizep); \ + Elf64_Addr (*mips_n64_gnu_pltenter) (Elf64_Sym *, unsigned int, \ + uintptr_t *, uintptr_t *, \ + struct La_mips_64_regs *, \ + unsigned int *, const char *name, \ + long int *framesizep); + +#define ARCH_PLTEXIT_MEMBERS \ + unsigned int (*mips_o32_gnu_pltexit) (Elf32_Sym *, unsigned int, \ + uintptr_t *, uintptr_t *, \ + const struct La_mips_32_regs *, \ + struct La_mips_32_retval *, \ + const char *); \ + unsigned int (*mips_n32_gnu_pltexit) (Elf32_Sym *, unsigned int, \ + uintptr_t *, uintptr_t *, \ + const struct La_mips_64_regs *, \ + struct La_mips_64_retval *, \ + const char *); \ + unsigned int (*mips_n64_gnu_pltexit) (Elf64_Sym *, unsigned int, \ + uintptr_t *, uintptr_t *, \ + const struct La_mips_64_regs *, \ + struct La_mips_64_retval *, \ + const char *); + +/* The MIPS ABI specifies that the dynamic section has to be read-only. */ + +/* The 64-bit MIPS ELF ABI uses an unusual reloc format. Each + relocation entry specifies up to three actual relocations, all at + the same address. The first relocation which required a symbol + uses the symbol in the r_sym field. The second relocation which + requires a symbol uses the symbol in the r_ssym field. If all + three relocations require a symbol, the third one uses a zero + value. + + We define these structures in internal headers because we're not + sure we want to make them part of the ABI yet. Eventually, some of + this may move into elf/elf.h. */ + +/* An entry in a 64 bit SHT_REL section. */ + +typedef struct +{ + Elf32_Word r_sym; /* Symbol index */ + unsigned char r_ssym; /* Special symbol for 2nd relocation */ + unsigned char r_type3; /* 3rd relocation type */ + unsigned char r_type2; /* 2nd relocation type */ + unsigned char r_type1; /* 1st relocation type */ +} _Elf64_Mips_R_Info; + +typedef union +{ + Elf64_Xword r_info_number; + _Elf64_Mips_R_Info r_info_fields; +} _Elf64_Mips_R_Info_union; + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + _Elf64_Mips_R_Info_union r_info; /* Relocation type and symbol index */ +} Elf64_Mips_Rel; + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + _Elf64_Mips_R_Info_union r_info; /* Relocation type and symbol index */ + Elf64_Sxword r_addend; /* Addend */ +} Elf64_Mips_Rela; + +#define ELF64_MIPS_R_SYM(i) \ + ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_sym) +#define ELF64_MIPS_R_TYPE(i) \ + (((_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_type1 \ + | ((Elf32_Word)(__extension__ (_Elf64_Mips_R_Info_union)(i) \ + ).r_info_fields.r_type2 << 8) \ + | ((Elf32_Word)(__extension__ (_Elf64_Mips_R_Info_union)(i) \ + ).r_info_fields.r_type3 << 16) \ + | ((Elf32_Word)(__extension__ (_Elf64_Mips_R_Info_union)(i) \ + ).r_info_fields.r_ssym << 24)) +#define ELF64_MIPS_R_INFO(sym, type) \ + (__extension__ (_Elf64_Mips_R_Info_union) \ + (__extension__ (_Elf64_Mips_R_Info) \ + { (sym), ELF64_MIPS_R_SSYM (type), \ + ELF64_MIPS_R_TYPE3 (type), \ + ELF64_MIPS_R_TYPE2 (type), \ + ELF64_MIPS_R_TYPE1 (type) \ + }).r_info_number) +/* These macros decompose the value returned by ELF64_MIPS_R_TYPE, and + compose it back into a value that it can be used as an argument to + ELF64_MIPS_R_INFO. */ +#define ELF64_MIPS_R_SSYM(i) (((i) >> 24) & 0xff) +#define ELF64_MIPS_R_TYPE3(i) (((i) >> 16) & 0xff) +#define ELF64_MIPS_R_TYPE2(i) (((i) >> 8) & 0xff) +#define ELF64_MIPS_R_TYPE1(i) ((i) & 0xff) +#define ELF64_MIPS_R_TYPEENC(type1, type2, type3, ssym) \ + ((type1) \ + | ((Elf32_Word)(type2) << 8) \ + | ((Elf32_Word)(type3) << 16) \ + | ((Elf32_Word)(ssym) << 24)) + +#undef ELF64_R_SYM +#define ELF64_R_SYM(i) ELF64_MIPS_R_SYM (i) +#undef ELF64_R_TYPE + +/*fixme*/ +#define ELF64_R_TYPE(i) (ELF64_MIPS_R_TYPE (i) & 0x00ff) +#undef ELF64_R_INFO +#define ELF64_R_INFO(sym, type) ELF64_MIPS_R_INFO ((sym), (type)) + +#endif diff --git a/compel/arch/mips/src/lib/include/syscall.h b/compel/arch/mips/src/lib/include/syscall.h new file mode 100755 index 000000000..704080172 --- /dev/null +++ b/compel/arch/mips/src/lib/include/syscall.h @@ -0,0 +1,7 @@ +#ifndef __COMPEL_SYSCALL_H__ +#define __COMPEL_SYSCALL_H__ + +#ifndef SIGSTKFLT +#define SIGSTKFLT 16 +#endif +#endif diff --git a/compel/arch/mips/src/lib/include/uapi/asm/.gitignore b/compel/arch/mips/src/lib/include/uapi/asm/.gitignore new file mode 100755 index 000000000..e69de29bb diff --git a/compel/arch/mips/src/lib/include/uapi/asm/breakpoints.h b/compel/arch/mips/src/lib/include/uapi/asm/breakpoints.h new file mode 100755 index 000000000..21eb1309f --- /dev/null +++ b/compel/arch/mips/src/lib/include/uapi/asm/breakpoints.h @@ -0,0 +1,6 @@ +#ifndef __COMPEL_BREAKPOINTS_H__ +#define __COMPEL_BREAKPOINTS_H__ +#define ARCH_SI_TRAP TRAP_BRKPT +extern int ptrace_set_breakpoint(pid_t pid, void *addr); +extern int ptrace_flush_breakpoints(pid_t pid); +#endif diff --git a/compel/arch/mips/src/lib/include/uapi/asm/cpu.h b/compel/arch/mips/src/lib/include/uapi/asm/cpu.h new file mode 100755 index 000000000..329b9529b --- /dev/null +++ b/compel/arch/mips/src/lib/include/uapi/asm/cpu.h @@ -0,0 +1,5 @@ +#ifndef __CR_ASM_CPU_H__ +#define __CR_ASM_CPU_H__ + +typedef struct { } compel_cpuinfo_t; +#endif /* __CR_ASM_CPU_H__ */ diff --git a/compel/arch/mips/src/lib/include/uapi/asm/fpu.h b/compel/arch/mips/src/lib/include/uapi/asm/fpu.h new file mode 100644 index 000000000..7f476d541 --- /dev/null +++ b/compel/arch/mips/src/lib/include/uapi/asm/fpu.h @@ -0,0 +1,4 @@ +#ifndef __CR_ASM_FPU_H__ +#define __CR_ASM_FPU_H__ + +#endif /* __CR_ASM_FPU_H__ */ diff --git a/compel/arch/mips/src/lib/include/uapi/asm/infect-types.h b/compel/arch/mips/src/lib/include/uapi/asm/infect-types.h new file mode 100755 index 000000000..423880821 --- /dev/null +++ b/compel/arch/mips/src/lib/include/uapi/asm/infect-types.h @@ -0,0 +1,66 @@ +#ifndef UAPI_COMPEL_ASM_TYPES_H__ +#define UAPI_COMPEL_ASM_TYPES_H__ + +#include +#include +#include +#include +#include +#define SIGMAX 64 +#define SIGMAX_OLD 31 + +/* + + * Copied from the Linux kernel header arch/mips/include/asm/ptrace.h + * + * A thread MIPS CPU context + **/ +typedef struct { + /* Saved main processor registers. */ + __u64 regs[32]; + + /* Saved special registers. */ + __u64 lo; + __u64 hi; + __u64 cp0_epc; + __u64 cp0_badvaddr; + __u64 cp0_status; + __u64 cp0_cause; +} user_regs_struct_t; + +/* from linux-3.10/arch/mips/kernel/ptrace.c */ +typedef struct { + /* Saved fpu registers. */ + __u64 regs[32]; + + __u32 fpu_fcr31; + __u32 fpu_id; + + +} user_fpregs_struct_t; + +#define MIPS_a0 regs[4] //arguments a0-a3 +#define MIPS_t0 regs[8] //temporaries t0-t7 +#define MIPS_v0 regs[2] +#define MIPS_v1 regs[3] +#define MIPS_sp regs[29] +#define MIPS_ra regs[31] + + +#define NATIVE_MAGIC 0x0A +#define COMPAT_MAGIC 0x0C +static inline bool user_regs_native(user_regs_struct_t *pregs) +{ + return true; +} + + +#define REG_RES(regs) ((regs).MIPS_v0) +#define REG_IP(regs) ((regs).cp0_epc) +#define REG_SP(regs) ((regs).MIPS_sp) +#define REG_SYSCALL_NR(regs) ((regs).MIPS_v0) + +//#define __NR(syscall, compat) ((compat) ? __NR32_##syscall : __NR_##syscall) +#define __NR(syscall, compat) __NR_##syscall + +#endif /* UAPI_COMPEL_ASM_TYPES_H__ */ diff --git a/compel/arch/mips/src/lib/include/uapi/asm/sigframe.h b/compel/arch/mips/src/lib/include/uapi/asm/sigframe.h new file mode 100755 index 000000000..ed6a959fc --- /dev/null +++ b/compel/arch/mips/src/lib/include/uapi/asm/sigframe.h @@ -0,0 +1,63 @@ +#ifndef UAPI_COMPEL_ASM_SIGFRAME_H__ +#define UAPI_COMPEL_ASM_SIGFRAME_H__ + +#include +#include + +#include +#include + +#include +#define u32 __u32 + +/* sigcontext defined in /usr/include/asm/sigcontext.h*/ +#define rt_sigcontext sigcontext + + +#include + +/* refer to linux-3.10/include/uapi/asm-generic/ucontext.h */ +struct k_ucontext{ + unsigned long uc_flags; + struct k_ucontext *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + k_rtsigset_t uc_sigmask; +}; + +/* Copy from the kernel source arch/mips/kernel/signal.c */ +struct rt_sigframe { + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_pad[2]; /* Was: signal trampoline */ + siginfo_t rs_info; + struct k_ucontext rs_uc; +}; + + +#define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->rs_uc) +#define RT_SIGFRAME_UC_SIGMASK(rt_sigframe) ((k_rtsigset_t *)(void *)&rt_sigframe->rs_uc.uc_sigmask) +#define RT_SIGFRAME_REGIP(rt_sigframe) ((long unsigned int)0x00) +#define RT_SIGFRAME_FPU(rt_sigframe) +#define RT_SIGFRAME_HAS_FPU(rt_sigframe) 1 + + +#define RT_SIGFRAME_OFFSET(rt_sigframe) 0 + + +#define ARCH_RT_SIGRETURN(new_sp, rt_sigframe) \ + asm volatile( \ + "move $29, %0 \n" \ + "li $2, "__stringify(__NR_rt_sigreturn)" \n" \ + "syscall \n" \ + : \ + : "r"(new_sp) \ + : "$29","$2","memory") + +int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, + struct rt_sigframe *rsigframe); + +#define rt_sigframe_erase_sigset(sigframe) \ + memset(&sigframe->rs_uc.uc_sigmask, 0, sizeof(k_rtsigset_t)) +#define rt_sigframe_copy_sigset(sigframe, from) \ + memcpy(&sigframe->rs_uc.uc_sigmask, from, sizeof(k_rtsigset_t)) +#endif /* UAPI_COMPEL_ASM_SIGFRAME_H__ */ diff --git a/compel/arch/mips/src/lib/include/uapi/asm/siginfo.h b/compel/arch/mips/src/lib/include/uapi/asm/siginfo.h new file mode 100755 index 000000000..519aea1a6 --- /dev/null +++ b/compel/arch/mips/src/lib/include/uapi/asm/siginfo.h @@ -0,0 +1,124 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1998, 1999, 2001, 2003 Ralf Baechle + * Copyright (C) 2000, 2001 Silicon Graphics, Inc. + */ +#ifndef _UAPI_ASM_SIGINFO_H +#define _UAPI_ASM_SIGINFO_H + + +#define __ARCH_SIGEV_PREAMBLE_SIZE (sizeof(long) + 2*sizeof(int)) +#undef __ARCH_SI_TRAPNO /* exception code needs to fill this ... */ + +#define HAVE_ARCH_SIGINFO_T + +/* + * Careful to keep union _sifields from shifting ... + */ + +#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) + +#define __ARCH_SIGSYS + +#define SI_MAX_SIZE 128 +#define SI_PAD_SIZE ((SI_MAX_SIZE - __ARCH_SI_PREAMBLE_SIZE) / sizeof(int)) +#define __ARCH_SI_UID_T __kernel_uid32_t + +#ifndef __ARCH_SI_UID_T +#define __ARCH_SI_UID_T __kernel_uid32_t +#endif + +#ifndef __ARCH_SI_BAND_T +#define __ARCH_SI_BAND_T long +#endif + +#ifndef __ARCH_SI_CLOCK_T +#define __ARCH_SI_CLOCK_T __kernel_clock_t +#endif + +#ifndef __ARCH_SI_ATTRIBUTES +#define __ARCH_SI_ATTRIBUTES +#endif + +typedef struct siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[SI_PAD_SIZE]; + + /* kill() */ + struct { + __kernel_pid_t _pid; /* sender's pid */ + __ARCH_SI_UID_T _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + __kernel_timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)]; + sigval_t _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ + } _timer; + + /* POSIX.1b signals */ + struct { + __kernel_pid_t _pid; /* sender's pid */ + __ARCH_SI_UID_T _uid; /* sender's uid */ + sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + __kernel_pid_t _pid; /* which child */ + __ARCH_SI_UID_T _uid; /* sender's uid */ + int _status; /* exit code */ + __ARCH_SI_CLOCK_T _utime; + __ARCH_SI_CLOCK_T _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + void *_addr; /* faulting insn/memory ref. */ +#ifdef __ARCH_SI_TRAPNO + int _trapno; /* TRAP # which caused the signal */ +#endif + short _addr_lsb; /* LSB of the reported address */ +#ifndef __GENKSYMS__ + struct { + void *_lower; + void *_upper; + } _addr_bnd; +#endif + } _sigfault; + + /* SIGPOLL */ + struct { + __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + + /* SIGSYS */ + struct { + void *_call_addr; /* calling user insn */ + int _syscall; /* triggering system call number */ + unsigned int _arch; /* AUDIT_ARCH_* of syscall */ + } _sigsys; + } _sifields; +} __ARCH_SI_ATTRIBUTES siginfo_t; + +/* + * si_code values + * Again these have been chosen to be IRIX compatible. + */ +#undef SI_ASYNCIO +#undef SI_TIMER +#undef SI_MESGQ +#define SI_ASYNCIO -2 /* sent by AIO completion */ + +#endif /* _UAPI_ASM_SIGINFO_H */ diff --git a/compel/arch/mips/src/lib/infect.c b/compel/arch/mips/src/lib/infect.c new file mode 100755 index 000000000..a7dcea55a --- /dev/null +++ b/compel/arch/mips/src/lib/infect.c @@ -0,0 +1,310 @@ +#include +#include +#include +#include +#include +#include +#include "errno.h" +#include +#include +#include "common/err.h" +#include "common/page.h" +#include "asm/infect-types.h" +#include "ptrace.h" +#include "infect.h" +#include "infect-priv.h" +#include "log.h" +#include "common/bug.h" +/* + * Injected syscall instruction + * mips64el is Little Endian + */ +const char code_syscall[] = { + 0x0c, 0x00, 0x00, 0x00, /* syscall */ + 0x0d, 0x00, 0x00, 0x00 /* break */ +}; + +/* 10-byte legacy floating point register */ +struct fpreg { + uint16_t significand[4]; + uint16_t exponent; +}; + +/* 16-byte floating point register */ +struct fpxreg { + uint16_t significand[4]; + uint16_t exponent; + uint16_t padding[3]; +}; + + +int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, + user_regs_struct_t *regs, + user_fpregs_struct_t *fpregs) +{ + sigframe->rs_uc.uc_mcontext.sc_regs[0] = regs->regs[0]; + sigframe->rs_uc.uc_mcontext.sc_regs[1] = regs->regs[1]; + sigframe->rs_uc.uc_mcontext.sc_regs[2] = regs->regs[2]; + sigframe->rs_uc.uc_mcontext.sc_regs[3] = regs->regs[3]; + sigframe->rs_uc.uc_mcontext.sc_regs[4] = regs->regs[4]; + sigframe->rs_uc.uc_mcontext.sc_regs[5] = regs->regs[5]; + sigframe->rs_uc.uc_mcontext.sc_regs[6] = regs->regs[6]; + sigframe->rs_uc.uc_mcontext.sc_regs[7] = regs->regs[7]; + sigframe->rs_uc.uc_mcontext.sc_regs[8] = regs->regs[8]; + sigframe->rs_uc.uc_mcontext.sc_regs[9] = regs->regs[9]; + sigframe->rs_uc.uc_mcontext.sc_regs[10] = regs->regs[10]; + sigframe->rs_uc.uc_mcontext.sc_regs[11] = regs->regs[11]; + sigframe->rs_uc.uc_mcontext.sc_regs[12] = regs->regs[12]; + sigframe->rs_uc.uc_mcontext.sc_regs[13] = regs->regs[13]; + sigframe->rs_uc.uc_mcontext.sc_regs[14] = regs->regs[14]; + sigframe->rs_uc.uc_mcontext.sc_regs[15] = regs->regs[15]; + sigframe->rs_uc.uc_mcontext.sc_regs[16] = regs->regs[16]; + sigframe->rs_uc.uc_mcontext.sc_regs[17] = regs->regs[17]; + sigframe->rs_uc.uc_mcontext.sc_regs[18] = regs->regs[18]; + sigframe->rs_uc.uc_mcontext.sc_regs[19] = regs->regs[19]; + sigframe->rs_uc.uc_mcontext.sc_regs[20] = regs->regs[20]; + sigframe->rs_uc.uc_mcontext.sc_regs[21] = regs->regs[21]; + sigframe->rs_uc.uc_mcontext.sc_regs[22] = regs->regs[22]; + sigframe->rs_uc.uc_mcontext.sc_regs[23] = regs->regs[23]; + sigframe->rs_uc.uc_mcontext.sc_regs[24] = regs->regs[24]; + sigframe->rs_uc.uc_mcontext.sc_regs[25] = regs->regs[25]; + sigframe->rs_uc.uc_mcontext.sc_regs[26] = regs->regs[26]; + sigframe->rs_uc.uc_mcontext.sc_regs[27] = regs->regs[27]; + sigframe->rs_uc.uc_mcontext.sc_regs[28] = regs->regs[28]; + sigframe->rs_uc.uc_mcontext.sc_regs[29] = regs->regs[29]; + sigframe->rs_uc.uc_mcontext.sc_regs[30] = regs->regs[30]; + sigframe->rs_uc.uc_mcontext.sc_regs[31] = regs->regs[31]; + sigframe->rs_uc.uc_mcontext.sc_mdlo = regs->lo; + sigframe->rs_uc.uc_mcontext.sc_mdhi = regs->hi; + sigframe->rs_uc.uc_mcontext.sc_pc = regs->cp0_epc; + + sigframe->rs_uc.uc_mcontext.sc_fpregs[0] = fpregs->regs[0]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[1] = fpregs->regs[1]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[2] = fpregs->regs[2]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[3] = fpregs->regs[3]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[4] = fpregs->regs[4]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[5] = fpregs->regs[5]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[6] = fpregs->regs[6]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[7] = fpregs->regs[7]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[8] = fpregs->regs[8]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[9] = fpregs->regs[9]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[10] = fpregs->regs[10]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[11] = fpregs->regs[11]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[12] = fpregs->regs[12]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[13] = fpregs->regs[13]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[14] = fpregs->regs[14]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[15] = fpregs->regs[15]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[16] = fpregs->regs[16]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[17] = fpregs->regs[17]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[18] = fpregs->regs[18]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[19] = fpregs->regs[19]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[20] = fpregs->regs[20]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[21] = fpregs->regs[21]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[22] = fpregs->regs[22]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[23] = fpregs->regs[23]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[24] = fpregs->regs[24]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[25] = fpregs->regs[25]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[26] = fpregs->regs[26]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[27] = fpregs->regs[27]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[28] = fpregs->regs[28]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[29] = fpregs->regs[29]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[30] = fpregs->regs[30]; + sigframe->rs_uc.uc_mcontext.sc_fpregs[31] = fpregs->regs[31]; + + return 0; +} + +int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, + struct rt_sigframe *rsigframe) +{ + return 0; +} + +int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, + void *arg, __maybe_unused unsigned long flags) +{ + user_fpregs_struct_t xsave = { }, *xs = NULL; + int ret = -1; + + if (ptrace(PTRACE_GETFPREGS, pid, NULL, &xsave)) { + pr_perror("Can't obtain FPU registers for %d", pid); + return ret; + } + + /*Restart the system call*/ + if (regs->regs[0]){ + switch ((long)(int)regs->regs[2]) { + case ERESTARTNOHAND: + case ERESTARTSYS: + case ERESTARTNOINTR: + regs->regs[2] = regs->regs[0]; + regs->regs[7] = regs->regs[26]; + regs->cp0_epc -= 4; + break; + case ERESTART_RESTARTBLOCK: + regs->regs[2] = __NR_restart_syscall; + regs->regs[7] = regs->regs[26]; + regs->cp0_epc -= 4; + break; + } + regs->regs[0] = 0; + } + + xs = &xsave; + ret = save(arg, regs, xs); + return ret; +} + +int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5, + unsigned long arg6) +{ + /*refer to glibc-2.20/sysdeps/unix/sysv/linux/mips/mips64/syscall.S*/ + user_regs_struct_t regs = ctl->orig.regs; + int err; + + regs.regs[2] = (unsigned long)nr; //syscall_number will be in v0 + regs.regs[4] = arg1; + regs.regs[5] = arg2; + regs.regs[6] = arg3; + regs.regs[7] = arg4; + regs.regs[8] = arg5; + regs.regs[9] = arg6; + + err = compel_execute_syscall(ctl, ®s, code_syscall); + *ret = regs.regs[2]; + + return err; +} + +void *remote_mmap(struct parasite_ctl *ctl, + void *addr, size_t length, int prot, + int flags, int fd, off_t offset) +{ + long map; + int err; + + err = compel_syscall(ctl, __NR_mmap, &map, + (unsigned long)addr, length, prot, flags, fd, offset >> PAGE_SHIFT); + + if (err < 0 || IS_ERR_VALUE(map)) { + pr_err("remote mmap() failed: %s\n", strerror(-map)); + return NULL; + } + + return (void *)map; +} + +/* + * regs must be inited when calling this function from original context + */ +void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs) +{ + regs->cp0_epc = new_ip; + if (stack){ + /* regs[29] is sp */ + regs->regs[29] = (unsigned long)stack; + } +} + +bool arch_can_dump_task(struct parasite_ctl *ctl) +{ + return true; +} + +int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s) +{ + long ret; + int err; + + err = compel_syscall(ctl, __NR_sigaltstack, + &ret, 0, (unsigned long)&s->rs_uc.uc_stack, + 0, 0, 0, 0); + return err ? err : ret; +} + + +int ptrace_set_breakpoint(pid_t pid, void *addr) +{ + return 0; +} + +int ptrace_flush_breakpoints(pid_t pid) +{ + return 0; +} + +/*refer to kernel linux-3.10/arch/mips/include/asm/processor.h*/ +#define TASK_SIZE32 0x7fff8000UL +#define TASK_SIZE64 0x10000000000UL +#define TASK_SIZE TASK_SIZE64 + +unsigned long compel_task_size(void) { return TASK_SIZE; } + +/* + * Get task registers (overwrites weak function) + * + */ +int ptrace_get_regs(int pid, user_regs_struct_t *regs) +{ + return ptrace(PTRACE_GETREGS, pid, NULL, regs); +} + +/* + * Set task registers (overwrites weak function) + */ +int ptrace_set_regs(int pid, user_regs_struct_t *regs) +{ + return ptrace(PTRACE_SETREGS, pid, NULL, regs); +} + +void compel_relocs_apply_mips(void *mem, void *vbase, compel_reloc_t *elf_relocs, size_t nr_relocs) +{ + size_t i, j; + + /* + * mips rebasing :load time relocation + * parasite.built-in.o and restorer.built-in.o is ELF 64-bit LSB relocatable for mips. + * so we have to relocate some type for R_MIPS_26 R_MIPS_HIGHEST R_MIPS_HIGHER R_MIPS_HI16 and R_MIPS_LO16 in there. + * for mips64el .if toload/store data or jump instruct ,need to relocation R_TYPE + */ + for (i = 0, j = 0; i < nr_relocs; i++) { + if (elf_relocs[i].type & COMPEL_TYPE_MIPS_26) { + int *where = (mem + elf_relocs[i].offset); + *where = *where | ((elf_relocs[i].addend + ((unsigned long)vbase & 0x00fffffff) /*low 28 bit*/)>>2); + + } else if (elf_relocs[i].type & COMPEL_TYPE_MIPS_64) { + unsigned long *where = (mem + elf_relocs[i].offset); + *where = elf_relocs[i].addend + (unsigned long)vbase; + + } else if (elf_relocs[i].type & COMPEL_TYPE_MIPS_HI16) { + /* refer to binutils mips.cc */ + int *where = (mem + elf_relocs[i].offset); + int v_lo16 = (unsigned long)vbase &0x00ffff; + + if ((v_lo16+elf_relocs[i].value+elf_relocs[i].addend) >= 0x8000){ + *where = *where | ((((unsigned long)vbase>>16) &0xffff)+0x1); + } else { + *where = *where | ((((unsigned long)vbase>>16) &0xffff)); + } + + } else if (elf_relocs[i].type & COMPEL_TYPE_MIPS_LO16) { + int *where = (mem + elf_relocs[i].offset); + int v_lo16 = (unsigned long)vbase &0x00ffff; + *where = *where | ((v_lo16 + elf_relocs[i].addend) & 0xffff); + + } else if (elf_relocs[i].type & COMPEL_TYPE_MIPS_HIGHER) { + int *where = (mem + elf_relocs[i].offset); + *where = *where | ((( (unsigned long)vbase + (uint64_t) 0x80008000) >> 32) & 0xffff); + + } else if (elf_relocs[i].type & COMPEL_TYPE_MIPS_HIGHEST) { + int *where = (mem + elf_relocs[i].offset); + *where = *where | ((( (unsigned long)vbase + (uint64_t) 0x800080008000llu) >> 48) & 0xffff); + } else + BUG(); + } +} diff --git a/include/common/arch/mips/asm/atomic.h b/include/common/arch/mips/asm/atomic.h new file mode 100755 index 000000000..600e3a70f --- /dev/null +++ b/include/common/arch/mips/asm/atomic.h @@ -0,0 +1,148 @@ +#ifndef __CR_ATOMIC_H__ +#define __CR_ATOMIC_H__ + +#include +#include "common/compiler.h" +#include "common/arch/mips/asm/utils.h" +#include "common/arch/mips/asm/cmpxchg.h" + +/* + * atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. + */ +#define atomic_read(v) (*(volatile int *)&(v)->counter) + +/* + * atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +#define atomic_set(v, i) ((v)->counter = (i)) +/* + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v. + */ + +static __inline__ void atomic_add(int i, atomic_t * v) +{ + int temp; + + do { + __asm__ __volatile__( + " .set mips3 \n" + " ll %0, %1 # atomic_add \n" + " addu %0, %2 \n" + " sc %0, %1 \n" + " .set mips0 \n" + : "=&r" (temp), "+m" (v->counter) + : "Ir" (i)); + } while (unlikely(!temp)); +} + +/* + * atomic_sub - subtract the atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v. + */ +static __inline__ void atomic_sub(int i, atomic_t * v) +{ + int temp; + + do { + __asm__ __volatile__( + " .set mips3 \n" + " ll %0, %1 # atomic_sub \n" + " subu %0, %2 \n" + " sc %0, %1 \n" + " .set mips0 \n" + : "=&r" (temp), "+m" (v->counter) + : "Ir" (i)); + } while (unlikely(!temp)); +} + +/* + * Same as above, but return the result value + */ +static __inline__ int atomic_add_return(int i, atomic_t * v) +{ + int result; + + smp_mb__before_llsc(); + + + int temp; + + do { + __asm__ __volatile__( + " .set mips3 \n" + " ll %1, %2 # atomic_add_return \n" + " addu %0, %1, %3 \n" + " sc %0, %2 \n" + " .set mips0 \n" + : "=&r" (result), "=&r" (temp), "+m" (v->counter) + : "Ir" (i)); + } while (unlikely(!result)); + + result = temp + i; + + smp_llsc_mb(); + + return result; +} + +static __inline__ int atomic_sub_return(int i, atomic_t * v) +{ + int result; + + smp_mb__before_llsc(); + + int temp; + + do { + __asm__ __volatile__( + " .set mips3 \n" + " ll %1, %2 # atomic_sub_return \n" + " subu %0, %1, %3 \n" + " sc %0, %2 \n" + " .set mips0 \n" + : "=&r" (result), "=&r" (temp), "+m" (v->counter) + : "Ir" (i)); + } while (unlikely(!result)); + + result = temp - i; + + smp_llsc_mb(); + + return result; +} + +#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) +#define atomic_dec_return(v) atomic_sub_return(1, (v)) +#define atomic_inc_return(v) atomic_add_return(1, (v)) + +/* + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. + */ +#define atomic_inc( v) atomic_add(1, (v)) + +/* + * atomic_dec - decrement and test + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1. + */ +#define atomic_dec(v) atomic_sub(1, (v)) + +#endif /* __CR_ATOMIC_H__ */ diff --git a/include/common/arch/mips/asm/bitops.h b/include/common/arch/mips/asm/bitops.h new file mode 100644 index 000000000..874845e45 --- /dev/null +++ b/include/common/arch/mips/asm/bitops.h @@ -0,0 +1,41 @@ +#ifndef _LINUX_BITOPS_H +#define _LINUX_BITOPS_H +#include +#include "common/compiler.h" +#include "common/asm-generic/bitops.h" + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ + +static inline int test_and_set_bit(unsigned long nr, + volatile unsigned long *addr) +{ + unsigned long *m = ((unsigned long *) addr) + (nr >> 6); + unsigned long temp = 0; + unsigned long res; + int bit = nr & 63UL; + + do { + __asm__ __volatile__( + " .set mips3 \n" + " lld %0, %1 # test_and_set_bit \n" + " or %2, %0, %3 \n" + " scd %2, %1 \n" + " .set mips0 \n" + : "=&r" (temp), "+m" (*m), "=&r" (res) + : "r" (1UL << bit) + : "memory"); + } while (unlikely(!res)); + + res = temp & (1UL << bit); + + return res != 0; +} + +#endif diff --git a/include/common/arch/mips/asm/bitsperlong.h b/include/common/arch/mips/asm/bitsperlong.h new file mode 100755 index 000000000..31aece3b6 --- /dev/null +++ b/include/common/arch/mips/asm/bitsperlong.h @@ -0,0 +1,6 @@ +#ifndef __CR_BITSPERLONG_H__ +#define __CR_BITSPERLONG_H__ + +# define BITS_PER_LONG 64 + +#endif /* __CR_BITSPERLONG_H__ */ diff --git a/include/common/arch/mips/asm/cmpxchg.h b/include/common/arch/mips/asm/cmpxchg.h new file mode 100755 index 000000000..bdc41390b --- /dev/null +++ b/include/common/arch/mips/asm/cmpxchg.h @@ -0,0 +1,67 @@ +#ifndef __CR_CMPXCHG_H__ +#define __CR_CMPXCHG_H__ + +#define __cmpxchg_asm(ld, st, m, old, new) \ +({ \ + __typeof(*(m)) __ret; \ + \ + if (kernel_uses_llsc) { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " .set mips3 \n" \ + "1: " ld " %0, %2 # __cmpxchg_asm \n" \ + " bne %0, %z3, 2f \n" \ + " .set mips0 \n" \ + " move $1, %z4 \n" \ + " .set mips3 \n" \ + " " st " $1, %1 \n" \ + " beqz $1, 1b \n" \ + " .set pop \n" \ + "2: \n" \ + : "=&r" (__ret), "=R" (*m) \ + : "R" (*m), "Jr" (old), "Jr" (new) \ + : "memory"); \ + } else { \ + } \ + \ + __ret; \ +}) +/* + * This function doesn't exist, so you'll get a linker error + * if something tries to do an invalid cmpxchg(). + */ +extern void __cmpxchg_called_with_bad_pointer(void); + +#define __cmpxchg(ptr, old, new, pre_barrier, post_barrier) \ +({ \ + __typeof__(ptr) __ptr = (ptr); \ + __typeof__(*(ptr)) __old = (old); \ + __typeof__(*(ptr)) __new = (new); \ + __typeof__(*(ptr)) __res = 0; \ + \ + pre_barrier; \ + \ + switch (sizeof(*(__ptr))) { \ + case 4: \ + __res = __cmpxchg_asm("ll", "sc", __ptr, __old, __new); \ + break; \ + case 8: \ + if (sizeof(long) == 8) { \ + __res = __cmpxchg_asm("lld", "scd", __ptr, \ + __old, __new); \ + break; \ + } \ + default: \ + __cmpxchg_called_with_bad_pointer(); \ + break; \ + } \ + \ + post_barrier; \ + \ + __res; \ +}) + +#define cmpxchg(ptr, old, new) __cmpxchg(ptr, old, new, smp_mb__before_llsc(), smp_llsc_mb()) + +#endif /* __CR_CMPXCHG_H__ */ diff --git a/include/common/arch/mips/asm/fls64.h b/include/common/arch/mips/asm/fls64.h new file mode 100644 index 000000000..fdae28513 --- /dev/null +++ b/include/common/arch/mips/asm/fls64.h @@ -0,0 +1,38 @@ +#ifndef _ASM_GENERIC_BITOPS_FLS64_H_ +#define _ASM_GENERIC_BITOPS_FLS64_H_ + +#include + +/** + * fls64 - find last set bit in a 64-bit word + * @x: the word to search + * + * This is defined in a similar way as the libc and compiler builtin + * ffsll, but returns the position of the most significant set bit. + * + * fls64(value) returns 0 if value is 0 or the position of the last + * set bit if value is nonzero. The last (most significant) bit is + * at position 64. + */ +#include "common/arch/mips/asm/bitops.h" +#if BITS_PER_LONG == 32 +static __always_inline int fls64(__u64 x) +{ + __u32 h = x >> 32; + if (h) + return fls(h) + 32; + return fls(x); +} +#elif BITS_PER_LONG == 64 +extern unsigned long __fls(unsigned long word); +static __always_inline int fls64(__u64 x) +{ + if (x == 0) + return 0; + return __fls(x) + 1; +} +#else +#error BITS_PER_LONG not 32 or 64 +#endif + +#endif /* _ASM_GENERIC_BITOPS_FLS64_H_ */ diff --git a/include/common/arch/mips/asm/linkage.h b/include/common/arch/mips/asm/linkage.h new file mode 100644 index 000000000..8f2426889 --- /dev/null +++ b/include/common/arch/mips/asm/linkage.h @@ -0,0 +1,58 @@ +#ifndef __CR_LINKAGE_H__ +#define __CR_LINKAGE_H__ + +#define zero $0 /* wired zero */ +#define AT $1 /* assembler temp - uppercase because of ".set at" */ +#define v0 $2 +#define v1 $3 + +#define a0 $4 +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define a4 $8 +#define a5 $9 +#define a6 $10 +#define a7 $11 +#define t0 $12 +#define t1 $13 +#define t2 $14 +#define t3 $15 + +#define s0 $16 /* callee saved */ +#define s1 $17 +#define s2 $18 +#define s3 $19 +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +#define t8 $24 /* caller saved */ +#define t9 $25 +#define jp $25 /* PIC jump register */ +#define k0 $26 /* kernel scratch */ +#define k1 $27 +#define gp $28 /* global pointer */ +#define sp $29 /* stack pointer */ +#define fp $30 /* frame pointer */ +#define s8 $30 /* same like fp! */ +#define ra $31 /* return address */ + +#define __ALIGN .align 8 +#define __ALIGN_STR ".align 8" + +#define GLOBAL(name) \ + .globl name; \ + name: + +#define ENTRY(name) \ + .globl name; \ + __ALIGN; \ + .type name, @function; \ + name: + +#define END(sym) \ + .size sym, . - sym + + +#endif /* __CR_LINKAGE_H__ */ diff --git a/include/common/arch/mips/asm/page.h b/include/common/arch/mips/asm/page.h new file mode 100755 index 000000000..bf27420f7 --- /dev/null +++ b/include/common/arch/mips/asm/page.h @@ -0,0 +1,39 @@ +#ifndef __CR_ASM_PAGE_H__ +#define __CR_ASM_PAGE_H__ + +#define ARCH_HAS_LONG_PAGES + +#ifndef CR_NOGLIBC +#include /* ffsl() */ +#include /* _SC_PAGESIZE */ + +static unsigned __page_size; +static unsigned __page_shift; + +static inline unsigned page_size(void) +{ + if (!__page_size) + __page_size = sysconf(_SC_PAGESIZE); + return __page_size; +} + +static inline unsigned page_shift(void) +{ + if (!__page_shift) + __page_shift = (ffsl(page_size()) - 1); + return __page_shift; +} + +#define PAGE_SIZE page_size() +#define PAGE_SHIFT page_shift() +#define PAGE_MASK (~(PAGE_SIZE - 1)) + +#define PAGE_PFN(addr) ((addr) / PAGE_SIZE) +#else /* CR_NOGLIBC */ + +extern unsigned page_size(void); +#define PAGE_SIZE page_size() + +#endif /* CR_NOGLIBC */ + +#endif /* __CR_ASM_PAGE_H__ */ diff --git a/include/common/arch/mips/asm/utils.h b/include/common/arch/mips/asm/utils.h new file mode 100644 index 000000000..6415bf485 --- /dev/null +++ b/include/common/arch/mips/asm/utils.h @@ -0,0 +1,24 @@ +#ifndef __UTILS_H__ +#define __UTILS_H__ + + +# define kernel_uses_llsc 1 + +typedef struct { + int counter; +}atomic_t; + + +/* + * FIXME: detect with compel_cpu_has_feature() if LL/SC implicitly + * provide a memory barrier. +*/ +#define __WEAK_LLSC_MB " sync \n" + +#define smp_llsc_mb() __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory") + +#define smp_mb__before_llsc() smp_llsc_mb() +#define smp_mb__before_atomic() smp_mb__before_llsc() +#define smp_mb__after_atomic() smp_llsc_mb() + +#endif /* __UTILS_H__ */ From e7d13b368db95c57d0a20ea016d6b0517e19d3b8 Mon Sep 17 00:00:00 2001 From: Guoyun Sun Date: Wed, 8 Apr 2020 10:21:11 +0800 Subject: [PATCH 2398/4375] mips:compel: Enable mips in compel/ Signed-off-by: Guoyun Sun --- compel/include/uapi/handle-elf.h | 9 ++++- compel/include/uapi/infect.h | 1 + compel/plugins/Makefile | 14 +++++++ compel/src/lib/handle-elf.c | 65 +++++++++++++++++++++++++++++++- compel/src/lib/infect.c | 5 ++- compel/src/main.c | 3 ++ 6 files changed, 93 insertions(+), 4 deletions(-) diff --git a/compel/include/uapi/handle-elf.h b/compel/include/uapi/handle-elf.h index ddeecb0d5..ba40be57f 100644 --- a/compel/include/uapi/handle-elf.h +++ b/compel/include/uapi/handle-elf.h @@ -4,7 +4,14 @@ #define COMPEL_TYPE_INT (1u << 0) #define COMPEL_TYPE_LONG (1u << 1) #define COMPEL_TYPE_GOTPCREL (1u << 2) - +#ifdef CONFIG_MIPS +#define COMPEL_TYPE_MIPS_26 (1u << 3) +#define COMPEL_TYPE_MIPS_HI16 (1u << 4) +#define COMPEL_TYPE_MIPS_LO16 (1u << 5) +#define COMPEL_TYPE_MIPS_HIGHER (1u << 6) +#define COMPEL_TYPE_MIPS_HIGHEST (1u << 7) +#define COMPEL_TYPE_MIPS_64 (1u << 8) +#endif typedef struct { unsigned int offset; unsigned int type; diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index dd672bc1c..4f14c7270 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -165,6 +165,7 @@ extern struct parasite_blob_desc *compel_parasite_blob_desc(struct parasite_ctl extern int __must_check compel_get_thread_regs(struct parasite_thread_ctl *, save_regs_t, void *); extern void compel_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *elf_relocs, size_t nr_relocs); +extern void compel_relocs_apply_mips(void *mem, void *vbase, compel_reloc_t *elf_relocs, size_t nr_relocs); extern unsigned long compel_task_size(void); diff --git a/compel/plugins/Makefile b/compel/plugins/Makefile index 197ff1b24..e5fa781ac 100644 --- a/compel/plugins/Makefile +++ b/compel/plugins/Makefile @@ -16,7 +16,12 @@ asflags-y += -I compel/include/uapi # General compel includes ccflags-y += -iquote compel/include + +ifeq ($(ARCH),mips) +ccflags-y += -mno-abicalls -fno-pic -fno-stack-protector +else ccflags-y += -fpie -fno-stack-protector +endif # General compel/plugins includes ccflags-y += -iquote $(obj)/include @@ -28,7 +33,12 @@ asflags-y += -iquote $(PLUGIN_ARCH_DIR)/include asflags-y += -iquote $(PLUGIN_ARCH_DIR) # General flags for assembly +ifeq ($(ARCH),mips) +asflags-y += -mno-abicalls -fno-pic -Wstrict-prototypes +else asflags-y += -fpie -Wstrict-prototypes +endif + asflags-y += -nostdlib -fomit-frame-pointer asflags-y += -fno-stack-protector ldflags-y += -z noexecstack @@ -57,6 +67,10 @@ ifeq ($(ARCH),x86) std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/memcpy.o endif +ifeq ($(ARCH),mips) + std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/memcpy.o +endif + ifeq ($(ARCH),ppc64) std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/memcpy.o std-lib-y += ./$(PLUGIN_ARCH_DIR)/std/memcmp.o diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index 69d5104b6..e97d75026 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -16,8 +16,9 @@ #include "piegen.h" #include "log.h" -piegen_opt_t opts = {}; - +#ifdef CONFIG_MIPS +#include "ldsodefs.h" +#endif /* Check if pointer is out-of-bound */ static bool __ptr_oob(const uintptr_t ptr, const uintptr_t start, const size_t size) { @@ -403,6 +404,66 @@ int __handle_elf(void *mem, size_t size) #endif switch (ELF_R_TYPE(r->rel.r_info)) { +#ifdef CONFIG_MIPS + case R_MIPS_PC16: + /* s+a-p relative */ + *((int32_t *)where) = *((int32_t *)where) | ((value32 + addend32 - place)>>2); + break; + + case R_MIPS_26: + /* local : (((A << 2) | (P & 0xf0000000) + S) >> 2 + * external : (sign–extend(A < 2) + S) >> 2 + */ + + if (((unsigned)ELF_ST_BIND(sym->st_info) == 0x1) + || ((unsigned)ELF_ST_BIND(sym->st_info) == 0x2)){ + /* bind type local is 0x0 ,global is 0x1,WEAK is 0x2 */ + addend32 = value32; + } + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_MIPS_26, " + ".addend = %-8d, .value = 0x%-16x, }, /* R_MIPS_26 */\n", + (unsigned int)place, addend32, value32); + break; + + case R_MIPS_32: + /* S+A */ + break; + + case R_MIPS_64: + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_MIPS_64, " + ".addend = %-8ld, .value = 0x%-16lx, }, /* R_MIPS_64 */\n", + (unsigned int)place, (long)addend64, (long)value64); + break; + + case R_MIPS_HIGHEST: + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_MIPS_HIGHEST, " + ".addend = %-8d, .value = 0x%-16x, }, /* R_MIPS_HIGHEST */\n", + (unsigned int)place, addend32, value32); + break; + + case R_MIPS_HIGHER: + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_MIPS_HIGHER, " + ".addend = %-8d, .value = 0x%-16x, }, /* R_MIPS_HIGHER */\n", + (unsigned int)place, addend32, value32); + break; + + case R_MIPS_HI16: + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_MIPS_HI16, " + ".addend = %-8d, .value = 0x%-16x, }, /* R_MIPS_HI16 */\n", + (unsigned int)place, addend32, value32); + break; + + case R_MIPS_LO16: + if((unsigned)ELF_ST_BIND(sym->st_info) == 0x1){ + /* bind type local is 0x0 ,global is 0x1 */ + addend32 = value32; + } + pr_out(" { .offset = 0x%-8x, .type = COMPEL_TYPE_MIPS_LO16, " + ".addend = %-8d, .value = 0x%-16x, }, /* R_MIPS_LO16 */\n", + (unsigned int)place, addend32, value32); + break; + +#endif #ifdef ELF_PPC64 case R_PPC64_REL24: /* Update PC relative offset, linker has not done this yet */ diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 3fad85ed3..296ffcbd0 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -817,7 +817,9 @@ err_cure: void compel_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *elf_relocs, size_t nr_relocs) { size_t i, j; - +#ifdef CONFIG_MIPS + compel_relocs_apply_mips(mem, vbase, elf_relocs, nr_relocs); +#else for (i = 0, j = 0; i < nr_relocs; i++) { if (elf_relocs[i].type & COMPEL_TYPE_LONG) { long *where = mem + elf_relocs[i].offset; @@ -840,6 +842,7 @@ void compel_relocs_apply(void *mem, void *vbase, size_t size, compel_reloc_t *el } else BUG(); } +#endif } static int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size) diff --git a/compel/src/main.c b/compel/src/main.c index 9fc3a924c..c5f6e57ed 100644 --- a/compel/src/main.c +++ b/compel/src/main.c @@ -53,11 +53,14 @@ static const flags_t flags = { #elif defined CONFIG_S390 .arch = "s390", .cflags = COMPEL_CFLAGS_PIE, +#elif defined CONFIG_MIPS + .arch = "mips", #else #error "CONFIG_ not defined, or unsupported ARCH" #endif }; +piegen_opt_t opts = {}; const char *uninst_root; static int piegen(void) From 158e8f8fe637117f00bb6ecbad84d6491970d84d Mon Sep 17 00:00:00 2001 From: Guoyun Sun Date: Wed, 8 Apr 2020 10:23:16 +0800 Subject: [PATCH 2399/4375] mips:proto: Add mips to protocol buffer files Signed-off-by: Guoyun Sun --- images/Makefile | 1 + images/core-mips.proto | 90 ++++++++++++++++++++++++++++++++++++++++++ images/core.proto | 5 +++ images/sa.proto | 1 + 4 files changed, 97 insertions(+) create mode 100755 images/core-mips.proto diff --git a/images/Makefile b/images/Makefile index bc67278e6..5458e4679 100644 --- a/images/Makefile +++ b/images/Makefile @@ -1,6 +1,7 @@ proto-obj-y += stats.o proto-obj-y += core.o proto-obj-y += core-x86.o +proto-obj-y += core-mips.o proto-obj-y += core-arm.o proto-obj-y += core-aarch64.o proto-obj-y += core-ppc64.o diff --git a/images/core-mips.proto b/images/core-mips.proto new file mode 100755 index 000000000..6391b1e86 --- /dev/null +++ b/images/core-mips.proto @@ -0,0 +1,90 @@ +syntax = "proto2"; + +import "opts.proto"; + +message user_mips_regs_entry { + required uint64 r0 = 1; + required uint64 r1 = 2; + required uint64 r2 = 3; + required uint64 r3 = 4; + required uint64 r4 = 5; + required uint64 r5 = 6; + required uint64 r6 = 7; + required uint64 r7 = 8; + required uint64 r8 = 9; + required uint64 r9 = 10; + required uint64 r10 = 11; + required uint64 r11 = 12; + required uint64 r12 = 13; + required uint64 r13 = 14; + required uint64 r14 = 15; + required uint64 r15 = 16; + required uint64 r16 = 17; + required uint64 r17 = 18; + required uint64 r18 = 19; + required uint64 r19 = 20; + required uint64 r20 = 21; + required uint64 r21 = 22; + required uint64 r22 = 23; + required uint64 r23 = 24; + required uint64 r24 = 25; + required uint64 r25 = 26; + required uint64 r26 = 27; + required uint64 r27 = 28; + required uint64 r28 = 29; + required uint64 r29 = 30; + required uint64 r30 = 31; + required uint64 r31 = 32; + required uint64 lo = 33; + required uint64 hi = 34; + required uint64 cp0_epc = 35; + required uint64 cp0_badvaddr = 36; + required uint64 cp0_status = 37; + required uint64 cp0_cause = 38; +} + +message user_mips_fpregs_entry { + required uint64 r0 = 1; + required uint64 r1 = 2; + required uint64 r2 = 3; + required uint64 r3 = 4; + required uint64 r4 = 5; + required uint64 r5 = 6; + required uint64 r6 = 7; + required uint64 r7 = 8; + required uint64 r8 = 9; + required uint64 r9 = 10; + required uint64 r10 = 11; + required uint64 r11 = 12; + required uint64 r12 = 13; + required uint64 r13 = 14; + required uint64 r14 = 15; + required uint64 r15 = 16; + required uint64 r16 = 17; + required uint64 r17 = 18; + required uint64 r18 = 19; + required uint64 r19 = 20; + required uint64 r20 = 21; + required uint64 r21 = 22; + required uint64 r22 = 23; + required uint64 r23 = 24; + required uint64 r24 = 25; + required uint64 r25 = 26; + required uint64 r26 = 27; + required uint64 r27 = 28; + required uint64 r28 = 29; + required uint64 r29 = 30; + required uint64 r30 = 31; + required uint64 r31 = 32; + required uint64 lo = 33; + required uint64 hi = 34; + required uint32 fpu_fcr31 = 35; + required uint32 fpu_id = 36; +} + +message thread_info_mips { + required uint64 clear_tid_addr = 1[(criu).hex = true]; + required uint64 tls = 2; + required user_mips_regs_entry gpregs = 3[(criu).hex = true]; + required user_mips_fpregs_entry fpregs = 4[(criu).hex = true]; +} diff --git a/images/core.proto b/images/core.proto index 22c2a9f1f..9e9e39388 100644 --- a/images/core.proto +++ b/images/core.proto @@ -5,6 +5,7 @@ import "core-arm.proto"; import "core-aarch64.proto"; import "core-ppc64.proto"; import "core-s390.proto"; +import "core-mips.proto"; import "rlimit.proto"; import "timer.proto"; @@ -55,6 +56,7 @@ message task_core_entry { optional bool child_subreaper = 18; // Reserved for container relative start time //optional uint64 start_time = 19; + optional uint64 blk_sigset_extended = 20[(criu).hex = true]; } message task_kobj_ids_entry { @@ -96,6 +98,7 @@ message thread_core_entry { optional uint32 seccomp_filter = 12; optional string comm = 13; + optional uint64 blk_sigset_extended = 14; } message task_rlimits_entry { @@ -110,6 +113,7 @@ message core_entry { AARCH64 = 3; PPC64 = 4; S390 = 5; + MIPS = 6; } required march mtype = 1; @@ -118,6 +122,7 @@ message core_entry { optional thread_info_aarch64 ti_aarch64 = 8; optional thread_info_ppc64 ti_ppc64 = 9; optional thread_info_s390 ti_s390 = 10; + optional thread_info_mips ti_mips = 11; optional task_core_entry tc = 3; optional task_kobj_ids_entry ids = 4; diff --git a/images/sa.proto b/images/sa.proto index 3bce0c4ff..07fd4ffd3 100644 --- a/images/sa.proto +++ b/images/sa.proto @@ -8,4 +8,5 @@ message sa_entry { required uint64 restorer = 3 [(criu).hex = true]; required uint64 mask = 4 [(criu).hex = true]; optional bool compat_sigaction = 5; + optional uint64 mask_extended = 6 [(criu).hex = true]; } From d325b7b775cd2e51651c00137be0df5bd3d2d74f Mon Sep 17 00:00:00 2001 From: Guoyun Sun Date: Wed, 8 Apr 2020 10:24:45 +0800 Subject: [PATCH 2400/4375] mips:criu/arch/mips: Add mips parts to criu Signed-off-by: Guoyun Sun --- criu/arch/mips/Makefile | 14 + criu/arch/mips/cpu.c | 53 ++++ criu/arch/mips/crtools.c | 252 ++++++++++++++++++ criu/arch/mips/include/asm/dump.h | 14 + criu/arch/mips/include/asm/int.h | 6 + criu/arch/mips/include/asm/kerndat.h | 7 + criu/arch/mips/include/asm/parasite-syscall.h | 8 + criu/arch/mips/include/asm/parasite.h | 9 + criu/arch/mips/include/asm/restore.h | 29 ++ criu/arch/mips/include/asm/restorer.h | 79 ++++++ criu/arch/mips/include/asm/syscall32.h | 17 ++ criu/arch/mips/include/asm/types.h | 31 +++ criu/arch/mips/include/asm/vdso.h | 23 ++ criu/arch/mips/restorer.c | 17 ++ criu/arch/mips/sigaction_compat.c | 19 ++ criu/arch/mips/sigframe.c | 13 + criu/arch/mips/vdso-pie.c | 21 ++ 17 files changed, 612 insertions(+) create mode 100755 criu/arch/mips/Makefile create mode 100755 criu/arch/mips/cpu.c create mode 100755 criu/arch/mips/crtools.c create mode 100755 criu/arch/mips/include/asm/dump.h create mode 100755 criu/arch/mips/include/asm/int.h create mode 100644 criu/arch/mips/include/asm/kerndat.h create mode 100755 criu/arch/mips/include/asm/parasite-syscall.h create mode 100755 criu/arch/mips/include/asm/parasite.h create mode 100755 criu/arch/mips/include/asm/restore.h create mode 100755 criu/arch/mips/include/asm/restorer.h create mode 100755 criu/arch/mips/include/asm/syscall32.h create mode 100755 criu/arch/mips/include/asm/types.h create mode 100755 criu/arch/mips/include/asm/vdso.h create mode 100755 criu/arch/mips/restorer.c create mode 100755 criu/arch/mips/sigaction_compat.c create mode 100755 criu/arch/mips/sigframe.c create mode 100755 criu/arch/mips/vdso-pie.c diff --git a/criu/arch/mips/Makefile b/criu/arch/mips/Makefile new file mode 100755 index 000000000..4bd99eb7e --- /dev/null +++ b/criu/arch/mips/Makefile @@ -0,0 +1,14 @@ +builtin-name := crtools.built-in.o + +ccflags-y += -iquote $(obj)/include +ccflags-y += -iquote criu/include -iquote include +ccflags-y += $(COMPEL_UAPI_INCLUDES) + +asflags-y += -Wstrict-prototypes +asflags-y += -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer +asflags-y += -iquote $(obj)/include +ldflags-y += -r -z noexecstack + +obj-y += cpu.o +obj-y += crtools.o +obj-y += sigframe.o diff --git a/criu/arch/mips/cpu.c b/criu/arch/mips/cpu.c new file mode 100755 index 000000000..484698e4f --- /dev/null +++ b/criu/arch/mips/cpu.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include + +#include "bitops.h" +#include "asm/types.h" +#include "asm/cpu.h" +#include +#include + +#include "common/compiler.h" +#include "cr_options.h" +#include "image.h" +#include "util.h" +#include "log.h" +#include "cpu.h" +#include "protobuf.h" +#include "images/cpuinfo.pb-c.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "cpu: " + +int cpu_init(void) +{ + return 0; +} + +int cpu_dump_cpuinfo(void) +{ + return 0; +} + +int cpu_validate_cpuinfo(void) +{ + return 0; +} + +int cpuinfo_dump(void) +{ + if (cpu_init()) + return -1; + if (cpu_dump_cpuinfo()) + return -1; + return 0; +} + +int cpuinfo_check(void) +{ + return 0; +} diff --git a/criu/arch/mips/crtools.c b/criu/arch/mips/crtools.c new file mode 100755 index 000000000..329ae8edb --- /dev/null +++ b/criu/arch/mips/crtools.c @@ -0,0 +1,252 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "log.h" +#include "asm/parasite-syscall.h" +#include "asm/restorer.h" +#include +#include "asm/dump.h" +#include "cr_options.h" +#include "common/compiler.h" +#include "restorer.h" +#include "parasite-syscall.h" +#include "util.h" +#include "cpu.h" +#include +#include "kerndat.h" + +#include "protobuf.h" +#include "images/core.pb-c.h" +#include "images/creds.pb-c.h" + + +int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) +{ + CoreEntry *core = x; + + /* Save the MIPS CPU state */ + core->ti_mips->gpregs->r0 = regs->regs[0]; + core->ti_mips->gpregs->r1 = regs->regs[1]; + core->ti_mips->gpregs->r2 = regs->regs[2]; + core->ti_mips->gpregs->r3 = regs->regs[3]; + core->ti_mips->gpregs->r4 = regs->regs[4]; + core->ti_mips->gpregs->r5 = regs->regs[5]; + core->ti_mips->gpregs->r6 = regs->regs[6]; + core->ti_mips->gpregs->r7 = regs->regs[7]; + core->ti_mips->gpregs->r8 = regs->regs[8]; + core->ti_mips->gpregs->r9 = regs->regs[9]; + core->ti_mips->gpregs->r10 = regs->regs[10]; + core->ti_mips->gpregs->r11 = regs->regs[11]; + core->ti_mips->gpregs->r12 = regs->regs[12]; + core->ti_mips->gpregs->r13 = regs->regs[13]; + core->ti_mips->gpregs->r14 = regs->regs[14]; + core->ti_mips->gpregs->r15 = regs->regs[15]; + core->ti_mips->gpregs->r16 = regs->regs[16]; + core->ti_mips->gpregs->r17 = regs->regs[17]; + core->ti_mips->gpregs->r18 = regs->regs[18]; + core->ti_mips->gpregs->r19 = regs->regs[19]; + core->ti_mips->gpregs->r20 = regs->regs[20]; + core->ti_mips->gpregs->r21 = regs->regs[21]; + core->ti_mips->gpregs->r22 = regs->regs[22]; + core->ti_mips->gpregs->r23 = regs->regs[23]; + core->ti_mips->gpregs->r24 = regs->regs[24]; + core->ti_mips->gpregs->r25 = regs->regs[25]; + core->ti_mips->gpregs->r26 = regs->regs[26]; + core->ti_mips->gpregs->r27 = regs->regs[27]; + core->ti_mips->gpregs->r28 = regs->regs[28]; + core->ti_mips->gpregs->r29 = regs->regs[29]; + core->ti_mips->gpregs->r30 = regs->regs[30]; + core->ti_mips->gpregs->r31 = regs->regs[31]; + + core->ti_mips->gpregs->lo = regs->lo; + core->ti_mips->gpregs->hi = regs->hi; + core->ti_mips->gpregs->cp0_epc = regs->cp0_epc; + core->ti_mips->gpregs->cp0_badvaddr = regs->cp0_badvaddr; + core->ti_mips->gpregs->cp0_status = regs->cp0_status; + core->ti_mips->gpregs->cp0_cause = regs->cp0_cause; + + core->ti_mips->fpregs->r0 = fpregs->regs[0]; + core->ti_mips->fpregs->r1 = fpregs->regs[1]; + core->ti_mips->fpregs->r2 = fpregs->regs[2]; + core->ti_mips->fpregs->r3 = fpregs->regs[3]; + core->ti_mips->fpregs->r4 = fpregs->regs[4]; + core->ti_mips->fpregs->r5 = fpregs->regs[5]; + core->ti_mips->fpregs->r6 = fpregs->regs[6]; + core->ti_mips->fpregs->r7 = fpregs->regs[7]; + core->ti_mips->fpregs->r8 = fpregs->regs[8]; + core->ti_mips->fpregs->r9 = fpregs->regs[9]; + core->ti_mips->fpregs->r10 = fpregs->regs[10]; + core->ti_mips->fpregs->r11 = fpregs->regs[11]; + core->ti_mips->fpregs->r12 = fpregs->regs[12]; + core->ti_mips->fpregs->r13 = fpregs->regs[13]; + core->ti_mips->fpregs->r14 = fpregs->regs[14]; + core->ti_mips->fpregs->r15 = fpregs->regs[15]; + core->ti_mips->fpregs->r16 = fpregs->regs[16]; + core->ti_mips->fpregs->r17 = fpregs->regs[17]; + core->ti_mips->fpregs->r18 = fpregs->regs[18]; + core->ti_mips->fpregs->r19 = fpregs->regs[19]; + core->ti_mips->fpregs->r20 = fpregs->regs[20]; + core->ti_mips->fpregs->r21 = fpregs->regs[21]; + core->ti_mips->fpregs->r22 = fpregs->regs[22]; + core->ti_mips->fpregs->r23 = fpregs->regs[23]; + core->ti_mips->fpregs->r24 = fpregs->regs[24]; + core->ti_mips->fpregs->r25 = fpregs->regs[25]; + core->ti_mips->fpregs->r26 = fpregs->regs[26]; + core->ti_mips->fpregs->r27 = fpregs->regs[27]; + core->ti_mips->fpregs->r28 = fpregs->regs[28]; + core->ti_mips->fpregs->r29 = fpregs->regs[29]; + core->ti_mips->fpregs->r30 = fpregs->regs[30]; + core->ti_mips->fpregs->r31 = fpregs->regs[31]; + core->ti_mips->fpregs->fpu_fcr31 = fpregs->fpu_fcr31; + core->ti_mips->fpregs->fpu_id = fpregs->fpu_id; + + return 0; +} + +int arch_alloc_thread_info(CoreEntry *core) +{ + ThreadInfoMips *ti_mips; + UserMipsRegsEntry *gpregs; + UserMipsFpregsEntry *fpregs; + + ti_mips = xmalloc(sizeof(*ti_mips)); + if (!ti_mips) + goto err; + + thread_info_mips__init(ti_mips); + core->ti_mips = ti_mips; + + gpregs = xmalloc(sizeof(*gpregs)); + if (!gpregs){ + xfree(ti_mips); + goto err; + } + + user_mips_regs_entry__init(gpregs); + ti_mips->gpregs = gpregs; + + fpregs = xmalloc(sizeof(*fpregs)); + if (!fpregs){ + xfree(ti_mips); + xfree(gpregs); + goto err; + } + + user_mips_fpregs_entry__init(fpregs); + ti_mips->fpregs = fpregs; + + return 0; +err: + return -1; +} + +void arch_free_thread_info(CoreEntry *core) +{ + if (!core->ti_mips) + return; + + if (core->ti_mips->gpregs) + xfree(core->ti_mips->gpregs); + + if (core->ti_mips->fpregs) + xfree(core->ti_mips->fpregs); + + xfree(core->ti_mips); +} + +int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) +{ + struct rt_sigframe *f = sigframe; + UserMipsFpregsEntry *r = core->ti_mips->fpregs; + + f->rs_uc.uc_mcontext.sc_fpregs[0] = r->r0; + f->rs_uc.uc_mcontext.sc_fpregs[1] = r->r1; + f->rs_uc.uc_mcontext.sc_fpregs[2] = r->r2; + f->rs_uc.uc_mcontext.sc_fpregs[3] = r->r3; + f->rs_uc.uc_mcontext.sc_fpregs[4] = r->r4; + f->rs_uc.uc_mcontext.sc_fpregs[5] = r->r5; + f->rs_uc.uc_mcontext.sc_fpregs[6] = r->r6; + f->rs_uc.uc_mcontext.sc_fpregs[7] = r->r7; + f->rs_uc.uc_mcontext.sc_fpregs[8] = r->r8; + f->rs_uc.uc_mcontext.sc_fpregs[9] = r->r9; + f->rs_uc.uc_mcontext.sc_fpregs[10] = r->r10; + f->rs_uc.uc_mcontext.sc_fpregs[11] = r->r11; + f->rs_uc.uc_mcontext.sc_fpregs[12] = r->r12; + f->rs_uc.uc_mcontext.sc_fpregs[13] = r->r13; + f->rs_uc.uc_mcontext.sc_fpregs[14] = r->r14; + f->rs_uc.uc_mcontext.sc_fpregs[15] = r->r15; + f->rs_uc.uc_mcontext.sc_fpregs[16] = r->r16; + f->rs_uc.uc_mcontext.sc_fpregs[17] = r->r17; + f->rs_uc.uc_mcontext.sc_fpregs[18] = r->r18; + f->rs_uc.uc_mcontext.sc_fpregs[19] = r->r19; + f->rs_uc.uc_mcontext.sc_fpregs[20] = r->r20; + f->rs_uc.uc_mcontext.sc_fpregs[21] = r->r21; + f->rs_uc.uc_mcontext.sc_fpregs[22] = r->r22; + f->rs_uc.uc_mcontext.sc_fpregs[23] = r->r23; + f->rs_uc.uc_mcontext.sc_fpregs[24] = r->r24; + f->rs_uc.uc_mcontext.sc_fpregs[25] = r->r25; + f->rs_uc.uc_mcontext.sc_fpregs[26] = r->r26; + f->rs_uc.uc_mcontext.sc_fpregs[27] = r->r27; + f->rs_uc.uc_mcontext.sc_fpregs[28] = r->r28; + f->rs_uc.uc_mcontext.sc_fpregs[29] = r->r29; + f->rs_uc.uc_mcontext.sc_fpregs[30] = r->r30; + f->rs_uc.uc_mcontext.sc_fpregs[31] = r->r31; + + return 0; +} + + +int restore_gpregs(struct rt_sigframe *f, UserMipsRegsEntry *r) +{ + f->rs_uc.uc_mcontext.sc_regs[0] = r->r0; + f->rs_uc.uc_mcontext.sc_regs[1] = r->r1; + f->rs_uc.uc_mcontext.sc_regs[2] = r->r2; + f->rs_uc.uc_mcontext.sc_regs[3] = r->r3; + f->rs_uc.uc_mcontext.sc_regs[4] = r->r4; + f->rs_uc.uc_mcontext.sc_regs[5] = r->r5; + f->rs_uc.uc_mcontext.sc_regs[6] = r->r6; + f->rs_uc.uc_mcontext.sc_regs[7] = r->r7; + f->rs_uc.uc_mcontext.sc_regs[8] = r->r8; + f->rs_uc.uc_mcontext.sc_regs[9] = r->r9; + f->rs_uc.uc_mcontext.sc_regs[10] = r->r10; + f->rs_uc.uc_mcontext.sc_regs[11] = r->r11; + f->rs_uc.uc_mcontext.sc_regs[12] = r->r12; + f->rs_uc.uc_mcontext.sc_regs[13] = r->r13; + f->rs_uc.uc_mcontext.sc_regs[14] = r->r14; + f->rs_uc.uc_mcontext.sc_regs[15] = r->r15; + f->rs_uc.uc_mcontext.sc_regs[16] = r->r16; + f->rs_uc.uc_mcontext.sc_regs[17] = r->r17; + f->rs_uc.uc_mcontext.sc_regs[18] = r->r18; + f->rs_uc.uc_mcontext.sc_regs[19] = r->r19; + f->rs_uc.uc_mcontext.sc_regs[20] = r->r20; + f->rs_uc.uc_mcontext.sc_regs[21] = r->r21; + f->rs_uc.uc_mcontext.sc_regs[22] = r->r22; + f->rs_uc.uc_mcontext.sc_regs[23] = r->r23; + f->rs_uc.uc_mcontext.sc_regs[24] = r->r24; + f->rs_uc.uc_mcontext.sc_regs[25] = r->r25; + f->rs_uc.uc_mcontext.sc_regs[26] = r->r26; + f->rs_uc.uc_mcontext.sc_regs[27] = r->r27; + f->rs_uc.uc_mcontext.sc_regs[28] = r->r28; + f->rs_uc.uc_mcontext.sc_regs[29] = r->r29; + f->rs_uc.uc_mcontext.sc_regs[30] = r->r30; + f->rs_uc.uc_mcontext.sc_regs[31] = r->r31; + + f->rs_uc.uc_mcontext.sc_mdlo = r->lo; + f->rs_uc.uc_mcontext.sc_mdhi = r->hi; + f->rs_uc.uc_mcontext.sc_pc = r->cp0_epc; + + return 0; +} + +int get_task_futex_robust_list_compat(pid_t pid, ThreadCoreEntry *info) +{ + return 0; +} diff --git a/criu/arch/mips/include/asm/dump.h b/criu/arch/mips/include/asm/dump.h new file mode 100755 index 000000000..58015833d --- /dev/null +++ b/criu/arch/mips/include/asm/dump.h @@ -0,0 +1,14 @@ +#ifndef __CR_ASM_DUMP_H__ +#define __CR_ASM_DUMP_H__ + +extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *); +extern int arch_alloc_thread_info(CoreEntry *core); +extern void arch_free_thread_info(CoreEntry *core); +extern int get_task_futex_robust_list_compat(pid_t pid, ThreadCoreEntry *info); + +static inline void core_put_tls(CoreEntry *core, tls_t tls) +{ + core->ti_mips->tls = tls; +} + +#endif diff --git a/criu/arch/mips/include/asm/int.h b/criu/arch/mips/include/asm/int.h new file mode 100755 index 000000000..642804e9b --- /dev/null +++ b/criu/arch/mips/include/asm/int.h @@ -0,0 +1,6 @@ +#ifndef __CR_ASM_INT_H__ +#define __CR_ASM_INT_H__ + +#include "asm-generic/int.h" + +#endif /* __CR_ASM_INT_H__ */ diff --git a/criu/arch/mips/include/asm/kerndat.h b/criu/arch/mips/include/asm/kerndat.h new file mode 100644 index 000000000..60956b573 --- /dev/null +++ b/criu/arch/mips/include/asm/kerndat.h @@ -0,0 +1,7 @@ +#ifndef __CR_ASM_KERNDAT_H__ +#define __CR_ASM_KERNDAT_H__ + +#define kdat_compatible_cr() 0 +#define kdat_can_map_vdso() 0 + +#endif /* __CR_ASM_KERNDAT_H__ */ diff --git a/criu/arch/mips/include/asm/parasite-syscall.h b/criu/arch/mips/include/asm/parasite-syscall.h new file mode 100755 index 000000000..a2b5e75ff --- /dev/null +++ b/criu/arch/mips/include/asm/parasite-syscall.h @@ -0,0 +1,8 @@ +#ifndef __CR_ASM_PARASITE_SYSCALL_H__ +#define __CR_ASM_PARASITE_SYSCALL_H__ + +#include "asm/types.h" + +struct parasite_ctl; + +#endif diff --git a/criu/arch/mips/include/asm/parasite.h b/criu/arch/mips/include/asm/parasite.h new file mode 100755 index 000000000..39882dd21 --- /dev/null +++ b/criu/arch/mips/include/asm/parasite.h @@ -0,0 +1,9 @@ +#ifndef __ASM_PARASITE_H__ +#define __ASM_PARASITE_H__ + +static inline void arch_get_tls(tls_t *ptls) +{ + asm("rdhwr %0, $29" : "=r"(*ptls)); +} + +#endif diff --git a/criu/arch/mips/include/asm/restore.h b/criu/arch/mips/include/asm/restore.h new file mode 100755 index 000000000..0cb9aa8ed --- /dev/null +++ b/criu/arch/mips/include/asm/restore.h @@ -0,0 +1,29 @@ +#ifndef __CR_ASM_RESTORE_H__ +#define __CR_ASM_RESTORE_H__ + +#include "asm/restorer.h" +#include "images/core.pb-c.h" + +#define JUMP_TO_RESTORER_BLOB(new_sp, restore_task_exec_start, \ + task_args) \ + asm volatile( \ + "move $4, %0 \n" \ + "move $25, %1 \n" \ + "move $5, %2 \n" \ + "move $29, $5 \n" \ + "jalr $25 \n" \ + "nop \n" \ + : \ + :"r"(task_args),"r"(restore_task_exec_start), \ + "g"(new_sp) \ + : "$29", "$25", "$4","$5") + +static inline void core_get_tls(CoreEntry *pcore, tls_t *ptls) +{ + *ptls = pcore->ti_mips->tls; +} + + +int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core); + +#endif diff --git a/criu/arch/mips/include/asm/restorer.h b/criu/arch/mips/include/asm/restorer.h new file mode 100755 index 000000000..1a33cd884 --- /dev/null +++ b/criu/arch/mips/include/asm/restorer.h @@ -0,0 +1,79 @@ +#ifndef __CR_ASM_RESTORER_H__ +#define __CR_ASM_RESTORER_H__ + +#include "asm/types.h" +#include +#include "images/core.pb-c.h" +#include +#include + +static inline void restore_tls(tls_t *ptls) { + asm volatile( + "move $4, %0 \n" + "li $2, "__stringify(__NR_set_thread_area)" \n" + "syscall \n" + : + : "r"(*ptls) + : "$4","$2","memory"); +} +static inline int arch_compat_rt_sigaction(void *stack, int sig, void *act) +{ + return -1; +} +static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len) +{ + return -1; +} + +#define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \ + thread_args, clone_restore_fn) \ + asm volatile( \ + "ld $5,%2 \n" /* a1 = new_sp */ \ + "dsubu $5,32 \n" \ + "sd %5,0($5) \n" \ + "sd %6,8($5) \n" \ + "sd %1,16($5) \n" \ + "move $4,%1 \n" /* a0=flags */ \ + "move $6,%3 \n" /* a2=parent_tid */ \ + "li $7,0 \n" /* a3 = tls is 0 */ \ + "move $8,%4 \n" /* a4 = child_tid */ \ + "li $2, "__stringify(__NR_clone)" \n" \ + "syscall \n" /* syscall */ \ + "sync \n" \ + "bnez $7,err \n" \ + "nop \n" \ + "beqz $2,thread_start \n" \ + "nop \n" \ + "move %0,$2 \n" \ + "b end \n" \ + "err:break \n" \ + "thread_start: \n" \ + "ld $25,0($29) \n" \ + "ld $4,8($29) \n" \ + "jal $25 \n" \ + "nop \n" \ + "end: \n" \ + : "=r"(ret) \ + : "r"(clone_flags), \ + "m"(new_sp), \ + "r"(&parent_tid), \ + "r"(&thread_args[i].pid), \ + "r"(clone_restore_fn), \ + "r"(&thread_args[i]) \ + :"$2","$4","$5","$6","$7","$8","$25","$29","memory") + +#define RUN_CLONE3_RESTORE_FN(ret, clone_args, size, args, \ + clone_restore_fn) do { \ + pr_err("This architecture does not support clone3() with set_tid, yet!\n"); \ + ret = -1; \ +} while (0) + +#define kdat_compatible_cr() 0 +#define arch_map_vdso(map, compat) -1 + +static inline void *alloc_compat_syscall_stack(void) { return NULL; } +static inline void free_compat_syscall_stack(void *stack32) { } +int restore_gpregs(struct rt_sigframe *f, UserMipsRegsEntry *r); +int restore_nonsigframe_gpregs(UserMipsRegsEntry *r); + +#endif diff --git a/criu/arch/mips/include/asm/syscall32.h b/criu/arch/mips/include/asm/syscall32.h new file mode 100755 index 000000000..a6e298217 --- /dev/null +++ b/criu/arch/mips/include/asm/syscall32.h @@ -0,0 +1,17 @@ +#ifndef __CR_SYSCALL32_H__ +#define __CR_SYSCALL32_H__ + +extern long sys_socket(int domain, int type, int protocol); +extern long sys_connect(int sockfd, struct sockaddr *addr, int addrlen); +extern long sys_sendto(int sockfd, void *buff, size_t len, unsigned int flags, struct sockaddr *addr, int addr_len); +extern long sys_recvfrom(int sockfd, void *ubuf, size_t size, unsigned int flags, struct sockaddr *addr, int *addr_len); +extern long sys_sendmsg(int sockfd, const struct msghdr *msg, int flags); +extern long sys_recvmsg(int sockfd, struct msghdr *msg, int flags); +extern long sys_shutdown(int sockfd, int how); +extern long sys_bind(int sockfd, const struct sockaddr *addr, int addrlen); +extern long sys_setsockopt(int sockfd, int level, int optname, const void *optval, unsigned int optlen); +extern long sys_getsockopt(int sockfd, int level, int optname, const void *optval, unsigned int *optlen); +extern long sys_shmat(int shmid, void *shmaddr, int shmflag); +extern long sys_pread(unsigned int fd, char *ubuf, u32 count, u64 pos); + +#endif /* __CR_SYSCALL32_H__ */ diff --git a/criu/arch/mips/include/asm/types.h b/criu/arch/mips/include/asm/types.h new file mode 100755 index 000000000..8366e0540 --- /dev/null +++ b/criu/arch/mips/include/asm/types.h @@ -0,0 +1,31 @@ +#ifndef __CR_ASM_TYPES_H__ +#define __CR_ASM_TYPES_H__ + +#include +#include + +#include "page.h" +#include "bitops.h" +#include "asm/int.h" + +#include + +#include "images/core.pb-c.h" + +#define core_is_compat(core) false + +#define CORE_ENTRY__MARCH CORE_ENTRY__MARCH__MIPS + +#define CORE_THREAD_ARCH_INFO(core) core->ti_mips + +typedef UserMipsRegsEntry UserRegsEntry; + +static inline u64 encode_pointer(void *p) { return (u64)p; } +static inline void *decode_pointer(u64 v) { return (void*)v; } + + +#define AT_VECTOR_SIZE 44 +typedef uint64_t auxv_t; +typedef unsigned long tls_t; + +#endif /* __CR_ASM_TYPES_H__ */ diff --git a/criu/arch/mips/include/asm/vdso.h b/criu/arch/mips/include/asm/vdso.h new file mode 100755 index 000000000..0e5da159e --- /dev/null +++ b/criu/arch/mips/include/asm/vdso.h @@ -0,0 +1,23 @@ +#ifndef __CR_ASM_VDSO_H__ +#define __CR_ASM_VDSO_H__ + +#include "asm/int.h" +#include "asm-generic/vdso.h" + +/* This definition is used in pie/util-vdso.c to initialize the vdso symbol + * name string table 'vdso_symbols' + */ + +/* + * This is a minimal amount of symbols + * we should support at the moment. + */ +#define VDSO_SYMBOL_MAX 3 +#define VDSO_SYMBOL_GTOD 0 +#define ARCH_VDSO_SYMBOLS \ + "__vdso_clock_gettime", \ + "__vdso_gettimeofday", \ + "__vdso_clock_getres" + + +#endif /* __CR_ASM_VDSO_H__ */ diff --git a/criu/arch/mips/restorer.c b/criu/arch/mips/restorer.c new file mode 100755 index 000000000..2e196b60c --- /dev/null +++ b/criu/arch/mips/restorer.c @@ -0,0 +1,17 @@ +#include + +#include "types.h" +#include "restorer.h" +#include "asm/restorer.h" +#include + +#include +#include +#include +#include "log.h" +#include "cpu.h" + +int restore_nonsigframe_gpregs(UserMipsRegsEntry *r) +{ + return 0; +} diff --git a/criu/arch/mips/sigaction_compat.c b/criu/arch/mips/sigaction_compat.c new file mode 100755 index 000000000..d3e45f082 --- /dev/null +++ b/criu/arch/mips/sigaction_compat.c @@ -0,0 +1,19 @@ +#include "log.h" +#include "asm/restorer.h" +#include +#include "asm/compat.h" +#include + +#ifdef CR_NOGLIBC +# include +#endif + +#include "cpu.h" + +extern char restore_rt_sigaction; + +int arch_compat_rt_sigaction(void *stack32, int sig, rt_sigaction_t_compat *act) +{ + return 0; +} + diff --git a/criu/arch/mips/sigframe.c b/criu/arch/mips/sigframe.c new file mode 100755 index 000000000..1e39102f0 --- /dev/null +++ b/criu/arch/mips/sigframe.c @@ -0,0 +1,13 @@ +#include +#include + +#include "asm/sigframe.h" +#include "asm/types.h" + +#include "log.h" +#include +int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, + struct rt_sigframe *rsigframe) +{ + return 0; +} diff --git a/criu/arch/mips/vdso-pie.c b/criu/arch/mips/vdso-pie.c new file mode 100755 index 000000000..737e5538b --- /dev/null +++ b/criu/arch/mips/vdso-pie.c @@ -0,0 +1,21 @@ +#include +#include "asm/types.h" + +#include +#include +#include "parasite-vdso.h" +#include "log.h" +#include "common/bug.h" + +#ifdef LOG_PREFIX +# undef LOG_PREFIX +#endif +#define LOG_PREFIX "vdso: " + +int vdso_redirect_calls(unsigned long base_to, unsigned long base_from, + struct vdso_symtable *sto, struct vdso_symtable *sfrom, + bool compat_vdso) +{ + pr_err("Vdso proxification isn't implemented on mips\n"); + return -1; +} From afe90627e276e9e68cdf4872cae8fa3c5c637914 Mon Sep 17 00:00:00 2001 From: Guoyun Sun Date: Wed, 8 Apr 2020 10:29:21 +0800 Subject: [PATCH 2401/4375] mips:criu: Enable mips in criu Signed-off-by: Guoyun Sun --- Makefile | 10 +++++++++- criu/cr-restore.c | 9 ++++++++- criu/kerndat.c | 9 +++++++++ criu/parasite-syscall.c | 17 +++++++++++++++++ criu/pie/Makefile | 4 ++++ criu/pie/Makefile.library | 4 ++++ 6 files changed, 51 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 00e563c11..e72dd1428 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ endif # # Supported Architectures -ifneq ($(filter-out x86 arm aarch64 ppc64 s390,$(ARCH)),) +ifneq ($(filter-out x86 arm aarch64 ppc64 s390 mips,$(ARCH)),) $(error "The architecture $(ARCH) isn't supported") endif @@ -76,6 +76,10 @@ ifeq ($(ARCH),x86) DEFINES := -DCONFIG_X86_64 endif +ifeq ($(ARCH),mips) + DEFINES := -DCONFIG_MIPS +endif + # # CFLAGS_PIE: # @@ -105,6 +109,10 @@ WARNINGS := -Wall -Wformat-security -Wdeclaration-after-statement -Wstrict-prot CFLAGS-GCOV := --coverage -fno-exceptions -fno-inline -fprofile-update=atomic export CFLAGS-GCOV +ifeq ($(ARCH),mips) +WARNINGS := -rdynamic +endif + ifneq ($(GCOV),) LDFLAGS += -lgcov CFLAGS += $(CFLAGS-GCOV) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index f572f79a0..99b36e0d4 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -461,9 +461,16 @@ static int restore_native_sigaction(int sig, SaEntry *e) ASSIGN_TYPED(act.rt_sa_handler, decode_pointer(e->sigaction)); ASSIGN_TYPED(act.rt_sa_flags, e->flags); ASSIGN_TYPED(act.rt_sa_restorer, decode_pointer(e->restorer)); +#ifdef CONFIG_MIPS + e->has_mask_extended = 1; + BUILD_BUG_ON(sizeof(e->mask)* 2 != sizeof(act.rt_sa_mask.sig)); + + memcpy(&(act.rt_sa_mask.sig[0]), &e->mask, sizeof(act.rt_sa_mask.sig[0])); + memcpy(&(act.rt_sa_mask.sig[1]), &e->mask_extended, sizeof(act.rt_sa_mask.sig[1])); +#else BUILD_BUG_ON(sizeof(e->mask) != sizeof(act.rt_sa_mask.sig)); memcpy(act.rt_sa_mask.sig, &e->mask, sizeof(act.rt_sa_mask.sig)); - +#endif if (sig == SIGCHLD) { sigchld_act = act; return 0; diff --git a/criu/kerndat.c b/criu/kerndat.c index 0b6d53bc7..831f9f72a 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -1007,6 +1007,15 @@ static bool kerndat_has_clone3_set_tid(void) pid_t pid; struct _clone_args args = {}; +#if defined(CONFIG_MIPS) + /* + * Currently the CRIU PIE assembler clone3() wrapper is + * not implemented for MIPS. + */ + kdat.has_clone3_set_tid = false; + return 0; +#endif + args.set_tid = -1; /* * On a system without clone3() this will return ENOSYS. diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index b649d1b51..5f9de152a 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -179,7 +179,12 @@ int parasite_dump_thread_seized(struct parasite_thread_ctl *tctl, pc->cap_last_cap = kdat.last_cap; tc->has_blk_sigset = true; +#ifdef CONFIG_MIPS + memcpy(&tc->blk_sigset, (unsigned long *)compel_thread_sigmask(tctl), sizeof(tc->blk_sigset)); + memcpy(&tc->blk_sigset_extended, (unsigned long *)compel_thread_sigmask(tctl)+1, sizeof(tc->blk_sigset)); +#else memcpy(&tc->blk_sigset, compel_thread_sigmask(tctl), sizeof(k_rtsigset_t)); +#endif ret = compel_get_thread_regs(tctl, save_task_regs, core); if (ret) { pr_err("Can't obtain regs for thread %d\n", pid); @@ -240,8 +245,15 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct pstree_item *i ASSIGN_TYPED(sa->sigaction, encode_pointer(args->sas[i].rt_sa_handler)); ASSIGN_TYPED(sa->flags, args->sas[i].rt_sa_flags); ASSIGN_TYPED(sa->restorer, encode_pointer(args->sas[i].rt_sa_restorer)); +#ifdef CONFIG_MIPS + sa->has_mask_extended = 1; + BUILD_BUG_ON(sizeof(sa->mask) * 2 != sizeof(args->sas[0].rt_sa_mask.sig)); + memcpy(&sa->mask, &(args->sas[i].rt_sa_mask.sig[0]), sizeof(sa->mask)); + memcpy(&sa->mask_extended, &(args->sas[i].rt_sa_mask.sig[1]), sizeof(sa->mask)); +#else BUILD_BUG_ON(sizeof(sa->mask) != sizeof(args->sas[0].rt_sa_mask.sig)); memcpy(&sa->mask, args->sas[i].rt_sa_mask.sig, sizeof(sa->mask)); +#endif sa->has_compat_sigaction = true; sa->compat_sigaction = !compel_mode_native(ctl); @@ -569,7 +581,12 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, } parasite_args_size = PARASITE_ARG_SIZE_MIN; /* reset for next task */ +#ifdef CONFIG_MIPS + memcpy(&item->core[0]->tc->blk_sigset, (unsigned long *)compel_task_sigmask(ctl), sizeof(item->core[0]->tc->blk_sigset)); + memcpy(&item->core[0]->tc->blk_sigset_extended, (unsigned long *)compel_task_sigmask(ctl)+1, sizeof(item->core[0]->tc->blk_sigset)); +#else memcpy(&item->core[0]->tc->blk_sigset, compel_task_sigmask(ctl), sizeof(k_rtsigset_t)); +#endif dmpi(item)->parasite_ctl = ctl; return ctl; diff --git a/criu/pie/Makefile b/criu/pie/Makefile index a30747ac3..265dcf82b 100644 --- a/criu/pie/Makefile +++ b/criu/pie/Makefile @@ -14,6 +14,10 @@ ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),) compel_plugins := $(shell $(COMPEL_BIN) plugins) endif +ifeq ($(ARCH),mips) + ccflags-y += -mno-abicalls -fno-pic +endif + LDS := compel/arch/$(ARCH)/scripts/compel-pack.lds.S restorer-obj-y += parasite-vdso.o ./$(ARCH_DIR)/vdso-pie.o diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library index de75b11d4..da2a2fab3 100644 --- a/criu/pie/Makefile.library +++ b/criu/pie/Makefile.library @@ -23,3 +23,7 @@ endif CFLAGS := $(filter-out -pg $(CFLAGS-GCOV) $(CFLAGS-ASAN),$(CFLAGS)) CFLAGS += $(CFLAGS_PIE) + +ifeq ($(ARCH),mips) +CFLAGS += -fno-stack-protector -DCR_NOGLIBC -mno-abicalls -fno-pic +endif From b5c34c74c5055301821c2acbe4cf8aad646da558 Mon Sep 17 00:00:00 2001 From: Guoyun Sun Date: Wed, 8 Apr 2020 10:49:47 +0800 Subject: [PATCH 2402/4375] mips:support docker-cross compile Signed-off-by: Guoyun Sun --- .travis.yml | 4 + scripts/build/Dockerfile.mips64el-cross | 44 ++++++ scripts/build/Makefile | 4 +- test/zdtm/lib/arch/mips/include/asm/atomic.h | 136 +++++++++++++++++++ test/zdtm/lib/test.c | 2 +- test/zdtm/static/pthread01.c | 5 + 6 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 scripts/build/Dockerfile.mips64el-cross create mode 100644 test/zdtm/lib/arch/mips/include/asm/atomic.h diff --git a/.travis.yml b/.travis.yml index 69a505193..8c126b47f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -95,6 +95,10 @@ jobs: env: TR_ARCH=ppc64-cross dist: bionic - env: TR_ARCH=local STREAM_TEST=1 + - os: linux + arch: amd64 + env: TR_ARCH=mips64el-cross + dist: bionic allow_failures: - env: TR_ARCH=docker-test - env: TR_ARCH=docker-test DIST=xenial diff --git a/scripts/build/Dockerfile.mips64el-cross b/scripts/build/Dockerfile.mips64el-cross new file mode 100644 index 000000000..1ba936105 --- /dev/null +++ b/scripts/build/Dockerfile.mips64el-cross @@ -0,0 +1,44 @@ +FROM dockcross/base:latest + +# Add the cross compiler sources +RUN echo "deb http://ftp.us.debian.org/debian/ buster main" >> /etc/apt/sources.list && \ + dpkg --add-architecture mips64el && \ + apt-get install emdebian-archive-keyring + +RUN apt-get update && apt-get install -y \ + crossbuild-essential-mips64el \ + libbz2-dev:mips64el \ + libexpat1-dev:mips64el \ + ncurses-dev:mips64el \ + libssl-dev:mips64el \ + protobuf-c-compiler \ + protobuf-compiler \ + python-protobuf \ + libnl-3-dev:mips64el \ + libprotobuf-dev:mips64el \ + libnet-dev:mips64el \ + libprotobuf-c-dev:mips64el \ + libcap-dev:mips64el \ + libaio-dev:mips64el \ + libnl-route-3-dev:mips64el + +ENV CROSS_TRIPLE=mips64el-linux-gnuabi64 +ENV CROSS_COMPILE=${CROSS_TRIPLE}- \ + CROSS_ROOT=/usr/${CROSS_TRIPLE} \ + AS=/usr/bin/${CROSS_TRIPLE}-as \ + AR=/usr/bin/${CROSS_TRIPLE}-ar \ + CC=/usr/bin/${CROSS_TRIPLE}-gcc \ + CPP=/usr/bin/${CROSS_TRIPLE}-cpp \ + CXX=/usr/bin/${CROSS_TRIPLE}-g++ \ + LD=/usr/bin/${CROSS_TRIPLE}-ld \ + FC=/usr/bin/${CROSS_TRIPLE}-gfortran + +ENV PATH="${PATH}:${CROSS_ROOT}/bin" \ + PKG_CONFIG_PATH=/usr/lib/${CROSS_TRIPLE}/pkgconfig \ + ARCH=mips \ + SUBARCH=mips + +COPY . /criu +WORKDIR /criu + +RUN make mrproper && date && make -j $(nproc) zdtm && date diff --git a/scripts/build/Makefile b/scripts/build/Makefile index 855539152..974d1455f 100644 --- a/scripts/build/Makefile +++ b/scripts/build/Makefile @@ -2,7 +2,9 @@ ARCHES := x86_64 fedora-asan fedora-rawhide centos armv7hf TARGETS := $(ARCHES) alpine TARGETS_CLANG := $(addsuffix $(TARGETS),-clang) CONTAINER_RUNTIME := docker -TARGETS += armv7-cross aarch64-cross ppc64-cross + +TARGETS += armv7-cross aarch64-cross ppc64-cross mips64el-cross + all: $(TARGETS) $(TARGETS_CLANG) .PHONY: all diff --git a/test/zdtm/lib/arch/mips/include/asm/atomic.h b/test/zdtm/lib/arch/mips/include/asm/atomic.h new file mode 100644 index 000000000..acf4c03cd --- /dev/null +++ b/test/zdtm/lib/arch/mips/include/asm/atomic.h @@ -0,0 +1,136 @@ +#ifndef __CR_ATOMIC_H__ +#define __CR_ATOMIC_H__ + +//#include +//#include "common/compiler.h" +//#include "common/arch/mips/asm/utils.h" +//#include "common/arch/mips/asm/cmpxchg.h" + +typedef uint32_t atomic_t; +/* typedef struct { */ +/* int counter; */ +/* }atomic_t; */ + +#define __WEAK_LLSC_MB " sync \n" + +#define smp_llsc_mb() __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory") + +#define smp_mb__before_llsc() smp_llsc_mb() +#define smp_mb__before_atomic() smp_mb__before_llsc() +#define smp_mb__after_atomic() smp_llsc_mb() + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#define atomic_get(v) (*(volatile int *)v) +#define atomic_set(v, i) ((*v) = (i)) + +//#define atomic_get atomic_read + +/* + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v. + */ + +static __inline__ void atomic_add(int i, atomic_t * v) +{ + int temp; + + do { + __asm__ __volatile__( + " .set mips3 \n" + " ll %0, %1 # atomic_add \n" + " addu %0, %2 \n" + " sc %0, %1 \n" + " .set mips0 \n" + : "=&r" (temp), "+m" (*v) + : "Ir" (i)); + } while (unlikely(!temp)); +} + +/* + * atomic_sub - subtract the atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v. + */ +static __inline__ void atomic_sub(int i, atomic_t * v) +{ + int temp; + + do { + __asm__ __volatile__( + " .set mips3 \n" + " ll %0, %1 # atomic_sub \n" + " subu %0, %2 \n" + " sc %0, %1 \n" + " .set mips0 \n" + : "=&r" (temp), "+m" (*v) + : "Ir" (i)); + } while (unlikely(!temp)); +} + +/* + * Same as above, but return the result value + */ +static __inline__ int atomic_add_return(int i, atomic_t * v) +{ + int result; + int temp; + + smp_mb__before_llsc(); + + do { + __asm__ __volatile__( + " .set mips3 \n" + " ll %1, %2 # atomic_add_return \n" + " addu %0, %1, %3 \n" + " sc %0, %2 \n" + " .set mips0 \n" + : "=&r" (result), "=&r" (temp), "+m" (*v) + : "Ir" (i)); + } while (unlikely(!result)); + + result = temp + i; + + smp_llsc_mb(); + + return result; +} + +static __inline__ int atomic_sub_return(int i, atomic_t * v) +{ + int result; + int temp; + + smp_mb__before_llsc(); + + do { + __asm__ __volatile__( + " .set mips3 \n" + " ll %1, %2 # atomic_sub_return \n" + " subu %0, %1, %3 \n" + " sc %0, %2 \n" + " .set mips0 \n" + : "=&r" (result), "=&r" (temp), "+m" (*v) + : "Ir" (i)); + } while (unlikely(!result)); + + result = temp - i; + + smp_llsc_mb(); + + return result; +} + +#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) +#define atomic_dec_return(v) atomic_sub_return(1, (v)) +#define atomic_inc_return(v) atomic_add_return(1, (v)) + +static inline unsigned int atomic_inc(atomic_t *v) { return atomic_add_return(1, v) - 1; } +static inline unsigned int atomic_dec(atomic_t *v) { return atomic_sub_return(1, v) + 1; } +#endif /* __CR_ATOMIC_H__ */ diff --git a/test/zdtm/lib/test.c b/test/zdtm/lib/test.c index 630476de0..e031357ac 100644 --- a/test/zdtm/lib/test.c +++ b/test/zdtm/lib/test.c @@ -403,7 +403,7 @@ pid_t sys_clone_unified(unsigned long flags, void *child_stack, void *parent_tid { #ifdef __x86_64__ return (pid_t)syscall(__NR_clone, flags, child_stack, parent_tid, child_tid, newtls); -#elif (__i386__ || __arm__ || __aarch64__ ||__powerpc64__) +#elif (__i386__ || __arm__ || __aarch64__ ||__powerpc64__ || __mips__) return (pid_t)syscall(__NR_clone, flags, child_stack, parent_tid, newtls, child_tid); #elif __s390x__ return (pid_t)syscall(__NR_clone, child_stack, flags, parent_tid, child_tid, newtls); diff --git a/test/zdtm/static/pthread01.c b/test/zdtm/static/pthread01.c index 1e84463ee..bdd7c59d8 100644 --- a/test/zdtm/static/pthread01.c +++ b/test/zdtm/static/pthread01.c @@ -27,6 +27,11 @@ static __thread struct tls_data_s { static task_waiter_t t1; static task_waiter_t t2; +#ifdef CONFIG_MIPS +#ifndef SIGSTKFLT +#define SIGSTKFLT 16 +#endif +#endif static char *decode_signal(const sigset_t *s, char *buf) { buf[0] = '\0'; From 40169b950eff23347975acc0de0b9316f08d175b Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 26 Mar 2020 06:26:48 +0000 Subject: [PATCH 2403/4375] style: fix typos Oddly, one of the test had a typo which should be fatal. Signed-off-by: Nicolas Viennot --- criu/config.c | 2 +- test/others/ext-tty/run.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/criu/config.c b/criu/config.c index e78b534a9..eb303fd77 100644 --- a/criu/config.c +++ b/criu/config.c @@ -876,7 +876,7 @@ int check_options(void) } if (!opts.restore_detach && opts.restore_sibling) { - pr_err("--restore-sibling only makes sense with --restore-detach\n"); + pr_err("--restore-sibling only makes sense with --restore-detached\n"); return 1; } diff --git a/test/others/ext-tty/run.py b/test/others/ext-tty/run.py index 2c0bacc84..8109033cb 100755 --- a/test/others/ext-tty/run.py +++ b/test/others/ext-tty/run.py @@ -29,7 +29,7 @@ ttyid = "fd[%d]:tty[%x:%x]" % (slave, st.st_rdev, st.st_dev) ret = subprocess.Popen([ "../../../criu/criu", "restore", "-v4", "--inherit-fd", ttyid, - "--restore-sibling", "--restore-detach" + "--restore-sibling", "--restore-detached" ]).wait() if ret: sys.exit(ret) From d38851c9bd003d9c5b2b1c804291f518db681938 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 18 Apr 2020 22:28:24 +0300 Subject: [PATCH 2404/4375] test/jenkins: use bash to run shell scripts We permanently have issues like this: ./test/jenkins/criu-iter.sh: 3: source: not found It looks like a good idea to use one shell to run our jenkins scripts. Signed-off-by: Andrei Vagin --- test/jenkins/criu-btrfs.sh | 2 ++ test/jenkins/criu-by-id.sh | 2 ++ test/jenkins/criu-dedup.sh | 2 ++ test/jenkins/criu-dump.sh | 2 ++ test/jenkins/criu-fault.sh | 1 + test/jenkins/criu-fcg.sh | 2 ++ test/jenkins/criu-groups.sh | 2 ++ test/jenkins/criu-inhfd.sh | 2 ++ test/jenkins/criu-iter.sh | 2 ++ test/jenkins/criu-join-ns.sh | 2 ++ test/jenkins/criu-lazy-common.sh | 2 ++ test/jenkins/criu-lazy-migration.sh | 2 ++ test/jenkins/criu-lazy-pages.sh | 2 ++ test/jenkins/criu-other.sh | 2 ++ test/jenkins/criu-overlay.sh | 2 ++ test/jenkins/criu-pre-dump.sh | 2 ++ test/jenkins/criu-remote-lazy-pages.sh | 2 ++ test/jenkins/criu-sibling.sh | 2 ++ test/jenkins/criu-snap.sh | 2 ++ test/jenkins/criu-stop.sh | 2 ++ test/jenkins/criu-user.sh | 2 ++ test/jenkins/criu.sh | 2 ++ 22 files changed, 43 insertions(+) diff --git a/test/jenkins/criu-btrfs.sh b/test/jenkins/criu-btrfs.sh index e749ad906..e456f1c34 100644 --- a/test/jenkins/criu-btrfs.sh +++ b/test/jenkins/criu-btrfs.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # This is a job which is executed on btrfs source `dirname $0`/criu-lib.sh && diff --git a/test/jenkins/criu-by-id.sh b/test/jenkins/criu-by-id.sh index 2381e73f7..c041ed358 100644 --- a/test/jenkins/criu-by-id.sh +++ b/test/jenkins/criu-by-id.sh @@ -1,3 +1,5 @@ +#!/bin/bash + echo 950000 > /sys/fs/cgroup/cpu,cpuacct/system/cpu.rt_runtime_us echo 950000 > /sys/fs/cgroup/cpu,cpuacct/system/jenkins.service/cpu.rt_runtime_us git checkout -f ${TEST_COMMIT} diff --git a/test/jenkins/criu-dedup.sh b/test/jenkins/criu-dedup.sh index e75ef5f82..0041496d8 100755 --- a/test/jenkins/criu-dedup.sh +++ b/test/jenkins/criu-dedup.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Check auto-deduplication of pagemaps set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-dump.sh b/test/jenkins/criu-dump.sh index 381cf7a98..4c49532b2 100755 --- a/test/jenkins/criu-dump.sh +++ b/test/jenkins/criu-dump.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Check that dump is not destructive set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-fault.sh b/test/jenkins/criu-fault.sh index c27dd3738..f871a140b 100755 --- a/test/jenkins/criu-fault.sh +++ b/test/jenkins/criu-fault.sh @@ -1,4 +1,5 @@ #!/bin/bash + # Check known fault injections set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-fcg.sh b/test/jenkins/criu-fcg.sh index 938a72f26..ca5054f5e 100755 --- a/test/jenkins/criu-fcg.sh +++ b/test/jenkins/criu-fcg.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Test how freeze cgroup works set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-groups.sh b/test/jenkins/criu-groups.sh index 508d20aa6..b5bea4eab 100755 --- a/test/jenkins/criu-groups.sh +++ b/test/jenkins/criu-groups.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Make one regular C/R cycle over randomly-generated groups set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-inhfd.sh b/test/jenkins/criu-inhfd.sh index a59dcda6e..8f44ba13a 100755 --- a/test/jenkins/criu-inhfd.sh +++ b/test/jenkins/criu-inhfd.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Check known fault injections set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-iter.sh b/test/jenkins/criu-iter.sh index d414b0575..304aa43db 100755 --- a/test/jenkins/criu-iter.sh +++ b/test/jenkins/criu-iter.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Make 3 iteration of dump/restore for each test set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-join-ns.sh b/test/jenkins/criu-join-ns.sh index 39ef182f0..241c29034 100755 --- a/test/jenkins/criu-join-ns.sh +++ b/test/jenkins/criu-join-ns.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Make one regular C/R cycle set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-lazy-common.sh b/test/jenkins/criu-lazy-common.sh index 7fdab40dd..a8ff9e51b 100644 --- a/test/jenkins/criu-lazy-common.sh +++ b/test/jenkins/criu-lazy-common.sh @@ -1,3 +1,5 @@ +#!/bin/bash + KERN_MAJ=`uname -r | cut -d. -f1` KERN_MIN=`uname -r | cut -d. -f2` if [ $KERN_MAJ -ge "4" ] && [ $KERN_MIN -ge "11" ]; then diff --git a/test/jenkins/criu-lazy-migration.sh b/test/jenkins/criu-lazy-migration.sh index 30e3c0375..02a212e0d 100755 --- a/test/jenkins/criu-lazy-migration.sh +++ b/test/jenkins/criu-lazy-migration.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Check lazy-pages set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-lazy-pages.sh b/test/jenkins/criu-lazy-pages.sh index a3ee9a4ec..9ef721739 100755 --- a/test/jenkins/criu-lazy-pages.sh +++ b/test/jenkins/criu-lazy-pages.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Check lazy-pages set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-other.sh b/test/jenkins/criu-other.sh index c6c231c86..bb68f912a 100755 --- a/test/jenkins/criu-other.sh +++ b/test/jenkins/criu-other.sh @@ -1,3 +1,5 @@ +#!/bin/bash + source `dirname $0`/criu-lib.sh && prep && make -C test other && diff --git a/test/jenkins/criu-overlay.sh b/test/jenkins/criu-overlay.sh index 5ef7682ac..de80007a3 100755 --- a/test/jenkins/criu-overlay.sh +++ b/test/jenkins/criu-overlay.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Make one regular C/R cycle set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-pre-dump.sh b/test/jenkins/criu-pre-dump.sh index 95f4d8549..137f7c23f 100755 --- a/test/jenkins/criu-pre-dump.sh +++ b/test/jenkins/criu-pre-dump.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Check 3 pre-dump-s before dump (with and w/o page server) set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-remote-lazy-pages.sh b/test/jenkins/criu-remote-lazy-pages.sh index ea0d17f0e..1c677e333 100755 --- a/test/jenkins/criu-remote-lazy-pages.sh +++ b/test/jenkins/criu-remote-lazy-pages.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Check remote-lazy-pages set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-sibling.sh b/test/jenkins/criu-sibling.sh index 93f070330..d59b38970 100755 --- a/test/jenkins/criu-sibling.sh +++ b/test/jenkins/criu-sibling.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Make 3 iteration of dump/restore for each test set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-snap.sh b/test/jenkins/criu-snap.sh index d28ba45d9..b08c57f52 100755 --- a/test/jenkins/criu-snap.sh +++ b/test/jenkins/criu-snap.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Check snapshots set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-stop.sh b/test/jenkins/criu-stop.sh index d92519d68..64da2ee8a 100644 --- a/test/jenkins/criu-stop.sh +++ b/test/jenkins/criu-stop.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Check --leave-stopped option set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu-user.sh b/test/jenkins/criu-user.sh index d89ede203..f4ec52fc6 100755 --- a/test/jenkins/criu-user.sh +++ b/test/jenkins/criu-user.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Make 3 iteration of dump/restore for each test set -e source `dirname $0`/criu-lib.sh diff --git a/test/jenkins/criu.sh b/test/jenkins/criu.sh index 19d545c3c..0ee750b08 100755 --- a/test/jenkins/criu.sh +++ b/test/jenkins/criu.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Make one regular C/R cycle set -e source `dirname $0`/criu-lib.sh From be1394122112381eca55faf5b1a7b2e2b51bd383 Mon Sep 17 00:00:00 2001 From: Guoyun Sun Date: Fri, 17 Apr 2020 11:54:31 +0000 Subject: [PATCH 2405/4375] mips: impliment arch_shmat() On MIPS CPUs with VIPT caches also has aliasing issues, just like ARMv6. To overcome this issue, page coloring 0x40000 align for shared mappings was introduced (SHMLBA) in kernel. https://github.com/torvalds/linux/blob/master/arch/mips/include/asm/shmparam.h Related to this, zdtm test suites ipc.c shm.c shm-unaligned.c and shm-mp.c are passed. Signed-off-by: Guoyun Sun --- criu/arch/mips/include/asm/restorer.h | 4 ++++ criu/arch/mips/restorer.c | 32 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/criu/arch/mips/include/asm/restorer.h b/criu/arch/mips/include/asm/restorer.h index 1a33cd884..d916377f4 100755 --- a/criu/arch/mips/include/asm/restorer.h +++ b/criu/arch/mips/include/asm/restorer.h @@ -76,4 +76,8 @@ static inline void free_compat_syscall_stack(void *stack32) { } int restore_gpregs(struct rt_sigframe *f, UserMipsRegsEntry *r); int restore_nonsigframe_gpregs(UserMipsRegsEntry *r); +#define ARCH_HAS_SHMAT_HOOK +unsigned long arch_shmat(int shmid, void *shmaddr, + int shmflg, unsigned long size); + #endif diff --git a/criu/arch/mips/restorer.c b/criu/arch/mips/restorer.c index 2e196b60c..e3a1e4a44 100755 --- a/criu/arch/mips/restorer.c +++ b/criu/arch/mips/restorer.c @@ -15,3 +15,35 @@ int restore_nonsigframe_gpregs(UserMipsRegsEntry *r) { return 0; } + +#define SHMLBA 0x40000 +unsigned long arch_shmat(int shmid, void *shmaddr, + int shmflg, unsigned long size) +{ + unsigned long smap; + + /* SHMLBA-aligned, direct call shmat() */ + if (!((unsigned long)shmaddr & (SHMLBA - 1))) + return sys_shmat(shmid, shmaddr, shmflg); + + smap = sys_shmat(shmid, NULL, shmflg); + if (IS_ERR_VALUE(smap)) { + pr_err("shmat() with NULL shmaddr failed: %d\n", (int)smap); + return smap; + } + + /* We're lucky! */ + if (smap == (unsigned long)shmaddr) + return smap; + + /* Warn ALOUD */ + pr_warn("Restoring shmem %p unaligned to SHMLBA.\n", shmaddr); + pr_warn("Make sure that you don't migrate shmem from non-VIPT cached CPU to VIPT cached \n"); + pr_warn("Otherwise YOU HAVE A CHANCE OF DATA CORRUPTIONS in writeable shmem\n"); + + smap = sys_mremap(smap, size, size, + MREMAP_FIXED | MREMAP_MAYMOVE, (unsigned long)shmaddr); + if (IS_ERR_VALUE(smap)) + pr_err("mremap() for shmem failed: %d\n", (int)smap); + return smap; +} From 277b0b69fac7afa6cbde51e7c99e2756029d0d6c Mon Sep 17 00:00:00 2001 From: Guoyun Sun Date: Wed, 22 Apr 2020 15:43:04 +0800 Subject: [PATCH 2406/4375] mips: fix fail when run zdtm test pthread01.c k_rtsigset_t is 16Bytes in mips architecture but not 8Bytes. so blk_sigset_extended be added in TaskCoreEntry and ThreadCoreEntry for dumping extern 8Bytes data in parasite-syscall.c, restore extern 8Bytes data in cr-restore.c Signed-off-by: Guoyun Sun --- criu/cr-restore.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 99b36e0d4..ec00bf71b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3551,8 +3551,12 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns for (i = 0; i < current->nr_threads; i++) { CoreEntry *tcore; struct rt_sigframe *sigframe; +#ifdef CONFIG_MIPS + k_rtsigset_t mips_blkset; +#else k_rtsigset_t *blkset = NULL; +#endif thread_args[i].pid = current->threads[i].ns[0].virt; thread_args[i].siginfo_n = siginfo_priv_nr[i]; thread_args[i].siginfo = task_args->siginfo; @@ -3563,11 +3567,22 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns if (thread_args[i].pid == pid) { task_args->t = thread_args + i; tcore = core; +#ifdef CONFIG_MIPS + mips_blkset.sig[0] = tcore->tc->blk_sigset; + mips_blkset.sig[1] = tcore->tc->blk_sigset_extended; +#else blkset = (void *)&tcore->tc->blk_sigset; +#endif } else { tcore = current->core[i]; - if (tcore->thread_core->has_blk_sigset) + if (tcore->thread_core->has_blk_sigset) { +#ifdef CONFIG_MIPS + mips_blkset.sig[0] = tcore->thread_core->blk_sigset; + mips_blkset.sig[1] = tcore->thread_core->blk_sigset_extended; +#else blkset = (void *)&tcore->thread_core->blk_sigset; +#endif + } } if ((tcore->tc || tcore->ids) && thread_args[i].pid != pid) { @@ -3607,7 +3622,11 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns thread_args[i].mz = mz + i; sigframe = (struct rt_sigframe *)&mz[i].rt_sigframe; +#ifdef CONFIG_MIPS + if (construct_sigframe(sigframe, sigframe, &mips_blkset, tcore)) +#else if (construct_sigframe(sigframe, sigframe, blkset, tcore)) +#endif goto err; if (tcore->thread_core->comm) From 8364b09407a969c1af68cd3e477449fa60d2518e Mon Sep 17 00:00:00 2001 From: Josh Abraham Date: Mon, 27 Apr 2020 13:40:46 -0400 Subject: [PATCH 2407/4375] soccr/test: Fix error logging in libsoccr tcp-test Signed-off-by: Joshua Abraham --- soccr/test/tcp-conn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/soccr/test/tcp-conn.c b/soccr/test/tcp-conn.c index e31f58e7e..cdd75129a 100644 --- a/soccr/test/tcp-conn.c +++ b/soccr/test/tcp-conn.c @@ -101,12 +101,12 @@ int main(void) /* Start testing */ dst_let = sizeof(addr); if (getsockname(sock, (struct sockaddr *) &addr, &dst_let)) { - pr_perror("connect"); + pr_perror("getsockname"); return 1; } dst_let = sizeof(addr); if (getpeername(sock, (struct sockaddr *) &dst, &dst_let)) { - pr_perror("connect"); + pr_perror("getpeername"); return 1; } From 5bd776da382fb0838830d80f4bec6c0aaec8bfbb Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Mon, 11 May 2020 02:38:14 -0700 Subject: [PATCH 2408/4375] Remove dupe of "deprecated stuff on" msg A similar one is already printed in check_options(). Before this patch: > $ ./criu/criu -vvvvvv --deprecated --log-file=/dev/stdout xxx > (00.000000) Turn deprecated stuff ON > ... > (00.029680) DEPRECATED ON > (00.029687) Error (criu/crtools.c:284): unknown command: xxx Signed-off-by: Kir Kolyshkin --- criu/crtools.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index ad61fa9bb..76172f350 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -210,9 +210,6 @@ int main(int argc, char *argv[], char *envp[]) if (fault_injected(FI_CANNOT_MAP_VDSO)) kdat.can_map_vdso = 0; - if (opts.deprecated_ok) - pr_debug("DEPRECATED ON\n"); - if (!list_empty(&opts.inherit_fds)) { if (strcmp(argv[optind], "restore")) { pr_err("--inherit-fd is restore-only option\n"); From 8452be93cf24b0dffe257ddab892a9c95d44c91b Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 13 May 2020 15:48:28 +0000 Subject: [PATCH 2409/4375] travis: use bionic almost everywhere A few tests were still running on xenial because at some point they were hanging. This switches now all tests to bionic except one docker test which still uses xenial to test with overlayfs. Signed-off-by: Adrian Reber --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8c126b47f..b28bd64f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,7 +51,7 @@ jobs: - os: linux arch: amd64 env: TR_ARCH=fedora-rawhide - dist: xenial # test hangs on bionic + dist: bionic - os: linux arch: amd64 env: TR_ARCH=podman-test @@ -69,19 +69,19 @@ jobs: - os: linux arch: amd64 env: TR_ARCH=alpine CLANG=1 - dist: xenial # test hangs on bionic + dist: bionic - os: linux arch: amd64 env: TR_ARCH=alpine - dist: xenial # test hangs on bionic + dist: bionic - os: linux arch: amd64 env: TR_ARCH=centos - dist: xenial # test hangs on bionic + dist: bionic - os: linux arch: amd64 env: TR_ARCH=fedora-asan - dist: xenial # test hangs on bionic + dist: bionic - os: linux arch: amd64 env: TR_ARCH=armv7-cross From 00b8257d9f31876e35e08e6d556f6f67d76f3908 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 13 May 2020 17:57:03 +0200 Subject: [PATCH 2410/4375] tests: move cross compilation to github actions This moves the cross compilation tests to github actions, to slightly reduce the number of Travis tests and run them in parallel on github actions. Signed-off-by: Adrian Reber --- .github/workflows/cross-compile.yml | 23 +++++++++++++++++++++++ .travis.yml | 16 ---------------- 2 files changed, 23 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/cross-compile.yml diff --git a/.github/workflows/cross-compile.yml b/.github/workflows/cross-compile.yml new file mode 100644 index 000000000..9545d3df6 --- /dev/null +++ b/.github/workflows/cross-compile.yml @@ -0,0 +1,23 @@ +name: Cross Compile Tests + +on: + push: + branches: [ criu-dev ] + pull_request: + branches: [ criu-dev ] + schedule: + - cron: '55 5 * * *' + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + target: [armv7-cross, aarch64-cross, ppc64-cross, mips64el-cross] + + steps: + - uses: actions/checkout@v2 + - name: Run Cross Compilation Targets + run: > + sudo make -C scripts/travis ${{ matrix.target }} diff --git a/.travis.yml b/.travis.yml index b28bd64f9..e71afa0a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -82,23 +82,7 @@ jobs: arch: amd64 env: TR_ARCH=fedora-asan dist: bionic - - os: linux - arch: amd64 - env: TR_ARCH=armv7-cross - dist: bionic - - os: linux - arch: amd64 - env: TR_ARCH=aarch64-cross - dist: bionic - - os: linux - arch: amd64 - env: TR_ARCH=ppc64-cross - dist: bionic - env: TR_ARCH=local STREAM_TEST=1 - - os: linux - arch: amd64 - env: TR_ARCH=mips64el-cross - dist: bionic allow_failures: - env: TR_ARCH=docker-test - env: TR_ARCH=docker-test DIST=xenial From 00a44031e220919c9df6a1e25db8f32fb141d741 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 15 May 2020 17:10:58 -0700 Subject: [PATCH 2411/4375] cr-service: fix wording in debug messages The message "Overwriting RPC settings with values from " is misleading, giving the impression that file is being read and consumed. It really puzzled me, since didn't exist. What it needs to say is "Would overwrite", i.e. if a file with such name is present, it would be used. Also, add actual "Parsing file ..." so it will be clear which files are being used. Signed-off-by: Kir Kolyshkin --- criu/config.c | 2 ++ criu/cr-service.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/criu/config.c b/criu/config.c index eb303fd77..904addf3a 100644 --- a/criu/config.c +++ b/criu/config.c @@ -126,6 +126,8 @@ static char ** parse_config(char *filepath) if (!configfile) return NULL; + pr_debug("Parsing config file %s\n", filepath); + configuration = xmalloc(config_size * sizeof(char *)); if (configuration == NULL) { fclose(configfile); diff --git a/criu/cr-service.c b/criu/cr-service.c index 53eadb1bc..6dc2379d6 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -405,7 +405,7 @@ static int setup_opts_from_req(int sk, CriuOpts *req) } if (req->config_file) { - pr_debug("Overwriting RPC settings with values from %s\n", req->config_file); + pr_debug("Would overwrite RPC settings with values from %s\n", req->config_file); } if (kerndat_init()) From f6d1b498dc22a66865e1c8899ac5dc2b81363ce1 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 15 May 2020 17:13:33 -0700 Subject: [PATCH 2412/4375] cr-service: spell out an error While working on runc checkpointing, I incorrectly closed status_fd prematurely, and received an error from CRIU, but it was non-descriptive. Do print the error from open(). Signed-off-by: Kir Kolyshkin --- criu/cr-service.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 6dc2379d6..7c2ff9835 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -680,8 +680,10 @@ static int setup_opts_from_req(int sk, CriuOpts *req) if (req->has_status_fd) { sprintf(status_fd, "/proc/%d/fd/%d", ids.pid, req->status_fd); opts.status_fd = open(status_fd, O_WRONLY); - if (opts.status_fd < 0) + if (opts.status_fd < 0) { + pr_perror("Can't reopen status fd %s", status_fd); goto err; + } } if (req->orphan_pts_master) From ae4fd07ca5c09482fa5a78f3ede0d31a4b5ff63e Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Thu, 20 Feb 2020 21:10:23 +0000 Subject: [PATCH 2413/4375] libcriu: Add orphan pts master The orphan pts master option was introduced with commit [1] to enable checkpoint/restore of containers with a pty pair used as a console. [1] https://github.com/checkpoint-restore/criu/commit/6afe523d97d59e6bf29621b8aa0e6a4332f710fc Signed-off-by: Radostin Stoyanov --- lib/c/criu.c | 11 +++++++++++ lib/c/criu.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/lib/c/criu.c b/lib/c/criu.c index 1d0a235f4..2ac18ade9 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -541,6 +541,17 @@ void criu_set_shell_job(bool shell_job) criu_local_set_shell_job(global_opts, shell_job); } +void criu_local_set_orphan_pts_master(criu_opts *opts, bool orphan_pts_master) +{ + opts->rpc->has_orphan_pts_master = true; + opts->rpc->orphan_pts_master = orphan_pts_master; +} + +void criu_set_orphan_pts_master(bool orphan_pts_master) +{ + criu_local_set_orphan_pts_master(global_opts, orphan_pts_master); +} + void criu_local_set_file_locks(criu_opts *opts, bool file_locks) { opts->rpc->has_file_locks = true; diff --git a/lib/c/criu.h b/lib/c/criu.h index 22db0fdcf..3a9204f5b 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -72,6 +72,7 @@ void criu_set_tcp_close(bool tcp_close); void criu_set_weak_sysctls(bool val); void criu_set_evasive_devices(bool evasive_devices); void criu_set_shell_job(bool shell_job); +void criu_set_orphan_pts_master(bool orphan_pts_master); void criu_set_file_locks(bool file_locks); void criu_set_track_mem(bool track_mem); void criu_set_auto_dedup(bool auto_dedup); @@ -185,6 +186,7 @@ void criu_local_set_tcp_close(criu_opts *opts, bool tcp_close); void criu_local_set_weak_sysctls(criu_opts *opts, bool val); void criu_local_set_evasive_devices(criu_opts *opts, bool evasive_devices); void criu_local_set_shell_job(criu_opts *opts, bool shell_job); +void criu_local_set_orphan_pts_master(criu_opts *opts, bool orphan_pts_master); void criu_local_set_file_locks(criu_opts *opts, bool file_locks); void criu_local_set_track_mem(criu_opts *opts, bool track_mem); void criu_local_set_auto_dedup(criu_opts *opts, bool auto_dedup); From 4ac9a3c904ace0414521afc05e1ba3287a95f248 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Fri, 21 Feb 2020 12:23:01 +0000 Subject: [PATCH 2414/4375] libcriu: Use spaces around '=' Signed-off-by: Radostin Stoyanov --- lib/c/criu.c | 94 ++++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/lib/c/criu.c b/lib/c/criu.c index 2ac18ade9..7daac7dbf 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -256,11 +256,11 @@ int criu_local_init_opts(criu_opts **o) return -1; } - opts->rpc = rpc; - opts->notify = NULL; + opts->rpc = rpc; + opts->notify = NULL; - opts->service_comm = CRIU_COMM_BIN; - opts->service_binary = strdup(CR_DEFAULT_SERVICE_BIN); + opts->service_comm = CRIU_COMM_BIN; + opts->service_binary = strdup(CR_DEFAULT_SERVICE_BIN); if(opts->service_binary == NULL) { perror("Can't allocate memory for criu service setting"); @@ -303,8 +303,8 @@ int criu_notify_pid(criu_notify_arg_t na) void criu_local_set_pid(criu_opts *opts, int pid) { - opts->rpc->has_pid = true; - opts->rpc->pid = pid; + opts->rpc->has_pid = true; + opts->rpc->pid = pid; } void criu_set_pid(int pid) @@ -408,8 +408,8 @@ void criu_set_work_dir_fd(int fd) void criu_local_set_leave_running(criu_opts *opts, bool leave_running) { - opts->rpc->has_leave_running = true; - opts->rpc->leave_running = leave_running; + opts->rpc->has_leave_running = true; + opts->rpc->leave_running = leave_running; } void criu_set_leave_running(bool leave_running) @@ -419,8 +419,8 @@ void criu_set_leave_running(bool leave_running) void criu_local_set_ext_unix_sk(criu_opts *opts, bool ext_unix_sk) { - opts->rpc->has_ext_unix_sk = true; - opts->rpc->ext_unix_sk = ext_unix_sk; + opts->rpc->has_ext_unix_sk = true; + opts->rpc->ext_unix_sk = ext_unix_sk; } void criu_set_ext_unix_sk(bool ext_unix_sk) @@ -477,8 +477,8 @@ int criu_add_unix_sk(unsigned int inode) void criu_local_set_tcp_established(criu_opts *opts, bool tcp_established) { - opts->rpc->has_tcp_established = true; - opts->rpc->tcp_established = tcp_established; + opts->rpc->has_tcp_established = true; + opts->rpc->tcp_established = tcp_established; } void criu_set_tcp_established(bool tcp_established) @@ -488,8 +488,8 @@ void criu_set_tcp_established(bool tcp_established) void criu_local_set_tcp_skip_in_flight(criu_opts *opts, bool tcp_skip_in_flight) { - opts->rpc->has_tcp_skip_in_flight = true; - opts->rpc->tcp_skip_in_flight = tcp_skip_in_flight; + opts->rpc->has_tcp_skip_in_flight = true; + opts->rpc->tcp_skip_in_flight = tcp_skip_in_flight; } void criu_set_tcp_skip_in_flight(bool tcp_skip_in_flight) @@ -499,8 +499,8 @@ void criu_set_tcp_skip_in_flight(bool tcp_skip_in_flight) void criu_local_set_tcp_close(criu_opts *opts, bool tcp_close) { - opts->rpc->has_tcp_close = true; - opts->rpc->tcp_close = tcp_close; + opts->rpc->has_tcp_close = true; + opts->rpc->tcp_close = tcp_close; } void criu_set_tcp_close(bool tcp_close) @@ -511,7 +511,7 @@ void criu_set_tcp_close(bool tcp_close) void criu_local_set_weak_sysctls(criu_opts *opts, bool val) { opts->rpc->has_weak_sysctls = true; - opts->rpc->weak_sysctls = val; + opts->rpc->weak_sysctls = val; } void criu_set_weak_sysctls(bool val) @@ -521,8 +521,8 @@ void criu_set_weak_sysctls(bool val) void criu_local_set_evasive_devices(criu_opts *opts, bool evasive_devices) { - opts->rpc->has_evasive_devices = true; - opts->rpc->evasive_devices = evasive_devices; + opts->rpc->has_evasive_devices = true; + opts->rpc->evasive_devices = evasive_devices; } void criu_set_evasive_devices(bool evasive_devices) @@ -532,8 +532,8 @@ void criu_set_evasive_devices(bool evasive_devices) void criu_local_set_shell_job(criu_opts *opts, bool shell_job) { - opts->rpc->has_shell_job = true; - opts->rpc->shell_job = shell_job; + opts->rpc->has_shell_job = true; + opts->rpc->shell_job = shell_job; } void criu_set_shell_job(bool shell_job) @@ -554,8 +554,8 @@ void criu_set_orphan_pts_master(bool orphan_pts_master) void criu_local_set_file_locks(criu_opts *opts, bool file_locks) { - opts->rpc->has_file_locks = true; - opts->rpc->file_locks = file_locks; + opts->rpc->has_file_locks = true; + opts->rpc->file_locks = file_locks; } void criu_set_file_locks(bool file_locks) @@ -565,8 +565,8 @@ void criu_set_file_locks(bool file_locks) void criu_local_set_log_level(criu_opts *opts, int log_level) { - opts->rpc->has_log_level = true; - opts->rpc->log_level = log_level; + opts->rpc->has_log_level = true; + opts->rpc->log_level = log_level; } void criu_set_log_level(int log_level) @@ -697,8 +697,8 @@ int criu_set_log_file(const char *log_file) void criu_local_set_cpu_cap(criu_opts *opts, unsigned int cap) { - opts->rpc->has_cpu_cap = true; - opts->rpc->cpu_cap = cap; + opts->rpc->has_cpu_cap = true; + opts->rpc->cpu_cap = cap; } void criu_set_cpu_cap(unsigned int cap) @@ -1410,7 +1410,7 @@ exit: static int send_req_and_recv_resp(criu_opts *opts, CriuReq *req, CriuResp **resp) { int fd; - int ret = 0; + int ret = 0; bool d = false; if (req->type == CRIU_REQ_TYPE__DUMP && req->opts->has_pid == false) @@ -1431,12 +1431,12 @@ static int send_req_and_recv_resp(criu_opts *opts, CriuReq *req, CriuResp **resp int criu_local_check(criu_opts *opts) { int ret = -1; - CriuReq req = CRIU_REQ__INIT; - CriuResp *resp = NULL; + CriuReq req = CRIU_REQ__INIT; + CriuResp *resp = NULL; saved_errno = 0; - req.type = CRIU_REQ_TYPE__CHECK; + req.type = CRIU_REQ_TYPE__CHECK; ret = send_req_and_recv_resp(opts, &req, &resp); if (ret) @@ -1463,13 +1463,13 @@ int criu_check(void) int criu_local_dump(criu_opts *opts) { int ret = -1; - CriuReq req = CRIU_REQ__INIT; - CriuResp *resp = NULL; + CriuReq req = CRIU_REQ__INIT; + CriuResp *resp = NULL; saved_errno = 0; - req.type = CRIU_REQ_TYPE__DUMP; - req.opts = opts->rpc; + req.type = CRIU_REQ_TYPE__DUMP; + req.opts = opts->rpc; ret = send_req_and_recv_resp(opts, &req, &resp); if (ret) @@ -1502,13 +1502,13 @@ int criu_dump(void) int criu_local_dump_iters(criu_opts *opts, int (*more)(criu_predump_info pi)) { int ret = -1, fd = -1, uret; - CriuReq req = CRIU_REQ__INIT; - CriuResp *resp = NULL; + CriuReq req = CRIU_REQ__INIT; + CriuResp *resp = NULL; saved_errno = 0; - req.type = CRIU_REQ_TYPE__PRE_DUMP; - req.opts = opts->rpc; + req.type = CRIU_REQ_TYPE__PRE_DUMP; + req.opts = opts->rpc; ret = -EINVAL; /* @@ -1573,13 +1573,13 @@ int criu_dump_iters(int (*more)(criu_predump_info pi)) int criu_local_restore(criu_opts *opts) { int ret = -1; - CriuReq req = CRIU_REQ__INIT; - CriuResp *resp = NULL; + CriuReq req = CRIU_REQ__INIT; + CriuResp *resp = NULL; saved_errno = 0; - req.type = CRIU_REQ_TYPE__RESTORE; - req.opts = opts->rpc; + req.type = CRIU_REQ_TYPE__RESTORE; + req.opts = opts->rpc; ret = send_req_and_recv_resp(opts, &req, &resp); if (ret) @@ -1612,8 +1612,8 @@ int criu_local_restore_child(criu_opts *opts) enum criu_service_comm saved_comm; const char *saved_comm_data; bool save_comm; - CriuReq req = CRIU_REQ__INIT; - CriuResp *resp = NULL; + CriuReq req = CRIU_REQ__INIT; + CriuResp *resp = NULL; /* * restore_child is not possible with criu running as a system @@ -1644,8 +1644,8 @@ int criu_local_restore_child(criu_opts *opts) saved_errno = 0; - req.type = CRIU_REQ_TYPE__RESTORE; - req.opts = opts->rpc; + req.type = CRIU_REQ_TYPE__RESTORE; + req.opts = opts->rpc; req.opts->has_rst_sibling = true; req.opts->rst_sibling = true; From f3341025207ba960e36140bb24d63098cdd69a57 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Mon, 24 Feb 2020 18:30:59 +0000 Subject: [PATCH 2415/4375] libcriu: Add space between 'if' and parenthesis Signed-off-by: Radostin Stoyanov --- lib/c/criu.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/c/criu.c b/lib/c/criu.c index 7daac7dbf..de57a65dc 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -58,7 +58,7 @@ int criu_local_set_service_address(criu_opts *opts, const char *path) } else { opts->service_address = strdup(CR_DEFAULT_SERVICE_ADDRESS); } - if(opts->service_address == NULL) { + if (opts->service_address == NULL) { return -ENOMEM; } return 0; @@ -90,7 +90,7 @@ int criu_local_set_service_binary(criu_opts *opts, const char *path) } else { opts->service_binary = strdup(CR_DEFAULT_SERVICE_BIN); } - if(opts->service_binary == NULL) { + if (opts->service_binary == NULL) { return -ENOMEM; } return 0; @@ -118,7 +118,7 @@ void criu_local_free_opts(criu_opts *opts) } opts->rpc->n_exec_cmd = 0; - if(opts->rpc->unix_sk_ino) { + if (opts->rpc->unix_sk_ino) { for (i = 0; i < opts->rpc->n_unix_sk_ino; i++) { free(opts->rpc->unix_sk_ino[i]); } @@ -126,7 +126,7 @@ void criu_local_free_opts(criu_opts *opts) } opts->rpc->n_unix_sk_ino = 0; - if(opts->rpc->ext_mnt) { + if (opts->rpc->ext_mnt) { for (i = 0; i < opts->rpc->n_ext_mnt; i++) { if (opts->rpc->ext_mnt[i]) { free(opts->rpc->ext_mnt[i]->val); @@ -138,7 +138,7 @@ void criu_local_free_opts(criu_opts *opts) } opts->rpc->n_ext_mnt = 0; - if(opts->rpc->cg_root) { + if (opts->rpc->cg_root) { for (i = 0; i < opts->rpc->n_cg_root; i++) { if (opts->rpc->cg_root[i]) { free(opts->rpc->cg_root[i]->ctrl); @@ -150,7 +150,7 @@ void criu_local_free_opts(criu_opts *opts) } opts->rpc->n_cg_root = 0; - if(opts->rpc->veths) { + if (opts->rpc->veths) { for (i = 0; i < opts->rpc->n_veths; i++) { if (opts->rpc->veths[i]) { free(opts->rpc->veths[i]->if_in); @@ -162,7 +162,7 @@ void criu_local_free_opts(criu_opts *opts) } opts->rpc->n_veths = 0; - if(opts->rpc->enable_fs) { + if (opts->rpc->enable_fs) { for (i = 0; i < opts->rpc->n_enable_fs; i++) { free(opts->rpc->enable_fs[i]); } @@ -170,7 +170,7 @@ void criu_local_free_opts(criu_opts *opts) } opts->rpc->n_enable_fs = 0; - if(opts->rpc->skip_mnt) { + if (opts->rpc->skip_mnt) { for (i = 0; i < opts->rpc->n_skip_mnt; i++) { free(opts->rpc->skip_mnt[i]); } @@ -178,7 +178,7 @@ void criu_local_free_opts(criu_opts *opts) } opts->rpc->n_skip_mnt = 0; - if(opts->rpc->irmap_scan_paths) { + if (opts->rpc->irmap_scan_paths) { for (i = 0; i < opts->rpc->n_irmap_scan_paths; i++) { free(opts->rpc->irmap_scan_paths[i]); } @@ -186,7 +186,7 @@ void criu_local_free_opts(criu_opts *opts) } opts->rpc->n_irmap_scan_paths = 0; - if(opts->rpc->cgroup_dump_controller) { + if (opts->rpc->cgroup_dump_controller) { for (i = 0; i < opts->rpc->n_cgroup_dump_controller; i++) { free(opts->rpc->cgroup_dump_controller[i]); } @@ -194,7 +194,7 @@ void criu_local_free_opts(criu_opts *opts) } opts->rpc->n_cgroup_dump_controller = 0; - if(opts->rpc->inherit_fd) { + if (opts->rpc->inherit_fd) { for (i = 0; i < opts->rpc->n_inherit_fd; i++) { if (opts->rpc->inherit_fd[i]) { free(opts->rpc->inherit_fd[i]->key); @@ -205,7 +205,7 @@ void criu_local_free_opts(criu_opts *opts) } opts->rpc->n_inherit_fd = 0; - if(opts->rpc->external) { + if (opts->rpc->external) { for (i = 0; i < opts->rpc->n_external; i++) { free(opts->rpc->external[i]); } @@ -213,7 +213,7 @@ void criu_local_free_opts(criu_opts *opts) } opts->rpc->n_external = 0; - if(opts->rpc->ps) { + if (opts->rpc->ps) { free(opts->rpc->ps->address); free(opts->rpc->ps); } @@ -262,7 +262,7 @@ int criu_local_init_opts(criu_opts **o) opts->service_comm = CRIU_COMM_BIN; opts->service_binary = strdup(CR_DEFAULT_SERVICE_BIN); - if(opts->service_binary == NULL) { + if (opts->service_binary == NULL) { perror("Can't allocate memory for criu service setting"); criu_local_free_opts(opts); return -1; @@ -325,7 +325,7 @@ void criu_set_images_dir_fd(int fd) int criu_local_set_parent_images(criu_opts *opts, const char *path) { opts->rpc->parent_img = strdup(path); - if(opts->rpc->parent_img == NULL) { + if (opts->rpc->parent_img == NULL) { return -ENOMEM; } return 0; @@ -577,7 +577,7 @@ void criu_set_log_level(int log_level) int criu_local_set_root(criu_opts *opts, const char *root) { opts->rpc->root = strdup(root); - if(opts->rpc->root == NULL) { + if (opts->rpc->root == NULL) { return -ENOMEM; } return 0; @@ -613,7 +613,7 @@ void criu_set_manage_cgroups_mode(enum criu_cg_mode mode) int criu_local_set_freeze_cgroup(criu_opts *opts, const char *name) { opts->rpc->freeze_cgroup = strdup(name); - if(opts->rpc->freeze_cgroup == NULL) { + if (opts->rpc->freeze_cgroup == NULL) { return -ENOMEM; } return 0; @@ -627,7 +627,7 @@ int criu_set_freeze_cgroup(const char *name) int criu_local_set_lsm_profile(criu_opts *opts, const char *name) { opts->rpc->lsm_profile = strdup(name); - if(opts->rpc->lsm_profile == NULL) { + if (opts->rpc->lsm_profile == NULL) { return -ENOMEM; } return 0; @@ -684,7 +684,7 @@ void criu_set_ext_masters(bool val) int criu_local_set_log_file(criu_opts *opts, const char *log_file) { opts->rpc->log_file = strdup(log_file); - if(opts->rpc->log_file == NULL) { + if (opts->rpc->log_file == NULL) { return -ENOMEM; } return 0; From 64347398c10b5911d0f1acd2db5c856b4b1fe464 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 20 May 2020 11:57:22 +0000 Subject: [PATCH 2416/4375] coverity: fix RESOURCE_LEAK criu/timens.c: 67 7. criu-3.14/criu/timens.c:67: leaked_storage: Variable "img" going out of scope leaks the storage it points to. 65| if (id == 0 && empty_image(img)) { 66| pr_warn("Clocks values have not been dumped\n"); 67|-> return 0; 68| } Signed-off-by: Adrian Reber --- criu/timens.c | 1 + 1 file changed, 1 insertion(+) diff --git a/criu/timens.c b/criu/timens.c index 2a7e95284..f81808abf 100644 --- a/criu/timens.c +++ b/criu/timens.c @@ -64,6 +64,7 @@ int prepare_timens(int id) if (id == 0 && empty_image(img)) { pr_warn("Clocks values have not been dumped\n"); + close_image(img); return 0; } From b4c51ea492c98011472dd28a7cb47bffcfb4ad20 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 20 May 2020 12:19:36 +0000 Subject: [PATCH 2417/4375] coverity: fix FORWARD_NULL in criu/proc_parse.c: 1481 8. criu-3.14/criu/proc_parse.c:1511: var_deref_model: Passing null pointer "f" to "fclose", which dereferences it. 1509| exit_code = 0; 1510| out: 1511|-> fclose(f); 1512| return exit_code; 1513| } Signed-off-by: Adrian Reber --- criu/proc_parse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 4a22700aa..d1ccd9281 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1480,7 +1480,7 @@ int parse_timens_offsets(struct timespec *boff, struct timespec *moff) f = fopen_proc(PROC_SELF, "timens_offsets"); if (!f) { pr_perror("Unable to open /proc/self/timens_offsets"); - goto out; + return exit_code; } while (fgets(buf, BUF_SIZE, f)) { int64_t sec, nsec; From e34f5dd3a351dc2e475fa235c25ed115ac996644 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 20 May 2020 12:38:55 +0000 Subject: [PATCH 2418/4375] clang: Branch condition evaluates to a garbage value criu-3.14/criu/namespaces.c:692:7: warning: Branch condition evaluates to a garbage value criu-3.14/criu/namespaces.c:690:3: note: 'supported' declared without an initial value protobuf_c_boolean supported; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ criu-3.14/criu/namespaces.c:691:8: note: Calling 'get_ns_id' id = get_ns_id(pid, &time_for_children_ns_desc, &supported); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ criu-3.14/criu/namespaces.c:479:9: note: Calling '__get_ns_id' return __get_ns_id(pid, nd, supported, NULL); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ criu-3.14/criu/namespaces.c:454:6: note: Assuming 'proc_dir' is < 0 if (proc_dir < 0) ^~~~~~~~~~~~ criu-3.14/criu/namespaces.c:454:2: note: Taking true branch if (proc_dir < 0) ^ criu-3.14/criu/namespaces.c:455:3: note: Returning without writing to '*supported' return 0; ^ criu-3.14/criu/namespaces.c:479:9: note: Returning from '__get_ns_id' return __get_ns_id(pid, nd, supported, NULL); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ criu-3.14/criu/namespaces.c:479:2: note: Returning without writing to '*supported' return __get_ns_id(pid, nd, supported, NULL); ^ criu-3.14/criu/namespaces.c:691:8: note: Returning from 'get_ns_id' id = get_ns_id(pid, &time_for_children_ns_desc, &supported); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ criu-3.14/criu/namespaces.c:692:7: note: Branch condition evaluates to a garbage value if (!supported || !id) { ^~~~~~~~~~ 690| protobuf_c_boolean supported; 691| id = get_ns_id(pid, &time_for_children_ns_desc, &supported); 692|-> if (!supported || !id) { 693| pr_err("Can't make timens id\n"); 694| Signed-off-by: Adrian Reber --- criu/namespaces.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/namespaces.c b/criu/namespaces.c index 89d97c7bc..04f242505 100644 --- a/criu/namespaces.c +++ b/criu/namespaces.c @@ -687,7 +687,7 @@ int dump_task_ns_ids(struct pstree_item *item) } if (ids->has_time_ns_id) { unsigned int id; - protobuf_c_boolean supported; + protobuf_c_boolean supported = false; id = get_ns_id(pid, &time_for_children_ns_desc, &supported); if (!supported || !id) { pr_err("Can't make timens id\n"); From faf6dbf33e04eb8a0907f44b2787022b14a840e0 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 15 May 2020 18:21:25 -0700 Subject: [PATCH 2419/4375] close_service_fd: rename to status_ready The name close_service_fd() is misleading, as it not just closes the status_fd, but also writes to it. On a high level, though, it signals the other side that we are ready, so rename to status_ready. Signed-off-by: Kir Kolyshkin --- criu/cr-service.c | 2 +- criu/include/util.h | 2 +- criu/uffd.c | 2 +- criu/util.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/criu/cr-service.c b/criu/cr-service.c index 7c2ff9835..7201b549a 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -1394,7 +1394,7 @@ int cr_service(bool daemon_mode) if (setup_sigchld_handler()) goto err; - if (close_status_fd()) + if (status_ready()) goto err; while (1) { diff --git a/criu/include/util.h b/criu/include/util.h index d67f6d39d..1b22d9e0b 100644 --- a/criu/include/util.h +++ b/criu/include/util.h @@ -177,7 +177,7 @@ extern int cr_system(int in, int out, int err, char *cmd, char *const argv[], un extern int cr_system_userns(int in, int out, int err, char *cmd, char *const argv[], unsigned flags, int userns_pid); extern int cr_daemon(int nochdir, int noclose, int close_fd); -extern int close_status_fd(void); +extern int status_ready(void); extern int is_root_user(void); extern void set_proc_self_fd(int fd); diff --git a/criu/uffd.c b/criu/uffd.c index 99373c04d..33b34ba25 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1456,7 +1456,7 @@ int cr_lazy_pages(bool daemon) } } - if (close_status_fd()) + if (status_ready()) return -1; /* diff --git a/criu/util.c b/criu/util.c index 517f0fc25..0a60fa105 100644 --- a/criu/util.c +++ b/criu/util.c @@ -643,7 +643,7 @@ out: return ret; } -int close_status_fd(void) +int status_ready(void) { char c = 0; @@ -1105,7 +1105,7 @@ int run_tcp_server(bool daemon_mode, int *ask, int cfd, int sk) } } - if (close_status_fd()) + if (status_ready()) return -1; if (sk >= 0) { From 62c03530c9d6e0a1012a589ed1a26c2612113238 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 15 May 2020 18:12:30 -0700 Subject: [PATCH 2420/4375] swrk: send notification instead of using status fd When we use swrk, we have a mechanism to send notifications over RPC. It is cleaner and more straightforward than sending \0 to status fd. For now, both mechanisms are supported, although status fd request option is now deprecated, so a warning is logged in case it's used. Guess we can remove it in a few years. Signed-off-by: Kir Kolyshkin --- criu/action-scripts.c | 1 + criu/cr-service.c | 2 ++ criu/include/action-scripts.h | 1 + criu/util.c | 4 ++++ 4 files changed, 8 insertions(+) diff --git a/criu/action-scripts.c b/criu/action-scripts.c index 2f7617c0f..5337efa64 100644 --- a/criu/action-scripts.c +++ b/criu/action-scripts.c @@ -29,6 +29,7 @@ static const char *action_names[ACT_MAX] = { [ ACT_PRE_RESUME ] = "pre-resume", [ ACT_POST_RESUME ] = "post-resume", [ ACT_ORPHAN_PTS_MASTER ] = "orphan-pts-master", + [ ACT_STATUS_READY ] = "status-ready", }; struct script { diff --git a/criu/cr-service.c b/criu/cr-service.c index 7201b549a..56be6bcd3 100644 --- a/criu/cr-service.c +++ b/criu/cr-service.c @@ -678,6 +678,8 @@ static int setup_opts_from_req(int sk, CriuOpts *req) } if (req->has_status_fd) { + pr_warn("status_fd is obsoleted; use status-ready notification instead\n"); + sprintf(status_fd, "/proc/%d/fd/%d", ids.pid, req->status_fd); opts.status_fd = open(status_fd, O_WRONLY); if (opts.status_fd < 0) { diff --git a/criu/include/action-scripts.h b/criu/include/action-scripts.h index 40b09b160..c2e8850aa 100644 --- a/criu/include/action-scripts.h +++ b/criu/include/action-scripts.h @@ -15,6 +15,7 @@ enum script_actions { ACT_POST_RESUME, ACT_PRE_RESUME, ACT_ORPHAN_PTS_MASTER, + ACT_STATUS_READY, ACT_MAX }; diff --git a/criu/util.c b/criu/util.c index 0a60fa105..4c1f3b4ca 100644 --- a/criu/util.c +++ b/criu/util.c @@ -45,6 +45,7 @@ #include "pstree.h" #include "cr-errno.h" +#include "action-scripts.h" #define VMA_OPT_LEN 128 @@ -647,6 +648,9 @@ int status_ready(void) { char c = 0; + if (run_scripts(ACT_STATUS_READY)) + return -1; + if (opts.status_fd < 0) return 0; From e57e74a18df0b7bbfb2fa556941fc7c8715e57d1 Mon Sep 17 00:00:00 2001 From: ZeyadYasser Date: Thu, 16 Apr 2020 15:58:18 +0200 Subject: [PATCH 2421/4375] criu: optimize find_unix_sk_by_ino() Fixes: #339 Replaced the linear search with a hashtable lookup. Signed-off-by: Zeyad Yasser --- criu/files.c | 1 + criu/include/sockets.h | 2 ++ criu/sk-unix.c | 19 ++++++++++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/criu/files.c b/criu/files.c index a1fd26764..2cfc9040e 100644 --- a/criu/files.c +++ b/criu/files.c @@ -1749,5 +1749,6 @@ struct collect_image_info files_cinfo = { int prepare_files(void) { init_fdesc_hash(); + init_sk_info_hash(); return collect_image(&files_cinfo); } diff --git a/criu/include/sockets.h b/criu/include/sockets.h index cd98d18e0..e971f3efd 100644 --- a/criu/include/sockets.h +++ b/criu/include/sockets.h @@ -62,6 +62,8 @@ extern int unix_sk_id_add(unsigned int ino); extern int unix_sk_ids_parse(char *optarg); extern int unix_prepare_root_shared(void); +extern void init_sk_info_hash(void); + extern int do_dump_opt(int sk, int level, int name, void *val, int len); #define dump_opt(s, l, n, f) do_dump_opt(s, l, n, f, sizeof(*f)) extern int do_restore_opt(int sk, int level, int name, void *val, int len); diff --git a/criu/sk-unix.c b/criu/sk-unix.c index 048ff44ae..cbcf1f66c 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -903,6 +903,7 @@ struct unix_sk_info { struct unix_sk_info *peer; struct pprep_head peer_resolve; /* XXX : union with the above? */ struct file_desc d; + struct hlist_node hash; /* To lookup socket by ino */ struct list_head connected; /* List of sockets, connected to me */ struct list_head node; /* To link in peer's connected list */ struct list_head scm_fles; @@ -934,11 +935,25 @@ struct scm_fle { #define USK_PAIR_SLAVE 0x2 #define USK_GHOST_FDSTORE 0x4 /* bound but removed address */ +#define SK_INFO_HASH_SIZE 32 + +static struct hlist_head sk_info_hash[SK_INFO_HASH_SIZE]; + +void init_sk_info_hash(void) +{ + int i; + + for (i = 0; i < SK_INFO_HASH_SIZE; i++) + INIT_HLIST_HEAD(&sk_info_hash[i]); +} + static struct unix_sk_info *find_unix_sk_by_ino(int ino) { struct unix_sk_info *ui; + struct hlist_head *chain; - list_for_each_entry(ui, &unix_sockets, list) { + chain = &sk_info_hash[ino % SK_INFO_HASH_SIZE]; + hlist_for_each_entry(ui, chain, hash) { if (ui->ue->ino == ino) return ui; } @@ -2044,6 +2059,7 @@ static int init_unix_sk_info(struct unix_sk_info *ui, UnixSkEntry *ue) INIT_LIST_HEAD(&ui->node); INIT_LIST_HEAD(&ui->scm_fles); INIT_LIST_HEAD(&ui->ghost_node); + INIT_HLIST_NODE(&ui->hash); return 0; } @@ -2135,6 +2151,7 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i) list_add_tail(&ui->ghost_node, &unix_ghost_addr); } + hlist_add_head(&ui->hash, &sk_info_hash[ui->ue->ino % SK_INFO_HASH_SIZE]); list_add_tail(&ui->list, &unix_sockets); return file_desc_add(&ui->d, ui->ue->id, &unix_desc_ops); } From 55f71b8667043fb8241bc500a96c20644d478eba Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 23 Apr 2020 14:13:15 +0000 Subject: [PATCH 2422/4375] lib/c: add criu_get_version() Although the CRIU version is exported in macros in version.h it only contains the CRIU version of libcriu during build time. As it is possible that CRIU is upgraded since the last time something was built against libcriu, this adds functions to query the actual CRIU binary about its version. Signed-off-by: Adrian Reber --- lib/c/criu.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/c/criu.h | 32 ++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/lib/c/criu.c b/lib/c/criu.c index de57a65dc..d052f8d1f 100644 --- a/lib/c/criu.c +++ b/lib/c/criu.c @@ -1668,3 +1668,68 @@ int criu_restore_child(void) { return criu_local_restore_child(global_opts); } + +int criu_local_get_version(criu_opts *opts) +{ + int ret = -1; + CriuReq req = CRIU_REQ__INIT; + CriuResp *resp = NULL; + + saved_errno = 0; + + req.type = CRIU_REQ_TYPE__VERSION; + req.opts = opts->rpc; + + ret = send_req_and_recv_resp(opts, &req, &resp); + if (ret) + goto exit; + + if (resp->success) { + ret = resp->version->major_number * 10000; + ret += resp->version->minor_number * 100; + if (resp->version->has_sublevel) + ret += resp->version->sublevel; + if (resp->version->gitid) { + /* Taken from runc: a git release -> minor + 1 */ + ret -= (ret % 100); + ret += 100; + } + } else { + ret = -EBADE; + } + +exit: + if (resp) + criu_resp__free_unpacked(resp, NULL); + + swrk_wait(opts); + + errno = saved_errno; + + return ret; +} + +int criu_get_version(void) +{ + return criu_local_get_version(global_opts); +} + +int criu_local_check_version(criu_opts *opts, int minimum) +{ + int version; + + version = criu_local_get_version(opts); + + if (version < 0) + return version; + + if (minimum <= version) + return 1; + + return 0; +} + +int criu_check_version(int minimum) +{ + return criu_local_check_version(global_opts, minimum); +} diff --git a/lib/c/criu.h b/lib/c/criu.h index 3a9204f5b..49f7a7005 100644 --- a/lib/c/criu.h +++ b/lib/c/criu.h @@ -158,6 +158,35 @@ int criu_restore_child(void); typedef void *criu_predump_info; int criu_dump_iters(int (*more)(criu_predump_info pi)); +/* + * Get the version of the actual binary used for RPC. + * + * As this library is just forwarding all tasks to an + * independent (of this library) CRIU binary, the actual + * version of the CRIU binary can be different then the + * hardcoded values in the libary (version.h). + * To be able to easily check the version of the CRIU binary + * the function criu_get_version() returns the version + * in the following format: + * + * (major * 10000) + (minor * 100) + sublevel + * + * If the CRIU binary has been built from a git checkout + * minor will increased by one. + */ +int criu_get_version(void); + +/* + * Check if the version of the CRIU binary is at least + * 'minimum'. Version has to be in the same format as + * described for criu_get_version(). + * + * Returns 1 if CRIU is at least 'minimum'. + * Returns 0 if CRIU is too old. + * Returns < 0 if there was an error. + */ +int criu_check_version(int minimum); + /* * Same as the list above, but lets you have your very own options * structure and lets you set individual options in it. @@ -229,6 +258,9 @@ int criu_local_restore(criu_opts *opts); int criu_local_restore_child(criu_opts *opts); int criu_local_dump_iters(criu_opts *opts, int (*more)(criu_predump_info pi)); +int criu_local_get_version(criu_opts *opts); +int criu_local_check_version(criu_opts *opts, int minimum); + #ifdef __GNUG__ } #endif From 047ecd3a15f83b15535943c2c87e0c55b4866dd9 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 23 Apr 2020 14:28:00 +0000 Subject: [PATCH 2423/4375] test/others/libcriu: test version library calls This adds the previously added libcriu version functions to the libcriu tests. Signed-off-by: Adrian Reber --- test/others/libcriu/lib.c | 7 ++++++- test/others/libcriu/lib.h | 1 + test/others/libcriu/test_self.c | 13 +++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/test/others/libcriu/lib.c b/test/others/libcriu/lib.c index 33aa4090d..0c7929cda 100644 --- a/test/others/libcriu/lib.c +++ b/test/others/libcriu/lib.c @@ -2,6 +2,8 @@ #include #include +#include "criu.h" + void what_err_ret_mean(int ret) { /* NOTE: errno is set by libcriu */ @@ -44,4 +46,7 @@ int chk_exit(int status, int want) return 1; } - +int get_version() +{ + printf("Using a CRIU binary with version %d\n", criu_get_version()); +} diff --git a/test/others/libcriu/lib.h b/test/others/libcriu/lib.h index 67b784bff..6fdf8aef2 100644 --- a/test/others/libcriu/lib.h +++ b/test/others/libcriu/lib.h @@ -1,2 +1,3 @@ void what_err_ret_mean(int ret); int chk_exit(int status, int want); +int get_version(void); diff --git a/test/others/libcriu/test_self.c b/test/others/libcriu/test_self.c index c9d2a2e64..374a4b545 100644 --- a/test/others/libcriu/test_self.c +++ b/test/others/libcriu/test_self.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,18 @@ int main(int argc, char *argv[]) criu_init_opts(); criu_set_service_binary(argv[1]); + + get_version(); + if (!criu_check_version(31400)) { + printf("CRIU version check failed. CRIU too old\n"); + return 1; + } + + if (criu_check_version(INT_MAX)) { + printf("CRIU version check failed. CRIU too new.\n"); + return 1; + } + criu_set_images_dir_fd(fd); criu_set_log_level(4); From d72428b7c4254c2e3587d8d84f16626302e7e111 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 23 Apr 2020 09:11:48 +0000 Subject: [PATCH 2424/4375] Also report clone3() errors correctly Without clone3() CRIU was able to detect a process with a wrong PID only in the already created child process. With clone3() this error can happen before the process is created. In the case of EEXIST this error will now be correctly forwarded to an RPC client. This was detected by running test/others/libcriu on a clone3() system. Signed-off-by: Adrian Reber --- criu/clone-noasan.c | 1 + criu/cr-restore.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/criu/clone-noasan.c b/criu/clone-noasan.c index a2190ba0a..35c40c21d 100644 --- a/criu/clone-noasan.c +++ b/criu/clone-noasan.c @@ -70,6 +70,7 @@ int clone3_with_pid_noasan(int (*fn)(void *), void *arg, int flags, if (!(flags & CLONE_PARENT)) { if (exit_signal != SIGCHLD) { pr_err("Exit signal not SIGCHLD\n"); + errno = EINVAL; return -1; } c_args.exit_signal = exit_signal; diff --git a/criu/cr-restore.c b/criu/cr-restore.c index ec00bf71b..e44ba308d 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -1439,6 +1439,8 @@ static inline int fork_with_pid(struct pstree_item *item) if (ret < 0) { pr_perror("Can't fork for %d", pid); + if (errno == EEXIST) + set_cr_errno(EEXIST); goto err_unlock; } From cbf099400a24debe4eaf830bd81138bb73a46a00 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Sat, 8 Feb 2020 16:58:36 +0100 Subject: [PATCH 2425/4375] Travis: use Vagrant to run VMs This adds the minimal configuration to run Fedora 31 based VMs on Travis. This can be used to test cgroupv2 based tests, tests with vdso=off and probably much more which requires booting a newer kernel. As an example this builds CRIU on Fedora 31 and reconfigures it to boot without VDSO support and runs one single test. Signed-off-by: Adrian Reber --- .travis.yml | 1 + scripts/travis/Makefile | 8 ++++++ scripts/travis/vagrant.sh | 53 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100755 scripts/travis/vagrant.sh diff --git a/.travis.yml b/.travis.yml index e71afa0a3..8ada90193 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ env: - TR_ARCH=x86_64 - TR_ARCH=x86_64 CLANG=1 - TR_ARCH=openj9-test + - TR_ARCH=vagrant-fedora-no-vdso jobs: include: - os: linux diff --git a/scripts/travis/Makefile b/scripts/travis/Makefile index 17abb703a..1af60fe8d 100644 --- a/scripts/travis/Makefile +++ b/scripts/travis/Makefile @@ -64,5 +64,13 @@ podman-test: openj9-test: restart-docker ./openj9-test.sh +setup-vagrant: + ./vagrant.sh setup + +vagrant-fedora-no-vdso: setup-vagrant + ./vagrant.sh fedora-no-vdso + +.PHONY: setup-vagrant vagrant-fedora-no-vdso + %: $(MAKE) -C ../build $@$(target-suffix) diff --git a/scripts/travis/vagrant.sh b/scripts/travis/vagrant.sh new file mode 100755 index 000000000..943a8b9a3 --- /dev/null +++ b/scripts/travis/vagrant.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# This script is used to run vagrant based tests on Travis. +# This script is started via sudo from .travis.yml + +set -e +set -x + +VAGRANT_VERSION=2.2.7 +FEDORA_VERSION=31 +FEDORA_BOX_VERSION=31.20191023.0 + +setup() { + apt-get -qq update + # Load the kvm modules for vagrant to use qemu + modprobe kvm kvm_intel + + # Tar up the git checkout to have vagrant rsync it to the VM + tar cf criu.tar ../../../criu + wget https://releases.hashicorp.com/vagrant/${VAGRANT_VERSION}/vagrant_${VAGRANT_VERSION}_$(uname -m).deb -O /tmp/vagrant.deb && \ + dpkg -i /tmp/vagrant.deb + + apt-get -qq install -y libvirt-bin libvirt-dev qemu-utils qemu + systemctl restart libvirt-bin + vagrant plugin install vagrant-libvirt + vagrant init fedora/${FEDORA_VERSION}-cloud-base --box-version ${FEDORA_BOX_VERSION} + # The default libvirt Vagrant VM uses 512MB. + # Travis VMs should have around 7.5GB. + # Increasing it to 4GB should work. + sed -i Vagrantfile -e 's,^end$, config.vm.provider :libvirt do |libvirt|'"\n"' libvirt.memory = 4096;end'"\n"'end,g' + vagrant up --provider=libvirt + mkdir -p /root/.ssh + vagrant ssh-config >> /root/.ssh/config + ssh default sudo dnf install -y gcc git gnutls-devel nftables-devel libaio-devel \ + libasan libcap-devel libnet-devel libnl3-devel make protobuf-c-devel \ + protobuf-devel python3-flake8 python3-future python3-protobuf \ + python3-junit_xml rubygem-asciidoctor iptables libselinux-devel + # Disable sssd to avoid zdtm test failures in pty04 due to sssd socket + ssh default sudo systemctl mask sssd + ssh default cat /proc/cmdline +} + +fedora-no-vdso() { + ssh default sudo grubby --update-kernel ALL --args="vdso=0" + vagrant reload + ssh default cat /proc/cmdline + ssh default 'cd /vagrant; tar xf criu.tar; cd criu; make -j 4' + # Excluding the VDSO test as we are running without VDSO + # Excluding two cgroup tests which seem to fail because of cgroup2 + ssh default 'cd /vagrant/criu/test; sudo ./zdtm.py run -a -x zdtm/static/cgroup04 -x zdtm/static/cgroup_ifpriomap -x zdtm/static/vdso01 --keep-going' +} + +$1 From 1d9438aefbd1609ee765f7e958b88883f402a662 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 28 Apr 2020 19:00:42 -0700 Subject: [PATCH 2426/4375] criu swrk: fix usage, allow common options TL;DR: this makes possible -v with criu swrk, and removes showing usage which is useless in swrk mode. 1. Since criu swrk command is not described in usage, there is no sense in showing it. Instead, show a one-line hint about how to use it. 2. In case some global options (like -v) are used, argv[1] might not point to "swrk". Use optind to point to a correct non-option argument. 3. While at it, also error out in case we have extra arguments. Signed-off-by: Kir Kolyshkin --- criu/crtools.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/criu/crtools.c b/criu/crtools.c index 76172f350..b696898e7 100644 --- a/criu/crtools.c +++ b/criu/crtools.c @@ -100,12 +100,18 @@ int main(int argc, char *argv[], char *envp[]) return 1; if (ret == 2) goto usage; + if (optind >= argc) { + pr_err("command is required\n"); + goto usage; + } log_set_loglevel(opts.log_level); - if (!strcmp(argv[1], "swrk")) { - if (argc < 3) - goto usage; + if (optind < argc && !strcmp(argv[optind], "swrk")) { + if (argc != optind+2) { + fprintf(stderr, "Usage: criu swrk \n"); + return 1; + } /* * This is to start criu service worker from libcriu calls. * The usage is "criu swrk " and is not for CLI/scripts. @@ -113,7 +119,7 @@ int main(int argc, char *argv[], char *envp[]) * corresponding lib call change. */ opts.swrk_restore = true; - return cr_service_work(atoi(argv[2])); + return cr_service_work(atoi(argv[optind+1])); } if (check_options()) @@ -125,11 +131,6 @@ int main(int argc, char *argv[], char *envp[]) if (opts.work_dir == NULL) SET_CHAR_OPTS(work_dir, opts.imgs_dir); - if (optind >= argc) { - pr_err("command is required\n"); - goto usage; - } - has_sub_command = (argc - optind) > 1; if (has_exec_cmd) { From 6ee4b72382f72362ab746876cf32a70712eb89f9 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 18 May 2020 11:19:23 +0300 Subject: [PATCH 2427/4375] arch/x86: Fix calculation of xstate_size The layout of xsave frame in a standart format is predefined by the hardware. Lets make sure we're increasing in frame offsets and use latest offset where appropriate. https://github.com/checkpoint-restore/criu/issues/1042 Reported-by: Ashutosh Mehra Signed-off-by: Cyrill Gorcunov --- criu/arch/x86/crtools.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c index 9c8beeedd..bc8022535 100644 --- a/criu/arch/x86/crtools.c +++ b/criu/arch/x86/crtools.c @@ -437,6 +437,7 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) void *from = xsave->member; \ size_t size = pb_repeated_size(xsave, member); \ size_t xsize = (size_t)compel_fpu_feature_size(feature); \ + size_t xstate_size_next = off + xsize; \ if (xsize != size) { \ if (size) { \ pr_err("%s reported %zu bytes (expecting %zu)\n",\ @@ -448,7 +449,8 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) } \ } \ xstate_bv |= (1UL << feature); \ - xstate_size += xsize; \ + BUG_ON(xstate_size > xstate_size_next); \ + xstate_size = xstate_size_next; \ memcpy(to, from, size); \ } \ } while (0) @@ -485,6 +487,11 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) UserX86XsaveEntry *xsave = core->thread_info->fpregs->xsave; uint8_t *extended_state_area = (void *)x; + /* + * Note the order does matter here and bound + * to the increasing offsets of XFEATURE_x + * inside memory layout (xstate_size calculation). + */ assign_xsave(XFEATURE_YMM, xsave, ymmh_space, extended_state_area); assign_xsave(XFEATURE_BNDREGS, xsave, bndreg_state, extended_state_area); assign_xsave(XFEATURE_BNDCSR, xsave, bndcsr_state, extended_state_area); From 808684c99eb4c0cf12a5725cd6bbe3fea191273c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 9 Jun 2020 16:52:10 +0300 Subject: [PATCH 2428/4375] Add CONTRIBUTING.md Move the existing contribution guidelines to a dedicated file for future extensions. Signed-off-by: Mike Rapoport --- CONTRIBUTING.md | 19 +++++++++++++++++++ README.md | 20 +++++--------------- 2 files changed, 24 insertions(+), 15 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..342619e88 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,19 @@ +[![master](https://travis-ci.org/checkpoint-restore/criu.svg?branch=master)](https://travis-ci.org/checkpoint-restore/criu) +[![development](https://travis-ci.org/checkpoint-restore/criu.svg?branch=criu-dev)](https://travis-ci.org/checkpoint-restore/criu) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/55251ec7db28421da4481fc7c1cb0cee)](https://www.codacy.com/app/xemul/criu?utm_source=github.com&utm_medium=referral&utm_content=xemul/criu&utm_campaign=Badge_Grade) +

+ +## How to contribute to CRIU + +CRIU project is (almost) the never-ending story, because we have to always keep up with the +Linux kernel supporting checkpoint and restore for all the features it provides. Thus we're +looking for contributors of all kinds -- feedback, bug reports, testing, coding, writing, etc. +Here are some useful hints to get involved. + +* We have both -- [very simple](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) and [more sophisticated](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3A%22new+feature%22) coding tasks; +* CRIU does need [extensive testing](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Atesting); +* Documentation is always hard, we have [some information](https://criu.org/Category:Empty_articles) that is to be extracted from people's heads into wiki pages as well as [some texts](https://criu.org/Category:Editor_help_needed) that all need to be converted into useful articles; +* Feedback is expected on the github issues page and on the [mailing list](https://lists.openvz.org/mailman/listinfo/criu); +* We accept github pull requests and this is the preferred way to contribute to CRIU. If you prefer to send patches by email, you are welcome to send them to [the devel list](http://criu.org/How_to_submit_patches); +* Spread the word about CRIU in [social networks](http://criu.org/Contacts); +* If you're giving a talk about CRIU -- let us know, we'll mention it on the [wiki main page](https://criu.org/News/events); diff --git a/README.md b/README.md index 6a578b953..d703638ec 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,11 @@ project is that it is mainly implemented in user space. There are some more proj doing C/R for Linux, and so far CRIU [appears to be](https://criu.org/Comparison_to_other_CR_projects) the most feature-rich and up-to-date with the kernel. +CRIU project is (almost) the never-ending story, because we have to always keep up with the +Linux kernel supporting checkpoint and restore for all the features it provides. Thus we're +looking for contributors of all kinds -- feedback, bug reports, testing, coding, writing, etc. +Please refer to [CONTRIBUTING.md](CONTRIBUTING.md) if you would like to get involved. + The project [started](https://criu.org/History) as the way to do live migration for OpenVZ Linux containers, but later grew to more sophisticated and flexible tool. It is currently used by (integrated into) OpenVZ, LXC/LXD, Docker, and other software, project gets tremendous @@ -56,21 +61,6 @@ One of the CRIU features is the ability to save and restore state of a TCP socke without breaking the connection. This functionality is considered to be useful by itself, and we have it available as the [libsoccr library](https://criu.org/Libsoccr). -## How to contribute - -CRIU project is (almost) the never-ending story, because we have to always keep up with the -Linux kernel supporting checkpoint and restore for all the features it provides. Thus we're -looking for contributors of all kinds -- feedback, bug reports, testing, coding, writing, etc. -Here are some useful hints to get involved. - -* We have both -- [very simple](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) and [more sophisticated](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3A%22new+feature%22) coding tasks; -* CRIU does need [extensive testing](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Atesting); -* Documentation is always hard, we have [some information](https://criu.org/Category:Empty_articles) that is to be extracted from people's heads into wiki pages as well as [some texts](https://criu.org/Category:Editor_help_needed) that all need to be converted into useful articles; -* Feedback is expected on the github issues page and on the [mailing list](https://lists.openvz.org/mailman/listinfo/criu); -* We accept github pull requests and this is the preferred way to contribute to CRIU. If you prefer to send patches by email, you are welcome to send them to [the devel list](http://criu.org/How_to_submit_patches); -* Spread the word about CRIU in [social networks](http://criu.org/Contacts); -* If you're giving a talk about CRIU -- let us know, we'll mention it on the [wiki main page](https://criu.org/News/events); - ## Licence The project is licensed under GPLv2 (though files sitting in the lib/ directory are LGPLv2.1). From d0fcb01d47de8d5c659cc09d0ab5d994d10b5ffa Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 9 Jun 2020 16:52:11 +0300 Subject: [PATCH 2429/4375] CONTRIBUTING.md: import "How to submit patches" from criu.org Import "How to submit patches" article from CRIU wiki and update its format to match GitHub markdown. Signed-off-by: Mike Rapoport --- CONTRIBUTING.md | 200 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 199 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 342619e88..edb7ecb48 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,6 +14,204 @@ Here are some useful hints to get involved. * CRIU does need [extensive testing](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Atesting); * Documentation is always hard, we have [some information](https://criu.org/Category:Empty_articles) that is to be extracted from people's heads into wiki pages as well as [some texts](https://criu.org/Category:Editor_help_needed) that all need to be converted into useful articles; * Feedback is expected on the github issues page and on the [mailing list](https://lists.openvz.org/mailman/listinfo/criu); -* We accept github pull requests and this is the preferred way to contribute to CRIU. If you prefer to send patches by email, you are welcome to send them to [the devel list](http://criu.org/How_to_submit_patches); +* We accept github pull requests and this is the preferred way to contribute to CRIU. If you prefer to send patches by email, you are welcome to send them to [CRIU development mailing list](https://lists.openvz.org/mailman/listinfo/criu). +Below we describe in more detail recommend practices for CRIU developemnt. * Spread the word about CRIU in [social networks](http://criu.org/Contacts); * If you're giving a talk about CRIU -- let us know, we'll mention it on the [wiki main page](https://criu.org/News/events); + +### Seting up the developemnt environment + +Although criu could be run as non-root (see [Security](https://criu.org/Security), development is better to be done as root. For example, some tests require root. So, it would be a good idea to set up some recent Linux distro on a virtual machine. + +### Get the source code + +The CRIU sources are tracked by Git. Official CRIU repo is at https://github.com/checkpoint-restore/criu. + +The repository may contain multiple branches. Development happens in the **criu-dev** branch. + +To clone CRIU repo and switch to the proper branch, run: + +``` + git clone https://github.com/checkpoint-restore/criu criu + cd criu + git checkout criu-dev +``` + +### Compile + +First, you need to install compile-time dependencies. Check [Installation dependencies](https://criu.org/Installation#Dependencies) for more info. + +To compile CRIU, run: + +``` + make +``` + +This should create the `./criu/criu` executable. + +## Edit the source code + +If you use ctags, you can generate the ctags file by running + +``` + make tags +``` + +When you change the source code, please keep in mind the following code conventions: + +* we prefer tabs and indentations to be 8 characters width +* CRIU mostly follows [Linux kernel coding style](https://www.kernel.org/doc/Documentation/process/coding-style.rst), but we are less strict than the kernel community. + +Other conventions can be learned from the source code itself. In short, make sure your new code +looks similar to what is already there. + +## Test your changes + +CRIU comes with an extensive test suite. To check whether your changes introduce any regressions, run + +``` + make test +``` + +The command runs [ZDTM Test Suite](https://criu.org/ZDTM_Test_Suite). Check for any error messages produced by it. + +In case you'd rather have someone else run the tests, you can use travis-ci for your +own github fork of CRIU. It will check the compilation for various supported platforms, +as well as run most of the tests from the suite. See https://travis-ci.org/checkpoint-restore/criu +for more details. + +## Sign your work + +To improve tracking of who did what, we ask you to sign off the patches +that are to be emailed. + +The sign-off is a simple line at the end of the explanation for the +patch, which certifies that you wrote it or otherwise have the right to +pass it on as an open-source patch. The rules are pretty simple: if you +can certify the below: + +### Developer's Certificate of Origin 1.1 + By making a contribution to this project, I certify that: + + (a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + + (b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + + (c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + + (d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. + +then you just add a line saying + +``` + Signed-off-by: Random J Developer +``` + +using your real name (please, no pseudonyms or anonymous contributions if +it possible). + +Hint: you can use `git commit -s` to add Signed-off-by line to your +commit message. To append such line to a commit you already made, use +`git commit --amend -s`. + +``` + From: Random J Developer + Subject: [PATCH] Short patch description + + Long patch description (could be skipped if patch + is trivial enough) + + Signed-off-by: Random J Developer + --- + Patch body here +``` + +## Submit your work upstream + +We accept github pull requests and this is the preferred way to contribute to CRIU. +For that you should push your work to your fork of CRIU at [GitHub](https://github.com) and create a [pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) + +Historically, CRIU worked with mailing lists and patches so if you still prefer this way continue reading till the end of this section. + +### Make a patch + +To create a patch, run + +``` + git format-patch --signoff origin/criu-dev +``` + +You might need to read GIT documentation on how to prepare patches +for mail submission. Take a look at http://book.git-scm.com/ and/or +http://git-scm.com/documentation for details. It should not be hard +at all. + +We recommend to post patches using `git send-email` + +``` + git send-email --cover-letter --no-chain-reply-to --annotate \ + --confirm=always --to=criu@openvz.org criu-dev +``` + +Note that the `git send-email` subcommand may not be in +the main git package and using it may require installation of a +separate package, for example the "git-email" package in Fedora and +Debian. + +If this is your first time using git send-email, you might need to +configure it to point it to your SMTP server with something like: + +``` + git config --global sendemail.smtpServer stmp.example.net +``` + +If you get tired of typing `--to=criu@openvz.org` all the time, +you can configure that to be automatically handled as well: + +``` + git config sendemail.to criu@openvz.org +``` + +If a developer is sending another version of the patch (e.g. to address +review comments), they are advised to note differences to previous versions +after the `---` line in the patch so that it helps reviewers but +doesn't become part of git history. Moreover, such patch needs to be prefixed +correctly with `--subject-prefix=PATCHv2` appended to +`git send-email` (substitute `v2` with the correct +version if needed though). + +### Mail patches + +The patches should be sent to CRIU development mailing list, `criu AT openvz.org`. Note that you need to be subscribed first in order to post. The list web interface is available at https://openvz.org/mailman/listinfo/criu; you can also use standard mailman aliases to work with it. + +Please make sure the email client you're using doesn't screw your patch (line wrapping and so on). + +{{Note| When sending a patch set that consists of more than one patch, please, push your changes in your local repo and provide the URL of the branch in the cover-letter}} + +### Wait for response + +Be patient. Most CRIU developers are pretty busy people so if +there is no immediate response on your patch — don't be surprised, +sometimes a patch may fly around a week before it gets reviewed. + +## Continuous integration + +Wiki article: [Continuous integration](https://criu.org/Continuous_integration) + +CRIU tests are run for each series sent to the mailing list. If you get a message from our patchwork that patches failed to pass the tests, you have to investigate what is wrong. + +We also recommend you to [enable Travis CI for your repo](https://criu.org/Continuous_integration#Enable_Travis_CI_for_your_repo) to check patches in your git branch, before sending them to the mailing list. From 2e5805878bbf1f80b2297b4b60a6859d15055142 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 14 Jun 2020 09:31:15 +0300 Subject: [PATCH 2430/4375] CONTRIBUTING.md: minor formatting fixes * Mark lowcase criu as code in the environment section * Add missing brace around the reference to https://criu.org/Secrity * Fixup an admolition block that GitHub cannot render * Spelling fixups * s/github/GitHub/g Signed-off-by: Mike Rapoport --- CONTRIBUTING.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index edb7ecb48..de4f3e1ea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,15 +13,15 @@ Here are some useful hints to get involved. * We have both -- [very simple](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) and [more sophisticated](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3A%22new+feature%22) coding tasks; * CRIU does need [extensive testing](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Atesting); * Documentation is always hard, we have [some information](https://criu.org/Category:Empty_articles) that is to be extracted from people's heads into wiki pages as well as [some texts](https://criu.org/Category:Editor_help_needed) that all need to be converted into useful articles; -* Feedback is expected on the github issues page and on the [mailing list](https://lists.openvz.org/mailman/listinfo/criu); -* We accept github pull requests and this is the preferred way to contribute to CRIU. If you prefer to send patches by email, you are welcome to send them to [CRIU development mailing list](https://lists.openvz.org/mailman/listinfo/criu). -Below we describe in more detail recommend practices for CRIU developemnt. +* Feedback is expected on the GitHub issues page and on the [mailing list](https://lists.openvz.org/mailman/listinfo/criu); +* We accept GitHub pull requests and this is the preferred way to contribute to CRIU. If you prefer to send patches by email, you are welcome to send them to [CRIU development mailing list](https://lists.openvz.org/mailman/listinfo/criu). +Below we describe in more detail recommend practices for CRIU development. * Spread the word about CRIU in [social networks](http://criu.org/Contacts); * If you're giving a talk about CRIU -- let us know, we'll mention it on the [wiki main page](https://criu.org/News/events); -### Seting up the developemnt environment +### Setting up the development environment -Although criu could be run as non-root (see [Security](https://criu.org/Security), development is better to be done as root. For example, some tests require root. So, it would be a good idea to set up some recent Linux distro on a virtual machine. +Although `criu` could be run as non-root (see [Security](https://criu.org/Security)), development is better to be done as root. For example, some tests require root. So, it would be a good idea to set up some recent Linux distro on a virtual machine. ### Get the source code @@ -76,14 +76,14 @@ CRIU comes with an extensive test suite. To check whether your changes introduce The command runs [ZDTM Test Suite](https://criu.org/ZDTM_Test_Suite). Check for any error messages produced by it. In case you'd rather have someone else run the tests, you can use travis-ci for your -own github fork of CRIU. It will check the compilation for various supported platforms, +own GitHub fork of CRIU. It will check the compilation for various supported platforms, as well as run most of the tests from the suite. See https://travis-ci.org/checkpoint-restore/criu for more details. ## Sign your work -To improve tracking of who did what, we ask you to sign off the patches -that are to be emailed. +To improve tracking of who did what, we ask you to sign off the commits in +your fork of CRIU or the patches that are to be emailed. The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right to @@ -142,7 +142,7 @@ commit message. To append such line to a commit you already made, use ## Submit your work upstream -We accept github pull requests and this is the preferred way to contribute to CRIU. +We accept GitHub pull requests and this is the preferred way to contribute to CRIU. For that you should push your work to your fork of CRIU at [GitHub](https://github.com) and create a [pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) Historically, CRIU worked with mailing lists and patches so if you still prefer this way continue reading till the end of this section. @@ -200,7 +200,7 @@ The patches should be sent to CRIU development mailing list, `criu AT openvz.org Please make sure the email client you're using doesn't screw your patch (line wrapping and so on). -{{Note| When sending a patch set that consists of more than one patch, please, push your changes in your local repo and provide the URL of the branch in the cover-letter}} +> **Note:** When sending a patch set that consists of more than one patch, please, push your changes in your local repo and provide the URL of the branch in the cover-letter ### Wait for response From 35f8c056ac49ab62b8575a2d1f04cbbd94ccff5b Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 14 Jun 2020 11:22:19 +0300 Subject: [PATCH 2431/4375] CONTRIBUTING.md: add sections about patch description and splitting Shamelessly stolen from the Linux kernel [1], shortened a bit and relaxed to match CRIU. [1] https://www.kernel.org/doc/html/latest/process/submitting-patches.html Signed-off-by: Mike Rapoport --- CONTRIBUTING.md | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index de4f3e1ea..1c731b7f8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -80,6 +80,77 @@ own GitHub fork of CRIU. It will check the compilation for various supported pla as well as run most of the tests from the suite. See https://travis-ci.org/checkpoint-restore/criu for more details. +## Describe your changes + +Describe your problem. Whether your change is a one-line bug fix or +5000 lines of a new feature, there must be an underlying problem that +motivated you to do this work. Convince the reviewer that there is a +problem worth fixing and that it makes sense for them to read past the +first paragraph. + +Once the problem is established, describe what you are actually doing +about it in technical detail. It's important to describe the change +in plain English for the reviewer to verify that the code is behaving +as you intend it to. + +Solve only one problem per commit. If your description starts to get +long, that's a sign that you probably need to split up your commit. +See [Separate your changes](#separate-your-changes). + +Describe your changes in imperative mood, e.g. "make xyzzy do frotz" +instead of "[This commit] makes xyzzy do frotz" or "[I] changed xyzzy +to do frotz", as if you are giving orders to the codebase to change +its behaviour. + +If your change fixes a bug in a specific commit, e.g. you found an issue using +`git bisect`, please use the `Fixes:` tag with the abbreviation of +the SHA-1 ID, and the one line summary. For example: + +``` + Fixes: 9433b7b9db3e ("make: use cflags/ldflags for config.h detection mechanism") +``` + +The following `git config` settings can be used to add a pretty format for +outputting the above style in the `git log` or `git show` commands: + +``` + [pretty] + fixes = Fixes: %h (\"%s\") +``` + +If your change address an issue listed in GitHub, please use `Fixes:` tag with the number of the issue. For instance: + +``` + Fixes: #339 +``` + +You may refer to [How to Write a Git Commit +Message](https://chris.beams.io/posts/git-commit/) article for +recommendations for good commit message. + +## Separate your changes + +Separate each **logical change** into a separate commit. + +For example, if your changes include both bug fixes and performance +enhancements for a single driver, separate those changes into two +or more commits. If your changes include an API update, and a new +driver which uses that new API, separate those into two commits. + +On the other hand, if you make a single change to numerous files, +group those changes into a single commit. Thus a single logical change +is contained within a single commit. + +The point to remember is that each commit should make an easily understood +change that can be verified by reviewers. Each commit should be justifiable +on its own merits. + +When dividing your change into a series of commits, take special care to +ensure that CRIU builds and runs properly after each commit in the +series. Developers using `git bisect` to track down a problem can end up +splitting your patch series at any point; they will not thank you if you +introduce bugs in the middle. + ## Sign your work To improve tracking of who did what, we ask you to sign off the commits in From 6815aa958d1ac01f0dd0c81d55475d44aabfff88 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 14 Jun 2020 11:26:14 +0300 Subject: [PATCH 2432/4375] CONTRIBUTING.md: add pull request guidelines Following the discussion at [1] describe best practices for pull request creation. [1] https://github.com/checkpoint-restore/criu/pull/1096 Signed-off-by: Mike Rapoport --- CONTRIBUTING.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1c731b7f8..d40f0014c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -216,6 +216,44 @@ commit message. To append such line to a commit you already made, use We accept GitHub pull requests and this is the preferred way to contribute to CRIU. For that you should push your work to your fork of CRIU at [GitHub](https://github.com) and create a [pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) +### Pull request guidelines + +Pull request comment should contain description of the problem your changes +solve and a brief outline of the changes included in the pull request. + +Please avoid pushing fixup commits to an existent pull request. Each commit +should be self contained and there should not be fixup commits in a patch +series. Pull requests that contain one commit which breaks something +and another commit which fixes it, will be rejected. + +Please merge the fixup commits into the commits that has introduced the +problem before creating a pull request. + +It may happen that the reviewers were not completely happy with your +changes and requested changes to your patches. After you updated your +changes please close the old pull request and create a new one that +contains the following: + +* Description of the problem your changes solve and a brief outline of the + changes +* Link to the previous version of the pull request +* Brief description of the changes between old and new versions of the pull + request. If there were more than one previous pull request, all the + revisions should be listed. For example: + +``` + v3: rebase on the current criu-dev + v2: add commit to foo() and update bar() coding style +``` + +If there are only minor updates to the commits in a pull request, it is +possible to force-push them into an existing pull request. This only applies +to small changes and should be used with care. If you update an existing +pull request, remember to add the description of the changes from the +previous version. + +### Mailing list submission + Historically, CRIU worked with mailing lists and patches so if you still prefer this way continue reading till the end of this section. ### Make a patch From ce22e0f37dfce44bcdd6c9b8a94713441f139158 Mon Sep 17 00:00:00 2001 From: Angie Ni Date: Thu, 4 Jun 2020 11:24:23 -0600 Subject: [PATCH 2433/4375] uffd: uffd_open prints info, caller prints error When uffd_open is called from kerndat_uffd, userfaultfd failure is not considered an error, so the goal is to suppress the error message -- instead, we print this message as info. If the function fails, it is the responsibility of the caller to print the error message. Signed-off-by: Angie Ni --- criu/uffd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/criu/uffd.c b/criu/uffd.c index 33b34ba25..5f4c15a60 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -269,7 +269,7 @@ int uffd_open(int flags, unsigned long *features) uffd = syscall(SYS_userfaultfd, flags); if (uffd == -1) { - pr_perror("Lazy pages are not available"); + pr_info("Lazy pages are not available: %s\n", strerror(errno)); return -errno; } From 41b535d312828eac6fd79481d04abe20163b0cc8 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 16 Jun 2020 14:26:06 +0000 Subject: [PATCH 2434/4375] test: skip vdso test on non-vdso systems Signed-off-by: Adrian Reber --- scripts/travis/vagrant.sh | 3 +-- test/zdtm/static/vdso01.checkskip | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100755 test/zdtm/static/vdso01.checkskip diff --git a/scripts/travis/vagrant.sh b/scripts/travis/vagrant.sh index 943a8b9a3..46740efc3 100755 --- a/scripts/travis/vagrant.sh +++ b/scripts/travis/vagrant.sh @@ -45,9 +45,8 @@ fedora-no-vdso() { vagrant reload ssh default cat /proc/cmdline ssh default 'cd /vagrant; tar xf criu.tar; cd criu; make -j 4' - # Excluding the VDSO test as we are running without VDSO # Excluding two cgroup tests which seem to fail because of cgroup2 - ssh default 'cd /vagrant/criu/test; sudo ./zdtm.py run -a -x zdtm/static/cgroup04 -x zdtm/static/cgroup_ifpriomap -x zdtm/static/vdso01 --keep-going' + ssh default 'cd /vagrant/criu/test; sudo ./zdtm.py run -a -x zdtm/static/cgroup04 -x zdtm/static/cgroup_ifpriomap --keep-going' } $1 diff --git a/test/zdtm/static/vdso01.checkskip b/test/zdtm/static/vdso01.checkskip new file mode 100755 index 000000000..a00df6231 --- /dev/null +++ b/test/zdtm/static/vdso01.checkskip @@ -0,0 +1,3 @@ +#!/bin/bash + +grep -q "\[vdso\]" /proc/self/maps From d38046b0035d977f44f99d68bb5e3c3d4fb4fd9a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 22 Jul 2017 11:33:12 +0300 Subject: [PATCH 2435/4375] mount: restore_task_mnt_ns - Lookup for mount namespace conditionally In case if our parent is a dead task (zombie) we should lookup for parent ids which will be inherited on restore. Otherwise parent->ids may be nil and SIGSEGV produced. Signed-off-by: Cyrill Gorcunov Rework and port from vzcriu: 87b320964 ("vz7: mount: restore_task_mnt_ns - Lookup for mount namespace conditionally") Fixes: #1066 Signed-off-by: Pavel Tikhomirov --- criu/mount.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/criu/mount.c b/criu/mount.c index 89b8cff59..a0b8b2e06 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -3094,19 +3094,19 @@ int restore_task_mnt_ns(struct pstree_item *current) return 0; if (current->ids && current->ids->has_mnt_ns_id) { + struct pstree_item *parent = current->parent; unsigned int id = current->ids->mnt_ns_id; struct ns_id *nsid; - /* - * Regardless of the namespace a task wants to - * live in, by that point they all will live in - * root's one (see prepare_pstree_kobj_ids() + - * get_clone_mask()). So if the current task's - * target namespace is the root's one -- it's - * already there, otherwise it will have to do - * setns(). + /* Zombies and helpers can have ids == 0 so we skip them */ + while (parent && !parent->ids) + parent = parent->parent; + + /** + * Our parent had restored the mount namespace before forking + * us and if we have the same mntns we just stay there. */ - if (current->parent && id == current->parent->ids->mnt_ns_id) + if (parent && id == parent->ids->mnt_ns_id) return 0; nsid = lookup_ns_by_id(id, &mnt_ns_desc); From f0438f47f28d73a75e0fff4c74ee50f80b0c70d1 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 22 Jun 2020 18:50:55 +0300 Subject: [PATCH 2436/4375] cgroup: make prepare_task_cgroup lookup current cgset in ancestors In case if our parent is a dead task (zombie) or a helper which in it's turn has zombie parent, and parent thus has zero cg_set we should look for current cgset deeper. Fixes: #1066 Signed-off-by: Pavel Tikhomirov --- criu/cgroup.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/criu/cgroup.c b/criu/cgroup.c index d4c712167..3737772df 100644 --- a/criu/cgroup.c +++ b/criu/cgroup.c @@ -1210,14 +1210,19 @@ static int move_in_cgroup(CgSetEntry *se, bool setup_cgns) int prepare_task_cgroup(struct pstree_item *me) { + struct pstree_item *parent = me->parent; CgSetEntry *se; u32 current_cgset; if (!rsti(me)->cg_set) return 0; - if (me->parent) - current_cgset = rsti(me->parent)->cg_set; + /* Zombies and helpers can have cg_set == 0 so we skip them */ + while (parent && !rsti(parent)->cg_set) + parent = parent->parent; + + if (parent) + current_cgset = rsti(parent)->cg_set; else current_cgset = root_cg_set; From 99c84878374e90e52ed1723f12564a5d16b1281d Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 22 Jun 2020 14:20:29 +0300 Subject: [PATCH 2437/4375] zdtm: add zombie_leader test Create a session leader and it's child - session member, make leader zombie. To restore this criu will need to create a helper task a child of our zombie so that member can inherit session. Before fixes in this patchset we segfault on empty ids and fail to restore cgroups because of empty cg_set Signed-off-by: Pavel Tikhomirov --- test/zdtm/static/Makefile | 1 + test/zdtm/static/zombie_leader.c | 83 +++++++++++++++++++++++++++++ test/zdtm/static/zombie_leader.desc | 1 + 3 files changed, 85 insertions(+) create mode 100644 test/zdtm/static/zombie_leader.c create mode 100644 test/zdtm/static/zombie_leader.desc diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 7d72673c3..45a0df784 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -229,6 +229,7 @@ TST_NOFILE := \ time \ timens_nested \ timens_for_kids \ + zombie_leader \ # jobctl00 \ ifneq ($(ARCH),arm) diff --git a/test/zdtm/static/zombie_leader.c b/test/zdtm/static/zombie_leader.c new file mode 100644 index 000000000..d94b2af04 --- /dev/null +++ b/test/zdtm/static/zombie_leader.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check non-empty session with zombie leader"; +const char *test_author = "Pavel Tikhomirov "; + +int child(void) +{ + while (1) + sleep(1); + + return 0; +} + +int zombie_leader(int *cpid) +{ + int pid; + + setsid(); + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork child"); + return 1; + } else if (pid == 0) { + exit(child()); + } + + *cpid = pid; + return 0; +} + +int main(int argc, char **argv) +{ + int ret = -1, status; + int pid, *cpid; + siginfo_t infop; + + test_init(argc, argv); + + cpid = (int *)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED, -1, 0); + *cpid = 0; + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork zombie"); + return 1; + } else if (pid == 0) { + exit(zombie_leader(cpid)); + } + + if (waitid(P_PID, pid, &infop, WNOWAIT | WEXITED) < 0) { + pr_perror("Failed to waitid zombie"); + goto err; + } + + if (!*cpid) { + pr_err("Don't know grand child's pid"); + goto err; + } + + test_daemon(); + test_waitsig(); + + ret = 0; +err: + waitpid(pid, &status, 0); + + if (*cpid) + kill(*cpid, SIGKILL); + + if (!ret) + pass(); + + return 0; +} diff --git a/test/zdtm/static/zombie_leader.desc b/test/zdtm/static/zombie_leader.desc new file mode 100644 index 000000000..6c4afe5f0 --- /dev/null +++ b/test/zdtm/static/zombie_leader.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns'} From 4e7ec3c88b518e7bbf986228bb822bed6869ad9c Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 5 May 2020 14:53:08 +0000 Subject: [PATCH 2438/4375] pidns: add pidns image file definition TODO: create correct magic Signed-off-by: Adrian Reber --- criu/image-desc.c | 1 + criu/include/image-desc.h | 1 + criu/include/magic.h | 1 + criu/include/protobuf-desc.h | 1 + criu/protobuf-desc.c | 1 + images/Makefile | 1 + images/pidns.proto | 5 +++++ lib/py/images/images.py | 1 + 8 files changed, 12 insertions(+) create mode 100644 images/pidns.proto diff --git a/criu/image-desc.c b/criu/image-desc.c index 617b95355..c9581f5b8 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -103,6 +103,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = { FD_ENTRY(NETNF_EXP, "netns-exp-%u"), FD_ENTRY(FILES, "files"), FD_ENTRY(TIMENS, "timens-%u"), + FD_ENTRY(PIDNS, "pidns-%u"), [CR_FD_STATS] = { .fmt = "stats-%s", diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 6283a576d..e37d535c2 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -27,6 +27,7 @@ enum { CR_FD_MNTS, CR_FD_USERNS, CR_FD_TIMENS, + CR_FD_PIDNS, _CR_FD_IPCNS_FROM, CR_FD_IPC_VAR, diff --git a/criu/include/magic.h b/criu/include/magic.h index d078ec422..ac5cd8033 100644 --- a/criu/include/magic.h +++ b/criu/include/magic.h @@ -96,6 +96,7 @@ #define FILES_MAGIC 0x56303138 /* Toropets */ #define MEMFD_INODE_MAGIC 0x48453499 /* Dnipro */ #define TIMENS_MAGIC 0x43114433 /* Beslan */ +#define PIDNS_MAGIC 0x12345678 #define IFADDR_MAGIC RAW_IMAGE_MAGIC #define ROUTE_MAGIC RAW_IMAGE_MAGIC diff --git a/criu/include/protobuf-desc.h b/criu/include/protobuf-desc.h index 43d961731..46f7f8cea 100644 --- a/criu/include/protobuf-desc.h +++ b/criu/include/protobuf-desc.h @@ -66,6 +66,7 @@ enum { PB_TIMENS, PB_IMG_STREAMER_REQUEST, PB_IMG_STREAMER_REPLY, + PB_PIDNS, /* PB_AUTOGEN_STOP */ diff --git a/criu/protobuf-desc.c b/criu/protobuf-desc.c index 13655264a..223a6149f 100644 --- a/criu/protobuf-desc.c +++ b/criu/protobuf-desc.c @@ -38,6 +38,7 @@ #include "images/timer.pb-c.h" #include "images/utsns.pb-c.h" #include "images/timens.pb-c.h" +#include "images/pidns.pb-c.h" #include "images/ipc-var.pb-c.h" #include "images/ipc-shm.pb-c.h" #include "images/ipc-msg.pb-c.h" diff --git a/images/Makefile b/images/Makefile index 5458e4679..9ce7198c0 100644 --- a/images/Makefile +++ b/images/Makefile @@ -55,6 +55,7 @@ proto-obj-y += rpc.o proto-obj-y += ext-file.o proto-obj-y += cgroup.o proto-obj-y += userns.o +proto-obj-y += pidns.o proto-obj-y += google/protobuf/descriptor.o # To make protoc-c happy and compile opts.proto proto-obj-y += opts.o proto-obj-y += seccomp.o diff --git a/images/pidns.proto b/images/pidns.proto new file mode 100644 index 000000000..7ff049749 --- /dev/null +++ b/images/pidns.proto @@ -0,0 +1,5 @@ +syntax = "proto2"; + +message pidns_entry { + optional string ext_key = 1; +} diff --git a/lib/py/images/images.py b/lib/py/images/images.py index ca6f207bb..7faefbb96 100644 --- a/lib/py/images/images.py +++ b/lib/py/images/images.py @@ -467,6 +467,7 @@ handlers = { 'CREDS': entry_handler(pb.creds_entry), 'UTSNS': entry_handler(pb.utsns_entry), 'TIMENS': entry_handler(pb.timens_entry), + 'PIDNS': entry_handler(pb.pidns_entry), 'IPC_VAR': entry_handler(pb.ipc_var_entry), 'FS': entry_handler(pb.fs_entry), 'GHOST_FILE': ghost_file_handler(), From f1e6b103692e20a031fde1257193aab3d1f45ef4 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 5 May 2020 15:16:19 +0000 Subject: [PATCH 2439/4375] pidns: write and read pidns information This loads and stores the key for an external PID namespace if specified by the user using: --external pid[]: